Spaces:
Sleeping
Sleeping
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| from typing import List | |
| import os | |
| def extract_frames(video_path: str, num_frames: int = 10) -> List[Image.Image]: | |
| """ | |
| Extracts a fixed number of evenly spaced frames from a video file. | |
| Args: | |
| video_path: Path to the video file | |
| num_frames: Number of frames to extract | |
| Returns: | |
| List of PIL Images extracted from the video | |
| Raises: | |
| ValueError: If video cannot be opened or is invalid | |
| """ | |
| 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}") | |
| try: | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if total_frames <= 0: | |
| raise ValueError("Video contains no frames or duration cannot be determined") | |
| # If video has fewer frames than requested, take all available frames | |
| actual_num_frames = min(num_frames, total_frames) | |
| # Calculate frame indices to extract (evenly spaced) | |
| indices = np.linspace(0, total_frames - 1, actual_num_frames, dtype=int) | |
| frames = [] | |
| for idx in indices: | |
| # Set the frame position | |
| cap.set(cv2.CAP_PROP_POS_FRAMES, idx) | |
| ret, frame = cap.read() | |
| if ret: | |
| # OpenCV returns BGR, convert to RGB for PIL | |
| frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| pil_image = Image.fromarray(frame_rgb) | |
| frames.append(pil_image) | |
| else: | |
| print(f"[Warning] Failed to read frame {idx} from {video_path}") | |
| if not frames: | |
| raise ValueError("Failed to extract any valid frames from the video") | |
| return frames | |
| finally: | |
| cap.release() | |