天天看點

C++ OpenCV基于距離變換與分水嶺的圖像分割

圖像分割

圖像分割,英文名image segmentation,就是把圖像分成若幹個特定的、具有獨特性質的區域并提出感興趣目标的技術和過程。它是由圖像處理到圖像分析的關鍵步驟。現有的圖像分割方法主要分以下幾類:

  • 基于門檻值的分割方法
  • 基于區域的分割方法
  • 基于邊緣的分割方法以及基于特定理論的分割方法

從數學角度來看,圖像分割是将數字圖像劃分成互不相交的區域的過程。圖像分割的過程也是一個标記過程,即把屬于同一區域的像索賦予相同的編号。

C++ OpenCV基于距離變換與分水嶺的圖像分割
  • 圖像分割的目标是将圖像中像素根據一定的規則分為若幹個(N)個cluster集合,I每個集合包含一類像素。
  • 根據算法分為監督學習算法和無監督學習算法,圖像分割的算法多數都是無監督學習算法。---KMeans
距離變換與分水嶺介紹

距離變換

C++ OpenCV基于距離變換與分水嶺的圖像分割

距離變換常見算法有兩種

  • 不斷膨脹/ 腐蝕得到
  • 基于倒角距離

分水嶺變換

C++ OpenCV基于距離變換與分水嶺的圖像分割

分水嶺變換常見的算法

基于浸泡理論實作

相關API

cv::distanceTransform(

InputArray src,

OutputArray dst,

OutputArray labels,

int distanceType,

int maskSize,

int labelType = DIST_LABEL_CCOMP

)

distanceType = DIST_L1/DIST_L2,

maskSize = 3x3,最新的支援5x5,推薦3x3、

labels離散維諾圖輸出,

dst輸出8位或者32位的浮點數,單一通道,大小與輸入圖像一緻

cv::watershed(

InputArray image,

InputOutputArray markers

)

操作步驟
  1. 将白色背景變成黑色-目的是為後面的變換做準備
  2. 使用filter2D與拉普拉斯算子實作圖像對比度提高,sharp
  3. 轉為二值圖像通過threshold
  4. 距離變換
  5. 對距離變換結果進行歸一化到[0~1]之間
  6. 使用門檻值,再次二值化,得到标記
  7. 腐蝕得到每個Peak - erode
  8. 發現輪廓 – findContours
  9. 繪制輪廓- drawContours
  10. 分水嶺變換 watershed
  11. 對每個分割區域着色輸出結果
代碼示範

建立一個項目opencv-0027,配置屬性(VS2017配置OpenCV通用屬性),然後在源檔案寫入#include和main方法

這次我們用opencv裡面自帶的一張圖像來實個這個方法

C++ OpenCV基于距離變換與分水嶺的圖像分割

運作顯示的圖像為

C++ OpenCV基于距離變換與分水嶺的圖像分割

1.将白色背景變成黑色

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們運作看一下

C++ OpenCV基于距離變換與分水嶺的圖像分割

可以看到右邊的已經把背景都換為黑色了。

2.使用filter2D與拉普拉斯算子實作圖像對比度提高,sharp

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們再運作看一下,左邊的就是生成的結果圖,可以看出左邊的清晰度更高了一些

C++ OpenCV基于距離變換與分水嶺的圖像分割

3.轉為二值圖像通過threshold

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們再運作看一下,左邊的圖像已經讓我們轉換為二值圖像了,也比較清晰

C++ OpenCV基于距離變換與分水嶺的圖像分割

4.距離變換

5.對距離變換結果進行歸一化到[0~1]之間

因為距離變換看不出任何效果,是以我們把4和5兩步放在一起顯示

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們再運作一下看看執行結果

C++ OpenCV基于距離變換與分水嶺的圖像分割

6.使用門檻值,再次二值化,得到标記

C++ OpenCV基于距離變換與分水嶺的圖像分割

顯示效果為

C++ OpenCV基于距離變換與分水嶺的圖像分割

7.腐蝕得到每個Peak

效果不太好看,我們需要再進行二值的腐蝕,把上面的代碼再修改一下

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們再看一下運作效果,可以看出來比剛才的效果好很多了

C++ OpenCV基于距離變換與分水嶺的圖像分割

8.标記并且開始查找輪廓

C++ OpenCV基于距離變換與分水嶺的圖像分割

這一步隻是查找輪廓,我們接下來繪制查找的輪廓再一起顯示出來

9.繪制輪廓

C++ OpenCV基于距離變換與分水嶺的圖像分割

上面drawContours和circle最後一個參數都是用了-1,代表着畫的輪廓裡面進行顔色填充

我們再顯示一下看看效果

C++ OpenCV基于距離變換與分水嶺的圖像分割

看到好像什麼也沒有,這是因為我們畫的輪廓太小了, 我們改一下顯示效果

C++ OpenCV基于距離變換與分水嶺的圖像分割

把最後顯示cv::imshow(imgdst,makers*5000)再乘5000,重新看一下顯示效果

C++ OpenCV基于距離變換與分水嶺的圖像分割

這會兒就可以看到繪制的輪廓出來了

10.分水嶺變換

C++ OpenCV基于距離變換與分水嶺的圖像分割

我們看看顯示的效果

C++ OpenCV基于距離變換與分水嶺的圖像分割

可以看出,每個輪廓都有明顯的區分開了。

11.對每個分割區域着色輸出結果

C++ OpenCV基于距離變換與分水嶺的圖像分割
C++ OpenCV基于距離變換與分水嶺的圖像分割

然後我們再運作看到最後結果

C++ OpenCV基于距離變換與分水嶺的圖像分割

-END-