opencv_c++学习(十八)

本文介绍了使用OpenCV进行连通域分析的方法,包括二值化图像、4邻域与8邻域概念,以及`connectedComponents`和`connectedComponentsWithStats`函数的使用。在实践中,通过代码展示了如何标记和统计图像中的连通域,并用随机颜色显示,同时计算并绘制了连通域的中心位置和外接矩形。
摘要由CSDN通过智能技术生成

一、连通域分析

连通域分割原理:
在这里插入图片描述
邻域分为4邻域和8邻域。如上图所示。当使用连通域分割方法时,需要首先将图像进行二值化处理,在进行连通域的处理。右图为连通域分割两遍法的一个示意图,具体原理可以自行查询,这里只分享实操部分。
连通域分割函数:

connectedComponents(InputArray image, OutputArray labels,  int 8, int ltype = cv_325)

image:待标记不同连通域的图像单通道,数据类型必须为CV_8U
labels:标记不同连通域后的输出图像,与输入图像具有相同的尺寸。
connectivity:标记连通域时使用的邻域种类,4表示4-邻域,8表示8-邻域,默认参数为8。
ltype:输出图像的数据类型,目前支持CV_32S和CV_16U两种数据类型,默认参数为CV_32S。
分割并统计连通域信息的函数:

connectedComponentswithStats(InputArray image, OutputArray labels, outputArray stats,utputArray centroids, connectivity =, int 8, int ltype = cv_32s

image:待标记不同连通域的图像单通道,数据类型必须为CV_8U。
labels:标记不同连通域后的输出图像,与输入图像具有相同的尺寸。
stats:不同连通域的统计信息矩阵,矩阵的数据类型为Cv_32S。矩阵中第i行是标签为i的连通域的统计特性。
centroids:每个连通域的质心坐标,数据类型为CV_64F。
connectivity:标记连通域时使用的邻域种类,4表示4-邻域,8表示8-邻域,默认参数值为8。
ltype:输出图像的数据类型,目前只支持CV_32s和lCV_16U这两种数据类型,默认参数值为CV_328。
在这里插入图片描述
分割检测应用案例:

int main() {

	//读取图片
	Mat src = imread("图片1.png", IMREAD_ANYCOLOR);
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}

	//暂存图像二值化的Mat对象
	Mat src1, src_BW;

	//将图像进行二值化操作
	cvtColor(src, src1, COLOR_BGR2GRAY);
	threshold(src1, src_BW, 50, 255, THRESH_BINARY);

	//生成随机颜色,用于区分不用连通域
	RNG rng(10000);
	Mat out;

	//统计图像中连通域的个数
	int number = connectedComponents(src_BW, out, 8, CV_16U);

	//对图像进行分割
	vector<Vec3b> colors;
	for (int i = 0; i < number; i++)
	{
		//使用均匀分布的随机数确定颜色
		Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
		colors.push_back(vec3);
	}

	//使用不同的颜色连通域标注
	//新建一个空白矩阵
	Mat result = Mat::zeros(src1.size(), src.type());
	int w = result.cols;
	int h = result.rows;

	//开始标注,逐像素点标注
	for (int row = 0; row < h; row++)
	{
		for (int col = 0; col < w; col++)
		{
			int label = out.at<uint16_t>(row, col);
			//如果为背景,则不改变
			if (label ==0)
			{
				continue;
			}
			result.at<Vec3b>(row, col) = colors[label];
		}
	}

	imshow("123", result);

	//统计连通域信息
	Mat stats, centorids;

	number = connectedComponentsWithStats(src_BW, out, stats, centorids, 8, CV_16U);

	//对图像进行分割
	vector<Vec3b> colors_new;
	for (int i = 0; i < number; i++)
	{
		//使用均匀分布的随机数确定颜色
		Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
		colors_new.push_back(vec3);
	}

	//使用不同的颜色连通域标注

	//开始标注,逐像素点标注
	for (int i = 1; i < number; i++)
	{
		//中心位置
		int center_x = centorids.at<double>(i, 0);
		int center_y = centorids.at<double>(i, 1);

		//矩形边框
		int x = stats.at<int>(i, CC_STAT_LEFT);
		int y = stats.at<int>(i, CC_STAT_TOP);
		int h = stats.at<int>(i, CC_STAT_WIDTH);
		int w = stats.at<int>(i, CC_STAT_HEIGHT);
		int area = stats.at<int>(i, CC_STAT_AREA);

		//绘制中心位置
		circle(src, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);

		//绘制外接矩形
		Rect rect(x, y, h, w);
		rectangle(src, rect, colors_new[i], 1, 8, 0);
		putText(src, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);

		cout << "number:" << i << "area:" << area << endl;
	}
	imshow("biaoji", src);

	waitKey(0);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值