Ask Your Question
1

How to determine the angle of rotation?

asked 2018-12-20 12:55:19 -0500

There is a square in an image with equal sides (that is inside another square).

image description

Does OpenCV have functions which can help to efficiently calculate the angle?

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
3

answered 2018-12-20 13:07:01 -0500

updated 2018-12-20 14:01:58 -0500

you can use minAreaRect() function that returns a RotatedRect having angle

you can test the code below

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    Mat src, gray;
    src = imread("e:/test/rr.jpg");
    if (src.empty())
        return -1;

    cvtColor(src, gray, COLOR_BGR2GRAY);
    gray = gray > 100;
    imshow("gray", gray);
    vector<vector<Point> > contours;

    findContours(gray.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    RotatedRect _minAreaRect;

    for (size_t i = 0; i < contours.size(); ++i)
    {
        _minAreaRect = minAreaRect(contours[i]);
        Point2f pts[4];
        _minAreaRect.points(pts);

        cout << "minAreaRect.angle: " << _minAreaRect.angle << endl;

        for (int j = 0; j < 4; j++)
           line(src, pts[j], pts[(j + 1) % 4], Scalar(0, 0, 255), 1, LINE_AA);
    }
    imshow("result", src);
    waitKey(0);
    return 0;
}

also see the code below (adopted from the code on stackoverflow)

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

//! Compute the distance between two points
/*! Compute the Euclidean distance between two points
*
* @Param a Point a
* @Param b Point b
*/
static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b)
{
    double xDiff = a.x - b.x;
    double yDiff = a.y - b.y;

    return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}

int main(int argc, char** argv)
{
    Mat src, gray;
    src = imread(argv[1]);
    if (src.empty())
        return -1;

    cvtColor(src, gray, COLOR_BGR2GRAY);
    gray = gray > 100;
    imshow("gray", gray);
    vector<vector<Point> > contours;

    findContours(gray.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    RotatedRect _minAreaRect;

    for (size_t i = 0; i < contours.size(); ++i)
    {
        _minAreaRect = minAreaRect(contours[i]);
        Point2f pts[4];
        _minAreaRect.points(pts);

        double dist0 = distanceBtwPoints(pts[0], pts[1]);
        double dist1 = distanceBtwPoints(pts[1], pts[2]);

        double angle = 0;
     //   if (dist0 > dist1 * 4)
            angle = atan2(pts[0].y - pts[1].y, pts[0].x - pts[1].x) * 180.0 / CV_PI;
       // if (dist1 > dist0 * 4)
       //     angle = atan2(pts[1].y - pts[2].y, pts[1].x - pts[2].x) * 180.0 / CV_PI;

        cout << "minAreaRect.angle: " << _minAreaRect.angle << endl;
        cout << "angle: " << angle;

        for (int j = 0; j < 4; j++)
           line(src, pts[j], pts[(j + 1) % 4], Scalar(0, 0, 255), 1, LINE_AA);
    }
    imshow("result", src);
    waitKey(0);
    return 0;
}
edit flag offensive delete link more

Comments

Sounds good. Thanks.

ya_ocv_user gravatar imageya_ocv_user ( 2018-12-20 13:28:14 -0500 )edit

Just so it's clear, the slope of a line is defined as rise (change in y) over run (change in x). The arctan(rise/run) function returns the angle in radians. Multiplying that radians by 180 divided by pi gives you the angle in degrees. That is, if the rise over run equals 1, then the angle returned is 45 degrees.

sjhalayka gravatar imagesjhalayka ( 2018-12-21 13:41:47 -0500 )edit

is there a Python solution for this?

Raki gravatar imageRaki ( 2019-02-04 09:15:23 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2018-12-20 12:55:19 -0500

Seen: 150 times

Last updated: Dec 20 '18