zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    C++11线程池
    muduo的事件处理(Reactor模型关键结构)
    sed和awk
    gdb
    C#访问级别
    C#表达式树浅析
    C#并发实战Parallel.ForEach使用
    c#获取本月有哪些周六、周日
    重装了Devexpress后项目报Dll引用找不到问题解决办法
    C#单例模式
  • 原文地址:https://www.cnblogs.com/farewell-farewell/p/6021780.html
Copyright © 2011-2022 走看看