Pratyush101 commited on
Commit
df8ec21
·
verified ·
1 Parent(s): a472ccb

Update app.py

Browse files

Add the squat detection code

Files changed (1) hide show
  1. app.py +281 -174
app.py CHANGED
@@ -1,191 +1,298 @@
1
- import logging
2
- import queue
3
- from pathlib import Path
4
- from typing import List, NamedTuple
5
- import mediapipe as mp
6
- import av
7
- import cv2
8
- import numpy as np
9
- import streamlit as st
10
- from streamlit_webrtc import WebRtcMode, webrtc_streamer
11
- from sample_utils.turn import get_ice_servers
12
- from cvzone.HandTrackingModule import HandDetector
13
- from cvzone.SelfiSegmentationModule import SelfiSegmentation
14
- import time
15
- import os
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
- st.title("Interactive Virtual Keyboard with Twilio Integration")
20
- st.info("Use your webcam to interact with the virtual keyboard via hand gestures.")
21
-
22
- class Button:
23
- def __init__(self, pos, text, size=[100, 100]):
24
- self.pos = pos
25
- self.size = size
26
- self.text = text
27
-
28
- # Initialize components
29
- detector = HandDetector(maxHands=1, detectionCon=0.8)
30
- # segmentor = SelfiSegmentation()
31
- # keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
32
- # ["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],
33
- # ["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
34
 
35
- # listImg = os.listdir('model/street')
36
- # imgList = [cv2.imread(f'model/street/{imgPath}') for imgPath in listImg]
37
- # indexImg = 0
38
 
 
 
39
 
40
- # # Function to process the video frame from the webcam
41
- # def process_video_frame(frame, detector, segmentor, imgList, indexImg, keys, session_state):
42
- # # Convert the frame to a numpy array (BGR format)
43
- # image = frame.to_ndarray(format="bgr24")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
- # # Remove background using SelfiSegmentation
46
- # imgOut = segmentor.removeBG(image, imgList[indexImg])
47
 
48
- # # Detect hands on the background-removed image
49
- # hands, img = detector.findHands(imgOut, flipType=False)
50
 
51
- # # Create a blank canvas for the keyboard
52
- # keyboard_canvas = np.zeros_like(img)
53
- # buttonList = []
54
-
55
- # # Create buttons for the virtual keyboard based on the keys list
56
- # for key in keys[0]:
57
- # buttonList.append(Button([30 + keys[0].index(key) * 105, 30], key))
58
- # for key in keys[1]:
59
- # buttonList.append(Button([30 + keys[1].index(key) * 105, 150], key))
60
- # for key in keys[2]:
61
- # buttonList.append(Button([30 + keys[2].index(key) * 105, 260], key))
62
-
63
- # # Draw the buttons on the keyboard canvas
64
- # for button in buttonList:
65
- # x, y = button.pos
66
- # cv2.rectangle(keyboard_canvas, (x, y), (x + button.size[0], y + button.size[1]), (255, 255, 255), -1)
67
- # cv2.putText(keyboard_canvas, button.text, (x + 20, y + 70), cv2.FONT_HERSHEY_PLAIN, 5, (0, 0, 0), 3)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- # # Handle input and gestures from detected hands
70
- # if hands:
71
- # for hand in hands:
72
- # lmList = hand["lmList"]
73
- # if lmList:
74
- # # Get the coordinates of the index finger tip (landmark 8)
75
- # x8, y8 = lmList[8][0], lmList[8][1]
76
- # for button in buttonList:
77
- # bx, by = button.pos
78
- # bw, bh = button.size
79
- # # Check if the index finger is over a button
80
- # if bx < x8 < bx + bw and by < y8 < by + bh:
81
- # # Highlight the button and update the text
82
- # cv2.rectangle(img, (bx, by), (bx + bw, by + bh), (0, 255, 0), -1)
83
- # cv2.putText(img, button.text, (bx + 20, by + 70), cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255), 3)
84
- # # Update the output text in session_state
85
- # session_state["output_text"] += button.text
86
-
87
- # # Corrected return: Create a video frame from the ndarray image
88
- # return av.VideoFrame.from_ndarray(img, format="bgr24")
89
-
90
-
91
-
92
-
93
-
94
-
95
- # Shared state for output text
96
- if "output_text" not in st.session_state:
97
- st.session_state["output_text"] = ""
98
-
99
- class Detection(NamedTuple):
100
- label: str
101
- score: float
102
- box: np.ndarray
103
-
104
-
105
- @st.cache_resource # Cache label colors
106
- def generate_label_colors():
107
- return np.random.uniform(0, 255, size=(2, 3)) # Two classes: Left and Right Hand
108
-
109
-
110
- COLORS = generate_label_colors()
111
-
112
- # Initialize MediaPipe Hands
113
- mp_hands = mp.solutions.hands
114
- detector = mp_hands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5)
115
-
116
- # Session-specific caching
117
- result_queue: "queue.Queue[List[Detection]]" = queue.Queue()
118
-
119
- # Hand detection callback
120
- def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
121
- image = frame.to_ndarray(format="bgr24")
122
- h, w = image.shape[:2]
123
-
124
- # Process image with MediaPipe Hands
125
- results = detector.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
126
-
127
- detections = []
128
- if results.multi_hand_landmarks:
129
- for hand_landmarks, hand_class in zip(results.multi_hand_landmarks, results.multi_handedness):
130
- # Extract bounding box
131
- x_min, y_min = 1, 1
132
- x_max, y_max = 0, 0
133
- for lm in hand_landmarks.landmark:
134
- x_min = min(x_min, lm.x)
135
- y_min = min(y_min, lm.y)
136
- x_max = max(x_max, lm.x)
137
- y_max = max(y_max, lm.y)
138
-
139
- # Scale bbox to image size
140
- box = np.array([x_min * w, y_min * h, x_max * w, y_max * h]).astype("int")
141
-
142
- # Label and score
143
- label = hand_class.classification[0].label
144
- score = hand_class.classification[0].score
145
-
146
- detections.append(Detection(label=label, score=score, box=box))
147
-
148
- # Draw bounding box and label
149
- color = COLORS[0 if label == "Left" else 1]
150
- cv2.rectangle(image, (box[0], box[1]), (box[2], box[3]), color, 2)
151
- caption = f"{label}: {round(score * 100, 2)}%"
152
- cv2.putText(
153
- image,
154
- caption,
155
- (box[0], box[1] - 15 if box[1] - 15 > 15 else box[1] + 15),
156
- cv2.FONT_HERSHEY_SIMPLEX,
157
- 0.5,
158
- color,
159
- 2,
160
- )
161
-
162
- # Put results in the queue
163
- result_queue.put(detections)
164
-
165
- return av.VideoFrame.from_ndarray(image, format="bgr24")
166
 
 
 
 
167
 
