Initial reproducible prototype
Browse files
core.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dependency-light Gaussian preview exporter for early pipeline tests."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def image_billboard_points(image: np.ndarray, max_side: int = 96):
|
| 11 |
+
"""Create an explicitly labeled 2.5D preview, not a learned reconstruction."""
|
| 12 |
+
image = np.asarray(image.convert("RGB") if hasattr(image, "convert") else image, dtype=np.uint8)
|
| 13 |
+
height, width = image.shape[:2]
|
| 14 |
+
scale = min(1.0, max_side / max(height, width))
|
| 15 |
+
new_w, new_h = max(1, round(width * scale)), max(1, round(height * scale))
|
| 16 |
+
yy, xx = np.mgrid[0:new_h, 0:new_w]
|
| 17 |
+
source_y = np.minimum((yy / max(new_h, 1) * height).astype(int), height - 1)
|
| 18 |
+
source_x = np.minimum((xx / max(new_w, 1) * width).astype(int), width - 1)
|
| 19 |
+
colors = image[source_y, source_x].reshape(-1, 3)
|
| 20 |
+
x = (xx.reshape(-1) / max(new_w - 1, 1) - 0.5).astype(np.float32)
|
| 21 |
+
y = -(yy.reshape(-1) / max(new_h - 1, 1) - 0.5).astype(np.float32)
|
| 22 |
+
z = np.ones_like(x, dtype=np.float32)
|
| 23 |
+
return np.column_stack([x, y, z]), colors
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def write_preview_ply(path: str | Path, points: np.ndarray, colors: np.ndarray) -> Path:
|
| 27 |
+
path = Path(path)
|
| 28 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 29 |
+
with path.open("w", encoding="utf-8") as handle:
|
| 30 |
+
handle.write("ply\nformat ascii 1.0\n")
|
| 31 |
+
handle.write(f"element vertex {len(points)}\n")
|
| 32 |
+
handle.write("property float x\nproperty float y\nproperty float z\n")
|
| 33 |
+
handle.write("property uchar red\nproperty uchar green\nproperty uchar blue\n")
|
| 34 |
+
handle.write("end_header\n")
|
| 35 |
+
for point, color in zip(points, colors):
|
| 36 |
+
handle.write(f"{point[0]:.6f} {point[1]:.6f} {point[2]:.6f} {int(color[0])} {int(color[1])} {int(color[2])}\n")
|
| 37 |
+
return path
|