本篇繼續按圖索驥繼續測試 OpenCV 功能, 本系列之前的文章參考 :
OpenCV 官方教學文件 (Python) 參考 :
OpenCV 提供了豐富的函式來處理影像, 下表為圖像讀寫與顯示會用到的函式 :
cv2 圖像處理函式 | 說明 |
imread(file [, mode]) | 以指定模式 mode 開啟檔案 file, 傳回一個代表圖片之 ndarray |
imwrite(file, img [quality]) | 將圖片物件 img 以品質 quality 寫入 file 檔案 (jpg/jpeg, png 等) |
imshow(name, img) | 將圖片物件 img 顯示於名為 name (字串) 的視窗內 |
waitKey(t) | 圖片視窗於 t 毫秒後關閉 (按 q 提前關閉), t=0 表示等按鍵才關閉 |
destroyAllWindows() | 關閉全部 cv2 所開啟的視窗 |
split(img) | 將圖片物件 img 分解為 B, G, R 三色, 傳回 (B, G, R) tuple |
一. 讀取並顯示圖片 :
此處要操作的圖檔是影像處理界赫赫有名的 Lenna 圖, 參考 :
此圖可從 Wiki 下載使用 :
下載後放在目前的工作目錄下便可用 OpenCV 讀取顯示 :
>>> import cv2
>>> lenna=cv2.imread('Lenna.jpg') # 讀取圖檔傳回 ndarray 物件, 預設為彩色模式
>>> type(lenna)
<class 'numpy.ndarray'>
>>> lenna.shape # 圖片物件的形狀為 316*316 彩色
(316, 316, 3)
>>> lenna.size # 像素總數 316*316*3=299568 點
299568
>>> lenna.dtype # 8 位元整數型態 (值 0~255)
dtype('uint8')
>>> lenna
array([[[125, 137, 225],
[130, 137, 224],
[125, 137, 225],
...,
可見圖片物件為 3 軸陣列. 注意, OpenCV 的顏色排列順序不是 RGB, 而是 GBR.
>>> cv2.imshow('lenna', lenna) # 開啟名為 'lenna' 視窗來顯示圖片物件 lenna
>>> cv2.waitKey(0) # 維持視窗顯示直到按下任意鍵
在 Python 互動環境執行上述指令時, 呼叫 imshow() 僅建立顯示視窗並未顯示圖片, 而是呼叫 waitKey() 時才顯示, 結果如下 :
將滑鼠移到圖形視窗上按任意鍵會傳回一個 code, 然後呼叫 destroyAllWindows() 可關閉視窗 :
13
>>> cv2.destroyAllWindows()
寫成 .py 程式如下 :
# opencv_read_picture_1.py
import cv2
lenna=cv2.imread('Lenna.jpg')
cv2.imshow('lenna', lenna)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上面測試中呼叫 imread() 時只傳入一個參數 (圖檔名稱), 並未指定開檔模式常數 mode, 預設是 1 (1=cv2.IMREAD_COLOR, 彩色模式), 事實上 OpenCV 定義了如下 13 種模式 :
imread() 的 mode 參數 | 說明 |
IMREAD_UNCHANGED (-1) | 原始模式 (包含 alpha 值) |
IMREAD_GRAYSCALE (0) | 灰階模式 |
IMREAD_COLOR (1) | BGR 彩色模式 (預設值) |
IMREAD_ANYDEPTH (2) | 有深度時傳回 16/32 位元物件, 否則傳回 8 位元物件 |
IMREAD_ANYCOLOR (4) | 以任何顏色格式讀取圖片 |
IMREAD_LOAD_GDAL (8) | 以 GDAL 驅動程式載入圖片 |
IMREAD_REDUCED_GRAYSCALE_2 (16) | 尺寸減少 1/2 的灰階模式 |
IMREAD_REDUCED_COLOR_2 (17) | 尺寸減少 1/2 的 BGR 彩色模式 |
IMREAD_REDUCED_GRAYSCALE_4 (32) | 尺寸減少 1/4 的灰階模式 |
IMREAD_REDUCED_COLOR_4 (33) | 尺寸減少 1/4 的 BGR 彩色模式 |
IMREAD_REDUCED_GRAYSCALE_8 (64) | 尺寸減少 1/8 的灰階模式 |
IMREAD_REDUCED_COLOR_8 (65) | 尺寸減少 1/8 的 BGR 彩色模式 |
IMREAD_IGNORE_ORIENTATION (128) | 忽略 EXIF 中的方向資訊 (不旋轉) |
這些模式常數是一個整數值, 可以用下列程式來顯示其值 :
>>> modes=[cv2.IMREAD_UNCHANGED,
cv2.IMREAD_GRAYSCALE,
cv2.IMREAD_COLOR,
cv2.IMREAD_ANYDEPTH,
cv2.IMREAD_ANYCOLOR,
cv2.IMREAD_LOAD_GDAL,
cv2.IMREAD_REDUCED_GRAYSCALE_2,
cv2.IMREAD_REDUCED_COLOR_2,
cv2.IMREAD_REDUCED_GRAYSCALE_4,
cv2.IMREAD_REDUCED_COLOR_4,
cv2.IMREAD_REDUCED_GRAYSCALE_8,
cv2.IMREAD_REDUCED_COLOR_8,
cv2.IMREAD_IGNORE_ORIENTATION]
>>> for mode in modes:
print(mode, end=',')
-1,0,1,2,4,8,16,17,32,33,64,65,128,
例如以灰階模式 (mode=0) 讀取圖片 :
# opencv_read_picture_2.py
import cv2
lenna=cv2.imread('Lenna.jpg', 0) # 灰階模式
cv2.imshow('lenna', lenna)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下 :
下面範例使用 mode=16 (cv2.IMREAD_REDUCED_GRAYSCALE_2) 來產生 1/2 灰階圖片物件 :
# opencv_read_picture_3.py
import cv2
lenna=cv2.imread('Lenna.jpg', 16) # 1/2 灰階模式
print(lenna.shape)
cv2.imshow('lenna', lenna)
cv2.waitKey(0)
cv2.destroyAllWindows()
輸出如下 :
>>> %Run opencv_read_picture_3.py
(158, 158)
可見尺寸之長寬確實變成 1/2 (因為是灰階, 故無顏色軸).
下面範例使用 mode=17 (cv2.IMREAD_REDUCED_COLOR_2) 來產生 1/2 彩色圖片 :
# opencv_read_picture_4.py
import cv2
lenna=cv2.imread('Lenna.jpg', cv2.IMREAD_REDUCED_COLOR_2) # 1/2 彩色
print(lenna.shape)
cv2.imshow('lenna', lenna)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下 :
>>> %Run opencv_read_picture_4py.py
(158, 158, 3)
可見尺寸已縮為 1/2 (長寬 316/2=158).
二. 寫入圖片 :
呼叫 cv2.imwrite() 可將圖片物件儲存為檔案, 此函式可傳入三個參數 :
- file : 輸出圖檔名稱 (含路徑), 必要參數
- img : 圖片物件 (ndarray), 必要參數
- quality : 圖片品質 (串列), 備選參數
下列範例先讀入 Lenna.jpg, 然後存成 Lenna,png :
# opencv_read_picture_5.py
import cv2
lenna=cv2.imread('Lenna.jpg') # 讀取 Lenna.jpg 為 ndarray 陣列
cv2.imwrite('Lenna.png', lenna) # 存成 PNG 檔 Lenna.png
cv2.waitKey(0)
cv2.destroyAllWindows()
執行完畢會在工作目錄下產生一個 Lenna.png :
也可以自己製作 ndarray 陣列來產生圖片物件並寫入圖檔, 下面範例改寫自 "一本精通 : OpenCV與AI影像辨識" :
# opencv_read_picture_6.py
import cv2
import numpy as np
img=np.zeros((400, 400, 3), dtype='uint8')
img += 170
img[100:300, 100:300]=[200, 150, 0]
cv2.imwrite('cv2_test_1.jpg', img)
cv2.imshow('cv2_test_1', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
此例先用 Numpy 的 zeros() 建立一個 400*300*3 的 ndarray 陣列物件, 所有元素都是 0, 然後用 += 運算符將每個元素都加一個整數 (170), 所以圖片目前的背景色是 (B, G, R)=(170, 170, 170), 再用切片運算將索引位置 100:300 的值全部改成 (B, G, R)=(200, 150, 0), 最後將其寫入檔案並顯示, 結果如下 :
注意, 如上所述, OpenCV 的像素的色彩順序是 B, G, R 而不是 R, G, B.
沒有留言 :
張貼留言