Skip to main content

Ultra-fast Gaussian Splatting PLY I/O library - pure Python with NumPy and Numba

Project description

gsply

Ultra-Fast Gaussian Splatting PLY I/O Library

Python License: MIT Tests

93M Gaussians/sec read | 57M Gaussians/sec write | Auto-optimized


What's New in v0.2.5

  • SOG Format Support: sogread() - Read SOG (Splat Ordering Grid) format files
    • Returns GSData container (same as plyread()) for consistent API
    • In-memory ZIP extraction: Read directly from bytes without disk I/O
    • Uses imagecodecs (fastest WebP decoder) for optimal performance
    • Compatible with PlayCanvas splat-transform format
  • Object-Oriented I/O API: Convenient save/load methods
    • data.save(file_path, compressed=False) - Instance method for saving GSData
    • GSData.load(file_path) - Classmethod for loading (auto-detects format)
    • gstensor.save(file_path, compressed=True) - GPU compression by default
    • GSTensor.load(file_path, device='cuda') - Direct GPU loading
  • Format Conversion API: In-place operations for PLY format conversion
    • normalize() / denormalize() - Convert between linear and PLY formats
    • Available for both GSData (CPU) and GSTensor (GPU)
  • Color Conversion API: In-place SH ↔ RGB conversion
    • to_rgb() / to_sh() - Convert sh0 between SH and RGB formats
    • Numba-optimized CPU and GPU-accelerated versions

Previous versions:

  • v0.2.4: GPU I/O API (plyread_gpu(), plywrite_gpu()), GPU compression optimizations
  • v0.2.2: Data Concatenation, GPU Concatenation, Performance Optimization, Mask Management

Full API Reference | Changelog


Quick Start

from gsply import GSData, GSTensor

# Read PLY file (auto-detects format, zero-copy)
data = GSData.load("model.ply")  # Object-oriented API

# Or use functional API
from gsply import plyread
data = plyread("model.ply")

# Access fields
positions = data.means    # (N, 3) xyz coordinates
colors = data.sh0         # (N, 3) RGB colors
scales = data.scales      # (N, 3) scale parameters
rotations = data.quats    # (N, 4) quaternions

# Save PLY file (object-oriented API)
data.save("output.ply")  # Uncompressed
data.save("output.ply", compressed=True)  # Compressed (71-74% smaller)

# Or use functional API
from gsply import plywrite
plywrite("output.ply", data, compressed=True)

# GPU acceleration (optional)
gstensor = GSTensor.load("model.ply", device='cuda')  # Direct GPU loading
gstensor.save("output.compressed.ply")  # GPU compression (default)

Performance: 93M Gaussians/sec read, 57M Gaussians/sec write (400K Gaussians in 6-7ms)

Installation | Examples | API Reference | Performance


Overview

Ultra-fast Gaussian Splatting PLY I/O for Python. Zero-copy reads, auto-optimized writes, optional GPU acceleration.

Key Features:

  • Fast: 93M Gaussians/sec read, 57M Gaussians/sec write
  • Auto-optimized: Writes are 2.6-2.8x faster automatically
  • Pure Python: NumPy + Numba (no C++ compilation)
  • Format support: Uncompressed PLY + PlayCanvas compressed (71-74% smaller) + SOG format
  • Object-Oriented API: data.save(), GSData.load(), gstensor.save(), GSTensor.load()
  • Format Conversion: normalize(), denormalize() for linear ↔ PLY format conversion
  • Color Conversion: to_rgb(), to_sh() for SH ↔ RGB conversion
  • GPU ready: Optional PyTorch integration with GSTensor

Installation

Basic Installation

pip install gsply

Core dependencies: NumPy and Numba (automatically installed)

Optional Features

GPU Acceleration (PyTorch):

pip install torch  # For GSTensor GPU features

Enables:

  • GSTensor - GPU-accelerated data container
  • plyread_gpu(), plywrite_gpu() - Direct GPU I/O
  • GPU compression/decompression (5-20x faster than CPU)
  • GPU format conversion (normalize(), denormalize(), to_rgb(), to_sh())

SOG Format Support:

pip install gsply[sogs]  # For SOG format support (sogread)

