reab5555 commited on
Commit
d325594
·
verified ·
1 Parent(s): 68302f1

Update visualization.py

Browse files
Files changed (1) hide show
  1. visualization.py +40 -88
visualization.py CHANGED
@@ -11,22 +11,12 @@ from moviepy.editor import VideoFileClip, AudioFileClip, CompositeVideoClip, Ima
11
  from moviepy.video.fx.all import resize
12
  from PIL import Image, ImageDraw, ImageFont
13
  from matplotlib.patches import Rectangle
 
 
14
  from scipy import interpolate
 
15
  import os
16
 
17
- # Utility functions
18
- def seconds_to_timecode(seconds):
19
- hours = seconds // 3600
20
- minutes = (seconds % 3600) // 60
21
- seconds = seconds % 60
22
- return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
23
-
24
- def determine_anomalies(values, threshold):
25
- mean = np.mean(values)
26
- std = np.std(values)
27
- anomalies = np.where(values > mean + threshold * std)[0]
28
- return anomalies
29
-
30
  def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_threshold=4):
31
  plt.figure(figsize=(16, 8), dpi=300)
32
  fig, ax = plt.subplots(figsize=(16, 8))
@@ -77,6 +67,7 @@ def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_thre
77
  ax.plot(segment_df['Seconds'], mean, color=color, linewidth=0.5)
78
  ax.fill_between(segment_df['Seconds'], mean - std, mean + std, color=color, alpha=0.1)
79
 
 
80
  median = np.median(mse_values)
81
  ax.axhline(y=median, color='black', linestyle='--', label='Median Baseline')
82
 
@@ -136,6 +127,7 @@ def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_thre
136
  plt.close()
137
  return fig, anomaly_frames
138
 
 
139
  def plot_mse_histogram(mse_values, title, anomaly_threshold, color='blue'):
140
  plt.figure(figsize=(16, 3), dpi=300)
141
  fig, ax = plt.subplots(figsize=(16, 3))
@@ -155,6 +147,7 @@ def plot_mse_histogram(mse_values, title, anomaly_threshold, color='blue'):
155
  plt.close()
156
  return fig
157
 
 
158
  def plot_mse_heatmap(mse_values, title, df):
159
  plt.figure(figsize=(20, 3), dpi=300)
160
  fig, ax = plt.subplots(figsize=(20, 3))
@@ -199,6 +192,7 @@ def plot_posture(df, posture_scores, color='blue', anomaly_threshold=3):
199
  # Create a new dataframe for posture data
200
  posture_df = pd.DataFrame({'Frame': posture_frames, 'Score': posture_scores})
201
 
 
202
  posture_df = posture_df.merge(df[['Frame', 'Seconds']], on='Frame', how='inner')
203
 
204
  ax.scatter(posture_df['Seconds'], posture_df['Score'], color=color, alpha=0.3, s=5)
@@ -223,68 +217,37 @@ def plot_posture(df, posture_scores, color='blue', anomaly_threshold=3):
223
  plt.close()
224
  return fig
225
 
226
- def filter_mse_for_most_frequent_person(df, mse_embeddings, mse_posture, mse_voice, most_frequent_person_frames):
227
- # Ensure most_frequent_person_frames is a list
228
- if not isinstance(most_frequent_person_frames, (list, np.ndarray)):
229
- most_frequent_person_frames = [most_frequent_person_frames]
230
-
231
- # Ensure df and mse arrays have the same length
232
- min_length = min(len(df), len(mse_embeddings), len(mse_posture), len(mse_voice))
233
- df = df.iloc[:min_length].copy()
234
- mse_embeddings = mse_embeddings[:min_length]
235
- mse_posture = mse_posture[:min_length]
236
- mse_voice = mse_voice[:min_length]
237
-
238
- # Create a mask for the most frequent person frames
239
- mask = df['Frame'].isin(most_frequent_person_frames)
240
-
241
- # Pad mask to match the length of the video frames
242
- padded_mask = np.zeros(len(mse_embeddings), dtype=bool)
243
- padded_mask[:len(mask)] = mask
244
-
245
- # Apply the mask to filter the MSE arrays
246
- mse_embeddings_filtered = np.where(padded_mask, mse_embeddings, 0)
247
- mse_posture_filtered = np.where(padded_mask, mse_posture, 0)
248
- mse_voice_filtered = np.where(padded_mask, mse_voice, 0)
249
-
250
- return mse_embeddings_filtered, mse_posture_filtered, mse_voice_filtered
251
 
