Transforms简单应用

transform库是一个对图片进行预处理的库,在训练的时候被广泛和频繁使用,下面是一些很常见的包。

导入Transforms库:

from torchvision import transforms

ToTensor类:

transforms库内有一个类:ToTensor。你可以把它理解为是一个工具,作用是将PIL数据类型和ndarray数据类型转换为tensor数据类型,方便将来的对图片的统一操作。

使用时,首先给ToTensor实例化一个对象,然后再把图片作为参数进行操作。

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
writer = SummaryWriter("log_of_normal")

#   Totensor    将ndarray或者PIL转换为tensor数据类型

img2_PIL = Image.open("dataset of mine/assignment1/train/bees_image/39747887_42df2855ee.jpg")

#   用PIL库内的Image包,使用open可以打开一个PIL类型的图片

trans_totensor = transforms.ToTensor()

#   transform的ToTensor方法可以生成一个ToTensor对象,然后将ndarray类型或者PIL类型的图片作为参数,就可以转换成tensor类型的图片

img2_tensor = trans_totensor(img2_PIL)
writer.add_image("tensor", img2_tensor, 0)

#   将ndarray转换为tensor

img1_cv = cv2.imread("dataset of mine/assignment1/train/bees_image/196430254_46bd129ae7.jpg")

img1_tensor = trans_totensor(img1_cv)
writer.add_image("tensor", img1_tensor, 1)

writer.close()

Normalize类——归一化处理:

为什么用Normalize这个类?

众所周知,彩色图片有三个通道,RGB的值落在[0, 255]之间,但是在加载图片的时候就自动转换成了[0, 1],比如说Totensor就有这个作用,将每个RGB值都除255。Normalize就是将每个像素的每个通道值整理到[-1,1]的区间内,称为归一化。

归一化后的数据可以加快神经网络模型的收敛速度,也就是加快模型的训练速度。

需要两个参数,都是列表,第一个参数是三个均值,分别是RGB值的均值,第二个参数是三个方差,分别是RGB值的方差。比如,对于红色R,均值mean就是将所有像素的R值求均而得到,方差std就是将所有像素的R值求方差得到。

归一化,是用Normalize参数设置成([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])。于是像素的RGB值就都落在[-1, 1]了。

from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
writer = SummaryWriter("log_of_normal")

#   Normalize   将图片归一化处理

img1_cv = cv2.imread("dataset of mine/assignment1/train/bees_image/196430254_46bd129ae7.jpg")
img1_tensor = trans_totensor(img1_cv)
print(img1_tensor[0][0][7])

#   打印第一行第七列像素的R值

trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

#   用Normalize生成一个对象,作为工具进行实际的归一化操作。参数是两个列表,第一个列表是三通道的均值mean,第二个列表是三通道的方差std

#   output = (input - mean) / std

img1_tensor_norm = trans_norm(img1_tensor)
print(img1_tensor_norm[0][0][7])
writer.add_image("normal", img1_tensor_norm, 0)
writer.close()

Resize类:

功能是修改图片的高和宽。它不仅可以修改PIL类型,还可以修改tensor类型,但是修改ndarray类型就会报错(我也不知道为什么它偏偏不支持这个类型)

参数通常是一个元组或者是一个数。如果是元组,那么就是将原图片的高和宽修改成指定的高和宽。如果只是一个数,那么就是将高或者宽比较小的那个设置成这个int值。

from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
writer = SummaryWriter("log_of_normal")

#   Resize
img1_cv = cv2.imread("dataset of mine/assignment1/train/bees_image/196430254_46bd129ae7.jpg")
img1_tensor = trans_totensor(img1_cv)
print(img1_tensor.shape)

#   用shape查看tensor类型的形状

trans_resize = transforms.Resize((512, 512))

#   生成一个Resize对象,作为工具。参数是一个元组,是被修改后的图片的高和宽
#   img PIL -> resize -> img_resize PIL

img2_PIL_resize = trans_resize(img2_PIL)
print(img2_PIL_resize.size)

#用size查看PIL类型的形状
#   img PIL -> totensor -> img_resize tensor

img2_tensor_resize = trans_totensor(img2_PIL_resize)
print(img2_tensor_resize.shape)
writer.add_image("Resize", img2_tensor_resize, 0)
writer.close()

Compose类:

Compose类实际上提供了一种渠道,将方法都聚集起来使用。使得totensor和其他方法的功能一步到位。

from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
writer = SummaryWriter("log_of_normal")
from PIL import Image

#   Compose方法,形象比喻成工具包

trans_resize_2 = transforms.Resize(512)

#   Resize 参数两个,说明高度和宽度就是我们所指定的大小,如果参数是一个,那么就是将图片最小的边更新为指定值
#   PIL -> resize -> PIL -> compose -> tensor

trans_compose = transforms.Compose([trans_resize_2, trans_totensor])

#   这个compose相当于是一个方法的顺序组合,列表里面放的都是方法,前一个的输出会当成后一个的输入进行,可以说是一种减少代码的方式
#   注意,compose方法里面的totensor方法只允许转换PIL图片,不允许ndarray作为被转换对象

img2_PIL = Image.open("dataset of mine/assignment1/train/bees_image/39747887_42df2855ee.jpg")
img2_tensor_resize_2 = trans_compose(img2_PIL)
writer.add_image("Resize", img2_tensor_resize_2, 1)
writer.close()

注意,totensor用在compose里面时只能将PIL类型转换为tensor类型,不能将ndarray类型转换为tensor类型。

