经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
OpenCV清除小面积连通域的实现方法
来源:jb51  时间:2021/9/6 11:52:50  对本文有异议

场景需求

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

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

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

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

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

C++实现代码

  1. /**
  2. * @brief Clear_MicroConnected_Areas 清除微小面积连通区函数
  3. * @param src 输入图像矩阵
  4. * @param dst 输出结果
  5. * @return min_area 设定的最小面积清除阈值
  6. */
  7. void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
  8. {
  9. // 备份复制
  10. dst = src.clone();
  11. std::vector<std::vector<cv::Point> > contours; // 创建轮廓容器
  12. std::vector<cv::Vec4i> hierarchy;
  13. // 寻找轮廓的函数
  14. // 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
  15. // 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
  16. cv::findContours(src, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());
  17. if (!contours.empty() && !hierarchy.empty())
  18. {
  19. std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
  20. // 遍历所有轮廓
  21. while (itc != contours.end())
  22. {
  23. // 定位当前轮廓所在位置
  24. cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
  25. // contourArea函数计算连通区面积
  26. double area = contourArea(*itc);
  27. // 若面积小于设置的阈值
  28. if (area < min_area)
  29. {
  30. // 遍历轮廓所在位置所有像素点
  31. for (int i = rect.y; i < rect.y + rect.height; i++)
  32. {
  33. uchar *output_data = dst.ptr<uchar>(i);
  34. for (int j = rect.x; j < rect.x + rect.width; j++)
  35. {
  36. // 将连通区的值置0
  37. if (output_data[j] == 255)
  38. {
  39. output_data[j] = 0;
  40. }
  41. }
  42. }
  43. }
  44. itc++;
  45. }
  46. }
  47. }

测试代码

  1. #include<iostream>
  2. #include<opencv2/opencv.hpp>
  3. using namespace std;
  4. using namespace cv;
  5. void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area);
  6. int main(void)
  7. {
  8. Mat A = Mat::zeros(500, 500, CV_8UC1);
  9. circle(A, Point2i(100, 100), 50, 255, -1);
  10. circle(A, Point2i(300, 400), 15, 255, -1);
  11. Mat B;
  12. Clear_MicroConnected_Areas(A, B, 1000);
  13. imshow("before:A", A);
  14. imshow("after:B", B);
  15. waitKey(0);
  16. system("pause");
  17. return 0;
  18. }
  19. void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
  20. {
  21. // 备份复制
  22. dst = src.clone();
  23. std::vector<std::vector<cv::Point> > contours; // 创建轮廓容器
  24. std::vector<cv::Vec4i> hierarchy;
  25. // 寻找轮廓的函数
  26. // 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
  27. // 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
  28. cv::findContours(src, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());
  29. if (!contours.empty() && !hierarchy.empty())
  30. {
  31. std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
  32. // 遍历所有轮廓
  33. while (itc != contours.end())
  34. {
  35. // 定位当前轮廓所在位置
  36. cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
  37. // contourArea函数计算连通区面积
  38. double area = contourArea(*itc);
  39. // 若面积小于设置的阈值
  40. if (area < min_area)
  41. {
  42. // 遍历轮廓所在位置所有像素点
  43. for (int i = rect.y; i < rect.y + rect.height; i++)
  44. {
  45. uchar *output_data = dst.ptr<uchar>(i);
  46. for (int j = rect.x; j < rect.x + rect.width; j++)
  47. {
  48. // 将连通区的值置0
  49. if (output_data[j] == 255)
  50. {
  51. output_data[j] = 0;
  52. }
  53. }
  54. }
  55. }
  56. itc++;
  57. }
  58. }
  59. }

测试效果

 

图1 处理前后图

到此这篇关于OpenCV-清除小面积连通域的文章就介绍到这了,更多相关OpenCV-清除小面积连通域内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号