reab5555 commited on
Commit
9b4ede0
·
verified ·
1 Parent(s): 0debb1e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -43
app.py CHANGED
@@ -18,6 +18,7 @@ from matplotlib.ticker import MaxNLocator
18
  import gradio as gr
19
  import tempfile
20
  import shutil
 
21
 
22
  # Initialize models and other global variables
23
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
@@ -76,48 +77,79 @@ def alignFace(img):
76
  new_img = cv2.warpAffine(img_raw, rotation_matrix, (width, height))
77
  return new_img
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  def extract_and_align_faces_from_video(video_path, aligned_faces_folder, desired_fps):
80
- video = cv2.VideoCapture(video_path, cv2.CAP_FFMPEG)
81
- if not video.isOpened():
82
- print(f"Error: Could not open video file at {video_path}")
83
- return {}, {}, desired_fps, 0
84
- frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
85
- original_fps = video.get(cv2.CAP_PROP_FPS)
86
- if frame_count == 0:
87
- print(f"Error: Video file at {video_path} appears to be empty")
88
- return {}, {}, desired_fps, 0
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  embeddings_by_frame = {}
90
  emotions_by_frame = {}
91
 
92
- for frame_num in range(0, frame_count, int(original_fps / desired_fps)):
93
- video.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
94
- ret, frame = video.read()
95
- if not ret or frame is None or frame.size == 0:
96
- print(f"Skipping frame {frame_num}: Frame is empty or couldn't be read")
97
- continue
98
- try:
99
- boxes, probs = mtcnn.detect(frame)
100
- if boxes is not None and len(boxes) > 0:
101
- box = boxes[0]
102
- if probs[0] >= 0.99:
103
- x1, y1, x2, y2 = [int(b) for b in box]
104
- face = frame[y1:y2, x1:x2]
105
- if face.size == 0:
106
- print(f"Skipping frame {frame_num}: Detected face region is empty")
107
- continue
108
- aligned_face = alignFace(face)
109
- if aligned_face is not None:
110
- aligned_face_resized = cv2.resize(aligned_face, (160, 160))
111
- output_path = os.path.join(aligned_faces_folder, f"frame_{frame_num}_face.jpg")
112
- cv2.imwrite(output_path, aligned_face_resized)
113
- embedding, emotion = get_face_embedding_and_emotion(aligned_face_resized)
114
- embeddings_by_frame[frame_num] = embedding
115
- emotions_by_frame[frame_num] = emotion
116
- except Exception as e:
117
- print(f"Error processing frame {frame_num}: {str(e)}")
118
- continue
 
 
 
 
119
 
120
- video.release()
121
  return embeddings_by_frame, emotions_by_frame, desired_fps, original_fps
122
 
123
  def cluster_embeddings(embeddings):
@@ -264,7 +296,7 @@ def plot_emotion(df, emotion):
264
  ax.xaxis.set_major_locator(MaxNLocator(nbins=100))
265
  ticks = ax.get_xticks()
266
  ax.set_xticklabels([df['Timecode'].iloc[int(tick)] if tick >= 0 and tick < len(df) else '' for tick in ticks], rotation=90, ha='right')
267
- plt.tight_layout()
268
  return fig
269
 
270
  def process_video(video_path, num_anomalies, num_components, desired_fps, batch_size, progress=gr.Progress()):
