opencv,Pillow,matplotlib是目前比较常用的一些图像的标准库

  • opencv文档:OpenCV-Python Tutorials
  • Pillow文档:Pillow (PIL Fork) 7.1.1 documentation
  • matplotlib文档:Python plotting - Matplotlib 3.2.1 documentation

对于Pillow的使用踩坑,import Pillow失败,No module named 'Pillow',参照如下文章:


HUST小菜鸡:No module named 'Pillow'zhuanlan.zhihu.com


pillow和opencv区别_pillow和opencv区别


一、opencv图像的读取


import cv2
img = cv2.imread('img.jpg')
print('img_shape',img.shape)     #读取数据的形状
print('img_size',img.size)       #读取数据的大小
print('img_dtype',img.dtype)     #读取数据的编码格式
print('img',img)                 #打印img数据
print('img_type',type(img))      #读取img的数据类型

b, g, r = cv2.split(img)    #通道分离
# print(img.shape[:2])
zeros = np.zeros(img.shape[:2],dtype='uint8')
merge_r = cv2.merge([r,zeros,zeros])
merge_g = cv2.merge([zeros,g,zeros])
merge_b = cv2.merge([zeros,zeros,b])

plt.subplot(231);plt.imshow(b)
plt.subplot(232);plt.imshow(g)
plt.subplot(233);plt.imshow(r)
plt.subplot(234);plt.imshow(merge_r)
plt.subplot(235);plt.imshow(merge_g)
plt.subplot(236);plt.imshow(merge_b)
plt.show()

cv2.imshow('img',img)   #显示图片
cv2.waitKey(0)
cv2.destroyAllWindows()


pillow和opencv区别_pillow和opencv区别_02

第一排从左到右分别是bgr通道的灰度图像,第二排从左到右分别是rgb各通道的图像


pillow和opencv区别_pillow和opencv区别_03

原图

