c++ - OpenCV floodFill() 填充未连接的区域

标签 c++ opencv image-processing flood-fill

我已经实现了来自 here 的连接组件识别算法,但在某些情况下,cv::floodFill(...) 似乎会填充未连接的区域。

首先,这是代码:

void ImageMatchingOpenCV::getConnectedComponents(const cv::Mat& binImg, vector<vector<cv::Point>>& components, vector<vector<cv::Point>>& contours, const int minSize)
  {
      cv::Mat ccImg;
      binImg.convertTo(ccImg, CV_32FC1);

      int gap=startPointParams.gap;
      int label = 1;
      for(int y=gap; y<binImg.rows-gap; ++y)
      {
          for(int x=gap; x<binImg.cols-gap; ++x)
          {
              if((int)ccImg.at<float>(y, x)!=255) continue;
              cv::Rect bBox;
              cv::floodFill(ccImg, cv::Point(x, y), cv::Scalar(label), &bBox, cv::Scalar(0), cv::Scalar(0), 4 /*| cv::FLOODFILL_FIXED_RANGE*/);
              if(bBox.x<gap || bBox.y<gap || bBox.x+bBox.width>=binImg.cols-gap || bBox.y+bBox.height>=binImg.rows-gap) continue;
              components.push_back(vector<cv::Point>()); contours.push_back(vector<cv::Point>());
              for(int i=bBox.y; i<bBox.y+bBox.height; ++i)
              {
                  for(int j=bBox.x; j<bBox.x+bBox.width; ++j)
                  {
                      if((int)ccImg.at<float>(i, j)!=label) continue;
                      components.back().push_back(cv::Point(j, i));
                      if(    (int)ccImg.at<float>(i+1, j)!=label
                          || (int)ccImg.at<float>(i-1, j)!=label
                          || (int)ccImg.at<float>(i, j+1)!=label
                          || (int)ccImg.at<float>(i, j-1)!=label) contours.back().push_back(cv::Point(j, i));
                  }
              }
              if(components.back().size()<minSize)
              {
                  components.pop_back();
                  contours.pop_back();
              }
              else
              {
                  ++label;
                  if(label==255) ++label;
                  break;
              }
          }
          if(label!=1) break;
      }       
  }

输入 cv::Mat 包含大小为 CV_8U 的 2448x2050 像素。像素值为 0(背景)或 255(前景)。图像中有 17 个连通分量。除第一个组件外,所有组件均已正确识别。错误的组件是迄今为止最大的一个(约 150 万像素),并且包含一些小的断开连接的像素组。它包含所有其他组件。错误分配给第一个组件的小的不连接像素组都连接到组件边界框的顶部。

编辑:我添加了一些图像来可视化问题。第一张图片显示了所有已识别的连接组件。第二张图片只显示了错误的组件(注意顶部断开连接的小像素组)。第三张图片放大了第二张图片的一部分:

All components

The erroneous component

Zoomed erroneous component

如果有人知道错误可能在哪里,我将不胜感激。

最佳答案

我自己发现了这个错误。在方法结束时,小组件被丢弃。在这种情况下,组件的编号(标签)不会增加:

if(components.back().size()<minSize)
{
    components.pop_back();
    contours.pop_back();
}
else
{
    ++label;
    if(label==255) ++label;        
}

这意味着,标签编号再次用于标记图像中的下一个组件。因此,几个小组件和一个足够大的组件可能具有相同的标签号。如果现在迭代大组件的边界框,那么这个边界框可能包含一些以前识别但未使用的具有相同标签号的小组件。

解决方案是删除 else 分支,而是始终增加标签编号。

关于c++ - OpenCV floodFill() 填充未连接的区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21906305/

相关文章:

c++ - friend get 返回类型的函数,该函数通过可变参数模板递归计算

c++ - 当没有抛出异常时,C++ 异常以什么方式减慢代码速度?

python 'Assertion Error (depth == CV_32F || depth == CV_64F)'

math - 平面中的变形点

ios - 缩放 CVImageBuffer 中的图像

c++ - 从相同的硬编码字符串文字初始化 std::string 和 std::wstring

c++ - 自 (vs2012/2010/2013) 以来,msvcrt 是否使用不同的堆进行分配

java - DCT隐写术

c++ - 函数返回和使用 copyTo 中的 OpenCV Mat

c++ - 来自图像的简单视频制作者