原文链接:https://www.cnblogs.com/skyfsm/p/8276501.html
最近在研究深度学习视觉相关的东西,经常需要写python代码搭建深度学习模型。比如写CNN模型相关代码时,我们需要借助python图像库来读取图像并进行一系列的图像处理工作。我最常用的图像库当然是opencv,很强大很好用,但是opencv也有一些坑,不注意的话也会搞出大麻烦。近期我也在看一些别人写的代码,因为个人习惯不一样,他们在做深度学习时用于图片读取的图像库各不相同,从opencv到PIL再到skimage等等各种库都有,有些库读进来的图片存储方式也不太一样,如果不好好总结这些主流图像读写库特点的话,以后看代码写代码都会遇坑无数。这篇文章就总结了以下主流Python图像库的一些基本使用方法和需要注意的地方:
- opencv
- PIL(pillow)
- matplotlib.image
- scipy.misc
- skimage
opencv: cv2.imread
opencv作为我最常用的图像处理库,当然第一个介绍,并且介绍得比较全面。毋庸置疑,opencv是今天介绍得所有图像库中最全面也最强大的库,如果我们只想掌握一个图像库,我觉得opencv库肯定是最适合不过了。
图片读取操作
import cv2
import numpy as np
img = cv2.imread(‘1.jpg’)
cv2.imshow(‘src’,img)
print(img.shape)
print(img.size)
print(img.dtype)
print(img)
cv2.waitKey()
![](https://i-blog.csdnimg.cn/blog_migrate/3f3834ebf3c9d7aaaeb2619e02c33a88.png)
![](https://i-blog.csdnimg.cn/blog_migrate/904083d8b4dfca69877dffce3f3fdce8.png)
值得注意的是,opencv读进来的图片已经是一个numpy矩阵了,彩色图片维度是(高度,宽度,通道数)。数据类型是uint8。
#gray = cv2.imread('1.jpg',cv2.IMREAD_GRAYSCALE)
#cv2.imshow('gray',gray)
#也可以这么写,先读入彩色图,再转灰度图
src = cv2.imread('1.jpg')
gray = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
cv2.imshow('gray',gray)
print(gray.shape)
print(gray.size)
print(gray)
cv2.waitKey()
![](https://i-blog.csdnimg.cn/blog_migrate/9f0d0f8464040b13f66957d9b0658cb9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/db25ccb124b0b3993cbedf97a38fe1ad.png)
上面提到了两种获取灰度图的方式,读进来的灰度图的矩阵格式是(高度,宽度)。
#注意,计算图片路径是错的,Opencv也不会提醒你,但print img时得到的结果是None
img2 = cv2.imread('2.jpg')
print(img2)
![](https://i-blog.csdnimg.cn/blog_migrate/6d8e20a2bfa0a08161edcecab296560e.png)
img2 = cv2.imread('2.jpg')
if img2 == None:
print('fail to load image!')
![](https://i-blog.csdnimg.cn/blog_migrate/ec057103e9b51270dc72fd61a70cba50.png)
图片矩阵变换
opencv读入图片的矩阵格式是:(height,width,channels)。而在深度学习中,因为要对不同通道应用卷积,所以会采取另一种方式:(channels,height,width)。为了应对该要求,我们可以这么做
print(img.shape)
img = img.transpose(2,0,1)
print(img.shape)
![](https://i-blog.csdnimg.cn/blog_migrate/2c27642906e06645d54d2eaa032f43b4.png)
在深度学习搭建CNN时,往往要做相应的图像数据处理,比如图像要扩展维度,比如扩展成(batch_size,channels,height,width)。
对于这种要求,我们可以这么做。
img = np.expand_dims(img, axis=0)
print(img.shape)
![](https://i-blog.csdnimg.cn/blog_migrate/6288b96e928480c09e05dc7fd6de9503.png)
上面提到的是预测阶段时预测单张图片的扩展维度的操作,如果是训练阶段,构建batch,即得到这种形式:(batch_size,channels,height,width)。我一般喜欢这么做
data_list = []
loop:
im = cv2.imread('xxx.png')
data_list.append(im)
data_arr = np.array(data_list)
这样子就能构造成我们想要的形式了。
图片归一化
img3 = cv2.imread('1.jpg')
img3 = img3.astype("float") / 255.0
print(img3.dtype)
print(img3)
![](https://i-blog.csdnimg.cn/blog_migrate/6ded5d41fa325e9114148b00db1967fb.png)
存储图片
cv2.imwrite('test1.jpg',img3)
img3 = img3 * 255
cv2.imwrite('test2.jpg',img3)
opencv大坑之BGR
opencv对于读进来的图片的通道排列是BGR,而不是主流的RGB!谨记!
img4 = cv2.imread('1.jpg')
img4 = cv2.cvtColor(img4,cv2.COLOR_BGR2RGB)
访问像素
print(img4[10,10])
print(gray[10,10])
img4[10,10] = [255,255,255]
gray[10,10] = 255
print(img4[10,10])
print(gray[10,10])
![](https://i-blog.csdnimg.cn/blog_migrate/16d6a16edf8348916d5b478184bc9fda.png)
ROI操作
roi = img4[200:550,100:450,:]
cv2.imshow('roi',roi)
cv2.waitKey()
![](https://i-blog.csdnimg.cn/blog_migrate/f19ed772c92d16e7c821bf28488087e8.png)
通道操作
img5 = cv2.imread('1.jpg')
b,g,r = cv2.split(img5)
img5 = cv2.merge((b,g,r))
img5[:,:,2] = 0 #将红色通道值全部设0
PIL:PIL.Image.open
图片读取
from PIL import Image
import numpy as np
PIL即Python Imaging Library,也即为我们所称的Pillow,是一个很流行的图像库,它比opencv更为轻巧,正因如此,它深受大众的喜爱。
图像读写
PIL读进来的图像是一个对象,而不是我们所熟知的numpy 矩阵。
img = Image.open('1.jpg')
print(img.format)
print(img.size)
print(img.mode)
img.show()
![](https://i-blog.csdnimg.cn/blog_migrate/f275dddd0c00ef7c45617c0dc404fe53.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ba32938150e70f89feb4f440988ab10d.png)
灰度图的获取
gray = Image.open('1.jpg').convert('L')
gray.show()
![](https://i-blog.csdnimg.cn/blog_migrate/05eef3981d1a50eab1ae6ddbc564a0aa.png)
try:
img2 = Image.open('2.jpg')
except IOError:
print('fail to load image!')
![](https://i-blog.csdnimg.cn/blog_migrate/b1febcb1aed260682947fd73ffd8fcf3.png)
arr = np.array(img3)
print(arr.shape)
print(arr.dtype)
print(arr)
![](https://i-blog.csdnimg.cn/blog_migrate/136f4232ea691cc7c55acca300010a8f.png)
灰度图的转化与彩图转化一样
arr_gray = np.array(gray)
print(arr_gray.shape)
print(arr_gray.dtype)
print(arr_gray)
![](https://i-blog.csdnimg.cn/blog_migrate/4aaf53a0127e4db379fd21847cc1b5a4.png)
存储图片
new_im = Image.fromarray(arr)
new_im.save('3.png')
图像操作
r, g, b = img.split()
img = Image.merge("RGB", (b, g, r))
img = img.copy()
ROI获取
img3 = Image.open('1.jpg')
roi = img3.crop((0,0,300,300))
roi.show()
matplotlib:matplotlib.image.imread
matplotlib是一个科学绘图神器,用的人非常多。
import matplotlib.pyplot as plt
import numpy as np
image = plt.imread('1.jpg')
plt.imshow(image)
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/cfd2263e3228c1b02a1a56a5ec866536.png)
image = plt.imread('1.jpg')
plt.imshow(image)
plt.axis('off')
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/b72299f6a48ae70c3df85bc105733ce9.png)
#plt.imread读入的就是一个矩阵,跟opencv一样,但彩图读进的是RGB,与opencv有区别
print(image.shape) # (h,w,c)
print(image.size)
print(image.dtype)
print(image)
![](https://i-blog.csdnimg.cn/blog_migrate/5763f9df5c0bdc4988f2e2ccf87da6a9.png)
im_r = image[:,:,0]
plt.imshow(im_r)
plt.show()
plt.imshow(im_r,cmap='Greys_r')
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/9e18d302e30a1b1bb5e1fcee139a9b5d.png)
import cv2
im2 = cv2.imread('1.jpg')
plt.imshow(im2)
plt.axis('off')
plt.show()
im2 = cv2.cvtColor(im2,cv2.COLOR_BGR2RGB)
plt.imshow(im2)
plt.axis('off')
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/5ede20d7d81bc28f6457d8dad8cc9159.png)
from PIL import Image
im3 = Image.open('1.jpg')
im3 = np.array(im3)
plt.figure(1)
plt.imshow(im3)
plt.axis('off')
plt.savefig('timo.jpg')
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/a9a013b5380d3541f7b8bb6e848cff82.png)
im_lol1 = plt.imread('lol.jpg')
im_lol2 = plt.imread('1.jpg')
figure = plt.figure(figsize=(20,10))
'''
figsize参数:指定绘图对象的宽度和高度,单位为英寸;dpi参数指定绘图对象的分辨率,
即每英寸多少个像素,缺省值为80。因此本例中所创建的图表窗口的宽度为8*80 = 640像素
'''
plt.axis("off")
ax = figure.add_subplot(121)
plt.axis('off')
ax.imshow(im_lol1)
ax.set_title('lol image 1')
ax = figure.add_subplot(122)
plt.axis('off')
ax.imshow(im_lol2)
ax.set_title('lol image 2')
plt.savefig(‘twp.jpg’)
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/81b2a53cd919764a7f404e8d3d6bb6d9.png)
scipy.misc:scipy.misc.imread
from scipy import misc
import matplotlib.pyplot as plt
im = misc.imread('1.jpg')
print(im.dtype)
print(im.size)
print(im.shape)
misc.imsave('misc1.png',im)
plt.imshow(im)
plt.show()
print(im)
![](https://i-blog.csdnimg.cn/blog_migrate/1980802566b4af04794f6c02fa1efab6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0f5ed7a9af29a887bf16805e70f07480.png)
可以看到,有warining,提示我们imread和imsave在后来的版本将会被弃用,叫我们使用imageio.imread和imageio.imwrite。
我们根据她的提示,使用imageio模块进行图片读写,warning也就没有了。
import imageio
im2 = imageio.imread('1.jpg')
print(im2.dtype)
print(im2.size)
print(im2.shape)
plt.imshow(im)
plt.show()
print(im2)
imageio.imsave('imageio.png',im2)
![](https://i-blog.csdnimg.cn/blog_migrate/1049ce58636609d4049a9c7603f310f6.png)
skimage:skimage.io.imread
from skimage import io
im = io.imread(‘1.jpg’)
print(im.shape) # numpy矩阵,(h,w,c)
print(im.dtype)
print(im.size)
io.imshow(im)
io.imsave(‘sk.png’,im)
print(im)
![](https://i-blog.csdnimg.cn/blog_migrate/bcd0dafea7274794bc7dc59a8d8fcce5.png)
图像也是以numpy array形式读入。
灰度图的获取方式:
im2 = io.imread('1.jpg',as_grey=True) #读入灰度图
print(im2.dtype)
print(im2.size)
print(im2.shape)
io.imshow(im2)
io.imsave('sk_gray.png',im2)
io.show()
print(im2)
![](https://i-blog.csdnimg.cn/blog_migrate/d67a038d65ea64cf416988dfc7202790.png)
可以看到,灰度图像的矩阵的值被归一化了,注意注意!
也可以以这种方式获得灰度图:
from skimage import color
im3 = io.imread('1.jpg')
im3 = color.rgb2grey(im3)
print(im3.dtype)
print(im3.size)
print(im3.shape)
io.imshow(im3)
io.show()
‘’’
skimage.color.rgb2grey(rgb)
skimage.color.rgb2hsv(rgb)
skimage.color.rgb2lab(rgb)
skimage.color.gray2rgb(image)
skimage.color.hsv2rgb(hsv)
skimage.color.lab2rgb(lab)
‘’’
![](https://i-blog.csdnimg.cn/blog_migrate/4b3eb2c736dd64acc8017178ecc13592.png)
总结
- 除了opencv读入的彩色图片以BGR顺序存储外,其他所有图像库读入彩色图片都以RGB存储。
- 除了PIL读入的图片是img类之外,其他库读进来的图片都是以numpy 矩阵。
- 各大图像库的性能,老大哥当属opencv,无论是速度还是图片操作的全面性,都属于碾压的存在,毕竟他是一个巨大的cv专用库。下面那张图就是我从知乎盗来的一张关于各个主流图像库的一些性能比较图,从测试结果看来,opencv确实胜出太多了。
![](https://i-blog.csdnimg.cn/blog_migrate/883ad7e8c4f4899405ba2a959e26a572.jpeg)