252
- def normalize_mse(mse):
253
- return mse / np.max(mse) if np.max(mse) > 0 else mse
 
 
 
254
 
255
- def pad_or_trim_array(arr, target_length):
256
- if len(arr) > target_length:
257
- return arr[:target_length]
258
- elif len(arr) < target_length:
259
- return np.pad(arr, (0, target_length - len(arr)), 'constant')
260
- return arr
261
 
262
- def create_heatmap(t, mse_embeddings_filtered, mse_posture_filtered, mse_voice_filtered, fps, total_frames, width):
263
- frame_index = min(int(t * fps), len(mse_embeddings_filtered) - 1)
264
 
265
- # Normalize the MSE values
266
- mse_embeddings_norm = normalize_mse(mse_embeddings_filtered)
267
- mse_posture_norm = normalize_mse(mse_posture_filtered)
268
- mse_voice_norm = normalize_mse(mse_voice_filtered)
269
-
270
- # Ensure all arrays have the correct length
271
- mse_embeddings_norm = pad_or_trim_array(mse_embeddings_norm, total_frames)
272
- mse_posture_norm = pad_or_trim_array(mse_posture_norm, total_frames)
273
- mse_voice_norm = pad_or_trim_array(mse_voice_norm, total_frames)
274
-
275
- # Create a 3D array for the heatmap (height, width, channels)
276
- heatmap_height = 3 # Assuming you want 3 rows in your heatmap
277
- heatmap_frame = np.zeros((heatmap_height, width, 3), dtype=np.uint8)
278
-
279
- # Fill the heatmap frame with color based on MSE values
280
- heatmap_frame[0, :, 0] = (mse_embeddings_norm[frame_index] * 255).astype(np.uint8) # Red channel for facial features
281
- heatmap_frame[1, :, 1] = (mse_posture_norm[frame_index] * 255).astype(np.uint8) # Green channel for body posture
282
- heatmap_frame[2, :, 2] = (mse_voice_norm[frame_index] * 255).astype(np.uint8) # Blue channel for voice
283
-
284
- return heatmap_frame
285
-
286
-
287
- def create_video_with_heatmap(video_path, df, mse_embeddings, mse_posture, mse_voice, output_folder, desired_fps, most_frequent_person_frames):
288
  print(f"Creating heatmap video. Output folder: {output_folder}")
289
 
290
  os.makedirs(output_folder, exist_ok=True)
@@ -308,32 +271,19 @@ def create_video_with_heatmap(video_path, df, mse_embeddings, mse_posture, mse_v
308
  np.arange(len(mse_posture)), mse_posture)
309
  mse_voice = np.interp(np.linspace(0, len(mse_voice) - 1, total_frames),
310
  np.arange(len(mse_voice)), mse_voice)
311
-
312
- print(f"Total frames: {total_frames}")
313
- print(f"mse_embeddings length: {len(mse_embeddings)}")
314
- print(f"mse_posture length: {len(mse_posture)}")
315
- print(f"mse_voice length: {len(mse_voice)}")
316
-
317
- # Filter MSE arrays for the most frequent person frames
318
- mse_embeddings_filtered, mse_posture_filtered, mse_voice_filtered = filter_mse_for_most_frequent_person(df, mse_embeddings, mse_posture, mse_voice, most_frequent_person_frames)
319
 
320
  def combine_video_and_heatmap(t):
321
  video_frame = video.get_frame(t)
