anomaly / modules /grid_builder.py
Anomaly
update dependencies
84669a3
import os
import cv2
import numpy as np
import math
from modules.video_queue import JobStatus
def assemble_grid_video(grid_job, child_jobs, settings):
"""
Assembles a grid video from the results of child jobs.
"""
print(f"Starting grid assembly for job {grid_job.id}")
output_dir = settings.get("output_dir", "outputs")
os.makedirs(output_dir, exist_ok=True)
video_paths = [child.result for child in child_jobs if child.status == JobStatus.COMPLETED and child.result and os.path.exists(child.result)]
if not video_paths:
print(f"No valid video paths found for grid job {grid_job.id}")
return None
print(f"Found {len(video_paths)} videos for grid assembly.")
# Determine grid size (e.g., 2x2, 3x3)
num_videos = len(video_paths)
grid_size = math.ceil(math.sqrt(num_videos))
# Get video properties from the first video
try:
cap = cv2.VideoCapture(video_paths[0])
if not cap.isOpened():
raise IOError(f"Cannot open video file: {video_paths[0]}")
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
cap.release()
except Exception as e:
print(f"Error getting video properties from {video_paths[0]}: {e}")
return None
output_filename = os.path.join(output_dir, f"grid_{grid_job.id}.mp4")
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video_writer = cv2.VideoWriter(output_filename, fourcc, fps, (width * grid_size, height * grid_size))
caps = [cv2.VideoCapture(p) for p in video_paths]
while True:
frames = []
all_frames_read = True
for cap in caps:
ret, frame = cap.read()
if ret:
frames.append(frame)
else:
# If one video ends, stop processing
all_frames_read = False
break
if not all_frames_read or not frames:
break
# Create a blank canvas for the grid
grid_frame = np.zeros((height * grid_size, width * grid_size, 3), dtype=np.uint8)
# Place frames into the grid
for i, frame in enumerate(frames):
row = i // grid_size
col = i % grid_size
grid_frame[row*height:(row+1)*height, col*width:(col+1)*width] = frame
video_writer.write(grid_frame)
for cap in caps:
cap.release()
video_writer.release()
print(f"Grid video saved to {output_filename}")
return output_filename