opencv#35 连通域分析

连通域分割原理

像素领域介绍:

4邻域是指中心的像素与它邻近的上下左右一共有4个像素,那么称这4个像素为中心像素的4邻域。

8邻域是以中心像素周围的8个像素分别是上下左右和对角线上的4个像素。

连通域的定义(分割)分为两种:以4邻域为相邻判定条件的连通域分割和8邻域为判定条件的连通域分割。连通域指某个区域内所有像素是相邻的,如果一个像素不能够通过这个区域中的像素到达另一个像素,那么这两个像素就不再同一连通域内。

连通域的划分通常采用两遍法,在进行连通域分析的时候,我们往往先对图像进行二值化处理,确定连通域的判定标准是采用4邻域还是8邻域,然后先对图像进行遍历得到结果,然后再对此结果进行遍历得到最终结果。

在进行遍历时遇到非0(非黑)的像素值,就对此像素进行编号,例如上图,进行第一次遍历时,遇到黄色的方格,标记为1,之后凡是与此放个相邻的像素,都将其设置为1,第一行遍历完后,赋值了1个1,遍历第二行,最左侧有个黄色像素,此像素的上方和左方的像素若有标记的数值,那么就将这个黄色像素标记为上方与左方数值较小的数,这里可以看到上方为空,左方是边缘,因此这个像素没有办法借助上方和左方标记,我们就需要对其进行独立标记,由于1已经用过,我们将其标记为2。

然后看下一个黄色的像素,这个像素左边的像素被标记为2,而上方是一个没有被标记的像素,因此这个像素也被标记为2。

然后继续看下一个像素,这个像素的左方和上方都被标记了,而两者标记数值不一致,因此我们根据规则选择两者之间较小数值,即1。

到达第三行时,遇见黄色像素,因为此像素上方的像素为1,因此也要记为1。

来到第四行,第四行第一个像素,左侧和上方都没有被标记,因此需要进行独立标记,1和2都用过了,我们对此像素标记3 。

下一个像素左侧为3上方为1,标记为1。

最后一行分别被标记为3和1。

 zhe

这样完成了第一次遍历,第二次遍历,将两个邻近的结果进行统一,比如上图第二行,标记为2和标记1的像素相连,因此我们将其中的2全部置为1,下方像素同理。 

这样便完成了两遍法实现图像邻域分割,图像分割的结果通过示例中也可以看出是一个与原图像具有相同尺寸的图像 。

只分割连通域的函数

connectedComponents()

int cv::connectedComponents(InputArray    image,
                             OutputArray   labels,
                                           connectivity =
                             int           8,
                             int           Itype = CV_325
                            )

·image:待标记不同连通域的图像单通道,数据类型必须为CV_8U。上面说过图像通常会进行二值化处理,若不进行二值化,则会将1~255之间的任何数都独立的看成不同区域,也就是即使出现2,3,4相邻的区域,也会判断为3个不同的连通域,因此,我们最好是使用0~255的数据,这样的数据是有限的,若我们使用0~1之间的小数,分割形式是无限的,那么分割的结果就会出现每一个单独的像素都是一个单独的连通域。我们要先对图像进行二值化,因为图像可能会受到光照影响,即使在真实物理世界中,是同一个像素值的物体,通过相机的采集,也会出现不同像素值的情况。

·labels:标记不同连通域后的输出图像,与输入图像具有相同尺寸。

·connectivity:标记连通域时使用的邻域种类,4表示4-邻域,8表示8-邻域,默认参数为8.

·ltype:输出图像的数据类型,目前支持CV_32S和CV_16U两种数据类型,默认参数为CV_32S。

分割并统计连通域信息的函数

connectedComponentsWithStats()

