Reputation:
I would like to find the midpoint of a rotated rectangle. The rotated rectangle has got the following coordinate
[[317, 80], [183, 291], [479, 150], [378, 387]]
I have got the following code to determine
cx = (coord[0][0] + coord[2][0])//2
cy = (coord[0][1] + coord[1][1])//2
Unfortunately, the center doesn't correspond to the actual center. How do I find the exact center of the above coordinates?
Upvotes: 1
Views: 3371
Reputation: 5630
There are several issues.
1.) The points are not ordered correctly for your formula to work. I guess they should be ordered like: (points should be ordered such, that you have a line of the rectangle between two points that are adjacent in the list and the last and first entry in the list)
points = [[183, 291], [378, 387], [479, 150], [317, 80]]
2.) There is a mistake in your formula. (I guess the formula should be the one, that finds the mid point of a line or in this case the midpoint of a diagonal between point 0 and point 2).
It should be
cx = (coord[idx1][0] + coord[idx2][0]) / 2
cy = (coord[idx1][1] + coord[idx2][1]) / 2
where idx1, idx2 are either 0,2 or 1,3
For a rectangle cx, cy will be identical regardless of whether you use idx1=0, idx2=2 or idx1=1, idx2=3
3.) This formula (midpoint of a diagonal) determines the centroid only for rectangles. What you have is a quadrangle, which is almost, but not exactly a rectangle, so the formula does not apply at all.
Try to calculate cx, cy with idx1, idx2 = 0, 2 and with idx1, idx2 = 1, 3 and you see, that you get different results. Thus you do not have a rectangle.
Either there is a typo in the coordinates, that you posted, or perhaps there is an error in the formula that calculated your rectangle or your question really meant to calculate the centroid of a quadrangle, which is different. In that case it might be advisable to adapt the title of the question
You can find the formula for a polygon here https://en.wikipedia.org/wiki/Centroid#Of_a_polygon
Upvotes: 0
Reputation: 77837
The centroid of a rectangle is the midpoint of either diagonal. You used different point pairs for your two coordinate computations. Also note that, for some reason, the points are not in the usual, adjacent order. The diagonals are points 1 & 2, 0 & 3. Use either pair, such as:
# Variables to make the computations easier to read
pt1 = 1
pt2 = 2
x = 0
y = 1
cx = (coord[pt1][x] + coord[pt2][x])//2
cy = (coord[pt1][y] + coord[pt2][y])//2
Better yet, research some simple shape modules. Most of these will have a straightforward midpoint
method.
Upvotes: 2
Reputation: 5805
I’m not sure if I’m following you, man, but if you want to calculate the centroid of a rectangle shape, it goes like this. Suppose you have the following rectangle aligned to the origin. The centroid is shown in green.
The centroid is computed as:
Cx = 0.5 * w
Cy = 0.5 * h
You can then apply a linear transformation. In this example, a rotation matrix, which is given as:
R = [ cos ϴ, -sin ϴ
sin ϴ, cos ϴ ]
The rectangle is now rotated from the original coordinate system. That’s the angle ϴ:
The centroid equations become:
Cx’ = cx cos ϴ - cy sin ϴ
Cy’ = cx sin ϴ + cy cos ϴ
Translating back to the coordinate original system, we’ve got:
Cx’’ = x + cx cos ϴ - cy sin ϴ
Cy’’ = y + cx sin ϴ + cy cos ϴ
The function should be something like this (in pseudo-code):
Tuple computeRotatedCentroid( x, y, width, height, theta ) {
cx = 0.5 * width;
cy = 0.5 * height;
thetaRadians = degreesToRadians(theta);
cosTheta = cos( thetaRadians );
sinTheta = sin( thetaRadians );
finalCx = x + cx * cosTheta - cy * sinTheta;
finalCy = y + cx * sinTheta + cy * cosTheta;
return makeTuple( finalCx, finalCy );
}
Upvotes: 0
Reputation: 46600
You can find the midpoint of a rotated rectangle (the centroid) with cv2.minAreaRect
. The function returns the following information:
(centroid, (width, height), angle) = cv2.minAreaRect(cnts)
Here's a simple example. Input image:
Result with the centroid highlighted in green
Coordinates
(157.6988067626953, 132.07565307617188)
Code
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Find contours and find centroid information on rotated rectangle
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
centroid, dimensions, angle = cv2.minAreaRect(cnts[0])
cv2.circle(image, (int(centroid[0]), int(centroid[1])), 5, (36,255,12), -1)
print(centroid)
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
Upvotes: 0