322
- heatmap_frame = create_heatmap(t, mse_embeddings_filtered, mse_posture_filtered, mse_voice_filtered, video.fps, total_frames, width)
323
  heatmap_frame_resized = cv2.resize(heatmap_frame, (width, heatmap_frame.shape[0]))
324
-
325
- # Ensure both frames have the same number of channels
326
- if video_frame.shape[2] != heatmap_frame_resized.shape[2]:
327
- heatmap_frame_resized = cv2.cvtColor(heatmap_frame_resized, cv2.COLOR_RGB2BGR)
328
-
329
  combined_frame = np.vstack((video_frame, heatmap_frame_resized))
330
  return combined_frame
331
 
332
  final_clip = VideoClip(combine_video_and_heatmap, duration=video.duration)
333
  final_clip = final_clip.set_audio(video.audio)
334
 
335
- # Write the final video using x264 codec
336
- final_clip.write_videofile(heatmap_video_path, codec='libx264', audio_codec='aac', fps=video.fps, preset='medium', ffmpeg_params=['-crf', '23'])
337
 
338
  # Close the video clips
339
  video.close()
@@ -347,6 +297,8 @@ def create_video_with_heatmap(video_path, df, mse_embeddings, mse_posture, mse_v
347
  print(f"Failed to create heatmap video at: {heatmap_video_path}")
348
  return None
349
 
 
 
350
  def plot_correlation_heatmap(mse_embeddings, mse_posture, mse_voice):
351
  data = np.vstack((mse_embeddings, mse_posture, mse_voice)).T
352
  df = pd.DataFrame(data, columns=["Facial Features", "Body Posture", "Voice"])
@@ -357,4 +309,4 @@ def plot_correlation_heatmap(mse_embeddings, mse_posture, mse_voice):
357
  heatmap = sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
358
  plt.title('Correlation Heatmap of MSEs')
359
  plt.tight_layout()
360
- return plt.gcf()
 
11
  from moviepy.video.fx.all import resize
12
  from PIL import Image, ImageDraw, ImageFont
13
  from matplotlib.patches import Rectangle
14
+ from utils import seconds_to_timecode
15
+ from anomaly_detection import determine_anomalies
16
  from scipy import interpolate
17
+ import gradio as gr
18
  import os
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def plot_mse(df, mse_values, title, color='navy', time_threshold=3, anomaly_threshold=4):
21
  plt.figure(figsize=(16, 8), dpi=300)
22
  fig, ax = plt.subplots(figsize=(16, 8))
 
67
  ax.plot(segment_df['Seconds'], mean, color=color, linewidth=0.5)
68
  ax.fill_between(segment_df['Seconds'], mean - std, mean + std, color=color, alpha=0.1)
69
 
70
+ # Rest of the function remains the same
71
  median = np.median(mse_values)
72
  ax.axhline(y=median, color='black', linestyle='--', label='Median Baseline')
73
 
 
127
  plt.close()
128
  return fig, anomaly_frames
129
 
130
+
131
  def plot_mse_histogram(mse_values, title, anomaly_threshold, color='blue'):
132
  plt.figure(figsize=(16, 3), dpi=300)
133
  fig, ax = plt.subplots(figsize=(16, 3))
 
147
  plt.close()
148
  return fig
149
 
150
+
151
  def plot_mse_heatmap(mse_values, title, df):
152
  plt.figure(figsize=(20, 3), dpi=300)
153
  fig, ax = plt.subplots(figsize=(20, 3))
 
192
  # Create a new dataframe for posture data
193
  posture_df = pd.DataFrame({'Frame': posture_frames, 'Score': posture_scores})
194
 
195
+
196
  posture_df = posture_df.merge(df[['Frame', 'Seconds']], on='Frame', how='inner')
197
 
198
  ax.scatter(posture_df['Seconds'], posture_df['Score'], color=color, alpha=0.3, s=5)
 
217
  plt.close()
218
  return fig
219
 
220
+ def create_heatmap(t, mse_embeddings, mse_posture, mse_voice, video_fps, total_frames, video_width):
221
+ frame_count = int(t * video_fps)
222
+
223
+ # Normalize MSE values
224
+ mse_embeddings_norm = (mse_embeddings - np.min(mse_embeddings)) / (np.max(mse_embeddings) - np.min(mse_embeddings))
225
+ mse_posture_norm = (mse_posture - np.min(mse_posture)) / (np.max(mse_posture) - np.min(mse_posture))
226
+ mse_voice_norm = (mse_voice - np.min(mse_voice)) / (np.max(mse_voice) - np.min(mse_voice))
227
+
228
+ combined_mse = np.zeros((3, total_frames))
229
+ combined_mse[0] = mse_embeddings_norm
230
+ combined_mse[1] = mse_posture_norm
231
+ combined_mse[2] = mse_voice_norm
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
+ fig, ax = plt.subplots(figsize=(video_width / 250, 0.6))
234
+ ax.imshow(combined_mse, aspect='auto', cmap='Reds', vmin=0, vmax=1, extent=[0, total_frames, 0, 3])
235
+ ax.set_yticks([0.5, 1.5, 2.5])
236
+ ax.set_yticklabels(['Voice', 'Posture', 'Face'], fontsize=7)
237
+ ax.set_xticks([])
238
 
239
+ ax.axvline(x=frame_count, color='black', linewidth=3)
 
 
 
 
 
240
 
241
+ plt.tight_layout(pad=0.5)
 
242
 
243
+ canvas = FigureCanvas(fig)
244
+ canvas.draw()
245
+ heatmap_img = np.frombuffer(canvas.tostring_rgb(), dtype='uint8')
246
+ heatmap_img = heatmap_img.reshape(canvas.get_width_height()[::-1] + (3,))
247
+ plt.close(fig)
248
+ return heatmap_img
249
+
250
+ def create_video_with_heatmap(video_path, df, mse_embeddings, mse_posture, mse_voice, output_folder, desired_fps, largest_cluster):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  print(f"Creating heatmap video. Output folder: {output_folder}")
252
 
253
  os.makedirs(output_folder, exist_ok=True)
 
271
  np.arange(len(mse_posture)), mse_posture)
