Область выделения OpenCV изображения из вектора квадратов

У меня есть изображение, которое содержит квадрат, и мне нужно извлечь область, содержащуюся в этом квадрате. После применения squares.c script (доступного в образцах каждого дистрибутива OpenCV) я получаю вектор квадратов, тогда мне нужно сохранить изображение для каждого из них.

Пользователь karlphillip предложил следующее:

for (size_t x = 0; x < squares.size(); x++) 
{
    Rect roi(squares[x][0].x, squares[x][0].y, 
             squares[x][1].x - squares[x][0].x, 
             squares[x][3].y - squares[x][0].y);
    Mat subimage(image, roi);
}

чтобы создать новый Mat подкатегорий для всех квадратов, обнаруженных в исходном изображении

Как заметил меня Карл, точки, обнаруженные на изображении, могут не представлять идеальный квадрат (как вы можете видеть на изображении выше), но код, который я только что предложил вам, предполагает, что они делают.

Фактически я получаю эту ошибку:

OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width &&
      roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height &&
      roi.y + roi.height <= m.rows) in Mat, file /usr/include/opencv/cxmat.hpp, 
      line 187

terminate called after throwing an instance of 'cv::Exception'
what():  /usr/include/opencv/cxmat.hpp:187: error: (-215) 0 <= roi.x && 
       0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y &&
       0 <= roi.height && roi.y + roi.height <= m.rows in function Mat

Aborted

Предложение о том, чтобы script принять также не идеальные квадраты?

Ответы

Ответ 1

Мне кажется, что мне нужно прояснить некоторые вещи об этом коде.

Первый, он предполагает, что обнаруженная область является идеальным квадратом, потому что она игнорирует некоторые из точек внутри squares[x] для создания нового Mat.

Второй, он также предполагает, что точки, которые делают область, были обнаружены по часовой стрелке, начиная с p0 в верхнем левом углу изображения:

(p0)  1st----2nd  (p1)
       |      |
       |      |
(p3)  4th----3rd  (p2)

что может быть неверно для всех обнаруженных регионов. Это означает, что этот код:

Rect roi(squares[x][0].x, squares[x][0].y, 
         squares[x][1].x - squares[x][0].x, 
         squares[x][3].y - squares[x][0].y);

вероятно, создаст ROI с недопустимыми размерами, такими как отрицательные значения ширины и высоты, и почему OpenCV бросает на вас cv::Exception на Mat subimage(image, roi);.

Что вы должны сделать, это написать код, который будет идентифицировать верхнюю левую точку региона и называть его p0, затем ближайший neightbor с правой стороны, p1, затем найдите нижнюю правую точку области и назовите ее p2, а затем что осталось p3. После этого сборка ROI проста:

Rect roi(p0.x, p0.y, 
         p1.x - p0.x, 
         p3.y - p0.y);

ИЗМЕНИТЬ

Я нашел отличное решение при чтении документации v2.3 OpenCV. Он автоматизирует процесс, который я описал ранее, и делает вещи намного проще и чисты. Вы можете использовать этот трюк, чтобы заказать 4 точки в векторе для значимой структуры Rect:

// Data returned and filled by findSquares(). Check the example squares.cpp for more info on this function.
vector<vector<Point> > squares;

for (size_t i = 0; i < squares.size(); i++)
{
    Rect rectangle = boundingRect(Mat(squares[i]));
    cout << "#" << i << " rectangle x:" << rectangle.x << " y:" << rectangle.y << " " << rectangle.width << "x" << rectangle.height << endl;
}