前言

​ 在计算机视觉任务中,大多数时候都涉及到图片的加载、训练以及训练结果的可视化。在实操过程中,经常会遇到图片各种类型之间的转换问题

​ 三种类型PIL、tensor、numpy,一种显示plt

图片的读入

​ 通常是有两种读入方式,分别是用PIL中的Image读入和用openCV读入。PIL(Python Imaging Library)是Python中最基础的图像处理库,OpenCV是一个很强大的图像处理库,适用面更广。两种读入方式是有区别的,主要有以下几个区别

  • 图片格式不同,Image读入的是“RGB”,Opencv读入的是“BGR”。
  • 读入图片的尺寸不同,Image读入的是 w h,Opencv读入的是h w c。其中w是宽,h是高,c是通道数。
  • Image读入是Image类无法直接显示其像素点的值(可以转换成numpy显示),Opencv读入的直接是numpy的格式。可以直接显示其像素值。

代码演示

import os.path
from PIL import Image
import cv2
import numpy as np
import matplotlib.pyplot as plt
import torchvision.transforms as standard_transforms

image = Image.open("1.jpg").convert("RGB")
image2 = cv2.imread("1.jpg")
print("Image read",image.size) # w h
print("Opencv read",image2.shape) # h w c
print(image)
print(image2)

图片的转换

​ 在视觉任务中加载图片通常要将其变为tensor,才能参与训练。下面将描述如何将读入的图片变成tensor,或者将tensor转成能够直接显示的图片格式(tensor类型的图片是无法直接可视化的)

PIL与tensor的相互转换

​ PIL和tensor的相互转换,要利用torchision中transforms中的一些类。PIL转tensor用里面的ToTensor转PIL用里面的ToPILImage类(这个类也可以将numpy格式的转为PIL)。

transform1 = standard_transforms.ToTensor()
transform2 = standard_transforms.ToPILImage()

​ 将上一节中的image转为tensor。要注意的是转为tensor后图片中像素点的方式也发生了变化,会将 w,h,c变为c,h,w,并且像素值由[0,255]变成了[0,1]。另外通常对于tensor要变为(n,c,h,w),这时候要用到unsqueeze(x) 是增加一维squeeze(x) 去掉维度为1的维度。其中x是对dim=x的进行增或者减

image = Image.open("1.jpg").convert("RGB")
image2 = cv2.imread("1.jpg")
image_tensor = transform1(image) # PIL转tensor
image_recover = transform2(image_tensor) # tensor转PIL
image_tensor_add = image_tensor.unsqueeze(0) # 添加n
print("Image read",image.size) # w h
print("Opencv read",image2.shape) # h w c
print("tensor",image_tensor.size()) #c h w
print("tensor recover to Image",image_recover.size)
print("tensor add ",image_tensor_add.size())

numpy与tensor的相互转换

numpy转tensor

​ 一种是直接利用torchvision.transform里的ToTensor直接转换。一种是用torch.from_numpy()转换,但是这种方法需要注意一下numpy的数据排列要将(h,w,c)变为(c,h,w)。并且还要将像素点的值变为[0,1]。

#方法一:直接转换
image_tensor_form_numpy = transform1(image2)
print("image_tensor_form_numpy: ",image_tensor_form_numpy.shape)
#方法二
image_tensor_from_numpy2 = cv2.cvtColor(image2,cv2.COLOR_BGR2RGB) #先将 BGR 变为 RGB
image_tensor_from_numpy2 = torch.from_numpy(image_tensor_from_numpy2.transpose((2, 0, 1))) # 转变格式后, 将numpy 转为 torch
image_tensor_from_numpy2 = image_tensor_from_numpy2.float().div(255) #归一化到[0,1]
print("image_tensor_from_numpy2 :",image_tensor_from_numpy2.size())

tensor转numpy

​ 先将tensor中的所有像素点的值乘 255,回到之前的状态。利用np.array(),将tensor变为numpy,并进行形状的变化。再将其变回原来的BGR格式

image_numpy_form_tensor = image_tensor.mul(255).byte() #将tensor中的所有像素点的值乘 255
image_numpy_form_tensor = np.array(image_numpy_form_tensor).transpose(1,2,0)
image_numpy_form_tensor = cv2.cvtColor(image_numpy_form_tensor,cv2.COLOR_RGB2BGR)
print("image_numpy_form_tensor: ",image_numpy_form_tensor.shape)

numpy与PIL的相互转换

PIL转numpy

​ PIL转numpy直接利用np.array(),就可以将PIL变成numpy,并且数据格式也自动变为(h,w,c), 然后再将其变为BGR格式即可。

image_numpy_form_Image = np.array(image)
image_numpy_form_Image = cv2.cvtColor(image_numpy_form_Image,cv2.COLOR_RGB2BGR)
print("image_numpy_form_Image ",image_numpy_form_Image.shape)

numpy转PIL

​ 先numpy的格式由BGR变为RGB,再用Image.fromarray()转换为PIL格式。数据格式也由(h,w,c)变回(w,h,c)

image_Image_from_numpy = cv2.cvtColor(image2,cv2.COLOR_BGR2RGB)
image_Image_from_numpy = Image.fromarray(image_Image_from_numpy)
print("image_Image_from_numpy: ",image_Image_from_numpy.size)

总结

​ 不同图片类型的转换是很有必要的,在适合的时候用适合的类型。尤其是tensor与两种类型的相互转换。搞清楚这些转换,可以在图片的处理上更加游刃有余。

图片格式转换时,主要考虑两点:通道顺序和维度顺序

附 plt转PIL

def plt2PIL(plt_img, save_path, size=(16, 16), dpi=14):
"""
@brief:plt图转PIL图,去白边、坐标轴,显示并保存
@param:plt_img, save_path, size=(16, 16), dpi=14
@return:NONE
"""
plt.figure(figsize=size, dpi=dpi)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
plt.imshow(plt_img)
plt.axis('off')
plt.savefig(save_path, pad_inches=0)
plt.show()

参考博客:pytorch中图片类型的转换——PIL、tensor、numpy

https://blog.csdn.net/weixin_43593330/article/details/107673739
https://blog.csdn.net/qq_36955294/article/details/82888443
https://www.cnblogs.com/ocean1100/p/9494640.html