Углы MinAreaRect - не уверены в возврате угла

Из функций MinAreaRect, он возвращает углы в диапазоне 0-360 градусов? Я не уверен, поскольку у меня есть объект, ориентированный на 90 градусов или около того, но я продолжаю получать -1 или -15 градусов. Может ли это быть ошибкой openCV?

Любые рекомендации, которые высоко ценятся.

Спасибо

Ответы

Ответ 1

Я предполагаю, что вы используете С++, но ответ должен быть таким же, если вы используете C или Python.

Функция minAreaRect, кажется, дает углы от -90 до 0 градусов, не считая нуля, поэтому интервал [-90, 0).

Функция дает -90 градусов, если прямоугольник, который он выдает, не вращается, т.е. прямоугольник имеет две стороны ровно горизонтально и две стороны точно вертикальные. Когда прямоугольник вращается по часовой стрелке, угол увеличивается (идет к нулю). Когда достигнут нуль, угол, заданный функцией, снова гаснет на -90 градусов.

Итак, если у вас длинный прямоугольник от minAreaRect, и он лежит ровно, minAreaRect вызовет угол -90 градусов. Если вы поворачиваете изображение до тех пор, пока прямоугольник, заданный параметром minAreaRect, не станет вертикально, угол снова скажет -90 градусов.

Я не знал об этом (я откладывал от своего проекта OpenCV, чтобы узнать, как он работает:/). В любом случае, здесь программа OpenCV, демонстрирующая minAreaRect, если я еще не объяснил это достаточно ясно:

#include <stdio.h>

#include <opencv\cv.h>
#include <opencv\highgui.h>

using namespace cv;

int main() {
    float angle = 0;
    Mat image(200, 400, CV_8UC3, Scalar(0));
    RotatedRect originalRect;
    Point2f vertices[4];
    vector<Point2f> vertVect;
    RotatedRect calculatedRect;

    while (waitKey(5000) != 27) {
        // Create a rectangle, rotating it by 10 degrees more each time.
        originalRect = RotatedRect(Point2f(100,100), Size2f(100,50), angle);

        // Convert the rectangle to a vector of points for minAreaRect to use.
        // Also move the points to the right, so that the two rectangles aren't
        // in the same place.
        originalRect.points(vertices);
        for (int i = 0; i < 4; i++) {
            vertVect.push_back(vertices[i] + Point2f(200, 0));
        }

        // Get minAreaRect to find a rectangle that encloses the points. This
        // should have the exact same orientation as our original rectangle.
        calculatedRect = minAreaRect(vertVect);

        // Draw the original rectangle, and the one given by minAreaRect.
        for (int i = 0; i < 4; i++) {
            line(image, vertices[i], vertices[(i+1)%4], Scalar(0, 255, 0));
            line(image, vertVect[i], vertVect[(i+1)%4], Scalar(255, 0, 0));
        }
        imshow("rectangles", image);

        // Print the angle values.
        printf("---\n");
        printf("Original angle:             %7.2f\n", angle);
        printf("Angle given by minAreaRect: %7.2f\n", calculatedRect.angle);
        printf("---\n");

        // Reset everything for the next frame.
        image = Mat(200, 400, CV_8UC3, Scalar(0));
        vertVect.clear();
        angle+=10;
    }

    return 0;
}

Это позволяет вам легко увидеть, как угол и форма прямоугольника, нарисованного вручную, сравнивается с интерпретацией minAreaRect того же прямоугольника.

Ответ 2

Улучшение ответа @Adam Goodwin Я хочу добавить свой маленький код, который немного изменяет поведение:

Я хотел иметь угол между более длинной стороной и вертикалью (для меня это самый естественный способ подумать о вращающихся прямоугольниках):

Behold my Paint skills

Если вам нужно то же самое, просто используйте этот код:

void printAngle(RotatedRect calculatedRect){
    if(calculatedRect.size.width < calculatedRect.size.height){
        printf("Angle along longer side: %7.2f\n", calculatedRect.angle+180);
    }else{
        printf("Angle along longer side: %7.2f\n", calculatedRect.angle+90);
    }
}

Чтобы увидеть его в действии, просто вставьте его в код Адама Гудвина:

printf("Angle given by minAreaRect: %7.2f\n", calculatedRect.angle);
printAngle(calculatedRect);
printf("---\n");

Ответ 3

После эксперимента я обнаружил, что если длинная сторона находится слева от нижней точки, значение угла находится между длинной стороной и осью Y +, но если длинная сторона находится справа от нижней точки, значение угла находится между длинной стороной и осью X +. Поэтому я использую код, подобный этому (java):

       rRect = Imgproc.minAreaRect(mop2f);
       if(rRect.size.width<rRect.size.height){
            angle = 90 -rRect.angle;
        }else{
            angle = -rRect.angle;
        }

Угол от 0 до 180.

Ответ 4

После долгих экспериментов я обнаружил, что взаимосвязь между ориентацией прямоугольника и выходным углом minAreaRect(). Это можно резюмировать на следующем изображении

enter image description here

В следующем описании предполагается, что у нас есть прямоугольник с неравной высотой и шириной длины, то есть он не квадратный.

Если прямоугольник лежит вертикально (ширина <высота), то обнаруженный угол равен -90. Если прямоугольник лежит горизонтально, то обнаруженный угол равен 0 градусам.

Если верхняя часть прямоугольника находится в первом квадранте, то обнаруженный угол уменьшается при повороте прямоугольника из горизонтального в вертикальное положение, пока обнаруженный угол не станет равным -90 градусов. В первом квадранте ширина обнаруженного прямоугольника длиннее его высоты.

Если верхняя часть обнаруженного прямоугольника находится во втором квадранте, то угол уменьшается при повороте прямоугольника из вертикального в горизонтальное положение. Но есть разница между вторым и первым квадрантом. Если прямоугольник приближается к вертикальному положению, но не находится в вертикальном положении, его угол приближается к 0. Если прямоугольник приближается к горизонтальному положению, но не находился в горизонтальном положении, его угол приближается к -90 градусам.