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;}

原图:

结果 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让AI帮你说话--GPT-SoVITS教程

有时候我们在录制视频的时候&#xff0c;由于周边环境嘈杂或者录音设备问题需要后期配音&#xff0c;这样就比较麻烦。一个比较直观的想法就是能不能将写好的视频脚本直接转换成我们的声音&#xff0c;让AI帮我们完成配音呢&#xff1f;在语音合成领域已经有很多这类工作了&…

1.Mybatis入门

目录 前言 1入门 1.1 入门程序实现 1.2 数据准备 ​编辑 1.3 配置Mybatis 1.4 编写SQL语句 1.5 单元测试 1.6 解决SQL警告与提示 2. JDBC介绍(了解) 2.1 介绍 2.2 代码 2.3 问题分析 2.4 技术对比 3. 数据库连接池 3.1 介绍 3.2 产品 4. lombok 4.1 介绍 4.…

AOP+Redisson 延时队列,实现缓存延时双删策略

一、缓存延时双删 关于缓存和数据库中的数据保持一致有很多种方案&#xff0c;但不管是单独在修改数据库之前&#xff0c;还是之后去删除缓存都会有一定的风险导致数据不一致。而延迟双删是一种相对简单并且收益比较高的实现最终一致性的方式&#xff0c;即在删除缓存之后&…

哪些 3D 建模软件值得推荐?

云端地球是一款免费的在线实景三维建模软件&#xff0c;不需要复杂的技巧&#xff0c;只要需要手机&#xff0c;多拍几张照片&#xff0c;就可以得到完整的三维模型&#xff01; 无论是大场景倾斜摄影测量还是小场景、小物体建模&#xff0c;都可以通过云端地球将二维数据向三…

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

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

为什么3d合并的模型不能移动---模大狮模型网

当你在3D软件中合并模型后&#xff0c;如果无法移动合并后的模型&#xff0c;可能有以下几个可能的原因&#xff1a; 模型被锁定或冻结&#xff1a;在3D软件中&#xff0c;你可能会将模型锁定或冻结以防止意外的移动或编辑。请确保解锁或解冻模型&#xff0c;这样你就可以自由地…

学籍管理系统(c++文件实现)

要求&#xff1a; 实现增删查改&#xff0c;两种方式查询&#xff0c;登录功能 设计&#xff1a; 学生端&#xff1a;可以查询个人成绩 管理员端&#xff1a;对学籍信息增删查改&#xff0c;查看所有信息&#xff0c;单人信息&#xff0c;学籍排序&#xff0c;统计绩点 三个…

【Python】采用OpenCV和Flask来进行网络图像推流的低延迟高刷FPS方法(项目模板)

【Python】采用OpenCV和Flask来进行网络图像推流的低延迟高刷FPS方法&#xff08;项目模板&#xff09; gitee项目模板&#xff1a; 网络图像推流项目模板&#xff08;采用OpenCV和Flask来进行网络图像推流的低延迟高刷FPS方法&#xff09; 前文&#xff1a; 【最简改进】基于…

伊恩·斯图尔特《改变世界的17个方程》相对论笔记

它告诉我们什么&#xff1f; 物质包含的能量等于其质量乘以光速的平方。 为什么重要&#xff1f; 光的速度很快&#xff0c;它的平方绝对是一个巨大的数。1千克的物质释放出的能量相当于史上最大的核武器爆炸所释放能量的约40%。一系列相关的方程改变了我们对空间、时间、物质和…

Prompt Learning 的几个重点paper

Prefix Tuning: Prefix-Tuning: Optimizing Continuous Prompts for Generation 在输入token之前构造一段任务相关的virtual tokens作为Prefix&#xff0c;然后训练的时候只更新Prefix部分的参数&#xff0c;PLM中的其他参数固定。针对自回归架构模型&#xff1a;在句子前面添…

vue 使用echarts-gl实现3d旋转地图

之前也有使用过echarts开发项目中涉及到的地图功能&#xff0c;当时使用geo来实现地图轮廓&#xff0c;看上去有种3d的感觉。最近闲来无事看了一份可视化大屏的UI设计图&#xff0c;感觉3d旋转地图挺好玩的&#xff0c;今天就来尝试实现下。 首先安装下echarts和echarts-gl依赖…

MyBatis框架-配置解析

文章目录 Mybatis配置解析核心配置文件environments 环境配置transactionManager 事务管理器dataSource 数据源mappers 映射器Mapper文件Properties优化类型别名&#xff08;typeAliases&#xff09;setting类型处理器&#xff08;typeHandlers&#xff09;对象工厂&#xff08…

shell脚本——条件语句

目录 一、条件语句 1、test命令测试条件表达式 2、整数数值比较 3、字符串比较 4、逻辑测试&#xff08;短路运算&#xff09; 5、双中括号 二、if语句 1、 分支结构 1.1 单分支结果 1.2 双分支 1.3 多分支 2、case 一、条件语句 条件测试&#xff1a;判断某需求是…

1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么?

1002. HarmonyOS 开发问题&#xff1a;鸿蒙 OS 技术特性是什么? 硬件互助&#xff0c;资源共享 分布式软总线 分布式软总线是多种终端设备的统一基座&#xff0c;为设备之间的互联互通提供了统一的分布式通信能力&#xff0c;能够快速发现并连接设备&#xff0c;高效地分发…

计算机网络——网络层(2)

计算机网络——网络层&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 网络层——控制平面概述路由选择转发表路由协议路由信息的交换小结 路由选择算法常见的路由选择算法距离矢量路由算法工作原理优缺点分析 链路状态路由算法基本工作原理优…

【详解】贪吃蛇游戏----下篇(完整源码)

目录 引入&#xff1a; 本片文章目的&#xff1a; 整个游戏的实现流程图如下&#xff1a; 游戏实现 GameRun PrintHelpInfo Pause NextIsFood printSnake EatFood NoFood KillByWall KillBySelf GameRun GameEnd 总代码&#xff1a; &#xff08;1&#xff09…

pcie基础知识

文章目录 总线PCIEPCIE对应版本速率pcie拓扑linux查看pcie设备PCIE配置空间BAR&#xff08;基地址寄存器&#xff09; 总线 什么是总线 总线就是电脑内部交互的通道。 最开始CPU连接声卡或者网卡用的是不同接口&#xff0c;比如你声卡坏了&#xff0c;换一个声卡&#xff0c;接…

二叉搜索树操作题目:二叉搜索树中的插入操作

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉搜索树中的插入操作 出处&#xff1a;701. 二叉搜索树中的插入操作 难度 3 级 题目描述 要求 给定二叉搜索…

C# 一个快速读取写入操作execl的方法封装

这里封装了3个实用类ExcelDataReaderExtensions&#xff0c;ExcelDataSetConfiguration&#xff0c;ExcelDataTableConfiguration和一个实用代码参考&#xff1a; using ExcelDataReader; using System; using System.Collections.Generic; using System.Linq; using System.T…

别再做“背锅侠”!软件测试工程师被开发吐槽,如何应对?

作为一名软件测试工程师&#xff0c;我们的角色可以算是“战场上的后勤”&#xff0c;战役的胜败和所有团队人员都息息相关。但是难免碰到战役失败后&#xff0c;很多团队互相推脱的局面&#xff0c;而测试人员就是所有团队中的弱势群体&#xff0c;自然是首当其冲的背锅侠&…