I’m attempting to measure the angle of a line from a camera, and I’m getting some pretty poor results when the line is near 45 degrees. When the line is between 39 and 52 degrees hough_line() thinks the line is exactly 45. Once the line gets a few degrees below or above that range hough_line() starts measuring the angle to within a couple degrees of true angle again.
Any idea why this is happening or how to better measure the angle of relatively short lines?
Here is some code I wrote to demonstrate the problem. Run it with LINE_LENGTH set to 75 and you’ll see significant error near 45 degrees; run it again with LINE_LENGTH set to 275 and the error near 45 is greatly reduced. I’ve tried rotating the image 20 degrees when the line is near the 45 degree mark and remeasuring the angle but the results are less than great.
import cv2
import numpy as np
from skimage.transform import (hough_line, hough_line_peaks)
blackFrame = np.zeros(shape=[600, 600, 3], dtype=np.uint8)
blackFrame = cv2.inRange(blackFrame, (125,125,125), (255,255,255))
ORIGIN = (300, 300)
LINE_LENGTH = 75 #275
LINE_COLOR = (255,255,255)
WINDOW_TITLE = "Line Angle Measurement Test"
def MeasureAngle(frame):
hspace, angles, distances = hough_line(frame)
angle=[]
for _, a , distances in zip(*hough_line_peaks(hspace, angles, distances)):
angle.append([_,a])
mainAngle = (0,0)
for segment in angle:
if segment[0] > mainAngle[0]:
mainAngle = segment
return mainAngle[1]
if __name__ == '__main__':
cv2.namedWindow(WINDOW_TITLE, cv2.WINDOW_NORMAL)
cv2.resizeWindow(WINDOW_TITLE, 600, 600)
cv2.moveWindow(WINDOW_TITLE, 0, 0)
for targetDegrees in range(0,90):
angle = targetDegrees*np.pi/180
lineEndpoint = (int(ORIGIN[0]+np.sin(angle)*LINE_LENGTH),
int(ORIGIN[1]-np.cos(angle)*LINE_LENGTH))
blackFrame = np.zeros(shape=[600, 600, 3], dtype=np.uint8)
blackFrame = cv2.inRange(blackFrame, (125,125,125), (255,255,255))
frameWithLine = cv2.line(blackFrame, ORIGIN, lineEndpoint, LINE_COLOR, 5)
angleRadians = MeasureAngle(frameWithLine)
angleDegrees = round(angleRadians*180/np.pi)
print(targetDegrees, angleDegrees, sep=":")
cv2.imshow(WINDOW_TITLE, frameWithLine)
cv2.waitKey(1)
cv2.destroyAllWindows()