Mathematicaljuice commited on
Commit
04fcb4d
·
verified ·
1 Parent(s): 7bae6bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -111
app.py CHANGED
@@ -1,5 +1,7 @@
1
  import cv2
2
- import mediapipe.python.solutions.hands as mp_hands
 
 
3
  import numpy as np
4
  import torch
5
  import torch.nn as nn
@@ -9,31 +11,12 @@ import gradio as gr
9
  # Labels
10
  # ----------------------------
11
  GESTURE_LABELS = {
12
- 0: "A",
13
- 1: "B",
14
- 2: "L",
15
- 3: "U",
16
- 4: "V",
17
- 5: "W",
18
- 6: "Z",
19
- 7: "F",
20
- 8: "five",
21
- 9: "one",
22
- 10: "three",
23
- 11: "two",
24
- 12: "six",
25
- 13: "seven",
26
- 14: "eight",
27
- 15: "nine",
28
- 16: "ten",
29
- 17: "E",
30
- 18: "four",
31
- 19: "i",
32
- 20: "k",
33
- 21: "r",
34
- 22: "zero",
35
- 23: "m",
36
- 24: "s"
37
  }
38
 
39
  CONF_THRESHOLD = 0.6
@@ -44,128 +27,84 @@ CONF_THRESHOLD = 0.6
44
  class GestureNet(nn.Module):
45
  def __init__(self, input_size=126, num_classes=len(GESTURE_LABELS)):
46
  super().__init__()
47
-
48
  self.fc1 = nn.Linear(input_size, 256)
49
  self.fc2 = nn.Linear(256, 128)
50
  self.fc3 = nn.Linear(128, num_classes)
51
-
52
  self.relu = nn.ReLU()
53
  self.dropout = nn.Dropout(0.3)
54
 
55
  def forward(self, x):
56
  x = self.relu(self.fc1(x))
57
  x = self.dropout(x)
58
-
59
  x = self.relu(self.fc2(x))
60
  x = self.dropout(x)
 
61
 
62
- x = self.fc3(x)
63
-
64
- return x
65
-
66
- # ----------------------------
67
- # Load Model
68
- # ----------------------------
69
  model = GestureNet()
70
-
71
- model.load_state_dict(
72
- torch.load(
73
- "gesture_model1.pth",
74
- map_location=torch.device("cpu")
75
- )
76
- )
77
-
78
  model.eval()
79
 
80
  # ----------------------------
81
- # Prediction Function
82
  # ----------------------------
83
- def predict(image):
84
-
85
- if image is None:
86
- return "No image uploaded"
87
-
88
- # Convert RGB
89
- image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
90
-
91
- # MediaPipe Hands
92
- with mp_hands.Hands(
93
- static_image_mode=True,
94
- max_num_hands=2,
95
- min_detection_confidence=0.5
96
- ) as hands:
97
-
98
- results = hands.process(image_rgb)
99
-
100
  coords = []
101
 
102
- # Extract landmarks
103
- if results.multi_hand_landmarks:
104
-
105
- for hand_landmarks in results.multi_hand_landmarks:
106
-
107
- hand_coords = np.array([
108
- [lm.x, lm.y, lm.z]
109
- for lm in hand_landmarks.landmark
110
- ])
111
-
112
- # Normalize
113
  hand_coords -= hand_coords[0]
114
-
115
- max_val = np.max(
116
- np.linalg.norm(hand_coords, axis=1)
117
- )
118
-
119
  if max_val > 0:
120
  hand_coords /= max_val
121
-
122
  coords.extend(hand_coords.flatten())
123
 
124
- # Pad / truncate
125
  if len(coords) < 126:
126
  coords.extend([0.0] * (126 - len(coords)))
127
-
128
  elif len(coords) > 126:
129
  coords = coords[:126]
 
130
 
131
- # Predict
132
- input_tensor = torch.tensor(
133
- coords,
134
- dtype=torch.float32
135
- ).unsqueeze(0)
136
-
137
- with torch.no_grad():
138
-
139
- outputs = model(input_tensor)
140
-
141
- probs = torch.softmax(outputs, dim=1)
142
-
143
- probs = probs.numpy()[0]
144
-
145
- pred_class = np.argmax(probs)
146
-
147
- confidence = probs[pred_class]
148
-
149
- if confidence >= CONF_THRESHOLD:
150
-
151
- label = GESTURE_LABELS[pred_class]
152
-
153
- return f"{label} ({confidence * 100:.2f}%)"
154
-
155
  return "Unknown"
156
 
157
  # ----------------------------
158
- # Gradio Interface
159
  # ----------------------------
160
  app = gr.Interface(
161
  fn=predict,
162
  inputs=gr.Image(type="numpy"),
163
  outputs="text",
164
  title="Hand Gesture Recognition",
165
- description="Upload a hand gesture image"
166
  )
167
 