Enables:

  • sogread() - Read SOG (Splat Ordering Grid) format files
  • In-memory ZIP extraction
  • PlayCanvas splat-transform compatibility

Development:

pip install -e .[dev]  # Install with dev dependencies (pytest, ruff, mypy)

Installation Examples

# Basic installation (CPU only)
pip install gsply

# With GPU support
pip install gsply torch

# With SOG format support
pip install gsply[sogs]

# Full installation (GPU + SOG)
pip install gsply[sogs] torch

# Development installation
git clone https://github.com/OpsiClear/gsply.git
cd gsply
pip install -e .[dev]

Examples

Basic I/O

from gsply import plyread, plywrite

# Read and access data
data = plyread("model.ply")
print(f"Loaded {len(data)} Gaussians")

# Unpack to individual arrays
means, scales, quats, opacities, sh0, shN = data.unpack()

# Write with individual arrays
plywrite("output.ply", means, scales, quats, opacities, sh0, shN)

# Or write directly from GSData
plywrite("output.ply", data)

# Or use object-oriented API
data.save("output.ply")  # Uncompressed
data.save("output.ply", compressed=True)  # Compressed

# Load using classmethod
data = GSData.load("scene.ply")  # Auto-detects format

Format Detection

from gsply import detect_format

is_compressed, sh_degree = detect_format("model.ply")
if is_compressed:
    print("Compressed PlayCanvas format")
else:
    print(f"Uncompressed format with SH degree {sh_degree}")

In-Memory Compression

from gsply import compress_to_bytes, decompress_from_bytes

# Compress for network transfer or storage
compressed_bytes = compress_to_bytes(data)

# Decompress from bytes
data_restored = decompress_from_bytes(compressed_bytes)

GPU Acceleration

from gsply import GSTensor, plyread_gpu, plywrite_gpu

# Direct GPU I/O (4x faster than CPU decompress + GPU transfer)
gstensor = plyread_gpu("model.compressed.ply", device='cuda')

# Access GPU tensors
positions_gpu = gstensor.means  # torch.Tensor on GPU
colors_gpu = gstensor.sh0       # torch.Tensor on GPU

# Filter on GPU
high_opacity = gstensor[gstensor.opacities > 0.5]

# Write back to compressed PLY (GPU compression)
plywrite_gpu("output.compressed.ply", gstensor)

# Or convert from CPU data
data = plyread("model.ply")
gstensor = GSTensor.from_gsdata(data, device='cuda')

# Or use object-oriented API
gstensor = GSTensor.load("model.ply", device='cuda')  # Auto-detects format
gstensor.save("output.compressed.ply")  # GPU compression (default)

# Convert back to CPU
data_cpu = gstensor.to_gsdata()

Data Manipulation

from gsply import GSData

# Slicing and indexing
subset = data[100:200]          # Slice
first = data[0]                 # Single Gaussian
filtered = data[data.opacities > 0.5]  # Boolean mask

# Concatenation
combined = data1.add(data2)     # Pairwise (1.9x faster)
combined = data1 + data2        # Or use + operator
merged = GSData.concatenate([data1, data2, data3])  # Bulk (6.15x faster)

# Optimize for faster operations
data = data.make_contiguous()   # 2-45x speedup for operations

# Copy and modify
bright = data.copy()
bright.sh0 *= 1.5  # Make brighter

# Format conversion before operations
data.denormalize()  # Convert to linear for easier manipulation
data.opacities = np.clip(data.opacities * 1.2, 0, 1)  # Modify in linear space
data.normalize()  # Convert back to PLY format before saving
data.save("modified.ply")

Performance

Benchmark Summary

Uncompressed Format (400K Gaussians, SH0):

  • Read: 5.7ms (70M Gaussians/sec)
  • Write: 19.3ms (21M Gaussians/sec)

Compressed Format (400K Gaussians, SH0):

  • Read: 8.5ms (47M Gaussians/sec)
  • Write: 15.0ms (27M Gaussians/sec)
  • Size reduction: 71-74%

Peak Performance:

  • Read: 78M Gaussians/sec (1M Gaussians, SH0, uncompressed)
  • Write: 29M Gaussians/sec (100K Gaussians, SH0, compressed)

GPU Transfer (400K Gaussians, RTX 3090 Ti):

  • With optimization: 1.99ms (11.4x faster)
  • Without optimization: 22.78ms

