-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
244 lines (203 loc) · 8.79 KB
/
main.py
File metadata and controls
244 lines (203 loc) · 8.79 KB
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import cv2
import numpy as np
import pyautogui
from hand_tracker import HandTracker
from utils import fingers_up
import sys
import subprocess
import os
import webbrowser
# Configuration
HEADLESS_MODE = True # Set to True to run without showing the window (WORKS WHEN MINIMIZED!)
DEBUG_MODE = False # Show finger detection status (only works with window)
# Open Hand Gesture Configuration - URLs, Folders, and Apps to open
URLS = [
"https://github.com/Kush05Bhardwaj",
"https://chatgpt.com/",
"https://www.linkedin.com/in/kush2012bhardwaj",
"https://www.youtube.com",
"https://mail.google.com/mail/u/0/#inbox"
]
FOLDERS = [
r"F:"
]
APPS = [
"taskmgr", # Task Manager
"code", # VS Code (if in PATH)
]
# Camera settings
wCam, hCam = 640, 480
frameR = 100 # Frame reduction (border)
# Smoothing settings - higher = smoother but slower response
smoothening = 5 # Reduced for faster response (was 7)
# Previous and current locations
plocX, plocY = 0, 0
clocX, clocY = 0, 0
# Click debouncing
click_cooldown = 0
right_click_cooldown = 0
app_launch_cooldown = 0 # Cooldown for app launching
fist_counter = 0 # Count frames with fist to avoid accidental exit
# PyAutoGUI settings for smoother movement
pyautogui.FAILSAFE = False # Disable failsafe for smoother movement
pyautogui.PAUSE = 0 # Remove delay between PyAutoGUI calls
def launch_open_hand_actions():
"""Launch all URLs, open all folders, and start all apps when open hand is detected"""
success_count = 0
# Open all URLs
for url in URLS:
try:
webbrowser.open(url)
print(f"\n✅ Opened URL: {url}")
success_count += 1
except Exception as e:
print(f"\n❌ Failed to open URL {url}: {e}")
# Open all folders
for folder in FOLDERS:
try:
if os.path.exists(folder):
os.startfile(folder)
print(f"\n✅ Opened folder: {folder}")
success_count += 1
else:
print(f"\n⚠️ Folder not found: {folder}")
except Exception as e:
print(f"\n❌ Failed to open folder {folder}: {e}")
# Launch all apps
for app in APPS:
try:
subprocess.Popen(app, shell=True)
print(f"\n✅ Launched app: {app}")
success_count += 1
except Exception as e:
print(f"\n❌ Failed to launch app {app}: {e}")
return success_count > 0
cap = cv2.VideoCapture(0)
cap.set(3, wCam)
cap.set(4, hCam)
cap.set(cv2.CAP_PROP_FPS, 30) # Set FPS for smoother capture
tracker = HandTracker(detectionCon=0.8, trackCon=0.8) # Higher confidence for stability
wScr, hScr = pyautogui.size()
# Create window only if not in headless mode
if not HEADLESS_MODE:
cv2.namedWindow("Virtual Mouse", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Virtual Mouse", 640, 480)
print("Virtual Mouse Started! Press ESC or Q to exit.")
else:
print("Virtual Mouse Started in HEADLESS mode! Close terminal or make a fist to exit.")
print("Controls:")
print(" ☝️ Index finger only - Move cursor")
print(" 👆 Thumb + Index - Left click")
print(" 👉 Thumb + Middle - Right click")
print(" ✌️ Index + Middle - Scroll DOWN")
print(" 🖖 Middle + Ring - Scroll UP")
print(f" 🖐️ Open hand (all fingers) - Open {len(URLS)} URLs, {len(FOLDERS)} folders & {len(APPS)} apps")
print(" ✊ Fist - Exit")
while True:
success, img = cap.read()
if not success:
continue
img = cv2.flip(img, 1)
img = tracker.findHands(img)
lmList = tracker.findPosition(img)
# Draw boundary rectangle
cv2.rectangle(img, (frameR, frameR), (wCam - frameR, hCam - frameR), (255, 0, 255), 2)
if lmList:
fingers = fingers_up(lmList)
x1, y1 = lmList[8][1], lmList[8][2] # Index finger tip
# Debug: Show finger status in console if headless
if DEBUG_MODE and HEADLESS_MODE:
print(f"Fingers: {fingers}", end='\r')
# Debug: Show finger status on screen if window visible
if DEBUG_MODE and not HEADLESS_MODE:
finger_status = f"Fingers: {fingers}"
cv2.putText(img, finger_status, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2)
# 🖱️ Move Mouse (Index Finger only - thumb must be down!)
if fingers[1] == 1 and fingers[0] == 0 and fingers[2] == 0 and fingers[3] == 0 and fingers[4] == 0:
# Convert coordinates with boundary checking
x3 = np.interp(x1, (frameR, wCam-frameR), (0, wScr))
y3 = np.interp(y1, (frameR, hCam-frameR), (0, hScr))
# Exponential smoothing for better control
clocX = plocX + (x3 - plocX) / smoothening
clocY = plocY + (y3 - plocY) / smoothening
# Move mouse with duration=0 for instant movement (no flip needed - already flipped in image)
pyautogui.moveTo(clocX, clocY, duration=0)
if not HEADLESS_MODE:
cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
cv2.putText(img, "MOVING", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 2)
plocX, plocY = clocX, clocY
fist_counter = 0 # Reset fist counter when moving
# 👆 Left Click (with debouncing)
if fingers[1] and fingers[0] and click_cooldown == 0:
pyautogui.click()
click_cooldown = 10 # Cooldown frames
if not HEADLESS_MODE:
cv2.putText(img, "LEFT CLICK", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
fist_counter = 0 # Reset fist counter
# 👉 Right Click (with debouncing)
if fingers[2] and fingers[0] and not fingers[1] and right_click_cooldown == 0:
pyautogui.rightClick()
right_click_cooldown = 10 # Cooldown frames
if not HEADLESS_MODE:
cv2.putText(img, "RIGHT CLICK", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
fist_counter = 0 # Reset fist counter
# ✌️ Scroll Down (Index + Middle)
if fingers[1] and fingers[2] and not fingers[0] and not fingers[3]:
pyautogui.scroll(-40) # Negative = scroll down
if not HEADLESS_MODE:
cv2.putText(img, "SCROLL DOWN", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2)
fist_counter = 0 # Reset fist counter
# 🖖 Scroll Up (Middle + Ring)
elif fingers[2] and fingers[3] and not fingers[0] and not fingers[1]:
pyautogui.scroll(40) # Positive = scroll up
if not HEADLESS_MODE:
cv2.putText(img, "SCROLL UP", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
fist_counter = 0 # Reset fist counter
# 🖐️ Open Hand - Launch URLs & Folders (all 5 fingers up)
elif fingers == [1,1,1,1,1] and app_launch_cooldown == 0:
success = launch_open_hand_actions()
if success:
app_launch_cooldown = 60 # Cooldown for 2 seconds (60 frames)
if not HEADLESS_MODE:
cv2.putText(img, "OPENING URLS & FOLDERS", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
fist_counter = 0 # Reset fist counter
# ❌ Exit (Fist) - must hold for 30 frames to avoid accidental exit (about 1 second)
if fingers == [0,0,0,0,0]:
fist_counter += 1
if not HEADLESS_MODE:
cv2.putText(img, f"EXITING... {fist_counter}/30", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
else:
if fist_counter % 5 == 0: # Print every 5 frames
print(f"\rHold FIST to exit: {fist_counter}/30", end='', flush=True)
if fist_counter >= 30:
print("\nExiting...")
break
else:
fist_counter = 0 # Reset if not a fist
else:
# No hand detected - reset fist counter to prevent accidental exit
fist_counter = 0
# Decrease cooldown
if click_cooldown > 0:
click_cooldown -= 1
if right_click_cooldown > 0:
right_click_cooldown -= 1
if app_launch_cooldown > 0:
app_launch_cooldown -= 1
# Show mode indicator
cv2.putText(img, "Virtual Mouse Active", (10, hCam - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# Display the frame only if not in headless mode
if not HEADLESS_MODE:
cv2.imshow("Virtual Mouse", img)
# Non-blocking key check - works even when minimized
key = cv2.waitKey(1) & 0xFF
if key == 27: # ESC to exit
break
elif key == ord('q'): # Q to exit
break
else:
# In headless mode, just add a small delay to prevent CPU overload
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
print("\nVirtual Mouse stopped. Goodbye!")