mkfallah commited on
Commit
4a85778
·
verified ·
1 Parent(s): 88dd3f5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -0
app.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import mediapipe as mp
4
+ import numpy as np
5
+
6
+ # Initialize MediaPipe once (better performance than creating per-frame)
7
+ mp_hands = mp.solutions.hands
8
+ mp_pose = mp.solutions.pose
9
+ mp_drawing = mp.solutions.drawing_utils
10
+
11
+ hands = mp_hands.Hands(
12
+ static_image_mode=False,
13
+ max_num_hands=2,
14
+ min_detection_confidence=0.5,
15
+ min_tracking_confidence=0.5
16
+ )
17
+
18
+ pose = mp_pose.Pose(
19
+ static_image_mode=False,
20
+ model_complexity=1, # 0 for fastest, 1 is a good balance
21
+ enable_segmentation=False,
22
+ min_detection_confidence=0.5,
23
+ min_tracking_confidence=0.5
24
+ )
25
+
26
+ def process_frame(frame, target_width, return_original_size):
27
+ """
28
+ frame: BGR numpy array from webcam (gradio provides RGB -> but gr.Image returns RGB by default)
29
+ We'll handle color conversions explicitly.
30
+ """
31
+ if frame is None:
32
+ return None
33
+
34
+ # Gradio's Image provides RGB ndarray; convert to BGR for OpenCV ops if needed
35
+ rgb_in = frame # already RGB
36
+ h0, w0 = rgb_in.shape[:2]
37
+
38
+ # Compute resize keeping aspect ratio
39
+ target_width = max(160, int(target_width))
40
+ scale = target_width / float(w0)
41
+ target_height = int(round(h0 * scale))
42
+
43
+ # Resize for processing
44
+ rgb_small = cv2.resize(rgb_in, (target_width, target_height), interpolation=cv2.INTER_AREA)
45
+
46
+ # Run MediaPipe on resized frame
47
+ # (MediaPipe expects RGB)
48
+ hand_results = hands.process(rgb_small)
49
+ pose_results = pose.process(rgb_small)
50
+
51
+ # Convert to BGR for drawing (MediaPipe drawing utils expect BGR or RGB? They draw on the array directly; we’ll use BGR for OpenCV compatibility)
52
+ bgr_draw = cv2.cvtColor(rgb_small, cv2.COLOR_RGB2BGR)
53
+
54
+ # Draw hands
55
+ if hand_results.multi_hand_landmarks:
56
+ for hand_landmarks in hand_results.multi_hand_landmarks:
57
+ mp_drawing.draw_landmarks(bgr_draw, hand_landmarks, mp_hands.HAND_CONNECTIONS)
58
+
59
+ # Draw pose
60
+ if pose_results.pose_landmarks:
61
+ mp_drawing.draw_landmarks(bgr_draw, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
62
+
63
+ # Convert back to RGB for Gradio
64
+ rgb_out_small = cv2.cvtColor(bgr_draw, cv2.COLOR_BGR2RGB)
65
+
66
+ if return_original_size:
67
+ # Upscale back to original frame size
68
+ rgb_out = cv2.resize(rgb_out_small, (w0, h0), interpolation=cv2.INTER_LINEAR)
69
+ return rgb_out
70
+ else:
71
+ return rgb_out_small
72
+
73
+ with gr.Blocks(title="Live Hand & Body Pose Detection") as demo:
74
+ gr.Markdown("# Live Hand & Body Pose Detection")
75
+ gr.Markdown("Upload from webcam; frames are resized before processing for better performance.")
76
+
77
+ with gr.Row():
78
+ cam = gr.Image(
79
+ source="webcam",
80
+ streaming=True,
81
+ label="Webcam",
82
+ )
83
+ out = gr.Image(label="Processed", streaming=True)
84
+
85
+ with gr.Row():
86
+ target_width = gr.Slider(
87
+ minimum=160, maximum=1280, value=640, step=20,
88
+ label="Processing width (px)"
89
+ )
90
+ return_original = gr.Checkbox(
91
+ value=False, label="Return at original webcam resolution"
92
+ )
93
+
94
+ # Live streaming
95
+ cam.stream(fn=process_frame, inputs=[cam, target_width, return_original], outputs=out)
96
+
97
+ if __name__ == "__main__":
98
+ # queue for backpressure; single worker avoids MP thread issues
99
+ demo.queue(concurrency_count=1).launch()