@@ -275,7 +307,10 @@ def process_video(video_path, num_anomalies, num_components, desired_fps, batch_
275
  os.makedirs(organized_faces_folder, exist_ok=True)
276
 
277
  progress(0.1, "Extracting and aligning faces")
278
- embeddings_by_frame, emotions_by_frame, _, original_fps = extract_and_align_faces_from_video(video_path, aligned_faces_folder, desired_fps)
 
 
 
279
 
280
  if not embeddings_by_frame:
281
  return "No faces were extracted from the video.", None, None, None, None
@@ -292,11 +327,17 @@ def process_video(video_path, num_anomalies, num_components, desired_fps, batch_
292
 
293
  progress(0.6, "Performing anomaly detection")
294
  feature_columns = [col for col in df.columns if col not in ['Frame', 'Timecode', 'Time (Minutes)', 'Embedding_Index']]
295
- anomalies_all, anomaly_scores_all, top_indices_all, _ = lstm_anomaly_detection(df[feature_columns].values, feature_columns, num_anomalies=num_anomalies, batch_size=batch_size)
 
 
 
296
 
297
  progress(0.8, "Generating plots")
298
- anomaly_plot = plot_anomaly_scores(df, anomaly_scores_all, top_indices_all, "All Features")
299
- emotion_plots = [plot_emotion(df, emotion) for emotion in ['fear', 'sad', 'angry']]
 
 
 
300
 
301
  progress(0.9, "Preparing results")
302
  results = f"Top {num_anomalies} anomalies (All Features):\n"
@@ -327,4 +368,5 @@ iface = gr.Interface(
327
  description="Upload a video to detect anomalies in facial expressions and emotions. Adjust parameters as needed."
328
  )
329
 
330
- iface.launch()
 
 
18
  import gradio as gr
19
  import tempfile
20
  import shutil
21
+ import subprocess
22
 
23
  # Initialize models and other global variables
24
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
 
77
  new_img = cv2.warpAffine(img_raw, rotation_matrix, (width, height))
78
  return new_img
79
 
80
+ def extract_frames(video_path, output_folder, fps):
81
+ os.makedirs(output_folder, exist_ok=True)
82
+ command = [
83
+ 'ffmpeg',
84
+ '-i', video_path,
85
+ '-vf', f'fps={fps}',
86
+ f'{output_folder}/frame_%04d.jpg'
87
+ ]
88
+ try:
89
+ subprocess.run(command, check=True, capture_output=True, text=True)
90
+ except subprocess.CalledProcessError as e:
91
+ print(f"Error extracting frames: {e}")
92
+ print(f"FFmpeg output: {e.output}")
93
+ raise
94
+
95
  def extract_and_align_faces_from_video(video_path, aligned_faces_folder, desired_fps):
96
+ print(f"Processing video: {video_path}")
97
+
98
+ # Extract frames using FFmpeg
99
+ frames_folder = os.path.join(os.path.dirname(aligned_faces_folder), 'extracted_frames')
100
+ extract_frames(video_path, frames_folder, desired_fps)
101
+
102
+ # Get video info
103
+ ffprobe_command = [
104
+ 'ffprobe',
105
+ '-v', 'error',
106
+ '-select_streams', 'v:0',
107
+ '-count_packets',
108
+ '-show_entries', 'stream=nb_read_packets,r_frame_rate',
109
+ '-of', 'csv=p=0',
110
+ video_path
111
+ ]
112
+ ffprobe_output = subprocess.check_output(ffprobe_command, universal_newlines=True).strip().split(',')
113
+ frame_count = int(ffprobe_output[0])
114
+ original_fps = eval(ffprobe_output[1])
115
+
116
+ print(f"Total frames: {frame_count}, Original FPS: {original_fps}, Desired FPS: {desired_fps}")
117
+
118
  embeddings_by_frame = {}
119
  emotions_by_frame = {}
120
 
121
+ for frame_file in sorted(os.listdir(frames_folder)):
122
+ if frame_file.endswith('.jpg'):
123
+ frame_num = int(frame_file.split('_')[1].split('.')[0])
124
+ frame_path = os.path.join(frames_folder, frame_file)
125
+ frame = cv2.imread(frame_path)
126
+
127
+ if frame is None:
128
+ print(f"Skipping frame {frame_num}: Could not read frame")
129
+ continue
130
+
131
+ try:
132
+ boxes, probs = mtcnn.detect(frame)
133
+ if boxes is not None and len(boxes) > 0:
134
+ box = boxes[0]
135
+ if probs[0] >= 0.99:
136
+ x1, y1, x2, y2 = [int(b) for b in box]
137
+ face = frame[y1:y2, x1:x2]
138
+ if face.size == 0:
139
+ print(f"Skipping frame {frame_num}: Detected face region is empty")
140
+ continue
141
+ aligned_face = alignFace(face)
142
+ if aligned_face is not None:
143
+ aligned_face_resized = cv2.resize(aligned_face, (160, 160))
144
+ output_path = os.path.join(aligned_faces_folder, f"frame_{frame_num}_face.jpg")
145
+ cv2.imwrite(output_path, aligned_face_resized)
146
+ embedding, emotion = get_face_embedding_and_emotion(aligned_face_resized)
147
+ embeddings_by_frame[frame_num] = embedding
148
+ emotions_by_frame[frame_num] = emotion
149
+ except Exception as e:
150
+ print(f"Error processing frame {frame_num}: {str(e)}")
151
+ continue
152
 
 
153
  return embeddings_by_frame, emotions_by_frame, desired_fps, original_fps
154
 
155
  def cluster_embeddings(embeddings):
 
296
  ax.xaxis.set_major_locator(MaxNLocator(nbins=100))
297
  ticks = ax.get_xticks()
298
  ax.set_xticklabels([df['Timecode'].iloc[int(tick)] if tick >= 0 and tick < len(df) else '' for tick in ticks], rotation=90, ha='right')
299
+ plt.tight_layout()
300
  return fig
301
 
302
  def process_video(video_path, num_anomalies, num_components, desired_fps, batch_size, progress=gr.Progress()):
 
307
  os.makedirs(organized_faces_folder, exist_ok=True)
308
 
309
  progress(0.1, "Extracting and aligning faces")
310
+ try:
311
+ embeddings_by_frame, emotions_by_frame, _, original_fps = extract_and_align_faces_from_video(video_path, aligned_faces_folder, desired_fps)
312
+ except Exception as e:
313
+ return f"Error extracting faces: {str(e)}", None, None, None, None
314
 
315
  if not embeddings_by_frame:
316
  return "No faces were extracted from the video.", None, None, None, None
 
327
 
328
  progress(0.6, "Performing anomaly detection")
329
  feature_columns = [col for col in df.columns if col not in ['Frame', 'Timecode', 'Time (Minutes)', 'Embedding_Index']]
330
+ try:
331
+ anomalies_all, anomaly_scores_all, top_indices_all, _ = lstm_anomaly_detection(df[feature_columns].values, feature_columns, num_anomalies=num_anomalies, batch_size=batch_size)
332
+ except Exception as e:
333
+ return f"Error in anomaly detection: {str(e)}", None, None, None, None
334
 
335
  progress(0.8, "Generating plots")
336
+ try:
337
+ anomaly_plot = plot_anomaly_scores(df, anomaly_scores_all, top_indices_all, "All Features")
338
+ emotion_plots = [plot_emotion(df, emotion) for emotion in ['fear', 'sad', 'angry']]
339
+ except Exception as e:
340
+ return f"Error generating plots: {str(e)}", None, None, None, None
341
 
342
  progress(0.9, "Preparing results")
343
  results = f"Top {num_anomalies} anomalies (All Features):\n"
 
368
  description="Upload a video to detect anomalies in facial expressions and emotions. Adjust parameters as needed."
369
  )
370
 
371
+ if __name__ == "__main__":
372
+ iface.launch()