Source code for GINCCO_lib.modules.image_to_video

# need to install this for run
#pip install imageio[ffmpeg] imageio[pyav] pillow

import os
import glob
import numpy as np

def _ensure_even_hw(arr):
    """Pad last row/col if H or W is odd to keep encoders happy."""
    h, w = arr.shape[:2]
    pad_h = 1 if h % 2 else 0
    pad_w = 1 if w % 2 else 0
    if pad_h or pad_w:
        # pad using edge values
        arr = np.pad(arr, ((0, pad_h), (0, pad_w), (0, 0)), mode="edge")
    return arr

[docs] def pngs_to_video(inputs, output_path, fps=24, resize_to=None): """ Convert a sequence of PNG images into an MP4 video using ``imageio`` with the PyAV plugin. This function reads a list or folder of PNG images, ensures that each frame is RGB (uint8), contiguous in memory, and has even pixel dimensions, then encodes them into an H.264 MP4 video file. Optionally, images can be resized before encoding. It provides a fully pure-Python workflow using ``imageio`` and ``Pillow``. Parameters ---------- inputs : str or list of str Either: * a directory path containing PNG files, * a glob pattern (e.g., ``"./frames/*.png"``), or * an explicit list of file paths. output_path : str Path to the output video file (e.g., ``"./output.mp4"``). fps : int, optional Frames per second of the output video. Default is 24. resize_to : tuple of int, optional Target video frame size ``(width, height)`` in pixels. If ``None``, uses the size of the first image. Default is ``None``. Returns ------- None The video is written directly to ``output_path``. Notes ----- - The output codec is **H.264** (requires ``pyav`` plugin in ``imageio``). - Any unreadable or malformed image will raise a ``RuntimeError``. Examples -------- >>> pngs_to_video("./frames/*.png", "movie.mp4", fps=30) >>> pngs_to_video(["frame1.png", "frame2.png", "frame3.png"], "out.mp4", resize_to=(1280, 720)) """ try: import imageio.v3 as iio from PIL import Image except ImportError as e: raise ImportError( "This function requires additional library " "Please install it with `pip install imageio[ffmpeg] imageio[pyav] pillow`." ) from e # Collect files if isinstance(inputs, str): files = glob.glob(inputs) if not os.path.isdir(inputs) else glob.glob(os.path.join(inputs, "*.png")) else: files = list(inputs) if not files: raise ValueError("No PNG files found") files.sort() # Target size from first image or resize_to with Image.open(files[0]) as im0: w, h = (resize_to if resize_to is not None else im0.size) try: with iio.imopen(output_path, "w", plugin="pyav") as writer: writer.init_video_stream(fps=fps, codec="h264") for idx, path in enumerate(files): try: im = Image.open(path).convert("RGB") except Exception as e: raise RuntimeError(f"Failed to open image: {path} ({e})") if im.size != (w, h): im = im.resize((w, h), Image.LANCZOS) frame = np.asarray(im) if frame.dtype != np.uint8: frame = frame.astype(np.uint8, copy=False) # ensure 3-channel RGB if frame.ndim != 3 or frame.shape[2] != 3: raise RuntimeError(f"Unexpected frame shape for {path}: {frame.shape}") # contiguous memory frame = np.ascontiguousarray(frame) # even H, W frame = _ensure_even_hw(frame) # final guard if frame.dtype != np.uint8 or frame.ndim != 3 or frame.shape[2] != 3: raise RuntimeError(f"Incompatible frame for {path}: dtype={frame.dtype}, shape={frame.shape}") writer.write_frame(frame) except Exception as e: # Add more context raise RuntimeError(f"Failed to write video: {e}")