python进行图像处理中分别用到过matplotlib.pyplot、PIL、cv2三种库,这三种库图像读取和保存方法

用python进行图像处理中分别用到过matplotlib.pyplot、PIL、cv2三种库,这三种库图像读取和保存方法各异,并且图像读取时顺序也有差异,如plt.imread和PIL.Image.open读入的都是RGB顺序,而cv2.imread读入的是BGR顺序。使用时需要倍加注意。

1. cv2,matplotlib,PIL比较

  • 读取图像

1.cv2.imread

opencv读进来的是numpy数组,是uint8类型,0-255范围,图像形状是(H,W,C),读入的顺序是BGR


  
  
  1. img = cv2.imread(img_path)
  2. print( 'cv2',img.shape) #(H,W,C)

2.matplotlib.pyplot.imread

matplotlib读取进来的图片是numpy数组,是unit8类型,0-255范围,图像形状是(H,W,C),读入的顺序是RGB


  
  
  1. img = plt.imread(img_path)
  2. print( 'plt',img.shape) #(H,W,C)

3.PIL.image.open

PIL是有自己的数据结构的,类型是<class 'PIL.Image.Image'>;但是可以转换成numpy数组,转换后的数组为unit8,0-255范围,图像形状是(H,W,C),读入的顺序是RGB


  
  
  1. '''PIL转成numpy数组:'''
  2. img = Image. open(img_path)
  3. print( type(img)) #<class 'PIL.Image.Image'>
  4. img = np.array(img)
  5. print( type(img)) #<class 'numpy.ndarray'>
  6. print( 'PIL',img.shape) #(H,W,C)

  
  
  1. '''numpy 转成 PIL'''
  2. #input img is numpy type
  3. img = Image.fromarray(img.astype( 'uint8')).convert( 'RGB')
  4. print( type(img)) #<class 'PIL.Image.Image'>
  • 显示图像

这三者均可以用plt.imshow(img),如代码:


  
  
  1. import PIL.Image as Image
  2. import matplotlib.pyplot as plt
  3. import cv2
  4. #cv2
  5. img = cv2.imread(img_path)
  6. plt.subplot( 1, 3, 1)
  7. plt.title( 'cv2')
  8. plt.imshow(img)
  9. #plt
  10. img = plt.imread(img_path)
  11. plt.subplot( 1, 3, 2)
  12. plt.title( 'plt')
  13. plt.imshow(img)
  14. #PIL
  15. img = Image. open(img_path)
  16. plt.subplot( 1, 3, 3)
  17. plt.title( 'PIL')
  18. plt.imshow(img)
  19. #show
  20. plt.show()

效果图:

可以看到,第一幅cv2图变色了,因为opencv读取进来的是BGR顺序呢的,而imshow需要的是RGB顺序,因此需要把cv2读的顺序转成RGB顺序

第一种方法:


   
   
  1. b,g,r = cv2.split(img)
  2. img = cv2.merge([r,g,b])

   
   
  1. img = cv2.imread(img_path)
  2. #=======================
  3. #convert BGR to RGB
  4. b,g,r = cv2.split(img)
  5. img = cv2.merge([r,g,b])
  6. #========================
  7. plt.title( 'cv2_RGB')
  8. plt.imshow(img)
  9. plt.show()

第二种方法:

img= img[:,:,::-1]
   
   

   
   
  1. img = cv2.imread(img_path)
  2. #=======================
  3. #convert BGR to RGB
  4. img = img[:,:,::- 1]
  5. #========================
  6. plt.title( 'cv2_RGB')
  7. plt.imshow(img)
  8. 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")

===============================================================================================

2. PIL.Image / numpy.ndarray与Tensor的相互转换

以上就是图像的基本操作,为了方便进行图像数据的操作,pytorch团队提供了一个torchvision.transforms包,我们可以用transforms进行以下操作:

  • PIL.Image / numpy.ndarray与Tensor的相互转化;
  • 归一化;
  • 对PIL.Image进行裁剪、缩放等操作。

通常,在使用torchvision.transforms,我们通常使用transforms.Compose将transforms组合在一起。

  • 1)PIL.Image / numpy.ndarray与Tensor的相互转化

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]:

  • 取值范围为[0, 255]的PIL.Image,转换成形状为[C, H, W],取值范围是[0, 1.0]的torch.FloadTensor;
  • 形状为[H, W, C]的numpy.ndarray,转换成形状为[C, H, W],取值范围是[0, 1.0]的torch.FloadTensor。

而transforms.ToPILImage则是将Tensor转化为PIL.Image。如果,我们要将Tensor转化为numpy,只需要使用 .numpy() 即可。如下:


  
  
  1. import torchvision
  2. import torchvision.transforms as transforms
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. img_path = 'your graph path'
  6. # transforms.ToTensor()
  7. transform1 = transforms.Compose([
  8. transforms.ToTensor(), # range [0, 255] -> [0.0,1.0] and convert [H,W,C] to [C,H,W]
  9. ])
  10. img = plt.imread(img_path)
  11. print( 'plt',img.shape) #(H,W,C)
  12. img = transform1(img) # 归一化到 [0.0,1.0],并转成[C,H,W]
  13. print(img.shape) #torch.Size([C,H,W])
  14. # 转化为numpy.ndarray并显示
  15. img_arr = img.numpy() * 255 #use np.numpy(): convert Tensor to numpy
  16. img_arr = img_arr.astype( 'uint8') #convert Float to Int
  17. print(img_arr.shape) #[C,H,W]
  18. img_new = np.transpose(img_arr, ( 1, 2, 0)) #use np.transpose() convert [C,H,W] to [H,W,C]
  19. plt.imshow(img_new)
  20. plt.show()
  • 2)归一化

归一化对神经网络的训练是非常重要的,那么我们如何归一化到[-1.0, -1.0]呢?只需要将上面的transform1改为如下所示:


  
  
  1. #归一化
  2. transform2 = transforms.Compose([
  3. transforms.ToTensor(),
  4. transforms.Normalize(mean = ( 0.5, 0.5, 0.5), std = ( 0.5, 0.5, 0.5))
  5. ]
  6. )

(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.故出现上面失真情况。

  • 3)PIL.Image的缩放裁剪等操作

此外,transforms还提供了裁剪,缩放等操作,以便进行数据增强。下面就看一个随机裁剪的例子,这个例子中,仍然使用 Compose 将 transforms 组合在一起,如下:


  
  
  1. transform4 = transforms.Compose([
  2. transforms.ToTensor(),
  3. transforms.ToPILImage(),
  4. transforms.RandomCrop(( 300, 300)),
  5. ])
  6. img = Image. open(img_path).convert( 'RGB')
  7. img3 = transform4(img)
  8. img3.show()

运行结果如下:

其他操作就不一一列举了。具体看http://pillow.readthedocs.io/en/5.2.x/handbook/tutorial.html#cutting-pasting-and-merging-images

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐享时分

你觉得有价值的话再打赏谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值