See detailed performance benchmarks for more information.


Format Support

Uncompressed PLY

Standard binary little-endian PLY format:

SH Degree Properties Description
0 14 xyz, f_dc(3), opacity, scales(3), quats(4)
1 23 + 9 f_rest coefficients
2 38 + 24 f_rest coefficients
3 59 + 45 f_rest coefficients

Compressed PLY (PlayCanvas)

Chunk-based quantized format:

  • Automatically saves as .compressed.ply when compressed=True
  • Compression ratio: 71-74% size reduction
  • Compatible with PlayCanvas, SuperSplat, other WebGL viewers
  • Parallel compression/decompression

SOG Format (Splat Ordering Grid) - Optional

WebP-based texture format for web deployment:

  • Requires gsply[sogs] installation
  • Uses WebP images for efficient storage
  • Codebook-based compression for scales and colors
  • Compatible with PlayCanvas splat-transform
  • Supports both .sog ZIP bundles and folder formats
  • Returns GSData: Same container as plyread() for consistent API
  • In-memory ZIP extraction: Can read directly from bytes without disk I/O
from gsply import sogread

# Read from file path - returns GSData (same as plyread)
data = sogread("model.sog")
positions = data.means  # Same API as GSData from plyread
colors = data.sh0

# Read from bytes (in-memory, no disk I/O)
with open("model.sog", "rb") as f:
    sog_bytes = f.read()
data = sogread(sog_bytes)  # Returns GSData - fully in-memory extraction and decoding

API Reference

Complete API documentation is available in docs/API_REFERENCE.md:

Core I/O:

  • plyread(file_path) - Read PLY files
  • plywrite(file_path, ...) - Write PLY files
  • detect_format(file_path) - Detect format and SH degree
  • sogread(file_path | bytes) - Read SOG files from path or bytes (requires gsply[sogs])

GSData Container:

  • data.save(file_path, compressed=False) - Save to PLY file
  • GSData.load(file_path) - Load from PLY file (classmethod, auto-detects format)
  • data.unpack() - Unpack to tuple
  • data.to_dict() - Convert to dictionary
  • data.copy() - Deep copy
  • data.consolidate() - Optimize for slicing
  • data.normalize(inplace=True) / data.to_ply_format() - Convert linear → PLY format (log/logit, modifies in-place by default)
  • data.denormalize(inplace=True) / data.from_ply_format() / data.to_linear() - Convert PLY format → linear (modifies in-place by default)
  • data.to_rgb(inplace=True) - Convert sh0 from SH format to RGB colors (Numba-optimized, modifies in-place by default)
  • data.to_sh(inplace=True) - Convert sh0 from RGB format to SH coefficients (Numba-optimized, modifies in-place by default)
  • data[index] - Indexing and slicing

Compression:

  • compress_to_bytes(data) - Compress to bytes
  • compress_to_arrays(data) - Compress to arrays
  • decompress_from_bytes(bytes) - Decompress from bytes

Utilities:

  • sh2rgb(sh) - SH to RGB conversion
  • rgb2sh(rgb) - RGB to SH conversion
  • logit(x, eps=1e-6) - Logit function (optimized CPU)
  • sigmoid(x) - Sigmoid function (optimized CPU)
  • SH_C0 - Normalization constant

GPU Support (PyTorch):

  • GSTensor.load(file_path, device='cuda') - Load from PLY file (classmethod, auto-detects format)
  • gstensor.save(file_path, compressed=True) - Save to PLY file (GPU compression by default)
  • gstensor.save_compressed(file_path) - Save compressed PLY (convenience alias)
  • GSTensor.from_gsdata(data, device='cuda') - Convert to GPU
  • gstensor.to_gsdata() - Convert to CPU
  • gstensor.normalize(inplace=True) / gstensor.to_ply_format() - Convert linear → PLY format (GPU, modifies in-place by default)
  • gstensor.denormalize(inplace=True) / gstensor.from_ply_format() / gstensor.to_linear() - Convert PLY format → linear (GPU, modifies in-place by default)
  • gstensor.to_rgb(inplace=True) - Convert sh0 from SH format to RGB colors (GPU, modifies in-place by default)
  • gstensor.to_sh(inplace=True) - Convert sh0 from RGB format to SH coefficients (GPU, modifies in-place by default)
  • Device management: .to(), .cpu(), .cuda()
  • Precision: .half(), .float(), .double()
  • Full slicing and manipulation support

