| """ |
| Shared utilities for eval_metrics: discover evals_ep0 outputs and load video frames. |
| """ |
| from __future__ import annotations |
|
|
| import os |
| from typing import List, Tuple |
|
|
| try: |
| import cv2 |
| HAS_CV2 = True |
| except ImportError: |
| HAS_CV2 = False |
|
|
| import numpy as np |
|
|
|
|
| def discover_evals_videos(evals_root: str, pattern: str = "*_gen_only.mp4") -> List[Tuple[str, str]]: |
| """ |
| Discover all generated-only MP4s under evals_ep0 structure. |
| Returns list of (relative_path, absolute_path) for each video. |
| """ |
| out: List[Tuple[str, str]] = [] |
| evals_root = os.path.abspath(evals_root) |
| for root, _dirs, files in os.walk(evals_root): |
| for f in files: |
| if f.endswith("_gen_only.mp4") or (pattern != "*_gen_only.mp4" and f.endswith(".mp4")): |
| absp = os.path.join(root, f) |
| rel = os.path.relpath(absp, evals_root) |
| out.append((rel, absp)) |
| return sorted(out, key=lambda x: x[0]) |
|
|
|
|
| def discover_loop_closure_videos(evals_root: str) -> List[Tuple[str, str]]: |
| """Discover MP4s under 1_loop_4chunk and 3_multi_ctx_4chunk for loop closure (prefer gen_only).""" |
| out: List[Tuple[str, str]] = [] |
| for sub in ("1_loop_4chunk", "3_multi_ctx_4chunk"): |
| d = os.path.join(evals_root, sub) |
| if not os.path.isdir(d): |
| continue |
| for root, _dirs, files in os.walk(d): |
| for f in files: |
| if f.endswith("_gen_only.mp4"): |
| absp = os.path.join(root, f) |
| rel = os.path.relpath(absp, evals_root) |
| out.append((rel, absp)) |
| return sorted(out, key=lambda x: x[0]) |
|
|
|
|
| def load_video_frames(path: str, max_frames: int | None = None) -> np.ndarray: |
| """ |
| Load video as array of frames (RGB, uint8). |
| Returns (N, H, W, 3). If max_frames set, stop after that many frames. |
| """ |
| if not HAS_CV2: |
| raise RuntimeError("opencv-python is required for video loading (pip install opencv-python)") |
| cap = cv2.VideoCapture(path) |
| frames = [] |
| while True: |
| ret, frame = cap.read() |
| if not ret: |
| break |
| frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
| frames.append(frame_rgb) |
| if max_frames is not None and len(frames) >= max_frames: |
| break |
| cap.release() |
| if not frames: |
| return np.zeros((0, 0, 0, 3), dtype=np.uint8) |
| return np.stack(frames, axis=0) |
|
|
|
|
| def load_video_frames_pil(path: str, max_frames: int | None = None): |
| """Load video as list of PIL Images (for CLIP etc.).""" |
| from PIL import Image |
| arr = load_video_frames(path, max_frames=max_frames) |
| if arr.size == 0: |
| return [] |
| return [Image.fromarray(arr[i]) for i in range(arr.shape[0])] |
|
|