Mathematicaljuice commited on
Commit
236535c
·
verified ·
1 Parent(s): dc79c99

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -28
app.py CHANGED
@@ -4,6 +4,8 @@ import numpy as np
4
  import torch
5
  import torch.nn as nn
6
  import gradio as gr
 
 
7
 
8
  # ----------------------------
9
  # Labels
@@ -45,18 +47,13 @@ model.eval()
45
  # MediaPipe
46
  # ----------------------------
47
  mp_hands = mp.solutions.hands
 
 
48
 
49
  # ----------------------------
50
- # Predict
51
  # ----------------------------
52
- def predict(image):
53
- # Gradio sends RGB, convert to BGR for OpenCV then back to RGB for MediaPipe
54
- image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
55
- image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
56
-
57
- with mp_hands.Hands(static_image_mode=True, max_num_hands=2) as hands:
58
- results = hands.process(image_rgb)
59
-
60
  coords = []
61
  if results.multi_hand_landmarks:
62
  for hand_landmarks in results.multi_hand_landmarks:
@@ -66,32 +63,144 @@ def predict(image):
66
  if max_val > 0:
67
  hand_coords /= max_val
68
  coords.extend(hand_coords.flatten())
 
 
69
 
 
 
70
  if len(coords) < 126:
71
- coords.extend([0.0] * (126 - len(coords)))
72
  elif len(coords) > 126:
73
  coords = coords[:126]
74
 
75
- if len(coords) == 126:
76
- input_tensor = torch.tensor(coords, dtype=torch.float32).unsqueeze(0)
77
- with torch.no_grad():
78
- outputs = model(input_tensor)
79
- probs = torch.softmax(outputs, dim=1)
80
- pred_class = torch.argmax(probs, dim=1).item()
81
- confidence = probs[0][pred_class].item()
82
- if confidence >= CONF_THRESHOLD:
83
- return f"{GESTURE_LABELS[pred_class]} ({confidence*100:.2f}%)"
 
84
 
85
- return "Unknown"
86
 
87
  # ----------------------------
88
- # Gradio UI
89
  # ----------------------------
