OpenCV groupRectangles - 获取分组和未分组的矩形

20
我正在使用OpenCV并希望建立有明显重叠的矩形。我尝试使用`groupRectangles`,它接受组阈值参数。设置阈值为0时,它根本不进行分组;阈值为1时,仅返回是由至少2个矩形生成的矩形。例如,在下面图片左侧给出的矩形上,您最终会得到右侧的2个矩形:

enter image description here

我想要的结果是3个矩形。除了上面案例中的右侧2个矩形之外,还应包括左侧图像中不与任何其他矩形重叠的右上角矩形。如何实现最佳效果?

我也有类似的问题...你已经找到解决方案了吗? - skm
3个回答

22

我最终采取的解决方案是在调用groupRectangles之前复制所有初始矩形。这样每个输入矩形都确保与至少一个其他矩形分组,并将出现在输出中:

int size = rects.size();
for( int i = 0; i < size; i++ )
{
    rects.push_back(Rect(rects[i]));
}
groupRectangles(rects, 1, 0.2);

不知道为什么这对我不起作用。在我的情况下,重复的矩形仍然被删除了。你有什么想法我在这里做错了吗? - Jaykob
更新:我解决了我的问题。我不知何故在输入数据的所有其他矩形周围有一个大矩形。这当然搞乱了一切。抱歉:D - Jaykob

2

虽然我来晚了,但是“复制”解决方案并没有很好地为我工作。我还遇到另一个问题,即合并的矩形会重叠并需要合并。

因此,我想出了一种过度解决方案(可能需要C++14编译器)。以下是使用示例:

std::vector<cv::Rect> rectangles, test1, test2, test3;

rectangles.push_back(cv::Rect(cv::Point(5, 5), cv::Point(15, 15)));
rectangles.push_back(cv::Rect(cv::Point(14, 14), cv::Point(26, 26)));
rectangles.push_back(cv::Rect(cv::Point(24, 24), cv::Point(36, 36)));

rectangles.push_back(cv::Rect(cv::Point(37, 20), cv::Point(40, 40)));
rectangles.push_back(cv::Rect(cv::Point(20, 37), cv::Point(40, 40)));

test1 = rectangles;
test2 = rectangles;
test3 = rectangles;

//Output format: {Rect(x, y, width, height), ...}

//Merge once
mergeRectangles(test1);
//Output rectangles: test1 = {Rect(5, 5, 31, 31), Rect(20, 20, 20, 20)} 

//Merge until there are no rectangles to merge
mergeRectangles(test2, true);
//Output rectangles: test2 = {Rect(5, 5, 35, 35)} 

//Override default merge (intersection) function to merge all rectangles
mergeRectangles(test3, false, [](const cv::Rect& r1, const cv::Rect& r2) {
    return true;
});
//Output rectangles: test3 = {Rect(5, 5, 35, 35)} 

功能:

void mergeRectangles(std::vector<cv::Rect>& rectangles, bool recursiveMerge = false, std::function<bool(const cv::Rect& r1, const cv::Rect& r2)> mergeFn = nullptr) {
    static auto defaultFn = [](const cv::Rect& r1, const cv::Rect& r2) {
        return (r1.x < (r2.x + r2.width) && (r1.x + r1.width) > r2.x && r1.y < (r2.y + r2.height) && (r1.y + r1.height) > r2.y);
    };

    static auto innerMerger = [](std::vector<cv::Rect>& rectangles, std::function<bool(const cv::Rect& r1, const cv::Rect& r2)>& mergeFn) {
        std::vector<std::vector<std::vector<cv::Rect>::const_iterator>> groups;
        std::vector<cv::Rect> mergedRectangles;
        bool merged = false;

        static auto findIterator = [&](std::vector<cv::Rect>::const_iterator& iteratorToFind) {
            for (auto groupIterator = groups.begin(); groupIterator != groups.end(); ++groupIterator) {
                auto foundIterator = std::find(groupIterator->begin(), groupIterator->end(), iteratorToFind);
                if (foundIterator != groupIterator->end()) {
                    return groupIterator;
                }
            }
            return groups.end();
        };

        for (auto rect1_iterator = rectangles.begin(); rect1_iterator != rectangles.end(); ++rect1_iterator) {
            auto groupIterator = findIterator(rect1_iterator);

            if (groupIterator == groups.end()) {
                groups.push_back({rect1_iterator});
                groupIterator = groups.end() - 1;
            }

            for (auto rect2_iterator = rect1_iterator + 1; rect2_iterator != rectangles.end(); ++rect2_iterator) {
                if (mergeFn(*rect1_iterator, *rect2_iterator)) {
                    groupIterator->push_back(rect2_iterator);
                    merged = true;
                }
            }
        }

        for (auto groupIterator = groups.begin(); groupIterator != groups.end(); ++groupIterator) {
            auto groupElement = groupIterator->begin();

            int x1 = (*groupElement)->x;
            int x2 = (*groupElement)->x + (*groupElement)->width;
            int y1 = (*groupElement)->y;
            int y2 = (*groupElement)->y + (*groupElement)->height;

            while (++groupElement != groupIterator->end()) {
                if (x1 > (*groupElement)->x)
                    x1 = (*groupElement)->x;
                if (x2 < (*groupElement)->x + (*groupElement)->width)
                    x2 = (*groupElement)->x + (*groupElement)->width;
                if (y1 >(*groupElement)->y)
                    y1 = (*groupElement)->y;
                if (y2 < (*groupElement)->y + (*groupElement)->height)
                    y2 = (*groupElement)->y + (*groupElement)->height;
            }

            mergedRectangles.push_back(cv::Rect(cv::Point(x1, y1), cv::Point(x2, y2)));
        }

        rectangles = mergedRectangles;
        return merged;
    };

    if (!mergeFn)
        mergeFn = defaultFn;

    while (innerMerger(rectangles, mergeFn) && recursiveMerge);
}

0

通过查看 opencv-3.3.0 源代码中的 groupRectangles()

    if( groupThreshold <= 0 || rectList.empty() )
    {
        // ......
        return;
    }

我发现,如果将groupThreshold设置为小于或等于0,则函数将仅返回而不进行任何分组。

另一方面,下面的代码会删除所有没有超过groupThreshold相似度的矩形。

    // filter out rectangles which don't have enough similar rectangles
    if( n1 <= groupThreshold )
        continue;

这就解释了为什么当groupThreshold=1时,只有至少有2个重叠的矩形才会出现在输出中。
一个可能的解决方案是修改上面显示的源代码(将“n1 <= groupThreshold”替换为“n1 < groupThreshold”),然后重新编译OpenCV。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接