Last active
May 25, 2023 10:57
-
-
Save botforge/c88b842cafaa077a91048d51c2db0bdf to your computer and use it in GitHub Desktop.
Calculate & visualize the angle between two colored objects in a video stream using OpenCV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
USES OPENCV 4.10, PROBABLY WILL WORK FOR OPENCV 2.70 and up | |
REMEMBER TO CALCULATE THE HSV BOUNDS FOR color1 & color2, use the trackbar: | |
https://gist.github.com/botforge/c6559abd3c48bceb78c2664dcb53cef6 | |
to get these values | |
""" | |
import cv2 | |
import numpy as np | |
import math | |
def distance(x1, y1, x2, y2): | |
""" | |
Calculate distance between two points | |
""" | |
dist = math.sqrt(math.fabs(x2-x1)**2 + math.fabs(y2-y1)**2) | |
return dist | |
def find_color1(frame): | |
""" | |
Filter "frame" for HSV bounds for color1 (inplace, modifies frame) & return coordinates of the object with that color | |
""" | |
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) | |
hsv_lowerbound = np.array([139, 149, 131]) #replace THIS LINE w/ your hsv lowerb | |
hsv_upperbound = np.array([179, 255, 219])#replace THIS LINE w/ your hsv upperb | |
mask = cv2.inRange(hsv_frame, hsv_lowerbound, hsv_upperbound) | |
res = cv2.bitwise_and(frame, frame, mask=mask) #filter inplace | |
cnts, hir = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
if len(cnts) > 0: | |
maxcontour = max(cnts, key=cv2.contourArea) | |
#Find center of the contour | |
M = cv2.moments(maxcontour) | |
if M['m00'] > 0 and cv2.contourArea(maxcontour) > 1000: | |
cx = int(M['m10']/M['m00']) | |
cy = int(M['m01']/M['m00']) | |
return (cx, cy), True | |
else: | |
return (700, 700), False #faraway point | |
else: | |
return (700, 700), False #faraway point | |
def find_color2(frame): | |
""" | |
Filter "frame" for HSV bounds for color1 (inplace, modifies frame) & return coordinates of the object with that color | |
""" | |
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) | |
hsv_lowerbound = np.array([101, 152, 92])#replace THIS LINE w/ your hsv lowerb | |
hsv_upperbound = np.array([149, 255, 243])#replace THIS LINE w/ your hsv upperb | |
mask = cv2.inRange(hsv_frame, hsv_lowerbound, hsv_upperbound) | |
res = cv2.bitwise_and(frame, frame, mask=mask) | |
cnts, hir = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
if len(cnts) > 0: | |
maxcontour = max(cnts, key=cv2.contourArea) | |
#Find center of the contour | |
M = cv2.moments(maxcontour) | |
if M['m00'] > 0 and cv2.contourArea(maxcontour) > 2000: | |
cx = int(M['m10']/M['m00']) | |
cy = int(M['m01']/M['m00']) | |
return (cx, cy), True #True | |
else: | |
return (700, 700), True #faraway point | |
else: | |
return (700, 700), True #faraway point | |
cap = cv2.VideoCapture(0) | |
while(1): | |
_, orig_frame = cap.read() | |
#we'll be inplace modifying frames, so save a copy | |
copy_frame = orig_frame.copy() | |
(color1_x, color1_y), found_color1 = find_color1(copy_frame) | |
(color2_x, color2_y), found_color2 = find_color2(copy_frame) | |
#draw circles around these objects | |
cv2.circle(copy_frame, (color1_x, color1_y), 20, (255, 0, 0), -1) | |
cv2.circle(copy_frame, (color2_x, color2_y), 20, (0, 128, 255), -1) | |
if found_color1 and found_color2: | |
#trig stuff to get the line | |
hypotenuse = distance(color1_x, color1_x, color2_x, color2_y) | |
horizontal = distance(color1_x, color1_y, color2_x, color1_y) | |
vertical = distance(color2_x, color2_y, color2_x, color1_y) | |
angle = np.arcsin(vertical/hypotenuse)*180.0/math.pi | |
#draw all 3 lines | |
cv2.line(copy_frame, (color1_x, color1_y), (color2_x, color2_y), (0, 0, 255), 2) | |
cv2.line(copy_frame, (color1_x, color1_y), (color2_x, color1_y), (0, 0, 255), 2) | |
cv2.line(copy_frame, (color2_x, color2_y), (color2_x, color1_y), (0, 0, 255), 2) | |
#put angle text (allow for calculations upto 180 degrees) | |
angle_text = "" | |
if color2_y < color1_y and color2_x > color1_x: | |
angle_text = str(int(angle)) | |
elif color2_y < color1_y and color2_x < color1_x: | |
angle_text = str(int(180 - angle)) | |
elif color2_y > color1_y and color2_x < color1_x: | |
angle_text = str(int(180 + angle)) | |
elif color2_y > color1_y and color2_x > color1_x: | |
angle_text = str(int(360 - angle)) | |
#CHANGE FONT HERE | |
cv2.putText(copy_frame, angle_text, (color1_x-30, color1_y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 128, 229), 2) | |
cv2.imshow('AngleCalc', copy_frame) | |
cv2.waitKey(5) | |
cap.release() | |
cv2.destroyAllWindows() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello .. This is giving error .. can you please help.
C:\Users\XPS\PycharmProjects\FaceMesh1\venv\Scripts\python.exe "C:/Users/XPS/PycharmProjects/FaceMesh1/orientation 2.py"
Error processing line 1 of C:\Users\XPS\PycharmProjects\FaceMesh1\venv\lib\site-packages\vision-1.0.0-py3.10-nspkg.pth:
Traceback (most recent call last):
File "C:\Users\XPS\AppData\Local\Programs\Python\Python310\lib\site.py", line 186, in addpackage
exec(line)
File "", line 1, in
File "", line 568, in module_from_spec
AttributeError: 'NoneType' object has no attribute 'loader'
Remainder of file ignored
Error processing line 1 of C:\Users\XPS\PycharmProjects\FaceMesh1\venv\lib\site-packages\vision-1.0.0-py3.10-nspkg.pth:
Traceback (most recent call last):
File "C:\Users\XPS\AppData\Local\Programs\Python\Python310\lib\site.py", line 186, in addpackage
exec(line)
File "", line 1, in
File "", line 568, in module_from_spec
AttributeError: 'NoneType' object has no attribute 'loader'
Remainder of file ignored
[ WARN:[email protected]] global D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (539) `anonymous-namespace'::SourceReaderCB::~SourceReaderCB terminating async callback
Traceback (most recent call last):
File "C:\Users\XPS\PycharmProjects\FaceMesh1\orientation 2.py", line 67, in
cap = cv2.VideoCapture(1)
KeyboardInterrupt
Process finished with exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)