使用OpenCV和C++实现的分水岭算法(Watershed)

分水岭算法(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=
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分水岭算法是一种基于图像的分割算法,可以将图像分成若干个不同的区域。OpenCV库中也提供了分水岭算法实现。 以下是C++ OpenCV分水岭算法的基本流程: 1. 读取原始图像并转换为灰度图像。 ```c++ Mat srcImage = imread("image.jpg"); Mat grayImage; cvtColor(srcImage, grayImage, COLOR_BGR2GRAY); ``` 2. 对灰度图像进行二值化处理。 ```c++ Mat binaryImage; threshold(grayImage, binaryImage, 0, 255, THRESH_BINARY | THRESH_OTSU); ``` 3. 对二值化图像进行距离变换。 ```c++ Mat distImage; distanceTransform(binaryImage, distImage, DIST_L2, 3, 5); ``` 4. 对距离变换后的图像进行阈值处理,得到分水岭掩模。 ```c++ Mat watershedMask; threshold(distImage, watershedMask, 0.7 * 255, 255, THRESH_BINARY); ``` 5. 对分水岭掩模进行形态学操作,消除噪点。 ```c++ Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(watershedMask, watershedMask, MORPH_OPEN, kernel); ``` 6. 对原始图像进行分水岭算法操作,得到分割结果。 ```c++ Mat markers; connectedComponents(watershedMask, markers); // 对标记图像进行彩色映射 Mat markImage; markers.convertTo(markImage, CV_8UC1); applyColorMap(markImage, markImage, COLORMAP_JET); // 分水岭算法 watershed(srcImage, markers); ``` 7. 显示分割结果。 ```c++ imshow("Segmentation", srcImage); waitKey(0); ``` 以上就是C++ OpenCV分水岭算法的基本流程。需要注意的是,分水岭算法的效果受到参数的影响,需要根据具体场景进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值