I’m trying to find the angle of rotation of an object (irregular shape, cannot share a picture. It looks sort of like a tree’s trunk, with a thinner base, two branches stemming from the lower middle (different sized branches) and a thicker top area). Currently my code is like this:
imgBlur = cv2.GaussianBlur(search_area, (7,7), 1)
imgGray = cv2.cvtColor(imgBlur, cv2.COLOR_BGR2GRAY)
img_canny = cv2.Canny(imgGray,threshold1, threshold2)
kernel = np.ones((5,5))
img_dilated = cv2.dilate(img_canny, kernel, iterations=1)
getContours(img_dilated, img_contour)
def getContours(img, imgContour):
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
perimeter = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
x,y,w,h = cv2.boundingRect(approx)
bounding_box_area = w*h
if bounding_box_area < 15000 and bounding_box_area > 150:
cv2.drawContours(imgContour, cnt, -1, (255, 0, 255), 2)
cv2.rectangle(imgContour, (x,y), (x+w, y+h), (0,255,0), 2)
[vx, vy, lx, ly] = cv2.fitLine(cnt, cv2.DIST_L2, 0, 0,.01, 0.01)
lefty = int((-lx*vy/vx) + ly)
righty = int(((img.shape[1]-lx)*vy/vx)+ly)
M = cv2.moments(cnt)
cx = cy = 0
if M['m00'] != 0:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(imgContour, (cx, cy), 3, (0, 0, 255), -1)
if lefty < 100000 and righty < 100000:
ret, p1, p2 = cv2.clipLine((x,y,w,h), (img.shape[1]-1,righty), (0,lefty))
cv2.line(imgContour,p1, p2,255,2)
So far I managed to get the contour, the bounding box, the centroid and the fit line, but I still cannot find the angle of rotation. I tried all sorts of methods (minAreaRect, angle between fit line and arbitrary axis…): the best I found is this
cnt = cnt.reshape(-1, 2).astype(np.float32)
cnt -= np.array([[cx, cy]])
mean, eigenvectors = cv2.PCACompute(cnt - np.array([[cx, cy]]), mean=None)
angle = np.arctan2(eigenvectors[0,1], eigenvectors[0,0]) * 180 / np.pi
if angle < 0:
angle += 360
but it has issues with some angles (jumping from 120 to 320, for example).