首页 > 解决方案 > 查找轮廓在模拟图像上发现太多轮廓

问题描述

我想找到分段岩石的二值图像的轮廓。opencv 的 findContours 函数存在一些问题。

  1. 轮廓大小约为 1000,而二值图像的轮廓可能约为 30-50。

  2. 当我绘制所有轮廓时,它们似乎是二进制图像中黑色边界的一个不错的表示。但是当我只绘制某个随机索引的一个轮廓时,它会显示一个小轮廓。

图片如下:

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

我想拥有与二进制图像一样的确切数量的轮廓。

代码 :

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(input_image, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
  for( int i = 0; i < (int)contours.size(); i++)
  {

      cv::drawContours(input_rgb_image, contours, 512 , cv::Scalar(0,255,0), 1, 8, hierarchy,1);


  }


标签: opencvimage-processingopencv-contour

解决方案


我会尝试几件事:

  • 双边滤波器而不是模糊。它以类似于模糊的方式平滑事物,但也尝试保留边界,这有利于分割。缺点 - 它的计算成本很高,但你可能会发现“你的”参数可以免费播放
  • 分水岭之前的模糊+均值偏移分割。Blur 会像预期的那样起作用,meanshift 将平均并连接具有相似颜色的轮廓,因此使轮廓的数量更小。根据参数,meanshift 也很昂贵。只是玩它。

更高级的是之后的轮廓分析。您可以根据以下条件联合一些邻居:

  • 直方图在某些 hsv 通道上的相似性;
  • 轮廓属性,例如圆度。如果两个联合邻居的圆度优于其中任何一个的圆度,则它们可以联合。像这样的东西。

圆度计算:

float calcRoundness(std::vector<cv::Point> &contour, double area)
{
        float p = cv::arcLength(contour, true);
        if (p == 0)
                return 0;
        float k = (4 * M_PI * area) / pow(p, 2);

        /* 1 is circle, 0.75 - squared area, etc. */
        return k;
}

推荐阅读