OpenCV——分水岭算法

分水岭算法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。

一般的分水岭算法会对微弱边缘,图像中的噪声,物体表面细微的灰度变化造成过度的分割。

以下为分水岭算法的示例程序。

watershedSegmenter.h

#if !defined WATERSHS
#define WATERSHS

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

class WatershedSegmenter {

  private:
      Mat markers;

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

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

        // Apply watershed
        watershed(image,markers);

        return markers;
      }

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

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

        return tmp;
      }

      // 以图像形式返回分水岭
     Mat getWatersheds() {

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


#endif

main.cpp

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

using namespace std;
using namespace cv;
int main()
{
    //设置视频读入,括号里面的数字是摄像头的选择,一般自带的是0
    VideoCapture capture(0);

    if (!capture.isOpened())
    {
        cout << "can not open the video" << endl;
        return -1;
    }

    Mat frame;
    Mat binImage;

    bool stop = false;
    while (!stop)
    {
        //读入视频帧,转换颜色空间,并分割通道
        capture >> frame;
        cvtColor(frame, binImage, CV_BGR2GRAY);

        threshold(binImage, binImage, 120, 255, THRESH_BINARY);


        //膨胀图像
        dilate(binImage, binImage, Mat());

        /*分水岭算法*/
        //*************************************************************
        Mat fg;
        //腐蚀图像6次
        erode(binImage, fg, Mat(), Point(-1, -1), 6);
        // Identify image pixels without objects
        Mat bg;

        //膨胀图像6次
        dilate(binImage, bg, Mat(), Point(-1, -1), 6);

        imshow("bg", bg);
        //进行固定阈值操作 
        threshold(bg, bg, 1, 128, THRESH_BINARY_INV);


        // Show markers image
        Mat markers(binImage.size(), CV_8U, Scalar(0));
        markers = fg + bg;
        imshow("markers image", markers);
        WatershedSegmenter segmenter;
        segmenter.setMarkers(markers);
        segmenter.process(frame);

        imshow("segmentation", segmenter.getSegmentation());
        imshow("Watersheds", segmenter.getWatersheds());
    }
    waitKey(0);
    return 0;
}
原文地址:https://www.cnblogs.com/farewell-farewell/p/6021780.html