opencv (五十)图像分割——分水岭法

小白学视觉,笔记,扩展

opencv (五十)图像分割——分水岭法_第1张图片

opencv (五十)图像分割——分水岭法_第2张图片

#include 
#include 

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat img, imgGray, imgMask, img_;
	Mat maskWaterShed;  // watershed()函数的参数
	img = imread("lenaw.png");  //含有标记的图像
	img_ = imread("lena.png");  //原图像
	cvtColor(img, imgGray, COLOR_BGR2GRAY);

	//二值化并开运算
	threshold(imgGray, imgMask, 254, 255, THRESH_BINARY);
	Mat k = getStructuringElement(0, Size(3, 3));
	morphologyEx(imgMask, imgMask, MORPH_OPEN, k);

	imshow("含有标记的图像", img);
	imshow("原图像", img_);
	imshow("imgMask", imgMask);
	
	vector> contours;
	vector hierarchy;
	findContours(imgMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
	//imshow("imgMask2", imgMask);

	//在maskWaterShed上绘制轮廓,用于输入分水岭算法
	maskWaterShed = Mat::zeros(imgMask.size(), CV_32S);
	for (int index = 0; index < contours.size(); index++)
	{
		drawContours(maskWaterShed, contours, index, Scalar::all(index + 1), -1, 8, hierarchy, INT_MAX);
	}
	
	//分水岭算法   需要对原图像进行处理
	watershed(img_, maskWaterShed);

	vector colors;  // 随机生成几种颜色,生成三种颜色,对三个标记进行注水
	for (int i = 0; i < contours.size(); i++)
	{
		int b = theRNG().uniform(0, 255);
		int g = theRNG().uniform(0, 255);
		int r = theRNG().uniform(0, 255);
		colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
	}

	Mat resultImg = Mat(img.size(), CV_8UC3);  //显示图像
	for (int i = 0; i < imgMask.rows; i++)
	{
		for (int j = 0; j < imgMask.cols; j++)
		{
			// 绘制每个区域的颜色
			int index = maskWaterShed.at(i, j);
			if (index == -1)  // 区域间的值被置为-1(边界)
			{
				resultImg.at(i, j) = Vec3b(255, 255, 255);
			}
			else if (index <= 0 || index > contours.size())  // 没有标记清楚的区域被置为0
			{
				resultImg.at(i, j) = Vec3b(0, 0, 0);
			}
			else  // 其他每个区域的值保持不变:1,2,…,contours.size()
			{
				resultImg.at(i, j) = colors[index - 1];  // 把些区域绘制成不同颜色
			}
		}
	}
	imshow("resultImg", resultImg);//分割注水结果,是不含原图像信息的
	resultImg = resultImg * 0.8 + img_ * 0.2;//为了便于查看,将分割结果和原图进行叠加
	//addWeighted(resultImg, 0.8, img_, 0.2, 0, resultImg);
	imshow("分水岭结果", resultImg);

	//绘制每个区域的图像,得到每个分割区域的原图
	for (int n = 1; n <= contours.size(); n++)
	{
		Mat resImage1 = Mat(img.size(), CV_8UC3);  // 声明一个最后要显示的图像
		for (int i = 0; i < imgMask.rows; i++)
		{
			for (int j = 0; j < imgMask.cols; j++)
			{
				int index = maskWaterShed.at(i, j);
				if (index == n)
					resImage1.at(i, j) = img_.at(i, j);
				else
					resImage1.at(i, j) = Vec3b(0, 0, 0);
			}
		}
		//显示图像
		imshow(to_string(n), resImage1);
	}

	waitKey(0);
	return 0;
}

在头像上,标记3个线条,作为注水点,不断注水,最后形成这三个区域的分水岭

为了便于找到这是哪个标记,二值化、开运算、轮廓提取;
在maskWaterShed上绘制轮廓,用于输入分水岭算法;
对原图像进行处理
opencv (五十)图像分割——分水岭法_第3张图片

随机生成几种颜色,生成三种颜色,对三个标记进行注水;
区域间的值被置为-1,白色填充(边界);
没有标记清楚的区域被置为0,黑色填充;
其他每个区域的值保持不变:1,2,…,contours.size(),用生成三种颜色,对三个标记进行注水;

分割注水结果,是不含原图像信息的;
为了便于查看,将分割结果和原图进行叠加;
opencv (五十)图像分割——分水岭法_第4张图片
绘制每个区域的图像,得到每个分割区域的原图
opencv (五十)图像分割——分水岭法_第5张图片

你可能感兴趣的:(OpenCV,C++,opencv,计算机视觉)