Simam3D-GPU / validate_splat.py
junaid-simamdigital's picture
Add binary splat validation
81aafbd verified
Raw History Blame Contribute Delete
2.47 kB
"""Validate the common 32-byte binary Gaussian .splat representation."""
from __future__ import annotations
import argparse
import json
import struct
from pathlib import Path
import numpy as np
RECORD_BYTES = 32
def validate_splat(path: str | Path) -> dict[str, object]:
path = Path(path)
payload = path.read_bytes()
if not payload:
raise ValueError("splat file is empty")
if len(payload) % RECORD_BYTES:
raise ValueError(f"splat byte length {len(payload)} is not divisible by {RECORD_BYTES}")
records = []
for offset in range(0, len(payload), RECORD_BYTES):
position = struct.unpack_from("<3f", payload, offset)
scale = struct.unpack_from("<3f", payload, offset + 12)
rgba = payload[offset + 24:offset + 28]
encoded_rotation = np.frombuffer(payload[offset + 28:offset + 32], dtype=np.uint8).astype(np.float64)
rotation = encoded_rotation / 255.0 * 2.0 - 1.0
records.append((position, scale, rgba, rotation))
positions = np.asarray([record[0] for record in records], dtype=np.float64)
scales = np.asarray([record[1] for record in records], dtype=np.float64)
rotations = np.asarray([record[3] for record in records], dtype=np.float64)
if not np.isfinite(positions).all() or not np.isfinite(scales).all():
raise ValueError("splat contains non-finite position or scale values")
if np.any(scales <= 0):
raise ValueError("splat scales must be positive")
norms = np.linalg.norm(rotations, axis=1)
if not np.all((norms >= 0.97) & (norms <= 1.03)):
raise ValueError("splat rotations are not unit quaternions")
return {
"path": str(path),
"record_bytes": RECORD_BYTES,
"vertex_count": len(records),
"byte_count": len(payload),
"finite": True,
"scale_min": float(scales.min()),
"scale_max": float(scales.max()),
"rotation_norm_min": float(norms.min()),
"rotation_norm_max": float(norms.max()),
"rgba_present": True,
"interpretation": "binary representation validation; not a learned reconstruction-quality claim",
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("splat", type=Path)
args = parser.parse_args(argv)
print(json.dumps(validate_splat(args.splat), indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())