第8章:形态学操作
第8章:形態學操作
- one. 腐蝕操作:
- two. 膨脹:
- three. 通用形態學函數:
- four. 開運算:
- five. 閉運算:
- six. 形態學梯度運算:
- seven. 禮帽運算:
- eight. 黑帽運算:
- night. 核函數:
? 形態學,即數學形態學,是圖像處理過程中一個非常重要的研究方向。形態學的目的是提取圖像中的分量信息,該分量信息通常對于表達和描繪圖像的形狀具有重要意義,通常是圖像理解時所使用的最本質的形狀特征。
? 例如,我們手寫一個阿拉伯數字,在識別時能夠通過形態學運算得到其骨架信息,而在具體的圖像運算時僅使用其骨架信息即可。
? 形態學處理廣泛應用于視覺檢測、文字識別、醫學圖像識別、圖像壓縮編碼等多個領域。
? 形態學操作主要包括:腐蝕、膨脹、開運算、閉運算、形態梯度學運算、禮帽運算(頂帽運算)、黑帽運算等操作。腐蝕操作和膨脹操作是形態學運算的基礎,將腐蝕和膨脹操作進行結合,就可以實現開運算和閉運算、形態學梯度運算、禮帽運算、黑帽運算、擊中擊不中等不同形式的運算。
(形態學操作的目的是為了提取圖像中總要的分量信息)
one. 腐蝕操作:
? 腐蝕操作是形態學最基本的操作之一,它能夠將圖像的邊界點消除,使圖像沿著邊界向內收縮,也可以將小于指定結構體元素的部分去除。(結構體也成為了核)。
? 腐蝕是用來"收縮"或者"細化二值圖像中的前景,借此實現去除噪聲、元素分割等功能的。
? 在腐蝕過程中,通常使用一個結構元來逐個像素的掃描要被腐蝕的圖像,并根據結構元和被腐蝕圖像的關系來確定腐蝕結果。
? 例如圖中整幅圖像的背景色是黑色的,前景對象是一個白色的圓形。圖像左上角的深色小方塊是遍歷圖像所使用的結構元。在腐蝕過程中,要將該結構元逐個像素的遍歷整個圖像,并根據結構元與被腐蝕圖像的關系,來確定腐蝕結果圖像中對應結構元中心點位置的像素點的像素值。
? 注意:腐蝕操作等形態學操作都是逐個像素的來決定值的,每次判定的點都是與結構元中心點所對應的點。
下面兩幅圖像表示結構元與前景色的兩種不同關系。根據這兩種不同的關系來決定腐蝕結果圖像中的結構元中心點所對應位置的像素點的像素值。
- 如果結構元完全處于前景圖像中,就將結構元中心點所對應的腐蝕結果圖像中的像素點的像素值處理為前景色(白色,像素點的像素值為1)
- 如果結構元未完全處于前景圖像中(可能部分在,也可能完全不在)就將結構元中心點對應的腐蝕結果圖形中的像素點的像素值處理為背景色(黑色,像素點的像素值為0)。
腐蝕的結果就是前景色白色的圓直徑變小。結構元也被稱為核。
腐蝕函數:
在OpenCV中,使用cv2.erode()函數來實現腐蝕操作,其語法格式為:
dst = cv2.erode(src, kernel[, anchor[, iterations[, borderType[, borderValue]]]])
-
dst:腐蝕后輸出的結果圖像,該圖像和原始圖像具有同樣的類型和大小。
-
src:原圖像,即需要進行腐蝕的原始圖像,圖像的通道數可以是任意的。但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
-
kernel:代表腐蝕操作時所采用的結構類型。它可以自定義生成,也可以通過函數從cv2.getStructutingElement()生成。
-
anchor:代表element結構中錨點的位置。該值默認為(-1, -1),在核中心的位置。
-
iterations:腐蝕操作迭代的次數,該值默認為1,即只進行一次腐蝕操作。
-
borderType:代表邊界樣式,一般采用其默認值BORDER_CONSTANT。該項的具體值如下所示
-
borderValue:邊界值,一般采用默認值。在C++中提供了函數morphologyDefaultBorderValue()來返回腐蝕和膨脹的"魔力(magic)"邊界值,python不支持該函數。
示例1:
import cv2 import numpy as npimg = cv2.imread('../erode.bmp') kernel = np.ones((5, 5), np.uint8) rst = cv2.erode(img, kernel) cv2.imshow('img', img) cv2.imshow('rst', rst) cv2.waitKey() cv2.destroyAllWindows()示例2:修改腐蝕迭代次數觀察
import cv2 import numpy as npimg = cv2.imread('../erode.bmp') kernel = np.ones((5, 5), np.uint8) rst = cv2.erode(img, kernel, iterations=5) cv2.imshow('img', img) cv2.imshow('rst', rst) cv2.waitKey() cv2.destroyAllWindows()two. 膨脹:
? 膨脹操作是形態學中另一種基本的操作。**膨脹操作和腐蝕操作的作用是相反的,膨脹操作能夠對圖像的邊界進行擴張。**膨脹操作將背景中與前景對象接觸到的像素點合并到前景對象中,從而實現將圖像邊界點向外擴張。如果圖像內兩個對象距離較近,那么在膨脹的過程中,兩個對象可能會連通在一起。膨脹對填補圖像分割后圖像內所存在的空白有很大幫助。
? 同腐蝕的過程一樣,在膨脹過程中,也是使用一個結構元(核)來逐個像素掃描被膨脹的圖像,并根據結構元和被膨脹圖像的關系來確定膨脹結果。
如上圖所示:
- 如果結構元中任意一點處于前景圖像中,就將膨脹結果圖像中對應像素點處理為前景色。
- 如果結構元完全處于背景圖像外,就將膨脹結果圖像中對應像素點處理為背景色。
膨脹操作:
在Opencv中,采用函數cv2.dilate()實現對圖像的膨脹操作,其語法結構為:
dst=cv2.dilate(src,kernel[,anchor[,iterations[,borderType[,borderValue]]]])
- dst:膨脹后輸出的結果圖像,該圖像和原始圖像具有同樣的類型和大小。
- src:原圖像,即需要進行膨脹的原始圖像,圖像的通道數可以是任意的。但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
- kernel:代表膨脹操作時所采用的結構類型。它可以自定義生成,也可以通過函數從cv2.getStructutingElement()生成。
參數kernel、anchor、iterations、borderType、borderValue與函數cv2.erode()內相應參數的含義一致。
示例1:
import cv2 import numpy as npimg = np.zeros((5, 5), np.uint8) img[2:3, 1:4] = 1 kernel = np.ones((3, 1), np.uint8) dilation = cv2.dilate(img, kernel) print('img=\n', img) print('kernel=\n', kernel) print('dilation=\n', dilation)# 輸入結果 img=[[0 0 0 0 0][0 0 0 0 0][0 1 1 1 0][0 0 0 0 0][0 0 0 0 0]] kernel=[[1][1][1]] dilation=[[0 0 0 0 0][0 1 1 1 0][0 1 1 1 0][0 1 1 1 0][0 0 0 0 0]]示例2:
import cv2 import numpy as npimg = cv2.imread('../dilate.bmp') kernel = np.ones((3, 3), np.uint8) rst = cv2.dilate(img, kernel, iterations=9) cv2.imshow('img', img) cv2.imshow('rst', rst) cv2.waitKey() cv2.destroyAllWindows()three. 通用形態學函數:
? 腐蝕操作和膨脹操作是形態學運算的基礎,將腐蝕和膨脹操作進行組合,就可以實現開運算、閉運算(關運算)、形態學梯度(Morphological Gradient)運算、禮帽運算(頂帽運算)、黑帽運算、擊中擊不中等多種不同形式的運算。
OpenCV提供了函數cv2.morphologyEx()來實現上述形態學運算,其語法結構如下:
dst=cv2.morphologyEx(src,op,kernel[,anchor[,iterations[,borderType[,borderValue]]]]])
式中:
-
dst:代表經過形態學處理后所輸出的目標圖像,該圖像和原始圖像具有同樣的類型和大小。
-
src:代表需要進行形態學操作的原始圖像。圖像的通道數可以是任意的,但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
-
op:代表操作類型,如下表所示。各種形態學運算的操作規則,均是將腐蝕和膨脹操作進行組合而得到的。
-
參數kernel、anchor、iterations、borderType、borderValue與函數cv2.erode()內相應參數的含義一致。
four. 開運算:
開運算進行的操作是先將圖像腐蝕,再對腐蝕的結果進行膨脹。開運算可以用于去噪、計數等。
例如,下圖中,通過先腐蝕后膨脹的開運算操作實現了去噪,其中:
- 左圖是原始圖像。
- 中間的圖是對原始圖像進行腐蝕的結果。
- 右圖是對腐蝕后的圖像進行膨脹的結果,即對原始圖像進行開運算的處理結果。
除此以外,開運算還可以用于計數。例如,在對下圖的區域進行計數前,可以利用開運算將連接在一起的不同區域劃分開,其中:
- 左圖是原始圖像。
- 中間的圖是對原始圖像進行腐蝕的結果。
- 右圖是對腐蝕后的圖像進行膨脹的結果,即對原始圖像進行開運算的處理結果。
通過將函數cv2.morphologyEx()中操作類型參數op設置為“cv2.MORPH_OPEN”,可以實現開運算。其語法結構如下:opening=cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
示例:
import cv2 import numpy as npimg1 = cv2.imread('../erode.bmp') img2 = cv2.imread('../cube.bmp')k = np.ones((20, 20), np.uint8) rst1 = cv2.morphologyEx(img1, cv2.MORPH_OPEN, k) rst2 = cv2.morphologyEx(img2, cv2.MORPH_OPEN, k)cv2.imshow('img1', img1) cv2.imshow('img2', img2) cv2.imshow('rst1', rst1) cv2.imshow('rst2', rst2) cv2.waitKey() cv2.destroyAllWindows()five. 閉運算:
? 閉運算是先膨脹、后腐蝕的運算,它有助于關閉前景物體內部的小孔,或去除物體上的小黑點,還可以將不同的前景圖像進行連接。
例如,通過先膨脹后腐蝕的閉運算去除了原始圖像內部的小孔(內部閉合的閉運算),其中:
-
左圖是原始圖像。
-
中間的圖是對原始圖像進行膨脹的結果。
-
右圖是對膨脹后的圖像進行腐蝕的結果,即對原始圖像進行閉運算的結果。
除此以外,閉運算還可以實現前景圖像的連接。例如,利用閉運算將原本獨立的兩部分前景圖像連接在一起,其中:
- 左圖是原始圖像。
- 中間的圖是對原始圖像進行膨脹的結果。
- 右圖是對膨脹后的圖像進行腐蝕的結果,即對原始圖像進行閉運算的結果。
示例:
import cv2 import numpy as npk = np.ones((10, 10), np.uint8) rst1 = cv2.morphologyEx(img1, cv2.MORPH_CLOSE, k) cv2.imshow('img1', img1) cv2.imshow('rst1', rst1) cv2.waitKey() cv2.destroyAllWindows()six. 形態學梯度運算:
? 形態學梯度運算是用圖像的膨脹圖像減腐蝕圖像的操作,該操作可以獲取原始圖像中前景圖像的邊緣。
例如:
示例:
import cv2 import numpy as npimg = cv2.imread('../erode.bmp')k = np.ones((5, 5), np.uint8) rst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, k) cv2.imshow('img', img) cv2.imshow('rst', rst) cv2.waitKey() cv2.destroyAllWindows()seven. 禮帽運算:
禮帽運算是用原始圖像減去其開運算圖像的操作。禮帽運算能夠獲取圖像的噪聲信息,或者得到比原始圖像的邊緣更亮的邊緣信息。
例如
- 左圖是原始圖像。
- 中間的圖是開運算圖像。
- 右圖是原始圖像減開運算圖像所得到的禮帽圖像。
示例:
import cv2 import numpy as npimg1 = cv2.imread('../erode.bmp') img2 = cv2.imread('../lena.bmp')k = np.ones((5, 5), np.uint8) rst1 = cv2.morphologyEx(img1, cv2.MORPH_TOPHAT, k) rst2 = cv2.morphologyEx(img2, cv2.MORPH_TOPHAT, k) cv2.imshow('img1', img1) cv2.imshow('img2', img2) cv2.imshow('rst1', rst1) cv2.imshow('rst2', rst2) cv2.waitKey() cv2.destroyAllWindows()eight. 黑帽運算:
? 黑帽運算是用閉運算圖像減去原始圖像的操作。黑帽運算能夠獲取圖像內部的小孔,或前景色中的小黑點,或者得到比原始圖像的邊緣更暗的邊緣部分。
例如:
- 左圖是原始圖像。
- 中間的圖是閉運算圖像。
- 右圖是使用閉運算圖像減原始圖像所得到的黑帽圖像。
示例:
import cv2 import numpy as npimg1 = cv2.imread('../noise2.bmp') img2 = cv2.imread('../lena.bmp')k = np.ones((10, 10), np.uint8) rst1 = cv2.morphologyEx(img1, cv2.MORPH_BLACKHAT, k) rst2 = cv2.morphologyEx(img2, cv2.MORPH_BLACKHAT, k) cv2.imshow('img1', img1) cv2.imshow('img2', img2) cv2.imshow('rst1', rst1) cv2.imshow('rst2', rst2) cv2.waitKey() cv2.destroyAllWindows()night. 核函數:
? 在進行形態學操作時,必須使用一個特定的核(結構元)。該核可以自定義生成,也可以通過函數 cv2.getStructuringElement()構造。函數 cv2.getStructuringElement()能夠構造并返回一個用于形態學處理所使用的結構元素。該函數的語法格式為:
- retval=cv2.getStructuringElement(shape,ksize[,anchor])
該函數用來返回一個用于形態學操作的指定大小和形狀的結構元素。函數中的參數含義如下。
- shape代表形狀類型,其可能的取值如表所示。
- ksize 代表結構元素的大小。
- anchor 代表結構元素中的錨點位置。默認的值是(-1,-1),是形狀的中心。只有十字星型的形狀與錨點位置緊密相關。在其他情況下,錨點位置僅用于形態學運算結果的調整。
當然,除了使用該函數,用戶也可以自己構建任意二進制掩碼作為形態學操作中所使用的結構元素。
示例1:使用函數cv2.getStructuringElement()生成不同結構的核。
import cv2k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) k2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5)) k3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))print('k1=\n', k1) print('k2=\n', k2) print('k3=\n', k3)# 輸出結果 k1=[[1 1 1 1 1][1 1 1 1 1][1 1 1 1 1][1 1 1 1 1][1 1 1 1 1]] k2=[[0 0 1 0 0][0 0 1 0 0][1 1 1 1 1][0 0 1 0 0][0 0 1 0 0]] k3=[[0 0 1 0 0][1 1 1 1 1][1 1 1 1 1][1 1 1 1 1][0 0 1 0 0]]示例2:使用不同的核進行形態學操作
import cv2img = cv2.imread('../round.bmp')k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25)) k2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (25, 25)) k3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25, 25))rst1 = cv2.erode(img, k1, iterations=3) rst2 = cv2.erode(img, k2, iterations=3) rst3 = cv2.erode(img, k3, iterations=3) cv2.imshow('img', img) cv2.imshow('rst1', rst1) cv2.imshow('rst2', rst2) cv2.imshow('rst3', rst3) cv2.waitKey() cv2.destroyAllWindows()總結
- 上一篇: python-snap7安装各种报错
- 下一篇: IT人的自我导向型学习:学习的4个层次