Spaces:
Running on Zero
Running on Zero
Download fdanyone/runs.py from rerun/4danyone-rerun: direct link, hf CLI and curl.
- Browser
- Download file 6.27 kB
-
https://huggingface.co/spaces/rerun/4danyone-rerun/resolve/4c983fd1a9ca8bfaeec577c88d117b66c3e3ae59/fdanyone/runs.py
- Command line
-
hf download hf://spaces/rerun/4danyone-rerun@4c983fd1a9ca8bfaeec577c88d117b66c3e3ae59/fdanyone/runs.py
-
curl -L -o runs.py https://huggingface.co/spaces/rerun/4danyone-rerun/resolve/4c983fd1a9ca8bfaeec577c88d117b66c3e3ae59/fdanyone/runs.py
6.27 kB
| """Read what one finished 4DAnyone inference run left on disk. | |
| Two readers live here. ``discover_run`` collects every artifact of a clip -- | |
| motion, generated videos, skeletons, and the source clip -- into a | |
| ``RunLayout``. The rig readers parse the ``cameras.json`` that | |
| ``fdanyone.output`` writes next to the generated videos. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import logging | |
| from dataclasses import dataclass | |
| from pathlib import Path | |
| from fdanyone.errors import FourDAnyoneError | |
| from fdanyone.io import read_json | |
| LOGGER = logging.getLogger("fdanyone.runs") | |
| # --------------------------------------------------------------------------- | |
| # Run layout | |
| # --------------------------------------------------------------------------- | |
| class RunLayout: | |
| """Files that one inference run left on disk for a single clip.""" | |
| clip: str | |
| data_dir: Path | |
| result_dir: Path | |
| motion_dir: Path | |
| cameras_json: Path | None | |
| metadata_json: Path | None | |
| source_video: Path | None | |
| dense_videos: tuple[tuple[int, Path], ...] | |
| skeleton_videos: tuple[tuple[int, Path], ...] | |
| sparse_videos: tuple[tuple[int, Path], ...] | |
| def has_motion(self) -> bool: | |
| return (self.motion_dir / "motion.json").is_file() and (self.motion_dir / "motion.safetensors").is_file() | |
| def numbered_videos(directory: Path) -> tuple[tuple[int, Path], ...]: | |
| """Return ``(camera_id, path)`` pairs for ``NN.mp4`` files, ID-ordered.""" | |
| if not directory.is_dir(): | |
| return () | |
| found: list[tuple[int, Path]] = [] | |
| for path in sorted(directory.glob("*.mp4")): | |
| try: | |
| found.append((int(path.stem), path)) | |
| except ValueError: | |
| LOGGER.warning("Ignoring video with a non-numeric name: %s", path) | |
| return tuple(sorted(found)) | |
| def find_source_video(data_dir: Path, clip: str, filename: str | None) -> Path | None: | |
| """Locate the input clip that produced the run.""" | |
| candidates: list[Path] = [] | |
| if filename: | |
| candidates.append(data_dir / "source" / "pexels" / filename) | |
| for suffix in (".mp4", ".mov", ".mkv", ".webm", ".MP4", ".MOV"): | |
| candidates.append(data_dir / "source" / "pexels" / f"{clip}{suffix}") | |
| for candidate in candidates: | |
| if candidate.is_file(): | |
| return candidate | |
| # Only the input and result trees can hold a clip; the rest of the data | |
| # root is model output that a recursive walk would scan for nothing. | |
| roots = tuple(root for root in (data_dir / "source", data_dir / "fdanyone") if root.is_dir()) | |
| if filename: | |
| matches = sorted(path for root in roots for path in root.rglob(filename) if path.is_file()) | |
| if matches: | |
| return matches[0] | |
| matches = sorted( | |
| path for root in roots for path in root.rglob(f"{clip}.*") if path.is_file() and path.suffix != ".rrd" | |
| ) | |
| return matches[0] if matches else None | |
| def discover_run(data_dir: Path, clip: str) -> RunLayout: | |
| """Collect every artifact of ``clip`` and reject an empty run.""" | |
| result_dir = data_dir / "fdanyone" / clip | |
| motion_dir = data_dir / "gvhmr" / "results" / clip | |
| metadata_json = result_dir / "metadata.json" | |
| cameras_json = result_dir / "cameras.json" | |
| metadata = read_json(metadata_json) | |
| filename = None | |
| if metadata is not None: | |
| filename = str(metadata.get("input", {}).get("filename") or "") or None | |
| layout = RunLayout( | |
| clip=clip, | |
| data_dir=data_dir, | |
| result_dir=result_dir, | |
| motion_dir=motion_dir, | |
| cameras_json=cameras_json if cameras_json.is_file() else None, | |
| metadata_json=metadata_json if metadata_json.is_file() else None, | |
| source_video=find_source_video(data_dir, clip, filename), | |
| dense_videos=numbered_videos(result_dir / "videos" / "dense"), | |
| skeleton_videos=numbered_videos(result_dir / "skeletons"), | |
| sparse_videos=numbered_videos(result_dir / "videos" / "sparse"), | |
| ) | |
| if not layout.has_motion and not layout.dense_videos and layout.source_video is None: | |
| raise FourDAnyoneError( | |
| f"Nothing to visualize for clip {clip!r}. Expected at least one of:\n" | |
| f" {motion_dir / 'motion.safetensors'} (GVHMR motion)\n" | |
| f" {result_dir / 'videos' / 'dense'} (generated views)\n" | |
| f" a source clip named {clip}.* under {data_dir}\n" | |
| "Run `python inference.py --video_path <clip>` first." | |
| ) | |
| return layout | |
| # --------------------------------------------------------------------------- | |
| # Camera rig | |
| # --------------------------------------------------------------------------- | |
| def read_cameras(result: Path) -> dict: | |
| """Read the ``cameras.json`` a result directory must carry.""" | |
| path = result / "cameras.json" | |
| try: | |
| cameras = json.loads(path.read_text()) | |
| except (FileNotFoundError, json.JSONDecodeError) as exc: | |
| raise FourDAnyoneError(f"Cannot read {path}: {exc}") from exc | |
| if not isinstance(cameras, dict): | |
| raise FourDAnyoneError("cameras.json must contain a JSON object.") | |
| return cameras | |
| def camera_records(rig: dict) -> list[dict]: | |
| """Validate an OPENCV rig and return its ID-ordered camera records.""" | |
| if not isinstance(rig, dict) or rig.get("camera_model") != "OPENCV": | |
| raise FourDAnyoneError("cameras.json has no supported OPENCV camera rig.") | |
| cameras = rig.get("cameras") | |
| if not isinstance(cameras, list) or not cameras: | |
| raise FourDAnyoneError("Camera rig must contain at least one camera.") | |
| if [camera.get("camera_id") for camera in cameras if isinstance(camera, dict)] != list(range(len(cameras))): | |
| raise FourDAnyoneError("Camera rig must be ordered by camera ID.") | |
| return cameras | |
| def dense_video_paths(result: Path, cameras: list[dict]) -> tuple[Path, ...]: | |
| """Return the generated video of every camera, in rig order.""" | |
| paths = [] | |
| for camera in cameras: | |
| camera_id = int(camera["camera_id"]) | |
| relative = f"videos/dense/{camera_id:02d}.mp4" | |
| if camera.get("video") != relative: | |
| raise FourDAnyoneError(f"Camera {camera_id:02d} points to the wrong target video.") | |
| paths.append(result / relative) | |
| return tuple(paths) | |