必威体育Betway必威体育官网
当前位置:首页 > IT技术

分水岭算法原理和c++实现

时间:2019-08-04 00:40:00来源:IT技术作者:seo实验室小编阅读:87次「手机版」
 

分水岭算法

算法原理

关于分水岭算法的介绍和原理,大家可以去看这篇博客,上面有很多动图,十分生动有趣:https://www.cnblogs.com/mikewolf2002/p/3304118.html。我们,先来看一下OpenCV提供的分水岭算法的函数接口

void watershed( InputArray image, InputOutputArray markers ); 

输入图像必须是3通道的RGB图像,最为关键的是第二个参数markers,这个参数包含不同区域的轮廓,每个轮廓有一个自己唯一的编号,轮廓的定位可以通过Opencv中findContours方法实现。然后分水岭算法会根据markers传入的轮廓作为种子(也就是所谓的注水点),对图像上其他的像素点根据分水岭算法规则进行判断,并对每个像素点的区域归属进行划定,直到处理完图像上所有像素点。而区域与区域之间的分界处的值被置为“-1”,以做区分。

算法步骤

参考:https://blog.csdn.net/kakiebu/article/details/82965629

  • 将RGB图像灰度化
  • 使用大津法转为二值图,并做形态学闭合操作
  • 形态学闭操作
  • 距离变换
  • 将距离变换结果归一化到[0-1]之间
  • 将图像取值范围变为8位(0-255)
  • 再使用大津法转为二值图,并做形态学闭合操作
  • 使用findContours寻找marks
  • 对原图做形态学的腐蚀操作
  • 执行分水岭算法
  • 随机分配颜色和显示

代码实现

//分水岭算法
Mat Watersegment(Mat src) {
	int row = src.rows;
	int col = src.cols;
	//1. 将RGB图像灰度化
	Mat grayImage = speed_rgb2gray(src);
	//2. 使用大津法转为二值图,并做形态学闭合操作
	threshold(grayImage, grayImage, 0, 255, THRESH_binary | THRESH_OTSU);
	//3. 形态学闭操作
	Mat kernel = getstructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
	morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);
	//4. 距离变换
	distanceTransform(grayImage, grayImage, DIST_L2, DIST_MASK_3, 5);
	//5. 将图像归一化到[0, 1]范围
	normalize(grayImage, grayImage, 0, 1, NORM_MINMAX);
	//6. 将图像取值范围变为8位(0-255)
	grayImage.convertTo(grayImage, CV_8UC1);
	//7. 再使用大津法转为二值图,并做形态学闭合操作
	threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);
	morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);
	//8. 使用findContours寻找marks
	vector<vector<Point>> contours;
	findContours(grayImage, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
	Mat marks = Mat::zeros(grayImage.size(), CV_32SC1);
	for (size_t i = 0; i < contours.size(); i++)
	{
		//static_cast<int>(i+1)是为了分水岭的标记不同,区域1、2、3...这样才能分割
		drawContours(marks, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i + 1)), 2);
	}
	//9. 对原图做形态学的腐蚀操作
	Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
	morphologyEx(src, src, MORPH_ERODE, k);
	//10. 调用opencv的分水岭算法
	watershed(src, marks);
	//11. 随机分配颜色
	vector<Vec3b> colors;
	for (size_t i = 0; i < contours.size(); i++) {
		int r = theRNG().uniform(0, 255);
		int g = theRNG().uniform(0, 255);
		int b = theRNG().uniform(0, 255);
		colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
	}

	// 12. 显示
	Mat dst = Mat::zeros(marks.size(), CV_8UC3);
	int index = 0;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			index = marks.at<int>(i, j);
			if (index > 0 && index <= contours.size()) {
				dst.at<Vec3b>(i, j) = colors[index - 1];
			}
			else if (index == -1)
			{
				dst.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
			}
			else {
				dst.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
			}
		}
	}
	return dst;
}

算法效果

原图

在这里插入图片描述结果图

在这里插入图片描述

参考博客

https://www.cnblogs.com/wjy-lulu/p/7056466.html

相关阅读

FPGA nios软核双向IO以及单独引脚的输入输出控制的实

我就是想要实现这样的功能: 学过51单片机的都知道,每一个8位IO口都有单独每一位的读取或者赋值方式,这个在LCD等外设的驱动引脚控制

模拟退火(Simulated Annealing, SA)算法简介与MATLAB

目录 模拟退火算法概述 算法步骤 算法特点 模拟退火算法MATLAB实现 【例1】一元/多元函数优化 【例2】TSP问题 模拟退火算法概述

瑞利信道:从原理到实现

瑞利信道模型 瑞利信道模型是无线通信信道最重要、最基础的的仿真模型。无线信道中的平坦衰落信道基本上都是在瑞利信道模型的基

百度霸屏是什么,如何实现霸屏广告?

百度霸屏百度霸屏顾名思义,也就是当你在百度中搜索某个关键词后,下面出现的展现信息全是你的文章内容或广告。当然这个针对的是百

多屏互动技术研究(二)之WifiDisplay(Miracast)技术原理

WifiDisplay(Miracast)技术原理及实现 文章目录WifiDisplay(Miracast)技术原理及实现1. WifiDisplay简介2. WifiDisplay协议流程3

分享到:

栏目导航

推荐阅读

热门阅读