Ankan Ghosh commited on
Commit
7ac41be
·
verified ·
1 Parent(s): 54d9add

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +166 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from streamlit_webrtc import webrtc_streamer, VideoProcessorBase
3
+ import av
4
+ import cv2
5
+ import mediapipe as mp
6
+ import numpy as np
7
+ import pyautogui
8
+
9
+ # Disable PyAutoGUI fail-safe
10
+ pyautogui.FAILSAFE = False
11
+
12
+
13
+ class HandMouseController(VideoProcessorBase):
14
+ def __init__(self):
15
+ # Initialize MediaPipe Hands with specific parameters
16
+ self.hands = mp.solutions.hands.Hands(
17
+ static_image_mode=False, max_num_hands=1, min_detection_confidence=0.7, min_tracking_confidence=0.7
18
+ )
19
+ self.drawing_utils = mp.solutions.drawing_utils
20
+
21
+ # Get the size of the screen
22
+ self.screen_width, self.screen_height = pyautogui.size()
23
+
24
+ # Variables to keep track of previous hand position
25
+ self.prev_y = None
26
+
27
+ # Feature toggles
28
+ self.enable_mouse_control = True
29
+ self.enable_scrolling = True
30
+
31
+ def recv(self, frame):
32
+ img = frame.to_ndarray(format="bgr24")
33
+ frame = cv2.flip(img, 1)
34
+ frame_height, frame_width, _ = frame.shape
35
+ rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
36
+ result = self.hands.process(rgb_frame)
37
+ hand_landmarks = result.multi_hand_landmarks
38
+
39
+ if hand_landmarks:
40
+ for hand_landmark in hand_landmarks:
41
+ self.drawing_utils.draw_landmarks(frame, hand_landmark, mp.solutions.hands.HAND_CONNECTIONS)
42
+ landmarks = hand_landmark.landmark
43
+
44
+ # Extract finger positions
45
+ finger_tips = [8, 12, 16, 20]
46
+ finger_mcp = [5, 9, 13, 17]
47
+ finger_states = []
48
+
49
+ for tip, mcp in zip(finger_tips, finger_mcp):
50
+ # Tip above MCP joint means finger is extended
51
+ if landmarks[tip].y < landmarks[mcp].y:
52
+ finger_states.append(1)
53
+ else:
54
+ finger_states.append(0)
55
+
56
+ # Check for Victory sign (Index and middle fingers extended)
57
+ if finger_states == [1, 1, 0, 0]:
58
+ gesture = "Victory"
59
+ # Check for Spider-Man sign (Index and little fingers extended)
60
+ elif finger_states == [1, 0, 0, 1]:
61
+ gesture = "Spider-Man"
62
+ else:
63
+ gesture = "None"
64
+
65
+ # Get index finger coordinates
66
+ index_finger_tip = landmarks[8]
67
+ x = int(index_finger_tip.x * frame_width)
68
+ y = int(index_finger_tip.y * frame_height)
69
+ index_x = self.screen_width / frame_width * x
70
+ index_y = self.screen_height / frame_height * y
71
+
72
+ # Mouse Control
73
+ if self.enable_mouse_control:
74
+ # Check for click gesture (thumb and index finger close together)
75
+ thumb_tip = landmarks[4]
76
+ thumb_x = int(thumb_tip.x * frame_width)
77
+ thumb_y = int(thumb_tip.y * frame_height)
78
+ thumb_index_distance = np.hypot(x - thumb_x, y - thumb_y)
79
+
80
+ if thumb_index_distance < 40:
81
+ # Click action
82
+ pyautogui.click()
83
+ pyautogui.sleep(1)
84
+ elif thumb_index_distance < 100:
85
+ # print("distance:", thumb_index_distance)
86
+ # Move cursor
87
+ pyautogui.moveTo(index_x, index_y)
88
+
89
+ # Scrolling Control
90
+ if self.enable_scrolling and gesture in ["Victory", "Spider-Man"]:
91
+ # Get current y position
92
+ current_y = landmarks[0].y # Use wrist position
93
+
94
+ if self.prev_y is not None:
95
+ delta_y = self.prev_y - current_y
96
+ scroll_amount = delta_y * 1000 # Adjust scroll sensitivity
97
+
98
+ if abs(scroll_amount) > 5:
99
+ pyautogui.scroll(int(scroll_amount))
100
+
101
+ self.prev_y = current_y
102
+ else:
103
+ self.prev_y = None
104
+
105
+ return av.VideoFrame.from_ndarray(frame, format="bgr24")
106
+
107
+
108
+ def main():
109
+ st.set_page_config(page_title="Virtual Mouse Controller", layout="wide")
110
+ st.title("Virtual Mouse Controller")
111
+
112
+ st.write(
113
+ """
114
+ Control your computer using hand gestures detected by your webcam.
115
+
116
+ ### Instructions:
117
+
118
+ - **Move Cursor** (:pinching_hand:): Hold your index finger up and move your hand to move the cursor.
119
+ - **Click** (:ok_hand:): Bring your thumb and index finger close together to click.
120
+ - **Scroll**:
121
+ - **Victory Sign** (:v:): Extend your index and middle fingers to enable scrolling.
122
+ - **Spider-Man Sign** (:the_horns:): Extend your index and little fingers to enable scrolling.
123
+ - Move your hand **up** or **down** to scroll.
124
+
125
+ **Note**: Ensure good lighting and keep your hand within the webcam's view.
126
+ """
127
+ )
128
+
129
+ st.sidebar.title("Settings")
130
+ enable_mouse = st.sidebar.checkbox("Enable Mouse Control", value=True)
131
+ enable_scroll = st.sidebar.checkbox("Enable Scrolling", value=True)
132
+
133
+ # Start the webcam stream with the HandMouseController
134
+ webrtc_ctx = webrtc_streamer(
135
+ key="hand-mouse",
136
+ video_processor_factory=HandMouseController,
137
+ media_stream_constraints={"video": True, "audio": False},
138
+ async_processing=True,
139
+ video_html_attrs={
140
+ "style": {"width": "1280px", "height": "720px"},
141
+ "controls": False,
142
+ "autoPlay": True,
143
+ },
144
+ )
145
+
146
+ if webrtc_ctx.video_processor:
147
+ webrtc_ctx.video_processor.enable_mouse_control = enable_mouse
148
+ webrtc_ctx.video_processor.enable_scrolling = enable_scroll
149
+
150
+ st.sidebar.markdown("---")
151
+ st.sidebar.markdown(
152
+ """
153
+ Developed with ❤️ by **OpenCV University**
154
+
155
+ **Tools:**
156
+
157
+ - OpenCV
158
+ - PyAutoGUI
159
+ - MediaPipe
160
+ - Streamlit
161
+ """
162
+ )
163
+
164
+
165
+ if __name__ == "__main__":
166
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ mediapipe==0.10.15
2
+ opencv-python==4.10.0.84
3
+ PyAutoGUI==0.9.54
4
+ streamlit==1.38.0
5
+ streamlit-webrtc==0.47.9