Anish commited on
Commit
8bdb51c
·
1 Parent(s): edd550f

[Feature Updated] > Updated anomaly_gif_maker a lot, to be able to precisely extract frames from the video, where the model and pipeline think that part is AI.

Browse files
backend/app/ai/video/anomaly_gif_maker.py CHANGED
@@ -20,30 +20,21 @@ def generate_anomaly_gif(frames: List[np.ndarray], center_idx: int) -> str:
20
  end_idx = min(len(frames), center_idx + 10)
21
 
22
  gif_frames = []
 
 
23
 
24
  for i in range(start_idx, end_idx):
25
  frame = frames[i]
26
 
27
- # 1. Take the grayscale X-Ray of the current frame
28
  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
29
- # 2. Extract sharp structural edges
30
  laplacian = cv2.Laplacian(gray, cv2.CV_64F)
31
  abs_laplacian = np.absolute(laplacian)
32
-
33
- # 3. Normalize to force the highest anomaly to glow at maximum brightness (255)
34
  laplacian_8u = cv2.normalize(abs_laplacian, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
35
- # 4. Blur it to turn sharp noise into soft glowing clouds
36
  heatmap_blurred = cv2.GaussianBlur(laplacian_8u, (15, 15), 0)
37
-
38
- # 5. Filter out natural background camera noise (anything under 70 brightness)
39
  _, heatmap_mask = cv2.threshold(heatmap_blurred, 70, 255, cv2.THRESH_TOZERO)
40
- # 6. Apply Jet Thermal Colors (Blue = natural, Red = AI Glitch)
41
  colored_heatmap = cv2.applyColorMap(heatmap_mask, cv2.COLORMAP_JET)
42
-
43
- # 7. Apply the thermal glow onto a copy of the video frame
44
  heatmap_overlay = cv2.addWeighted(frame.copy(), 0.5, colored_heatmap, 0.7, 0)
45
 
46
- # 8. Find the contours (puddles) of the highest glowing areas and draw Red Boxes
47
  _, thresh = cv2.threshold(laplacian_8u, 100, 255, cv2.THRESH_BINARY)
48
  contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
49
  contours = sorted(contours, key=cv2.contourArea, reverse=True)[:3]
@@ -53,35 +44,28 @@ def generate_anomaly_gif(frames: List[np.ndarray], center_idx: int) -> str:
53
  x, y, w, h = cv2.boundingRect(contour)
54
  cv2.rectangle(heatmap_overlay, (x, y), (x+w, y+h), (0, 0, 255), 2)
55
 
56
- # --- CREATE THE SIDE-BY-SIDE SPLIT SCREEN ---
57
-
58
- # 9. Resize both halves by 50% so the final GIF file size stays small
59
  h, w = frame.shape[:2]
60
  small_original = cv2.resize(frame, (w//2, h//2))
61
  small_heatmap = cv2.resize(heatmap_overlay, (w//2, h//2))
62
 
63
- # 10. Add clear text labels to the top of both screens
64
  cv2.putText(small_original, "ORIGINAL", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
65
  cv2.putText(small_heatmap, "AI RADIANCE MAP", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
66
 
67
- # 11. Add an extra flashing text warning when it reaches the absolute worst frame
 
68
  if i == center_idx:
69
  cv2.putText(small_heatmap, "PEAK GLITCH", (10, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
 
 
 
 
70
 
71
- # 12. Mathematically glue the two images together side-by-side using axis=1 (horizontal)
72
  combined_frame = np.concatenate((small_original, small_heatmap), axis=1)
73
-
74
- # 13. Convert from BGR back to RGB before saving so the GIF colors aren't inverted
75
  rgb_frame = cv2.cvtColor(combined_frame, cv2.COLOR_BGR2RGB)
76
  gif_frames.append(rgb_frame)
77
 
78
- # 13b. If this is the absolute peak glitch, append it 8 extra times to create a 1.2-second "Freeze-Frame" pause!
79
- if i == center_idx:
80
- for _ in range(8):
81
- gif_frames.append(rgb_frame)
82
-
83
- # 14. Synthesize the final GIF animation (Slowed down to ~6.5fps for better readability, and loop=0 for infinite looping)
84
- imageio.mimsave(save_path, gif_frames, format='GIF', duration=5, loop=0)
85
 
86
  return save_path
87
 
 
20
  end_idx = min(len(frames), center_idx + 10)
21
 
22
  gif_frames = []
23
+ # Create a list to track exactly how many seconds EVERY individual frame stays on screen
24
+ frame_durations = []
25
 
26
  for i in range(start_idx, end_idx):
27
  frame = frames[i]
28
 
 
29
  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
30
  laplacian = cv2.Laplacian(gray, cv2.CV_64F)
31
  abs_laplacian = np.absolute(laplacian)
 
 
32
  laplacian_8u = cv2.normalize(abs_laplacian, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
 
33
  heatmap_blurred = cv2.GaussianBlur(laplacian_8u, (15, 15), 0)
 
 
34
  _, heatmap_mask = cv2.threshold(heatmap_blurred, 70, 255, cv2.THRESH_TOZERO)
 
35
  colored_heatmap = cv2.applyColorMap(heatmap_mask, cv2.COLORMAP_JET)
 
 
36
  heatmap_overlay = cv2.addWeighted(frame.copy(), 0.5, colored_heatmap, 0.7, 0)
37
 
 
38
  _, thresh = cv2.threshold(laplacian_8u, 100, 255, cv2.THRESH_BINARY)
39
  contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
40
  contours = sorted(contours, key=cv2.contourArea, reverse=True)[:3]
 
44
  x, y, w, h = cv2.boundingRect(contour)
45
  cv2.rectangle(heatmap_overlay, (x, y), (x+w, y+h), (0, 0, 255), 2)
46
 
 
 
 
47
  h, w = frame.shape[:2]
48
  small_original = cv2.resize(frame, (w//2, h//2))
49
  small_heatmap = cv2.resize(heatmap_overlay, (w//2, h//2))
50
 
 
51
  cv2.putText(small_original, "ORIGINAL", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
52
  cv2.putText(small_heatmap, "AI RADIANCE MAP", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
53
 
54
+ # --- THE FIX ---
55
+ # If this is the peak glitch, assign it a massive 3-Second duration!
56
  if i == center_idx:
57
  cv2.putText(small_heatmap, "PEAK GLITCH", (10, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
58
+ frame_durations.append(3.0) # Pause for 3.0 real seconds!
59
+ else:
60
+ # Normal frames zip by at fast normal speed (0.15 seconds per frame)
61
+ frame_durations.append(0.15)
62
 
 
63
  combined_frame = np.concatenate((small_original, small_heatmap), axis=1)
 
 
64
  rgb_frame = cv2.cvtColor(combined_frame, cv2.COLOR_BGR2RGB)
65
  gif_frames.append(rgb_frame)
66
 
67
+ # We pass our explicit list of durations to tell the GIF EXACTLY how long to hold each frame
68
+ imageio.mimsave(save_path, gif_frames, format='GIF', duration=frame_durations, loop=0)
 
 
 
 
 
69
 
70
  return save_path
71