168
- # ----------------------------
169
- # Launch
170
- # ----------------------------
171
- app.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import cv2
2
+ import mediapipe as mp
3
+ from mediapipe.tasks.python import vision
4
+ from mediapipe.tasks.python import BaseOptions
5
  import numpy as np
6
  import torch
7
  import torch.nn as nn
 
11
  # Labels
12
  # ----------------------------
13
  GESTURE_LABELS = {
14
+ 0: "A", 1: "B", 2: "L", 3: "U", 4: "V", 5: "W",
15
+ 6: "Z", 7: "F", 8: "five", 9: "one", 10: "three",
16
+ 11: "two", 12: "six", 13: "seven", 14: "eight",
17
+ 15: "nine", 16: "ten", 17: "E", 18: "four",
18
+ 19: "i", 20: "k", 21: "r", 22: "zero",
19
+ 23: "m", 24: "s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
  CONF_THRESHOLD = 0.6
 
27
  class GestureNet(nn.Module):
28
  def __init__(self, input_size=126, num_classes=len(GESTURE_LABELS)):
29
  super().__init__()
 
30
  self.fc1 = nn.Linear(input_size, 256)
31
  self.fc2 = nn.Linear(256, 128)
32
  self.fc3 = nn.Linear(128, num_classes)
 
33
  self.relu = nn.ReLU()
34
  self.dropout = nn.Dropout(0.3)
35
 
36
  def forward(self, x):
37
  x = self.relu(self.fc1(x))
38
  x = self.dropout(x)
 
39
  x = self.relu(self.fc2(x))
40
  x = self.dropout(x)
41
+ return self.fc3(x)
42
 
 
 
 
 
 
 
 
43
  model = GestureNet()
44
+ model.load_state_dict(torch.load("gesture_model1.pth", map_location="cpu"))
 
 
 
 
 
 
 
45
  model.eval()
46
 
47
  # ----------------------------
48
+ # MediaPipe HandLandmarker
49
  # ----------------------------
50
+ # Initialize the HandLandmarker once for efficiency
51
+ model_path = "hand_landmarker.task" # You may need to download this file
52
+ # If you don't have the model file, uncomment the next line to download automatically:
53
+ # import urllib.request; urllib.request.urlretrieve("https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task", "hand_landmarker.task")
54
+
55
+ base_options = BaseOptions(model_asset_path=model_path)
56
+ options = vision.HandLandmarkerOptions(base_options=base_options, num_hands=2)
57
+ landmarker = vision.HandLandmarker.create_from_options(options)
58
+
59
+ def extract_hand_features(image_rgb):
60
+ """Extract normalized 63 landmarks (x,y,z) from up to 2 hands, returns flattened list of length 126."""
61
+ mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image_rgb)
62
+ detection_result = landmarker.detect(mp_image)
 
 
 
 
63
  coords = []
64
 
65
+ if detection_result.hand_landmarks:
66
+ for hand_landmarks in detection_result.hand_landmarks:
67
+ # Convert to numpy array of shape (21, 3)
68
+ hand_coords = np.array([[lm.x, lm.y, lm.z] for lm in hand_landmarks])
69
+ # Normalize: subtract wrist (index 0) and scale by max distance
 
 
 
 
 
 
70
  hand_coords -= hand_coords[0]
71
+ max_val = np.max(np.linalg.norm(hand_coords, axis=1))
 
 
 
 
72
  if max_val > 0:
73
  hand_coords /= max_val
 
74
  coords.extend(hand_coords.flatten())
75
 
76
+ # Pad or truncate to fixed length 126 (21*3*2)
77
  if len(coords) < 126:
78
  coords.extend([0.0] * (126 - len(coords)))
 
79
  elif len(coords) > 126:
80
  coords = coords[:126]
81
+ return coords
82
 
83
+ def predict(image):
84
+ # Convert BGR (Gradio default) to RGB
85
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
86
+ features = extract_hand_features(image_rgb)
87
+
88
+ if len(features) == 126:
89
+ input_tensor = torch.tensor(features, dtype=torch.float32).unsqueeze(0)
90
+ with torch.no_grad():
91
+ outputs = model(input_tensor)
92
+ probs = torch.softmax(outputs, dim=1).numpy()[0]
93
+ pred_class = np.argmax(probs)
94
+ confidence = probs[pred_class]
95
+ if confidence >= CONF_THRESHOLD:
96
+ return f"{GESTURE_LABELS[pred_class]} ({confidence*100:.2f}%)"
 
 
 
 
 
 
 
 
 
 
97
  return "Unknown"
98
 
99
  # ----------------------------
100
+ # Gradio UI
101
  # ----------------------------
102
  app = gr.Interface(
103
  fn=predict,
104
  inputs=gr.Image(type="numpy"),
105
  outputs="text",
106
  title="Hand Gesture Recognition",
107
+ description="Upload an image of a hand gesture"
108
  )
109
 
110
+ app.launch()