2015-04-08 3 views
3

При использовании OpenCV для задач обнаружения я постоянно сталкиваюсь с проблемой слияния перекрывающих ограничивающих прямоугольников; то есть, по существу, обнаруживая ограничительную рамку вокруг объединения двух перекрывающихся ограничивающих прямоугольников. Это очень часто встречается при обнаружении объектов, когда по какой-либо причине объект интереса разломается на несколько ограничивающих прямоугольников, а не на одно всеобъемлющее.OpenCV: Слияние перекрывающихся прямоугольников

Есть несколько ответов на StackOverflow для алгоритмических решений и полезных внешних библиотек (например this, this, this), и есть также функция groupRectangles обеспечивается OpenCV (и литания связанных вопросов/ошибок: this, this, и т.д).

Я, кажется, обнаружил, что вышеупомянутые решения немного сложны для задачи, которую я пытаюсь выполнить. Многие алгоритмические решения решают эту проблему с математической точки зрения (скорее, как мысленный эксперимент), в то время как операции, подобные rect1 | rect2, могут стать очень медленными, когда число прямоугольников велико (это O (N^2) для обработки всего) и groupRectangles имеет некоторые причуды, которые делают его лишь частично эффективным. Поэтому я придумал несколько хакерское решение, которое действительно работает довольно эффективно. Я думал, что буду делиться этим ниже для всех, кому нужно быстрое решение этой общей проблемы.

Не стесняйтесь, чтобы комментировать и критиковать его.

+0

тест для пересечения: cv :: Rect intersect = rect1 && rect2; Комбинация: if (intersection.width) комбинация = rect1 || rect2; – Micka

+0

@ Мика, но это требует, чтобы вы проходили N прямоугольников N раз каждый. Для маленького N это нормально. Но эмпирически я обнаружил, что квадратичное время работы заканчивается тем, что медленнее, чем мое решение ниже, когда вы получаете больше N – marcman

+0

, что очевидно! вы можете разделить пространство (похожее на ваш ответ), но это будет медленным для меньших чисел и может использовать больше памяти. – Micka

ответ

2
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))); 
    } 
} 
+0

Одна ошибка заключается в том, что вы все равно можете иметь ограничительную рамку внутри большего, если внутренний прямоугольник не пересекается с двумя другими, которые сливаются.Например, если квадранты TR, BR, BL в плоскости 2D XY заполнены, и в квадранте TL нет небольшого объекта, который не подключен. Результатом будет прямоугольник вокруг всей плоскости, а также отдельный внутри квадранта TL. Одно исправление - снова вызвать эту функцию, но тогда легко начать вращаться ... – marcman

+0

Я могу предложить гораздо более быстрый и легкий способ. Сначала группируйте все связанные поля, используя их попарное перекрытие (оператор &). Для каждой группы ящиков найдите min и max для осей x и y. Результаты те же, что и у вас, но метод не тяжелый. – William

+1

@William, как эффективно группировать связанные ящики? Предполагая, что все, что у вас есть, является вектором ограничивающих прямоугольников, как вы можете сделать это быстрее, чем O (N^2)? Я упомянул в комментарии выше, я не делал анализ моего решения, но эмпирически он работает быстрее, чем сравнение каждого 'Rect' со всеми остальными – marcman

Смежные вопросы