分水岭算法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。
一般的分水岭算法会对微弱边缘,图像中的噪声,物体表面细微的灰度变化造成过度的分割。
以下为分水岭算法的示例程序。
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,,);
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(); if (!capture.isOpened())
{
cout << "can not open the video" << endl;
return -;
} Mat frame;
Mat binImage; bool stop = false;
while (!stop)
{
//读入视频帧,转换颜色空间,并分割通道
capture >> frame;
cvtColor(frame, binImage, CV_BGR2GRAY); threshold(binImage, binImage, , , THRESH_BINARY); //膨胀图像
dilate(binImage, binImage, Mat()); /*分水岭算法*/
//*************************************************************
Mat fg;
//腐蚀图像6次
erode(binImage, fg, Mat(), Point(-, -), );
// Identify image pixels without objects
Mat bg; //膨胀图像6次
dilate(binImage, bg, Mat(), Point(-, -), ); imshow("bg", bg);
//进行固定阈值操作
threshold(bg, bg, , , THRESH_BINARY_INV); // Show markers image
Mat markers(binImage.size(), CV_8U, Scalar());
markers = fg + bg;
imshow("markers image", markers);
WatershedSegmenter segmenter;
segmenter.setMarkers(markers);
segmenter.process(frame); imshow("segmentation", segmenter.getSegmentation());
imshow("Watersheds", segmenter.getWatersheds());
}
waitKey();
return ;
}