【问题标题】:How to correctly rotate irregular rectangle with OpenCV?如何使用 OpenCV 正确旋转不规则矩形?
【发布时间】:2017-04-10 18:50:55
【问题描述】:

我正在尝试像这样旋转一个不规则的矩形:

Example

为了把它放直。我的轮廓是 cv::vector 类型,转换后我得到一个 cv::vector 类型,以便进行一些精确的计算。

因此,我还需要一种很好的方法来进行这种旋转,所以首先我需要检测侧面。我试过使用'minarearect',但结果一点都不好。边界矩形不匹配不规则矩形方向与足够的精度。

是否有任何“最佳周长矩形”或类似的,而不是“最小面积矩形”?我认为这会给我更多的准确性。 但是,您知道旋转矩形的其他方法吗?

请原谅我的英语。感谢您的帮助!

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    您可以使用 PCA 获取矩形方向(第一个和第二个组件)的边,通过这些轴方向,您可以计算旋转角度。此处示例:http://docs.opencv.org/3.1.0/d1/dee/tutorial_introduction_to_pca.html

    刚刚画了另一个变种的草图:

    #include <iostream>
    #include <vector>
    #include "opencv2/opencv.hpp"
    using namespace std;
    using namespace cv;
    
    //-----------------------------------------------------------------------------------------------------
    //
    //-----------------------------------------------------------------------------------------------------
    void getSamplePoints(Mat& src,vector<Point2f>& pts)
    {
        pts.clear();
        for (int i = 0; i < src.rows; ++i)
        {
            for (int j = 0; j < src.cols; ++j)
            {
                uchar v = src.at<uchar>(i, j);
                if (v > 0)
                {
                    pts.push_back(Point2f(j, i));
                }
            }
        }
    }
    //-----------------------------------------------------------------------------------------------------
    //
    //-----------------------------------------------------------------------------------------------------
    double distance_to_Line(cv::Point2f line_start, cv::Point2f line_end, cv::Point2f point)
    {
        double normalLength = _hypot(line_end.x - line_start.x, line_end.y - line_start.y);
        double distance = (double)((point.x - line_start.x) * (line_end.y - line_start.y) - (point.y - line_start.y) * (line_end.x - line_start.x)) / normalLength;
        return distance;
    }
    //-----------------------------------------------------------------------------------------------------
    //
    //-----------------------------------------------------------------------------------------------------
    void getPointsFromVector(vector<Point2f>& pts,Point2f p1, Point2f p2, float dist, vector<Point2f>& pts_res)
    {
        for (int i = 0; i < pts.size(); ++i)
        {
            double d = distance_to_Line(p1, p2, pts[i]);
            if (fabs(d) < dist)
            {
                pts_res.push_back(pts[i]);
            }
        }
    }
    //-----------------------------------------------------------------------------------------------------
    //
    //-----------------------------------------------------------------------------------------------------
    int main(int argc, unsigned int** argv)
    {
        string fname = "../../data/rect_to_fit.png";
        Mat src = imread(fname, 1);
        if (src.empty())
        {
            return 0;
        }
        cvtColor(src, src, COLOR_BGR2GRAY);
    
        vector<Point2f> pts;
        getSamplePoints(src, pts);
    
    
        RotatedRect R = minAreaRect(pts);
        Point2f r_pts[4];
        R.points(r_pts);
    
        for (int j = 0; j < 4; j++)
        {
            vector<Point2f> res_pts;
            Point2f p1 = r_pts[j];
            Point2f p2 = r_pts[(j + 1) % 4];
            getPointsFromVector(pts,p1,p2,20, res_pts);
            for (auto p : res_pts)
            {
                circle(src, p, 3, Scalar::all(255), -1);
            }
          //  imshow("src", src);
          //  waitKey(0);
            Vec4f L;
            fitLine(res_pts, L, cv::DIST_L2, 0, 0.01, 0.01);
            float x = L[2];
            float y = L[3];
            float vx = L[0];
            float vy = L[1];
            float lefty = int((-x*vy / vx) + y);
            float righty = int(((src.cols - x)*vy / vx) + y);
            line(src, Point2f(src.cols - 1, righty), Point2f(0, lefty), Scalar::all(255), 2);
        }
    
        imshow("src", src);
        imwrite("result.jpg", src);
        waitKey(0);
    
        return 0;
    }
    

    我得到的结果:

    【讨论】:

    • 谢谢!我首先尝试使用 PCA。一旦我得到我的第一个结果,我会给你反馈!
    • PCA 给出点的最长分布方向,如果是正方形,它可能给出对角线方向。 PCA 适用于长方形或其他细长物体。对于方形的,您可能需要使用 RANSAC 方法。
    • PCA 没有给我任何好的方法,你可以在这里看到:example。我认为接近对角线也很糟糕......
    • 附加了我的草图,可以更好地解决它。它搜索边线,您可以从中找到旋转(通过平均平行边的角度为ex)。
    • 哇,太棒了!非常感谢,安德烈!
    猜你喜欢
    • 1970-01-01
    • 2021-02-27
    • 2013-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多