Python各種圖像庫的圖片讀寫方式總結

最近在研究深度學習視覺相關的東西,常常須要寫python代碼搭建深度學習模型。好比寫CNN模型相關代碼時,咱們須要藉助python圖像庫來讀取圖像並進行一系列的圖像處理工做。我最經常使用的圖像庫固然是opencv,很強大很好用,可是opencv也有一些坑,不注意的話也會搞出大麻煩。近期我也在看一些別人寫的代碼,由於我的習慣不同,他們在作深度學習時用於圖片讀取的圖像庫各不相同,從opencv到PIL再到skimage等等各類庫都有,有些庫讀進來的圖片存儲方式也不太同樣,若是很差好總結這些主流圖像讀寫庫特色的話,之後看代碼寫代碼都會遇坑無數。這篇文章就總結了如下主流Python圖像庫的一些基本使用方法和須要注意的地方:python

  1. opencv
  2. PIL(pillow)
  3. matplotlib.image
  4. scipy.misc
  5. skimage

opencv: cv2.imread

opencv做爲我最經常使用的圖像處理庫,固然第一個介紹,而且介紹得比較全面。毋庸置疑,opencv是今天介紹得全部圖像庫中最全面也最強大的庫,若是咱們只想掌握一個圖像庫,我以爲opencv庫確定是最適合不過了。app

圖片讀取操做

import cv2
import numpy as np

#讀入圖片:默認彩色圖,cv2.IMREAD_GRAYSCALE灰度圖,cv2.IMREAD_UNCHANGED包含alpha通道
img = cv2.imread('1.jpg')
cv2.imshow('src',img)
print(img.shape) # (h,w,c)
print(img.size) # 像素總數目
print(img.dtype)
print(img)
cv2.waitKey()

值得注意的是,opencv讀進來的圖片已是一個numpy矩陣了,彩色圖片維度是(高度,寬度,通道數)。數據類型是uint8。oop

#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()

上面提到了兩種獲取灰度圖的方式,讀進來的灰度圖的矩陣格式是(高度,寬度)。性能

#注意,計算圖片路徑是錯的,Opencv也不會提醒你,但print img時獲得的結果是None
img2 = cv2.imread('2.jpg')
print(img2)

#如何解決「讀到的圖片不存在的問題」? #加入判斷語句,若是爲空,作異常處理
img2 = cv2.imread('2.jpg')
if img2 == None:
    print('fail to load image!')

圖片矩陣變換

opencv讀入圖片的矩陣格式是:(height,width,channels)。而在深度學習中,由於要對不一樣通道應用卷積,因此會採起另外一種方式:(channels,height,width)。爲了應對該要求,咱們能夠這麼作學習

#注意到,opencv讀入的圖片的彩色圖是一個channel last的三維矩陣(h,w,c),即(高度,寬度,通道)
#有時候在深度學習中用到的的圖片矩陣形式多是channel first,那咱們能夠這樣轉一下
print(img.shape)
img = img.transpose(2,0,1)
print(img.shape)

在深度學習搭建CNN時,每每要作相應的圖像數據處理,好比圖像要擴展維度,好比擴展成(batch_size,channels,height,width)。測試

對於這種要求,咱們能夠這麼作。ui

#有時候還要擴展維度,好比有時候咱們須要預測單張圖片,要在要加一列作圖片的個數,能夠這麼作
img = np.expand_dims(img, axis=0)
print(img.shape)

上面提到的是預測階段時預測單張圖片的擴展維度的操做,若是是訓練階段,構建batch,即獲得這種形式:(batch_size,channels,height,width)。我通常喜歡這麼作3d

data_list = [] 
loop:
    im = cv2.imread('xxx.png')
    data_list.append(im)
data_arr = np.array(data_list)

這樣子就能構形成咱們想要的形式了。code

圖片歸一化

#由於opencv讀入的圖片矩陣數值是0到255,有時咱們須要對其進行歸一化爲0~1
img3 = cv2.imread('1.jpg')
img3 = img3.astype("float") / 255.0  #注意須要先轉化數據類型爲float
print(img3.dtype)
print(img3)

存儲圖片

#存儲圖片
cv2.imwrite('test1.jpg',img3) #獲得的是全黑的圖片,由於咱們把它歸一化了
#因此要獲得可視化的圖,須要先*255還原
img3 = img3 * 255
cv2.imwrite('test2.jpg',img3)  #這樣就能夠看到彩色原圖了

opencv大坑之BGR

opencv對於讀進來的圖片的通道排列是BGR,而不是主流的RGB!謹記!orm

