分水嶺算法:基于拓撲地貌的邊界提取
核心原理
分水嶺算法將圖像視為拓撲地貌,灰度值代表海拔高度。通過模擬浸水過程:
- 局部極小值:對應集水盆(區域內部)。
- 分水嶺線:集水盆之間的山脊(區域邊界)。
- 淹沒過程:從最低點開始注水,水位上升時在不同集水盆匯合處構建堤壩(分水嶺)。
關鍵步驟
- 預處理:
- 梯度計算:使用Sobel、Canny等算子提取邊緣(如?
gradient = cv2.Laplacian(image, cv2.CV_64F)
)。 - 降噪:高斯模糊或形態學開運算去除微小噪聲。
- 梯度計算:使用Sobel、Canny等算子提取邊緣(如?
- 標記控制:
- 前景標記:通過閾值分割或距離變換提取確定區域(如?
cv2.distanceTransform
)。 - 背景標記:膨脹操作擴展背景區域。
- 前景標記:通過閾值分割或距離變換提取確定區域(如?
- 分水嶺變換:使用?
cv2.watershed
?函數,標記區域邊界為?-1
。
import cv2 # OpenCV庫,用于圖像處理
import numpy as np # NumPy庫,用于數值計算def watershed_segmentation(image):"""使用分水嶺算法對輸入圖像進行分割,并標記邊界:param image: 輸入的BGR彩色圖像:return: 標記了分水嶺邊界的圖像(邊界顯示為紅色)"""# 1. 轉換為灰度圖像# 分水嶺通常基于灰度圖像的梯度計算,因此先將彩色圖像轉為灰度圖gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 2. 閾值分割(二值化)# 使用Otsu算法自動確定閾值,并反轉二值圖像(背景為白色,前景為黑色)# cv2.THRESH_BINARY_INV:反轉二值化,使前景為白色(255),背景為黑色(0)ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 3. 形態學開運算(去噪)# 定義3x3的全1結構元素(核)kernel = np.ones((3, 3), np.uint8)# 開運算 = 先腐蝕后膨脹,用于去除小的噪聲點(如孤立白點)opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)# 4. 確定背景區域# 對開運算結果進行膨脹操作,擴展背景區域,確保背景完全覆蓋噪聲sure_bg = cv2.dilate(opening, kernel, iterations=3)# 5. 距離變換(提取確定的前景)# 計算每個前景像素到最近背景像素的距離(歐式距離,L2范數)dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)# 對距離變換結果進行閾值化,提取確定的前景區域(距離較大的像素)ret, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)# 將結果轉換為8位無符號整數(0-255)sure_fg = np.uint8(sure_fg)# 6. 確定未知區域(邊界區域)# 未知區域 = 背景區域 - 確定的前景區域unknown = cv2.subtract(sure_bg, sure_fg)# 7. 標記連通區域# 對確定的前景區域進行連通組件標記(每個連通區域分配一個唯一標簽)ret, markers = cv2.connectedComponents(sure_fg)# 分水嶺算法要求標記從1開始(0表示未知區域),因此對所有標記+1markers = markers + 1# 將未知區域(unknown)的標記設為0markers[unknown == 255] = 0# 8. 應用分水嶺算法# 輸入原始圖像和標記矩陣,分水嶺算法會修改標記矩陣# 邊界區域的標記會被設為-1markers = cv2.watershed(image, markers)# 9. 標記邊界(可視化)# 將分水嶺邊界(markers == -1)在原圖上標記為藍色image[markers == -1] = [255, 0, 0] # BGR格式的藍色return image# 主程序
if __name__ == "__main__":# 讀取輸入圖像(確保路徑正確)image = cv2.imread('input.jpg')# 調用分水嶺分割函數result = watershed_segmentation(image)# 保存結果圖像cv2.imwrite('output.jpg', result)
?分水嶺算法主要是用于標記前景和背景的分界線,最終的處理結果如下: