分水嶺算法(學習筆記)

分水嶺算法watershed

  • 進行圖像分割
  • 基本的步驟
    • 通過形態學開運算對原圖像O去噪
    • 通過膨脹操作獲取“確定背景B”
    • 利用距離變換函數對圖像進行運算,並對其進行閾值處理,得到“確定前景F”
    • 計算未知區域UN(UN = O – B – F )
    • 利用函數connecedComponents對原圖像O進行標註
    • 對函數connecedComponents的標註結果進行修正
    • 使用分水嶺函數watershed完成對圖像的分割

操作小記

代碼
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('coins.jpg')
if img is None:
    print('Could not open or find the image ')
    exit(0)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
# cv.imshow("threshold", thresh)    #閾值處理後會有緊挨着(粘連)的情況
# 去噪處理
kernel = np.ones((3, 3), np.uint8)
opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)  # 開運算
# sure background area
sure_bg = cv.dilate(opening, kernel, iterations=3)  # 膨脹操作

# Finding sure foreground area
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)  # 距離背景點足夠遠的點認爲是確定前景

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)  # 確定未知區域:減法運算
# Marker labelling
ret, markers = cv.connectedComponents(sure_fg)  # 設定壩來阻止水匯聚

# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
markers = cv.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
plt.imshow(img)
plt.show()
效果

在這裏插入圖片描述

代碼分析

ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)

  • 函數的作用是進行閾值處理
  • 返回參數:ret爲閾值,thresh爲處理結果
  • 輸入參數中
    • gray爲輸入圖像的灰度圖像,上一行代碼cv.cvtColor(img, cv.COLOR_BGR2GRAY)進行了色彩空間的轉換
    • 0爲設定的閾值
    • 255代表圖像最大值
    • cv.THRESH_BINARY_INV + cv.THRESH_OTSU二值化的方式,THRESH_BINARY_INV表示採取反二進制閾值化,而`THRESH_OTSU``代表採用自適應圖像的二值化Otsu
      • 說明:反二進制閾值化:小於閾值取255,大於閾值取0
  • 測試中,ret=162.0thresh的效果如下:
    在這裏插入圖片描述
  • 相關資料:濾波和卷積

opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)

  • 函數的作用是去除噪聲
  • 輸入參數中
    • thresh是進行閾值處理的圖像
    • cv.MORPH_OPEN表示進行開運算,開運算就是對圖像先腐蝕再膨脹
    • kernel爲形態學運算的內核,上一句kernel = np.ones((3, 3), np.uint8)設置了參考點位於中心3x3的核
    • iterations用於設置迭代次數,這裏設置爲2
  • opening爲處理結果,效果如下:
    在這裏插入圖片描述
  • 相關資料:More Morphology Transformations

sure_bg = cv.dilate(opening, kernel, iterations=3)

  • 作用:用膨脹的方式獲取背景
  • sure_bg爲得到的結果,效果如下:
    在這裏插入圖片描述

# Finding sure foreground area
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)  # 距離背景點足夠遠的點認爲是確定前景

通過函數cv.distanceTransform(...)進行距離變換,cv.DIST_L2代表採用歐幾里得的距離計算公式,5代表掩膜尺寸,用來確定前景,然後通過閾值處理得到核心的區域,超過最大值的70%才留下來

dst = cv2.distanceTransform( src, distanceType, maskSize[, dst[, dstType]] )
  • src:8位單通道的二值圖像
  • distanceType:距離類型參數
  • maskSize:掩膜尺寸
  • dstType:目標圖像的類型,默認值爲cv_32F
  • dst :計算得到的目標圖像

distanceType取值
在這裏插入圖片描述
maskSize說明
在這裏插入圖片描述

得到效果如下:
在這裏插入圖片描述

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)  # 確定未知區域:減法運算

通過做減法來獲取到未知區域,確定的背景-確定的前景

確定未知區域

對確定的前景F進行膨脹放大——得到——確定的背景B
未知區域UN = 原圖像O—確定的背景B — 確定前景F
減法運算
在這裏插入圖片描述

unknown的效果如下:
在這裏插入圖片描述


# # Marker labelling
ret, markers = cv.connectedComponents(sure_fg)  # 設定壩來阻止水匯聚

# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0

用來設置水壩來分割背景和前景,將未知區域標記爲0

標註確定的前景圖像函數connectedComponents

cv2. connectedComponents中:背景標註爲0,其他對象使用從1開始的正整數標註

  • 數值0代表背景區域
  • 從數值1開始的值,代表不同的前景區域

在分水嶺算法中,標註0代表未知區域,所以需要對上面的標註結果進行調整

  • 數值1代表背景區域
  • 從數值2開始的值,代表不同的前景區域
  • 對未知區域進行標註,將計算出的未知區域標註爲0

retval, labels = cv2. connectedComponents(image )

  • images:8位單通道的待標註圖像
  • retval :返回標註的數量
  • labels :標註的結果圖像

markers = cv.watershed(img, markers)
進行分水嶺算法

Markers = cv2.watershed(image, markers )

Image: 輸入圖像,必須是一個8bit 3通道的圖像

  • 在處理之前必須用正數大致勾畫出圖像中的期望分割區域。
  • 每個區域被標註爲1、2、3等。對尚未確定的區域,需要將它們標註爲0.
  • 標註區域可以理解爲進行分水嶺算法分割的“種子”區域

markers: 32位單通道的標註結果,和image大小相同

  • 算法會根據markers傳入的輪廓作爲種子(也就是所謂的注水點),對圖像上其他的像素點根據分水嶺算法規則進行判斷,並對每個像素點的區域歸屬進行劃定
  • 每個像素要麼要麼被設置爲初期的“種子值”,要麼爲“-1”
  • 區域與區域之間的分界處的值被置爲“-1”
附錄

官方文檔:The Watershed Transformation

距離變換函數distanceTransform
提取前景對象
如果前景對象的中心(質心)距離值爲0的像素點距離較遠,會得到一個較大的值
如果前景對象的邊緣距離值爲0的像素點較近,會得到一個較小的值
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章