David Driscoll commited on
Commit
fd8b339
·
1 Parent(s): 5c7b604

red lines for FMesh

Browse files
Files changed (1) hide show
  1. app.py +59 -31
app.py CHANGED
@@ -7,7 +7,6 @@ from torchvision.models.detection import FasterRCNN_ResNet50_FPN_Weights
7
  from PIL import Image
8
  import mediapipe as mp
9
  from fer import FER # Facial emotion recognition
10
- # from transformers import AutoFeatureExtractor, AutoModel # (Unused now for facial recognition)
11
 
12
  # -----------------------------
13
  # Configuration
@@ -144,34 +143,58 @@ def compute_faces_overlay(image):
144
  return boxes, text
145
 
146
  # -----------------------------
147
- # New Facemesh Functions (for Facial Recognition)
148
  # -----------------------------
149
  def compute_facemesh_overlay(image):
150
  """
151
  Uses MediaPipe Face Mesh to detect and draw facial landmarks.
 
 
 
 
152
  """
153
  frame_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
154
  h, w, _ = frame_bgr.shape
 
 
 
 
155
  # Initialize Face Mesh in static mode
156
  face_mesh = mp.solutions.face_mesh.FaceMesh(
157
  static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5
158
  )
159
  results = face_mesh.process(cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB))
 
160
  if results.multi_face_landmarks:
161
  for face_landmarks in results.multi_face_landmarks:
