Johnnyyyyy56 commited on
Commit
4646367
·
verified ·
1 Parent(s): 37b8be0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -200
app.py CHANGED
@@ -26,25 +26,22 @@ BACKENDS = ['opencv', 'mtcnn', 'ssd', 'dlib']
26
  SAVE_DIR = Path("/tmp/emotion_results")
27
  SAVE_DIR.mkdir(exist_ok=True)
28
 
29
- # Create directories
30
- (SAVE_DIR / "faces").mkdir(exist_ok=True) # For raw face crops
31
- (SAVE_DIR / "annotated").mkdir(exist_ok=True) # For annotated images
32
  for emotion in EMOTION_MAP.keys():
33
- (SAVE_DIR / "faces" / emotion).mkdir(exist_ok=True, parents=True)
34
- (SAVE_DIR / "annotated" / emotion).mkdir(exist_ok=True, parents=True)
35
 
36
  # Log file setup
37
  LOG_FILE = SAVE_DIR / "emotion_logs.csv"
38
  if not LOG_FILE.exists():
39
  with open(LOG_FILE, 'w', newline='') as f:
40
  writer = csv.writer(f)
41
- writer.writerow(["timestamp", "batch_no", "emotion", "confidence", "face_path", "annotated_path"])
42
 
43
- def log_emotion(batch_no, emotion, confidence, face_path, annotated_path):
44
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
45
  with open(LOG_FILE, 'a', newline='') as f:
46
  writer = csv.writer(f)
47
- writer.writerow([timestamp, batch_no, emotion, confidence, str(face_path), str(annotated_path)])
48
 
49
  def predict_emotion(batch_no: str, image):
50
  if not batch_no.strip():
@@ -83,31 +80,23 @@ def predict_emotion(batch_no: str, image):
83
  confidence = result['emotion'][emotion]
84
  region = result['region']
85
 
86
- # Extract face coordinates
87
  x, y, w, h = region['x'], region['y'], region['w'], region['h']
