1. 程式人生 > >Opencv學習——影象分割之分水嶺演算法

Opencv學習——影象分割之分水嶺演算法

分水嶺演算法是比較經典的影象分割演算法。最近看到一副區域檢測和統計的影象,感覺可以通過分水嶺演算法進行實現,於是順便對opencv的分水嶺演算法進行學習。如圖需要分割的影象:
這裡寫圖片描述

opencv有自帶的分水嶺分割示例,分割影象為硬幣影象,如圖:
這裡寫圖片描述
由於示例是python的程式碼,沒有C++的程式碼,所以打算先用C++實現示例中的功能,然後再對本文開頭的影象進行分割。

基本步驟

  1. 標記背景區域;
  2. 標記前景和未知區域;
  3. 合併標記影象;
  4. 分水嶺演算法進行分割。

標記背景影象

基本操作:灰度化->閾值分割(OTSU)->形態學去噪->形態學膨脹得到背景圖。

Mat src = imread("water_coins.jpg");
Mat frame;
cvtColor(src, frame, CV_BGR2GRAY);  //灰度化
Mat marker = frame.clone();
threshold(marker, frame, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);    //閾值分割(OTSU)
//去除噪聲,開運算
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(frame, frame, MORPH_OPEN, element, Point(-1
, -1), 2); //膨脹得到背景區域 Mat imgbg; dilate(frame, imgbg, element, Point(-1, -1), 3);

標記前景影象

標記前景採用了距離變換函式:

C++: void distanceTransform(InputArray src, OutputArray dst, int distanceType, int maskSize, int dstType=CV_32F )

src – 8位單通道二值影象.
dst – 輸出計算好的距離影象,8位或32位浮點型單通道影象 .
distanceType – 距離計算型別,包括曼哈頓距離,歐式距離等 .
maskSize – 距離變換掩膜尺寸 .
dstType – 輸出影象型別. CV_8U or CV_32F. CV_8U只能用於CV_DIST_L1.

具體步驟:

//找前景
Mat imageThin(frame.size(), CV_32FC1); //定義儲存距離變換結果的Mat矩陣  
distanceTransform(frame, imageThin, CV_DIST_L2, 5);  //距離變換 
normalize(imageThin, imageThin, 0, 255, CV_MINMAX);  //歸一化利於顯示
threshold(imageThin, imageThin, 200, 255, CV_THRESH_BINARY);

距離變換後效果圖:
這裡寫圖片描述
前景圖:
這裡寫圖片描述

標記未知區域

//找未知區域
imageThin.convertTo(imageThin, imgbg.type());
Mat unknown;
subtract(imgbg, imageThin, unknown); //影象相減

這裡寫圖片描述

合併標記影象

Mat imglabels, imgstats, imgcentroid;
connectedComponentsWithStats(imageThin, imglabels, imgstats, imgcentroid);  //連通域標記

imglabels = imglabels + 100;    //背景區域畫素為100

imglabels.convertTo(imglabels, CV_8U);
for (int i=0;i<unknown.rows;i++)
{
    uchar* ptr = unknown.ptr<uchar>(i);
    for (int j=0;j<unknown.cols;j++)
    {
        if (255==ptr[j])
        {
            imglabels.at<uchar>(i, j) = 0; //未知區域畫素為0
        }
    }
}

imglabels.convertTo(imglabels, CV_32S); //影象型別轉換

標記影象:
這裡寫圖片描述

分水嶺分割

watershed(src, imglabels);

分割後圖像:
這裡寫圖片描述
可以看到最後分割的效果,在某些地方由於硬幣靠的太近分割效果不理想。後續可以通過圓檢測等方式進行處理。

回到最初的氣泡圖,同樣可以通過上述步驟進行分割,主要是得到標記影象,氣泡圖由於無法確定背景區域,所以在選定前景區域後,其他區域都設定為未知區域。最後分割的效果如圖:
這裡寫圖片描述