Ora

How to convert images to video in Python?

Published in Python Video Processing 8 mins read

Converting images to video in Python is a straightforward process primarily using the OpenCV (Open Source Computer Vision Library) and Pillow (PIL Fork) libraries. This allows you to combine a sequence of static images into a dynamic video file, useful for time-lapses, animations, or photo slideshows.

Getting Started: Essential Libraries and Setup

To begin, you'll need to install the necessary libraries. OpenCV (aliased as cv2 in Python) handles video writing, while Pillow (PIL) is excellent for image manipulation, such as resizing. The os module helps manage file paths.

pip install opencv-python pillow

Step-by-Step Guide to Image-to-Video Conversion

The core process involves reading each image, ensuring it's the correct size, and then writing it sequentially to a video file.

1. Import Required Libraries

Start by importing os for directory operations, PIL (Pillow) for image processing, and cv2 (OpenCV) for video creation.

import os
from PIL import Image
import cv2

2. Set Up the Image Folder and Gather Images

Organize your images in a dedicated folder. It's crucial that your images are named in a sequence that reflects the desired order in the video (e.g., image001.jpg, image002.jpg).

  • Specify the input directory: This is where your images are stored.
  • Specify the output video path: Define the name and location for your new video file.
image_folder = 'path/to/your/images' # Replace with your image directory
video_name = 'output_video.mp4'

Next, gather all image file paths and sort them to ensure they are processed in the correct order.

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg") or img.endswith(".png")]
images.sort() # Ensure correct order, e.g., 'image1.jpg', 'image2.jpg'

3. Determine Video Dimensions and Frame Rate (FPS)

For a smooth video, all frames must have the same dimensions. You can either set a fixed target dimension or compute the average dimensions from your input images to maintain aspect ratios or prevent excessive cropping.

  • Compute average or target dimensions: If images have varying sizes, resize them to a consistent dimension. A common approach is to take the dimensions of the first image or calculate an average.
  • Define Frame Rate (FPS): This determines how many images are displayed per second. Common values include 24, 25, or 30 FPS.
# Option 1: Use the dimensions of the first image
first_image_path = os.path.join(image_folder, images[0])
frame = cv2.imread(first_image_path)
height, width, layers = frame.shape
print(f"Using dimensions from first image: {width}x{height}")

# Option 2: Compute average dimensions (more robust for varied inputs)
# In this approach, you'd iterate through images, get their sizes,
# calculate an average width and height, then use those for resizing.
# For simplicity, we'll proceed with Option 1 in the example below,
# but resizing all images to an average or a specific target size is good practice.

fps = 20 # Frames per second

4. Initialize Video Writer

OpenCV's cv2.VideoWriter object is used to write frames to a video file. You need to specify the output filename, the codec, FPS, and frame size.

  • Codec: Defines how the video is compressed. XVID (for AVI), MP4V (for MP4), or H264 are common. fourcc is a 4-character code.
  • Output Dimensions: Must match the dimensions you will resize your images to.
# Define the codec (e.g., 'mp4v' for MP4)
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # Codec for MP4
out = cv2.VideoWriter(video_name, fourcc, fps, (width, height))

5. Process Images and Write Frames to Video

Loop through your sorted image list. For each image:

  • Load the image: Use cv2.imread().
  • Resize the image: Ensure it matches the width and height specified for the VideoWriter. This is a critical step for consistent video output.
  • Write the frame: Use out.write().
print("Converting images to video...")
for image_file in images:
    img_path = os.path.join(image_folder, image_file)
    frame = cv2.imread(img_path)

    if frame is None:
        print(f"Warning: Could not read image {image_file}. Skipping.")
        continue

    # Resize image to the target dimensions if necessary
    if frame.shape[1] != width or frame.shape[0] != height:
        frame = cv2.resize(frame, (width, height))

    out.write(frame)

print(f"Video '{video_name}' created successfully.")

6. Release the Video Writer

After all images have been processed, it's essential to release the VideoWriter object to finalize and save the video file, freeing up resources.

out.release()
cv2.destroyAllWindows() # Close any OpenCV windows if opened

7. Verify the Created Video (Optional)

You can optionally open and play the generated video file using a media player or even within Python using cv2.imshow() to confirm it was created correctly. This step corresponds to the "Display the video" mentioned in some guides.

# Optional: Play the created video
# cap = cv2.VideoCapture(video_name)
# if not cap.isOpened():
#     print("Error: Could not open video for playback.")
# else:
#     print("Playing video...")
#     while cap.isOpened():
#         ret, frame = cap.read()
#         if not ret:
#             break
#         cv2.imshow('Video Playback', frame)
#         if cv2.waitKey(25) & 0xFF == ord('q'): # Press 'q' to quit
#             break
#     cap.release()
#     cv2.destroyAllWindows()

