OpenCV C++实现区域面积筛选以及统计区域个数

ops/2024/10/22 18:28:57/

目录

1、背景介绍

2、代码实现

2.1 获取原图

2.1.1 区域图像imread 

2.1.2 具体实现

2.2 获取图像大小 

2.3 阈值分割

2.3.1 阈值分割threshold

2.3.2 具体实现 

2.4  区域面积筛选

2.4.1 获取轮廓findContours

2.4.2 获取轮廓面积contourArea 

2.4.3 填充区域fillPoly

2.4.4 具体实现

2.5 统计区域个数并获取质心坐标

2.5.1  获取图像中心矩moments

2.5.2 具体实现

3、测试界面

4、总结 


1、背景介绍

本文实现了根据源图像的灰度值来分割成二值图像,通过面积筛选剔除掉面积小的区域,并统计区域的个数以及区域中心坐标。

IDE:Qt Creator 4.8.0  

编译器:MSVC 2017 64bit

Opencv库:opencv4.5.1

2、代码实现

2.1 获取原图

2.1.1 区域图像imread 

cv::Mat cv::imread(const String& filename, int flags = IMREAD_COLOR);
  • 第一个参数为图像地址
  • 第二个参数为读取类型
IMREAD_COLOR总是读取三通道图像
IMREAD_GRAYSCALE总是读取单通道图像 
IMREAD_ANYCOLOR通道数由文件实际通道数(不超过3)
IMREAD_ANYDEPTH允许加载超过8bit深度。
IMREAD_UNCHANGED等于将Cv::IMREAD_ANYCOLOR和CV::IMREAD_ANYDEPTH组合了起来。

2.1.2 具体实现

通过imread函数获取源图像,因为后续需要做阈值分割,需要用到灰度图像,所以imread的第二个参数取IMREAD_GRAYSCALE;

//获取图像
std::string strPicName = "./pic.png";
m_mSrcImage = cv::imread(strPicName, cv::IMREAD_GRAYSCALE);
cv::imshow("Src",m_mSrcImage);

2.2 获取图像大小 

//获取图像大小
int iHeight = m_mSrcImage.rows;
int iWidth = m_mSrcImage.cols;

2.3 阈值分割

2.3.1 阈值分割threshold

double cv::threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type);

src:输入的灰度图像或彩色图像。

dst:输出的二值化图像。

thresh:阈值,用于将像素点的亮度值与该值进行比较,从而确定像素点的颜色。

maxval:最大值,当像素点的亮度值大于等于阈值时,将其设置为该值。

type:二值化类型,常用的有以下几种:

THRESH_BINARY大于等于阈值的像素点设置为最大值,小于阈值的像素点设置为0。
THRESH_BINARY_INV大于等于阈值的像素点设置为0,小于阈值的像素点设置为最大值。
THRESH_TRUNC大于等于阈值的像素点设置为阈值,小于阈值的像素点保持不变。
THRESH_TOZERO大于等于阈值的像素点保持不变,小于阈值的像素点设置为0。
THRESH_TOZERO_INV大于等于阈值的像素点设置为0,小于阈值的像素点保持不变。

如果想要实现获取某个灰度阈值区间的区域,则可以先使用THRESH_TOZERO,获取小于thresholdMax的区域,然后使用THRESH_BINARY,获取大于thresholdMin的区域。

2.3.2 具体实现 

//阈值分割
double thresholdMin = 5;
double thresholdMax = 200;
double MaxVal = 255;
cv::Mat MatThreshold1;
cv::threshold(m_mSrcImage,MatThreshold1,thresholdMax,MaxVal,cv::THRESH_TOZERO_INV);
cv::Mat MatThreshold2;
cv::threshold(MatThreshold1,MatThreshold2,thresholdMin,MaxVal,cv::THRESH_BINARY);
cv::imshow("Threshold",MatThreshold2);

2.4  区域面积筛选

2.4.1 获取轮廓findContours

cv::void findContours(cv::InputOutputArray image,cv::OutputArrayOfArray contours,cv::OutputArray hierarchy,int mode,     int method,cv::Point offset = cv::Point())

findContours输入一个图像矩阵,返回一个双重向量  vector<vector<Point>> contours  每一组Point都连续,构成一组向量集合,在图像上的显示即为一个轮廓(点集),由于一张图像往往包含很多对象,因此一个轮廓不足以描述图像中的所有对象,因此还需要一个容器去包含所有的轮廓,我们称这个包含所有轮廓的容器为轮廓集。所以我们有上述的双重向量的定义方式。    轮廓数量=contours的元素个数

这里参数介绍太多了,就不具体介绍了。

2.4.2 获取轮廓面积contourArea 

double cv::contourArea( InputArray _contour, bool oriented )
  • contour:轮廓的像素点
  • oriented:区域面积是否具有方向的标志,true表示面积具有方向性,false表示不具有方向性,默认值为不具有方向性的false。

2.4.3 填充区域fillPoly

void cv::fillPoly(     InputOutputArray  img,InputArrayOfArrays       pts,const Scalar &        color,int   lineType = LINE_8,int   shift = 0,Point       offset = Point()
)

2.4.4 具体实现

  1. 通过findContours函数获取轮廓数据;
  2. 获取每个轮廓数据的面积,筛选给定的面积区间并保存到新的轮廓数据;
  3. 通过轮廓数据进行填充生成新的图像。
