本文介绍图片读取的5种方式,以及pytorch使用中可能会涉及到的三种数据格式:PIL,ndarray,tensor,并介绍其转换方式。
读取图片的5种方式
- cv2.imread(path)
import cv2
img = cv2.imread(path)
- skimage.io.imread(path)
import skimage.io as io
img = io.imread(path)
- matplotlib.pyplot.imread
import matplotlib.pyplot as plt
img = plt.imread(path)
- scipy.misc.imread
from scipy.misc import imread
img = imread(path)
- PIL.Image.open
from PIL import Image
img = Image.open(path)
类型上,除了PIL特殊,为 PIL.JpegImagePlugin.JpegImageFile
,其他4种读取的图片格式均为numpy.ndarray
格式;
维度上,除了PIL其它都是H,W,C
,PIL是W,H,C
。pytorch是N,C,H,W
,tensorflow是N,H,W,C
通道上,除了opencv(cv2)读进来的顺序是BGR
,其他都是RGB
。
显示图片
- matpltlib.pyplot(plt)显示numpy数组格式的RGB图像或者tensor格式图片。如果是float32类型的图像,范围0-1;如果是uint8图像,范围是0-255;plt.imshow(image,cmap = ‘gray’),灰度图显示要设置cmap参数,显示cv2的图像需要转换通道为RGB。
- python自带的show(),显示PIL读取的图片
- cv.imshow(),显示numpy格式的图片,显示的图片通道顺序和cv2.imread()读取得到的图片的通道顺序一样,要求是BGR。
PIL,ndarray,tensor三者的转换
PIL.Image/numpy.ndarray转化为Tensor,常常用在训练模型阶段的数据读取,而Tensor转化为PIL.Image/numpy.ndarray则用在验证模型阶段的数据输出。tensor分为gpu上和cpu上的,GPU上的tensor不能直接转换为numpy,需要先转换为CPU上的tensor。ndarray(cv2)就是各种格式之间的中转)。
统一引用包
from PIL import Image
import numpy as np
import cv2
import torchvision
PIL—>ndarray:
img = Image.open('D:/1pic/g.jpg')
img = cv2.cvtColor(np.array(img),cv2.COLOR_RGB2BGR)#
cv2.imshow("img",img)
cv2.waitKey()
ndarray—>PIL
ndarray转PIL要求数据类型dtype=uint8, range[0, 255] and shape H x W x C
img = cv2.imread('D:/1pic/g.jpg')#BGR
img = cv2.cvtColor(np.array(img),cv2.COLOR_BGR2RGB) #必须的
img = Image.fromarray(img) #fromarray并不会做通道变换
img.show(img)
PIL—>tensor
def PIL_to_tensor(image):
image = torchvision.transforms.ToTensor()(image).unsqueeze(0)
return image.to(device, torch.float)
把像素值范围为[0, 255]的PIL.Image或者numpy.ndarray型数据,shape=(H x W x C)转换成的像素值范围为[0.0, 1.0]的torch.FloatTensor,shape为(N x C x H x W) 待确认。
对于PILImage转化的Tensor,其数据类型是torch.FloatTensor
Image.open 返回的图片类型为PIL Image, 数值类型为uint8,值为0-255,尺寸为 W * H * C(宽度高度通道数)。通过img=np.array(img)转为numpy数组后,统一尺寸为 H * W * C。
注意transforms.Normalize(mean, std)作用于torch.*Tensor。给定均值(R, G, B)和标准差(R,
G, B),用公式channel = (channel - mean) / std进行规范化。(是对tensor进行归一化,所以需要放在transforms.ToTensor()之后)
eg:
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
all_transforms = transforms.Compose([
transforms.Scale(256),
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(), # 对PIL.Image图片进行操作
transforms.ToTensor(),
normalize])
tensor—>PIL
tensor转PIL,要求tensor必须是float类型的,为C x H x W格式,double的不可以!
# 输入tensor变量
# 输出PIL格式图片
def tensor_to_PIL(tensor):
image = tensor.cpu().clone()
image = image.squeeze(0)
image = torchvision.transforms.ToPILImage()(image)
return image
ndarray–>tensor
对ndarray的数据类型没有限制,但转化成的Tensor的数据类型是由ndarray的数据类型决定的。
def toTensor(img):
assert type(img) == np.ndarray,'the img type is {}, but ndarry expected'.format(type(img))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = torch.from_numpy(img.transpose((2, 0, 1)))
return img.float().div(255).unsqueeze(0) # 255也可以改为256
不与输入共享内存的:
torch.Tensor(data):会给生成tensor默认float32类型,且不能用dtype参数进行修改
torch.tensor(data):会根据输入ndarray数据类型自动推断,且能通过dtype = …修改生成tensor类型
与输入共享内存的(共用一个数据地址,会修改调原始数据):
torch.as_tensor(ndarray):会自动推断类型,接受ndarray类型及tensor类型。注意因为ndarray是放在cpu上的,若用GPU则需要从cpu copy到Gpu。共享内存对python的内置类型如list等不支持。
torch.from_numpy(data):会自动推断类型,只接受numpy的ndarray类型
tensor—>ndarray
def tensor_to_np(tensor):
img = tensor.mul(255).byte()
img = img.cpu().numpy().squeeze(0).transpose((1, 2, 0))
return img