Skip to content
/ spz Public

SPZ file format handling for Rust and Python, and CLI tools.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

Jackneill/spz

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

SPZ

Rust and Python implementation of the .SPZ file format (v3) and CLI tools.
 
WIP
 

Crates.io Version docs.rs lib.rs GitHub Tag
GitHub CI Deps GitHub Last Commit
CodSpeed CodeCov Codacy grade
Licenses FOSSA Status FOSSA Security
Python Version from PEP 621 TOML PyPI - Wheel



Get it on Flathub Get it on Snapcraft Store

What is SPZ?

SPZ is a compressed file format for 3D Gaussian Splats, designed by Niantic. It provides efficient storage of Gaussian Splat data with configurable spherical harmonics degrees and coordinate system support.

See docs/SPZ.md for more information.

CLI

$ # install:
$ cargo install spz
$ # or
$ flatpak install io.github.jackneill.spz
$ # or
$ snap install spz
$
$ # run:
$ path/to/spz info assets/racoonfamily.spz

GaussianSplat={num_points=932560, sh_degree=3, antialiased=true, median_ellipsoid_volume=0.0000000046213082, bbox=[x=-281.779541 to 258.382568, y=-240.000000 to 240.000000, z=-240.000000 to 240.000000]}

Rust

Usage

[dependencies]
spz = { version = "0.0.7", default-features = false, features = [] }
use spz::prelude::*;

Examples

cargo run --example load_spz

Quick Start

// SPDX-License-Identifier: Apache-2.0 OR MIT

use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use spz::{coord::CoordinateSystem, gaussian_splat::GaussianSplat, unpacked::UnpackOptions};

fn main() -> Result<()> {
	let mut sample_spz = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
	sample_spz.push("../../assets/racoonfamily.spz");

	let _gs1 = GaussianSplat::builder()
		.filepath(&sample_spz)
		.packed(true)?
		.unpack_options(
			UnpackOptions::builder()
				.to_coord_system(CoordinateSystem::UNSPECIFIED)
				.build(),
		)
		.load()
		.with_context(|| format!("unable to load file: {:?}", sample_spz))?;

	let _gs0 = GaussianSplat::builder().filepath(&sample_spz).load()?;

	Ok(())
}

#[allow(unused)]
async fn load_spz_async<P>(spz_file: P) -> Result<GaussianSplat>
where
	P: AsRef<Path>,
{
	GaussianSplat::builder()
		.filepath(spz_file.as_ref())
		.packed(true)?
		.unpack_options(
			UnpackOptions::builder()
				.to_coord_system(CoordinateSystem::UNSPECIFIED)
				.build(),
		)
		.load_async()
		.await
		.with_context(|| format!("unable to load file: {:?}", spz_file.as_ref()))
}

API

Overview

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct GaussianSplat {
	pub num_points: i32,
	pub spherical_harmonics_degree: i32,
	pub antialiased: bool,
	pub positions: Vec<f32>,
	pub scales: Vec<f32>,
	pub rotations: Vec<f32>,
	pub alphas: Vec<f32>,
	pub colors: Vec<f32>,
	pub spherical_harmonics: Vec<f32>,
}

Tests

Pre-Requisites

Run

just test
just fuzz
just mutants

Benches

Pre-Requisites

  • cargo install cargo-criterion
  • Install gnuplot for html reports.

Run

just bench
  • The html report of the benchmark can be found under ./target/criterion/report/index.html.
  • View Benchmark and Profiling data on CodSpeed, (from CI runs).

Test Code Coverage

CodeCov Grid

Build

Pre-Requisites

Python

Usage

uvx pip install spz
# pyproject.toml

[project]
dependencies = [
    "spz",
]

Examples

import spz

# Load from file
splat = spz.load("scene.spz")  # -> GaussianSplat
# or
splat = spz.GaussianSplat.load(
    "scene.spz", coordinate_system=spz.CoordinateSystem.RUB
)  # -> GaussianSplat
# or
with spz.SplatReader("scene.spz") as ctx:
    splat2 = ctx.splat  # -> GaussianSplat

with spz.temp_save(splat) as tmp_path:
    import subprocess

    subprocess.run(["viewer", str(tmp_path)])

# Access properties
print(f"{splat.num_points:,} points")
print(f"center: {splat.bbox.center}")
print(f"size: {splat.bbox.size}")

# Access data (flat arrays, list[float])
positions = splat.positions  # [x1, y1, z1, x2, y2, z2, ...]
scales = splat.scales
rotations = splat.rotations
alphas = splat.alphas
colors = splat.colors
sh = splat.spherical_harmonics

# Serialize
data = splat.to_bytes()  # -> bytes
splat2 = spz.GaussianSplat.from_bytes(data)  # -> GaussianSplat

# Create from data
new_splat = spz.GaussianSplat(
    positions=[0.0, 0.0, 0.0, 1.0, 2.0, 3.0],  # flat array
    scales=[-5.0] * 6,
    rotations=[1.0, 0.0, 0.0, 0.0] * 2,
    alphas=[0.5, 0.8],
    colors=[255.0, 0.0, 0.0, 0.0, 255.0, 0.0],
)  # -> GaussianSplat

# Save to file
new_splat.save("output.spz")

with spz.SplatWriter("output2.spz") as writer:
    writer.splat = splat2

with spz.modified_splat("scene.spz", "scene_rotated.spz") as splat:
    splat.rotate_180_deg_about_x()

Documentation

Further documentation is available under ./docs.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

FOSSA Scan