我們在前兩次教程中概述了OpenCV對於圖像的濾波,通常對於一個實戰項目而言,濾波之后的下一步操作就是圖像的形態學處理了,從本次教程開始,我們正式步入了OpenCV圖像形態學處理的部分。
形態學(morphology)一詞通常表示生物學的一個分支,該分支主要研究動植物的形態和結構。而我們圖像處理中指的形態學,往往表示的是數學形態學。下面一起來了解數學形態學的概念。
數學形態學是一門建立在格論和拓撲學基礎之上的圖像分析學科,是數學形態學圖像處理的基本理論。其基本的運算包括:二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形態學梯度、Top-hat變換、顆粒分析、流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形態學梯度等。
簡單來講,形態學操作就是基於形狀的一系列圖像處理操作。OpenCV為進行圖像的形態學變換提供了快捷、方便的函數。最基本的形態學操作有二種,他們是:膨脹與腐蝕(Dilation與Erosion)。
膨脹與腐蝕能實現多種多樣的功能,主要如下:
1 消除噪聲
2 分割出獨立的圖像元素,在圖像中連接相鄰的元素。
3 尋找圖像中的明顯的極大值區域或極小值區域
4 求出圖像的梯度
腐蝕和膨脹是對白色部分(高亮部分)而言的,不是黑色部分。膨脹就是圖像中的高亮部分進行膨脹,“領域擴張”,效果圖擁有比原圖更大的高亮區域。腐蝕就是原圖中的高亮部分被腐蝕,“領域被蠶食”,效果圖擁有比原圖更小的高亮區域。
膨脹
其實,膨脹就是求局部最大值的操作。
按數學方面來說,膨脹或者腐蝕操作就是將圖像(或圖像的一部分區域,我們稱之為A)與核(我們稱之為B)進行卷積。
核可以是任何的形狀和大小,它擁有一個單獨定義出來的參考點,我們稱其為錨點。多數情況下,核是一個小的中間帶有參考點和實心正方形或者圓盤,其實,我們可以把核視為模板或者掩碼。
而膨脹就是求局部最大值的操作,核B與圖形卷積,即計算核B覆蓋的區域的像素點的最大值,並把這個最大值賦值給參考點指定的像素。這樣就會使圖像中的高亮區域逐漸增長。如下圖所示,這就是膨脹操作:
我們來看一下函數原型:
cv2. dilate (img,kernel,iterations)->dst
第一個參數:img指需要膨脹的圖
第二個參數:kernel指膨脹操作的內核,默認是一個簡單的3X3矩陣,我們也可以利用getStructuringElement()函數指明它的形狀
第三個參數:iterations指的是膨脹次數,省略是默認為1
dst則為返回的圖像。
定義卷積核需要用到Numpy中的函數,它可以定義一個矩形的卷積核結構元素,我們來看一下代碼:
import cv2 import numpy as np img = cv2.imread('01.jpg',0) kernel = np.ones((5,5),np.uint8) dict = cv2.dilate(img,kernel,iterations = 1) cv2.imshow("org",img) cv2.imshow("result", dict) cv2.waitKey(0) cv2.destroyAllWindows()
我們定義了一個5*5的矩形卷積核,效果:
事實上,在某些情況下,我們可能需要橢圓形/圓形的內核。因此,為此,OpenCV具有一個函數cv.getStructuringElement()。我們只需傳遞內核的形狀和大小,即可獲得所需的內核,函數原型:
retval=cv.getStructuringElement(shape, ksize[, anchor])
這個函數的第一個參數表示內核的形狀,有三種形狀可以選擇。
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
橢圓形:MORPH_ELLIPSE;
第二和第三個參數分別是內核的尺寸以及錨點的位置。一般在調用erode以及dilate函數之前,先定義一個變量來獲得。
getStructuringElement函數的返回值: 對於錨點的位置,有默認值Point(-1,-1),表示錨點位於中心點。element形狀唯一依賴錨點位置,其他情況下,錨點只是影響了形態學運算結果的偏移。
我們看一下代碼:
import cv2 import numpy as np img = cv2.imread('01.jpg',0) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) dict = cv2.dilate(img,kernel,iterations = 1) cv2.imshow("org",img) cv2.imshow("result", dict) cv2.waitKey(0) cv2.destroyAllWindows()
至於卷積核的形狀我在這里選擇了橢圓形,大家可以自己選擇其他形狀進行實驗:
腐蝕
再來看一下腐蝕,膨脹和腐蝕是一對好友,是相反的一對操作,所以腐蝕就是求局部最小值的操作。我們一般都會把腐蝕和膨脹對應起來理解和學習。下文就可以看到,兩者的函數原型也是基本上一樣的。
我們來看一下函數原型:
cv2.erode(img,kernel,iterations)->dst
第一個參數:img指需要腐蝕的圖
第二個參數:kernel指腐蝕操作的內核,默認是一個簡單的3X3矩陣,我們也可以利用getStructuringElement()函數指明它的形狀
第三個參數:iterations指的是腐蝕次數,省略是默認為1
dst則為返回的圖像。
代碼:
import cv2 import numpy as np img = cv2.imread('01.jpg',0) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) erode = cv2.erode(img,kernel,iterations = 1) cv2.imshow("org",img) cv2.imshow("result", erode) cv2.waitKey(0) cv2.destroyAllWindows()
效果:
腐蝕與膨脹是形態學處理中的基礎操作,它們有着很重要的作用,也是后面開操作與閉操作的基礎,所以必須熟練運用。