opencv3实现分水岭算法-watershed函数

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

bool g_bDrawing = false;
Point g_CurrPoint, g_OrgPoint;
int g_nThick = 5, g_nBlue = 255, g_nGreen = 255, g_nRed = 0;
int g_nImageOneValue = 49;
Mat srcImage;
Mat grayImage;
Mat maskImage;

/*注意:不能在毁掉函数中写入未初始化的矩阵类,所以需要用时,需要写一个标志位,然后再在while(1)循环内使用*/
void onMouse(int event, int x, int y, int flag, void *param)
{
	Mat &img = *(cv::Mat*)param;

	switch (event)
	{
		//移动鼠标的时候
	case CV_EVENT_MOUSEMOVE:
	{
							   g_OrgPoint = g_CurrPoint;
							   g_CurrPoint = Point(x, y);

							   if (g_bDrawing == 1)
							   {
								   line(srcImage, g_CurrPoint, g_OrgPoint, Scalar(g_nBlue, g_nGreen, g_nRed), g_nThick);
								   imshow("【鼠标事件窗口】", srcImage);

								   //在掩码图上进行显示
								   line(maskImage, g_CurrPoint, g_OrgPoint, Scalar(g_nBlue, g_nGreen, g_nRed), g_nThick);
								   imshow("【掩码图像】", maskImage);
							   }
	}
		break;
		//点击鼠标左键时
	case CV_EVENT_LBUTTONDOWN:
	{
								 g_bDrawing = true;
								 g_OrgPoint = Point(x, y);
								 g_CurrPoint = g_OrgPoint;
	}
		break;
		//松开鼠标左键时
	case CV_EVENT_LBUTTONUP:
	{
							   g_bDrawing = false;
	}
		break;
	}
}

int main()
{
	Mat tempImage;
	RNG &rng = theRNG();

	srcImage = imread("2.jpg");

	//用一个变量来存储原图像
	Mat g_srcImage;
	srcImage.copyTo(g_srcImage);

	//为掩码图 分配空间
	//因为后面需要在掩码图像中寻找轮廓,所以需要一幅单通道的图像
	maskImage.create(srcImage.size(), CV_8UC1);
	maskImage = Scalar::all(0);

	//需要得到一个 三个通道的灰度图, 以便之后在该灰度图中画上彩色,便于看清效果
	//首先将原图灰度化,再将灰度化的图转换到 bgr空间中
	cvtColor(srcImage, tempImage, CV_BGR2GRAY);
	cvtColor(tempImage, grayImage, CV_GRAY2BGR);

	namedWindow("【鼠标事件窗口】");
	setMouseCallback("【鼠标事件窗口】", onMouse, 0);

	namedWindow("【滚动条窗口】", 0);
	createTrackbar("thick", "【滚动条窗口】", &g_nThick, 100, 0);
	createTrackbar("Blue", "【滚动条窗口】", &g_nBlue, 255, 0);
	createTrackbar("Green", "【滚动条窗口】", &g_nGreen, 255, 0);
	createTrackbar("Red", "【滚动条窗口】", &g_nRed, 255, 0);
	createTrackbar("Value", "【滚动条窗口】", &g_nImageOneValue, 100, 0);

	char key;
	while (1)
	{
		imshow("【鼠标事件窗口】", srcImage);
		key = waitKey();
		if (key == 27)
			break;

		//如果检测到 键值是1 则恢复原图
		if (key == '1')
		{
			g_srcImage.copyTo(srcImage);
			maskImage = Scalar::all(0);
			imshow("【鼠标事件窗口】", srcImage);
		}

		//如果检测到空格 则开始执行分水岭算法
		if (key == ' ')
		{
			//分水岭算法的步骤:
			/*1、首先在掩码图中找到轮廓, 目的是让区域有索引值
			  2、用索引值来替代轮廓所包围的所有像素,使在一个轮廓中的像素,具有相同的像素值
			  3、利用分水岭算法函数将 区域内的像素值用索引值来代替
			  4、遍历得到的图像,使具有相同像素值的元素得到同一种颜色,方便显示(这一步 是使之前不易显示的图像得到显示)*/

			//首先,在掩码图像中寻找轮廓
			vector<vector<Point>> contours;
			vector<Vec4i> hierarchy;
			findContours(maskImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

			//利用分水岭算法函数
			//因为该函数的输出的图像和输入的图像是一个类型的,所以需要借助中间变量,同时也要保证中间变量具有索引值
			//这就可以通过在中间变变量中绘制轮廓来实现对轮廓索引值的标注
			Mat midImage(maskImage.size(), CV_32S, Scalar(0));
			for (int i = 0; i < (int)contours.size(); i++)
			{
				//让每个像素都得到标记
				drawContours(midImage, contours, i, Scalar(i + 1), -1/*填充*/, 8, hierarchy);
			}
			imshow("【绘制轮廓的图】", midImage);
			//分水岭算法的实现
			//函数中的midImage已经为图像的每个像素储存了索引值,就利用这些索引值对原图像进行分水岭操作
			//以标记作为基准,利用分水岭算法进行扩展
			watershed(g_srcImage, midImage);

			//显示分水岭算法后的图像
			imshow("【分水岭算法结果图】", midImage);

			//遍历得到的掩码图像,用颜色值来替代相同的索引值
			//在这之前需要先定义一个随机颜色
			vector<Vec3b> rngColor((int)contours.size());
			rngColor.clear();
			for (int i = 0; i < (int)contours.size(); i++)
			{
				uchar blue = rng.uniform(0, 255);
				uchar green = rng.uniform(0, 255);
				uchar red = rng.uniform(0, 255);

				rngColor.push_back(Vec3b(blue, green, red));
			}
			//开始绘制
			Mat waterImage(srcImage.size(), CV_8UC3);
			for (int i = 0; i < midImage.rows; i++)
			{
				for (int j = 0; j < midImage.cols; j++)
				{
					int g_nValue = midImage.at<int>(i, j);

					if (g_nValue == -1)
						waterImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
					else if (g_nValue == 0)
						waterImage.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
					else
						waterImage.at<Vec3b>(i, j) = rngColor[g_nValue - 1];
				}
			}
			waterImage = waterImage * ((1 + g_nImageOneValue) / 100.0) + grayImage * (1 - ((1 + g_nImageOneValue) / 100.0));
			imshow("【分水岭图像】", waterImage);
		}
	}

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值