OpenCV:合并重叠的矩形
OpenCV: Merging overlapping rectangles
在使用 OpenCV 进行检测任务时,我一直 运行 解决合并重叠边界框的问题;也就是说,本质上是在两个重叠边界框的并集周围找到边界框。当由于某种原因,感兴趣的对象被分成许多边界框,而不是一个包罗万象的边界框时,这在对象检测中经常出现。
Whosebug 上有一些关于算法解决方案和有用的外部库(例如 this, this, this), and there's also the groupRectangles
function provided by OpenCV (and the litany of associated questions/bugs: this, this 等)的答案。
我似乎发现上述解决方案对于我要执行的任务来说有点过于复杂。许多算法解决方案从数学角度解决了这个问题(更像是一个思想实验),而当矩形数量很多时,像 rect1 | rect2
这样的操作会变得非常慢(它是 O(N^2) 到handle everything) 并且 groupRectangles
有一些怪癖使其只能部分有效。所以我想出了一个有点老套的解决方案,但实际上非常有效。我想我会在下面与其他需要快速解决这个常见问题的人分享它。
欢迎评论批评。
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)));
}
}
在使用 OpenCV 进行检测任务时,我一直 运行 解决合并重叠边界框的问题;也就是说,本质上是在两个重叠边界框的并集周围找到边界框。当由于某种原因,感兴趣的对象被分成许多边界框,而不是一个包罗万象的边界框时,这在对象检测中经常出现。
Whosebug 上有一些关于算法解决方案和有用的外部库(例如 this, this, this), and there's also the groupRectangles
function provided by OpenCV (and the litany of associated questions/bugs: this, this 等)的答案。
我似乎发现上述解决方案对于我要执行的任务来说有点过于复杂。许多算法解决方案从数学角度解决了这个问题(更像是一个思想实验),而当矩形数量很多时,像 rect1 | rect2
这样的操作会变得非常慢(它是 O(N^2) 到handle everything) 并且 groupRectangles
有一些怪癖使其只能部分有效。所以我想出了一个有点老套的解决方案,但实际上非常有效。我想我会在下面与其他需要快速解决这个常见问题的人分享它。
欢迎评论批评。
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)));
}
}