python+opencv圖像形態學處理
本篇博客主要是關於形態學中的腐蝕、膨脹、開運算、閉運算、禮帽和黑帽的函數用法。
內容會比較,為方便查閱。代碼的解釋會寫在代碼中。
用於測試的圖像原圖:
一、腐蝕
- 關於腐蝕就是將圖像的邊界腐蝕掉,或者說使得圖像整體上看起來變瘦了。它的操作原理就是卷積核沿着圖像滑動,如果與卷積核對應的原圖像的所有像素值都是1,那么中心元素保持原來的值,否則就變為0。這對於去除白噪聲很有用,也可以用於斷開兩個連載一起的物體。
- 通俗的講,腐蝕操作就是讓圖像整體看起來瘦一點。
- 但是老貓發現,這句話並不完全正確,腐蝕操作不一定會讓圖像變瘦,有可能還會讓它變胖。
例如:
1 #腐蝕 2 #讀取圖像 3 img1=cv.imread("oldcat.jpg") 4 5 #將圖像進行反向二值化操作,即將白色部分變為黑色,黑色部分變為白色 6 #ret,img2=cv.threshold(img1,80,255,cv.THRESH_BINARY_INV) 7 8 #定義一個3*3的卷積核
9 kernel=np.ones((3,3),np.uint8) 10 11 #圖像腐蝕:cv2.erode(輸入圖像,卷積核,iterations=腐蝕的次數) 12 erosion=cv.erode(img1,kernel,iterations=1) 13 14 #在圖像上添加文本,方便分清每個操作相對應的圖像 15 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 16 cv.putText(erosion,"erosion",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 17 18 #將原圖像和腐蝕操作的圖像放在同一個窗口顯示 19 glay=np.hstack((img1,erosion)) 20 cv.imshow("glay",glay) 21 cv.waitKey(0) 22 cv.destroyAllWindows()
效果圖:
可以發現:
相比於原圖,腐蝕並沒有變瘦,反而還“胖”了。
原因:
形態學處理是一個對二值化灰度圖像的處理,主要是對白色圖像的一個卷積操作。
由於原圖字體是黑色,底色為白色,所以在進行腐蝕操作的時候,卷積核中只要有一個點為0,卷積核的中心點也會為0。
解決方法:
對原圖像進行一個反向二值化處理,即將白色部分變為黑色,黑色部分變為白色
去掉上面代碼ret,img2=cv.threshold(img,80,255,cv.THRESH_BINARY_INV)的注釋,同時將erosion=cv.erode(img1,kernel,iterations=1)改為erosion=cv.erode(img2,kernel,iterations=1)
效果圖:
如圖所示:這樣腐蝕處理的圖像才會變瘦
二、膨脹
膨脹:卷積核所對應的原圖像的像素值只要有一個是1,中心像素值就是1。一般在除噪是,先腐蝕再膨脹,因為腐蝕在去除白噪聲的時候也會使圖像縮小,所以我們之后要進行膨脹。當然也可以用來將兩者物體分開。
例如:
1 import numpy as np 2 import cv2 as cv 3 #膨脹 4 #讀取圖像 5 img1=cv.imread("oldcat.jpg",0) 6 7 #將圖像進行反向二值化操作,即將白色部分變為黑色,黑色部分變為白色 8 ret,img2=cv.threshold(img1,80,255,cv.THRESH_BINARY_INV) 9 10 #定義一個3*3的卷積核 11 kernel=np.ones((3,3),np.uint8) 12 13 #圖像腐蝕:cv2.dilate(輸入圖像,卷積核,iterations=腐蝕的次數) 14 dilation=cv.dilate(img2,kernel,iterations=1) 15 16 #在圖像上添加文本,方便分清每個操作相對應的圖像 17 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 18 19 #將原圖像和膨脹操作的圖像放在同一個窗口顯示 20 glay=np.hstack((img1,dilation)) 21 cv.imshow("glay",glay) 22 cv.waitKey(0) 23 cv.destroyAllWindows()
效果圖:
腐蝕和膨脹是比較簡單的。
三、開運算
了解形態學基本處理的同學都知道,開運算和閉運算就是將腐蝕和膨脹按照一定的次序進行處理。但這兩者並不是可逆的,即先開后閉並不能得到原先的圖像。
例如:
1 import numpy as np 2 import cv2 as cv 3 #開運算 4 #先腐蝕,再膨脹 5 img1=cv.imread("oldcat.jpg",0) 6 #反二值化,小於127設為255,即黑變白;大於127的設為 0,即白變黑。 7 ret,img2=cv.threshold(img1,127,255,cv.THRESH_BINARY_INV) 8 9 #定義一個3*3的卷積核 10 kernel=np.ones((3,3),np.uint8) 11 12 #開運算 13 opening2=cv.morphologyEx(img2,cv.MORPH_OPEN,kernel) 14 15 #在圖像上添加文本,方便分清每個操作相對應的圖像 16 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 17 18 #將原圖像和開運算操作的圖像放在同一個窗口顯示 19 glay=np.hstack((img1,opening2)) 20 cv.imshow("glay",glay) 21 cv.waitKey(0) 22 cv.destroyAllWindows()
效果圖:
四、閉運算
閉運算:就是先膨脹,后腐蝕,也是不可逆的。
1 import numpy as np 2 import cv2 as cv 3 #閉運算 4 #先膨脹,后腐蝕 5 img1=cv.imread("oldcat.jpg",0) 6 #反二值化,小於127設為255,即黑變白;大於127的設為 0,即白變黑。 7 ret,img2=cv.threshold(img1,127,255,cv.THRESH_BINARY_INV) 8 9 #定義一個3*3的卷積核 10 kernel=np.ones((3,3),np.uint8) 11 12 #閉運算 13 closing=cv.morphologyEx(img2,cv.MORPH_CLOSE,kernel) 14 15 #在圖像上添加文本,方便分清每個操作相對應的圖像 16 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 17 18 #將原圖像和閉運算操作的圖像放在同一個窗口顯示 19 glay=np.hstack((img1,closing)) 20 cv.imshow("glay",glay) 21 cv.waitKey(0) 22 cv.destroyAllWindows()
效果圖:
五、梯度運算
梯度運算,類似於提取輪廓。梯度=膨脹-腐蝕
例如:
1 import numpy as np 2 import cv2 as cv 3 #梯度運算,類似於提取輪廓 4 #梯度=膨脹-腐蝕 5 img1=cv.imread("oldcat.jpg",0) 6 7 #反二值化,小於127設為255,即黑變白;大於127的設為 0,即白變黑。 8 ret,img2=cv.threshold(img1,127,255,cv.THRESH_BINARY_INV) 9 10 #定義一個3*3的卷積核 11 kernel=np.ones((3,3),np.uint8) 12 13 #梯度運算 14 gradient=cv.morphologyEx(img2,cv.MORPH_GRADIENT,kernel) 15 16 #在圖像上添加文本,方便分清每個操作相對應的圖像 17 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 18 19 #將原圖像和梯度運算操作的圖像放在同一個窗口顯示 20 glay=np.hstack((img1,gradient)) 21 cv.imshow("glay",glay) 22 cv.waitKey(0) 23 cv.destroyAllWindows()
效果圖:
六、禮帽
禮帽就是原始初入減去開運算結果
例如:
1 import numpy as np 2 import cv2 as cv 3 #禮帽,小線條 4 #禮帽=原始輸入-運算結果 5 img1=cv.imread("oldcat.jpg",0) 6 ret,img2=cv.threshold(img1,127,255,cv.THRESH_BINARY_INV) 7 kernel=np.ones((3,3),np.uint8) 8 9 #禮帽 10 tophat=cv.morphologyEx(img2,cv.MORPH_TOPHAT,kernel) 11 12 #在圖像上添加文本,方便分清每個操作相對應的圖像 13 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 14 15 #將原圖像和禮帽運算操作的圖像放在同一個窗口顯示 16 glay=np.hstack((img1,tophat)) 17 cv.imshow("glay",glay) 18 cv.waitKey(0) 19 cv.destroyAllWindows()
效果圖:
七、黑帽
黑帽=閉運算-原始輸入
例如:
1 import numpy as np 2 import cv2 as cv 3 #黑帽。只能看見大概輪廓 4 #黑帽=閉運算-原始輸入 5 img1=cv.imread("oldcat.jpg",0) 6 ret,img2=cv.threshold(img1,127,255,cv.THRESH_BINARY_INV) 7 kernel=np.ones((3,3),np.uint8) 8 9 #黑帽 10 blackhat=cv.morphologyEx(img2,cv.MORPH_BLACKHAT,kernel) 11 12 #在圖像上添加文本,方便分清每個操作相對應的圖像 13 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) 14 15 #將原圖像和開運算操作的圖像放在同一個窗口顯示 16 glay=np.hstack((img1,blackhat)) 17 cv.imshow("glay",glay) 18 cv.waitKey(0) 19 cv.destroyAllWindows()
效果圖:
八、總結
- 本篇博客主要是關於圖像形態學處理,文字描述雖然不多,但是每一行代碼都有解釋,並且每一個運算處理的效果圖都有原圖和處理后的圖像對比。
- 圖像形態學處理是針對灰度圖的,所以在讀取原圖的過程中,直接關閉了顏色通道,雖然方便但也有不足,就是圖像上,添加的文字信息也會失去顏色。具體可以觀察腐蝕處理和膨脹處理再讀取代碼上的區別。
- 為了方便更容易理解,我是將原圖進行了一個二值化反色處理,再進行相應的形態學處理。若不進行二值化反色處理,結果是跟我的效果圖是不一樣的。具體就是將代碼中的二值化處理代碼去掉,大家可以試一試,對比觀察,更深的理解形態學處理是什么實現的。
實踐出真知,博客的代碼很完整,但還需要自己實際寫一遍才能更加理解。