Complete Code Example

Here's a consolidated example:

import os
from PIL import Image
import cv2

def convert_images_to_video(image_folder, output_video_name, fps=20):
    """
    Converts a sequence of images from a folder into a video file.

    Args:
        image_folder (str): Path to the directory containing images.
        output_video_name (str): Name of the output video file (e.g., 'my_video.mp4').
        fps (int, optional): Frames per second for the video. Defaults to 20.
    """
    images = [img for img in os.listdir(image_folder) if img.lower().endswith(('.png', '.jpg', '.jpeg'))]
    images.sort() # Ensure natural sorting for chronological order

    if not images:
        print(f"No images found in {image_folder}. Exiting.")
        return

    # Read the first image to get dimensions
    first_image_path = os.path.join(image_folder, images[0])
    first_frame = cv2.imread(first_image_path)
    if first_frame is None:
        print(f"Error: Could not read the first image {first_image_path}. Check path and file integrity.")
        return

    height, width, layers = first_frame.shape
    size = (width, height)
    print(f"Video dimensions set to: {width}x{height} (from first image)")

    # Define the codec and create VideoWriter object
    # For MP4, 'mp4v' or 'XVID' can be used. On some systems, 'MJPG' for .avi is more compatible.
    fourcc = cv2.VideoWriter_fourcc(*'mp4v') # H.264 is common for MP4, but 'mp4v' is broadly supported.
    out = cv2.VideoWriter(output_video_name, fourcc, fps, size)

    if not out.isOpened():
        print(f"Error: Could not open video writer for {output_video_name}. Check codec support or file path.")
        return

    print(f"Starting video conversion with {len(images)} images at {fps} FPS...")
    for i, image_file in enumerate(images):
        img_path = os.path.join(image_folder, image_file)
        frame = cv2.imread(img_path)

        if frame is None:
            print(f"Warning: Could not read image {image_file}. Skipping.")
            continue

        # Resize the frame to match the target video size
        if frame.shape[1] != width or frame.shape[0] != height:
            frame = cv2.resize(frame, size, interpolation=cv2.INTER_AREA)

        out.write(frame)
        if (i + 1) % 100 == 0:
            print(f"Processed {i + 1}/{len(images)} images...")

    out.release()
    cv2.destroyAllWindows()
    print(f"Video '{output_video_name}' successfully created!")

# --- Example Usage ---
# Make sure you have a folder named 'my_images' with .jpg or .png files in your script's directory
# or provide a full path.
# Example: Create dummy images for testing
# for i in range(1, 11):
#     img = Image.new('RGB', (640, 480), color = (i*20, 100, 200))
#     img.save(f'my_images/frame_{i:03d}.jpg')

# convert_images_to_video('my_images', 'my_output_video.mp4', fps=15)

Customization and Advanced Tips

Feature Description How to Customize
Frame Rate Controls the speed of the video (images per second). Adjust the fps parameter in cv2.VideoWriter.
Output Codec Determines the video compression format (e.g., H.264, MPEG-4). Change the fourcc code (e.g., *'XVID' for .avi, *'mp4v' for .mp4).
Image Sorting Ensures images appear in the correct chronological order. Use list.sort() with natural sorting logic (key=lambda f: int(re.sub('\D', '', f))) for complex names)
Image Resizing Guarantees all frames have consistent dimensions. Use cv2.resize() or Image.resize() from Pillow with appropriate interpolation methods.
Audio Python's OpenCV doesn't directly handle audio. For adding audio, use external libraries like moviepy after video creation.
Error Handling Gracefully manage missing images or codec issues. Incorporate try-except blocks and checks for None on imread() returns.

Common Issues and Troubleshooting

  • Codec Not Found: If out.isOpened() returns False, your system might not have the required codec. Try different fourcc codes (e.g., *'MJPG' for .avi files, which is widely supported).
  • Dimension Mismatch: Ensure all images are resized to the exact (width, height) specified in cv2.VideoWriter. Inconsistent sizes will lead to errors or distorted videos.
  • Incorrect Image Order: Double-check your sorting logic, especially if image filenames have complex numbering (e.g., image_1.jpg, image_10.jpg needs careful sorting).
  • Large Number of Images: For thousands of images, consider processing in batches or optimizing image loading to manage memory efficiently.

By following these steps, you can effectively convert a series of images into a video file using Python and OpenCV, unlocking powerful capabilities for visual content creation.