第8章:形态学操作
第8章:形態(tài)學(xué)操作
- one. 腐蝕操作:
- two. 膨脹:
- three. 通用形態(tài)學(xué)函數(shù):
- four. 開(kāi)運(yùn)算:
- five. 閉運(yùn)算:
- six. 形態(tài)學(xué)梯度運(yùn)算:
- seven. 禮帽運(yùn)算:
- eight. 黑帽運(yùn)算:
- night. 核函數(shù):
? 形態(tài)學(xué),即數(shù)學(xué)形態(tài)學(xué),是圖像處理過(guò)程中一個(gè)非常重要的研究方向。形態(tài)學(xué)的目的是提取圖像中的分量信息,該分量信息通常對(duì)于表達(dá)和描繪圖像的形狀具有重要意義,通常是圖像理解時(shí)所使用的最本質(zhì)的形狀特征。
? 例如,我們手寫(xiě)一個(gè)阿拉伯?dāng)?shù)字,在識(shí)別時(shí)能夠通過(guò)形態(tài)學(xué)運(yùn)算得到其骨架信息,而在具體的圖像運(yùn)算時(shí)僅使用其骨架信息即可。
? 形態(tài)學(xué)處理廣泛應(yīng)用于視覺(jué)檢測(cè)、文字識(shí)別、醫(yī)學(xué)圖像識(shí)別、圖像壓縮編碼等多個(gè)領(lǐng)域。
? 形態(tài)學(xué)操作主要包括:腐蝕、膨脹、開(kāi)運(yùn)算、閉運(yùn)算、形態(tài)梯度學(xué)運(yùn)算、禮帽運(yùn)算(頂帽運(yùn)算)、黑帽運(yùn)算等操作。腐蝕操作和膨脹操作是形態(tài)學(xué)運(yùn)算的基礎(chǔ),將腐蝕和膨脹操作進(jìn)行結(jié)合,就可以實(shí)現(xiàn)開(kāi)運(yùn)算和閉運(yùn)算、形態(tài)學(xué)梯度運(yùn)算、禮帽運(yùn)算、黑帽運(yùn)算、擊中擊不中等不同形式的運(yùn)算。
(形態(tài)學(xué)操作的目的是為了提取圖像中總要的分量信息)
one. 腐蝕操作:
? 腐蝕操作是形態(tài)學(xué)最基本的操作之一,它能夠?qū)D像的邊界點(diǎn)消除,使圖像沿著邊界向內(nèi)收縮,也可以將小于指定結(jié)構(gòu)體元素的部分去除。(結(jié)構(gòu)體也成為了核)。
? 腐蝕是用來(lái)"收縮"或者"細(xì)化二值圖像中的前景,借此實(shí)現(xiàn)去除噪聲、元素分割等功能的。
? 在腐蝕過(guò)程中,通常使用一個(gè)結(jié)構(gòu)元來(lái)逐個(gè)像素的掃描要被腐蝕的圖像,并根據(jù)結(jié)構(gòu)元和被腐蝕圖像的關(guān)系來(lái)確定腐蝕結(jié)果。
? 例如圖中整幅圖像的背景色是黑色的,前景對(duì)象是一個(gè)白色的圓形。圖像左上角的深色小方塊是遍歷圖像所使用的結(jié)構(gòu)元。在腐蝕過(guò)程中,要將該結(jié)構(gòu)元逐個(gè)像素的遍歷整個(gè)圖像,并根據(jù)結(jié)構(gòu)元與被腐蝕圖像的關(guān)系,來(lái)確定腐蝕結(jié)果圖像中對(duì)應(yīng)結(jié)構(gòu)元中心點(diǎn)位置的像素點(diǎn)的像素值。
? 注意:腐蝕操作等形態(tài)學(xué)操作都是逐個(gè)像素的來(lái)決定值的,每次判定的點(diǎn)都是與結(jié)構(gòu)元中心點(diǎn)所對(duì)應(yīng)的點(diǎn)。
下面兩幅圖像表示結(jié)構(gòu)元與前景色的兩種不同關(guān)系。根據(jù)這兩種不同的關(guān)系來(lái)決定腐蝕結(jié)果圖像中的結(jié)構(gòu)元中心點(diǎn)所對(duì)應(yīng)位置的像素點(diǎn)的像素值。
- 如果結(jié)構(gòu)元完全處于前景圖像中,就將結(jié)構(gòu)元中心點(diǎn)所對(duì)應(yīng)的腐蝕結(jié)果圖像中的像素點(diǎn)的像素值處理為前景色(白色,像素點(diǎn)的像素值為1)
- 如果結(jié)構(gòu)元未完全處于前景圖像中(可能部分在,也可能完全不在)就將結(jié)構(gòu)元中心點(diǎn)對(duì)應(yīng)的腐蝕結(jié)果圖形中的像素點(diǎn)的像素值處理為背景色(黑色,像素點(diǎn)的像素值為0)。
腐蝕的結(jié)果就是前景色白色的圓直徑變小。結(jié)構(gòu)元也被稱為核。
腐蝕函數(shù):
在OpenCV中,使用cv2.erode()函數(shù)來(lái)實(shí)現(xiàn)腐蝕操作,其語(yǔ)法格式為:
dst = cv2.erode(src, kernel[, anchor[, iterations[, borderType[, borderValue]]]])
-
dst:腐蝕后輸出的結(jié)果圖像,該圖像和原始圖像具有同樣的類型和大小。
-
src:原圖像,即需要進(jìn)行腐蝕的原始圖像,圖像的通道數(shù)可以是任意的。但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
-
kernel:代表腐蝕操作時(shí)所采用的結(jié)構(gòu)類型。它可以自定義生成,也可以通過(guò)函數(shù)從cv2.getStructutingElement()生成。
-
anchor:代表element結(jié)構(gòu)中錨點(diǎn)的位置。該值默認(rèn)為(-1, -1),在核中心的位置。
-
iterations:腐蝕操作迭代的次數(shù),該值默認(rèn)為1,即只進(jìn)行一次腐蝕操作。
-
borderType:代表邊界樣式,一般采用其默認(rèn)值BORDER_CONSTANT。該項(xiàng)的具體值如下所示
-
borderValue:邊界值,一般采用默認(rèn)值。在C++中提供了函數(shù)morphologyDefaultBorderValue()來(lái)返回腐蝕和膨脹的"魔力(magic)"邊界值,python不支持該函數(shù)。
示例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:修改腐蝕迭代次數(shù)觀察
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. 膨脹:
? 膨脹操作是形態(tài)學(xué)中另一種基本的操作。**膨脹操作和腐蝕操作的作用是相反的,膨脹操作能夠?qū)D像的邊界進(jìn)行擴(kuò)張。**膨脹操作將背景中與前景對(duì)象接觸到的像素點(diǎn)合并到前景對(duì)象中,從而實(shí)現(xiàn)將圖像邊界點(diǎn)向外擴(kuò)張。如果圖像內(nèi)兩個(gè)對(duì)象距離較近,那么在膨脹的過(guò)程中,兩個(gè)對(duì)象可能會(huì)連通在一起。膨脹對(duì)填補(bǔ)圖像分割后圖像內(nèi)所存在的空白有很大幫助。
? 同腐蝕的過(guò)程一樣,在膨脹過(guò)程中,也是使用一個(gè)結(jié)構(gòu)元(核)來(lái)逐個(gè)像素掃描被膨脹的圖像,并根據(jù)結(jié)構(gòu)元和被膨脹圖像的關(guān)系來(lái)確定膨脹結(jié)果。
如上圖所示:
- 如果結(jié)構(gòu)元中任意一點(diǎn)處于前景圖像中,就將膨脹結(jié)果圖像中對(duì)應(yīng)像素點(diǎn)處理為前景色。
- 如果結(jié)構(gòu)元完全處于背景圖像外,就將膨脹結(jié)果圖像中對(duì)應(yīng)像素點(diǎn)處理為背景色。
膨脹操作:
在Opencv中,采用函數(shù)cv2.dilate()實(shí)現(xiàn)對(duì)圖像的膨脹操作,其語(yǔ)法結(jié)構(gòu)為:
dst=cv2.dilate(src,kernel[,anchor[,iterations[,borderType[,borderValue]]]])
- dst:膨脹后輸出的結(jié)果圖像,該圖像和原始圖像具有同樣的類型和大小。
- src:原圖像,即需要進(jìn)行膨脹的原始圖像,圖像的通道數(shù)可以是任意的。但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
- kernel:代表膨脹操作時(shí)所采用的結(jié)構(gòu)類型。它可以自定義生成,也可以通過(guò)函數(shù)從cv2.getStructutingElement()生成。
參數(shù)kernel、anchor、iterations、borderType、borderValue與函數(shù)cv2.erode()內(nèi)相應(yīng)參數(shù)的含義一致。
示例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)# 輸入結(jié)果 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. 通用形態(tài)學(xué)函數(shù):
? 腐蝕操作和膨脹操作是形態(tài)學(xué)運(yùn)算的基礎(chǔ),將腐蝕和膨脹操作進(jìn)行組合,就可以實(shí)現(xiàn)開(kāi)運(yùn)算、閉運(yùn)算(關(guān)運(yùn)算)、形態(tài)學(xué)梯度(Morphological Gradient)運(yùn)算、禮帽運(yùn)算(頂帽運(yùn)算)、黑帽運(yùn)算、擊中擊不中等多種不同形式的運(yùn)算。
OpenCV提供了函數(shù)cv2.morphologyEx()來(lái)實(shí)現(xiàn)上述形態(tài)學(xué)運(yùn)算,其語(yǔ)法結(jié)構(gòu)如下:
dst=cv2.morphologyEx(src,op,kernel[,anchor[,iterations[,borderType[,borderValue]]]]])
式中:
-
dst:代表經(jīng)過(guò)形態(tài)學(xué)處理后所輸出的目標(biāo)圖像,該圖像和原始圖像具有同樣的類型和大小。
-
src:代表需要進(jìn)行形態(tài)學(xué)操作的原始圖像。圖像的通道數(shù)可以是任意的,但是要求圖像的深度必須是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F中的一種。
-
op:代表操作類型,如下表所示。各種形態(tài)學(xué)運(yùn)算的操作規(guī)則,均是將腐蝕和膨脹操作進(jìn)行組合而得到的。
-
參數(shù)kernel、anchor、iterations、borderType、borderValue與函數(shù)cv2.erode()內(nèi)相應(yīng)參數(shù)的含義一致。
four. 開(kāi)運(yùn)算:
開(kāi)運(yùn)算進(jìn)行的操作是先將圖像腐蝕,再對(duì)腐蝕的結(jié)果進(jìn)行膨脹。開(kāi)運(yùn)算可以用于去噪、計(jì)數(shù)等。
例如,下圖中,通過(guò)先腐蝕后膨脹的開(kāi)運(yùn)算操作實(shí)現(xiàn)了去噪,其中:
- 左圖是原始圖像。
- 中間的圖是對(duì)原始圖像進(jìn)行腐蝕的結(jié)果。
- 右圖是對(duì)腐蝕后的圖像進(jìn)行膨脹的結(jié)果,即對(duì)原始圖像進(jìn)行開(kāi)運(yùn)算的處理結(jié)果。
除此以外,開(kāi)運(yùn)算還可以用于計(jì)數(shù)。例如,在對(duì)下圖的區(qū)域進(jìn)行計(jì)數(shù)前,可以利用開(kāi)運(yùn)算將連接在一起的不同區(qū)域劃分開(kāi),其中:
- 左圖是原始圖像。
- 中間的圖是對(duì)原始圖像進(jìn)行腐蝕的結(jié)果。
- 右圖是對(duì)腐蝕后的圖像進(jìn)行膨脹的結(jié)果,即對(duì)原始圖像進(jìn)行開(kāi)運(yùn)算的處理結(jié)果。
通過(guò)將函數(shù)cv2.morphologyEx()中操作類型參數(shù)op設(shè)置為“cv2.MORPH_OPEN”,可以實(shí)現(xiàn)開(kāi)運(yùn)算。其語(yǔ)法結(jié)構(gòu)如下: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. 閉運(yùn)算:
? 閉運(yùn)算是先膨脹、后腐蝕的運(yùn)算,它有助于關(guān)閉前景物體內(nèi)部的小孔,或去除物體上的小黑點(diǎn),還可以將不同的前景圖像進(jìn)行連接。
例如,通過(guò)先膨脹后腐蝕的閉運(yùn)算去除了原始圖像內(nèi)部的小孔(內(nèi)部閉合的閉運(yùn)算),其中:
-
左圖是原始圖像。
-
中間的圖是對(duì)原始圖像進(jìn)行膨脹的結(jié)果。
-
右圖是對(duì)膨脹后的圖像進(jìn)行腐蝕的結(jié)果,即對(duì)原始圖像進(jìn)行閉運(yùn)算的結(jié)果。
除此以外,閉運(yùn)算還可以實(shí)現(xiàn)前景圖像的連接。例如,利用閉運(yùn)算將原本獨(dú)立的兩部分前景圖像連接在一起,其中:
- 左圖是原始圖像。
- 中間的圖是對(duì)原始圖像進(jìn)行膨脹的結(jié)果。
- 右圖是對(duì)膨脹后的圖像進(jìn)行腐蝕的結(jié)果,即對(duì)原始圖像進(jìn)行閉運(yùn)算的結(jié)果。
示例:
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. 形態(tài)學(xué)梯度運(yùn)算:
? 形態(tài)學(xué)梯度運(yùn)算是用圖像的膨脹圖像減腐蝕圖像的操作,該操作可以獲取原始圖像中前景圖像的邊緣。
例如:
示例:
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. 禮帽運(yùn)算:
禮帽運(yùn)算是用原始圖像減去其開(kāi)運(yùn)算圖像的操作。禮帽運(yùn)算能夠獲取圖像的噪聲信息,或者得到比原始圖像的邊緣更亮的邊緣信息。
例如
- 左圖是原始圖像。
- 中間的圖是開(kāi)運(yùn)算圖像。
- 右圖是原始圖像減開(kāi)運(yùn)算圖像所得到的禮帽圖像。
示例:
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. 黑帽運(yùn)算:
? 黑帽運(yùn)算是用閉運(yùn)算圖像減去原始圖像的操作。黑帽運(yùn)算能夠獲取圖像內(nèi)部的小孔,或前景色中的小黑點(diǎn),或者得到比原始圖像的邊緣更暗的邊緣部分。
例如:
- 左圖是原始圖像。
- 中間的圖是閉運(yùn)算圖像。
- 右圖是使用閉運(yùn)算圖像減原始圖像所得到的黑帽圖像。
示例:
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. 核函數(shù):
? 在進(jìn)行形態(tài)學(xué)操作時(shí),必須使用一個(gè)特定的核(結(jié)構(gòu)元)。該核可以自定義生成,也可以通過(guò)函數(shù) cv2.getStructuringElement()構(gòu)造。函數(shù) cv2.getStructuringElement()能夠構(gòu)造并返回一個(gè)用于形態(tài)學(xué)處理所使用的結(jié)構(gòu)元素。該函數(shù)的語(yǔ)法格式為:
- retval=cv2.getStructuringElement(shape,ksize[,anchor])
該函數(shù)用來(lái)返回一個(gè)用于形態(tài)學(xué)操作的指定大小和形狀的結(jié)構(gòu)元素。函數(shù)中的參數(shù)含義如下。
- shape代表形狀類型,其可能的取值如表所示。
- ksize 代表結(jié)構(gòu)元素的大小。
- anchor 代表結(jié)構(gòu)元素中的錨點(diǎn)位置。默認(rèn)的值是(-1,-1),是形狀的中心。只有十字星型的形狀與錨點(diǎn)位置緊密相關(guān)。在其他情況下,錨點(diǎn)位置僅用于形態(tài)學(xué)運(yùn)算結(jié)果的調(diào)整。
當(dāng)然,除了使用該函數(shù),用戶也可以自己構(gòu)建任意二進(jìn)制掩碼作為形態(tài)學(xué)操作中所使用的結(jié)構(gòu)元素。
示例1:使用函數(shù)cv2.getStructuringElement()生成不同結(jié)構(gòu)的核。
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)# 輸出結(jié)果 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:使用不同的核進(jìn)行形態(tài)學(xué)操作
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()總結(jié)
- 上一篇: python-snap7安装各种报错
- 下一篇: SQL相关路径查询脚本