88
-
89
- # 1. Save raw face crop (for training)
90
- face_crop = frame[y:y+h, x:x+w]
91
- timestamp = int(time.time())
92
- face_dir = SAVE_DIR / "faces" / emotion
93
- face_path = face_dir / f"{batch_no}_{timestamp}.jpg"
94
- cv2.imwrite(str(face_path), face_crop)
95
-
96
- # 2. Create and save annotated image (for display)
97
- annotated_frame = frame.copy()
98
- cv2.rectangle(annotated_frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
99
- cv2.putText(annotated_frame, f"{emotion} {EMOTION_MAP[emotion]} {confidence:.1f}%",
100
  (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
101
 
102
- annotated_dir = SAVE_DIR / "annotated" / emotion
103
- annotated_path = annotated_dir / f"{batch_no}_{timestamp}.jpg"
104
- cv2.imwrite(str(annotated_path), annotated_frame)
 
 
105
 
106
- # Log both paths
107
- log_emotion(batch_no, emotion, confidence, face_path, annotated_path)
108
 
109
  # Convert back to PIL format for display
110
- output_img = Image.fromarray(cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB))
111
  return output_img, f"Batch {batch_no}: {emotion.title()} ({confidence:.1f}%)", "", gr.Image(visible=True), gr.Textbox(visible=True)
112
 
113
  except Exception as e:
@@ -118,66 +107,21 @@ def toggle_webcam(batch_no):
118
  return gr.Image(visible=True), gr.Image(visible=False), gr.Textbox(visible=False), ""
119
  return gr.Image(visible=False), gr.Image(visible=False), gr.Textbox(visible=False), "Please enter a batch number"
120
 
121
- def get_image_gallery(emotion, image_type):
122
- """Get image gallery for selected emotion and type"""
123
- if emotion == "All Emotions":
124
- image_dict = {}
125
- for emot in EMOTION_MAP.keys():
126
- folder = SAVE_DIR / image_type / emot
127
- image_dict[emot] = [str(f) for f in folder.glob("*.jpg") if f.exists()]
128
- else:
129
- folder = SAVE_DIR / image_type / emotion
130
- image_dict = {emotion: [str(f) for f in folder.glob("*.jpg") if f.exists()]}
131
- return image_dict
132
-
133
- def create_custom_zip(selected_images):
134
- """Create zip from selected images"""
135
- if not selected_images:
136
- return None
137
- zip_path = SAVE_DIR / "selected_images.zip"
138
  with zipfile.ZipFile(zip_path, 'w') as zipf:
139
- for img_path in selected_images:
140
- if Path(img_path).exists():
141
- zipf.write(img_path, arcname=Path(img_path).name)
142
- return str(zip_path) if zip_path.exists() else None
143
-
144
- def delete_selected_images(selected_images):
145
- """Delete selected images"""
146
- if not selected_images:
147
- return "No images selected"
148
-
149
- deleted_count = 0
150
- for img_path in selected_images:
151
- try:
152
- Path(img_path).unlink()
153
- deleted_count += 1
154
- except Exception as e:
155
- print(f"Error deleting {img_path}: {e}")
156
-
157
- # Update logs
158
- if LOG_FILE.exists():
159
- df = pd.read_csv(LOG_FILE)
160
- for img_path in selected_images:
161
- if "faces" in img_path:
162
- df = df[df.face_path != img_path]
163
- else:
164
- df = df[df.annotated_path != img_path]
165
- df.to_csv(LOG_FILE, index=False)
166
-
167
- return f"Deleted {deleted_count} images"
168
-
169
- def update_gallery(emotion, image_type):
170
- """Update the image gallery view"""
171
- image_dict = get_image_gallery(emotion, image_type)
172
- gallery = []
173
- for emotion, images in image_dict.items():
174
- for img_path in images:
175
- gallery.append((img_path, f"{emotion}: {Path(img_path).name}"))
176
- return gr.Gallery(value=gallery, label="Image Gallery"), gr.CheckboxGroup(
177
- choices=[img[0] for img in gallery],
178
- label="Selected Images",
179
- value=[]
180
- )
181
 
182
  def get_logs():
183
  if LOG_FILE.exists():
@@ -195,15 +139,12 @@ def download_logs():
195
  return str(LOG_FILE)
196
  return None
197
 
198
- def clear_all_data():
199
- """Clear all images and logs"""
200
  # Clear all images
201
  for emotion in EMOTION_MAP.keys():
202
- for img_type in ["faces", "annotated"]:
203
- folder = SAVE_DIR / img_type / emotion
204
- for file in folder.glob("*"):
205
- if file.is_file():
206
- file.unlink()
207
 
208
  # Clear logs
209
  if LOG_FILE.exists():
@@ -212,7 +153,7 @@ def clear_all_data():
212
  # Recreate empty log file
213
  with open(LOG_FILE, 'w', newline='') as f:
214
  writer = csv.writer(f)
215
- writer.writerow(["timestamp", "batch_no", "emotion", "confidence", "face_path", "annotated_path"])
216
 
217
  return "All data has been cleared", pd.DataFrame(), None
218
 
@@ -220,7 +161,6 @@ def clear_all_data():
220
  with gr.Blocks(title="Emotion Capture", css="""
221
  .gradio-container { max-width: 800px !important }
222
  .message { color: red; font-weight: bold; }
223
- .gallery { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
224
  """) as capture_interface:
225
 
226
  gr.Markdown("""
@@ -265,117 +205,44 @@ with gr.Blocks(title="Emotion Capture", css="""
265
 
266
  # Data Management Interface
267
  with gr.Blocks(title="Data Management", css="""
268
- .gradio-container { max-width: 1200px !important }
269
  .data-section { border: 1px solid #ccc; padding: 20px; border-radius: 5px; margin-top: 20px; }
270
- .gallery { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
271
- .action-buttons { margin-top: 20px; }
272
  """) as data_interface:
273
 
274
  gr.Markdown("# Data Management Interface")
275
 
276
- with gr.Tab("Image Management"):
277
- with gr.Column():
278
- gr.Markdown("## Select and Manage Images")
279
  with gr.Row():
280
  emotion_selector = gr.Dropdown(
281
  choices=["All Emotions"] + list(EMOTION_MAP.keys()),
282
- label="Emotion Category",
283
- value="All Emotions"
284
- )
285
- image_type_selector = gr.Dropdown(
286
- choices=["faces", "annotated"],
287
- label="Image Type",
288
- value="faces"
289
  )
290
- refresh_btn = gr.Button("Refresh Gallery")
291
-
292
- gallery = gr.Gallery(
293
- label="Image Gallery",
294
- elem_classes="gallery",
295
- columns=4
296
- )
297
- selected_images = gr.CheckboxGroup(
298
- label="Selected Images",
299
- interactive=True
300
- )
301
-
302
- with gr.Row(variant="panel"):
303
- with gr.Column():
304
- gr.Markdown("### Download Options")
305
- download_btn = gr.Button("Download Selected", variant="primary")
306
- download_all_btn = gr.Button("Download All in Category")
307
- download_output = gr.File(label="Download Result")
308
-
309
- with gr.Column():
310
- gr.Markdown("### Delete Options")
311
- delete_btn = gr.Button("Delete Selected", variant="stop")
312
- delete_all_btn = gr.Button("Delete All in Category", variant="stop")
313
- delete_output = gr.Textbox(label="Delete Status")
314
 
315
- # Update gallery when parameters change
316
- emotion_selector.change(
317
- update_gallery,
318
- inputs=[emotion_selector, image_type_selector],
319
- outputs=[gallery, selected_images]
320
- )
321
-
322
- image_type_selector.change(
323
- update_gallery,
324
- inputs=[emotion_selector, image_type_selector],
325
- outputs=[gallery, selected_images]
326
- )
327
-
328
- refresh_btn.click(
329
- update_gallery,
330
- inputs=[emotion_selector, image_type_selector],
331
- outputs=[gallery, selected_images]
332
- )
333
-
334
- # Download handlers
335
  download_btn.click(
336
- create_custom_zip,
337
- inputs=selected_images,
338
- outputs=download_output
339
- )
340
-
341
- download_all_btn.click(
342
- lambda e, t: create_custom_zip([img[0] for img in get_image_gallery(e, t).items() for img in img[1]]),
343
- inputs=[emotion_selector, image_type_selector],
344
- outputs=download_output
345
- )
346
-
347
- # Delete handlers
348
- delete_btn.click(
349
- delete_selected_images,
350
- inputs=selected_images,
351
- outputs=delete_output
352
- ).then(
353
- lambda: update_gallery(emotion_selector.value, image_type_selector.value),
354
- outputs=[gallery, selected_images]
355
- )
356
-
357
- delete_all_btn.click(
358
- lambda e, t: delete_selected_images([img for img_list in get_image_gallery(e, t).values() for img in img_list]),
359
- inputs=[emotion_selector, image_type_selector],
360
- outputs=delete_output
361
- ).then(
362
- lambda: update_gallery(emotion_selector.value, image_type_selector.value),
363
- outputs=[gallery, selected_images]
364
  )
365
 
366
  with gr.Tab("Emotion Logs"):
367
- with gr.Column():
368
- gr.Markdown("## Emotion Analysis Logs")
369
  with gr.Row():
370
- refresh_logs_btn = gr.Button("Refresh Logs")
371
  download_logs_btn = gr.Button("Download Logs as CSV")
372
- clear_all_btn = gr.Button("Clear All Data", variant="stop")
373
 
374
  logs_display = gr.Markdown()
375
  logs_csv = gr.File(label="Logs Download")
376
  clear_message = gr.Textbox(label="Status", interactive=False)
377
 
378
- refresh_logs_btn.click(
379
  view_logs,
380
  outputs=logs_display
381
  )
@@ -385,12 +252,9 @@ with gr.Blocks(title="Data Management", css="""
385
  outputs=logs_csv
386
  )
387
 
388
- clear_all_btn.click(
389
- clear_all_data,
390
  outputs=[clear_message, logs_display, logs_csv]
391
- ).then(
392
- lambda: update_gallery("All Emotions", "faces"),
393
- outputs=[gallery, selected_images]
394
  )
395
 
396
  # Initial load of logs
@@ -402,16 +266,7 @@ with gr.Blocks(title="Data Management", css="""
402
  # Combine interfaces
403
  demo = gr.TabbedInterface(
404
  [capture_interface, data_interface],
405
- ["Emotion Capture", "Data Management"],
406
- css="""
407
- .tab { padding: 20px; }
408
- """
409
- )
410
-
411
- # Initialize gallery and logs
412
- demo.load(
413
- lambda: update_gallery("All Emotions", "faces"),
414
- outputs=[gallery, selected_images]
415
  )
416
 
417
  if __name__ == "__main__":
 
26
  SAVE_DIR = Path("/tmp/emotion_results")
27
  SAVE_DIR.mkdir(exist_ok=True)
28
 
29
+ # Create emotion subdirectories
 
 
30
  for emotion in EMOTION_MAP.keys():
31
+ (SAVE_DIR / emotion).mkdir(exist_ok=True)
 
32
 
33
  # Log file setup
34
  LOG_FILE = SAVE_DIR / "emotion_logs.csv"
35
  if not LOG_FILE.exists():
36
  with open(LOG_FILE, 'w', newline='') as f:
37
  writer = csv.writer(f)
38
+ writer.writerow(["timestamp", "batch_no", "emotion", "confidence", "image_path"])
39
 
40
+ def log_emotion(batch_no, emotion, confidence, image_path):
41
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
42
  with open(LOG_FILE, 'a', newline='') as f:
43
  writer = csv.writer(f)
44
+ writer.writerow([timestamp, batch_no, emotion, confidence, image_path])
45
 
46
  def predict_emotion(batch_no: str, image):
47
  if not batch_no.strip():
 
80
  confidence = result['emotion'][emotion]
81
  region = result['region']
82
 
83
+ # Draw annotations on the image
84
  x, y, w, h = region['x'], region['y'], region['w'], region['h']
85
+ cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
86
+ cv2.putText(frame, f"{emotion} {EMOTION_MAP[emotion]} {confidence:.1f}%",
 
 
 
 
 
 
 
 
 
 
87
  (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
88
 
89
+ # Save the result in emotion-specific folder
90
+ timestamp = int(time.time())
91
+ emotion_dir = SAVE_DIR / emotion
92
+ output_path = str(emotion_dir / f"{batch_no}_{timestamp}.jpg")
93
+ cv2.imwrite(output_path, frame)
94
 
95
+ # Log the result
96
+ log_emotion(batch_no, emotion, confidence, output_path)
97
 
98
  # Convert back to PIL format for display
99
+ output_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
100
  return output_img, f"Batch {batch_no}: {emotion.title()} ({confidence:.1f}%)", "", gr.Image(visible=True), gr.Textbox(visible=True)
101
 
102
  except Exception as e:
 
107
  return gr.Image(visible=True), gr.Image(visible=False), gr.Textbox(visible=False), ""
108
  return gr.Image(visible=False), gr.Image(visible=False), gr.Textbox(visible=False), "Please enter a batch number"
109
 
110
+ def create_zip(emotion=None):
111
+ zip_path = SAVE_DIR / "emotion_results.zip"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  with zipfile.ZipFile(zip_path, 'w') as zipf:
113
+ if emotion and emotion != "All Emotions":
114
+ # Zip specific emotion folder
115
+ folder = SAVE_DIR / emotion
116
+ for file in folder.iterdir():
117
+ zipf.write(file, arcname=f"{emotion}/{file.name}")
118
+ else:
119
+ # Zip all images
120
+ for emotion in EMOTION_MAP.keys():
121
+ folder = SAVE_DIR / emotion
122
+ for file in folder.iterdir():
123
+ zipf.write(file, arcname=f"{emotion}/{file.name}")
124
+ return str(zip_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  def get_logs():
127
  if LOG_FILE.exists():
 
139
  return str(LOG_FILE)
140
  return None
141
 
142
+ def clear_data():
 
143
  # Clear all images
144
  for emotion in EMOTION_MAP.keys():
145
+ folder = SAVE_DIR / emotion
146
+ for file in folder.glob("*"):
147
+ file.unlink()
 
 
148
 
149
  # Clear logs
150
  if LOG_FILE.exists():
 
153
  # Recreate empty log file
154
  with open(LOG_FILE, 'w', newline='') as f:
155
  writer = csv.writer(f)
156
+ writer.writerow(["timestamp", "batch_no", "emotion", "confidence", "image_path"])
157
 
158
  return "All data has been cleared", pd.DataFrame(), None
159
 
 
161
  with gr.Blocks(title="Emotion Capture", css="""
162
  .gradio-container { max-width: 800px !important }
163
  .message { color: red; font-weight: bold; }
 
164
  """) as capture_interface:
165
 
166
  gr.Markdown("""
 
205
 
206
  # Data Management Interface
207
  with gr.Blocks(title="Data Management", css="""
208
+ .gradio-container { max-width: 900px !important }
209
  .data-section { border: 1px solid #ccc; padding: 20px; border-radius: 5px; margin-top: 20px; }
 
 
210
  """) as data_interface:
211
 
212
  gr.Markdown("# Data Management Interface")
213
 
214
+ with gr.Tab("Download Images"):
215
+ with gr.Column(elem_classes="data-section"):
216
+ gr.Markdown("## Download Options")
217
  with gr.Row():
218
  emotion_selector = gr.Dropdown(
219
  choices=["All Emotions"] + list(EMOTION_MAP.keys()),
220
+ label="Select Emotion Category",
221
+ value="All Emotions",
222
+ interactive=True
 
 
 
 
223
  )
224
+ download_btn = gr.Button("Download Images as ZIP")
225
+ download_file = gr.File(label="Download Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  download_btn.click(
228
+ create_zip,
229
+ inputs=emotion_selector,
230
+ outputs=download_file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  )
232
 
233
  with gr.Tab("Emotion Logs"):
234
+ with gr.Column(elem_classes="data-section"):
235
+ gr.Markdown("## Emotion Logs")
236
  with gr.Row():
237
+ refresh_btn = gr.Button("Refresh Logs")
238
  download_logs_btn = gr.Button("Download Logs as CSV")
239
+ clear_btn = gr.Button("Clear All Data", variant="stop")
240
 
241
  logs_display = gr.Markdown()
242
  logs_csv = gr.File(label="Logs Download")
243
  clear_message = gr.Textbox(label="Status", interactive=False)
244
 
245
+ refresh_btn.click(
246
  view_logs,
247
  outputs=logs_display
248
  )
 
252
  outputs=logs_csv
253
  )
254
 
255
+ clear_btn.click(
256
+ clear_data,
257
  outputs=[clear_message, logs_display, logs_csv]
 
 
 
258
  )
259
 
260
  # Initial load of logs
 
266
  # Combine interfaces
267
  demo = gr.TabbedInterface(
268
  [capture_interface, data_interface],
269
+ ["Emotion Capture", "Data Management"]
 
 
 
 
 
 
 
 
 
270
  )
271
 
272
  if __name__ == "__main__":