RandomCrop类:

将会随机按指定的大小裁剪图片。

参数一般只有一个,要么是一个元组,为裁出来的长方形图片的大小,要么是一个int,为裁出来的正方形图片大小。

一般RandomCrop并不会就地修改原图片,所以它其实可以作为数据量的来源,起到补充数据量的作用。

from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
from PIL import Image
writer = SummaryWriter("log_of_normal")

#   RandomCrop

trans_random = transforms.RandomCrop((512, 312))

#   RandomCrop只有一个参数,那么将会随机裁剪图片某个正方形区域,否则将随机裁剪一个矩形区域,裁剪超出范围会报错
#   随机裁剪,增加数据量
#   依然是生成一个对象作为实际操作工具,而不是拿类来操作

trans_compose_2 = transforms.Compose([trans_random, trans_totensor])
img2_PIL = Image.open("dataset of mine/assignment1/train/bees_image/39747887_42df2855ee.jpg")
img2_PIL_resize = trans_resize(img2_PIL)
for i in range(10):
    img2_tensor_resize_crop = trans_compose_2(img2_PIL_resize)
    writer.add_image("RandomCrop", img2_tensor_resize_crop, i)
writer.close()

这里就体现了Compose所说的,compose参数里的totensor这时候只能转换PIL类型为tensor类型,不能转ndarray为tensor类型。

总代码:

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
import cv2
import numpy as np

#   使用SummaryWriter
writer = SummaryWriter("log_of_normal")
#   使用SummaryWriter创建一个运行日志
for i in range(100):
    writer.add_scalar("y = x**2", i*i, i)
#   使用add_scalar创建一条曲线

#   cv2读取图片,类型为nparray
img1_cv = cv2.imread("dataset of mine/assignment1/train/bees_image/196430254_46bd129ae7.jpg")
#   用cv2打开一个nparray类型的文件,需要以图片的相对地址或者绝对地址作为参数
writer.add_image("array", img1_cv, 0, dataformats="HWC")
#   add_image方法接收tensor或者nparray数据类型

#   Totensor    将nparray或者PIL转换为tensor数据类型
img2_PIL = Image.open("dataset of mine/assignment1/train/bees_image/39747887_42df2855ee.jpg")
#   用PIL库内的Image包,使用open可以打开一个PIL类型的图片
trans_totensor = transforms.ToTensor()
#   transform的ToTensor方法可以生成一个ToTensor对象,然后将ndarray类型或者PIL类型的图片作为参数,就可以转换成tensor类型的图片
img2_tensor = trans_totensor(img2_PIL)
writer.add_image("tensor", img2_tensor, 0)
#   将ndarray转换为tensor
img1_tensor = trans_totensor(img1_cv)
writer.add_image("tensor", img1_tensor, 1)

#   Normalize   将图片归一化处理
print(img1_tensor[0][0][7])
#   打印第一行第七列像素的R值
trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
#   用Normalize生成一个对象,作为工具进行实际的归一化操作。参数是两个列表,第一个列表是三通道的均值mean,第二个列表是三通道的方差std
#   output = (input - mean) / std
img1_tensor_norm = trans_norm(img1_tensor)
print(img1_tensor_norm[0][0][7])
writer.add_image("normal", img1_tensor_norm, 0)

#   Resize + totensor
print(img1_tensor.shape)
#   用shape查看tensor类型的形状
trans_resize = transforms.Resize((512, 512))
#   生成一个Resize对象,作为工具。参数是一个元组,是被修改后的图片的高和宽
#   img PIL -> resize -> img_resize PIL
img2_PIL_resize = trans_resize(img2_PIL)
print(img2_PIL_resize.size)
#   img PIL -> totensor -> img_resize tensor
img2_tensor_resize = trans_totensor(img2_PIL_resize)
print(img2_tensor_resize.shape)
writer.add_image("Resize", img2_tensor_resize, 0)

#   Compose方法,形象比喻成工具包
trans_resize_2 = transforms.Resize(512)
#   Resize 参数两个,说明高度和宽度就是我们所指定的大小,如果参数是一个,那么就是将图片最小的边更新为指定值
#   PIL -> resize -> PIL -> compose -> tensor
trans_compose = transforms.Compose([trans_resize_2, trans_totensor])
#   这个compose相当于是一个方法的顺序组合,列表里面放的都是方法,前一个的输出会当成后一个的输入进行,可以说是一种减少代码的方式
#   注意,compose方法里面的totensor方法只允许转换PIL图片,不允许ndarray作为被转换对象
img2_tensor_resize_2 = trans_compose(img2_PIL)
writer.add_image("Resize", img2_tensor_resize_2, 1)

#   RandomCrop
trans_random = transforms.RandomCrop((512, 312))
#   RandomCrop只有一个参数,那么将会随机裁剪图片某个正方形区域,否则将随机裁剪一个矩形区域,裁剪超出范围会报错
#   随机裁剪,增加数据量
#   依然是生成一个对象作为实际操作工具,而不是拿类来操作
trans_compose_2 = transforms.Compose([trans_random, trans_totensor])
for i in range(10):
    img2_tensor_resize_crop = trans_compose_2(img2_PIL_resize)
    writer.add_image("RandomCrop", img2_tensor_resize_crop, i)
writer.close()
#   最后必须关闭日志

学到这里不容易,祝你学习快乐~

你可能感兴趣的:(pytorch,人工智能,深度学习,计算机视觉)