千家信息网

OpenCV如何清除小面积连通域

发表于:2024-11-20 作者:千家信息网编辑
千家信息网最后更新 2024年11月20日,小编给大家分享一下OpenCV如何清除小面积连通域,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!场景需求使用OpenCV,
千家信息网最后更新 2024年11月20日OpenCV如何清除小面积连通域

小编给大家分享一下OpenCV如何清除小面积连通域,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

场景需求

使用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 > contours;  // 创建轮廓容器        std::vector       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 >::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(i);                                        for (int j = rect.x; j < rect.x + rect.width; j++)                                         {                                                // 将连通区的值置0                                                if (output_data[j] == 255)                                                 {                                                        output_data[j] = 0;                                                }                                        }                                }                        }                        itc++;                }        }}

测试代码

#include#include 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 > contours;  // 创建轮廓容器        std::vector       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 >::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(i);                                        for (int j = rect.x; j < rect.x + rect.width; j++)                                         {                                                // 将连通区的值置0                                                if (output_data[j] == 255)                                                 {                                                        output_data[j] = 0;                                                }                                        }                                }                        }                        itc++;                }        }}

测试效果

以上是"OpenCV如何清除小面积连通域"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0