272
  mse_voice = np.interp(np.linspace(0, len(mse_voice) - 1, total_frames),
273
  np.arange(len(mse_voice)), mse_voice)
 
 
 
 
 
 
 
 
274
 
275
  def combine_video_and_heatmap(t):
276
  video_frame = video.get_frame(t)
277
+ heatmap_frame = create_heatmap(t, mse_embeddings, mse_posture, mse_voice, video.fps, total_frames, width)
278
  heatmap_frame_resized = cv2.resize(heatmap_frame, (width, heatmap_frame.shape[0]))
 
 
 
 
 
279
  combined_frame = np.vstack((video_frame, heatmap_frame_resized))
280
  return combined_frame
281
 
282
  final_clip = VideoClip(combine_video_and_heatmap, duration=video.duration)
283
  final_clip = final_clip.set_audio(video.audio)
284
 
285
+ # Write the final video
286
+ final_clip.write_videofile(heatmap_video_path, codec='libx264', audio_codec='aac', fps=video.fps)
287
 
288
  # Close the video clips
289
  video.close()
 
297
  print(f"Failed to create heatmap video at: {heatmap_video_path}")
298
  return None
299
 
300
+
301
+ # Function to create the correlation heatmap
302
  def plot_correlation_heatmap(mse_embeddings, mse_posture, mse_voice):
303
  data = np.vstack((mse_embeddings, mse_posture, mse_voice)).T
304
  df = pd.DataFrame(data, columns=["Facial Features", "Body Posture", "Voice"])
 
309
  heatmap = sns.heatmap(corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
310
  plt.title('Correlation Heatmap of MSEs')
311
  plt.tight_layout()
312
+ return plt.gcf()