-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpurplependulum.py
98 lines (78 loc) · 3.24 KB
/
purplependulum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from collections import deque
from imutils.video import VideoStream
import numpy as np
import argparse
import cv2 as cv
import imutils
import time
from threading import Thread
from playsound import playsound
# Constants
RIGHT_CENTER_X_THRESHOLD = 280 # Adjust this value based on your video frame width
LEFT_CENTER_X_THRESHOLD = 320
DIST_THRESHOLD = 100 # Threshold for distance comparison
def play_sound():
playsound('Piano_C3.mp3')
# Construct argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="path to the (optional) video file")
ap.add_argument("-b", "--buffer", type=int, default=64, help="max buffer size")
args = vars(ap.parse_args())
# Lower and upper boundaries of the "purple" color in HSV color space
purpleLower = (140, 50, 50)
purpleUpper = (160, 255, 255)
pts = deque(maxlen=args["buffer"])
# Video path not supplied, grab reference to Webcam
if not args.get("video", False):
vs = VideoStream(src=0).start()
else:
vs = cv.VideoCapture(args["video"])
while True:
frame = vs.read() # Grab current frame
frame = frame[1] if args.get("video", False) else frame # Handle frame from VideoCapture or VideoStream
# Video ended or no frame received
if frame is None:
break
# Resize frame, blur it, and convert it to HSV
frame = imutils.resize(frame, width=600)
blurred = cv.GaussianBlur(frame, (11, 11), 0)
hsv = cv.cvtColor(blurred, cv.COLOR_BGR2HSV)
# Construct a mask for purple color, perform dilations and erosions to remove blobs
mask = cv.inRange(hsv, purpleLower, purpleUpper)
mask = cv.erode(mask, None, iterations=2)
mask = cv.dilate(mask, None, iterations=2)
# Find contours in the mask and initialize the current (x, y) center of the ball
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
center = None
# Proceed when a contour is found
if len(cnts) > 0:
c = max(cnts, key=cv.contourArea) # Find the largest contour in the mask
((x, y), radius) = cv.minEnclosingCircle(c) # Compute the minimum enclosing circle
M = cv.moments(c)
if M["m00"] != 0:
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])) # Centroid
if radius > 10:
cv.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 2)
cv.circle(frame, center, 5, (0, 0, 255), -1)
if center is not None:
frame_width = frame.shape[1]
middle_x = frame_width // 2
if center[0] > middle_x - RIGHT_CENTER_X_THRESHOLD and center[0] < middle_x + LEFT_CENTER_X_THRESHOLD:
sound_thread = Thread(target=play_sound)
sound_thread.start()
pts.appendleft(center)
for i in range(1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
continue
thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
cv.line(frame, pts[i - 1], pts[i], (0, 0, 255), thickness)
cv.imshow("Frame", frame)
key = cv.waitKey(1) & 0xFF
if key == ord("q"):
break
if not args.get("video", False):
vs.stop()
else:
vs.release()
cv.destroyAllWindows()