Created
February 28, 2026 06:19
-
-
Save salmanhiro/afa42e418ce3ec0e8cae29e87f6ac164 to your computer and use it in GitHub Desktop.
frame_extract.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import cv2 | |
| import random | |
| import argparse | |
| def extract_random_interval_frames( | |
| video_path: str, | |
| output_dir: str, | |
| min_interval_sec: float = 2.0, | |
| max_interval_sec: float = 8.0, | |
| max_frames: int | None = None, | |
| jpeg_quality: int = 95 | |
| ) -> None: | |
| """ | |
| Extract frames from a video using randomized time intervals. | |
| Parameters | |
| ---------- | |
| video_path : str | |
| Path to input video. | |
| output_dir : str | |
| Folder where extracted frames will be saved. | |
| min_interval_sec : float | |
| Minimum random jump in seconds between extracted frames. | |
| max_interval_sec : float | |
| Maximum random jump in seconds between extracted frames. | |
| max_frames : int | None | |
| Maximum number of frames to save. If None, continue until end of video. | |
| jpeg_quality : int | |
| JPEG quality for saved frames (0-100). | |
| """ | |
| if min_interval_sec <= 0 or max_interval_sec <= 0: | |
| raise ValueError("Intervals must be positive.") | |
| if min_interval_sec > max_interval_sec: | |
| raise ValueError("min_interval_sec must be <= max_interval_sec.") | |
| os.makedirs(output_dir, exist_ok=True) | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| raise RuntimeError(f"Could not open video: {video_path}") | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if fps <= 0 or total_frames <= 0: | |
| cap.release() | |
| raise RuntimeError("Could not read FPS or total frame count from video.") | |
| duration_sec = total_frames / fps | |
| print(f"Video: {video_path}") | |
| print(f"FPS: {fps:.2f}") | |
| print(f"Total frames: {total_frames}") | |
| print(f"Duration: {duration_sec:.2f} sec") | |
| current_time_sec = 0.0 | |
| saved_count = 0 | |
| while current_time_sec < duration_sec: | |
| frame_idx = int(current_time_sec * fps) | |
| cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx) | |
| success, frame = cap.read() | |
| if not success: | |
| print(f"Stopping: could not read frame at {current_time_sec:.2f}s") | |
| break | |
| out_name = f"frame_{saved_count:05d}_t{current_time_sec:08.2f}s.jpg" | |
| out_path = os.path.join(output_dir, out_name) | |
| ok = cv2.imwrite( | |
| out_path, | |
| frame, | |
| [cv2.IMWRITE_JPEG_QUALITY, jpeg_quality] | |
| ) | |
| if not ok: | |
| print(f"Warning: failed to save {out_path}") | |
| else: | |
| print(f"Saved: {out_path}") | |
| saved_count += 1 | |
| if max_frames is not None and saved_count >= max_frames: | |
| print(f"Reached max_frames={max_frames}") | |
| break | |
| jump = random.uniform(min_interval_sec, max_interval_sec) | |
| current_time_sec += jump | |
| cap.release() | |
| print(f"Done. Saved {saved_count} frames to: {output_dir}") | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description="Extract frames from a video at randomized time intervals." | |
| ) | |
| parser.add_argument("video_path", type=str, help="Path to input video") | |
| parser.add_argument("output_dir", type=str, help="Folder to save frames") | |
| parser.add_argument( | |
| "--min-sec", | |
| type=float, | |
| default=2.0, | |
| help="Minimum random interval in seconds" | |
| ) | |
| parser.add_argument( | |
| "--max-sec", | |
| type=float, | |
| default=8.0, | |
| help="Maximum random interval in seconds" | |
| ) | |
| parser.add_argument( | |
| "--max-frames", | |
| type=int, | |
| default=None, | |
| help="Maximum number of frames to extract" | |
| ) | |
| parser.add_argument( | |
| "--seed", | |
| type=int, | |
| default=None, | |
| help="Random seed for reproducibility" | |
| ) | |
| parser.add_argument( | |
| "--jpeg-quality", | |
| type=int, | |
| default=95, | |
| help="JPEG quality (0-100)" | |
| ) | |
| args = parser.parse_args() | |
| if args.seed is not None: | |
| random.seed(args.seed) | |
| extract_random_interval_frames( | |
| video_path=args.video_path, | |
| output_dir=args.output_dir, | |
| min_interval_sec=args.min_sec, | |
| max_interval_sec=args.max_sec, | |
| max_frames=args.max_frames, | |
| jpeg_quality=args.jpeg_quality | |
| ) | |
| if __name__ == "__main__": | |
| main() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage i.e
python frame_extract.py Video/ucl.mp4 ucl --min-sec 3 --max-sec 10 --max-frames 100 --seed 42