python的便捷是如此的引人着迷,而opencv給python提供的接口使我們能夠使用python來快速驗證我們的想法,或者與別的模塊快速結合,在這個系列文章我會通過jupyter notebook來快速展示opencv的使用
#在開頭引入必要的庫
import matplotlib.pyplot as plt
import numpy as np
import cv2
#ipython
%matplotlib inline
圖像讀取
opencv使用imread讀取圖片,imshow顯示圖片,但是對於我而言,常使用jupyter作為展示的工具,imshow在瀏覽器環境中就失去了它的作用,因此我會使用matplotlib來展示
#讀取一張圖片
cv2.imread(img,flag)
#img這一參數中填入圖片的完全路徑或者相對路徑
這里我們需要稍微了解下flag這個參數,這決定了opencv是如何讀入我們的圖像的
我們知道通常圖像每個像素點的顏色我們以RGB的格式來描述(或者RGBA),可以通過三基色(red,green,blue)來描述所有顏色,對於透明圖片我們會增加一個a(alpha)來描述其顏色的透明度.
cv2.IMREAD_COLOR : 讀入圖片,任何與透明度相關通道的會被忽視,默認以這種方式讀入.
cv2.IMREAD_GRAYSCALE : 以灰度圖的形式讀入圖片.
cv2.IMREAD_UNCHANGED : 保留讀取圖片原有的顏色通道.
可以簡單的用-1,0,1來分別表示這3個flag
就讓我們從著名的lenna圖開始吧
lenna_img = cv2.imread("lena.jpg")
plt.imshow(lenna_img)
plt.axis("off")#去除坐標軸
plt.show()

當把這張圖片打印出來后,你一定在疑惑,咦,這張圖怎么變青色了?
原因就在於opencv默認的imread是以BGR的方式進行存儲的,而matplotlib的imshow默認則是以RGB格式展示,所以此處我們必須對圖片的通道進行轉換
lenna_img = cv2.cvtColor(lenna_img,cv2.COLOR_BGR2RGB)
plt.imshow(lenna_img)
plt.axis("off")
plt.show()

Lenna終於恢復了她的本來樣子了
這里我們了解一下cvtColor這個函數,它的第一個參數是圖片,第二個參數則是顏色通道的轉化方式
它的命名是有規律的通常以COLOR作為開頭,后面則跟着它的轉化方式,BGR通道轉化為RGB,因此就是cv2.COLOR_BGR2RGB
你可以試着猜測從RGB通道轉化為BGR通道的api名,通過補全驗證你的想法
我們在剛剛使用了默認的flag讀入了圖片,那么讓我們用用另外兩個試試效果
gray_lenna_img = cv2.imread("lena.jpg",0)
orign_lenna_img = cv2.imread("lena.jpg",1)
plt.subplot(121)
plt.imshow(gray_lenna_img,cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(122)
orign_lenna_img = cv2.cvtColor(orign_lenna_img,cv2.COLOR_BGR2RGB)
plt.imshow(orign_lenna_img)
plt.axis("off")
plt.show()

因為lenna圖並沒有包含透明度這一通道,讀入的仍然是BGR格式,所以我們從lenna圖是看不出區別的
圖片在python下的儲存方式
opencv的一個Image對象在python和C++下的存儲方式是不同的,在c++下,通過opencv實現的Mat來進行存儲,而python下則基於numpy
numpy對於使用python進行科學計算的人都不算陌生,它為python提供了一個高效的矩陣運算模塊.
這就意味着我們可以直接使用numpy的api對圖片進行計算和處理.
print("Lenna圖在python中存儲的類型為",type(lenna_img))
print("讀入lenna圖的shape為",lenna_img.shape)
print("以灰白圖讀入lenna圖的shape為",gray_lenna_img.shape)
#Lenna圖在python中存儲的類型為 <class 'numpy.ndarray'>
#讀入lenna圖的shape為 (512, 512, 3)
#以灰白圖讀入lenna圖的shape為 (512, 512)
上文實現的bgr裝RGB我們也可以使用numpy來輕松的實現
lenna_img = cv2.imread("lena.jpg")
b,g,r = cv2.split(lenna_img)
lenna_img = cv2.merge([r,g,b])
plt.imshow(lenna_img)
plt.axis("off")
plt.show()
#結果如下

我們可以對之前的函數進行一些包裝,畢竟每次都要設定坐標軸為off怎么也會厭煩的啊
def show_cv_img(cv_image):
image = cv2.cvtColor(cv_image,cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.axis("off")
考慮到subplot此處沒有直接plt.show
show_cv_img(cv2.imread("lena.jpg"))#jupyter result

圖片的展示與存儲
雖然說我們通常使用jupyter來使用opencv,但還是要了解下opencv默認的imshow
img = cv2.imread("lenna.jpg")
cv2.namedWindow('image', cv2.WINDOW_NORMAL)#給顯示的窗口命名,后面的flag默認為cv2.WINDOW_AUTOSIZE,自動調整邊框
#,但是在條形圖過長時,使用windownormal我們可以自行調整邊框
cv2.imshow('image',img)#展示圖片
cv2.waitKey(0)#等待按鍵按下
cv2.destroyAllWindows()#清除所有窗口
我們可以使用imwrite來存儲一張圖片,接受一個numpy的數組作為參數.
cv2.imwrite('cope_lenna_img.jpg',lenna_img)
#result: True
他會返回一個bool值來表示它是否成功存儲.
我們成功在當前目錄存儲了一個叫做copy_lenna_img.jpg的圖像.
Warning:
注意后綴.你的后綴是jpg還是png決定它以怎樣的方式保存
Opencv對於圖像的讀入和存儲都已經封裝好了給我們,是我們能夠輕松的讀入,存儲,避免去了解圖片文件的格式才能讀取,存儲圖片,但僅僅這樣顯然不是opencv的真正面目,還不如直接用pillow呢.
那么Opencv到底NB在哪里呢?
