打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OpenCV-清除小面积连通域

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

场景需求

       使用OpenCV,往往遇到这类场景:需要清除目标图像中比较小的噪声区,保留主要区域信息。

       特此分享自己写的一个简单的清除小面积连通域函数,逻辑比较简单,给大家留出了足够的发展空间,根据自身场景需求进行调整。

       原理可以简单归结为:搜索图像的连通区轮廓->遍历各个连通区->基于阈值删除面积较小的连通区

       运行速度方面,我没单独测试过这个单元,大家如果试过之后太慢可以评论告诉我哦~

       反正平常我工作跑那种2000*2000的图像,这个函数的耗时几乎忽略不计。。。

C++实现代码

/**
* @brief  Clear_MicroConnected_Areas         清除微小面积连通区函数
* @param  src                                输入图像矩阵
* @param  dst                                输出结果
* @return min_area                           设定的最小面积清除阈值
*/
void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
{
// 备份复制
dst = src.clone();
std::vector<std::vector<cv::Point> > contours;  // 创建轮廓容器
std::vector<cv::Vec4i> hierarchy;  

// 寻找轮廓的函数
// 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
// 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
cv::findContours(src, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());

if (!contours.empty() && !hierarchy.empty()) 
{
std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
// 遍历所有轮廓
while (itc != contours.end()) 
{
// 定位当前轮廓所在位置
cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
// contourArea函数计算连通区面积
double area = contourArea(*itc);
// 若面积小于设置的阈值
if (area < min_area) 
{
// 遍历轮廓所在位置所有像素点
for (int i = rect.y; i < rect.y + rect.height; i++) 
{
uchar *output_data = dst.ptr<uchar>(i);
for (int j = rect.x; j < rect.x + rect.width; j++) 
{
// 将连通区的值置0
if (output_data[j] == 255) 
{
output_data[j] = 0;
}
}
}
}
itc++;
}
}
}

测试代码

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area);

int main(void)
{
Mat A = Mat::zeros(500, 500, CV_8UC1);
circle(A, Point2i(100, 100), 50, 255, -1);
circle(A, Point2i(300, 400), 15, 255, -1);
Mat B;
Clear_MicroConnected_Areas(A, B, 1000);

imshow("before:A", A);
imshow("after:B", B);
waitKey(0);

system("pause");
return 0;
}

void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
{
// 备份复制
dst = src.clone();
std::vector<std::vector<cv::Point> > contours;  // 创建轮廓容器
std::vector<cv::Vec4i> hierarchy;  

// 寻找轮廓的函数
// 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
// 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
cv::findContours(src, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());

if (!contours.empty() && !hierarchy.empty()) 
{
std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
// 遍历所有轮廓
while (itc != contours.end()) 
{
// 定位当前轮廓所在位置
cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
// contourArea函数计算连通区面积
double area = contourArea(*itc);
// 若面积小于设置的阈值
if (area < min_area) 
{
// 遍历轮廓所在位置所有像素点
for (int i = rect.y; i < rect.y + rect.height; i++) 
{
uchar *output_data = dst.ptr<uchar>(i);
for (int j = rect.x; j < rect.x + rect.width; j++) 
{
// 将连通区的值置0
if (output_data[j] == 255) 
{
output_data[j] = 0;
}
}
}
}
itc++;
}
}
}

测试效果

图1 处理前后图

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
OpenCV(C++版)轮廓(contour)检测
通过HSV进行颜色分离
基于distanceTransform-距离变换的区域中心提取
opencv二维码识别解码
OpenCV探索之路(二十二):制作一个类“全能扫描王”的简易扫描软件
opencv 截取轮廓中的图像
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服