Development

Setup

# Clone repository
git clone https://github.com/OpsiClear/gsply.git
cd gsply

# Install in development mode
pip install -e .[dev]

# Run tests
pytest tests/ -v

# Run with coverage
pytest tests/ -v --cov=gsply --cov-report=html

Project Structure

gsply/
├── src/gsply/          # Source code
│   ├── gsdata.py       # GSData dataclass
│   ├── reader.py       # PLY reading
│   ├── writer.py       # PLY writing
│   ├── formats.py      # Format detection
│   └── torch/          # PyTorch integration
│       └── gstensor.py # GSTensor GPU dataclass
├── tests/              # Unit tests (169 tests)
├── benchmarks/         # Performance benchmarks
├── docs/               # Documentation
└── pyproject.toml      # Package configuration

Testing

gsply has comprehensive test coverage with 169 passing tests:

# Run all tests
pytest tests/ -v

# Run PyTorch tests (requires torch)
pytest tests/ -v -k "torch or gstensor"

# Run with coverage
pytest tests/ -v --cov=gsply --cov-report=html

Benchmarking

Compare gsply performance against other PLY libraries:

# Install benchmark dependencies
pip install -e .[benchmark]

# Run benchmark
python benchmarks/benchmark.py

# Custom settings
python benchmarks/benchmark.py --config.file path/to/model.ply --config.iterations 20

Documentation


CI/CD

Complete GitHub Actions pipeline:

  • Multi-platform: Ubuntu, Windows, macOS
  • Multi-version: Python 3.10, 3.11, 3.12, 3.13
  • Core + PyTorch testing
  • Automated benchmarking
  • PyPI publishing on release

Contributing

Contributions are welcome! Please see .github/CONTRIBUTING.md for guidelines.

Quick start:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Run tests and benchmarks
  5. Submit a pull request

License

MIT License - see LICENSE file for details.


Citation

If you use gsply in your research, please cite:

@software{gsply2024,
  author = {OpsiClear},
  title = {gsply: Ultra-Fast Gaussian Splatting PLY I/O},
  year = {2024},
  url = {https://github.com/OpsiClear/gsply}
}

Related Projects

  • gsplat: CUDA-accelerated Gaussian Splatting rasterizer
  • nerfstudio: NeRF training framework with Gaussian Splatting support
  • PlayCanvas SuperSplat: Web-based Gaussian Splatting viewer
  • 3D Gaussian Splatting: Original paper and implementation

Made with Python and numpy

Report Bug | Request Feature | Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gsply-0.2.5.tar.gz (111.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gsply-0.2.5-py3-none-any.whl (76.2 kB view details)

Uploaded Python 3

File details

Details for the file gsply-0.2.5.tar.gz.

File metadata

  • Download URL: gsply-0.2.5.tar.gz
  • Upload date:
  • Size: 111.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gsply-0.2.5.tar.gz
Algorithm Hash digest
SHA256 c2634fdfb17cfb44ae149f274db397812286fb40d9bc6b9f3079b4d513d87c43
MD5 3791191c4c6d9f71807c48ed601e386b
BLAKE2b-256 b7e0ac2027eb7df05c10ca0c55076a96c0ccdcfe857f5e2e6606ea0d4b47e397

See more details on using hashes here.

Provenance

The following attestation bundles were made for gsply-0.2.5.tar.gz:

Publisher: publish.yml on OpsiClear/gsply

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gsply-0.2.5-py3-none-any.whl.

File metadata

  • Download URL: gsply-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 76.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gsply-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c04c7806596d227c971729be141c3c26719f211d86ae3a62b22a398890bba53a
MD5 5114cf5fa729d2d6f256f715e5c40a12
BLAKE2b-256 56dfb13ebc3abb3c32056951aa0aa6379755e560e8e14745dbd43bff21408c7e

See more details on using hashes here.

Provenance

The following attestation bundles were made for gsply-0.2.5-py3-none-any.whl:

Publisher: publish.yml on OpsiClear/gsply

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page