python opencv之分水嶺演算法樣本,pythonopencv
本文介紹了python opencv之分水嶺演算法樣本,分享給大家,具體如下:
目標
- 使用分水嶺演算法對基於標記的映像進行分割
- 使用函數cv2.watershed()
原理:
灰階映像可以被看成拓撲平面,灰階值高的地區可以看出山峰,灰階值低的地區可以看成是山穀。向每一個山穀當中灌不同顏色的水。水位升高,不同山穀的水會匯合,為防止不同山穀的水匯合,小在匯合處建立起堤壩。然後繼續灌水,然後再建立堤壩,直到山峰都掩模。構建好的堤壩就是映像的分割。
此方法通常會得到過渡分割的結果,因為映像中的雜訊以及其他因素。為了減少此影響,opencv使用基於標記的分水嶺演算法,此演算法要設定哪些山穀中的匯合點,哪些不是。這是一種互動映像分割演算法那。我們要給已知對象打上不同表情。如果某個地區肯定是前景或對象,就使用某個顏色或灰階值標籤標記它。如果是背景那麼使用其他顏色進行標記,其餘不能確定的部分用0標記。然後使用分水嶺演算法,每次灌水,標籤會被更新,當兩個不同顏色的標籤相遇就會構建堤壩,知道所有山峰掩模,最後得到的邊界對象值是-1。
代碼:
對挨在一起的對象進行分割。
使用Otsu's 二值化後的結果為
要出去映像中的白色雜訊。可以使用形態學運算,使用閉運算去除對象中的空洞。
靠近對象中心的地區是前景,離對象遠的地區是背景,不確定的地區是邊界。
首先提取硬幣地區,使用腐蝕操作去掉邊緣,剩下的就是硬幣。但硬幣沒有接觸時,此方法有效,但是由於硬幣相互接觸,就要使用另外一種有效方法:距離變換加上合適的閾值。
之後,要尋找不確定是否是硬幣的地區。這裡需要膨脹操作。膨脹操作會將對象邊界延伸到背景當中。由於邊界地區被去除,現在就能知道哪些地區是前景,哪些是背景。
餘下的地區不知道如何區分,那麼使用分水嶺演算法。這些地區通常是前景與背景的交界處。從能否確認是否是背景的地區中減去確定是前景的地區就得到了邊界。
(前景和背景)
(上面的圖是直接使用作者的代碼後生產的結果,提取到了前景,為了示範一下不確定的地區,調了一下計算前景的距離變換的參數,使得中間出現不確定的地區)
這裡面使用個cv2.distanceTransform函數
該函數用於計算2值圖象中所有像素離其最近的值為0像素的近似距離。
參數為
cv2.distanceTransform(src, distanceType, maskSize[, dst]) → dst#src為輸入的二值映像。distanceType為計算距離的方式,可以是如下值DIST_USER = ⑴, //!< User defined distanceDIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2|DIST_L2 = 2, //!< the simple euclidean distanceDIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|)DIST_L12 = 4, //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846DIST_HUBER = 7 //!< distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345#maskSize是蒙板尺寸,只有0,3,5DIST_MASK_3 = 3, //!< mask=3DIST_MASK_5 = 5, //!< mask=5DIST_MASK_PRECISE = 0 //!< mask=0
import numpy as npimport cv2from matplotlib import pyplot as pltimg = cv2.imread('21.jpg')gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)kernel = np.ones((3,3),np.uint8)opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)# sure background areasure_bg = cv2.dilate(opening,kernel,iterations=3)#膨脹# Finding sure foreground areadist_transform = cv2.distanceTransform(opening,1,5)ret, sure_fg = cv2.threshold(dist_transform,0.2*dist_transform.max(),255,0)#參數改小了,出現不確定地區# Finding unknown regionsure_fg = np.uint8(sure_fg)unknown = cv2.subtract(sure_bg,sure_fg)#減去前景cv2.imshow('p',sure_fg)cv2.waitKey(0)
現在知道了那些背景是硬幣,可以建立標籤。(與原映像大小相同,資料類型為int32的數組)。
對於已經確定分類的地區,也就是背景和前景,使用整數標記,不確定的地區是用0標記。可以使用cv2.connectedComponents()函數來實現此功能。它會將背景標記為0,其他標記為位從1開始的正整數。
但是,如果背景標記為0,那麼分水嶺演算法會將其當成位置地區,所以使用不同的整數進行標記,對於不確定的地區,函數標記為0.
結果使用JET顏色地圖表示。深藍色未知地區,硬幣地區使用不同顏色。其餘部分用淺藍色。
使用分水嶺演算法
效果不錯
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。