Ultra-fast Gaussian Splatting PLY I/O library - pure Python, zero dependencies
Project description
gsply
Ultra-Fast Gaussian Splatting PLY I/O Library
6.3x faster reads | 1.4x faster writes | Zero dependencies | Pure Python
Features | Installation | Quick Start | Performance | Documentation
Overview
gsply is a pure Python library for ultra-fast reading and writing of Gaussian Splatting PLY files. Built specifically for performance-critical applications, gsply achieves 6.3x faster reads and 1.4x faster writes compared to plyfile, with zero external dependencies beyond numpy.
Why gsply?
- Blazing Fast: Zero-copy reads by default, single bulk operations
- Zero Dependencies: Pure Python + numpy (no C++ compilation needed)
- Format Support: Uncompressed PLY + PlayCanvas compressed format
- Auto-Detection: Automatically detects format and SH degree
- Production Ready: 65 passing tests, comprehensive benchmarks, CI/CD pipeline
Features
- Fastest Gaussian PLY I/O: Read 6.3x faster, write 1.4x faster than plyfile
- Read (default zero-copy): 8.09ms (400K Gaussians, SH0) - 49M Gaussians/sec
- Write (uncompressed): 8.72ms vs 12.18ms (50K Gaussians, SH3)
- Compressed read: 14.74ms (400K Gaussians) - 27M Gaussians/sec
- Compressed write: 63ms (400K Gaussians) - 6.3M Gaussians/sec with parallel processing
- Zero-copy optimization: Enabled by default for maximum performance
- Zero dependencies: Pure Python + numpy (no compilation required)
- Multiple SH degrees: Supports SH degrees 0-3 (14, 23, 38, 59 properties)
- Compressed format: PlayCanvas-compatible chunk-based compression (3.4x smaller for SH0)
- Auto-format detection: Automatically detects uncompressed vs compressed formats
- Type-safe: Full type hints for Python 3.10+
- GSData container: Named tuple for clean attribute access and tuple unpacking
Installation
From PyPI (coming soon)
pip install gsply
From Source
git clone https://github.com/OpsiClear/gsply.git
cd gsply
pip install -e .
Quick Start
import gsply
# Read PLY file (auto-detects format) - returns GSData container
# Uses fast zero-copy mode by default (6.3x faster than plyfile)
data = gsply.plyread("model.ply")
print(f"Loaded {data.means.shape[0]} Gaussians")
# Access via attributes
positions = data.means
colors = data.sh0
# Or unpack if needed (for compatibility)
means, scales, quats, opacities, sh0, shN = data[:6]
# Explicit zero-copy reading (default, 6.3x faster than plyfile)
data = gsply.plyread("model.ply", fast=True)
# Safe copy reading (if you need independent arrays)
data = gsply.plyread("model.ply", fast=False)
# Write uncompressed PLY file
gsply.plywrite("output.ply", data.means, data.scales, data.quats,
data.opacities, data.sh0, data.shN)
# Write compressed PLY file (saves as "output.compressed.ply", 14.5x smaller)
gsply.plywrite("output.ply", data.means, data.scales, data.quats,
data.opacities, data.sh0, data.shN, compressed=True)
# Detect format before reading
is_compressed, sh_degree = gsply.detect_format("model.ply")
print(f"Compressed: {is_compressed}, SH degree: {sh_degree}")
API Reference
plyread(file_path, fast=True)
Read Gaussian Splatting PLY file (auto-detects format).
Parameters:
file_path(str | Path): Path to PLY filefast(bool, optional): Use zero-copy optimization for uncompressed files. Default: True.fast=True: 1.65x faster, uses array views (default)fast=False: Safe independent copies of all arrays
Returns:
GSData namedtuple with Gaussian parameters:
means: (N, 3) - Gaussian centersscales: (N, 3) - Log scalesquats: (N, 4) - Rotations as quaternions (wxyz)opacities: (N,) - Logit opacitiessh0: (N, 3) - DC spherical harmonicsshN: (N, K, 3) - Higher-order SH coefficients (K=0 for degree 0, K=9 for degree 1, etc.)base: Base array (None for safe copies, array for zero-copy reads)
Performance:
fast=True: ~2.89ms for 50K Gaussians (zero-copy views)fast=False: ~4.75ms for 50K Gaussians (safe copies)- Speedup: 1.65x with zero-copy optimization
Example:
# Default: fast zero-copy reading (1.65x faster)
data = gsply.plyread("model.ply")
print(f"Loaded {data.means.shape[0]} Gaussians with SH degree {data.shN.shape[1]}")
# Access via attributes
positions = data.means
colors = data.sh0
# Or unpack if needed
means, scales, quats, opacities, sh0, shN = data[:6]
# Safe copy reading (if you need independent arrays)
data = gsply.plyread("model.ply", fast=False)
plywrite(file_path, means, scales, quats, opacities, sh0, shN=None, compressed=False)
Write Gaussian Splatting PLY file.
Parameters:
file_path(str | Path): Output PLY file path (auto-adjusted to.compressed.plyifcompressed=True)means(np.ndarray): Shape (N, 3) - Gaussian centersscales(np.ndarray): Shape (N, 3) - Log scalesquats(np.ndarray): Shape (N, 4) - Rotations as quaternions (wxyz)opacities(np.ndarray): Shape (N,) - Logit opacitiessh0(np.ndarray): Shape (N, 3) - DC spherical harmonicsshN(np.ndarray, optional): Shape (N, K, 3) or (N, K*3) - Higher-order SHcompressed(bool): If True, write compressed format and auto-adjust extension
Format Selection:
compressed=Falseor.plyextension -> Uncompressed format (fast)compressed=True-> Compressed format, saves as.compressed.plyautomatically.compressed.plyor.ply_compressedextension -> Compressed format
Performance:
- Uncompressed: ~8ms for 400K Gaussians (49M Gaussians/sec)
- Compressed: ~63ms for 400K Gaussians (6.3M Gaussians/sec), 3.4x smaller files
Example:
# Write uncompressed (fast, ~8ms for 400K Gaussians)
gsply.plywrite("output.ply", means, scales, quats, opacities, sh0, shN)
# Write compressed (saves as "output.compressed.ply", ~63ms, 3.4x smaller)
gsply.plywrite("output.ply", means, scales, quats, opacities, sh0, shN, compressed=True)
detect_format(file_path)
Detect PLY format type and SH degree.
Parameters:
file_path(str | Path): Path to PLY file
Returns: Tuple of (is_compressed, sh_degree):
is_compressed(bool): True if compressed formatsh_degree(int | None): 0-3 for uncompressed, None for compressed/unknown
Example:
is_compressed, sh_degree = gsply.detect_format("model.ply")
if is_compressed:
print("Compressed PlayCanvas format")
else:
print(f"Uncompressed format with SH degree {sh_degree}")
Performance
Benchmark Results
Real-World Dataset (90 files, 36M Gaussians total, SH degree 0):
| Operation | gsply | Throughput | Details |
|---|---|---|---|
| Read (uncompressed, zero-copy) | 8.09ms | 49M Gaussians/sec | 400K Gaussians avg |
| Write (compressed) | 63ms | 6.3M Gaussians/sec | 400K Gaussians, 3.4x compression |
| Read (compressed) | 14.74ms | 27M Gaussians/sec | Parallel decompression |
Comparison vs Other Libraries (50K Gaussians, SH degree 3):
| Operation | gsply | plyfile | Open3D | Winner |
|---|---|---|---|---|
| Read (zero-copy, default) | 2.89ms | 18.23ms | 43.10ms | gsply 6.3x faster |
| Read (safe copies) | 4.75ms | 18.23ms | 43.10ms | gsply 3.8x faster |
| Write (uncompressed) | 8.72ms | 12.18ms | 35.69ms | gsply 1.4x faster |
Why gsply is Faster
Read Performance (6.3x speedup with zero-copy, default):
- gsply: Single
np.fromfile()+ zero-copy array views (keeps base array alive) - plyfile: 59 individual property accesses + column stacking + multiple copies
- Result: No memory copies for shN coefficients, 1.65x faster than safe copies
- Alternative:
fast=Falsestill achieves 3.8x speedup with safe independent arrays
Write Performance (1.4x speedup):
- gsply: Pre-allocated arrays + dtype optimization + direct binary write
- plyfile: 59 individual assignments + PLY structure overhead
- Result: Eliminates unnecessary copies and type conversions
Compressed Format (with optimizations):
- Read: 14.74ms for 400K Gaussians (27M Gaussians/sec) via parallel JIT decompression
- Write: 63ms for 400K Gaussians (6.3M Gaussians/sec) via radix sort + parallel JIT packing
- Optimizations: O(n) radix sort for chunk sorting, numba parallel processing for bit packing/unpacking
- Size: 3.4x smaller files with PlayCanvas-compatible chunk quantization
Key Insight: gsply's performance comes from recognizing that Gaussian Splatting PLY files follow a fixed format, allowing bulk operations and zero-copy views instead of generic PLY parsing. For details, see docs/PERFORMANCE.md.
Format Support
Uncompressed PLY
Standard binary little-endian PLY format with Gaussian Splatting properties:
| 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 with automatic extension handling:
- File extension: Automatically saves as
.compressed.plywhencompressed=True - Compression ratio: 3.4x for SH0 (3.8-14.5x depending on SH degree)
- Chunk size: 256 Gaussians per chunk
- Bit-packed data: 11-10-11 bits (position/scale), 2+10-10-10 bits (quaternion)
- Parallel decompression: 14.74ms for 400K Gaussians (27M Gaussians/sec)
- Parallel compression: 63ms for 400K Gaussians (6.3M Gaussians/sec) with radix sort
- Compatible with: PlayCanvas, SuperSplat, other WebGL viewers
For format details, see docs/COMPRESSED_FORMAT.md.
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/
│ ├── __init__.py # Public API
│ ├── reader.py # PLY reading (uncompressed + compressed)
│ ├── writer.py # PLY writing (uncompressed + compressed)
│ └── py.typed # PEP 561 type marker
├── tests/ # Unit tests (56 tests)
├── benchmarks/ # Performance benchmarks
├── docs/ # Documentation
│ ├── PERFORMANCE.md # Performance benchmarks and optimization history
│ ├── COMPRESSED_FORMAT.md # Compressed PLY format specification
│ ├── VECTORIZATION_EXPLAINED.md # Vectorization deep-dive
│ ├── CI_CD_SETUP.md # CI/CD pipeline documentation
│ ├── BUILD.md # Build and distribution guide
│ ├── RELEASE_NOTES.md # Release notes and version history
│ ├── COMPATIBILITY_FIXES.md # Format compatibility details
│ └── archive/ # Historical documentation
├── .github/ # CI/CD workflows
├── pyproject.toml # Package configuration
└── README.md # This file
Benchmarking
Compare gsply performance against other PLY libraries:
# Install benchmark dependencies
pip install -e .[benchmark]
# Run benchmark with default settings
python benchmarks/benchmark.py
# Custom test file and iterations
python benchmarks/benchmark.py --config.file path/to/model.ply --config.iterations 20
# Skip write benchmarks
python benchmarks/benchmark.py --config.skip-write
The benchmark measures:
- Read performance: Time to load PLY file into numpy arrays
- Write performance: Time to write numpy arrays to PLY file
- File sizes: Comparison of output file sizes
- Verification: Output equivalence between libraries
Example output:
READ PERFORMANCE (50K Gaussians, SH degree 3)
Library Time Speedup
gsply (fast) 2.89ms baseline (FASTEST)
gsply (safe) 4.75ms 0.61x (1.6x slower than fast)
plyfile 18.23ms 0.16x (6.3x SLOWER)
Open3D 43.10ms 0.07x (14.9x slower)
WRITE PERFORMANCE
Library Time Speedup File Size
gsply 8.72ms baseline (FASTEST) 11.34MB
plyfile 12.18ms 0.72x (1.4x slower) 11.34MB
Open3D 35.69ms 0.24x (4.1x slower) 1.15MB (XYZ only)
Testing
gsply has comprehensive test coverage with 65 passing tests:
# Run all tests
pytest tests/ -v
# Run specific test file
pytest tests/test_reader.py -v
# Run with coverage report
pytest tests/ -v --cov=gsply --cov-report=html
Test categories:
- Format detection (compressed/uncompressed, SH degrees)
- Reading (various SH degrees, edge cases, compressed format)
- Writing (various SH degrees, format preservation, compressed format)
- Round-trip (read-write-read consistency)
- Error handling (invalid files, malformed data)
Documentation
gsply includes comprehensive documentation covering all aspects of the library:
- docs/PERFORMANCE.md - Performance benchmarks, optimization history, and comparison with other libraries
- docs/COMPRESSED_FORMAT.md - Complete compressed PLY format specification with examples
- docs/VECTORIZATION_EXPLAINED.md - Deep-dive into vectorization techniques for 38.5x speedup
- docs/BUILD.md - Build system, distribution, and packaging guide
- docs/CI_CD_SETUP.md - CI/CD pipeline reference and GitHub Actions workflows
- docs/RELEASE_NOTES.md - Release notes and version history
- docs/COMPATIBILITY_FIXES.md - Format compatibility details and fixes
- docs/archive/ - Historical documentation from development phases
CI/CD
gsply includes a complete GitHub Actions CI/CD pipeline:
- Multi-platform testing: Ubuntu, Windows, macOS
- Multi-version testing: Python 3.10, 3.11, 3.12, 3.13
- Automated benchmarking: Performance tracking on PRs
- Build verification: Wheel building and installation testing
- PyPI publishing: Automated release on GitHub Release
See docs/CI_CD_SETUP.md for details.
Contributing
Contributions are welcome! Please see .github/CONTRIBUTING.md for guidelines.
Quick start:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run tests and benchmarks
- 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gsply-0.1.0.tar.gz.
File metadata
- Download URL: gsply-0.1.0.tar.gz
- Upload date:
- Size: 40.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76988cb5f74b997c170e8cfc4b731edfa0964996b94f38c300900ae02bf796dd
|
|
| MD5 |
6b4885d6693b01120e983fe5f426d104
|
|
| BLAKE2b-256 |
afca3a79fa6bed7ff0fc33da101ce668d78b50dd37e394595e204960ca3b9f08
|
Provenance
The following attestation bundles were made for gsply-0.1.0.tar.gz:
Publisher:
publish.yml on OpsiClear/gsply
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gsply-0.1.0.tar.gz -
Subject digest:
76988cb5f74b997c170e8cfc4b731edfa0964996b94f38c300900ae02bf796dd - Sigstore transparency entry: 689209170
- Sigstore integration time:
-
Permalink:
OpsiClear/gsply@5d101595a94efe79c2b44819d2c00b4a6049faad -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/OpsiClear
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5d101595a94efe79c2b44819d2c00b4a6049faad -
Trigger Event:
release
-
Statement type:
File details
Details for the file gsply-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gsply-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8d0b380cc71ab4b0d18ae163e7e31f99d812ec3708d22a68a9766a533a89458
|
|
| MD5 |
4370c341cb7ff21a7fb14ab7221a0852
|
|
| BLAKE2b-256 |
fd83385d4f47e726e15c230e8d78a4c988fc0325c6b648b442fb6c3513fdece5
|
Provenance
The following attestation bundles were made for gsply-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on OpsiClear/gsply
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gsply-0.1.0-py3-none-any.whl -
Subject digest:
a8d0b380cc71ab4b0d18ae163e7e31f99d812ec3708d22a68a9766a533a89458 - Sigstore transparency entry: 689209184
- Sigstore integration time:
-
Permalink:
OpsiClear/gsply@5d101595a94efe79c2b44819d2c00b4a6049faad -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/OpsiClear
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5d101595a94efe79c2b44819d2c00b4a6049faad -
Trigger Event:
release
-
Statement type: