| """Video utilities — encode SVD frames to MP4.""" |
| from __future__ import annotations |
|
|
| from pathlib import Path |
| from typing import List, Union |
|
|
| import imageio.v2 as imageio |
| import numpy as np |
| from PIL import Image |
|
|
|
|
| def frames_to_mp4(frames: List[Image.Image], path: Union[str, Path], fps: int = 8) -> None: |
| """Save a list of PIL frames as an MP4 video.""" |
| path = Path(path) |
| path.parent.mkdir(parents=True, exist_ok=True) |
| arr = [np.array(f.convert("RGB")) for f in frames] |
| writer = imageio.get_writer(str(path), fps=fps, codec="libx264", |
| quality=8, macro_block_size=1) |
| for frame in arr: |
| writer.append_data(frame) |
| writer.close() |
|
|
|
|
| def gif_from_frames(frames: List[Image.Image], path: Union[str, Path], fps: int = 8) -> None: |
| """Save frames as an animated GIF (good for previews).""" |
| path = Path(path) |
| path.parent.mkdir(parents=True, exist_ok=True) |
| frames[0].save( |
| path, save_all=True, append_images=frames[1:], |
| duration=int(1000 / fps), loop=0, optimize=True, |
| ) |
|
|