分水岭算法学习(opencv)

分水岭算法可以将图像中的边缘转化成“山脉”,将均匀区域转化为“山谷”。首先,计算灰度图像的梯度,然后开始从用户指定点(或算法得到的点) 开始持续“灌注”盆地直到这些区域连在一起。基于这样产生的标记就可以吧区域合并在一起,合并后的区域又通过聚集的方式进行分割,好像图像被“填充”起来一样。通过这种方式,与指示点相连的盆地就为指示点“所拥有”。最终我们把图像分割成相应的标记区域。

例1:

 #include"cv.h"
#include"highgui.h"
using namespace cv;

Mat markerMask, img;
Point prePt(-1,-1);
void onMouse(int event ,int x,int y,int flags,void* param){
	if (event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON)) prePt = Point(-1,-1);
	if (event == CV_EVENT_LBUTTONDOWN)	prePt = Point(x,y);
	if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON)){
		Point pt(x,y);
		if (prePt.x < 0) prePt = pt;
		line(markerMask,prePt,pt,Scalar(255,255,255),5);
		line(img, prePt, pt, Scalar(255, 255, 255), 5);
		prePt = pt;
		imshow("原图", img);
	}

}
int main(){
	Mat img0 = imread("D:\\tongliya.jpg",1);
	img0.copyTo(img);
	namedWindow("原图",1);
	imshow("原图",img);
	Mat imgGray;//最后显示watershed效果图用
	cvtColor(img0,markerMask,CV_BGR2GRAY);
	cvtColor(markerMask,imgGray,CV_GRAY2BGR);
	markerMask = Scalar::all(0);
	setMouseCallback("原图",onMouse,NULL);
	while (1){
		int c = waitKey(10);
		if ((char)c == 'q' || (char)c == 27) return 0;

		if ((char)c == 'r'){
			img0.copyTo(img);
			markerMask = Scalar::all(0);
			imshow("原图",img);
		}
		if (char(c) == 'p'){
			vector<vector<Point>> contours;
			vector<Vec4i> hierarchy;
			int count=0;

			findContours(markerMask,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);<span style="color:#33CC00;">//输入图像image必须为一个2值单通道图像</span>
			if (contours.empty()) continue;

			Mat markers(markerMask.size(),CV_32S);
			markers = Scalar::all(0);

			for (int idx = 0; idx >= 0; idx = hierarchy[idx][0], count++)<span style="color:#33CC00;">//hierarchy[idx][0]表示后一个轮廓</span>
				drawContours(markers,contours,idx,Scalar::all(count+1),-1,8,hierarchy,INT_MAX);
			if (count == 0) continue;
			watershed(img0,markers);
			vector<Vec3b> colorTab;
			<span style="color:#33CC00;">//随机设置颜色</span>
                        for (int i = 0; i < count; i++)
			{
				int b = theRNG().uniform(0, 255);
				int g = theRNG().uniform(0, 255);
				int r = theRNG().uniform(0, 255);

				colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
			}
			Mat wshed(markers.size(),CV_8UC3);
			for (int i = 0; i < markers.rows;i++)
			for (int j = 0; j < markers.cols; j++){
				int tmp = markers.at<int>(i,j);
				if (tmp == -1) wshed.at<Vec3b>(i, j) = Vec3b(255,255,255);//边界值为-1
				else if (tmp <= 0 || tmp>count) wshed.at<Vec3b>(i, j) = Vec3b(0,0,0);
				else 
					wshed.at<Vec3b>(i, j) = colorTab[tmp-1];
			}
			imshow("分水岭变换1", wshed);
			wshed = 0.5*wshed + 0.5*imgGray;
			imshow("分水岭变换",wshed);		
		}	
	}
	return 0;

}



个人理解:

          1.watershed()函数接受两个参数,void watershed(InputArray image, InputOutputArraymarkers)

输入图像image为 8位3通道,markers为带有标记图像(or map),结果保存在markers中。

          2.markers根据标记把像素 设置为1,2,3.。。。。

          3.findContours contours参数为检测的轮廓数组,count记录轮廓组数,markers的结果也为1,2,....count,所以颜色也随机设为count种。

          4.根据markers值,不同区域绘制不同颜色,边界值为-1,绘制为白色。

           5.结果截图

例2:

#include "cv.h"
#include "highgui.h"
using namespace cv;
int main(){
    Mat img = imread("D:\\tongliya.jpg");
    imshow("original image",img);
    Mat imgGray;
    cvtColor(img,imgGray,CV_BGR2GRAY);
    imshow("gray image", imgGray);
    Mat binary;
    //adaptiveThreshold(imgGray,binary,255,ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,5,0);
    threshold(imgGray,binary,100,255,CV_THRESH_BINARY_INV);
    imshow("binary image", binary);
    Mat fg;
    erode(binary,fg,Mat(),Point(-1,-1),1);//255标注前景,腐蚀使高亮区域隔离且缩小,可以获取仅仅属于重要物体的像素
    imshow("foreground image",fg);
    Mat bg;
    dilate(binary,bg,Mat(),Point(-1,-1),1);//背景用128标注,膨胀使高亮区域得到扩展和联通
    threshold(bg,bg,1,128,THRESH_BINARY_INV);
    imshow("background image", bg);
    Mat markers(binary.size(),CV_8U,Scalar::all(0));
    markers = fg + bg;//分水岭算法输入参数
    imshow("markers image", markers);
    markers.convertTo(markers,CV_32S);
    watershed(img,markers);//更新标记图像
    Mat tmp = markers.clone();
    markers.convertTo(tmp,CV_8U);//返回标记图像,分水岭位于值0
    imshow("Segmentation",tmp);
    markers.convertTo(tmp,CV_8U,255,255);
    imshow("Watersheds边界", tmp);

    waitKey();
    return 0;
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值