前言

本节学习Transform的基本使用

Transforms用途

把Transforms当成工具箱的话,里面的class就是不同的工具。例如像totensor、resize这些工具。

Transforms可以将一些特定格式的图片,经过Transforms里面的工具,获得我们想要的结果。

Transforms该如何使用

 __call__方法的使用

创建Person类

定义方法__call__,并调用

class Person:
    def __call__(self,name):
        print("__call__ "+"Hello "+name)

person = Person()  # 实例化对象
person("zhangsan") # 调用__call__方法

输出结果

__call__ Hello zhangsan

定义方法hello

class Person:    
    def hello(self,name):
        print("hello "+name)

person = Person()  # 实例化对象
person.hello("list") # 调用hello方法

输出结果

hello list

可以看出区别,使用__call__方法的时候直接用对象名加上属性即可调用,使用hello方法的时候还需要用点调用。

全部代码

class Person:
    def __call__(self,name):
        print("__call__ "+"Hello "+name)
        
    def hello(self,name):
        print("hello "+name)
        
person = Person()  # 实例化对象
person("zhangsan") # 调用__call__方法
person.hello("list") # 调用hello方法

需要Tensor数据类型原因

Tensor有一些属性,比如反向传播、梯度等属性,它包装了神经网络需要的一些属性。

以下代码是在tensorboard中展示transforms.ToTensor工具所处理过的tensor类型图片代码:

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

img_path = "dataset/val/bees/10870992_eebeeb3a12.jpg"
img = Image.open(img_path)

writer = SummaryWriter("logs") 

tensor_trans = transforms.ToTensor() 
img_tensor = tensor_trans(img)

writer.add_image("Temsor_img",img_tensor) 
writer.close()

Tensorboard界面如下:

常见的Transforms工具

Transforms的工具主要关注他的输入、输出、作用。

 Transforms.ToTensor使用

从transforms中取出工具ToTensor(创建具体的工具)

trans_totensor = transforms.ToTensor()

填入ToTensor工具所需要输入的东西(使用工具)

img_tensor = trans_totensor(img)

以下是完整代码:

from torchvision import transforms
from PIL import Image

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#ToTensor
trans_totensor = transforms.ToTensor()  # 创建 transforms.ToTensor类 的实例化对象
img_tensor = trans_totensor(img)  # 调用 transforms.ToTensor类 的__call__的魔术方法   
print(img_tensor)

Normanize归一化

传入均值和标准差,因为图片按照 tensor 类型的存储顺序存成 C H W(通道数,长,宽)的图片,所以提供三个均值和三个标准差

trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])#input[channel]=(input[chnnel]-mean[channel])/std[channel]
img_norm = trans_norm(img_tensor)

归一化计算公式:input[channel]=(input[chnnel]-mean[channel])/std[channel]

所以,假设均值和标准差都设置在0.5,则input=(input-0.5)/0.5=2*input-1,若input图片的像素值设定在0到1之内,即input=[0,1],则最后结果在-1到1之间,即result=[-1,1]

print(img_tensor[0][0][0])
print(img_norm[0][0][0])

前后输出结果对比

tensor(0.3137)
tensor(-0.3725)

转为tensor类型后在Tensorboard中打开后看到的效果

可以看出归一化操作前后,图片明显不同

完整代码

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#Normalize
print(img_tensor[0][0][0])
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm)

writer.close()

Resize裁剪

Resize裁剪方法一(指定裁剪大小)

PIL数据类型的 img -> resize到尺寸为512*512的大小 -> PIL数据类型的 img_resize

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

想在tensorboard显示,则需要将PIL类型转换为tensor类型

PIL 数据类型的 img_resize -> ToTensor ->tensor数据类型的 img_resize (变量名相同,值覆盖)

img_resize = trans_totensor(img_resize)

在Tensorboard中打开的效果

可以看出裁剪后的效果

完整代码

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#Resize1
print(img.size)
trans_resize = transforms.Resize((512,512))
img_resize = trans_resize(img)
img_resize = trans_totensor(img_resize)
print(img_resize)
writer.add_image("Resize",img_resize,0)

writer.close()

Resize裁剪方法二(等比缩放)

等比例变换 and Compose的使用

等比缩放:

trans_resize_2 = transforms.Resize(512)

如果输入为一个整数,则图像的短边会被裁剪到这个大小,长边同比例缩放。例如,如果高度>宽度,输入整数为512,那么图像会被按照以下格式裁剪(512*高度/宽度,512)。

Compose函数中的两个参数表示按顺序执行的图像变换,后面一个参数的输入为前面一个参数的输出,先将图像调整大小为等比例的256像素,然后将PIL Image转换为Tensor格式。

(类似流水线操作:PIL类型的 Image -> 操作:resize(256) -> PIL类型的 Image -> 操作:totensor -> tensor类型的 Image)

trans_compose = transforms.Compose([trans_resize_2, trans_totensor])
img_resize_2 = trans_compose(img)
Compose()中的参数需要的是一个列表。Python中,列表所需要的数据形式是[数据1,数据2,...]。在Compose中,数据需要的是transforms类型数据,所以得到Compose[transforms参数1,transforms参数2,...]。

 在Tensorboard中打开的效果

因为是等比例缩小,所以形状没变,但可以看出清晰度降低。

完整代码

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#Resize2 and Compose
trans_resize_2 = transforms.Resize(256)
trans_compose = transforms.Compose([trans_resize_2,trans_totensor])
img_resize_2 = trans_compose(img)
writer.add_image("Resize2",img_resize_2,0)

writer.close()

RandomCrop随机裁剪

RandomCrop随机裁剪方式一(等比缩放)

等比例随机裁剪为312*312

trans_random = transforms.RandomCrop(312)

Compose()组合处理图像(裁剪 and tensor转换)

trans_compose_2 = transforms.Compose(trans_random,trans_totensor)

裁剪10块

for i in range(10):
    img_crop = trans_compose_2(img)
    writer.add_image("RandomCrop",img_crop,i)

在Tensorboard中打开的效果

可以看出随机裁剪效果

完整代码

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#RandomCrop1
trans_random = transforms.RandomCrop(312)
trans_compose_2 = transforms.Compose([trans_random,trans_totensor])
for i in range(10):
    img_crop = trans_compose_2(img)
    writer.add_image("RandomCrop",img_crop,i)
    
writer.close()

RandomCrop随机裁剪方式二(指定大小裁剪)

跟Resize的方法一大致相同,不多赘述

在Tensorboard中打开的效果

可以看出随机裁剪效果

以下是完整代码

from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs")
img_path = "dataset/train/ants_image/0013035.jpg"
img = Image.open(img_path)

#RandomCrop2
trans_random = transforms.RandomCrop((312,100))  # 指定随即裁剪的宽和高       
trans_compose_2 = transforms.Compose([trans_random,trans_totensor])
for i in range(10):
    img_crop = trans_compose_2(img)
    writer.add_image("RandomCrop",img_crop,i) 
    print(img_crop.size()) 

writer.close()

注意输入输出

看官方文档

关注方法需要什么参数

不知道返回类型的时候 print 、print(type()) 、debug

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