OpenCV 是基於 C/C++,用於處理圖像,opencv-python
是它的 Python 封裝版本,它是基於 NumPy,若能有對 NumPy 的認識,並遵照陣列程式設計典範,就能獲得便利性與效能,無論如何,先來個基本的圖片讀取與顯示:
import cv2
img = cv2.imread('caterpillar.jpg')
cv2.imshow('caterpillar', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
這邊看到匯入了 cv2
,2 並不是指 OpenCV 的版本號,而是指底層是 C++ API,過去的 cv
表示基於 C API。
cv2.imread
用於讀取圖片,傳回具有 NumPy 陣列行為的物件,若只是要顯示圖片,可以透過 cv2.imshow
,第一個參數用來指定視窗標題文字,預設它會自動根據圖片調整視窗大小,若想自由縮放視窗,可以透過 cv2.namedWindow
,這個函式預設是 cv2.WINDOW_AUTOSIZE
,表示自動調整視窗大小,若指定 cv2.WINDOW_NORMAL
,就可以自由調整視窗大小。
cv2.imshow
並不會阻斷流程執行,為了不因為執行結束就關閉視窗,這邊使用了 cv2.waitKey
,表示等待使用者按下按鍵,可以指定等待時間,指定為 0 的話表示不限制等待時間,cv2.waitKey
會傳回按下的按鍵編碼,若指定的時間到又沒按下任何鍵,會傳回 -1。
cv2.destroyAllWindows
會關閉全部視窗,若想指定特定視窗,可以使用 cv2.destroyWindow
指定標題文字。
以下是執行結果:
cv2.imread
的預設值是 cv2.IMREAD_COLOR
,會讀取圖片的 RGB,然而忽略透明度,傳回的是具有三維的 NumPy 陣列行為的物件,圖片使用的是電腦繪圖座標,因此 y 往下為正,x 往右為正,軸 0 用來指定圖片像素的 y 索引,軸 1 用來指定圖片像素的 x 索引,若是讀取了圖片的 RGB,軸 2 用來指定像素的 BGR 欄位索引(不是 RGB!),上圖是個 250x250 的圖片,因此傳回的陣列形狀是 (250, 250, 3),若顯示字串描述,會像是:
[[[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]]]
只要取出部份的陣列內容,就可以達到裁剪圖片的效果,自行使用迴圈雖然可以達到目的,然而善用一下〈NumPy 陣列索引〉,既方便又能兼顧效能:
import cv2
top = 50
left = 50
right = 200
bottom = 200
img = cv2.imread('caterpillar.jpg')
cv2.imshow('caterpillar', img[top:bottom, left:right])
cv2.waitKey(0)
cv2.destroyAllWindows()
顯示的圖片如下:
既然改變陣列可以控制圖片,那麼若轉置 y 與 x 的像素,就能達到翻轉圖片的效果:
import cv2
img = cv2.imread('caterpillar.jpg')
cv2.imshow('caterpillar', img.transpose((1, 0, 2)))
cv2.waitKey(0)
cv2.destroyAllWindows()
transpose
是 NumPy 陣列的方法(也可以透過 numpy.transpose
),必須指定 axes
參數,代表著哪些軸要轉置,上例的圖片顯示為:
若是灰階圖片,可以簡單地透過 .T
轉置,因為 cv2.imread
會傳回二維陣列,例如:
import cv2
img = cv2.imread('caterpillar.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('caterpillar', img.T)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.IMREAD_GRAYSCALE
指定以灰階格式讀取圖片,傳回的陣列形狀會是 (250, 250),每個元素代表著灰階值,例如顯示其字串描述的話會是:
[[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]]
因為是二維陣列,透過 .T
就可以得到轉置矩陣,範例的顯示如下:
以上範例都是翻轉圖片的效果,如果只是要旋轉呢?NumPy 有 rot90
函式,OpenCV 有 rotate
方法,都可以用來旋轉圖片:
import cv2
import numpy as np
img = cv2.imread('caterpillar.jpg')
# 或使用 cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE))
cv2.imshow('caterpillar', np.rot90(img))
cv2.waitKey(0)
cv2.destroyAllWindows()
執行結果如下:
這邊主要是著重在 OpenCV 與 NumPy 的關係,當然,OpenCV 還有其他處理圖片的方式,這就之後有機會遇到再來談了。