【问题标题】:MinAreaRect angles - Unsure about the angle returnedMinAreaRect 角度 - 不确定返回的角度
【发布时间】:2021-12-20 17:21:34
【问题描述】:

从 MinAreaRect 的函数中,它是否返回 0-360 度范围内的角度? 我不确定,因为我有一个方向为 90 度左右的对象,但我一直得到 -1 或 -15 度。这可能是 openCV 错误吗?

非常感谢任何指导。

谢谢

【问题讨论】:

    标签: opencv angle


    【解决方案1】:

    我假设您使用的是 C++,但如果您使用的是 C 或 Python,答案应该是相同的。

    函数minAreaRect似乎给出的角度范围是-90到0度,不包括零,所以区间是[-90, 0)。

    如果它输出的矩形没有旋转,该函数给出 -90 度,即矩形有两条完全水平的边和两条完全垂直的边。随着矩形顺时针旋转,角度增加(趋向于零)。当达到零时,函数给出的角度再次回到 -90 度。

    因此,如果您有一个来自minAreaRect 的长矩形,并且它平躺,minAreaRect 将调用角度 -90 度。如果您旋转图像直到minAreaRect 给出的矩形完全直立,那么角度将再次显示-90 度。

    我实际上对此一无所知(我拖延了我的 OpenCV 项目以了解它是如何工作的:/)。无论如何,如果我解释得不够清楚,这里有一个演示 minAreaRect 的 OpenCV 程序:

    #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 对同一矩形的解释的比较。

    【讨论】:

    • 老兄,你是一个严肃的宝石。谢谢:)
    • 没问题 :) OpenCV 的文档似乎遗漏了很多重要的细节
    • 再问一个问题,如果它只给出介于 -90,-1 之间的天使,我怎么能从 rotaterect 获得 0-360 度的变换?是的,当您深入研究代码或其示例时,opencv 在文档方面可能会更好
    • 好吧,OpenCV 无法自行解决这个问题。如果不确切知道你在做什么,很难说,但我采取的方法是在你的对象上获得一个朝向一侧的特征点。然后,当您从minAreaRect 获取矩形时,您可以看到该点在矩形中的位置,并使用它来计算对象的方向。
    • 好的,谢谢,可能我得按你说的去做
    【解决方案2】:

    改进@Adam Goodwin 的答案,我想添加我的小代码来稍微改变行为:

    我想要长边和垂直之间的角度(对我来说,这是考虑旋转矩形的最自然的方式):

    如果您需要相同的,只需使用以下代码:

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

    要查看它的实际效果,只需将其插入 Adam Goodwins 代码:

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

    【讨论】:

    • 如果我想检查我的 360 度旋转矩形。我们该怎么做。因为您当前的代码将使用 0-180 度垂直。有什么提示吗?
    【解决方案3】:

    经过大量实验,我发现minAreaRect()的矩形方向和输出角度之间的关系。可以概括为下图

    以下描述假设我们有一个长宽不相等的矩形,即它不是正方形。

    如果矩形垂直放置(宽度

    如果矩形的顶部在第一象限,则检测到的角度随着矩形从水平位置旋转到垂直位置而减小,直到检测到的角度变为-90度。在第一象限,检测到的矩形的宽度大于其高度。

    如果检测到的矩形的顶部位于第二象限,则角度会随着矩形从垂直位置旋转到水平位置而减小。 但是第二象限和第一象限是有区别的。如果矩形接近垂直位置但尚未处于垂直位置,则其角度接近0。如果矩形接近水平位置但尚未处于水平位置,则其角度接近-90度

    here这个帖子也很好解释。

    【讨论】:

      【解决方案4】:

      经过实验,我发现如果长边在底点的左边,角度值在长边和Y+轴之间,但是如果长边在底点的右边,角度值位于长边和 X+ 轴之间。 所以我使用这样的代码(java):

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

      角度从0到180。

      【讨论】:

        【解决方案5】:

        这取决于 opencv 的版本,至少对于 Python 而言。

        对于 opencv-python='4.5.4.60'。该角度是正 x 轴与轴逆时针旋转时遇到的第一条线之间的角度。以下是sn-p的代码。

        import cv2
        import numpy as np
        
        box1 = [[0, 0], [1, 0], [1, 2], [0, 2]]
        cv2.minAreaRect(np.asarray(box1))  # angel = 90.0
        
        box2 = [[0, 0], [2, 0], [2, 1], [0, 1]]
        cv2.minAreaRect(np.asarray(box2))  # angel = 90.0
        
        box3 = [[0, 0], [2**0.5, 2**0.5], [0.5*2**0.5, 1.5*2**0.5], [-0.5*2**0.5, 0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box3, dtype=np.float32))  # angle = 44.999
        
        box4 = [[0, 0], [-2**0.5, 2**0.5], [-0.5*2**0.5, 1.5*2**0.5], [0.5*2**0.5, 0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box4, dtype=np.float32))  # angle = 45.0
        
        box5 = [[0, 0], [-0.5*2**0.5, 0.5*2**0.5], [-2**0.5, 0], [-0.5*2**0.5, -0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box5, dtype=np.float32))  # angle = 45.0
        

        对于 opencv-python='3.4.13.47'。该角度是正 x 轴和轴顺时针旋转时遇到的第一条线之间的角度。以下是sn-p的代码。

        import cv2
        import numpy as np
        
        box1 = [[0, 0], [1, 0], [1, 2], [0, 2]]
        cv2.minAreaRect(np.asarray(box1))  # angel = -90.0
        
        box2 = [[0, 0], [2, 0], [2, 1], [0, 1]]
        cv2.minAreaRect(np.asarray(box2))  # angel = -90.0
        
        box3 = [[0, 0], [2**0.5, 2**0.5], [0.5*2**0.5, 1.5*2**0.5], [-0.5*2**0.5, 0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box3, dtype=np.float32))  # angle = -44.999
        
        box4 = [[0, 0], [-2**0.5, 2**0.5], [-0.5*2**0.5, 1.5*2**0.5], [0.5*2**0.5, 0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box4, dtype=np.float32))  # angle = -45.0
        
        box5 = [[0, 0], [-0.5*2**0.5, 0.5*2**0.5], [-2**0.5, 0], [-0.5*2**0.5, -0.5*2**0.5]]
        cv2.minAreaRect(np.asarray(box5, dtype=np.float32))  # angle = -45.0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-09
          • 2022-01-19
          • 2020-02-25
          • 2019-08-17
          • 2016-03-20
          • 1970-01-01
          • 2021-07-13
          • 1970-01-01
          相关资源
          最近更新 更多