[C++]使用OpenCV去除面积较小的连通域
这是后期补充的部分,和前期的代码不太一样
效果图

源代码
//测试
void CCutImageVS2013Dlg::OnBnClickedTestButton1()
{vector<vector<Point> > contours; //轮廓数组vector<Point2d> centers; //轮廓质心坐标 vector<vector<Point> >::iterator itr; //轮廓迭代器vector<Point2d>::iterator itrc; //质心坐标迭代器vector<vector<Point> > con; //当前轮廓double area;double minarea = 1000;double maxarea = 0;Moments mom; // 轮廓矩Mat image, gray, edge, dst;image = imread("D:\\66.png");cvtColor(image, gray, COLOR_BGR2GRAY);Mat rgbImg(gray.size(), CV_8UC3); //创建三通道图blur(gray, edge, Size(3, 3)); //模糊去噪threshold(edge, edge, 200, 255, THRESH_BINARY_INV); //二值化处理,黑底白字//--------去除较小轮廓,并寻找最大轮廓--------------------------findContours(edge, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //寻找轮廓itr = contours.begin(); //使用迭代器去除噪声轮廓while (itr != contours.end()){area = contourArea(*itr); //获得轮廓面积if (area<minarea) //删除较小面积的轮廓 {itr = contours.erase(itr); //itr一旦erase,需要重新赋值}else{itr++;}if (area>maxarea) //寻找最大轮廓{maxarea = area;}}dst = Mat::zeros(image.rows, image.cols, CV_8UC3);/*绘制连通区域轮廓,计算质心坐标*/Point2d center;itr = contours.begin();while (itr != contours.end()){area = contourArea(*itr); con.push_back(*itr); //获取当前轮廓if (area == maxarea){vector<Rect> boundRect(1); //定义外接矩形集合boundRect[0] = boundingRect(Mat(*itr));cvtColor(gray, rgbImg, COLOR_GRAY2BGR);Rect select;select.x = boundRect[0].x;select.y = boundRect[0].y;select.width = boundRect[0].width;select.height = boundRect[0].height;rectangle(rgbImg, select, Scalar(0, 255, 0), 3, 2); //用矩形画矩形窗drawContours(dst, con, -1, Scalar(0, 0, 255), 2); //最大面积红色绘制}elsedrawContours(dst, con, -1, Scalar(255, 0, 0), 2); //其它面积蓝色绘制con.pop_back();//计算质心mom = moments(*itr);center.x = (int)(mom.m10 / mom.m00);center.y = (int)(mom.m01 / mom.m00);centers.push_back(center);itr++;}imshow("rgbImg", rgbImg);//imshow("gray", gray);//imshow("edge", edge);imshow("origin", image);imshow("connected_region", dst);waitKey(0);return;
}
前期做的,方法可能不太一样
一,先看效果图
原图

