原文鏈接:http://www.juzicode.com/opencv-python-erode-dilate
回傳Opencv-Python教程
形態學變換是基于影像形狀的變換程序,通常用來處理二值影像,當然也可以用在灰度圖上,OpenCV中的形態學變換同平滑處理一樣也是基于一種“滑動視窗”的操作,不過在形態學變換中“滑動視窗”有一個更專業的名詞:“結構元”,也可以像平滑處理那樣稱呼為kernel,結構元的形狀有方形、十字形、橢圓形等,其形狀決定了形態學變換的特點,形態學變換主要有腐蝕、膨脹、開操作、閉操作等等,
1、腐蝕erode()
腐蝕操作可以將邊界的白色(前景)像素“腐蝕”掉,但仍能保持大部分白色,類似平滑處理的滑動視窗,用某種結構元在影像上滑動,當結構元覆寫原始影像中的所有像素都為“1”時,新影像中該像素點的值才為“1”(CV8U為255),腐蝕可以用來去除噪聲、去掉“粘連”,
介面形式:
cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) ->dst
- 引數含義:
- src:通道數任意;影像深度只能是CV_8U, CV_16U, CV_16S, CV_32F or CV_64F;
- kernel:可以由getStructuringElement()構建;
- dst:輸出影像,通道數和資料型別同src;
- anchor:錨點,默認使用(-1,-1)表示中心點;
- iterations:腐蝕次數;
- borderType:邊界型別;
- borderValue:邊界值;
下面是一個kernel大小為5和7的腐蝕例子:
import matplotlib.pyplot as plt
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
img = cv2.imread('..\\samples\\picture\\mnist-7.jpg',cv2.IMREAD_GRAYSCALE)
_,img = cv2.threshold(img,127,255,0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) #ksize=5,5
img_ret1 = cv2.erode(img,kernel,iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7)) #ksize=7x7,
img_ret2 = cv2.erode(img,kernel,iterations=1)
img_ret3 = cv2.erode(img,kernel,iterations=2) #ksize=7x7,腐蝕2次
#顯示影像
fig,ax = plt.subplots(2,2)
ax[0,0].set_title('原圖-mnist(juzicode.com)')
ax[0,0].imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) #matplotlib顯示影像為rgb格式
ax[0,1].set_title('erode ksize=5')
ax[0,1].imshow(cv2.cvtColor(img_ret1,cv2.COLOR_BGR2RGB))
ax[1,0].set_title('erode ksize=7')
ax[1,0].imshow(cv2.cvtColor(img_ret2,cv2.COLOR_BGR2RGB))
ax[1,1].set_title('erode ksize=7 iter=2')
ax[1,1].imshow(cv2.cvtColor(img_ret3,cv2.COLOR_BGR2RGB))
ax[0,0].axis('off');ax[0,1].axis('off');ax[1,0].axis('off');ax[1,1].axis('off')#關閉坐標軸顯示
plt.show()
運行結果:

