分水岭分割算法(watershed segmentation)的C++实现(法1)

运行环境:ubuntu16.04+Qt+opencv2.4.13

参考链接:http://blog.csdn.net/u010741471/article/details/45193521

watershedsegmenter.h

#ifndef WATERSHEDSEGMENTER
#define WATERSHEDSEGMENTER

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class WatershedSegmenter {

  private:
      //用来表示标记(图)
      cv::Mat markers;

  public:
       //设置标记图
      void setMarkers(const cv::Mat& markerImage) {

        //watershed()的输入参数必须为一个32位有符号的标记,所以要先进行转换
        markerImage.convertTo(markers,CV_32S);
      }
      //执行watershed()
      cv::Mat process(const cv::Mat &image) {

        // Apply watershed
        cv::watershed(image,markers);

        return markers;
      }

      // 以图像形式返回结果
      cv::Mat getSegmentation() {

        cv::Mat tmp;
    // 从32S到8U(0-255)会进行饱和运算,所以像素高于255的一律复制为255
        markers.convertTo(tmp,CV_8U);//

        return tmp;
      }

      // 以图像形式返回分水岭(我理解的是分割线)
      cv::Mat getWatersheds() {

        cv::Mat tmp;
        //在设置标记图像,即执行setMarkers()后,边缘的像素会被赋值为-1,其他的用正整数表示
        //下面的这个转换可以让边缘像素变为-1*255+255=0,即黑色,其余的溢出,赋值为255,即白色。
        markers.convertTo(tmp,CV_8U,255,255);
        return tmp;
      }
};

#endif // WATERSHEDSEGMENTER

main.cpp

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "watershedsegmenter.h"

using namespace std;
using namespace cv;

int main()
{
    // Read input image 原图
    Mat image= imread("/home/osksh/skin_c/dulani_anuradha4.jpg");
    if (!image.data)
        return 0;

    // Display the image
    namedWindow("Original Image");
    imshow("Original Image",image);

    Mat binary,fg,bg;
    cvtColor(image,binary,CV_RGBA2GRAY);

    //Display the binary image
    namedWindow("Binary Image");
    imshow("Binary Image",binary);

    // 由二值图像获得前景。腐蚀。移除噪点与微小物体

    erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6);

    // Display the foreground image
    namedWindow("Foreground Image");
    imshow("Foreground Image",fg);

    //膨胀二值图来获取背景(只有草地,没有树林)
    dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6);
    threshold(bg,bg,150,128,cv::THRESH_BINARY_INV);
    //最后一个参数的表示 ifsrc>1,dst=0,else dst=128。这样就使背景全为灰色(128)
    // Display the background image
    namedWindow("Background Image");
    imshow("Background Image",bg);

    // Show markers image
    Mat markers(binary.size(),CV_8U,cv::Scalar(0));
    markers= fg+bg;//使用重载操作符+
    namedWindow("Markers");
    imshow("Markers",markers);

    // Create watershed segmentation object
    WatershedSegmenter segmenter;

    // Set markers and process
    segmenter.setMarkers(markers);
    segmenter.process(image);

    // Display segmentation result
    namedWindow("Segmentation");
    imshow("Segmentation",segmenter.getSegmentation());

    // Display watersheds
    namedWindow("Watersheds");
    imshow("Watersheds",segmenter.getWatersheds());

    waitKey(0);
    return 0;
}