Natwar commited on
Commit
83027cf
·
verified ·
1 Parent(s): e513d23

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +207 -0
app.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Install required dependencies
2
+ !pip install -q mediapipe tensorflow opencv-python-headless gradio Pillow numpy
3
+
4
+ import os
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ import cv2
8
+ import mediapipe as mp
9
+ import gradio as gr
10
+ from PIL import Image
11
+
12
+ # Hand Tracker class - using the provided implementation
13
+ class handTracker():
14
+ def __init__(self, mode=False, maxHands=2, modelComplexity=1,
15
+ detectionConfidence=0.5, trackConfidence=0.5):
16
+ self.mode = mode
17
+ self.maxHands = maxHands
18
+ self.modelComplexity = modelComplexity
19
+ self.detectionConfidence = detectionConfidence
20
+ self.trackConfidence = trackConfidence
21
+
22
+ self.mpHands = mp.solutions.hands
23
+ self.hands = self.mpHands.Hands(
24
+ static_image_mode=self.mode,
25
+ max_num_hands=self.maxHands,
26
+ model_complexity=self.modelComplexity,
27
+ min_detection_confidence=self.detectionConfidence,
28
+ min_tracking_confidence=self.trackConfidence)
29
+
30
+ self.mpDraw = mp.solutions.drawing_utils
31
+ self.mpDrawStyles = mp.solutions.drawing_styles
32
+
33
+ def findAndDrawHands(self, frame):
34
+ RGBimage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
35
+ self.results = self.hands.process(RGBimage)
36
+
37
+ if self.results.multi_hand_landmarks:
38
+ for handLms in self.results.multi_hand_landmarks:
39
+ self.mpDraw.draw_landmarks(
40
+ frame,
41
+ handLms,
42
+ self.mpHands.HAND_CONNECTIONS,
43
+ self.mpDrawStyles.get_default_hand_landmarks_style(),
44
+ self.mpDrawStyles.get_default_hand_connections_style())
45
+ return frame
46
+
47
+ def findLandmarks(self, frame, handNo=0):
48
+ landmarkList = []
49
+ x_list = []
50
+ y_list = []
51
+ bbox = []
52
+
53
+ if self.results.multi_hand_landmarks:
54
+ if handNo < len(self.results.multi_hand_landmarks):
55
+ myHand = self.results.multi_hand_landmarks[handNo]
56
+
57
+ for id, lm in enumerate(myHand.landmark):
58
+ h, w, c = frame.shape
59
+ cx, cy = int(lm.x * w), int(lm.y * h)
60
+ x_list.append(cx)
61
+ y_list.append(cy)
62
+ landmarkList.append([id, cx, cy])
63
+
64
+ if x_list and y_list:
65
+ xmin, xmax = min(x_list), max(x_list)
66
+ ymin, ymax = min(y_list), max(y_list)
67
+
68
+ padding = 20
69
+ xmin = max(0, xmin - padding)
70
+ ymin = max(0, ymin - padding)
71
+ boxW = min(w - xmin, xmax - xmin + 2*padding)
72
+ boxH = min(h - ymin, ymax - ymin + 2*padding)
73
+
74
+ if boxW > boxH:
75
+ diff = boxW - boxH
76
+ ymin = max(0, ymin - diff//2)
77
+ boxH = min(h - ymin, boxW)
78
+ elif boxH > boxW:
79
+ diff = boxH - boxW
80
+ xmin = max(0, xmin - diff//2)
81
+ boxW = min(w - xmin, boxH)
82
+
83
+ bbox = [xmin, ymin, boxW, boxH]
84
+ return landmarkList, bbox
85
+
86
+ # Model loading with compatibility handling
87
+ def load_model_with_compatibility(model_path):
88
+ try:
89
+ model = tf.keras.models.load_model(model_path)
90
+ print("✓ Model loaded successfully")
91
+ return model
92
+ except Exception as e:
93
+ print(f"Standard loading failed: {str(e)}")
94
+ try:
95
+ class CustomDepthwiseConv2D(tf.keras.layers.DepthwiseConv2D):
96
+ def __init__(self, **kwargs):
97
+ if 'groups' in kwargs:
98
+ del kwargs['groups']
99
+ super(CustomDepthwiseConv2D, self).__init__(**kwargs)
100
+
101
+ custom_objects = {'DepthwiseConv2D': CustomDepthwiseConv2D}
102
+ model = tf.keras.models.load_model(
103
+ model_path,
104
+ custom_objects=custom_objects,
105
+ compile=False
106
+ )
107
+ print("✓ Model loaded in compatibility mode")
108
+ return model
109
+ except Exception as e2:
110
+ print(f"Compatibility loading failed: {str(e2)}")
111
+ return create_simple_asl_model()
112
+
113
+ def create_simple_asl_model():
114
+ labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
115
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
116
+ 'T', 'U', 'V', 'W', 'X', 'Y']
117
+
118
+ print("Creating a new compatible model...")
119
+ model = tf.keras.Sequential([
120
+ tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
121
+ tf.keras.layers.MaxPooling2D((2, 2)),
122
+ tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
123
+ tf.keras.layers.MaxPooling2D((2, 2)),
124
+ tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
125
+ tf.keras.layers.Flatten(),
126
+ tf.keras.layers.Dense(128, activation='relu'),
127
+ tf.keras.layers.Dropout(0.5),
128
+ tf.keras.layers.Dense(len(labels), activation='softmax')
129
+ ])
130
+ model.compile(optimizer='adam',
131
+ loss='sparse_categorical_crossentropy',
132
+ metrics=['accuracy'])
133
+ return model
134
+
135
+ model_path = "keras_model.h5"
136
+ model = load_model_with_compatibility(model_path)
137
+ model_input_shape = (224, 224, 3)
138
+ labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
139
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
140
+ 'T', 'U', 'V', 'W', 'X', 'Y']
141
+
142
+ def preprocess_hand_roi(hand_roi, target_shape):
143
+ if target_shape[2] == 3:
144
+ if len(hand_roi.shape) == 2 or hand_roi.shape[2] == 1:
145
+ hand_roi_rgb = cv2.cvtColor(hand_roi, cv2.COLOR_GRAY2RGB)
146
+ else:
147
+ hand_roi_rgb = hand_roi.copy()
148
+
149
+ resized = cv2.resize(hand_roi_rgb, (target_shape[0], target_shape[1]))
150
+ normalized = resized.astype('float32') / 255.0
151
+ else:
152
+ if len(hand_roi.shape) > 2 and hand_roi.shape[2] > 1:
153
+ hand_roi_gray = cv2.cvtColor(hand_roi, cv2.COLOR_BGR2GRAY)
154
+ else:
155
+ hand_roi_gray = hand_roi
156
+
157
+ resized = cv2.resize(hand_roi_gray, (target_shape[0], target_shape[1]))
158
+ normalized = resized.astype('float32') / 255.0
159
+ if len(normalized.shape) == 2:
160
+ normalized = normalized[..., np.newaxis]
161
+
162
+ return np.expand_dims(normalized, axis=0), resized
163
+
164
+ def process_image(input_image):
165
+ frame = cv2.cvtColor(np.array(input_image), cv2.COLOR_RGB2BGR)
166
+ tracker = handTracker(detectionConfidence=0.7)
167
+ frame_with_hands = tracker.findAndDrawHands(frame.copy())
168
+ landmarks, bbox = tracker.findLandmarks(frame)
169
+
170
+ if not bbox:
171
+ return "No hand detected", None
172
+
173
+ x, y, w, h = bbox
174
+ hand_roi = frame[y:y+h, x:x+w]
175
+ cv2.rectangle(frame_with_hands, (x, y), (x+w, y+h), (0, 255, 0), 2)
176
+
177
+ model_input, _ = preprocess_hand_roi(hand_roi, model_input_shape)
178
+
179
+ try:
180
+ prediction = model.predict(model_input, verbose=0)[0]
181
+ predicted_class = np.argmax(prediction)
182
+ confidence = np.max(prediction)
183
+ letter = labels[predicted_class] if predicted_class < len(labels) else "Unknown"
184
+ except:
185
+ return "Prediction error", None
186
+
187
+ result_text = f"Prediction: {letter} (Confidence: {confidence:.2f})"
188
+ cv2.putText(frame_with_hands, result_text, (10, 30),
189
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
190
+
191
+ output_image = cv2.cvtColor(frame_with_hands, cv2.COLOR_BGR2RGB)
192
+ return result_text, Image.fromarray(output_image)
193
+
194
+ # Gradio interface
195
+ interface = gr.Interface(
196
+ fn=process_image,
197
+ inputs=gr.Image(label="Upload Hand Sign Image", type="pil"),
198
+ outputs=[
199
+ gr.Text(label="Prediction Result"),
200
+ gr.Image(label="Processed Image")
201
+ ],
202
+ title="ASL Sign Language Recognition",
203
+ description="Upload an image of a hand sign to recognize the ASL letter."
204
+ )
205
+
206
+ if __name__ == "__main__":
207
+ interface.launch(share=True)