原圖圖源:mnist
從運行結果可以看到kernel的ksize越大,iterations次數越多,影像看起來越“廋”,
2、膨脹dilate()
膨脹是腐蝕的逆操作,可以將邊界的白色(前景)像素“生長”擴大,滑動視窗經過白色像素時,只要結構元中有1個像素為“1”時,新影像中該像素點的值就為“1”(CV8U為255),膨脹可以用來增強連接、填充凹痕,
介面形式:
cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) ->dst
- 引數含義:
- src:通道數任意;影像深度只能是CV_8U, CV_16U, CV_16S, CV_32F or CV_64F;
- kernel:可以由getStructuringElement()構建;
- dst:輸出影像,通道數和資料型別同src;
- anchor:錨點,默認使用(-1,-1)表示中心點;
- iterations:腐蝕次數;
- borderType:邊界型別;
- borderValue:邊界值;
下面是一個kernel大小為5和7的膨脹例子:
import matplotlib.pyplot as plt
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
img = cv2.imread('..\\samples\\picture\\mnist-7-b.jpg',cv2.IMREAD_GRAYSCALE)
_,img = cv2.threshold(img,127,255,0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
img_ret1 = cv2.dilate(img,kernel,iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
img_ret2 = cv2.dilate(img,kernel,iterations=1)
img_ret3 = cv2.dilate(img,kernel,iterations=2)
#顯示影像
fig,ax = plt.subplots(2,2)
ax[0,0].set_title('原圖-mnist(juzicode.com)')
ax[0,0].imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) #matplotlib顯示影像為rgb格式
ax[0,1].set_title('dilate ksize=5')
ax[0,1].imshow(cv2.cvtColor(img_ret1,cv2.COLOR_BGR2RGB))
ax[1,0].set_title('dilate ksize=7')
ax[1,0].imshow(cv2.cvtColor(img_ret2,cv2.COLOR_BGR2RGB))
ax[1,1].set_title('dilate ksize=7 iter=2')
ax[1,1].imshow(cv2.cvtColor(img_ret3,cv2.COLOR_BGR2RGB))
ax[0,0].axis('off');ax[0,1].axis('off');ax[1,0].axis('off');ax[1,1].axis('off')#關閉坐標軸顯示
plt.show()
運行結果:
![]()
原圖圖源:mnist
從運行結果可以看到kernel的ksize越大,iterations次數越多,影像看起來越“胖”,
3、結構元生成getStructuringElement()
結構元生成函式用來生成形態學變換的kernel引數,
介面形式:
cv2.getStructuringElement(shape, ksize[, anchor]) ->retval
- 引數含義:
- shape:結構元(kernel)的形狀;
- ksize:結構元(kernel)的大小;
- anchor:錨點,默認使用(-1,-1)表示中心點;
其中shape屬性有可選的3種形狀:
| cv2.MORPH_RECT | 方形,所有的數值均為1 |
| cv2.MORPH_CROSS | 十字交叉形,在錨點坐標的水平和豎直方向的元素為1,其他為0 |
| cv2.MORPH_ELLIPSE | 橢圓形 |
下面是一個kernel大小為7,形狀不同的膨脹例子:
import matplotlib.pyplot as plt
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
img = cv2.imread('..\\samples\\picture\\mnist-7-b.jpg',cv2.IMREAD_GRAYSCALE)
_,img = cv2.threshold(img,127,255,0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
print('MORPH_RECT kernel:\n',kernel)
img_ret1 = cv2.dilate(img,kernel,iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(7,7))
print('MORPH_ELLIPSE kernel:\n',kernel)
img_ret2 = cv2.dilate(img,kernel,iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(7,7))
print('MORPH_CROSS kernel:\n',kernel)
img_ret3 = cv2.dilate(img,kernel,iterations=1)
#顯示影像
fig,ax = plt.subplots(2,2)
ax[0,0].set_title('原圖-mnist(juzicode.com)')
ax[0,0].imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) #matplotlib顯示影像為rgb格式
ax[0,1].set_title('MORPH_RECT kernel')
ax[0,1].imshow(cv2.cvtColor(img_ret1,cv2.COLOR_BGR2RGB))
ax[1,0].set_title('MORPH_ELLIPSE kernel')
ax[1,0].imshow(cv2.cvtColor(img_ret2,cv2.COLOR_BGR2RGB))
ax[1,1].set_title('MORPH_CROSS kernel')
ax[1,1].imshow(cv2.cvtColor(img_ret3,cv2.COLOR_BGR2RGB))
ax[0,0].axis('off');ax[0,1].axis('off');ax[1,0].axis('off');ax[1,1].axis('off')#關閉坐標軸顯示
plt.show()
運行結果:
VX公眾號: 桔子code / juzicode.com
cv2.__version__: 4.5.3
MORPH_RECT kernel:
[[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 1 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]]
MORPH_ELLIPSE kernel:
[[0 0 0 1 0 0 0]
[0 1 1 1 1 1 0]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[0 1 1 1 1 1 0]
[0 0 0 1 0 0 0]]
MORPH_CROSS kernel:
[[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[1 1 1 1 1 1 1]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]]
![]()
原圖圖源:mnist
從運行結果可以看到當使用方形MORPH_RECT的結構元時,新影像的邊界看起來仍然是方方正正的,但是使用十字形MORPH_CROSS和橢圓形MORPH_ELLIPSE的結構元時,邊界要顯得“圓滑”的多,
4、實際應用的例子
下面是一個用腐蝕去除噪聲的例子:
import matplotlib.pyplot as plt
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
img = cv2.imread('..\\samples\\picture\\mnist-7-noise.jpg',cv2.IMREAD_GRAYSCALE)
_,img = cv2.threshold(img,127,255,0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
img_ret1 = cv2.erode(img,kernel,iterations=2)
#顯示影像
fig,ax = plt.subplots(1,2)
ax[0].set_title('原圖 (juzicode.com)')
ax[0].imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) #matplotlib顯示影像為rgb格式
ax[1].set_title('erode ksize=7 iter=2')
ax[1].imshow(cv2.cvtColor(img_ret1,cv2.COLOR_BGR2RGB))
ax[0].axis('off');ax[1].axis('off')
plt.show()

原圖圖源:mnist
在原圖中白色小點表示的噪聲通過腐蝕操作被去除掉了,
下面是一個在五線譜中去除橫線的例子:
import matplotlib.pyplot as plt
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
img = cv2.imread('..\\samples\\data\\notes.png',cv2.IMREAD_GRAYSCALE)
_,img_bin = cv2.threshold(img,127,255,1)#二值反色
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(1,7))
img_erode = cv2.erode(img_bin,kernel,iterations=1)
img_dilate = cv2.dilate(img_erode,kernel,iterations=1)
#顯示影像
fig,ax = plt.subplots(3,1)
ax[0].set_title('原圖 (juzicode.com)')
ax[0].imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) #matplotlib顯示影像為rgb格式
ax[1].set_title('img_erode')
ax[1].imshow(cv2.cvtColor(img_erode,cv2.COLOR_BGR2RGB))
ax[2].set_title('img_dilate')
ax[2].imshow(cv2.cvtColor(img_dilate,cv2.COLOR_BGR2RGB))
ax[0].axis('off');ax[1].axis('off');ax[2].axis('off')
plt.show()

因為橫線是水平方向的,高度小長度大,先用一個1×7的結構元進行腐蝕,這時腐蝕會作用到垂直方向上,水平方向幾乎不會被影響到,從而將高度較小的橫線腐蝕掉,但是因為腐蝕操作將需要保留的符號也腐蝕掉了一部分,所以再用同樣的結構元進行一次膨脹操作,就能復原出符號的形狀,
擴展閱讀:
- OpenCV-Python教程
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293306.html
標籤:AI
