Python+Opencv分水岭算法
目錄
- 一、分水嶺算法(Watershed)簡介
- 二、分水嶺算法實現步驟
- 三、閾值和輪廓檢測硬幣分割代碼實現與分析
- 四、分水嶺硬幣分割代碼實現
- 五、代碼效果展示與分析
- 參考資料
- 注意事項
一、分水嶺算法(Watershed)簡介
??所有的灰度圖像都可視為拓撲平面,我們將灰度值高的區域看成山峰,將灰度值低的區域看成山谷,我們向圖像上所有的"山谷"中注入不同顏色的水,不斷的注水,水位則會不斷上升,注入的水將灌滿山谷,并可能淹沒山峰,為了防止不同顏色的山谷中的水溢出匯合,我們可在匯合的地方筑起堤壩,故可將堤壩看作是對圖像的分割后形成的邊界。具體的事例如下圖所示。
二、分水嶺算法實現步驟
步驟1-構建梯度圖像。
步驟2-通過一定規則生成n個最初的注水區域(先驗知識或局部梯度最小值)。
步驟3-往注水區域內加水,當兩注水區域即將合并時,記錄下此時的邊界。
步驟4-當圖像邊緣徹底被分割成n個獨立區域是算法結束。
具體的實現過程如下圖所示:
三、閾值和輪廓檢測硬幣分割代碼實現與分析
# coding=utf-8 # 導入python包 from __future__ import print_function from skimage.feature import peak_local_max from skimage.morphology import watershed from scipy import ndimage import argparse import imutils import cv2# 設置參數并進行參數解析 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to input image") args = vars(ap.parse_args())# 讀取圖片 image = cv2.imread(args["image"]) # 進行mean—shift濾波 shifted = cv2.pyrMeanShiftFiltering(image, 21, 51) cv2.imshow("Input", image)# 進行圖片灰度化處理 gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY) # 進行閾值分割 thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] cv2.imshow("Thresh", thresh)# 在閾值圖片中尋找輪廓 cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) print("[INFO] {} unique contours found".format(len(cnts)))# 遍歷所有的輪廓并依次顯示不同的結果 for (i, c) in enumerate(cnts):((x, y), _) = cv2.minEnclosingCircle(c)cv2.putText(image, "#{}".format(i + 1), (int(x) - 10, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)cv2.drawContours(image, [c], -1, (0, 255, 0), 2)# 顯示輸出結果 cv2.imshow("Image", image) cv2.waitKey(0)
??上圖展示了使用閾值和輪廓的分割結果。通過觀察上圖我們可以發現,閾值分割并不能很好的將硬幣區分開來,輪廓檢測算法也不能很好的獲取所有的硬幣的完整輪廓,即這兩種思路都不能很好的解決硬幣檢測問題。
四、分水嶺硬幣分割代碼實現
# coding=utf-8 # 導入相應的python包 from skimage.feature import peak_local_max from skimage.morphology import watershed from scipy import ndimage import numpy as np import argparse import imutils import cv2# 設置并解析參數 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to input image") args = vars(ap.parse_args())# 讀取圖片 image = cv2.imread(args["image"]) # 進行mean shift濾波 shifted = cv2.pyrMeanShiftFiltering(image, 21, 51) cv2.imshow("Input", image)# 進行灰度化處理 gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY) # 進行閾值分割 thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] cv2.imshow("Thresh", thresh)# 計算從每個二元像素到最近零像素的精確歐幾里得距離,然后在距離圖中找到峰值 D = ndimage.distance_transform_edt(thresh) localMax = peak_local_max(D, indices=False, min_distance=20, labels=thresh)# 利用8連通性對局部峰進行連通分量分析,然后應用分水嶺算法 markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0] labels = watershed(-D, markers, mask=thresh) print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))# 循環顯示標簽 for label in np.unique(labels):# 如果該標簽為0,則表示其為背景,直接忽略if label == 0:continue# 為標簽區域分配內存并將在mask上繪制結果mask = np.zeros(gray.shape, dtype="uint8")mask[labels == label] = 255# 在mask上檢測輪廓并獲得最大的一個輪廓cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)# 畫一個圈把物體圍起來((x, y), r) = cv2.minEnclosingCircle(c)cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2)cv2.putText(image, "#{}".format(label), (int(x) - 10, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)# 顯示最終結果 cv2.imshow("Output", image) cv2.waitKey(0)運行方法:python watershed_segement.py --image 圖片 (這里的圖片需要更換為自己的圖片)
五、代碼效果展示與分析
??上圖展示了分水嶺硬幣分割代碼的運行結果。通過觀察這些結果,我們可以獲得一些信息,即使用分水嶺算法可以很好地將具有重疊的硬幣分割開來,并自動的對圖片中的硬幣個數進行統計。
參考資料
[1] 參考鏈接
注意事項
[1] 該博客是本人原創博客,如果您對該博客感興趣,想要轉載該博客,請與我聯系(qq郵箱:1575262785@qq.com),我會在第一時間回復大家,謝謝大家的關注.
[2] 由于個人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進意見。
[3] 如果您在閱讀本博客時遇到不理解的地方,希望您可以聯系我,我會及時的回復您,和您交流想法和意見,謝謝。
[4] 本文測試的圖片可以通過該鏈接進行下載。網盤鏈接-提取碼:w2ss。
[5] 本人業余時間承接各種本科畢設設計和各種小項目,包括圖像處理(數據挖掘、機器學習、深度學習等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊,備注“項目”!!!
總結
以上是生活随笔為你收集整理的Python+Opencv分水岭算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python+Opencv常用小工具集合
- 下一篇: 解空间树(回溯算法,分支界限法)