void cv::connectedComponentsWithStats(InputArray    images,
                                      OutputArray   labels,
                                      OutputArray   stats,
                                      OutputArray   centroids,
                                                    connectiviity =
                                      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和CV_16U两种数据类型,默认参数为CV_32S。

上图参数是此函数可以获得的信息。

示例 
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv; //opencv的命名空间
using namespace std;

//主函数
int main()
{
	//对图像进行距离变换
	Mat img = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/hua.jpg");
	if (img.empty())
	{
		cout << "请确认图像文件名是否正确" << endl;
		return -1;
	}
	Mat hua, huaBW;

	//将图像转成二值化的图像,用于统计连通域。
	cvtColor(img, hua, COLOR_BGR2GRAY);
	threshold(hua, huaBW, 25, 255, THRESH_BINARY); //二值化

	//生成随机颜色,用于区分不同连通域。
	RNG rng(10086); //RNG用来生成随机数,这里用了10086进行初始化。
	Mat out;
	int number = connectedComponents(huaBW, out, 8, CV_16U); //统计图像中连通域的个数
	vector<Vec3b> colors; //vector是一个能够存放任意类型的动态数组,Vec3b可以看成vector<uchar,3>,即一个uchar类型,长度为3的vector向量(简单地说,就是一个uchar类型的数组,长度为3).
	for (int i = 0; i < number; i++);
	{
		//使用均匀分布的随机数确定颜色;rng.uniform(),可以生成指定范围的均匀分布的随机数
		Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
		colors.push_back(vec3);
	}
	 //以不同的颜色标记出不同的连通域
	Mat result = Mat::zeros(hua.size(), img.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("原图", img);
	imshow("标记后的图像", result);

	cout <<"接下来统计连通域信息"<< endl;
	waitKey(0);

	Mat stats, centroids;
	number = connectedComponentsWithStats(huaBW, out, stats, centroids, 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 = centroids.at<double>(i, 0);
		int center_y = centroids.at<double>(i, 1);
		//矩形边框
		int x = stats.at<int>(i, CC_STAT_LEFT);
		int y = stats.at<int>(i, CC_STAT_TOP);
		int w = stats.at<int>(i, CC_STAT_WIDTH);
		int h = stats.at<int>(i, CC_STAT_HEIGHT);
		int area = stats.at<int>(i, CC_STAT_AREA);

		//中心位置绘制
		circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);
		//外接矩形
		Rect rect(x, y, w, h);
		rectangle(img, rect, colors_new[i], 1, 8, 0);
		putText(img, format("%d", i), Point(center_x, center_y),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
		cout << "number" << i << ",aera:" << area << endl;
	}
	//显示结果
	imshow("标记后的图像", img);
	waitKey(0);//等待函数用于显示图像,按下键盘任意键后退出
	return 0;

}

原图:

结果 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/356457.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

老司机用脚本批量巧删恶意文件

作者&#xff1a;田逸&#xff08;formyz&#xff09; 一个NFS服务器&#xff0c;为多个Web项目所共享。这些目录包括PHP程序、图片、HTML页面和用户上传的文档和附件等。因为某些Web框架古老&#xff0c;存在诸如不对上传文件做严格的安全性检查&#xff0c;虽然此NFS服务器位…

腾讯发表多模态大模型最新综述,从26个主流大模型看多模态效果提升关键方法

在大规模语言模型&#xff08;LLMs&#xff09;通往通用人工智能&#xff08;AGI&#xff09;的道路中&#xff0c;从传统的单一的“语言模态”扩展到“图像”、“语音”等等的“多模态”必然是大模型进化的必经之路。 在过去的 2023 年&#xff0c;多模态大规模语言模型&…

建筑效果图渲染制作周期是多久

建筑效果图的渲染制作周期会根据多种因素而变化&#xff0c;包括项目的复杂性、渲染的详细程度、分辨率要求、场景中的元素数量和复杂度、以及项目所需的修改和迭代次数等。 通常&#xff0c;简单的建筑效果图可能在几个工作日内完成&#xff0c;而大型或高度复杂的项目可能需要…

合并两个排序的链表

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

Cantor表(刷题)(C语言)

个人博客主页&#xff1a;https://blog.csdn.net/2301_79293429?typeblog 专栏&#xff1a;https://blog.csdn.net/2301_79293429/category_12545690.html 题目描述 现代数学的著名证明之一是 Georg Cantor 证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的&…

【JLU】校园网linux客户端运行方法

终于给这输入法整好了&#xff0c;就像上面图里那样执行命令就行 写一个开机自启的脚本会更方便&#xff0c;每次都运行也挺烦的 补充了一键运行脚本&#xff0c;文件路径需要自己修改 #!/bin/bashrun_per_prog"sudo /home/d0/ubuntu-drclient-64/DrClient/privillege.s…

Java项目:基于SSM框架实现的高校毕业生就业管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm817基于SSM框架实现的高校毕业生就业管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调…

【linux】-centos7版本前后-变化篇

1.centos7版本前后区别 首先文件系统变化&#xff0c;由EXT4&#xff0c;变为XFS格式。可支持容量500TB的文件&#xff0c;而6代仅能支持16TB。首个进程变为systemd, 替换了熟悉的init进程。它的特点是功能强大&#xff0c;体积也很强大。 systemd给我们带来了一个全家桶命令&…

Java基础数据结构之反射

一.定义 Java的反射机制是在运行状态中的&#xff0c;对于任意一个类都能知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法及属性。既然能拿到&#xff0c;我们就可以修改部分类型信息。这种动态获取信息以及动态调用对象方法的功能…

3d合并模型是重名材质---模大狮模型网

当合并3d模型时&#xff0c;如果存在重名的材质&#xff0c;可能会导致加载问题。这是因为3D软件在处理重名材质时可能会出现冲突。你可以尝试以下方法解决这个问题&#xff1a; 重命名材质&#xff1a;检查合并的模型中的材质&#xff0c;确保它们具有唯一的命名。修改重名的材…

【学网攻】 第(15)节 -- 标准ACL访问控制列表

系列文章目录 目录 系列文章目录 文章目录 前言 一、ACL(访问控制列表)是什么? 二、实验 1.引入 实验拓扑图 实验配置 测试PC2能否Ping通PC3 配置ACL访问控制 实验验证 PC1 Ping PC3 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认…

Android T 远程动画显示流程(更新中)

序 本地动画和远程动画区别是什么? 本地动画&#xff1a;自给自足。对自身SurfaceControl矢量动画进行控制。 远程动画&#xff1a;拿来吧你&#xff01;一个app A对另一个app B通过binder跨进程通信&#xff0c;控制app B的SurfaceControl矢量动画。 无论是本地动画还是远程…

C++之类继承隐式转换实例(二百五十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

应急响应-流量分析

在应急响应中&#xff0c;有时需要用到流量分析工具&#xff0c;。当需要看到内部流量的具体情况时&#xff0c;就需要我们对网络通信进行抓包&#xff0c;并对数据包进行过滤分析&#xff0c;最常用的工具是Wireshark。 Wireshark是一个网络封包分析软件。网络封包分析软件的…

全连MGRE(OSPF)综合实验

一.要求 二.底层--所有节点拥有合法ip地址 r1: r2&#xff08;isp&#xff09;: r3: r4: r5: r6: 三.全网可达 r1: r3&#xff1a; r4: r5: r6: 四.构建全连的MGRE环境 R1-R3-R4 R1&#xff1a; r3: r4: R1-R5-R6 r1: r5: r6: 五.ospf配置 R1&#xff1a; r3: r4: r5: r6:…

Linux下安装edge

edge具有及其强大的功能&#xff0c;受到很多人的喜爱&#xff0c;它也开发Linux版本&#xff0c;下面是安装方法&#xff1a; 1.去edge官网下载Linux(.deb)文件。 https://www.microsoft.com/zh-cn/edge/download?formMA13FJ 2.下载之后输入以下指令&#xff08;后面是安装…

Docker私有仓库搭建

目录 搭建本地私有仓库 Docker--harbor私有仓库部署与管理 Harbor 简介 什么是Harbor Harbor的特性 Harbor的构成 Harbor 部署 部署 Docker-Compose 服务 ​编辑部署 Harbor 服务 启动 Harbor 进入浏览器http://192.168.20.10进入harbor的客户端 搭建本地私有仓库 …

如何本地搭建Tale博客网站并发布到公网分享好友远程访问——“cpolar内网穿透”

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

【linux】磁盘相关命令fdisk/lsblk和file

1. fdisk 磁盘分区&#xff0c;查看系统分区。 fdisk 的意思是 固定磁盘(Fixed Disk) 或 格式化磁盘(Format Disk)&#xff0c;它是命令行下允许用户对分区进行查看、创建、调整大小、删除、移动和复制的工具。它支持 MBR、Sun、SGI、BSD 分区表&#xff0c;但是它不支持 GUI…

Nginx实现反向代理负载均衡实验

实验环境&#xff1a; VM REdhat虚拟机&#xff08;192.168.87.5&#xff09;一台、VM Redhat虚拟机&#xff08;192.168.87.3&#xff09;一台、阿里云服务器&#xff08;47.93.79.92&#xff09;一台 实验要求&#xff1a;通过windows浏览器访问192.168.87.5&#xff08;虚…