Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -362,33 +362,37 @@ def process_video(video_path, num_anomalies, num_components, desired_fps, batch_
|
|
| 362 |
os.makedirs(aligned_faces_folder, exist_ok=True)
|
| 363 |
os.makedirs(organized_faces_folder, exist_ok=True)
|
| 364 |
|
| 365 |
-
progress(0.1, "Extracting
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 370 |
|
| 371 |
if not embeddings_by_frame:
|
| 372 |
return "No faces were extracted from the video.", None, None, None, None, None, None
|
| 373 |
|
| 374 |
-
progress(0.
|
| 375 |
embeddings = list(embeddings_by_frame.values())
|
| 376 |
clusters = cluster_embeddings(embeddings)
|
| 377 |
|
| 378 |
-
progress(0.
|
| 379 |
organize_faces_by_person(embeddings_by_frame, clusters, aligned_faces_folder, organized_faces_folder)
|
| 380 |
|
| 381 |
-
progress(0.
|
| 382 |
df, largest_cluster = save_person_data_to_csv(embeddings_by_frame, emotions_by_frame, clusters, desired_fps, original_fps, temp_dir, num_components)
|
| 383 |
|
| 384 |
-
progress(0.
|
| 385 |
feature_columns = [col for col in df.columns if col not in ['Frame', 'Timecode', 'Time (Minutes)', 'Embedding_Index']]
|
| 386 |
try:
|
| 387 |
anomalies_all, anomaly_scores_all, top_indices_all, anomalies_comp, anomaly_scores_comp, top_indices_comp, _ = lstm_anomaly_detection(df[feature_columns].values, feature_columns, num_anomalies=num_anomalies, batch_size=batch_size)
|
| 388 |
except Exception as e:
|
| 389 |
return f"Error in anomaly detection: {str(e)}", None, None, None, None, None, None
|
| 390 |
|
| 391 |
-
progress(0.
|
| 392 |
try:
|
| 393 |
anomaly_plot_all = plot_anomaly_scores(df, anomaly_scores_all, top_indices_all, "All Features")
|
| 394 |
anomaly_plot_comp = plot_anomaly_scores(df, anomaly_scores_comp, top_indices_comp, "Components Only")
|
|
@@ -397,7 +401,7 @@ def process_video(video_path, num_anomalies, num_components, desired_fps, batch_
|
|
| 397 |
except Exception as e:
|
| 398 |
return f"Error generating plots: {str(e)}", None, None, None, None, None, None
|
| 399 |
|
| 400 |
-
progress(0
|
| 401 |
results = f"Top {num_anomalies} anomalies (All Features):\n"
|
| 402 |
results += "\n".join([f"{score:.4f} at {timecode}" for score, timecode in
|
| 403 |
zip(anomaly_scores_all[top_indices_all], df['Timecode'].iloc[top_indices_all].values)])
|
|
@@ -405,15 +409,72 @@ def process_video(video_path, num_anomalies, num_components, desired_fps, batch_
|
|
| 405 |
results += "\n".join([f"{score:.4f} at {timecode}" for score, timecode in
|
| 406 |
zip(anomaly_scores_comp[top_indices_comp], df['Timecode'].iloc[top_indices_comp].values)])
|
| 407 |
|
| 408 |
-
# Add top emotion scores to results
|
| 409 |
for emotion in ['fear', 'sad', 'angry']:
|
| 410 |
top_indices = np.argsort(df[emotion].values)[-num_anomalies:][::-1]
|
| 411 |
results += f"\n\nTop {num_anomalies} {emotion.capitalize()} Scores:\n"
|
| 412 |
results += "\n".join([f"{df[emotion].iloc[i]:.4f} at {df['Timecode'].iloc[i]}" for i in top_indices])
|
| 413 |
|
| 414 |
-
progress(1.0, "Complete")
|
| 415 |
return results, anomaly_plot_all, anomaly_plot_comp, components_plot, *emotion_plots
|
| 416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
# Gradio interface
|
| 418 |
iface = gr.Interface(
|
| 419 |
fn=process_video,
|
|
|
|
| 362 |
os.makedirs(aligned_faces_folder, exist_ok=True)
|
| 363 |
os.makedirs(organized_faces_folder, exist_ok=True)
|
| 364 |
|
| 365 |
+
progress(0.1, "Extracting frames")
|
| 366 |
+
frames_folder = os.path.join(temp_dir, 'extracted_frames')
|
| 367 |
+
extract_frames(video_path, frames_folder, desired_fps)
|
| 368 |
+
|
| 369 |
+
progress(0.2, "Getting video info")
|
| 370 |
+
frame_count, original_fps = get_video_info(video_path)
|
| 371 |
+
|
| 372 |
+
progress(0.3, "Processing frames")
|
| 373 |
+
embeddings_by_frame, emotions_by_frame = process_frames(frames_folder, aligned_faces_folder, frame_count, progress)
|
| 374 |
|
| 375 |
if not embeddings_by_frame:
|
| 376 |
return "No faces were extracted from the video.", None, None, None, None, None, None
|
| 377 |
|
| 378 |
+
progress(0.6, "Clustering embeddings")
|
| 379 |
embeddings = list(embeddings_by_frame.values())
|
| 380 |
clusters = cluster_embeddings(embeddings)
|
| 381 |
|
| 382 |
+
progress(0.7, "Organizing faces")
|
| 383 |
organize_faces_by_person(embeddings_by_frame, clusters, aligned_faces_folder, organized_faces_folder)
|
| 384 |
|
| 385 |
+
progress(0.8, "Saving person data")
|
| 386 |
df, largest_cluster = save_person_data_to_csv(embeddings_by_frame, emotions_by_frame, clusters, desired_fps, original_fps, temp_dir, num_components)
|
| 387 |
|
| 388 |
+
progress(0.9, "Performing anomaly detection")
|
| 389 |
feature_columns = [col for col in df.columns if col not in ['Frame', 'Timecode', 'Time (Minutes)', 'Embedding_Index']]
|
| 390 |
try:
|
| 391 |
anomalies_all, anomaly_scores_all, top_indices_all, anomalies_comp, anomaly_scores_comp, top_indices_comp, _ = lstm_anomaly_detection(df[feature_columns].values, feature_columns, num_anomalies=num_anomalies, batch_size=batch_size)
|
| 392 |
except Exception as e:
|
| 393 |
return f"Error in anomaly detection: {str(e)}", None, None, None, None, None, None
|
| 394 |
|
| 395 |
+
progress(0.95, "Generating plots")
|
| 396 |
try:
|
| 397 |
anomaly_plot_all = plot_anomaly_scores(df, anomaly_scores_all, top_indices_all, "All Features")
|
| 398 |
anomaly_plot_comp = plot_anomaly_scores(df, anomaly_scores_comp, top_indices_comp, "Components Only")
|
|
|
|
| 401 |
except Exception as e:
|
| 402 |
return f"Error generating plots: {str(e)}", None, None, None, None, None, None
|
| 403 |
|
| 404 |
+
progress(1.0, "Preparing results")
|
| 405 |
results = f"Top {num_anomalies} anomalies (All Features):\n"
|
| 406 |
results += "\n".join([f"{score:.4f} at {timecode}" for score, timecode in
|
| 407 |
zip(anomaly_scores_all[top_indices_all], df['Timecode'].iloc[top_indices_all].values)])
|
|
|
|
| 409 |
results += "\n".join([f"{score:.4f} at {timecode}" for score, timecode in
|
| 410 |
zip(anomaly_scores_comp[top_indices_comp], df['Timecode'].iloc[top_indices_comp].values)])
|
| 411 |
|
|
|
|
| 412 |
for emotion in ['fear', 'sad', 'angry']:
|
| 413 |
top_indices = np.argsort(df[emotion].values)[-num_anomalies:][::-1]
|
| 414 |
results += f"\n\nTop {num_anomalies} {emotion.capitalize()} Scores:\n"
|
| 415 |
results += "\n".join([f"{df[emotion].iloc[i]:.4f} at {df['Timecode'].iloc[i]}" for i in top_indices])
|
| 416 |
|
|
|
|
| 417 |
return results, anomaly_plot_all, anomaly_plot_comp, components_plot, *emotion_plots
|
| 418 |
|
| 419 |
+
def get_video_info(video_path):
|
| 420 |
+
ffprobe_command = [
|
| 421 |
+
'ffprobe',
|
| 422 |
+
'-v', 'error',
|
| 423 |
+
'-select_streams', 'v:0',
|
| 424 |
+
'-count_packets',
|
| 425 |
+
'-show_entries', 'stream=nb_read_packets,r_frame_rate',
|
| 426 |
+
'-of', 'csv=p=0',
|
| 427 |
+
video_path
|
| 428 |
+
]
|
| 429 |
+
ffprobe_output = subprocess.check_output(ffprobe_command, universal_newlines=True).strip().split(',')
|
| 430 |
+
frame_rate, frame_count = ffprobe_output
|
| 431 |
+
|
| 432 |
+
frac = fractions.Fraction(frame_rate)
|
| 433 |
+
original_fps = float(frac.numerator) / float(frac.denominator)
|
| 434 |
+
frame_count = int(frame_count)
|
| 435 |
+
|
| 436 |
+
return frame_count, original_fps
|
| 437 |
+
|
| 438 |
+
def process_frames(frames_folder, aligned_faces_folder, frame_count, progress):
|
| 439 |
+
embeddings_by_frame = {}
|
| 440 |
+
emotions_by_frame = {}
|
| 441 |
+
|
| 442 |
+
for i, frame_file in enumerate(sorted(os.listdir(frames_folder))):
|
| 443 |
+
if frame_file.endswith('.jpg'):
|
| 444 |
+
frame_num = int(frame_file.split('_')[1].split('.')[0])
|
| 445 |
+
frame_path = os.path.join(frames_folder, frame_file)
|
| 446 |
+
frame = cv2.imread(frame_path)
|
| 447 |
+
|
| 448 |
+
progress((i + 1) / frame_count, f"Processing frame {i + 1} of {frame_count}")
|
| 449 |
+
|
| 450 |
+
if frame is None:
|
| 451 |
+
print(f"Skipping frame {frame_num}: Could not read frame")
|
| 452 |
+
continue
|
| 453 |
+
|
| 454 |
+
try:
|
| 455 |
+
boxes, probs = mtcnn.detect(frame)
|
| 456 |
+
if boxes is not None and len(boxes) > 0:
|
| 457 |
+
box = boxes[0]
|
| 458 |
+
if probs[0] >= 0.99:
|
| 459 |
+
x1, y1, x2, y2 = [int(b) for b in box]
|
| 460 |
+
face = frame[y1:y2, x1:x2]
|
| 461 |
+
if face.size == 0:
|
| 462 |
+
print(f"Skipping frame {frame_num}: Detected face region is empty")
|
| 463 |
+
continue
|
| 464 |
+
aligned_face = alignFace(face)
|
| 465 |
+
if aligned_face is not None:
|
| 466 |
+
aligned_face_resized = cv2.resize(aligned_face, (160, 160))
|
| 467 |
+
output_path = os.path.join(aligned_faces_folder, f"frame_{frame_num}_face.jpg")
|
| 468 |
+
cv2.imwrite(output_path, aligned_face_resized)
|
| 469 |
+
embedding, emotion = get_face_embedding_and_emotion(aligned_face_resized)
|
| 470 |
+
embeddings_by_frame[frame_num] = embedding
|
| 471 |
+
emotions_by_frame[frame_num] = emotion
|
| 472 |
+
except Exception as e:
|
| 473 |
+
print(f"Error processing frame {frame_num}: {str(e)}")
|
| 474 |
+
continue
|
| 475 |
+
|
| 476 |
+
return embeddings_by_frame, emotions_by_frame
|
| 477 |
+
|
| 478 |
# Gradio interface
|
| 479 |
iface = gr.Interface(
|
| 480 |
fn=process_video,
|