OpenCv笔记(五)--图像分割与分水岭算法

距离变换

输出像素的值为,输入图像中,与最近的零像素的距离,可显示物体靠质心的位置。

一般先对灰度图像取反,即转化为黑色背景。

void distanceTransform( InputArray src, OutputArray dst,
                        int distanceType, int maskSize, int dstType=CV_32F);
//distanceType,输入DIST_C,DIST_L1,DIST_L2,分别表示计算四连通,八连通,和精准的欧氏距离
//markSize输入3/5.表示使用3x3/5x8的掩膜

分水岭算法

先通过距离变换求出物体质心后,将其想象成山顶,而其他地方为山谷,灌水后,山谷被填满,只剩下山顶,图像就被分割开来。

void watershed( InputArray image, InputOutputArray markers );
//输入8位三通道图像,输入cv_32SC1的Markers标记。
//输出给markers,0为不确定区域,-1为边界。

实战演练

处理流程

  1. 将白色背景转化为黑色
  2. sharp,使用拉普拉斯算子将图像对比度提高,突出边缘。
  3. 二值化
  4. 距离变换
  5. 归一化[0~1]之间
  6. 再次二值化
  7. 腐蚀
  8. 发现轮廓
  9. 绘制轮廓/轮廓编号
  10. 分水岭变换
  11. 着色输出
#include<opencv2/opencv.hpp>
#include<opencv2/core/mat.hpp>
#include<iostream>
#include<vector>
using namespace std;
using namespace cv;

int main()
{
	Mat src0;
	Mat src, dst;
	src = imread("C:/Users/LBJ/Desktop/OpenCVTest/puke.png");
	if (!src.data)
	{
		cout << "The iamge is empty" << endl;
		return -1;
	}
	imshow("input_img", src);
	src0 = src;


	//背景转化为黑色
	cvtColor(src, src, CV_BGR2GRAY);
	threshold(src, src, 251, 255, THRESH_TOZERO_INV);
	medianBlur(src, src, 5);

	//锐化提高边缘对比度
	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1,
		1, -8, 1,
		1, 1, 1);
	Mat laplas, sharp = src;
	filter2D(sharp, laplas, CV_32F, kernel, Point(-1, -1), 0);
	src.convertTo(sharp, CV_32F);
	sharp = sharp - laplas * 5;
	sharp.convertTo(sharp, CV_8U);

	threshold(sharp, sharp, 30, 255, THRESH_BINARY | THRESH_OTSU);

	//距离变换0
	Mat distan;
	distanceTransform(sharp, distan, CV_DIST_L2, CV_DIST_MASK_PRECISE);
	normalize(distan, distan, 0, 255, NORM_MINMAX);
	threshold(distan, distan, 0.4 * 255, 255, THRESH_BINARY);



	//腐蚀
	Mat marks = Mat::zeros(src.size(), CV_32SC1);
	Mat erod;
	Mat ker = Mat::ones(Size(3, 3), CV_8U);
	erode(distan, erod, ker, Point(-1, -1));

	//发现轮廓 绘制轮廓
	Mat dist_8u;
	erod.convertTo(dist_8u, CV_8UC1);
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	findContours(dist_8u, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	for (int i = 0; i < contours.size(); i++)
	{
		drawContours(marks, contours, i, Scalar::all(i + 1), -1, 8, hierachy, 0, Point(0, 0));

	}
	circle(marks, Point(5, 5), 3, Scalar(255, 255, 255), -1);

	//分水岭变换
	cvtColor(src0, src0, CV_BGR2GRAY);
	threshold(~src0, src0, 20, 255, THRESH_BINARY);
	cvtColor(src0, src0, CV_GRAY2BGR);

	watershed(src0, marks);
	Mat marker = Mat::zeros(marks.size(), CV_8UC1);
	marks.convertTo(marker, CV_8UC1);
	bitwise_not(marker, marker, Mat());

	dst = Mat::zeros(src0.size(), src0.type());
	RNG rng;
	vector<Vec3b> colors;
	for (size_t i = 0; i < contours.size(); i++)
	{
		int r = rng.uniform(0, 255);
		int g = rng.uniform(0, 255);
		int b = rng.uniform(0, 255);
		colors.push_back(Vec3b(uchar(b), uchar(g), uchar(r)));
	}

	for (size_t row = 0; row < marks.rows; row++)
	{
		for (size_t col = 0; col < marks.cols; col++)
		{
			if (marks.at<int>(row,col)==-1)
			{
				dst.at<Vec3b>(row, col) = Vec3b(255, 255, 255);
			}
			else if (marks.at<int>(row, col) >0 && marks.at<int>(row, col)<=static_cast<int>(contours.size()))
			{
				dst.at<Vec3b>(row, col) = colors[marks.at<int>(row, col)-1];
			}
			else
			{
				continue;
			}
		
		}


	}
	imshow("output", dst);

	waitKey(0);
	return 0;
}



感觉分割的效果还是有待提高的,后续再优化

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值