处理前后图
二,实现源代码
//=======函数实现=====================================================================
void RemoveSmallRegion(Mat &Src, Mat &Dst, int AreaLimit, int CheckMode, int NeihborMode)
{int RemoveCount = 0;//新建一幅标签图像初始化为0像素点,为了记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查 //初始化的图像全部为0,未检查 Mat PointLabel = Mat::zeros(Src.size(), CV_8UC1);if (CheckMode == 1)//去除小连通区域的白色点 {//cout << "去除小连通域.";for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (Src.at<uchar>(i, j) < 10){PointLabel.at<uchar>(i, j) = 3;//将背景黑色点标记为合格,像素为3 }}}}else//去除孔洞,黑色点像素 {//cout << "去除孔洞";for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (Src.at<uchar>(i, j) > 10){PointLabel.at<uchar>(i, j) = 3;//如果原图是白色区域,标记为合格,像素为3 }}}}vector<Point2i>NeihborPos;//将邻域压进容器 NeihborPos.push_back(Point2i(-1, 0));NeihborPos.push_back(Point2i(1, 0));NeihborPos.push_back(Point2i(0, -1));NeihborPos.push_back(Point2i(0, 1));if (NeihborMode == 1){//cout << "Neighbor mode: 8邻域." << endl;NeihborPos.push_back(Point2i(-1, -1));NeihborPos.push_back(Point2i(-1, 1));NeihborPos.push_back(Point2i(1, -1));NeihborPos.push_back(Point2i(1, 1));}else int a = 0;//cout << "Neighbor mode: 4邻域." << endl;int NeihborCount = 4 + 4 * NeihborMode;int CurrX = 0, CurrY = 0;//开始检测 for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (PointLabel.at<uchar>(i, j) == 0)//标签图像像素点为0,表示还未检查的不合格点 { //开始检查 vector<Point2i>GrowBuffer;//记录检查像素点的个数 GrowBuffer.push_back(Point2i(j, i));PointLabel.at<uchar>(i, j) = 1;//标记为正在检查 int CheckResult = 0;for (int z = 0; z < GrowBuffer.size(); z++){for (int q = 0; q < NeihborCount; q++){CurrX = GrowBuffer.at(z).x + NeihborPos.at(q).x;CurrY = GrowBuffer.at(z).y + NeihborPos.at(q).y;if (CurrX >= 0 && CurrX<Src.cols&&CurrY >= 0 && CurrY<Src.rows) //防止越界 {if (PointLabel.at<uchar>(CurrY, CurrX) == 0){GrowBuffer.push_back(Point2i(CurrX, CurrY)); //邻域点加入buffer PointLabel.at<uchar>(CurrY, CurrX) = 1; //更新邻域点的检查标签,避免重复检查 }}}}if (GrowBuffer.size()>AreaLimit) //判断结果(是否超出限定的大小),1为未超出,2为超出 CheckResult = 2;else{CheckResult = 1;RemoveCount++;//记录有多少区域被去除 }for (int z = 0; z < GrowBuffer.size(); z++){CurrX = GrowBuffer.at(z).x;CurrY = GrowBuffer.at(z).y;PointLabel.at<uchar>(CurrY, CurrX) += CheckResult;//标记不合格的像素点,像素值为2 }//********结束该点处的检查********** }}}CheckMode = 255 * (1 - CheckMode);//开始反转面积过小的区域 for (int i = 0; i < Src.rows; ++i){for (int j = 0; j < Src.cols; ++j){if (PointLabel.at<uchar>(i, j) == 2){Dst.at<uchar>(i, j) = CheckMode;}else if (PointLabel.at<uchar>(i, j) == 3){Dst.at<uchar>(i, j) = Src.at<uchar>(i, j);}}}//cout << RemoveCount << " objects removed." << endl;
}
//=======函数实现=====================================================================
//=======调用函数=====================================================================Mat img;img = imread("D:\\1_1.jpg", 0);//读取图片threshold(img, img, 128, 255, CV_THRESH_BINARY_INV);imshow("去除前", img);Mat img1;RemoveSmallRegion(img, img, 200, 0, 1);imshow("去除后", img);waitKey(0);
//=======调用函数=====================================================================
相关文章:
[C++]使用OpenCV去除面积较小的连通域
这是后期补充的部分,和前期的代码不太一样 效果图 源代码 //测试 void CCutImageVS2013Dlg::OnBnClickedTestButton1() {vector<vector<Point> > contours; //轮廓数组vector<Point2d> centers; //轮廓质心坐标 vector<vector<Point&…...
vscode连接不上,终端ssh正常,一直输入密码正确但是无法登录
若是之前链结果突然等不上,使用第一个链接 若是第一次链接连不上,先使用第二个链接,在使用第一个链接 原因:原因是服务器端的wget命令不能使用,vscode需要服务器端下载个文件,无法下载就导致了如上的错误…...
Hive on Spark 配置
目录 1 Hive 引擎简介2 Hive on Spark 配置2.1 在 Hive 所在节点部署 Spark2.2 在hive中创建spark配置文件2.3 向 HDFS上传Spark纯净版 jar 包2.4 修改hive-site.xml文件2.5 Hive on Spark测试2.6 报错 1 Hive 引擎简介 Hive引擎包括:MR(默认)…...
ROS 基本
ROS创建自己的功能包 ROS中工作空间(workspace)是一个存放工程开发相关文件的文件夹,其中有四个文件夹。 src:代码空间(Source Space)build:编译空间(Build Space)devel:开发空间(Development Space)install:安装空间(Install Space) OK接下来创作工作空间&#…...
Pygame基础9-射击
简介 玩家用鼠标控制飞机(白色方块)移动,按下鼠标后,玩家所在位置出现子弹,子弹匀速向右飞行。 代码 没有什么新的东西,使用两个精灵类表示玩家和子弹。 有一个细节需要注意,当子弹飞出屏幕…...
Ps:颜色查找
颜色查找 Color Lookup命令通过应用预设的 LUT 来改变图像的色彩和调性,从而为摄影师和设计师提供了一种快速实现复杂色彩调整的方法,广泛应用于颜色分级、视觉风格的统一和创意色彩效果的制作。 Ps菜单:图像/调整/颜色查找 Adjustments/Colo…...
vue3+vite 模板vue3-element-admin框架如何关闭当前页面跳转 tabs
使用模版: 有来开源组织 / vue3-element-admin 需要关闭的.vue 页面增加以下方法 //setup 里import {LocationQuery, useRoute, useRouter} from "vue-router"; const router useRouter(); function close() {console.log(|--router.currentRoute.value, router.cur…...
JavaScript 对象管家 Proxy
JavaScript 在 ES6 中,引入了一个新的对象类型 Proxy,它可以用来代理另一个对象,并可以在代理过程中拦截、覆盖和定制对象的操作。Proxy 对象封装另一个对象并充当中间人,其提供了一个捕捉器函数,可以在代理对象上拦截…...
Qt + Vs联合开发
Qt + Vs联合开发 文章目录 Qt + Vs联合开发环境说明VS+Qt安装注意事项QtCreator msvc编译器配置Visual Studio 2019 + Qt 5.12.10Visual Studio 2015 + Qt5.12.10VsQt环境配置安装插件 Qt Visual Studio Tools插件配置Qt创建项目Vs创建Qt项目VsQt工程转换Vs工程转Qt工程Qt工程转…...
开源知识库平台Raneto--使用Docker部署Raneto
文章目录 一、Raneto介绍1.1 Raneto简介1.2 知识库介绍 二、阿里云环境2.1 环境规划2.2 部署介绍 三、环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Raneto镜像五、部署Raneto知识库平台5.1 创建挂载目录5.2 编辑config.js文件5.3 编…...
鸿蒙原OS开发实例:【ArkTS类库单次I/O任务开发】
Promise和async/await提供异步并发能力,适用于单次I/O任务的场景开发,本文以使用异步进行单次文件写入为例来提供指导。 实现单次I/O任务逻辑。 import fs from ohos.file.fs; import common from ohos.app.ability.common;async function write(data:…...
C语言:二叉树的构建
目录 一、二叉树的存储 1.1 顺序存储 1.2 链式存储 二、二叉树的顺序结构及实现 2.1堆的概念及结构 2.2堆的构建 2.3堆的插入 2.4堆顶的删除 2.5堆的完整代码 三、二叉树的链式结构及实现 3.1链式二叉树的构建 3.2链式二叉树的遍历 3.2.1前序遍历 …...
软件测试工程师面试汇总功能测试篇
Q:一、进行测试用例设计的时候用到的方法有哪些? A:最常使用的测试用例设计方法包括等价类划分法、边界值分析方法、场景法、错误推测法。其中,最容易 发现错误的是边界值法,使用最多的是场景法。以注册为例:首先从需求确定用户名…...
javaAPI1
API application pragramming interface 应用程序编程接口 除java.lang包以外,其他包中的类在使用时需要导入 建包 package com.abc.javabean; 导包格式,import 包名.类名 API使用技巧 1,先看关键字 2,看参数列表 3,看返回值类型 String 封装字符串和处理字符串的类…...
案例研究|DataEase实现物业数据可视化管理与决策支持
河北隆泰物业服务有限责任公司(以下简称为“隆泰物业”)创建于2002年,总部设在河北省高碑店市,具有国家一级物业管理企业资质,通过了质量体系、环境管理体系、职业健康安全管理体系等认证。自2016年至今,隆…...
Android Studio Iguana | 2023.2.1 补丁 1
Android Studio Iguana | 2023.2.1 Canary 3 已修复的问题Android Gradle 插件 问题 295205663 将 AGP 从 8.0.2 更新到 8.1.0 后,任务“:app:mergeReleaseClasses”执行失败 问题 298008231 [Gradle 8.4][升级] 由于使用 kotlin gradle 插件中已废弃的功能&#…...
iOS17 隐私协议适配详解
1. 背景 网上搜了很多文章,总算有点头绪了。其实隐私清单最后做出来就是一个plist文件。找了几个常用三方已经配好的看了看,比着做就好了。 WWDC23 中关于隐私部分的更新(WWDC23 隐私更新官网),其中提到了第三方 SDK 的…...
LeetCode 每日一题 Day 116-122
2580. 统计将重叠区间合并成组的方案数 给你一个二维整数数组 ranges ,其中 ranges[i] [starti, endi] 表示 starti 到 endi 之间(包括二者)的所有整数都包含在第 i 个区间中。 你需要将 ranges 分成 两个 组(可以为空…...
linux离线安装jenkins及使用教程
本教程采用jenkins.war的方式离线安装部署,在线下载的方式会遇到诸多问题,不宜采用 基本环境: 1.jdk环境,Jenkins是java语言开发的,因需要jdk环境。 2.git/svn客户端,因一般代码是放在git/svn服务器上的&a…...
NXP-S32DS软件安装
文章目录 一、安装包获取二、S32DS安装三、芯片插件安装 一、安装包获取 登录NXP官网,进入软件目录https://www.nxp.com/ 下载S32DS软件和RTD驱动库,并安装S32DS软件。 单击“S32DS.3.5_b220726_win32.x86_64.exe”下载该软件 点击“License Keys”&…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
