"""Dependency-light Gaussian preview exporter for early pipeline tests.""" from __future__ import annotations from pathlib import Path import numpy as np def image_billboard_points(image: np.ndarray, max_side: int = 96): """Create an explicitly labeled 2.5D preview, not a learned reconstruction.""" image = np.asarray(image.convert("RGB") if hasattr(image, "convert") else image, dtype=np.uint8) height, width = image.shape[:2] scale = min(1.0, max_side / max(height, width)) new_w, new_h = max(1, round(width * scale)), max(1, round(height * scale)) yy, xx = np.mgrid[0:new_h, 0:new_w] source_y = np.minimum((yy / max(new_h, 1) * height).astype(int), height - 1) source_x = np.minimum((xx / max(new_w, 1) * width).astype(int), width - 1) colors = image[source_y, source_x].reshape(-1, 3) x = (xx.reshape(-1) / max(new_w - 1, 1) - 0.5).astype(np.float32) y = -(yy.reshape(-1) / max(new_h - 1, 1) - 0.5).astype(np.float32) z = np.ones_like(x, dtype=np.float32) return np.column_stack([x, y, z]), colors def write_preview_ply(path: str | Path, points: np.ndarray, colors: np.ndarray) -> Path: path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8") as handle: handle.write("ply\nformat ascii 1.0\n") handle.write(f"element vertex {len(points)}\n") handle.write("property float x\nproperty float y\nproperty float z\n") handle.write("property uchar red\nproperty uchar green\nproperty uchar blue\n") handle.write("end_header\n") for point, color in zip(points, colors): handle.write(f"{point[0]:.6f} {point[1]:.6f} {point[2]:.6f} {int(color[0])} {int(color[1])} {int(color[2])}\n") return path