How to extract images from video using Python OpenCV?

I ran into a situation last month where I had to pull individual frames from a recording for a presentation. The video was only 30 seconds long but contained 900 frames, and I needed specific ones to illustrate key points. Manually screenshotting was not an option.

OpenCV makes frame extraction straightforward. This article covers reading videos, extracting every frame or every Nth frame, saving them in multiple formats, and handling webcam streams. By the end, you will have a reusable script you can adapt for any video processing task.

TLDR

  • cv2.VideoCapture opens video files and webcam streams
  • Loop over frames with cam.read(), check the boolean return value
  • Skip frames with a counter modulo to extract every Nth frame
  • Save frames with cv2.imwrite, supports JPG, PNG, and other formats
  • cv2.waitKey and cam.release() clean up resources properly

What is frame extraction in OpenCV?

Frame extraction is the process of reading a video file and pulling out individual images (frames) one by one. OpenCV provides the VideoCapture class which handles this. It reads video files from disk or streams from a webcam, and the read() method returns both the frame data and a boolean indicating whether a frame was successfully retrieved.

Setting up OpenCV

Install OpenCV with pip before writing any code. The package name is opencv-python.


pip install opencv-python

Once installed, import it in your script with a standard import statement. The OpenCV module in Python handles reading, processing, and writing image and video data through a consistent API.


Package installed: opencv-python version 4.x.x

Extracting all frames from a video file

Pass the video filename to VideoCapture and it opens the file. Each call to read() advances to the next frame and returns a tuple of (success, frame). A while loop runs until read() returns False.


import cv2

cam = cv2.VideoCapture("video.mp4")
currentframe = 0

while True:
    ret, frame = cam.read()
    if not ret:
        break
    name = f"frame_{currentframe:04d}.jpg"
    cv2.imwrite(name, frame)
    currentframe += 1

cam.release()
print(f"Extracted {currentframe} frames")


Extracted 900 frames
Saved: frame_0000.jpg, frame_0001.jpg, ... frame_0899.jpg

The ret value from read() tells you whether the frame was successfully grabbed. Once there are no more frames to read, ret becomes False and the loop exits. The cv2.imwrite function saves each frame as a JPEG file. The frame counter formats each filename with zero-padding so the files sort correctly in a file explorer.

Extracting specific frames by interval or timestamp

Extracting every frame produces a lot of images. A 60-second video at 30 fps gives you 1800 frames. If you only need a subset, use a modulo check on the frame counter to save every Nth frame. Alternatively, set the position by timestamp using CAP_PROP_POS_MSEC.


import cv2

cam = cv2.VideoCapture("video.mp4")
frame_number = 0
saved = 0
skip = 10  # save every 10th frame

while True:
    ret, frame = cam.read()
    if not ret:
        break
    if frame_number % skip == 0:
        cv2.imwrite(f"frame_{saved:04d}.jpg", frame)
        saved += 1
    frame_number += 1

cam.release()
print(f"Read {frame_number} frames, saved {saved} images")


Read 900 frames, saved 90 images

For specific timestamps, use CAP_PROP_POS_MSEC before calling read(). The example below extracts frames at 1.0, 5.5, and 12.3 seconds into the video.


import cv2

cam = cv2.VideoCapture("video.mp4")
timestamps = [1.0, 5.5, 12.3]  # seconds

for i, t in enumerate(timestamps):
    cam.set(cv2.CAP_PROP_POS_MSEC, t * 1000)
    ret, frame = cam.read()
    if ret:
        cv2.imwrite(f"timestamp_{i}_{t}s.jpg", frame)

cam.release()


Saved: timestamp_0_1.0s.jpg, timestamp_1_5.5s.jpg, timestamp_2_12.3s.jpg

Adjusting the skip value changes the density. Set skip to 1 to save all frames, or 30 to save one frame per second from a 30 fps video. The FPS value from get(CAP_PROP_FPS) helps you convert between seconds and frame numbers if you prefer working with frame indices instead of millisecond offsets.

Saving frames in different formats

cv2.imwrite automatically detects the format from the file extension. JPEG compression is applied by default for .jpg files. PNG is useful when you need lossless quality for frames that will undergo further image processing tasks like edge detection.


import cv2

cam = cv2.VideoCapture("video.mp4")
saved = 0

while True:
    ret, frame = cam.read()
    if not ret:
        break
    cv2.imwrite(f"frame_{saved:04d}.jpg", frame)   # JPEG
    cv2.imwrite(f"frame_{saved:04d}.png", frame)  # PNG (lossless)
    saved += 1

cam.release()


Saved: frame_0000.jpg (28 KB), frame_0000.png (210 KB)
Saved: frame_0001.jpg (27 KB), frame_0001.png (208 KB)

PNG files are significantly larger because they store pixel data without compression. JPEG files are much smaller but lose some quality each time they are re-saved. Use PNG when the extracted frames will be used for further image processing or analysis where quality matters.

Capturing frames from a webcam

VideoCapture accepts an integer in addition to a filename. Passing 0 opens the default webcam on your system. This lets you capture frames from a live camera stream for real-time image processing applications like color detection.

<pre class="wp-block-syntaxhighlighter-code">
import cv2

cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

frame_count = 0
max_frames = 50

while frame_count < max_frames:
    ret, frame = cam.read()
    if not ret:
        print("Camera read error")
        break
    cv2.imwrite(f"webcam_{frame_count:04d}.jpg", frame)
    frame_count += 1
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cam.release()
cv2.destroyAllWindows()
print(f"Captured {frame_count} frames from webcam")
</pre>

Captured 50 frames from webcam
Webcam frames saved as: webcam_0000.jpg ... webcam_0049.jpg

The CAP_PROP settings configure resolution before capturing begins. The waitKey call polls for a keypress and lets you quit early by pressing q. The destroyAllWindows call closes any display windows created by imshow if you add a preview window later.

Frame by Frame OpenCV - extracted video frames saved as images

FAQ

Q: cv2.imwrite returns False and does not save the file.

The most common cause is that the frame data is empty or the output directory does not exist. Check that VideoCapture successfully opened the file with cam.isOpened() before calling imwrite. Also verify the folder path exists.

Q: The video opens but frames come back as empty arrays.

Some video codecs do not decode properly in OpenCV on certain systems. Installing opencv-python-headless instead of the full opencv-python package can resolve codec issues on headless servers. For local development, installing the correct video codecs (e.g., ffmpeg) on the system often fixes playback.

Q: How do I convert the extracted frames back into a video?

Use VideoWriter to create a video object with a target codec, frame size, and fps. Loop over your saved image files, read each one with imread, and write it to the VideoWriter object. You can find a full example in the moviepy module tutorial which covers video processing workflows in Python.

Q: Can I extract frames as PNG with transparency?

OpenCV loads video frames as BGR numpy arrays with three channels. PNG files support transparency through a fourth alpha channel, but video frames do not have alpha data by default. The alpha channel would be all-opaque (255) if you force a four-channel write, which does not provide any useful transparency information.

I have used frame extraction in several projects beyond presentations. Extracting frames from screen recordings helped me debug a GUI automation script. Pulling every 300th frame from a time-lapse gave me a manageable sample set for a computer vision training task. The same pattern applies regardless of the source video.

Isha Bansal
Isha Bansal

Hey there stranger!
Do check out my blogs if you are a keen learner!

Hope you like them!

Articles: 185