90
- app = gr.Interface(
91
- fn=predict,
92
- inputs=gr.Image(type="numpy"),
93
- outputs="text",
94
- title="Hand Gesture Recognition",
95
- description="Upload an image of a hand gesture to recognize it."
96
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  app.launch()
 
4
  import torch
5
  import torch.nn as nn
6
  import gradio as gr
7
+ import tempfile
8
+ import os
9
 
10
  # ----------------------------
11
  # Labels
 
47
  # MediaPipe
48
  # ----------------------------
49
  mp_hands = mp.solutions.hands
50
+ mp_drawing = mp.solutions.drawing_utils
51
+ mp_drawing_styles = mp.solutions.drawing_styles
52
 
53
  # ----------------------------
54
+ # Core landmark extraction + prediction
55
  # ----------------------------
56
+ def extract_coords(results):
 
 
 
 
 
 
 
57
  coords = []
58
  if results.multi_hand_landmarks:
59
  for hand_landmarks in results.multi_hand_landmarks:
 
63
  if max_val > 0:
64
  hand_coords /= max_val
65
  coords.extend(hand_coords.flatten())
66
+ return coords
67
+
68
 
69
+ def run_model(coords):
70
+ """Return (label, confidence) or ('Unknown', 0.0)."""
71
  if len(coords) < 126:
72
+ coords = coords + [0.0] * (126 - len(coords))
73
  elif len(coords) > 126:
74
  coords = coords[:126]
75
 
76
+ input_tensor = torch.tensor(coords, dtype=torch.float32).unsqueeze(0)
77
+ with torch.no_grad():
78
+ outputs = model(input_tensor)
79
+ probs = torch.softmax(outputs, dim=1)
80
+ pred_class = torch.argmax(probs, dim=1).item()
81
+ confidence = probs[0][pred_class].item()
82
+
83
+ if confidence >= CONF_THRESHOLD:
84
+ return GESTURE_LABELS[pred_class], confidence
85
+ return "Unknown", confidence
86
 
 
87
 
88
  # ----------------------------
89
+ # Image prediction
90
  # ----------------------------
91
+ def predict_image(image):
92
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
93
+ image_rgb = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2RGB)
94
+
95
+ with mp_hands.Hands(static_image_mode=True, max_num_hands=2) as hands:
96
+ results = hands.process(image_rgb)
97
+
98
+ coords = extract_coords(results)
99
+ if not coords:
100
+ return "No hand detected"
101
+
102
+ label, conf = run_model(coords)
103
+ return f"{label} ({conf*100:.2f}%)"
104
+
105
+
106
+ # ----------------------------
107
+ # Video prediction
108
+ # ----------------------------
109
+ def predict_video(video_path):
110
+ if video_path is None:
111
+ return None
112
+
113
+ cap = cv2.VideoCapture(video_path)
114
+ if not cap.isOpened():
115
+ return None
116
+
117
+ fps = cap.get(cv2.CAP_PROP_FPS) or 25
118
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
119
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
120
+
121
+ # Write to a temp file that Gradio can serve
122
+ tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
123
+ out_path = tmp.name
124
+ tmp.close()
125
+
126
+ fourcc = cv2.VideoWriter_fourcc(*"mp4v")
127
+ writer = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
128
+
129
+ with mp_hands.Hands(
130
+ static_image_mode=False,
131
+ max_num_hands=2,
132
+ min_detection_confidence=0.5,
133
+ min_tracking_confidence=0.5,
134
+ ) as hands:
135
+ while True:
136
+ ret, frame = cap.read()
137
+ if not ret:
138
+ break
139
+
140
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
141
+ results = hands.process(frame_rgb)
142
+
143
+ # Draw landmarks
144
+ if results.multi_hand_landmarks:
145
+ for hand_landmarks in results.multi_hand_landmarks:
146
+ mp_drawing.draw_landmarks(
147
+ frame,
148
+ hand_landmarks,
149
+ mp_hands.HAND_CONNECTIONS,
150
+ mp_drawing_styles.get_default_hand_landmarks_style(),
151
+ mp_drawing_styles.get_default_hand_connections_style(),
152
+ )
153
+
154
+ # Predict and overlay label
155
+ coords = extract_coords(results)
156
+ if coords:
157
+ label, conf = run_model(coords)
158
+ text = f"{label} ({conf*100:.1f}%)"
159
+ color = (0, 220, 0) if label != "Unknown" else (0, 0, 220)
160
+ else:
161
+ text = "No hand detected"
162
+ color = (180, 180, 180)
163
+
164
+ cv2.putText(
165
+ frame, text,
166
+ (20, 50),
167
+ cv2.FONT_HERSHEY_SIMPLEX,
168
+ 1.4, color, 3, cv2.LINE_AA,
169
+ )
170
+
171
+ writer.write(frame)
172
+
173
+ cap.release()
174
+ writer.release()
175
+ return out_path
176
+
177
+
178
+ # ----------------------------
179
+ # Gradio UI – two tabs
180
+ # ----------------------------
181
+ with gr.Blocks(title="Hand Gesture Recognition") as app:
182
+ gr.Markdown("# ✋ Hand Gesture Recognition")
183
+ gr.Markdown(
184
+ "Recognises **25 gestures** (A B E F L U V W Z i k m r s "
185
+ "zero one two three four five six seven eight nine ten)."
186
+ )
187
+
188
+ with gr.Tab("📷 Image"):
189
+ with gr.Row():
190
+ img_input = gr.Image(type="numpy", label="Upload image")
191
+ img_output = gr.Textbox(label="Prediction")
192
+ img_btn = gr.Button("Predict", variant="primary")
193
+ img_btn.click(predict_image, inputs=img_input, outputs=img_output)
194
+
195
+ with gr.Tab("🎬 Video"):
196
+ gr.Markdown(
197
+ "Upload a short video clip. Each frame is processed and the "
198
+ "predicted gesture is overlaid. Hand landmarks are drawn in real time."
199
+ )
200
+ with gr.Row():
201
+ vid_input = gr.Video(label="Upload video")
202
+ vid_output = gr.Video(label="Annotated output")
203
+ vid_btn = gr.Button("Predict", variant="primary")
204
+ vid_btn.click(predict_video, inputs=vid_input, outputs=vid_output)
205
+
206
  app.launch()