当前位置: 首页 > news >正文

OpenCV4(C++)—— 图像连通域的详细分析

文章目录

  • 前言
  • 一、connectedComponents函数
  • 二、connectedComponentsWithStats函数

前言

图像连通域,其实就是图像分割的一种方法。它通过检测像素之间的连接关系和相似性来划分图像中的区域,以便进行后续处理。图像邻域和图像邻域分析就不介绍了,网上很多。本文会通过代码和结果图来直观展示。


一、connectedComponents函数

  OpenCV4提供了提取图像中不同连通域的 connectedComponents() 函数,并为部分参数增加了默认值。使用时直接填入输入图像和输出图像两个参数即可。
在这里插入图片描述

  举例:找出上面图像中所有水果,并用矩形框标出

代码如下(示例):

#include <opencv2/opencv.hpp>
#include<iostream>  
using namespace std;int main()
{cv::Mat image = cv::imread("C:/Users/Opencv/temp/300.png", cv::IMREAD_GRAYSCALE);cv::Mat binImg;cv::threshold(image, binImg, 235, 255, cv::THRESH_BINARY_INV);  // 二值化处理// //统计图像中连通域的个数cv::Mat labels;int numComponents = cv::connectedComponents(binImg, labels);// 绘制每个连通域的边界框cv::Mat output = image.clone();for (int i = 1; i < numComponents; ++i) {// 提取当前连通域的maskcv::Mat mask = (labels == i);// 查找轮廓std::vector<std::vector<cv::Point>> contours;cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);// 绘制边界框cv::Rect boundingRect = cv::boundingRect(contours[0]);cv::rectangle(output, boundingRect, cv::Scalar(0, 255, 0), 2);}cv::imshow("原图", image);cv::imshow("二值图", binImg);cv::imshow("标记", output);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

分析:
(1)根据图像邻域分析原理,进行连通域统计之前,要先把输入图像转换为二值图像。

(2)将二值图传入connectedComponents函数中,连通域结果记录在labels中,返回值是连通域的个数。可视化labels,白色区域就是函数判定的连通域,对这些连通域的所有像素会进行标号处理,从“1”开始。从图1中可以看到很许多较小的连通域,将其放大(如图2),可以看到标号“17”的连通域只有4个像素,标号“18”的只有2个像素。

在这里插入图片描述

图 1

在这里插入图片描述

图 2

(3)示例代码中 cv::Mat mask = (labels == i); 分析:当 i=1 时,labels图中只会把标号“1”的连通域提取出来,其他连通域都置为0,所以通过循环可依次找出不同标号的连通域。下面图3为标号“1”的连通域,可以看到其他白色区域都没有了。然后再对它进行查找轮廓,再添加矩形框,结果如图4。
在这里插入图片描述

图 3

在这里插入图片描述

图 4

下面图5为循环到标号“7”的连通域,详细像素值如图6,矩形框结果如图7

在这里插入图片描述

图 5

在这里插入图片描述

图 6

在这里插入图片描述

图 7

(4)示例代码的最终结果如图8。而原本只想要检测出三个水果,可以通过判定连通域大小,将较大的连通域删除,只保留较大的。示例代码修改如下,结果如图9所示

在这里插入图片描述

图 8
int main()
{cv::Mat image = cv::imread("C:/Users/Opencv/temp/300.png", cv::IMREAD_GRAYSCALE);cv::Mat binImg;cv::threshold(image, binImg, 235, 255, cv::THRESH_BINARY_INV);  // 二值化处理// //统计图像中连通域的个数cv::Mat labels;int numComponents = cv::connectedComponents(binImg, labels);// 绘制每个连通域的边界框cv::Mat output = image.clone();for (int i = 1; i < numComponents; ++i) {// 提取当前连通域的maskcv::Mat mask = (labels == i);// 查找轮廓std::vector<std::vector<cv::Point>> contours;cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);  // 计算边界框面积cv::Rect boundingRect = cv::boundingRect(contours[0]);int area = boundingRect.width * boundingRect.height;if (area < 200)  // 面积小于200的不要continue;// 绘制边界框cv::rectangle(output, boundingRect, cv::Scalar(0, 255, 0), 2);}cv::imshow("原图", image);cv::imshow("二值图", binImg);cv::imshow("标记", output);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

在这里插入图片描述

图 9

二、connectedComponentsWithStats函数

  connectedComponents()函数只能通过标签将图像中的不同连通域区分开,无法得到更多的统计信息。上面的示例代码中,额外采用了findContours函数获得轮廓,然后使用boundingRect函数来计算其最小外接矩形。

  因为得到目标的矩形区域是非常常用的一个步骤,所以OpenCV4提供了connectedComponentsWithStats ()函数用于标记出图像中不同连通域的同时统计连通域的位置、面积的信息。

  相比于connectedComponents()函数,该函数主要多了两个参数:stats和centroids

int cv::connectedComponentsWithStats(InputArray image,                  // 输入图像,应为二值化图像OutputArray labels,                // 输出标签图像,每个像素点对应一个连通域标签OutputArray stats,                 // 输出统计信息,包括连通域的外接矩形、面积等OutputArray centroids,             // 输出连通域的质心坐标int connectivity = 8,              // 连通性,可选择 4 或 8 连通int ltype = CV_32S                   // 标签图像的数据类型,默认为 CV_32S
);

上述示例代码可以修改为:

int main()
{cv::Mat image = cv::imread("C:/Users/Opencv/temp/300.png", cv::IMREAD_GRAYSCALE);cv::Mat binImg;cv::threshold(image, binImg, 235, 255, cv::THRESH_BINARY_INV);  // 二值化处理// 连通组件标记及统计信息计算cv::Mat labels, stats, centroids;int numComponents = cv::connectedComponentsWithStats(binImg, labels, stats, centroids);// 绘制每个连通组件的外接矩形和质心cv::Mat output = image.clone();cv::cvtColor(output, output, cv::COLOR_GRAY2BGR); // 将灰度图转为伪彩色图以便绘制// cv::Mat output = cv::imread("C:/Users/jutze/ljw_C++/Opencv/temp/300.png"); // 或者直接用原图的彩色图for (int i = 1; i < numComponents; ++i) {// 根据面积过滤连通组件int area = stats.at<int>(i, cv::CC_STAT_AREA);if (area > 200){// 绘制外接矩形cv::Rect boundingRect(stats.at<int>(i, cv::CC_STAT_LEFT),stats.at<int>(i, cv::CC_STAT_TOP),stats.at<int>(i, cv::CC_STAT_WIDTH),stats.at<int>(i, cv::CC_STAT_HEIGHT));cv::rectangle(output, boundingRect, cv::Scalar(0, 255, 0), 2);// 绘制质心cv::Point centroid(centroids.at<double>(i, 0), centroids.at<double>(i, 1));cv::circle(output, centroid, 5, cv::Scalar(255, 0, 0), -1);}}cv::imshow("原图", image);cv::imshow("二值图", binImg);cv::imshow("标记", output);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

在这里插入图片描述
注:示例代码中,有一行代码是将灰度图转为伪彩色图,我们知道灰度图是无法转回彩色图的,所以这步称为伪彩色。即将单通道转为三通道,但数值一样,如[247]转为[247,247,247]。三个通道数值一样,所呈现的视觉效果跟灰度图是相同的,如下图
在这里插入图片描述
可以看到,output已经是3×UINT8的三通道类型了,但看起来还是跟灰度图一样。再放大看看数值,三个通道一样

在这里插入图片描述
因为原图是彩色图,示例代码中将其转为灰度图,我们也可以直接用原图来进行绘制,结果如下

在这里插入图片描述

相关文章:

OpenCV4(C++)—— 图像连通域的详细分析

文章目录 前言一、connectedComponents函数二、connectedComponentsWithStats函数 前言 图像连通域&#xff0c;其实就是图像分割的一种方法。它通过检测像素之间的连接关系和相似性来划分图像中的区域&#xff0c;以便进行后续处理。图像邻域和图像邻域分析就不介绍了&#x…...

Rule-Engine-Starter V1.0.0

一个轻量级的规则引擎、搜索引擎&#xff0c;让条件匹配简单、优雅。 GIT地址 https://gitcode.cosmoplat.com/15011240224/rule-engine-starter 介绍 Rule-Engine-Starter 是一个轻量级规则引擎&#xff0c;V1.0.0主要解决条件匹配问题。比如飞书文档&#xff0c;每个文档都…...

绘制X-Bar-S和X-Bar-R图,监测过程,计算CPK过程能力指数

X-Bar-S图和X-Bar-R图是统计质量控制中常用的两种控制图&#xff0c;用于监测过程的稳定性和一致性。它们的主要区别在于如何计算和呈现数据的变化以及所关注的问题类型。 X-Bar-S图&#xff08;平均值与标准偏差图&#xff09;&#xff1a; X-Bar代表样本均值&#xff0c;S代表…...

【每日一句】只出现一次的数

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;位运算 其他语言Cpython3 写在最后 Tag 【位运算-异或和】【数组】【2023-10-14】 题目来源 136. 只出现一次的数字 题目解读 给你一个数组&#xff0c;找出数组中只出现一次的元素。题目保证仅有一个元素出现一次&a…...

GDB调试程序常用命令

编译文件 g -g -o test test.cpp(注意&#xff1a;GDB调试的前提是在编译时加上-g参数.) 启动gdb # 方法一 gdb test # 方法二 gdb file test 设置断点 tbreak&#xff1a;设置临时断点&#xff0c;仅在第一次触发后失效。 watch&#xff1a;设置观察点&#xff0c;监控变量的…...

C语言,求两个数的二进制表达中,有多少个位数不同

以前我的博客中写过一篇求二进制的1的个数的博客&#xff0c;里面用按位与1的方式来判断位数是否为一。 如代码所示&#xff1a; #include <stdio.h> int num(int n) {int a 0;int i 0;while (i < 32){a a (n & 1);n n >> 1;i;}return a; } int main…...

解决Win10电脑无线网卡的移动热点无法开启问题

一、目的 利用无线网卡连接网络&#xff0c;然后又用无线网卡通过移动热点分享该网络。 移动热点&#xff0c;简单地说&#xff0c;就是将台式机或笔记本的 Internet 连接转化成 WIFI 信号以供移动设备无线上网的功能&#xff0c;硬件前提是电脑须安装有无线网卡。 二、问题 …...

Spring framework Day10:JSR330注入注解

前言 JSR330是Java社区标准化进程&#xff08;Java Community Process&#xff0c;简称JCP&#xff09;中的一个规范&#xff0c;全名为"Dependency Injection for Java"&#xff0c;即Java的依赖注入规范。它定义了一组注解和相关的规范&#xff0c;用于实现依赖注…...

Java开发中List数据量大,需要分片批次处理

在开发过程中可能会遇到需要处理的List数据量过大&#xff0c;可以选择分批处理的方式对大量数据进行处理。 1、使用 apache 的工具包 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><v…...

Apache Doris 2.0.2 版本正式发布!

峰会官网已上线&#xff0c;最新议程请关注&#xff1a;doris-summit.org.cn 点击报名 亲爱的社区小伙伴们&#xff0c;Apache Doris 2.0.2 版本已于 2023 年 10 月 6 日正式发布&#xff0c;该版本对多个功能进行了更新优化&#xff0c;旨在更好地满足用户的需求。有 92 位贡献…...

transformers架构实现

目录 架构代码如下 模型打印如下 架构代码如下 import numpy as np from torch.autograd import Variable import copy from torch import softmax import math import torch import torch.nn.functional as F import torch.nn as nn # 构建Embedding类来实现文本嵌入层 class…...

C++类型推导

这里对C的类型推导方式进行一次全面的总结。 C中有三种类型推导的方式&#xff0c;分别是模板、auto以及decltype()。以下分别介绍这三种方式的同异。 一 模板 假设有这样的函数模板和这样的调用&#xff1a; template<typename T> void f(ParamType param);f(expr);…...

Open3D(C++) SVD分解求两个点云的变换矩阵

目录 一、算法原理二、代码实现三、结果展示四、相关链接一、算法原理 计算两个点云的质心计算中心化向量计算协方差矩阵奇异值分解,求解旋转矩阵 R R R计算平移向量 t t...

rtmp htttp推流Windows桌面到srs进行播放

推流命令: ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset ultrafast -tune zerolatency -pix_fmt yuv420p -f flv rtmp://xxx.xxx.xxxx.xx/live/livestream 后面是推流地址 推流后的播放地址为: http://xxxxxx:8080/live/livestream.flv 可以写一个…...

NSSCTF做题(9)

[GDOUCTF 2023]<ez_ze> 看见输入框而且有提示说是ssti注入 输入{{7*7}} 试试&#xff0c;发现报错 输入{%%}发现了是jinja2模板 找到关键函数 Python SSTI利用jinja过滤器进行Bypass ph0ebuss Blog 原理见这篇文章&#xff0c;这里直接给出payload {%set ninedict(aaa…...

【09】基础知识:React组件的生命周期

组件从创建到死亡它会经历一些特定的阶段。 React 组件中包含一系列勾子函数&#xff08;生命周期回调函数 <> 生命周期钩子函数 <> 生命周期函数 <> 生命周期钩子&#xff09;&#xff0c;会在特定的时刻调用。 我们在定义组件时&#xff0c;会在特定的生…...

Pytorch之ConvNeXt图像分类

文章目录 前言一、ConvNeXt设计决策1.设计方案2.Training Techniques3.Macro Design&#x1f947;Changing stage compute ratio&#x1f948;Change stem to "Patchify" 4.ResNeXt-ify5. Inverted Bottleneck6.Large Kernel Size7.Micro Design✨Replacing ReLU wit…...

Linux系统编程:makefile以及文件系统编程

增量编译概念 首先回顾一下我们之前写的各种gcc指令用来执行程序&#xff1a; 可以看见非常繁琐&#xff0c;两个文件就要写这么多&#xff0c;那要是成百上千岂不完蛋。 所以为了简化工作量&#xff0c;很自然的想到了将这些命令放在一起使用脚本文件来一键执行&#xff0c…...

《动手学深度学习 Pytorch版》 8.5 循环神经网络的从零开始实现

%matplotlib inline import math import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2lbatch_size, num_steps 32, 35 train_iter, vocab d2l.load_data_time_machine(batch_size, num_steps) # 仍然使用时间机器数据集8.…...

写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换

我们这里是利用按位与来计算的 我们可以想想怎么保留偶数上的位&#xff1f;我们可以利用0x55555555按位与上这个数就保留了偶数 我们知道&#xff0c;16进制0x55555555转换为二进制就是0x01010101010101010101010101010101 我们知道&#xff0c;二进制每一位&#xff0c;如…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...