Download training/prepare_frames.py from jc-builds/LiquidInbetween: direct link, hf CLI and curl.
- Browser
- Download file 1.51 kB
-
https://huggingface.co/jc-builds/LiquidInbetween/resolve/main/training/prepare_frames.py
- Command line
-
hf download hf://jc-builds/LiquidInbetween/training/prepare_frames.py
-
curl -L -o prepare_frames.py https://huggingface.co/jc-builds/LiquidInbetween/resolve/main/training/prepare_frames.py
1.51 kB
| """Decode training videos to 15 fps frames (fit in 448 px) as uint8 arrays, | |
| and mark scene cuts so no training triplet spans one.""" | |
| import json, subprocess, sys | |
| from pathlib import Path | |
| import numpy as np | |
| src, out = Path(sys.argv[1]), Path(sys.argv[2]) | |
| out.mkdir(parents=True, exist_ok=True) | |
| index = [] | |
| for video in sorted(src.glob("v*.webm")): | |
| probe = json.loads(subprocess.run(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", | |
| "stream=width,height", "-of", "json", str(video)], capture_output=True, text=True).stdout) | |
| w, h = probe["streams"][0]["width"], probe["streams"][0]["height"] | |
| s = 448 / max(w, h) | |
| W, H = int(round(w * s / 8) * 8), int(round(h * s / 8) * 8) | |
| raw = subprocess.run(["ffmpeg", "-v", "error", "-i", str(video), "-vf", f"fps=15,scale={W}:{H}:flags=area", | |
| "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], capture_output=True).stdout | |
| frames = np.frombuffer(raw, np.uint8).reshape(-1, H, W, 3) | |
| small = frames[:, ::8, ::8].astype(np.float32).mean(-1) | |
| diff = np.abs(np.diff(small, axis=0)).mean((1, 2)) | |
| cuts = np.where(diff > max(18.0, np.median(diff) * 6))[0] + 1 # first frame of each new shot | |
| np.save(out / f"{video.stem}.npy", frames) | |
| index.append({"name": video.stem, "frames": int(len(frames)), "width": W, "height": H, "cuts": cuts.tolist()}) | |
| print(video.stem, frames.shape, "cuts:", len(cuts)) | |
| (out / "index.json").write_text(json.dumps(index, indent=1)) | |