分水岭算法(watershed)是一种比较基本的数学形态学分割算法,其基本思想是将灰度图像转换为梯度图像,将梯度值看作高低起伏的山岭,将局部极小值及其邻域看作一个“集水盆”。设想一个个“集水盆”中存在积水,且水位不断升高,淹没梯度较低的地方,当水漫过程停止后,图像就可以被分割成几块连通区域。
分水岭算法有不同的实现方法。本文要实现的是通过人为标注一些种子点,将这些种子点看作集水盆的底部,利用区域增长的方法,完成图像的分割。试图实现OpenCV中cv::watershed函数的功能,经过测试,与OpenCV相比分割结果相似,但性能差很多。(前者32ms左右,后者8ms左右,原因可能是循环中使用了cv::mat来访问图像中的元素,改用指针速度可能会提高很多)。
OpenCV函数的运行结果:(OpenCV函数对分割边缘也做了处理,我写的那个程序没有)
程序运行结果:
参考:
http://wenku.baidu.com/view/d1fde240336c1eb91a375d95.html
http://blog.csdn.net/fdl19881/article/details/6749976
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<vector>
#include<iostream>
#include<queue>
#include<fstream>
cv::Mat marker_mask;
cv::Mat g_markers;
cv::Mat img0, img, img_gray,wshed;
cv::Point_<int> prev_pt(-1,-1);
using std::vector;
using std::queue;
static void my_watershed(cv::Mat img,cv::Mat& markers,int comp_count);
static void mouse_event(int event,int x, int y,int flags, void*)
{
if(img.rows==0)
return;
if(event==CV_EVENT_LBUTTONUP||!(flags&CV_EVENT_FLAG_LBUTTON))
prev_pt=cv::Point_<int>(-1,-1);
else if(event==CV_EVENT_LBUTTONDOWN)
prev_pt=cv::Point2i(x,y);
else if(event==CV_EVENT_MOUSEMOVE&&(flags&CV_EVENT_FLAG_LBUTTON))
{
cv::Point2i pt(x,y);
if(prev_pt.x<0)
prev_pt=pt;
cv::line(marker_mask,prev_pt,pt,cv::Scalar(255,255,255),1,8,0);
cv::line(img,prev_pt,pt,cv::Scalar(255,255,255),1,8,0);
prev_pt=pt;
cv::imshow("image",img);
}
}
int main()
{
img0=cv::imread("Lenna.png",1);
img=img0.clone();
CvRNG rng = cvRNG(-1);
img_gray=img0.clone();
wshed=img0.clone();
marker_mask=cv::Mat(cv::Size(img0.cols,img0.rows),8,1);
g_markers=