這裡簡單記錄自己在 Python 中常用的 OpenCV 指令。
Reading Image
利用 imread()
進行影像讀取。Opencv 讀圖都是採 BGR 格式。
src = "image.png" # 圖片的路徑
dst = cv2.imread(src) # bgr (3 channel)
dst = cv2.imread(src, 0) # gray (1 channel)
Showing Image
使用 imshow()
顯示影像。通常會配合 waitKey(0)
及 destroyAllWindows()
使用。
waitKey(0)
:等待使用者按下按鍵。此時程式會在這裡等待,不做任何動作。destroyAllWindows()
:關閉所有 OpenCV 的視窗。
img = cv2.imread("image.png")
cv2.imshow("frame", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Resizing Image
縮放圖片處理。
dst = cv2.resize(src, dsize, fx, fy, interpolation)
參數說明:
src: 輸入影像。
dsize: 輸出影像大小。
fx、fy:縮放因子 (我通常不會去設)。
interpolation: 插值方式 (我通常不會去設)。
- INTER_NEAREST:最近鄰插值。
- INTER_LINEAR:雙線性插值(預設)。
- INTER_CUBIC:雙三次插值。
- INTER_AREA:藉由 pixel 之間的關係重新進行採樣。
- INTER_LANCZOS4:在 8x8 鄰域上進行 Lanczos 插值。
插值的其他參數可以參考 OpenCV: Geometric Image Transformations
Image Flip
翻轉影像。能夠設定水平翻轉、垂直翻轉、同時水平及垂直翻轉。
flipped_vertically = cv2.flip(image, 0) # 圍繞 X軸 翻轉,垂直翻轉
flipped_horizontally = cv2.flip(image, 1) # 圍繞 Y軸 翻轉,水平翻轉
flipped_ver_and_hor = cv2.flip(image, -1) # 同時垂直與水平翻轉
Affine Transformation
仿射轉換是指影像透過一系列的幾何轉換之後,實現影像平移、旋轉等等。轉換完的影像會保持平直性及平移性。平直性代表直線依然是直線;平行性代表平行線依然是平行線。
dst = cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)
參數
說明
src
輸入影像
M
代表一個 2x3 的 Affine 矩陣
dsize
輸出影像的大小
flags
內插類型,預設是 INTER_LINEAR
borderMode
邊緣類型,預設是 BORDER_CONSTANT
borderValue
邊界值,預設是 0
幾何變換操作如圖所示
下圖秀出各種幾何變換,也間接解釋為何使用 2x3 矩陣來定義轉換矩陣 M。
圖片來源取自 2D affine transformation matrix - Affine transformation - Wikipedia
Image Translation
平移影像。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 定義一個平移函數
def translate(image, x, y):
height, width = image.shape[:2] # 取得影像長、寬
M = np.float32([[1, 0, x], [0, 1, y]]) # 定義轉換矩陣 M
shifted = cv2.warpAffine(image, M, (width, height)) # 實現仿射轉換
return shifted # 回傳轉換結果
img = cv2.imread("lena.bmp", 0) # 讀取影像
new = translate(img, 100, 200) # 進行平移
# 顯示原始影像、轉換結果
plt.imshow(img),plt.show()
plt.imshow(new),plt.show()
```
### Rotate Image
旋轉圖像。
import cv2 import numpy as np import matplotlib.pyplot as plt
定義旋轉函數
def rotate(image, angle, scale=1.0): height, width = image.shape[:2] # 取得影像長、寬 center = (width/2, height/2) # 設定影像中心位置 # 旋轉影像 M = cv2.getRotationMatrix2D(center, angle, scale) rotated = cv2.warpAffine(image, M, (width, height)) return rotated # 回傳轉換結果
img = cv2.imread(“lena.bmp”, 0) # 讀取影像 new = rotate(img, 45) # 進行平移
顯示原始影像、轉換結果
plt.imshow(img),plt.show() plt.imshow(new),plt.show()
Color Space Conversions
-----------------------
dst = cv2.cvtColor(img, cv2.COLOR_XXX2XXX)
我常用的是
* 色彩、灰階 互轉
* COLOR\_BGR2GRAY
* COLOR\_RGB2GRAY
* COLOR\_GRAY2BGR
* COLOR\_GRAY2RGB
* HSV 空間
* COLOR\_BGR2HSV
* COLOR\_RGB2HSV
* COLOR\_HSV2BGR
* COLOR\_HSV2RGB
`cv2.COLOR_XXX2XXX` 相關轉換參數可參考 [OpenCV: Color Space Conversions](https://docs.opencv.org/3.4/d8/d01/group__imgproc__color__conversions.html)。
Image Thresholding
------------------
這裡直接用官方的範例 — [OpenCV: Image Thresholding](https://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html) 來說明:```
dst = cv2.threshold(src, thresh, maxval, thresholding_type)
```本身提供五種類型的取閥值方式
* **[cv.THRESH\_BINARY](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a147222a96556ebc1d948b372bcd7ac59)**
* **[cv.THRESH\_BINARY\_INV](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a19120b1a11d8067576cc24f4d2f03754)**
* **[cv.THRESH\_TRUNC](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576ac7e89a5e95490116e7d2082b3096b2b8)**
* **[cv.THRESH\_TOZERO](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a0e50a338a4b711a8c48f06a6b105dd98)**
* **[cv.THRESH\_TOZERO\_INV](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a47518a30aae90d799035bdcf0bb39a50)**
官方範例:```
# 引入必要模組
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 讀取漸變圖
img = cv2.imread('gradient.png', 0)
# 各種閥值函數
ret,thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
# 顯示取閥值的結果
titles = ["Original Image", "BINARY", "BINARY_INV", "TRUNC", "TOZERO", "TOZERO_INV"]
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i+1)
plt.imshow(images[i], "gray", vmin=0, vmax=255)
plt.title(titles[i])
plt.xticks([])
plt.yticks([])
plt.show()
``` 圖片來源取自 [OpenCV: Image Thresholding](https://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html)。 除了上面 Simple Thresholding 之外,還有 Adaptive Thresholding 及 Otsu's thresholding 的方式。
Video Capturing
---------------
能夠擷取影片檔、攝影機的類別。通常會與 `waitKey()` 搭配使用。
### Example
建構一個小型攝影機程式
* 使用 `VideoCapture()` 可以建立一個影像擷取物件,這裡我們希望取出攝影機的影像,所以將這個物件命名為 `camera`。
* 使用 `read()` 來獲得新的影像,並用 `imshow()` 來顯示影像。
* 由於 `camera` 會不斷的拍攝新的影像,所以要用 `while` 迴圈來跑 `read()` 跟 `imshow()`。
* 利用 `waitKey(1)` 來偵測按鍵。當按下 `'q'` 時,就會跳出 `while` 迴圈。
* 最後要關閉程式前,要先用 `release()` 來釋放 `camera`,並用 `destroyAllWindows()` 關閉視窗。
import cv2 # 引入 OpenCV
camera = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 選擇攝影機
while True: ret, frame = camera.read() # 從 Camera 中擷取影像 cv2.imshow(“frame”, frame) # 顯示影像 # 若按下 q 鍵則離開迴圈 if cv2.waitKey(1) & 0xFF == ord(“q”): break
camera.release() # 釋放攝影機
cv2.destroyAllWindows() # 關閉視窗
Note:如果要讀影片檔,直接在 VideoCapture() 的地方,輸入影片路徑即可。
cap = cv2.VideoCapture(“video.mp4”)