web-dev-qa-db-fra.com

Angles MinAreaRect - Pas sûr de l'angle renvoyé

À partir des fonctions de MinAreaRect, retourne-t-il des angles dans la plage de 0 à 360 degrés? Je ne suis pas sûr car j'ai un objet qui est orienté à 90 degrés environ mais je continue à obtenir -1 ou -15 degrés. Serait-ce une erreur openCV?

Toute orientation très appréciée.

Merci

29
user349026

Je vais supposer que vous utilisez C++, mais la réponse devrait être la même si vous utilisez C ou Python.

La fonction minAreaRect semble donner des angles allant de -90 à 0 degrés, sans compter zéro, donc un intervalle de [-90, 0).

La fonction donne -90 degrés si le rectangle qu'elle émet n'est pas tourné, c'est-à-dire que le rectangle a deux côtés exactement horizontaux et deux côtés exactement verticaux. Lorsque le rectangle tourne dans le sens des aiguilles d'une montre, l'angle augmente (va vers zéro). Lorsque zéro est atteint, l'angle donné par la fonction revient à -90 degrés.

Donc, si vous avez un long rectangle de minAreaRect, et qu'il est couché à plat, minAreaRect appellera l'angle -90 degrés. Si vous faites pivoter l'image jusqu'à ce que le rectangle donné par minAreaRect soit parfaitement droit, l'angle indiquera à nouveau -90 degrés.

Je ne savais rien de tout cela (j'ai tergiversé depuis mon projet OpenCV pour savoir comment ça marche: /). Quoi qu'il en soit, voici un programme OpenCV qui montre minAreaRect si je ne l'ai pas déjà expliqué assez clairement:

#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;
}

Cela vous permet de voir facilement comment l'angle et la forme d'un rectangle dessiné manuellement se comparent à l'interprétation minAreaRect du même rectangle.

39
Adam Goodwin

En améliorant la réponse de @Adam Goodwin, je veux ajouter mon petit code qui change un peu le comportement:

Je voulais avoir l'angle entre le côté le plus long et la verticale (pour moi, c'est la façon la plus naturelle de penser aux rectangles tournés):

Behold my Paint skills

Si vous en avez besoin, utilisez simplement ce code:

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);
    }
}

Pour le voir en action il suffit de l'insérer dans le code Adam Goodwins:

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

Après beaucoup d'expériences, j'ai trouvé que la relation entre l'orientation du rectangle et l'angle de sortie de minAreaRect(). Il peut être résumé dans l'image suivante

enter image description here

La description suivante suppose que nous avons un rectangle de hauteur et de largeur inégales, c'est-à-dire qu'il n'est pas carré.

Si le rectangle est vertical (largeur <hauteur), alors l'angle détecté est -90. Si le rectangle se trouve horizontalement, l'angle détecté est également de -90 degrés.

Si la partie supérieure du rectangle est dans le premier quadrant, alors l'angle détecté diminue à mesure que le rectangle tourne de la position horizontale à la position verticale, jusqu'à ce que l'angle détecté devienne -90 degrés. Dans le premier quadrant, la largeur du rectangle détecté est plus longue que sa hauteur.

Si la partie supérieure du rectangle détecté se trouve dans le deuxième quadrant, l'angle diminue à mesure que le rectangle pivote de la position verticale à la position horizontale. Mais il y a une différence entre le deuxième et le premier quadrant. Si le rectangle s'approche de la position verticale mais n'a pas été en position verticale, son angle s'approche de 0. Si le rectangle s'approche de la position horizontale mais n'est pas en position horizontale, son angle approche de -90 degrés .

Ce post ici est également bon pour expliquer cela.

2
jdhao