torchvision.transforms.ToTensor
将
PIL.Image
或
numpy.ndarray
类型的图片转为
torch.Tensor
类型,如果图片的灰度级在
[0, 255]
,会除以
255.0
,归一化到
[0.0, 1.0]
。这个基本上每个数据集都会用到。
不用给参数。
>>> from torchvision import transforms
>>> import numpy as np
>>> a = np.array([[255, 199, 30]], dtype=np.uint8)
array([[255, 199, 30]], dtype=uint8)
>>> t = transforms.ToTensor()
>>> b = t(a)
tensor([[[1.0000, 0.7804, 0.1176]]])
torchvision.transforms.Grayscale(num_output_channels=1)
将彩色图片转为灰度图片。图片必须是PIL.Image
或torch.Tensor
类型。
如果num_output_channels=1
,返回单通道灰度图片;如果num_output_channels=3
,返回三通道的灰度图片,其中r == g == b
。一般我们不用设置,默认为1
就行了。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.Grayscale()
img = transform(img)
torchvision.transforms.Normalize(mean, std, inplace=False)
用均值和标准差标准化数据,将数据映射到区间[-1, 1]
,能加快模型的收敛速度,一般加到ToTensor
后面。仅限torch.Tensor
类型。
mean (sequence)
:各通道的均值。
std (sequence)
:各通道的标准差。
inplace
:是否直接在原数据上操作。
torchvision.transforms.Compose(transforms)
将若干个转换方法组合起来。
transforms
:带组合的转换方法
train_file = datasets.MNIST(
root='./dataset/',
train=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
torchvision.transforms.CenterCrop(size)
对图片进行中心裁剪。中心就是图片高和宽二分之一的交点。图片必须是PIL.Image
或torch.Tensor
类型。
size
是输出图片的高、宽。你可以给一个整型的数字,比如3
,表示输出3x3
的图片;你也可以给一个元组,比如(3, 5)
,表示输出高为3
,宽为5
的图片。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform_1 = transforms.CenterCrop(300)
img_1 = transform_1(img)
transform_2 = transforms.CenterCrop(500)
img_2 = transform_2(img)
transform_3 = transforms.CenterCrop((500,300))
img_3 = transform_3(img)
torchvision.transforms.Pad(padding, fill=0, padding_mode=‘constant’)
对图像边缘进行拓展填充。
padding
:拓展宽度。如果是整型,则所有边都拓展;如果是二元组,则指定左右和上下的拓展宽度。如果是四元组,则指定左、上、右、下的拓展宽度。
fill
:像素填充的值,默认是0
,代表黑色。可以指定整型,也可以用三元组表示分别填充RGB通道。
padding_mode
:拓展模式,默认为constant
,表示所有填的所有值都一样。edge
表示用边缘值填充;reflecty
以边缘为对称轴进行轴对称填充(边缘不重复),如在[1, 2, 3, 4]
的两边填充2个元素就是[3, 2, 1, 2, 3, 4, 3, 2]
;symmetricy
以边缘为对称轴进行轴对称填充(边缘重复),如在[1, 2, 3, 4]
的两边填充2个元素就是[2, 1, 1, 2, 3, 4, 4, 3]
。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.Pad(100, (255, 0, 0))
img = transform(img)
torchvision.transforms.RandomCrop(size, padding=None, pad_if_needed=False, fill=0, padding_mode=‘constant’)
在随机位置对图像进行裁剪
size
:输出图片的高、宽。与中心裁剪的参数定义一致。
padding
:拓展宽度。与边缘拓展的参数定义一致。
pad_if_needed
:如果设置为True
,当图像小于目标尺寸时会先填充再随机裁剪。
fill
:像素填充值。与边缘拓展的参数定义一致。
padding_mode
:拓展模式。与边缘拓展的参数定义一致。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.RandomCrop(300)
img_1 = transform(img)
img_2 = transform(img)
img_3 = transform(img)
torchvision.transforms.Resize(size, interpolation=2)
调整图像的大小到指定尺寸。图像必须是PIL.Image
或torch.Tensor
类型。这个也用的比较多,训练是按批的,必须保证每批图像的尺寸是相同,所以一般都会在训练前进行resize
操作。
size
: 可以输入一个元组,表示图像的高、宽。比如(300, 500)
,返回高为300
,宽为500
的图片;也可以只输入一个整型的数字,短边就是这个数字,然后长边按照相同的长宽比进行调整。比如一张高、宽分别为400
、200
的图片,指定size = 300
,那么返回的图像高、宽分别是600
、300
。计算过程:∵ with < height ∴ width = size = 300, height = size*height/width = 300*400*200 = 600
。
interpolation
:插值法,默认即可。
尺寸缩放的size
参数如果只给定一个整数值,返回的图像不一定是方形的。要注意和中心裁剪的size
参数区分开来。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.Resize((720, 720))
img = transform(img)
img.save('img.jpg')
torchvision.transforms.RandomRotation(degrees, resample=False, expand=False, center=None, fill=None)
按角度随机旋转图像。图像必须是PIL.Image
或torch.Tensor
类型。
degrees
: 旋转的角度范围。如果只填一个整型或浮点型的数字,比如90
,表示在-90°
和90°
之间随机旋转。也可以给一个序列类型的值,比如(45, 90)
,表示逆时针旋转,旋转角度从45°
到90°
之间随机取一个值。
resample
:重采样方法,默认即可。
expand
:是否扩展。默认为False
表示输出图和输入图大小一样,旋转超出区域就丢掉不要了;设置为True
表示扩展边界以保证显示整个原图。
center
:旋转中心的坐标,可接受的输入是元组或列表类型。默认是图片的中心,比如1280x720
的图片中心就是(640, 360)
。
fill
:图像外部区域的填充颜色。默认是0也就是黑色,也支持RGB
格式的颜色,比如(255, 0, 0)
就表示用红色填充。
官方只给了按角度随机旋转的方法,并没有给指定角度旋转的方法,但指定角度旋转也可以通过通过设置随机旋转的参数实现。比如图像顺时针旋转90°
,只需要设置degrees=(-90, -90)
。官方确实很聪明,只用一个函数就把随机旋转和定向旋转都实现了。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform_1 = transforms.RandomRotation(degrees=(45, 45))
img_1 = transform_1(img)
transform_2 = transforms.RandomRotation(degrees=(45, 45), expand=True)
img_2 = transform_2(img)
transform_3 = transforms.RandomRotation(degrees=(45, 45), fill=(255, 0, 0))
img_3 = transform_3(img)
torchvision.transforms.RandomHorizontalFlip(p=0.5)
字面意思,就是水平翻转图像。不过是否翻转是随机的。
p
:水平翻转的概率,如果是1
就一定翻转,如果给0就一定不翻转,如果其它值则按概率随机选择是否翻转。比如0.5
,那么就有一半的可能翻转,一般的可能不翻转。图像必须是PIL.Image
或torch.Tensor
类型。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.RandomHorizontalFlip(p=1)
img = transform(img)
img.save('img.jpg')
torchvision.transforms.RandomVerticalFlip(p=0.5)
字面意思,就是垂直翻转图像。不过是否翻转是随机的。
p
:垂直翻转的概率,如果是1
就一定翻转,如果给0就一定不翻转,如果其它值则按概率随机选择是否翻转。比如0.5
,那么就有一半的可能翻转,一般的可能不翻转。图像必须是PIL.Image
或torch.Tensor
类型。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform = transforms.RandomVerticalFlip(p=1)
img = transform(img)
img.save('img.jpg')
torchvision.transforms.ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)
随机改变图片的亮度,对比度和饱和度。
brightness
:亮度;允许输入浮点型或二元组(min, max)
。如果是浮点型,那么亮度在[max(0, 1 ## brightness), 1 + brightness]
区间随机变换;如果是元组,亮度在给定的元组间随机变换。不允许输入负值。
contrast
:对比度。允许输入规则和亮度一致。
saturation
:饱和度。允许输入规则和亮度一致。
hue
:色调。允许输入浮点型或二元组(min, max)
。如果是浮点型,那么亮度在[-hue, hue]
区间随机变换;如果是元组,亮度在给定的元组间随机变换。不允许输入负值。必须满足0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5
。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform_1 = transforms.ColorJitter(brightness=(2, 2))
img_1 = transform_1(img)
transform_2 = transforms.ColorJitter(contrast=(2, 2))
img_2 = transform_2(img)
transform_3 = transforms.ColorJitter(saturation=(2, 2))
img_3 = transform_3(img)
torchvision.transforms.GaussianBlur(kernel_size, sigma=(0.1, 2.0))
对图像应用高斯模糊
kernel_size
:模糊半径。必须是奇数。
sigma
:正态分布的标准差。如果是浮点型,则固定;如果是二元组(min, max)
,sigma
在区间中随机选取一个值。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform_1 = transforms.GaussianBlur(21, 10)
img_1 = transform_1(img)
transform_2 = transforms.GaussianBlur(101, 10)
img_2 = transform_2(img)
transform_3 = transforms.GaussianBlur(101, 100)
img_3 = transform_3(img)
torchvision.transforms.RandomAffine(degrees, translate=None, scale=None, shear=None, resample=0, fillcolor=0)
汇总了旋转、平移、缩放、扭曲等图像变换方法,并且支持叠加。比如旋转的同时又进行平移或缩放等。
degrees
(sequence or float or int):随机旋转的角度范围。和随机旋转的参数定义一致。设置为0表示不旋转。
translate
(tuple, optional) :水平和垂直平移的因子。如(a, b)
,表示在-img_width * a < dx < img_width * a
范围内随机水平平移,在-img_height * b < dy < img_height * b
范围内随机垂直平移。
scale
(tuple, optional):缩放因子。如(a, b)
,表示在a <= scale <= b
随机缩放。
shear
(sequence or float or int, optional):随机扭曲的角度范围。如(45, 90)
,表示在45~90范围内随机选取一个角度进行与横轴平行的扭曲。
resample
(int, optional) :重采样。
fillcolor
(tuple or int) :填充色。默认为0
,也就是黑色。支持三元组的RGB
颜色。
from PIL import Image
from torchvision import transforms
img = Image.open('test.jpg')
transform_1 = transforms.RandomAffine(90)
img_1 = transform_1(img)
transform_2 = transforms.RandomAffine(0, (0.1, 0))
img_2 = transform_2(img)
transform_3 = transforms.RandomAffine(0, None, (0.5, 2))
img_3 = transform_3(img)
transform_4 = transforms.RandomAffine(0, None, None, (45, 90))
img_4 = transform_4(img)
数据增强的transform
操作会增加样本量吗?需不需要单独的把数据集拿出来增强一下再训练?
如果tranform
里面有随机的方法,那么每个epoch
训练的数据集将会不同,就相当于增加了样本数量,所以直接训练即可,不用单独拿出来做增强。
如果是对批数据进行变换,那么该批的所有变换都是相同的。为什么要这样说?之前不是提到随机旋转这些随机的操作嘛,pytorch
在训练前需要把数据做成批数据,然后用数据加载器喂到模型中训练,也就是说这些随机的方法对于同一批数据的随机是相同,比如要旋转45°
的话就都旋转45°
,而不同批可能会不同。
https://pytorch.org/docs/stable/torchvision/transforms.html
torchvision.transforms是包含一系列常用图像变换方法的包,可用于图像预处理、数据增强等工作,但是注意它更适合于classification等对数据增强后无需改变图像的label的情况,对于Segmentation等对图像增强时需要同步改变label的情况可能不太实用,需要自己重新封装一下。
通过本次机器学习项目,我们使用PyTorch训练了一个模型,能够根据本地提供的图片库判断输入的图片是否为库里所有的人物。上述代码中,我们使用了PyTorch中的models模块加载了一个预训练的ResNet18模型,并将其最后一层的输出改为2,以适应我们的二分类任务。在训练过程中,我们使用了交叉验证的方法,同时记录了最佳的模型权重和准确率。上述代码中,我们使用了PIL库下载了一张图片,并使用了之前定义的数据增强操作对其进行预处理。然后,我们使用训练好的模型对其进行预测,并输出预测结果。文件夹存放模型文件,
今天阅读其他大佬的代码,发现了一种可以同时对image和mask做数据增强的方法,记录一下。
from torchvision.transforms import functional as F
from torchvision import transforms as tfs
from PIL import Image
import matplotlib.pyplot as plt
def rand_crop(image, label, height=300, width=300):
1. 什么是语义分割?
语义分割是一种将图像中的每个像素划分为一类的图像分析过程。
这与人类在默认情况下一直在做的事情类似。当我们看到某样东西时,我们下意识地试图将图像的哪一部分“分割”成一个预定义的类/标签/类别。
上图显示了语义分割的结果。mask中的人用红色像素表示,草是浅绿色,树是深绿色,天空是蓝色。
我们可以通过简单地检查mask在该像素处是否为红色来判断哪个像素属于“person”类,但是我们不能判断两个红色的mask像素是属于同一个人还是属于不同的人。
2. 语义分割的应用
语义分割最常用的
一、图像平滑
图像平滑是一种区域增强的算法,平滑算法有邻域平均法、中指滤波、边界保持类滤波等。在图像产生、传输和复制过程中,常常会因为多方面原因而被噪声干扰或出现数据丢失,降低了图像的质量(某一像素,如果它与周围像素点相比有明显的不同,则该点被噪声所感染)。这就需要对图像进行一定的增强处理以减小这些缺陷带来的影响。
为了方便做出比较,先给一幅图片中加入噪声,代码如下:
import cv2
import numpy as np
# 读取图片
image = cv2.imread('E:/pyth
在pytorch中实现将sobel算子和卷积层结合来提取图像中物体的边缘轮廓图,如下代码是卷积执行soble边缘检测算子的实现:
import torch
import numpy as np
from torch import nn
from PIL import Image
from torch.autograd import Variable
import torch.nn.functional as F
import cv2
def edge_conv2d(im):
# 用nn.Conv2
1.什么是数据增强 数据增强包含一系列用来生成新训练样本的技术,这些技术是通过对原始数据采用随机抖动和扰乱而类标签未变化来实现。我们应用数据增强的目标是增加模型的泛化性。鉴于我们的网络持续不断看到新的、稍微修改过的输入数据点,它能够学习更多鲁棒性。在测试时,我们不会应用数据增强来评估我们训练过的网络。在大多数情况下,你将看到测试准确性的提高,仅以轻微降低训练准确性为代价。图1:左: 一...