//区域面积筛选
double dAreaMin = 7000;
double dAreaMax = 9500;
std::vector<std::vector<cv::Point >> Contours;
cv::findContours(MatThreshold2,Contours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);
std::vector<std::vector<cv::Point >> SelectContours;
for(int i=0;i!=(int)Contours.size();i++)
{std::vector<cv::Point > Contour = Contours[i];double dArea = cv::contourArea(Contour,false);if(dArea>dAreaMin&&dArea<dAreaMax){SelectContours.push_back(Contour);}
}
cv::Mat SelectMat = cv::Mat::zeros(iHeight,iWidth,CV_8UC1);
cv::fillPoly(SelectMat,SelectContours,cv::Scalar(255,0,0));
cv::imshow("SelectMat",SelectMat);

2.5 统计区域个数并获取质心坐标

2.5.1  获取图像中心矩moments

cv::Moments cv::moments ( InputArray array,bool binaryImage = false)
  • opencv中提供了moments()来计算图像中的中心矩(最高到三阶);
  • x坐标通过cv::Moments的成员变量m10/m00获得;
  • y坐标通过cv::Moments的成员变量m01/m00获得;

2.5.2 具体实现

  1. 获取新生成区域的轮廓,根据双重向量的size获取区域个数
  2. 通过moments()来获取质心坐标
//获取各个区域质心的坐标vector
std::vector<std::vector<cv::Point >> CenterContours;
cv::findContours(SelectMat,CenterContours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);
//统计区域个数
int iCount = CenterContours.size();
ui->sb_Count->setValue(iCount);
//获取质心坐标
std::vector<int> vCenterX;//质心X坐标
std::vector<int> vCenterY;//质心Y坐标
for(int i=0;i!=(int)CenterContours.size();i++)
{std::vector<cv::Point > CenterContour = CenterContours[i];cv::Moments M = cv::moments(CenterContour,false);int iCenterX = (M.m10/M.m00);int iCenterY = (M.m01/M.m00);vCenterX.push_back(iCenterX);vCenterY.push_back(iCenterY);
}

3、测试界面

4、总结 

本文通过opencv的函数进行图像的基本处理,实现了图像阈值化、面积筛选、统计区域个数、统计区域质心等功能模块,成功实现了功能需求。 


http://www.ppmy.cn/ops/27042.html

相关文章

【MySql】深入了解MySQL死锁:原因、检测和解决方法

在数据库系统中&#xff0c;死锁是一种常见的并发问题&#xff0c;它可能会导致应用程序性能下降甚至数据库系统崩溃。本文将深入探讨MySQL死锁的原因、检测方法和解决方法 1. 什么是死锁 死锁是指两个或多个事务在互相请求锁资源时&#xff0c;因为相互持有对方所需的资源而…

机器人正反向运动学(FK和IK)

绕第一个顶点可以沿Z轴转动&#xff0c;角度用alpha表示 绕第二个点沿X轴转动&#xff0c;角度为Beta 第三个点沿X轴转动&#xff0c;记作gama 这三个点构成姿态&#xff08;pose&#xff09; 我们记第一个点为P0&#xff0c;画出它的本地坐标系&#xff0c;和世界坐标系一样红…

Linux网络编程---多进/线程并发服务器

一、多进程并发服务器 实现一个服务器可以连接多个客户端&#xff0c;每当accept函数等待到客户端进行连接时 就创建一个子进程 思路分析&#xff1a; 核心思路&#xff1a;让accept循环阻塞等待客户端&#xff0c;每当有客户端连接时就fork子进程&#xff0c;让子进程去和客户…

SpringCloud02(远程调用Feign,网关Gateway,配置中心Nacos)

目录 一、远程调用Feign【要会用】 1. Feign简介 1 什么是Feign 2 准备基础代码 2. Feign入门【重点】 步骤 实现 测试 3. Feign配置Ribbon 1 说明 2 配置 4. Feign配置日志 1 说明 2 步骤 5. Feign使用优化 1 说明 2 步骤 6. 小结 二、网关Gateway 1. 网关…

vue的build先上部署的 devServer不生效的场景记录

文章目录 Nginx 相关命令VUE项目devServer.proxy&#xff08;正向代理&#xff09;匹配请求中的地址工作流程开发期间代理proxy的配置项目打包上线出现的问题描述 Nginx 相关命令 //运行命令 start nginx 启动nginx服务//运行命令 nginx -s stop 停止nginx服务//运行命令 ngin…

为什么Bash中的“[“和“]“周围应该有空格

问题&#xff1a; 我试图编写一个使用 if 语句的 Bash 脚本。 if[$CHOICE -eq 1];脚本一直在报错&#xff0c;直到我在 [ 前后并在 ] 之前加了一个空格&#xff0c;如下所示&#xff1a; if [ $CHOICE -eq 1 ];我的问题是&#xff0c;为什么在 Bash 中方括号周围的空格如此重…

IDEA 申请学生许可证

如果你有学生账号&#xff0c;并且账号是 EDU 结尾的&#xff0c;可以申请 IDEA 的学生许可证。 有效期一年&#xff0c;完全免费。 在界面上输入邮件地址&#xff0c;然后单击按钮提交。 邮件中单击链接 JetBrains 会把一个带有链接的邮件发送到你的邮箱中。 单击邮箱中的…

8.机器学习-十大算法之一朴素贝叶斯(Naive Bayes)算法原理讲解

8.机器学习-十大算法之一朴素贝叶斯&#xff08;Naive Bayes&#xff09;算法原理讲解 一摘要二个人简介三朴素贝叶斯算法简介朴素贝叶斯算法概念贝叶斯方法朴素贝叶斯算法贝叶斯公式 四贝叶斯算法的核心思想&#xff1a;利用贝叶斯定理进行分类五优缺点优点缺点 六朴素贝叶斯原…