#opencv讀入的矩陣是BGR,若是想轉爲RGB,能夠這麼轉
img4 = cv2.imread('1.jpg')
img4 = cv2.cvtColor(img4,cv2.COLOR_BGR2RGB)

訪問像素

#訪問像素
print(img4[10,10])  #3channels
print(gray[10,10]) #1channel
img4[10,10] = [255,255,255]
gray[10,10] = 255
print(img4[10,10])  #3channels
print(gray[10,10]) #1channel

ROI操做

#roi操做
roi = img4[200:550,100:450,:]
cv2.imshow('roi',roi)
cv2.waitKey()

通道操做

#分離通道
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) #注意,省略了通道 (w,h)
print(img.mode)  #L爲灰度圖,RGB爲真彩色,RGBA爲加了透明通道
img.show() # 顯示圖片

灰度圖的獲取

gray = Image.open('1.jpg').convert('L')
gray.show()

#讀取不到圖片會拋出異常IOError,咱們能夠捕捉它,作異常處理
try:
    img2 = Image.open('2.jpg')
except IOError:
    print('fail to load image!')

#pillow讀進來的圖片不是矩陣,咱們將圖片轉矩陣,channel last
arr = np.array(img3)
print(arr.shape)
print(arr.dtype)
print(arr)

灰度圖的轉化與彩圖轉化同樣

arr_gray = np.array(gray)
print(arr_gray.shape)
print(arr_gray.dtype)
print(arr_gray)

存儲圖片

#矩陣再轉爲圖像
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)) #(左上x,左上y,右下x,右下y)座標
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()

#也能夠關閉顯示x,y軸上的數字
image = plt.imread('1.jpg')
plt.imshow(image)
plt.axis('off')
plt.show()

#plt.imread讀入的就是一個矩陣,跟opencv同樣,但彩圖讀進的是RGB,與opencv有區別
print(image.shape) # (h,w,c)
print(image.size)
print(image.dtype) 
print(image)

im_r = image[:,:,0] #紅色通道
plt.imshow(im_r)
plt.show()
#此時會發現顯示的是熱量圖,不是咱們預想的灰度圖,能夠添加 cmap 參數解決
plt.imshow(im_r,cmap='Greys_r')
plt.show()

#與opencv結合使用
import cv2
im2 = cv2.imread('1.jpg')
plt.imshow(im2)
plt.axis('off')
plt.show()
#發現圖像顏色怪怪的,緣由固然是咱們前面提到的RGB順序不一樣的緣由啦,轉一下就好
im2 = cv2.cvtColor(im2,cv2.COLOR_BGR2RGB)
plt.imshow(im2)
plt.axis('off')
plt.show()
#因此不管用什麼庫讀進圖片,只要把圖片改成矩陣,那麼matplotlib就能夠處理了

#再試一試pillow和matplotlib結合
from PIL import Image
im3 = Image.open('1.jpg')
im3 = np.array(im3)
plt.figure(1)
plt.imshow(im3)
plt.axis('off')
#存儲圖像,注意,必須在show以前savefig,不然存儲的圖片一片空白
plt.savefig('timo.jpg')
plt.show()

#最後以一個綜合例子總結matplotlib最基本的圖片顯示技巧吧
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) # 圖片以1行2列的形式顯示
plt.axis('off')
ax.imshow(im_lol1) #第一張圖
ax.set_title('lol image 1')#給圖片加titile 
ax = figure.add_subplot(122) 
plt.axis('off')
ax.imshow(im_lol2) 
ax.set_title('lol image 2')#給圖片加titile 

plt.savefig('twp.jpg')
plt.show()

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)

能夠看到,有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)

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)

圖像也是以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)

能夠看到,灰度圖像的矩陣的值被歸一化了,注意注意!

也能夠以這種方式得到灰度圖:

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)

'''

總結

  1. 除了opencv讀入的彩色圖片以BGR順序存儲外,其餘全部圖像庫讀入彩色圖片都以RGB存儲。
  2. 除了PIL讀入的圖片是img類以外,其餘庫讀進來的圖片都是以numpy 矩陣。
  3. 各大圖像庫的性能,老大哥當屬opencv,不管是速度仍是圖片操做的全面性,都屬於碾壓的存在,畢竟他是一個巨大的cv專用庫。下面那張圖就是我從知乎盜來的一張關於各個主流圖像庫的一些性能比較圖,從測試結果看來,opencv確實勝出太多了。

相關文章
相關標籤/搜索