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
一、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()
第一排从左到右分别是bgr通道的灰度图像,第二排从左到右分别是rgb各通道的图像
原图
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()
第一排自左到右为rgb通道的灰度图像,第二排自左到右为rgb通道的图像
matplotlib显示的图像
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的图像读取
使用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)
<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.Tensor
与numpy.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()
左边为原始图像,右边为从numpy-&amp;amp;gt;tensor-&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