aideepfake / scripts /frame_extractor.py
GitHub Action
Deploy backend to Hugging Face Space
887f5f0
Raw
History Blame Contribute Delete
2.52 kB
import cv2
import os
import numpy as np
class FrameExtractor:
"""
Extracts frames from video files at regular intervals using OpenCV.
"""
def __init__(self, max_frames: int = 5):
self.max_frames = max_frames
def extract_frames(self, video_path: str) -> list[dict]:
"""
Extracts up to max_frames from the video at even intervals.
Returns a list of dicts containing the frame index, timestamp, and RGB image array.
"""
if not os.path.exists(video_path):
raise FileNotFoundError(f"Video file not found: {video_path}")
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise ValueError(f"Could not open video file: {video_path}")
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
if total_frames <= 0 or fps <= 0:
# Fallback for video streams/files without index information
fps = 25.0
total_frames = 100
duration = total_frames / fps
# Determine step size to extract max_frames
num_to_extract = min(self.max_frames, total_frames)
if num_to_extract <= 1:
indices = [0]
else:
indices = np.linspace(0, total_frames - 1, num_to_extract, dtype=int).tolist()
frames = []
for i, idx in enumerate(indices):
cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
ret, frame = cap.read()
if not ret or frame is None:
continue
# Convert to RGB (OpenCV uses BGR by default)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Scale down large frames to prevent excessive memory/CPU usage
height, width = frame_rgb.shape[:2]
max_dim = 960
if max(height, width) > max_dim:
scale = max_dim / max(height, width)
new_width = int(width * scale)
new_height = int(height * scale)
frame_rgb = cv2.resize(frame_rgb, (new_width, new_height), interpolation=cv2.INTER_AREA)
width, height = new_width, new_height
timestamp = idx / fps
frames.append({
"frame_idx": int(idx),
"timestamp": round(timestamp, 2),
"image": frame_rgb,
"width": width,
"height": height
})
cap.release()
return frames