168
 
169
- webrtc_ctx = webrtc_streamer(
170
- key="keyboard-demo",
171
- mode=WebRtcMode.SENDRECV,
172
- rtc_configuration={
173
- "iceServers": get_ice_servers(),
174
- "iceTransportPolicy": "relay",
175
- },
176
- video_frame_callback=video_frame_callback,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  media_stream_constraints={"video": True, "audio": False},
178
- async_processing=True,
179
  )
180
 
181
 
182
- st.markdown("### Instructions")
183
- st.write(
184
- """
185
- 1. Turn on your webcam using the checkbox above.
186
- 2. Use hand gestures to interact with the virtual keyboard.
187
- """
188
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
 
191
 
 
1
+ # import logging
2
+ # import queue
3
+ # from pathlib import Path
4
+ # from typing import List, NamedTuple
5
+ # import mediapipe as mp
6
+ # import av
7
+ # import cv2
8
+ # import numpy as np
9
+ # import streamlit as st
10
+ # from streamlit_webrtc import WebRtcMode, webrtc_streamer
11
+ # from sample_utils.turn import get_ice_servers
12
+ # from cvzone.HandTrackingModule import HandDetector
13
+ # from cvzone.SelfiSegmentationModule import SelfiSegmentation
14
+ # import time
15
+ # import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ # logger = logging.getLogger(__name__)
 
 
18
 
19
+ # st.title("Interactive Virtual Keyboard with Twilio Integration")
20
+ # st.info("Use your webcam to interact with the virtual keyboard via hand gestures.")
21
 
22
+ # class Button:
23
+ # def __init__(self, pos, text, size=[100, 100]):
24
+ # self.pos = pos
25
+ # self.size = size
26
+ # self.text = text
27
+
28
+ # # Initialize components
29
+ # detector = HandDetector(maxHands=1, detectionCon=0.8)
30
+ # # segmentor = SelfiSegmentation()
31
+ # # keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
32
+ # # ["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],
33
+ # # ["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
34
+
35
+ # # listImg = os.listdir('model/street')
36
+ # # imgList = [cv2.imread(f'model/street/{imgPath}') for imgPath in listImg]
37
+ # # indexImg = 0
38
+
39
+
40
+ # # # Function to process the video frame from the webcam
41
+ # # def process_video_frame(frame, detector, segmentor, imgList, indexImg, keys, session_state):
42
+ # # # Convert the frame to a numpy array (BGR format)
43
+ # # image = frame.to_ndarray(format="bgr24")
44
 
45
+ # # # Remove background using SelfiSegmentation
46
+ # # imgOut = segmentor.removeBG(image, imgList[indexImg])
47
 
48
+ # # # Detect hands on the background-removed image
49
+ # # hands, img = detector.findHands(imgOut, flipType=False)
50
 
51
+ # # # Create a blank canvas for the keyboard
52
+ # # keyboard_canvas = np.zeros_like(img)
53
+ # # buttonList = []
54
+
55
+ # # # Create buttons for the virtual keyboard based on the keys list
56
+ # # for key in keys[0]:
57
+ # # buttonList.append(Button([30 + keys[0].index(key) * 105, 30], key))
58
+ # # for key in keys[1]:
59
+ # # buttonList.append(Button([30 + keys[1].index(key) * 105, 150], key))
60
+ # # for key in keys[2]:
61
+ # # buttonList.append(Button([30 + keys[2].index(key) * 105, 260], key))
62
+
63
+ # # # Draw the buttons on the keyboard canvas
64
+ # # for button in buttonList:
65
+ # # x, y = button.pos
66
+ # # cv2.rectangle(keyboard_canvas, (x, y), (x + button.size[0], y + button.size[1]), (255, 255, 255), -1)
67
+ # # cv2.putText(keyboard_canvas, button.text, (x + 20, y + 70), cv2.FONT_HERSHEY_PLAIN, 5, (0, 0, 0), 3)
68
+
69
+ # # # Handle input and gestures from detected hands
70
+ # # if hands:
71
+ # # for hand in hands:
72
+ # # lmList = hand["lmList"]
73
+ # # if lmList:
74
+ # # # Get the coordinates of the index finger tip (landmark 8)
75
+ # # x8, y8 = lmList[8][0], lmList[8][1]
76
+ # # for button in buttonList:
77
+ # # bx, by = button.pos
78
+ # # bw, bh = button.size
79
+ # # # Check if the index finger is over a button
80
+ # # if bx < x8 < bx + bw and by < y8 < by + bh:
81
+ # # # Highlight the button and update the text
82
+ # # cv2.rectangle(img, (bx, by), (bx + bw, by + bh), (0, 255, 0), -1)
83
+ # # cv2.putText(img, button.text, (bx + 20, by + 70), cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255), 3)
84
+ # # # Update the output text in session_state
85
+ # # session_state["output_text"] += button.text
86
+
87
+ # # # Corrected return: Create a video frame from the ndarray image
88
+ # # return av.VideoFrame.from_ndarray(img, format="bgr24")
89
+
90
+
91
+
92
+
93
+
94
+
95
+ # # Shared state for output text
96
+ # if "output_text" not in st.session_state:
97
+ # st.session_state["output_text"] = ""
98
+
99
+ # class Detection(NamedTuple):
100
+ # label: str
101
+ # score: float
102
+ # box: np.ndarray
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
+ # @st.cache_resource # Cache label colors
106
+ # def generate_label_colors():
107
+ # return np.random.uniform(0, 255, size=(2, 3)) # Two classes: Left and Right Hand
108
 
109
 
110
+ # COLORS = generate_label_colors()
111
+
112
+ # # Initialize MediaPipe Hands
113
+ # mp_hands = mp.solutions.hands
114
+ # detector = mp_hands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5)
115
+
116
+ # # Session-specific caching
117
+ # result_queue: "queue.Queue[List[Detection]]" = queue.Queue()
118
+
119
+ # # Hand detection callback
120
+ # def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
121
+ # image = frame.to_ndarray(format="bgr24")
122
+ # h, w = image.shape[:2]
123
+
124
+ # # Process image with MediaPipe Hands
125
+ # results = detector.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
126
+
127
+ # detections = []
128
+ # if results.multi_hand_landmarks:
129
+ # for hand_landmarks, hand_class in zip(results.multi_hand_landmarks, results.multi_handedness):
130
+ # # Extract bounding box
131
+ # x_min, y_min = 1, 1
132
+ # x_max, y_max = 0, 0
133
+ # for lm in hand_landmarks.landmark:
134
+ # x_min = min(x_min, lm.x)
135
+ # y_min = min(y_min, lm.y)
136
+ # x_max = max(x_max, lm.x)
137
+ # y_max = max(y_max, lm.y)
138
+
139
+ # # Scale bbox to image size
140
+ # box = np.array([x_min * w, y_min * h, x_max * w, y_max * h]).astype("int")
141
+
142
+ # # Label and score
143
+ # label = hand_class.classification[0].label
144
+ # score = hand_class.classification[0].score
145
+
146
+ # detections.append(Detection(label=label, score=score, box=box))
147
+
148
+ # # Draw bounding box and label
149
+ # color = COLORS[0 if label == "Left" else 1]
150
+ # cv2.rectangle(image, (box[0], box[1]), (box[2], box[3]), color, 2)
151
+ # caption = f"{label}: {round(score * 100, 2)}%"
152
+ # cv2.putText(
153
+ # image,
154
+ # caption,
155
+ # (box[0], box[1] - 15 if box[1] - 15 > 15 else box[1] + 15),
156
+ # cv2.FONT_HERSHEY_SIMPLEX,
157
+ # 0.5,
158
+ # color,
159
+ # 2,
160
+ # )
161
+
162
+ # # Put results in the queue
163
+ # result_queue.put(detections)
164
+
165
+ # return av.VideoFrame.from_ndarray(image, format="bgr24")
166
+
167
+
168
+
169
+ # webrtc_ctx = webrtc_streamer(
170
+ # key="keyboard-demo",
171
+ # mode=WebRtcMode.SENDRECV,
172
+ # rtc_configuration={
173
+ # "iceServers": get_ice_servers(),
174
+ # "iceTransportPolicy": "relay",
175
+ # },
176
+ # video_frame_callback=video_frame_callback,
177
+ # media_stream_constraints={"video": True, "audio": False},
178
+ # async_processing=True,
179
+ # )
180
+
181
+
182
+ # st.markdown("### Instructions")
183
+ # st.write(
184
+ # """
185
+ # 1. Turn on your webcam using the checkbox above.
186
+ # 2. Use hand gestures to interact with the virtual keyboard.
187
+ # """
188
+ # )
189
+
190
+ import cv2
191
+ import mediapipe as mp
192
+ import numpy as np
193
+ import streamlit as st
194
+ from streamlit_webrtc import webrtc_streamer
195
+
196
+ # Initialize MediaPipe Pose
197
+ mp_pose = mp.solutions.pose
198
+ mp_drawing = mp.solutions.drawing_utils
199
+
200
+ # Function to calculate angles between three points
201
+ def calculate_angle(a, b, c):
202
+ a = np.array(a) # First point
203
+ b = np.array(b) # Midpoint
204
+ c = np.array(c) # Endpoint
205
+ radians = np.arctan2(c[1]-b[1], c[0]-b[0]) - np.arctan2(a[1]-b[1], a[0]-b[0])
206
+ angle = np.abs(radians * 180.0 / np.pi)
207
+ if angle > 180.0:
208
+ angle = 360 - angle
209
+ return angle
210
+
211
+ # Squat detection processor class
212
+ class VideoProcessor:
213
+ def __init__(self):
214
+ self.pose = mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5)
215
+
216
+ def recv(self, frame):
217
+ image = frame.to_ndarray(format="bgr24")
218
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
219
+ image.flags.writeable = False
220
+ results = self.pose.process(image)
221
+ image.flags.writeable = True
222
+ image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
223
+
224
+ try:
225
+ landmarks = results.pose_landmarks.landmark
226
+ hip = [landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x,
227
+ landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y]
228
+ knee = [landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].x,
229
+ landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].y]
230
+ ankle = [landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].x,
231
+ landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].y]
232
+ shoulder = [landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x,
233
+ landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y]
234
+ foot_index = [landmarks[mp_pose.PoseLandmark.LEFT_FOOT_INDEX.value].x,
235
+ landmarks[mp_pose.PoseLandmark.LEFT_FOOT_INDEX.value].y]
236
+ x_axis_hip = [hip[0], 0]
237
+
238
+ angle_knee = calculate_angle(hip, knee, ankle)
239
+ angle_ankle = calculate_angle(foot_index, ankle, knee)
240
+ angle_hip = calculate_angle(shoulder, hip, x_axis_hip)
241
+
242
+ feedback = ""
243
+ if 80 < angle_knee < 110 and 29 < angle_hip < 40:
244
+ feedback = "Good Squat!"
245
+ elif angle_knee < 80:
246
+ feedback = "Squat too deep!"
247
+ elif angle_knee > 110:
248
+ feedback = "Lower your hips!"
249
+ elif angle_hip < 29:
250
+ feedback = "Bend Forward!"
251
+ elif angle_hip > 45:
252
+ feedback = "Bend Backward!"
253
+
254
+ cv2.putText(image, feedback, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)
255
+ mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
256
+ except Exception as e:
257
+ print(f"Error: {e}")
258
+
259
+ return frame.from_ndarray(image, format="bgr24")
260
+
261
+ # Streamlit WebRTC configuration
262
+ webrtc_streamer(
263
+ key="squat_detector",
264
+ video_processor_factory=VideoProcessor,
265
  media_stream_constraints={"video": True, "audio": False},
266
+ rtc_configuration={"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]},
267
  )
268
 
269
 
270
+
271
+
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+
285
+
286
+
287
+
288
+
289
+
290
+
291
+
292
+
293
+
294
+
295
+
296
 
297
 
298