How to Extract Frames from Video
Sep 12, 2026 • 8 min read
Three ways to do it — pick the one that fits your workflow. All free, no watermarks, no account needed.
⚡ Quickest: Online Tool (This Site)
- Open Video Frame Extractor
- Drop your video (MP4, MOV, WebM — up to 2 GB)
- Choose FPS (1–60) and format (JPG/WebP/PNG)
- Click Extract → Download ZIP
Runs entirely in your browser via WebCodecs. No upload, no server, works offline after first load.
Method 1: Free Online Tool (Recommended)
Step-by-Step
1 Open the Extractor
Go to videotoimagesequence.online/video-frame-extractor. Works in Chrome, Firefox, Edge, Safari.
2 Load Your Video
- Drag & drop, or click "Choose File"
- Supported: MP4 (H.264), MOV (H.264), WebM (VP8/VP9)
- Max: ~2 GB (browser memory limit)
- HEVC/ProRes? Transcode to H.264 first (see codec guide)
3 Configure Extraction
Tip: See FPS decision guide for task-specific recommendations.
4 Extract & Download
- Click "Extract Frames" — progress bar shows frames processed
- Frames zip automatically when complete
- Download ZIP → unzip → frames named
frame_000001.jpg
Advanced Features
⏱ Exact Timestamp Extractor
Need frames at specific times? Use Exact Timestamp Extractor — enter timestamps (e.g., 00:01:30.500) and get precise frames.
🎞 Image Sequence Export
For VFX/Blender/After Effects: Video to Image Sequence tool exports numbered sequences with padding (frame_0001, frame_0002...).
🤖 AI Dataset Export
For ML training: Video Frames for AI Datasets — preset FPS by task, auto-train/val/test split structure.
Method 2: FFmpeg (Command Line / Automation)
Best for: batch processing, CI/CD pipelines, servers, large videos, automation.
Basic Extraction
# Extract all frames (matches video FPS) ffmpeg -i input.mp4 frames/frame_%06d.jpg # Extract at specific FPS (e.g., 5 FPS) ffmpeg -i input.mp4 -vf fps=5 frames/frame_%06d.jpg # Extract with custom quality (1=best, 31=worst for JPG) ffmpeg -i input.mp4 -vf fps=5 -q:v 2 frames/frame_%06d.jpgFormat Options
# JPG (default) ffmpeg -i input.mp4 -vf fps=5 -q:v 2 frames/frame_%06d.jpg # PNG (lossless) ffmpeg -i input.mp4 -vf fps=5 frames/frame_%06d.png # WebP (modern, smaller) ffmpeg -i input.mp4 -vf fps=5 -c:v libwebp -quality 90 frames/frame_%06d.webp # BMP / TIFF (rare, lossless) ffmpeg -i input.mp4 -vf fps=5 frames/frame_%06d.bmpTime Range Extraction
# Start at 1:30, extract 30 seconds at 10 FPS ffmpeg -ss 00:01:30 -t 30 -i input.mp4 -vf fps=10 frames/frame_%06d.jpg # Extract single frame at exact timestamp ffmpeg -ss 00:02:15.500 -i input.mp4 -vframes 1 frame_exact.jpgBatch Process Multiple Videos
# Windows (PowerShell)
Get-ChildItem *.mp4 | ForEach-Object {'{'}
$name = $_.BaseName
ffmpeg -i $_.Name -vf fps=5 "$name/frame_%06d.jpg"
{'}'}
# Linux/macOS (Bash)
for f in *.mp4; do
name="${f%.*}"
mkdir -p "$name"
ffmpeg -i "$f" -vf fps=5 "$name/frame_%06d.jpg"
doneMethod 3: Python (OpenCV / MoviePy)
Best for: ML pipelines, data loading, custom preprocessing, integration with training code.
OpenCV (Fast, No Dependencies Beyond opencv-python)
import cv2
import os
def extract_frames_opencv(video_path, output_dir, fps=5, format='jpg', quality=90):
os.makedirs(output_dir, exist_ok=True)
cap = cv2.VideoCapture(video_path)
video_fps = cap.get(cv2.CAP_PROP_FPS)
frame_interval = int(video_fps / fps)
count = 0
saved = 0
while True:
ret, frame = cap.read()
if not ret:
break
if count % frame_interval == 0:
name = f"frame_{saved:06d}.{format}"
if format == 'jpg':
cv2.imwrite(os.path.join(output_dir, name), frame, [cv2.IMWRITE_JPEG_QUALITY, quality])
elif format == 'png':
cv2.imwrite(os.path.join(output_dir, name), frame)
elif format == 'webp':
cv2.imwrite(os.path.join(output_dir, name), frame, [cv2.IMWRITE_WEBP_QUALITY, quality])
saved += 1
count += 1
cap.release()
print(f"Extracted {saved} frames to {output_dir}")
# Usage
extract_frames_opencv('video.mp4', 'frames/', fps=5, format='jpg', quality=90)MoviePy (Higher Level, Handles More Codecs)
from moviepy.editor import VideoFileClip
import os
def extract_frames_moviepy(video_path, output_dir, fps=5, format='jpg'):
os.makedirs(output_dir, exist_ok=True)
clip = VideoFileClip(video_path)
duration = clip.duration
# Sample at regular intervals
times = [i / fps for i in range(int(duration * fps) + 1)]
for i, t in enumerate(times):
if t > duration:
break
frame = clip.get_frame(t)
name = f"frame_{i:06d}.{format}"
from PIL import Image
Image.fromarray(frame).save(os.path.join(output_dir, name), quality=90 if format == 'jpg' else None)
clip.close()
print(f"Extracted {len(times)} frames to {output_dir}")
# Usage
extract_frames_moviepy('video.mp4', 'frames/', fps=5, format='jpg')Comparison: Which Method to Use?
| Criteria | Online Tool | FFmpeg | Python |
|---|---|---|---|
| Setup | Zero | Install once | pip install |
| Max Video Size | ~2 GB | Unlimited | RAM dependent |
| Batch/Automation | Manual | Excellent | Excellent |
| Codecs Supported | H.264, VP8/9 | All | Most (via FFmpeg) |
| Privacy | Local only | Local only | Local only |
| Preview/Seek | Visual | CLI only | Programmatic |
| Best For | One-offs, quick jobs | Batch, servers, CI | ML pipelines, custom logic |
Troubleshooting
❌ "File too large" / Browser crashes
Video exceeds browser memory. Fix: Split video (ffmpeg -i input.mp4 -c copy -segment_time 300 -f segment part_%03d.mp4) or use FFmpeg/Python.
❌ "Codec not supported" (HEVC/ProRes)
Browser can't decode. Fix: Transcode first: ffmpeg -i input.mov -c:v libx264 -crf 18 -preset fast output.mp4
❌ Output frames are black/green/corrupted
Variable frame rate or seek issue. Fix: Force CFR: ffmpeg -i input.mp4 -vsync cfr -c:v libx264 fixed.mp4 then extract.
❌ Wrong number of frames extracted
FPS math mismatch. Fix: Check source FPS: ffprobe -v error -select_streams v -show_entries stream=r_frame_rate -of csv=p=0 input.mp4
❌ ZIP download fails / incomplete
Too many frames for browser ZIP. Fix: Lower FPS, use WebP, or extract in chunks with FFmpeg.