SoFunction
Updated on 2024-10-30

Function Output Angle Problems in opencv Explained

preamble

Many examples on the Internet say that the function's output angle range in [-90,0], but the actual output range in [0,90]. Then research, identified as opencv4.5 version upgrade changes caused.

Input: the four points of the quadrilateral (no order required).

Output: coordinates of the center point of the smallest outer rectangle x,y, width and height w,h, angle anlge, output as tuple ((x,y),(w,h), anlge), order format unchanged.

1. Version 4.5

Version 4.5 defines that the first coincident edge of the clockwise rotation of the x-axis is w, angle is the angle of the clockwise rotation of the x-axis, and angle takes the value of (0,90].

cnts, _ = (mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
rect = (cnts[0])
box = np.int0((rect))
print(rect)

Output: ((201.25, 92.10), (20.93, 101.94), 67.47)

Center point coordinates: (201, 92), width and height: (20, 101), angle: 67.

Together with the rotate function, the box can be flattened. Rotate function (rotate counterclockwise):

import cv2
import numpy as np
 
def rotate(img, angle, center=None, scale=1.0, fill=0, interpolation=cv2.INTER_LINEAR, expand=True):
    if center is not None and expand:
        raise ValueError('`auto_bound` conflicts with `center`')
 
    h, w = [:2]
    if center is None:
        center = ((w - 1) * 0.5, (h - 1) * 0.5)
    assert isinstance(center, tuple)
 
    matrix = cv2.getRotationMatrix2D(center, angle, scale)
    if expand:
        cos = (matrix[0, 0])
        sin = (matrix[0, 1])
        new_w = h * sin + w * cos
        new_h = h * cos + w * sin
        matrix[0, 2] += (new_w - w) * 0.5
        matrix[1, 2] += (new_h - h) * 0.5
        w = int((new_w))
        h = int((new_h))
    rotated = (
        img,
        matrix, (w, h),
        flags=interpolation,
        borderValue=fill)
    return rotated

Perform a rotation:

rotate(img, -23, center=(201, 92), expand=False)

Results:

Perspective Description:

Angle is the value when the x-axis is rotated clockwise and the rectangular boundary is touched for the first time, range: 0~90°, the boundary of the first contact is wide, and the direction of differentiation can be determined using the values of width and height.

The angle is adjusted in counterclockwise rotation as:

if rect[1][0] > rect[1][1]: # w > h 
    angle = int(rect[2]) 
else: 
    angle = -(90 - int(rect[2]))

2. Versions prior to 4.5

Some users test 4.1.*, 4.2.*, 4.3.*, 4.4.* under the minAreaRect function are the same, that is, the common online angle output for [-90 ~ 0] case. But the actual test python version 4 series of the above 4.5 version of the situation, may be c++ version of the difference. Here to add [-90~0] case.

rect = (cnts[0])

rect[0] returns the center of the smallest outer rectangle, rect[1] is the width and height of the smallest outer rectangle. rect[2] is the rotation angle.

Width, height and angle are defined as follows: angle is the angle of rotation of the first edge encountered when the x-axis is rotated along the counterclockwise direction, because it is rotated counterclockwise so the angle is 0~-90 degrees. Conventions: the first edge encountered is the width, the other edge is the height.

Addendum: opencv ---minAreaRect() calculates the deflection angle and corrects the

  • The purpose of this experiment was to calculate the angle of deflection of the target image and to correct it without changing the image size of the
  • The minAreaRect() function and getRotationMatrix2D() function are mainly used here.
  • First a brief introduction to the minAreaRect () function, I stepped on some potholes here, here to explain, if there is something wrong, you can correct.

The function is minAreaRect(InputArray points), InputArray points is the required minimum outer rectangle of the set of points, the set of points is not a number.

This rectangle is allowed to have a deflection angle and can be non-parallel to the boundaries of the image.

Call form: RotatedRect minAreaRect(InputArray points)

  • Angle calculation rule: take the upper-left corner as the origin, rotate the X-axis counterclockwise, the first angle obtained is the rotation angle, and the first edge is the width of the smallest external rectangle. Angle range [-90, 0], when the smallest external rectangle is parallel (or perpendicular) to the X-axis, the angle is -90. (It has nothing to do with the length and width of the target image.)

clockwise is positive, counterclockwise is negative

  • function getRotationMatrix2D(Point2f center, double angle, double scale)

Parameter details:

Point2f center: the center point of the rotation.

double angle: the angle of rotation // here the angle clockwise is negative, counterclockwise is positive

double scale: image scaling factor

  • The pitfalls were mainly in the angle separation, which I summarized:

minAreaRect(): start from the positive direction of X-axis, clockwise is positive, counterclockwise is negative.

getRotationMatrix2D(): start from X axis positive direction, clockwise is negative, counterclockwise is positive.

Here is an example:

#include <iostream>
#include <string>
#include <>
#include <vector>
#include <>
#include <fstream>
#include <opencv2/>
#include <opencv2/core/>
#include <opencv2/highgui/>
 
using namespace cv;
using namespace std;
 
int main()
{  
	Mat image = imread("");  
	Mat gaussianimage,grayimage, cannyimage, thresholdimage;
 
//--------------------- rotates -----------------
	// Calculate the deflection angle
	GaussianBlur(image, gaussianimage, Size(5, 5), 3, 3);// Remove as many impurities as possible
	Canny(gaussianimage, cannyimage, 50, 150, 3);
	cvtColor(cannyimage, grayimage, CV_GRAY2BGR);
	vector<vector<Point>>vec_point;
	vector<Vec4i>hireachy;
	findContours(cannyimage, vec_point, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
 
	double degree = 0;
	for (size_t i = 0; i < vec_point.size(); i++)
	{
		RotatedRect minrect = minAreaRect(vec_point[i]);//minAreaRect(): start with X-axis square, clockwise is positive, counterclockwise is negative.
		degree = ;
		
        //The purpose here is to rotate the target image to a horizontal position
		if (degree > -90 && degree <= -45)
		{
			degree += 90;
		}
		else if (degree >-45 && degree < 0)
		{
			degree;
		}
		else
		{
			degree = 0;
		}		
		cout <<"degree:" << degree << endl;
	}	
 
	//Rotation correction
	Point center = Point( / 2,  / 2);
	double angle = degree;
	double scale = 1;
	Mat rot(2, 3, CV_32FC1);
	rot = getRotationMatrix2D(center, angle, scale);//getRotationMatrix2D(): start with X-axis square, clockwise is negative, counterclockwise is positive.
	Mat rotimage;
	warpAffine(image, rotimage, rot, ());
	namedWindow("rotation", 0);
	resizeWindow("rotation", 800, 600);
	imshow("rotation", rotimage);
}

Rendering:

summarize

to this article on the opencv function output angle of the problem is introduced to this article, more related opencv function output angle content please search for my previous articles or continue to browse the following related articles I hope you will support me in the future more!