# How to determine the angle of rotation?

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

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

edit retag close merge delete

Sort by ยป oldest newest most voted

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

more

Sounds good. Thanks.

( 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.

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

is there a Python solution for this?

( 2019-02-04 09:15:23 -0500 )edit

Official site

GitHub

Wiki

Documentation