162
- for landmark in face_landmarks.landmark:
163
- x = int(landmark.x * w)
164
- y = int(landmark.y * h)
165
- cv2.circle(frame_bgr, (x, y), 1, (0, 255, 0), -1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  text = "Facemesh detected"
167
  else:
168
  text = "No facemesh detected"
169
  face_mesh.close()
170
- return frame_bgr, text
171
 
172
  def analyze_facemesh(image):
173
- annotated_image, text = compute_facemesh_overlay(image)
174
- return annotated_image, f"<div style='color: lime !important;'>Facemesh Analysis: {text}</div>"
 
175
 
176
  # -----------------------------
177
  # Main Analysis Functions for Single Image
@@ -187,7 +210,7 @@ def analyze_posture_current(image):
187
  output = current_frame.copy()
188
  if posture_cache["landmarks"]:
189
  output = draw_posture_overlay(output, posture_cache["landmarks"])
190
- return output, f"<div style='color: lime !important;'>Posture Analysis: {posture_cache['text']}</div>"
191
 
192
  def analyze_emotion_current(image):
193
  global emotion_cache
@@ -196,7 +219,7 @@ def analyze_emotion_current(image):
196
  if emotion_cache["counter"] % SKIP_RATE == 0 or emotion_cache["text"] is None:
197
  text = compute_emotion_overlay(image)
198
  emotion_cache["text"] = text
199
- return current_frame, f"<div style='color: lime !important;'>Emotion Analysis: {emotion_cache['text']}</div>"
200
 
201
  def analyze_objects_current(image):
202
  global objects_cache
@@ -211,7 +234,7 @@ def analyze_objects_current(image):
211
  if objects_cache["boxes"]:
212
  output = draw_boxes_overlay(output, objects_cache["boxes"], (255, 255, 0))
213
  combined_text = f"Object Detection: {objects_cache['text']}<br>Details: {objects_cache['object_list_text']}"
214
- return output, f"<div style='color: lime !important;'>{combined_text}</div>"
215
 
216
  def analyze_faces_current(image):
217
  global faces_cache
@@ -224,7 +247,7 @@ def analyze_faces_current(image):
224
  output = current_frame.copy()
225
  if faces_cache["boxes"]:
226
  output = draw_boxes_overlay(output, faces_cache["boxes"], (0, 0, 255))
227
- return output, f"<div style='color: lime !important;'>Face Detection: {faces_cache['text']}</div>"
228
 
229
  def analyze_all(image):
230
  current_frame = np.array(image).copy()
@@ -249,37 +272,38 @@ def analyze_all(image):
249
  description_text = f"Image Description: The scene features {object_list_text}."
250
  else:
251
  description_text = "Image Description: No prominent objects detected."
252
- combined_text += f"<br><br><div style='border:1px solid lime; padding:10px; box-shadow: 0 0 10px lime;'><b>{description_text}</b></div>"
253
- combined_text_html = f"<div style='color: lime !important;'>{combined_text}</div>"
254
  return current_frame, combined_text_html
255
 
256
  # -----------------------------
257
- # Custom CSS (High-Tech Neon Theme)
258
  # -----------------------------
259
  custom_css = """
260
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
261
  body {
262
- background-color: #0e0e0e;
263
  font-family: 'Orbitron', sans-serif;
264
- color: #32CD32;
265
  }
266
  .gradio-container {
267
- background: linear-gradient(135deg, #1a1a1a, #333333);
268
- border: 2px solid #32CD32;
269
- box-shadow: 0 0 15px #32CD32;
270
  border-radius: 10px;
271
  padding: 20px;
272
  max-width: 1200px;
273
  margin: auto;
274
  }
275
  .gradio-title, .gradio-description, .tab-item, .tab-item * {
276
- color: #32CD32 !important;
277
- text-shadow: 0 0 10px #32CD32;
278
  }
279
  input, button, .output {
280
- border: 1px solid #32CD32;
281
- box-shadow: 0 0 8px #32CD32;
282
- color: #32CD32;
 
283
  }
284
  """
285
 
@@ -323,14 +347,18 @@ faces_interface = gr.Interface(
323
  )
324
 
325
  # -----------------------------
326
- # New Facemesh Interface (Used for facial recognition via facemesh)
327
  # -----------------------------
328
  facemesh_interface = gr.Interface(
329
  fn=analyze_facemesh,
330
  inputs=gr.Image(label="Upload an Image for Facemesh"),
331
- outputs=[gr.Image(type="numpy", label="Annotated Output"), gr.HTML(label="Facemesh Analysis")],
 
 
 
 
332
  title="Facemesh",
333
- description="Detects facial landmarks using MediaPipe Face Mesh.",
334
  live=False
335
  )
336
 
@@ -367,8 +395,8 @@ tabbed_interface = gr.TabbedInterface(
367
  # -----------------------------
368
  demo = gr.Blocks(css=custom_css)
369
  with demo:
370
- gr.Markdown("<h1 class='gradio-title' style='color: #32CD32;'>Multi-Analysis Image App</h1>")
371
- gr.Markdown("<p class='gradio-description' style='color: #32CD32;'>Upload an image to run high-tech analysis for posture, emotions, objects, faces, and facemesh landmarks.</p>")
372
  tabbed_interface.render()
373
 
374
  if __name__ == "__main__":
 
7
  from PIL import Image
8
  import mediapipe as mp
9
  from fer import FER # Facial emotion recognition
 
10
 
11
  # -----------------------------
12
  # Configuration
 
143
  return boxes, text
144
 
145
  # -----------------------------
146
+ # New Facemesh Functions (with connected red lines and mask output)
147
  # -----------------------------
148
  def compute_facemesh_overlay(image):
149
  """
150
  Uses MediaPipe Face Mesh to detect and draw facial landmarks.
151
+ Draws green dots for landmarks and connects them with thin red lines.
152
+ Returns two images:
153
+ - annotated: the original image overlaid with the facemesh
154
+ - mask: a black background image with only the facemesh drawn
155
  """
156
  frame_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
157
  h, w, _ = frame_bgr.shape
158
+ # Create a copy for annotated output and a black mask
159
+ annotated = frame_bgr.copy()
160
+ mask = np.zeros_like(frame_bgr)
161
+
162
  # Initialize Face Mesh in static mode
163
  face_mesh = mp.solutions.face_mesh.FaceMesh(
164
  static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5
165
  )
166
  results = face_mesh.process(cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB))
167
+
168
  if results.multi_face_landmarks:
169
  for face_landmarks in results.multi_face_landmarks:
170
+ # Convert landmarks to pixel coordinates
171
+ landmark_points = []
172
+ for lm in face_landmarks.landmark:
173
+ x = int(lm.x * w)
174
+ y = int(lm.y * h)
175
+ landmark_points.append((x, y))
176
+ # Draw thin red lines between connected landmarks using the FACEMESH_TESSELATION
177
+ for connection in mp.solutions.face_mesh.FACEMESH_TESSELATION:
178
+ start_idx, end_idx = connection
179
+ if start_idx < len(landmark_points) and end_idx < len(landmark_points):
180
+ pt1 = landmark_points[start_idx]
181
+ pt2 = landmark_points[end_idx]
182
+ cv2.line(annotated, pt1, pt2, (0, 0, 255), 1)
183
+ cv2.line(mask, pt1, pt2, (0, 0, 255), 1)
184
+ # Draw green dots for each landmark
185
+ for pt in landmark_points:
186
+ cv2.circle(annotated, pt, 2, (0, 255, 0), -1)
187
+ cv2.circle(mask, pt, 2, (0, 255, 0), -1)
188
  text = "Facemesh detected"
189
  else:
190
  text = "No facemesh detected"
191
  face_mesh.close()
192
+ return annotated, mask, text
193
 
194
  def analyze_facemesh(image):
195
+ annotated_image, mask_image, text = compute_facemesh_overlay(image)
196
+ return (annotated_image, mask_image,
197
+ f"<div style='color: #ff6347 !important;'>Facemesh Analysis: {text}</div>")
198
 
199
  # -----------------------------
200
  # Main Analysis Functions for Single Image
 
210
  output = current_frame.copy()
211
  if posture_cache["landmarks"]:
212
  output = draw_posture_overlay(output, posture_cache["landmarks"])
213
+ return output, f"<div style='color: #ff6347 !important;'>Posture Analysis: {posture_cache['text']}</div>"
214
 
215
  def analyze_emotion_current(image):
216
  global emotion_cache
 
219
  if emotion_cache["counter"] % SKIP_RATE == 0 or emotion_cache["text"] is None:
220
  text = compute_emotion_overlay(image)
221
  emotion_cache["text"] = text
222
+ return current_frame, f"<div style='color: #ff6347 !important;'>Emotion Analysis: {emotion_cache['text']}</div>"
223
 
224
  def analyze_objects_current(image):
225
  global objects_cache
 
234
  if objects_cache["boxes"]:
235
  output = draw_boxes_overlay(output, objects_cache["boxes"], (255, 255, 0))
236
  combined_text = f"Object Detection: {objects_cache['text']}<br>Details: {objects_cache['object_list_text']}"
237
+ return output, f"<div style='color: #ff6347 !important;'>{combined_text}</div>"
238
 
239
  def analyze_faces_current(image):
240
  global faces_cache
 
247
  output = current_frame.copy()
248
  if faces_cache["boxes"]:
249
  output = draw_boxes_overlay(output, faces_cache["boxes"], (0, 0, 255))
250
+ return output, f"<div style='color: #ff6347 !important;'>Face Detection: {faces_cache['text']}</div>"
251
 
252
  def analyze_all(image):
253
  current_frame = np.array(image).copy()
 
272
  description_text = f"Image Description: The scene features {object_list_text}."
273
  else:
274
  description_text = "Image Description: No prominent objects detected."
275
+ combined_text += f"<br><br><div style='border:1px solid #ff6347; padding:10px; box-shadow: 0 0 10px #ff6347;'><b>{description_text}</b></div>"
276
+ combined_text_html = f"<div style='color: #ff6347 !important;'>{combined_text}</div>"
277
  return current_frame, combined_text_html
278
 
279
  # -----------------------------
280
+ # Custom CSS (Revamped High-Contrast Neon Theme)
281
  # -----------------------------
282
  custom_css = """
283
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
284
  body {
285
+ background-color: #121212;
286
  font-family: 'Orbitron', sans-serif;
287
+ color: #ffffff;
288
  }
289
  .gradio-container {
290
+ background: linear-gradient(135deg, #2d2d2d, #1a1a1a);
291
+ border: 2px solid #ff6347;
292
+ box-shadow: 0 0 15px #ff6347;
293
  border-radius: 10px;
294
  padding: 20px;
295
  max-width: 1200px;
296
  margin: auto;
297
  }
298
  .gradio-title, .gradio-description, .tab-item, .tab-item * {
299
+ color: #ff6347 !important;
300
+ text-shadow: 0 0 10px #ff6347;
301
  }
302
  input, button, .output {
303
+ border: 1px solid #ff6347;
304
+ box-shadow: 0 0 8px #ff6347;
305
+ color: #ffffff;
306
+ background-color: #1a1a1a;
307
  }
308
  """
309
 
 
347
  )
348
 
349
  # -----------------------------
350
+ # New Facemesh Interface (Outputs annotated image and mask)
351
  # -----------------------------
352
  facemesh_interface = gr.Interface(
353
  fn=analyze_facemesh,
354
  inputs=gr.Image(label="Upload an Image for Facemesh"),
355
+ outputs=[
356
+ gr.Image(type="numpy", label="Annotated Output"),
357
+ gr.Image(type="numpy", label="Mask Output"),
358
+ gr.HTML(label="Facemesh Analysis")
359
+ ],
360
  title="Facemesh",
361
+ description="Detects facial landmarks using MediaPipe Face Mesh and outputs both an annotated image and a mask on a black background.",
362
  live=False
363
  )
364
 
 
395
  # -----------------------------
396
  demo = gr.Blocks(css=custom_css)
397
  with demo:
398
+ gr.Markdown("<h1 class='gradio-title'>Multi-Analysis Image App</h1>")
399
+ gr.Markdown("<p class='gradio-description'>Upload an image to run high-tech analysis for posture, emotions, objects, faces, and facemesh landmarks.</p>")
400
  tabbed_interface.render()
401
 
402
  if __name__ == "__main__":