Skip to content

Instantly share code, notes, and snippets.

@salmanhiro
Created February 28, 2026 06:19
Show Gist options
  • Select an option

  • Save salmanhiro/afa42e418ce3ec0e8cae29e87f6ac164 to your computer and use it in GitHub Desktop.

Select an option

Save salmanhiro/afa42e418ce3ec0e8cae29e87f6ac164 to your computer and use it in GitHub Desktop.
frame_extract.py
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()
@salmanhiro
Copy link
Author

Usage i.e python frame_extract.py Video/ucl.mp4 ucl --min-sec 3 --max-sec 10 --max-frames 100 --seed 42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment