【问题标题】:OpenCV: Merging overlapping rectanglesOpenCV:合并重叠的矩形
【发布时间】:2015-06-13 21:56:51
【问题描述】:

在使用 OpenCV 进行检测任务时,我一直遇到合并重叠边界框的问题;也就是说,本质上是在两个重叠边界框的并集​​周围找到边界框。这在对象检测中经常出现,因为某种原因,感兴趣的对象被分割成多个边界框,而不是一个包罗万象的边界框。

在 StackOverflow 上有一些算法解决方案和有用的外部库的答案(例如 thisthisthis),还有 OpenCV 提供的 groupRectangles 函数(以及一连串相关问题/错误:thisthis 等)。

我似乎发现上述解决方案对于我正在尝试执行的任务来说有点过于复杂。许多算法解决方案从数学角度解决了这个问题(更像是一个思想实验),而当矩形数量很高时,像rect1 | rect2 这样的操作会变得非常慢(处理所有事情都是 O(N^2) ) 和groupRectangles 有一些怪癖,使其仅部分有效。所以我想出了一个有点骇人听闻的解决方案,它实际上非常有效。我想我会在下面与其他需要快速解决此常见问题的人分享。

欢迎评论和批评。

【问题讨论】:

  • 测试交集:cv::Rect intersect = rect1 && rect2;组合:if(intersection.width) 组合 = rect1 || rect2;
  • @Micka 但这需要你遍历 N 个矩形 N 次。对于一个小的 N 很好。但根据经验,我发现当你得到更大的 N 时,二次运行时间最终会比我下面的解决方案慢
  • 这显然是真的!您可以对空间进行分区(类似于您的答案),但是对于较小的数字会很慢并且可能会使用更多的内存。
  • @Micka 也是可行的。我发布此内容的部分原因是因为它也相当轻巧且易于实现。一旦你进入分区和诸如此类的事情往往会滚雪球
  • @marcman 我认为为了使这篇文章更有价值,你应该更好地指定 1)合并 2 个矩形是什么意思,特别是在结果方面:你只想要交集,还是面积的总和,还是最小 x0 和 y0(顶角 r 坐标)和最大 x1 和 y1(底角坐标)? 2)“太复杂”是什么意思?加工太复杂、太贵? 3)为什么你的特殊解决方案更适合?这是否取决于您拥有的输入数据类型?如果是,请更详细地描述您的输入数据。

标签: c++ opencv bounding-box object-detection


【解决方案1】:
void mergeOverlappingBoxes(std::vector<cv::Rect> &inputBoxes, cv::Mat &image, std::vector<cv::Rect> &outputBoxes)
{
    cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1); // Mask of original image
    cv::Size scaleFactor(10,10); // To expand rectangles, i.e. increase sensitivity to nearby rectangles. Doesn't have to be (10,10)--can be anything
    for (int i = 0; i < inputBoxes.size(); i++)
    {
        cv::Rect box = inputBoxes.at(i) + scaleFactor;
        cv::rectangle(mask, box, cv::Scalar(255), CV_FILLED); // Draw filled bounding boxes on mask
    }

    std::vector<std::vector<cv::Point>> contours;
    // Find contours in mask
    // If bounding boxes overlap, they will be joined by this function call
    cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    for (int j = 0; j < contours.size(); j++)
    {
        outputBoxes.push_back(cv::boundingRect(contours.at(j)));
    }
}

【讨论】:

  • 一个错误是,如果内部矩形与其他两个正在合并的矩形不相交,您仍然可以在较大的矩形内得到一个边界框。例如,如果 2D XY 平面中的 TR、BR、BL 象限被填充,并且 TL 象限中有一个未连接的小对象。结果将是整个平面周围的一个矩形,以及 TL 象限内的一个不同的矩形。一种解决方法是再次调用此函数,但随后很容易开始螺旋式上升...
  • 我可能会建议一种更快更轻松的方法。首先,使用它们的成对重叠(运算符 &)对所有相关联的框进行分组。对于每组框,找到轴 x 和 y 的最小值和最大值。结果和你的一样,但是方法不是很重。
  • @William 您如何有效地对关联的框进行分组?假设你只有一个边界框向量,你怎么能比 O(N^2) 时间更快地做到这一点?我在上面的评论中提到过,我没有对我的解决方案进行分析,但从经验上看,它比将每个 Rect 与其他每个比较运行得更快
  • 我喜欢C4 detector 所做的事情。检查 Pedestrian_ICRA.cpp 中的函数 void PostProcess()。不幸的是,他使用自己的类,需要做一些额外的工作才能使用 cv::Rect。
  • @Antoniorect上的操作列表可以在here找到。 +/- a cv::Point() 进行翻译。 +/- cv::Size() 将放大或缩小rect。不过,我也必须对其进行测试才能确定
猜你喜欢
  • 2016-06-27
  • 1970-01-01
  • 2016-10-17
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
  • 2018-11-02
  • 1970-01-01
  • 2014-05-13
相关资源
最近更新 更多