D:Setuppythonpython.exe D:/Pycharm/bboxe_context/test.py
img_shape (480, 640, 3)
img_size 921600
img_dtype uint8
img [[[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ...

 [[ 41  95 102]
  [ 60 118 117]
  [ 96 164 157]
  ...
  [ 20 113  86]
  [ 16 103  93]
  [  9 120 106]]

 [[ 27  92 107]
  [ 93 157 162]
  [ 74 153 140]
  ...
  [ 45 118  92]
  [  6  71  46]
  [  8  88  45]]

 [[ 21 126 117]
  [ 72 145 149]
  [ 62 136 136]
  ...
  [ 42 122  79]
  [ 23 120  76]
  [ 18  80  66]]]

img_type <class 'numpy.ndarray'>

Process finished with exit code 0


由打印的数据结果可知及查阅资料可知,opencv读取的图像的通道顺序为BGR,读取的数据类型为numpy.ndarray,取值范围为[0,255],数据元素类型为uint8.

二、matplotlib


import cv2
import matplotlib.pyplot as plt
img = plt.imread('img.jpg')
print('img_shape',img.shape)     #读取数据的形状
print('img_size',img.size)       #读取数据的大小
print('img_dtype',img.dtype)     #读取数据的编码格式
print('img',img)                 #打印img数据
print('img_type',type(img))      #读取img的数据类型

r, g, b = cv2.split(img)    #通道分离
# print(img.shape[:2])
zeros = np.zeros(img.shape[:2],dtype='uint8')
merge_r = cv2.merge([r,zeros,zeros])
merge_g = cv2.merge([zeros,g,zeros])
merge_b = cv2.merge([zeros,zeros,b])

plt.subplot(231);plt.imshow(r)
plt.subplot(232);plt.imshow(g)
plt.subplot(233);plt.imshow(b)
plt.subplot(234);plt.imshow(merge_r)
plt.subplot(235);plt.imshow(merge_g)
plt.subplot(236);plt.imshow(merge_b)
plt.show()

plt.imshow(img)
plt.show()

cv2.imshow('img',img)   #显示图片
cv2.waitKey(0)
cv2.destroyAllWindows()


pillow和opencv区别_pillow和opencv区别_04

第一排自左到右为rgb通道的灰度图像,第二排自左到右为rgb通道的图像

pillow和opencv区别_pillow和opencv区别_05

matplotlib显示的图像

pillow和opencv区别_pillow和opencv区别_06

opencv显示plt读取的img的图像

对比两者可以看出图像的色彩明显不对,是因为通道顺序不对


img_shape (480, 640, 3)
img_size 921600
img_dtype uint8
img [[[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ...

 [[102  95  41]
  [117 118  60]
  [157 164  96]
  ...
  [ 86 113  20]
  [ 93 103  16]
  [106 120   9]]

 [[107  92  27]
  [162 157  93]
  [140 153  74]
  ...
  [ 92 118  45]
  [ 46  71   6]
  [ 45  88   8]]

 [[117 126  21]
  [149 145  72]
  [136 136  62]
  ...
  [ 79 122  42]
  [ 76 120  23]
  [ 66  80  18]]]
img_type <class 'numpy.ndarray'>


由打印的结果可以看出,matplotlib读取的图像的通道顺序为RGB,读取的数据类型为numpy.ndarray,取值范围为[0,255],数据元素类型为uint8。


以上分析了opencv和matplotlib的图像读取,可以看出通道顺序存在明显的差别

(读取的结果详细见上述的print(img)返回的结果)


plt.imshow(img)
plt.show()

img_cv = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)

cv2.imshow('img',img_cv)   #显示图片
cv2.waitKey(0)
cv2.destroyAllWindows()


通道变换后,两个图像都正常显示没有差别


pillow和opencv区别_pillow和opencv区别_07


pillow和opencv区别_pillow和opencv区别_08


三、Pillow的图像读取

使用pip安装Pillow。Pillow是从PIL fork过来的Python 图片库。


from PIL import Image

im = Image.open('img.jpg')
print(im)
print('PIL_im_mode & type:',im.mode,type(im.mode))          #读取im的图片模式
print('PIL_im_size & type:',im.size,type(im.size))          #读取im的图片尺寸
print('PIL_im_height & type:',im.height,type(im.height))      #读取im的图片高度
print('PIL_im_width & type:',im.width,type(im.width))        #读取im的图片宽度
print('PIL_im_palette & type:',im.palette,type(im.palette))    #读取im的图片调色板
print('PIL_im_info & type:',im.info,type(im.info))          #读取im的图片有关数据
Image._show(im)


pillow和opencv区别_pillow和opencv区别_09


<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x480 at 0x20624335A48>
PIL_im_mode & type: RGB <class 'str'>
PIL_im_size & type: (640, 480) <class 'tuple'>
PIL_im_height & type: 480 <class 'int'>
PIL_im_width & type: 640 <class 'int'>
PIL_im_palette & type: None <class 'NoneType'>
PIL_im_info & type: {'jfif': 257, 'jfif_version': (1, 1), 'dpi': (72, 72), 'jfif_unit': 1, 'jfif_density': (72, 72)} <class 'dict'>
PIL_im_format & type: JPEG <class 'str'>


由打印的结果可知,PIL读取的图像的数据格式不是一个numpy.ndarray,打印出来的结果是一个物理地址,读取的结果包含mode,size,info,format等属性。

通过np.array可将其转换成numpy.ndarray供后期的处理和使用


from PIL import Image

im = Image.open('img.jpg')
print(im)
img = np.array(im)
img = plt.imread('img.jpg')
print('img_shape',img.shape)     #读取数据的形状
print('img_size',img.size)       #读取数据的大小
print('img_dtype',img.dtype)     #读取数据的编码格式
print('img',img)                 #打印img数据
print('img_type',type(img))      #读取img的数据类型


可以使用opencv等对其处理


<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x480 at 0x19120761CC8>
img_shape (480, 640, 3)
img_size 921600
img_dtype uint8
img [[[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ...

 [[102  95  41]
  [117 118  60]
  [157 164  96]
  ...
  [ 86 113  20]
  [ 93 103  16]
  [106 120   9]]

 [[107  92  27]
  [162 157  93]
  [140 153  74]
  ...
  [ 92 118  45]
  [ 46  71   6]
  [ 45  88   8]]

 [[117 126  21]
  [149 145  72]
  [136 136  62]
  ...
  [ 79 122  42]
  [ 76 120  23]
  [ 66  80  18]]]
img_type <class 'numpy.ndarray'>

Process finished with exit code 0



在用神经网络处理图像的时候,都会将numpy的图像数组转换成tensor的类型,将PIL.Image和numpy.nd (H x W x C),取值范围为[0,255]转换成torch.FloatTensor(C x H x W),取值范围为[0,1]

torch.Tensor 高维矩阵的表示: (nSample)x C x H x W

numpy.ndarray 高维矩阵的表示: H x W x C

在深度学习中,原始图像需要转换为深度学习框架自定义的数据格式,在pytorch中,需要转为torch.Tensor。pytorch提供了torch.Tensornumpy.ndarray转换接口,同时由于矩阵维度不同,还需要使用numpy.transpose( ) 来改变矩阵形状。


torch.from_numpy(   )      #numpy.ndarray转为torch.Tensor

img_tensor.numpy()         #将tensor转为numpy


转换过程如下


import torch
import numpy as np
import matplotlib.pyplot as plt
import cv2

img_orig = cv2.imread('img.jpg')
img = cv2.cvtColor(img_orig,cv2.COLOR_BGR2RGB)
print('orig_img_shape:',img.shape)

img_tensor = torch.from_numpy(np.transpose(img,(2,0,1)))
print('tensor_shape:',img_tensor.shape)

img_numpy = np.transpose(img_tensor.numpy(),(1,2,0))
print('from_tensor2numpy:',img_numpy.shape)

print(img == img_numpy)

plt.subplot(121);plt.imshow(img)
plt.subplot(122);plt.imshow(img_numpy)
plt.show()


pillow和opencv区别_pillow和opencv区别_10

左边为原始图像,右边为从numpy-&amp;amp;amp;gt;tensor-&amp;amp;amp;gt;numpy

D:Setuppythonpython.exe D:/Pycharm/bboxe_context/test.py
orig_img_shape: (480, 640, 3)
tensor_shape: torch.Size([3, 480, 640])
from_tensor2numpy: (480, 640, 3)
[[[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]

 [[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]

 [[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]

 ...

 [[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]

 [[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]

 [[ True  True  True]
  [ True  True  True]
  [ True  True  True]
  ...
  [ True  True  True]
  [ True  True  True]
  [ True  True  True]]]

Process finished with exit code 0