OpenCV groupRectangles - 获取分组和未分组的矩形
Posted
技术标签:
【中文标题】OpenCV groupRectangles - 获取分组和未分组的矩形【英文标题】:OpenCV groupRectangles - getting grouped and ungrouped rectangles 【发布时间】:2014-01-29 02:45:03 【问题描述】:我正在使用 OpenCV,并希望将具有显着重叠的矩形组合在一起。我已经尝试为此使用groupRectangles
,它采用组阈值参数。阈值为 0 时,它根本不进行任何分组,阈值为 1 时仅返回至少是 2 个矩形的结果的矩形。例如,给定下图中左侧的矩形,您最终会得到右侧的 2 个矩形:
我想最终得到 3 个矩形。上图中右侧的 2,加上左侧图像右上角的矩形,该矩形不与任何其他矩形重叠。实现这一目标的最佳方法是什么?
【问题讨论】:
我也有类似的问题...您已经找到解决方案了吗? 【参考方案1】:我最终采用的解决方案是在调用groupRectangles
之前复制所有初始矩形。这样,每个输入矩形都可以保证与至少一个其他矩形分组,并且会出现在输出中:
int size = rects.size();
for( int i = 0; i < size; i++ )
rects.push_back(Rect(rects[i]));
groupRectangles(rects, 1, 0.2);
【讨论】:
不知何故这对我不起作用。在我的情况下,重复的矩形仍然被删除。知道我在这里做错了什么吗? 更新:我解决了我的问题。我不知何故在我的输入数据中的所有其他矩形周围都有一个大矩形。这当然把一切都搞砸了。对不起:D【参考方案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);
【讨论】:
【参考方案3】:通过查看 opencv-3.3.0 源代码中的groupRectangles():
if( groupThreshold <= 0 || rectList.empty() )
// ......
return;
我看到如果 groupThreshold
设置为小于或等于 0,该函数将直接返回而不进行任何分组。
另一方面,以下code 删除了所有相似度不超过groupThreshold
的矩形。
// filter out rectangles which don't have enough similar rectangles
if( n1 <= groupThreshold )
continue;
这就解释了为什么当 groupThreshold=1 时,输出中只有至少有 2 个重叠的矩形。
一种可能的解决方案是修改上面显示的源代码(将n1 <= groupThreshold
替换为n1 < groupThreshold
)并重新编译OpenCV。
【讨论】:
以上是关于OpenCV groupRectangles - 获取分组和未分组的矩形的主要内容,如果未能解决你的问题,请参考以下文章
OpenCV groupRectangles - 获取分组和未分组的矩形