影像處理(image processing)與電腦視覺(computer vision)是兩個讓人常常聯想在一起的名詞,同樣都是接收影像資訊,兩者的差異反映在最終結果:影像處理輸出的是「處理後的影像」,電腦視覺輸出的是「圖像中的資訊」。這兩種不同的技術運用,實際上卻是唇齒相依息息相關,電腦視覺需要影像處理來解析更多的資訊;同樣的,影像處理為了滿足電腦視覺的需求,也發展出各種更深更廣的技術,以期能深入剖析影像,取得更多的特徵與資訊。
今天要帶大家來了解,如何使用 OpenCV 進行捲積(Convolution)的影像處理技術。但在開始之前,我們需要先了解以下幾個電腦術語:
- Image Patch:指的是影像中以某一點為中心的一小塊區域(大小如 3×3、5×5 等)。
- Low Frequency Information:指平坦、單調、無太多紋理、邊緣、邊角等特徵,例如:「An image patch is said to have low frequency information」。
- High Frequency Information:與 Low Frequency 相反,有很多的紋理、邊緣、邊角等特徵。
- Low Pass Filtering:Low Pass 指的是 blurring(模糊)、smoothing(平滑)等動作;Low Pass Filtering 指讓影像中 Low Frequency 的資訊通過,阻隔 High Frequency 的部份。
- High Pass Filtering:High Pass 指的是 sharpening(銳化)或 edge enhancement(邊緣強化)等動作;High Pass Filtering 指阻卻影像中 Low Pass 的部份,讓 High Pass 的資訊通過。
認識 Image Filtering
當我們需要強化影像中的某些特徵並消除其他不想要的特徵,所採用的方法便是使用特定 kernel,針對整張進行捲積(convolution)操作。舉例來說,模糊(blur)、邊緣偵測(edge detection)、邊緣強化(edge enhancement)、噪點去除(noise removal)等,都是使用 kernel 針對影像進行捲積的結果。
kernel 指的是一個固定尺寸的窗格(如 3×3),在影像處理中,我們稱該窗格為 kernel 或 filter。若由左上到右下移動,使用該 kernel 針對影像重疊區域進行運算,最終便會得出一幅經過 filtered 的新影像,這樣的動作稱為捲積(convolution)。目前最流行的 CNN 進行的就是 image filtering 的工作。
如下圖所示,藍色 grid 為定義的 3×3 kernel,在捲積過程進行中,底下覆蓋區域(圖中的紅色的 grid)與 kernel 進行交乘加總後(下方的 output pixel),將作為輸出新圖中該 kernel 區域的中心點;若由左上至右下重複進行上述步驟,輪巡整張圖片後就會得到右邊的圖形。
使用 kernel 針對影像進行捲積的結果(圖片來源:曾成訓提供)
執行 convolution 後,會發現有一個很明顯的特性,就是輸出的圖片尺寸會比原來的小一圈,一般我們會採取四種方式來處理此特性:
- Ignore the boundary pixels:忽略消失的邊界影像,直接使用輸出的圖片。
- Zero padding:先在原圖周圍填補一圈為 0 的像素,再進行捲積,使輸出的圖片尺寸不變。
- Replicate border:直接複製原圖最邊界的 pixels 到輸出的圖周圍,例如:aaaaaa 🡨 abcdefgh 🡪 hhhhhhh
- Reflect border:與 Replicate border 類似,但複製的方式是對稱方式 copy,例如:fedcba 🡨 abcdefgh 🡪 hgfedcb
使用 OpenCV 進行捲積操作
OpenCV 內建了非常方便的捲積指令 filter 2D,只要先定義好使用的 kernel,便可直接進行捲積,我們來試看看。(後文中所指的 kernel 與 filter 都是指用於捲積的過濾窗格)
import numpy as np
import cv2
import imutils
import sys
# cv2.IMREAD_COLOR為imread的預設值,此參數亦可不加。
imageName = "DSCF3454.jpg"
image = cv2.imread(imageName, cv2.IMREAD_COLOR)
#若無指定圖片則結束程式。
if image is None:
print("Could not open or find the image")
sys.exit()
#縮小圖片到較適當尺寸。
image = imutils.resize(image, height=450)
# 設定kernel size為5x5
kernel_size = 5
# 使用numpy建立 5*5且值為1/(5**2)的矩陣作為kernel。
kernel = np.ones((kernel_size, kernel_size), dtype=np.float32) / kernel_size**2
# 顯示矩陣內容,所有值皆為0.04的5x5矩陣
print (kernel)
# 使用cv2.filter2D進行convolute,
result = cv2.filter2D(image, dst=-1, kernel=kernel, anchor=(-1, -1), delta=0, borderType=cv2.BORDER_DEFAULT)
cv2.imshow("Filter", result)
cv2.imshow("Original", image)
cv2.waitKey(0)
- 程式中定義的 kernel
程式中所使用的 filter 有「模糊化圖片」的功能 ,所產生的 kernel 如下圖所示:
只需不到短短一分鐘...
輸入您的信箱與ID註冊即可享有一切福利!
會員福利
免費電子報
會員搶先看
主題訂閱
好文收藏