用python进行图像处理中分别用到过matplotlib.pyplot、PIL、cv2三种库,这三种库图像读取和保存方法各异,并且图像读取时顺序也有差异,如plt.imread和PIL.Image.open读入的都是RGB顺序,而cv2.imread读入的是BGR顺序。使用时需要倍加注意。
1.cv2.imread
opencv读进来的是numpy数组,是uint8类型,0-255范围,图像形状是(H,W,C),读入的顺序是BGR
img = cv2.imread(img_path)
print('cv2',img.shape) #(H,W,C)
2.matplotlib.pyplot.imread
matplotlib读取进来的图片是numpy数组,是unit8类型,0-255范围,图像形状是(H,W,C),读入的顺序是RGB
img = plt.imread(img_path)
print('plt',img.shape) #(H,W,C)
3.PIL.image.open
PIL是有自己的数据结构的,类型是
'''PIL转成numpy数组:'''
img = Image.open(img_path)
print(type(img)) #
img = np.array(img)
print(type(img)) #
print('PIL',img.shape) #(H,W,C)
'''numpy 转成 PIL'''
#input img is numpy type
img = Image.fromarray(img.astype('uint8')).convert('RGB')
print(type(img)) #
这三者均可以用plt.imshow(img),如代码:
import PIL.Image as Image
import matplotlib.pyplot as plt
import cv2
#cv2
img = cv2.imread(img_path)
plt.subplot(1,3,1)
plt.title('cv2')
plt.imshow(img)
#plt
img = plt.imread(img_path)
plt.subplot(1,3,2)
plt.title('plt')
plt.imshow(img)
#PIL
img = Image.open(img_path)
plt.subplot(1,3,3)
plt.title('PIL')
plt.imshow(img)
#show
plt.show()
效果图:
可以看到,第一幅cv2图变色了,因为opencv读取进来的是BGR顺序呢的,而imshow需要的是RGB顺序,因此需要把cv2读的顺序转成RGB顺序
第一种方法:
b,g,r = cv2.split(img) img = cv2.merge([r,g,b])
img = cv2.imread(img_path) #======================= #convert BGR to RGB b,g,r = cv2.split(img) img = cv2.merge([r,g,b]) #======================== plt.title('cv2_RGB') plt.imshow(img) plt.show()
第二种方法:
img= img[:,:,::-1]
img = cv2.imread(img_path) #======================= #convert BGR to RGB img = img[:,:,::-1] #======================== plt.title('cv2_RGB') plt.imshow(img) plt.show()
两种方法效果图都一样:haha,这样就正常了,逍遥哥哥回来了......
1)cv2.imwrite - 保存numpy格式的图片
cv2.imwrite("cv2.jpg",img)
2)plt.imsave - 保存numpy格式的图片
plt.imsave('plt.jpg',img)
3)PIL.image - 保存PIL格式的图片
img.save("PIL.jpg")
===============================================================================================
以上就是图像的基本操作,为了方便进行图像数据的操作,pytorch团队提供了一个torchvision.transforms包,我们可以用transforms进行以下操作:
通常,在使用torchvision.transforms,我们通常使用transforms.Compose将transforms组合在一起。
PIL.Image / numpy.ndarray转化为Tensor,常常用在训练模型阶段的数据读取,而Tensor转化为PIL.Image / numpy.ndarray则用在验证模型阶段的数据输出。
注意:Tensor的形状是[C,H,W],而cv2,plt,PIL形状都是[H,W,C]
我们可以使用 transforms.ToTensor() 将 PIL.Image/numpy.ndarray 数据进转化为torch.FloadTensor,并归一化到[0, 1.0]:
而transforms.ToPILImage则是将Tensor转化为PIL.Image。如果,我们要将Tensor转化为numpy,只需要使用 .numpy() 即可。如下:
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
img_path = 'your graph path'
# transforms.ToTensor()
transform1 = transforms.Compose([
transforms.ToTensor(), # range [0, 255] -> [0.0,1.0] and convert [H,W,C] to [C,H,W]
])
img = plt.imread(img_path)
print('plt',img.shape) #(H,W,C)
img = transform1(img) # 归一化到 [0.0,1.0],并转成[C,H,W]
print(img.shape) #torch.Size([C,H,W])
# 转化为numpy.ndarray并显示
img_arr = img.numpy() * 255 #use np.numpy(): convert Tensor to numpy
img_arr = img_arr.astype('uint8') #convert Float to Int
print(img_arr.shape) #[C,H,W]
img_new = np.transpose(img_arr, (1, 2, 0)) #use np.transpose() convert [C,H,W] to [H,W,C]
plt.imshow(img_new)
plt.show()
归一化对神经网络的训练是非常重要的,那么我们如何归一化到[-1.0, -1.0]呢?只需要将上面的transform1改为如下所示:
#归一化
transform2 = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean = (0.5, 0.5, 0.5), std = (0.5, 0.5, 0.5))
]
)
(1)transforms.Compose就是将transforms组合在一起;
(2)transforms.Normalize使用如下公式进行归一化:
channel=(channel-mean)/ std
这样一来,我们的数据中的每个值就变成了[-1,1]的数了。来看下将上面transform1改为transform2所运行的效果图如下:
看上图已经出现失真了,原因是什么呢?
当上面操作已经将像素值转成[-1,1]时,执行代码img_arr = img.numpy() * 255时,举个例子,图像的某一行像素值变成
[ 207. 203. 203. ... -173. -175. -175. ],再执行代码img_arr = img_arr.astype('uint8')时,像素值变成
[207 203 203 ... 83 81 81]。就拿其中的 -173 变成 83 来说,首先我们要明确:符号数值在计算机里是用补码存储。
173原码=10101101,由于是负数,-173补码=01010010,计算机里储存的就是这个数值。那么当img_arr = img_arr.astype('uint8')读作无符号数uint8时,01010010连同符号位一起计算=83.故出现上面失真情况。
此外,transforms还提供了裁剪,缩放等操作,以便进行数据增强。下面就看一个随机裁剪的例子,这个例子中,仍然使用 Compose 将 transforms 组合在一起,如下:
transform4 = transforms.Compose([
transforms.ToTensor(),
transforms.ToPILImage(),
transforms.RandomCrop((300,300)),
])
img = Image.open(img_path).convert('RGB')
img3 = transform4(img)
img3.show()
运行结果如下:
其他操作就不一一列举了。具体看http://pillow.readthedocs.io/en/5.2.x/handbook/tutorial.html#cutting-pasting-and-merging-images