| import glob
|
| from pathlib import Path
|
| import uuid
|
| import sys
|
| from typing import List
|
|
|
| sys.path.append((Path(__file__).parent / "extern").as_posix())
|
|
|
|
|
| import argparse
|
| from rich_argparse import RichHelpFormatter
|
| from rich.console import Console
|
| from rich.progress import Progress
|
|
|
| import numpy as np
|
| import subprocess
|
|
|
|
|
| def write_prores_444_video(output_file, frames: List[np.ndarray], fps):
|
|
|
| frames = [(frame * 65535).clip(0, 65535).astype(np.uint16) for frame in frames]
|
|
|
| height, width, _ = frames[0].shape
|
|
|
|
|
| command = [
|
| "ffmpeg",
|
| "-y",
|
| "-f",
|
| "rawvideo",
|
| "-vcodec",
|
| "rawvideo",
|
| "-s",
|
| f"{width}x{height}",
|
| "-pix_fmt",
|
| "rgb48le",
|
| "-r",
|
| str(fps),
|
| "-i",
|
| "-",
|
| "-c:v",
|
| "prores_ks",
|
| "-profile:v",
|
| "4",
|
| "-pix_fmt",
|
| "yuva444p10le",
|
| "-r",
|
| str(fps),
|
| "-y",
|
| output_file,
|
| ]
|
|
|
| process = subprocess.Popen(command, stdin=subprocess.PIPE)
|
|
|
| for frame in frames:
|
| process.stdin.write(frame.tobytes())
|
|
|
| process.stdin.close()
|
| process.wait()
|
|
|
|
|
| if __name__ == "__main__":
|
| default_output = f"./output_{uuid.uuid4()}.mov"
|
| parser = argparse.ArgumentParser(
|
| description="FILM frame interpolation", formatter_class=RichHelpFormatter
|
| )
|
| parser.add_argument("inputs", nargs="*", help="Input image files")
|
| parser.add_argument("--output", help="Output JSON file", default=default_output)
|
| parser.add_argument("-v", "--verbose", action="store_true", help="Verbose mode")
|
| parser.add_argument(
|
| "--glob", help="Enable glob pattern matching", metavar="PATTERN"
|
| )
|
| parser.add_argument(
|
| "--interpolate", type=int, default=4, help="Time for interpolated frames"
|
| )
|
| parser.add_argument("--fps", type=int, default=30, help="Out FPS")
|
| align = 64
|
| block_width = 2
|
| block_height = 2
|
|
|
| args = parser.parse_args()
|
|
|
|
|
| if not args.glob and not args.inputs:
|
| parser.error("Either --glob flag or inputs must be provided.")
|
| if args.glob:
|
| glob_pattern = args.glob
|
| try:
|
| pattern_path = str(Path(glob_pattern).expanduser().resolve())
|
|
|
| if not any(glob.glob(pattern_path)):
|
| raise ValueError(f"No files found for glob pattern: {glob_pattern}")
|
| except Exception as e:
|
| console = Console()
|
| console.print(
|
| f"[bold red]Error: Invalid glob pattern '{glob_pattern}': {e}[/bold red]"
|
| )
|
|
|
| exit(1)
|
| else:
|
| glob_pattern = None
|
|
|
| input_files: List[Path] = []
|
|
|
| if glob_pattern:
|
| input_files = [
|
| Path(p)
|
| for p in list(glob.glob(str(Path(glob_pattern).expanduser().resolve())))
|
| ]
|
| else:
|
| input_files = [Path(p) for p in args.inputs]
|
|
|
| console = Console()
|
| console.print("Input Files:", style="bold", end=" ")
|
| console.print(f"{len(input_files):03d} files", style="cyan")
|
|
|
|
|
| console.print("\nOutput File:", style="bold", end=" ")
|
| console.print(f"{Path(args.output).resolve().absolute()}", style="cyan")
|
|
|
| with Progress(console=console, auto_refresh=True) as progress:
|
| from frame_interpolation.eval import util
|
| from frame_interpolation.eval import util, interpolator
|
|
|
|
|
|
|
| model = interpolator.Interpolator(
|
| "G:/MODELS/FILM/pretrained_models/film_net/Style", None
|
| )
|
|
|
| task = progress.add_task("[cyan]Interpolating frames...", total=1)
|
|
|
| frames = list(
|
| util.interpolate_recursively_from_files(
|
| [x.as_posix() for x in input_files], args.interpolate, model
|
| )
|
| )
|
|
|
|
|
| write_prores_444_video(args.output, frames, fps=args.fps)
|
| progress.update(task, advance=1)
|
| progress.refresh()
|
|
|