I need help on how to detect the current angle of a shape based on another image of the same shape?
For example, lets say I take an image and after the usual image processing:
- Change to gray
- Apply threshold
(I am using ideal shapes drawn in paint, the objective is to detect physical objects but for simplicity lets assume this images)
I get this white shape image:
So now my new image is the following (without the red lines) which has moved 225 degrees.
How can I calculate the 225 degrees based on the original image orientation?
I have managed to get the following code working. But the angle wrt the original sample is something I can not figure out
As you can see, this position reports 45º but it should report 225º
The idea is to be able to do the same processing with this kind of shapes also:
This one should report 315º
# ------------------------------- FUNCTIONS -------------------------------------
def drawGrid(image):
print("Image size: " + str(result.shape)) # (700, 900, 3)
image_width = result.shape[1] # 900
image_height = result.shape[0] # 700
# https://www.geeksforgeeks.org/python-opencv-cv2-line-method/
number_lines = int(image_width / 100)
for x in range(number_lines):
# Start coordinate, here (0, 0)
# represents the top left corner of image
start_point = (100*x, 0) # x, y
# End coordinate, here (250, 250)
# represents the bottom right corner of image
end_point = (100*x, image_height - 10)
# Green color in BGR
color = (0, 255, 0)
# Line thickness of 9 px
thickness = 1
# Draw a diagonal green line with thickness of 9 px
image = cv2.line(result, start_point, end_point, color, thickness)
# Write line number
cv2.putText(result,str(x), (100*x,image_height - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0))
number_lines = int(image_height / 100)
for y in range(number_lines):
# Start coordinate, here (0, 0)
# represents the top left corner of image
start_point = (0, 100*y) # x, y
# End coordinate, here (250, 250)
# represents the bottom right corner of image
end_point = (image_width - 10, 100*y)
# Green color in BGR
color = (0, 255, 0)
# Line thickness of 9 px
thickness = 1
# Draw a diagonal green line with thickness of 9 px
image = cv2.line(result, start_point, end_point, color, thickness)
# Write line number
cv2.putText(result,str(y), (image_width - 10,100*y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0))
# resize image
def resizeImage(img):
scale_percent = 100 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
# resize image
resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
return resized
# ------------------------------- FUNCTIONS -------------------------------------
correct_area = 37621
# load image as HSV and select saturation
img = cv2.imread("images/sample225.png")
# img = resizeImage(img)
hh, ww, cc = img.shape
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
""""
# Show image and wait
cv2.imshow("img", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
"""
# threshold the grayscale image
ret, thresh = cv2.threshold(gray, 0, 255, 0)
# find outer contour
cntrs = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# select first contour, or if 2 contours are found, select the second one
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# Loop over the contours to count them
number_contours = 0
for c in cntrs:
number_contours += 1
print("Number of contours found: " + str(number_contours))
# Get rotated rectangle from outer contour
rotrect = cv2.minAreaRect(cntrs[0])
# print coordinates of box
print("Rectangle Box definition: ")
print(rotrect)
# Get external box of the contour points
box = cv2.boxPoints(rotrect)
box = np.int0(box)
print("Rectangle Box points: ")
print(box)
# draw rotated rectangle on copy of img as result
result = img.copy()
cv2.drawContours(result,[box],0,(0,0,255),2)
# get angle from rotated rectangle
angle = rotrect[-1]
print("Angle: " + str(angle))
# from https://www.pyimagesearch.com/2017/02/20/text-skew-correction-opencv-python/
# the `cv2.minAreaRect` function returns values in the
# range [-90, 0); as the rectangle rotates clockwise the
# returned angle trends to 0 -- in this special case we
# need to add 90 degrees to the angle
if angle < -45:
angle = -(90 + angle)
angle = round(angle,2)
print("Corrected angle: " + str(angle))
# Draw a grid to check coordinates visually
drawGrid(result)
# Get area of the contour
area = cv2.contourArea(box)
print ("Area: " + str(area))
# https://www.pyimagesearch.com/2016/02/01/opencv-center-of-contour/
# compute the center of the contour
# Find center position of the external contour box
M = cv2.moments(box)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
print("Box center x: " + str(cX))
print("Box center y: " + str(cY))
cv2.circle(result, (cX,cY), 3, (0,0,255), thickness=-1, lineType=8, shift=0)
boxX = cX
boxY = cY
# Find center position of the contour [0]
M = cv2.moments(cntrs[0])
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
print("Box center x: " + str(cX))
print("Box center y: " + str(cY))
cv2.circle(result, (cX,cY), 3, (0,255,0), thickness=-1, lineType=8, shift=0)
cntrsX = cX
cntrsY = cY
# Draw -centers- data on image
cv2.putText(result, "Center Box", (cX+30, cY-30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.putText(result, "Center Cnt", (cX+30, cY+30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0))
# draw axis
red_color = (0, 0, 255)
blue_color = (255, 0, 0)
center = cX, cY
print("center: " + str(center))
end_point = (cX+150, cY)
end_point2 = (cX, cY+150)
print("start_point:" + str(center))
print("end_point:" + str(end_point))
cv2.line(result, center, end_point, blue_color)
cv2.line(result, center, end_point2, blue_color)
# Draw information on top left
cv2.putText(result,"Angle: " + str(angle), (5,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.putText(result,"Pos: " + str(box), (5,100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.putText(result,"Number of contours: " + str(number_contours), (5,150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.putText(result,"Area: " + str(area), (5,200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
"""
if(area > correct_area*0.95 and area < correct_area*1.05):
cv2.putText(result, "OK", (1320, 100), cv2.FONT_HERSHEY_SIMPLEX, 4, (0, 255, 0), 10)
else:
cv2.putText(result, "NOK", (1230, 100), cv2.FONT_HERSHEY_SIMPLEX, 4, (0, 0, 255), 10)
"""
cv2.putText(result,"Center M box: " + str((boxX,boxY)), (5,250), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.putText(result,"Center M contour[0]: " + str((cntrsX,cntrsY)), (5,300), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0))
RestaX = boxX-cntrsX
RestaY = cntrsY-boxY
cv2.putText(result, "X Diff: " + str(RestaX), (5, 350), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255))
cv2.putText(result, "Y Diff: " + str(RestaY), (5, 400), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255))
# Calculate angle w.r.t original shape
cv2.putText(result, "Angle w.r.t original: " + str("???"), (5, 450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255))
""""
if(RestaX > 0 and RestaX != 0):
analysis_result = "Redondo en Derecha"
elif(RestaX < 0 and RestaX != 0):
analysis_result = "Redondo en Izquierda"
else:
analysis_result = "Redondo indeterminado"
cv2.putText(result, analysis_result, (5, 450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255))
"""
# Show image
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
If you run this code against this image, it should give you the result above.
Thanks for your help.