Skip to content

Latest commit

Β 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Fast Depth Compression (fdcomp)

A high-performance Python library for lossless depth image compression using state-of-the-art TRVL (Temporal RVL) and RVL algorithms.

Python C++ OpenCV Tests

Disclaimer: The project is currently under development and there might be installation issues or issues in the backend. Please report these in the issues, I am trying to fix it as soon as possible. Pre-compiled binaries will be available at some point but for now please install everything from source.

Recent Major Updates:

  • βœ… Backend Migration Complete: The Python frontend has been successfully moved to the C++ backend for improved performance
  • βœ… Enhanced C++ Bindings: Optimized Python bindings with zero-copy operations and NumPy integration
  • βœ… Performance Testing: Added comprehensive performance benchmarking tools
  • βœ… Improved API: Streamlined encoder/decoder interfaces with better error handling

✨ Features

  • πŸ”₯ Ultra-Fast Performance: C++ backend with Python bindings for optimal speed
  • πŸ“Š TRVL Algorithm: Advanced temporal compression for depth video sequences
  • ⚑ RVL Algorithm: Wilson's Run-Length Variable compression implementation
  • πŸ”„ Lossless Compression: Perfect reconstruction of depth data
  • πŸ“¦ Easy Integration: Simple Python API for seamless workflow integration

πŸ“š Table of Contents

Section Description
πŸ“ Project Structure Overview of project folders and files
πŸ“ˆ Performance Overview of project folders and files
βš™οΈ Installation Prerequisites & installation steps
πŸš€ Quick Start Basic usage examples
πŸ“– API Reference Details of encoders, decoders, utilities
πŸ§ͺ Tests How to run the test suite
πŸ“œ Algorithm References Citations for compression algorithms
πŸ“„ License Licensing information

πŸ“ Project Structure

fast-depth-compression/
β”œβ”€β”€ πŸ“ backend/              # C++ implementation
β”‚   β”œβ”€β”€ πŸ“ cpp/              # Core algorithms
β”‚   └── πŸ“ bindings/         # Python bindings
β”œβ”€β”€ πŸ“ fdcomp/               # Python package
β”œβ”€β”€ πŸ“ examples/             # Usage/data examples
β”œβ”€β”€ πŸ“ tests/                # Tests for Python/C++
└── πŸ“„ README.md             # This file

πŸ“ˆ Performance

  • Easy Python API: Shallow Numpy API with similar structure to json and yaml libraries.
  • High-performance C++ core: Compute-heavy paths implemented in modern C++.
  • Zero-copy bridging: NumPy arrays are passed to C++ without intermediate copies.
  • GIL released: Encode/decode run outside the Python GIL, enabling real multi-threaded
Algorithm Video Length Shape Loading Saving
TRVL 139 (350, 630) 129.19 ms 165.75 ms

Note that these were measured in Python with much of the running time coming from the bindings.

πŸ—οΈ Installation

Prerequisites

These prereuisities are currently based on my current setups, I have tested the package on. All tests were made on Ubuntu 22.4

So, before installation, ensure you have:

  • Python 3.11 or higher
  • CMake 3.30 or higher
  • OpenCV development libraries
  • C++14 compatible compiler

πŸ“¦ Install System Dependencies

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install cmake build-essential
# (Optional) If you want to build tests
sudo apt-get install libopencv-dev 

πŸš€ Install fdcomp

Option 1: Direct Installation (Recommended)

pip install .

Option 2: Development Installation

pip install -e .

Option 3: Build C++ backend with tests

mkdir build
cd build
cmake -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_CPP_TESTS=ON ..
cmake --build .

🎯 Quick Start

Basic TRVL Compression Example

import fdcomp
import numpy as np
import matplotlib.pyplot as plt

# Load depth data
depth_arr = np.load("examples/depth.npz")['depth'][0]
height, width = depth_arr.shape

# Initialize TRVL encoder/decoder
encoder = fdcomp.EncoderTRVL(
    frame_size=width * height, 
    change_threshold=10, 
    invalidation_threshold=2
)
decoder = fdcomp.DecoderTRVL(frame_size=width * height)

# Compress depth frame
compressed_data = encoder.encode(depth_arr, keyframe=False)
print(f"Original size: {depth_arr.nbytes} bytes")
print(f"Compressed size: {len(compressed_data)} bytes")
print(f"Compression ratio: {depth_arr.nbytes / len(compressed_data):.2f}x")

# Decompress and verify
decompressed = decoder.decode(compressed_data)
decompressed = np.reshape(decompressed, (height, width))
decompressed = decompressed.view(np.float16)

# Check lossless compression
l2_error = np.linalg.norm(depth_arr - decompressed)
print(f"L2 reconstruction error: {l2_error}")  # Should be 0.0 for lossless

# Save visualization
original_img = ((depth_arr.astype(np.float32) / depth_arr.max()) * 255).astype(np.uint8)
restored_img = ((decompressed.astype(np.float32) / decompressed.max()) * 255).astype(np.uint8)

plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.imshow(original_img, cmap='gray')
plt.title('Original Depth')
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(restored_img, cmap='gray')
plt.title('Decompressed Depth')
plt.axis('off')

plt.tight_layout()
plt.savefig('compression_comparison.png', dpi=150, bbox_inches='tight')
plt.show()

Simple File Save/Load Example

import fdcomp
import numpy as np

# Load your depth data
depth_arr = np.load("examples/depth.npz")['depth'][0]

# Save compressed depth file
fdcomp.save(depth_arr, "my_depth.dep")

# Load and verify
loaded_depth = fdcomp.load("my_depth.dep")

print(f"Original shape: {depth_arr.shape}, dtype: {depth_arr.dtype}")
print(f"Loaded shape: {loaded_depth.shape}, dtype: {loaded_depth.dtype}")

# Verify lossless compression
l2_error = np.linalg.norm(depth_arr - loaded_depth)
print(f"Reconstruction error: {l2_error}")  # Should be 0.0

πŸ“– API Reference

The fdcomp API consists of a high-level Python interface powered by an optimized C++ backend with zero-copy operations and NumPy integration.

🐍 Python API

High-Level Functions

save(data: np.ndarray, file: Union[str, Path], encoder: Union[str, Encoder] = "trvl", **kwargs)

  • Save depth data to compressed file format
  • data: NumPy array with depth data (2D or 3D)
  • file: Output file path (automatically adds .dep extension)
  • encoder: Compression algorithm - "trvl", "rvl", or "raw"

load(file: Union[str, Path], decoder: Union[str, Decoder] = None, **kwargs) β†’ np.ndarray

  • Load compressed depth data from file
  • file: Input file path
  • decoder: Decompression algorithm (auto-detected if None)
  • Returns: Reconstructed depth data as NumPy array

loads(data: Union[bytes, List[bytes]], decoder: Union[str, Decoder], frame_size: int, **kwargs) β†’ np.ndarray

  • Load depth data from raw compressed bytes
  • data: Compressed bytes or list of frame bytes
  • decoder: Decompression algorithm
  • frame_size: Number of pixels per frame

dump(data: np.ndarray, encoder: Union[str, Encoder], **kwargs) β†’ Union[bytes, List[bytes]]

  • Compress depth data to bytes without saving to file
  • data: NumPy array with depth data
  • encoder: Compression algorithm

inspect(file: Union[str, Path], print_result: bool = True) β†’ dict

  • Analyze compressed file metadata
  • Returns: Dictionary with file information (shape, dtype, compression type, etc.)

Base Classes

Class: Encoder C++ backend wrapper for all encoders with optimized NumPy integration

class Encoder:
    def encode(self, data: np.ndarray, verbose: bool = False, *args, **kwargs) β†’ Union[bytes, List[bytes]]
    def _cast_int16(self, data: np.ndarray, suppress_warnings: bool = True) β†’ np.ndarray
  • encode(data, verbose=False): Main encoding method with automatic dtype conversion
  • _cast_int16(data): Smart conversion to int16 with minimal copying (float16β†’view, float32β†’narrow+view)

Class: FrameEncoder(Encoder) Single-frame encoder with C++ backend

class FrameEncoder(Encoder):
    def __init__(self, frame_size: int, suppress_warnings: bool = True)

Class: VideoEncoder(Encoder) Multi-frame encoder with C++ backend

class VideoEncoder(Encoder):
    def __init__(self, frame_encoder: FrameEncoder, suppress_warnings: bool = True)
    def encode(self, data: np.ndarray, *args, **kwargs) β†’ List[bytes]

Class: Decoder C++ backend wrapper for all decoders with NumPy output optimization

class Decoder:
    def decode(self, data: Union[bytes, List[bytes]], output_size: Tuple[int,int] = None, 
               dtype = np.int16, verbose: bool = False, *args, **kwargs) β†’ np.ndarray
  • decode(): Main decoding method returning NumPy arrays directly from C++
  • output_size: Optional reshaping to (height, width)
  • dtype: Output data type (int16, float16, float32)
  • verbose: Enable timing information

Class: FrameDecoder(Decoder) Single-frame decoder with C++ backend

Class: VideoDecoder(Decoder) Multi-frame decoder with C++ backend

Algorithm Implementations

TRVL (Temporal RVL) - Optimized for depth video sequences

Class Description Key Parameters
EncoderTRVL Frame-level TRVL encoder frame_size, change_threshold=10, invalidation_threshold=2
EncoderTRVLVideo Video TRVL encoder with keyframe support frame_size, keyframe_interval=10, change_threshold=10, invalidation_threshold=2
DecoderTRVL Frame-level TRVL decoder frame_size
DecoderTRVLVideo Video TRVL decoder with keyframe handling frame_size, keyframe_interval=10

RVL (Run-Length Variable) - Fast general-purpose compression

Class Description Key Parameters
EncoderRVL Frame-level RVL encoder frame_size
EncoderRVLVideo Video RVL encoder frame_size
DecoderRVL Frame-level RVL decoder frame_size
DecoderRVLVideo Video RVL decoder with optimized flat output frame_size

Raw - Uncompressed NumPy serialization

Class Description
EncoderRaw NumPy array serialization
EncoderRawVideo Multi-frame NumPy serialization
DecoderRaw NumPy array deserialization
DecoderRawVideo Multi-frame NumPy deserialization

⚑ C++ Backend API

The C++ backend provides high-performance implementations with zero-copy operations and optimized memory management.

Base Classes

FrameEncoder

class FrameEncoder {
public:
    explicit FrameEncoder(int frame_size);
    virtual std::vector<char> encode(short* depth_buffer) = 0;
    
    int getFrameSize();
    void setFrameSize(int frame_size);
};

VideoEncoder

class VideoEncoder {
public:
    VideoEncoder(FrameEncoder* encoder);
    
    std::vector<std::vector<char>> encode(short* depth_buffer, int num_frames);
    std::vector<std::vector<char>> encode(short* depth_buffer);
    
    void setFrameEncoder(FrameEncoder* encoder);
    void setFrameSize(int frame_size);
    void setNumFrames(int num_frames);
    int getFrameSize();
    int getNumFrames();
};

FrameDecoder

class FrameDecoder {
public:
    explicit FrameDecoder(int frame_size);
    virtual std::vector<short> decode(char* compressed_bytes) = 0;
    
    int getFrameSize();
    void setFrameSize(int frame_size);
};

VideoDecoder

class VideoDecoder {
public:
    explicit VideoDecoder(FrameDecoder* decoder);
    
    std::vector<std::vector<short>> decode(std::vector<char*> video_bytes);
    std::vector<std::vector<short>> decode(std::vector<std::vector<char>> video_bytes);
    
    void setFrameDecoder(FrameDecoder* decoder);
    void setFrameSize(int frame_size);
    void setNumFrames(int num_frames);
    int getFrameSize();
    int getNumFrames();
};

TRVL Implementation

trvl::EncoderTRVL

class EncoderTRVL : public FrameEncoder {
public:
    EncoderTRVL(int frame_size, short change_threshold, int invalidation_threshold);
    
    std::vector<char> encode(short* depth_buffer, bool keyframe);
    std::vector<char> encode(short* depth_buffer) override;
    void setKeyframe(bool is_keyframe);
};

trvl::VideoEncoderTRVL

class VideoEncoderTRVL : public VideoEncoder {
public:
    VideoEncoderTRVL(int keyframe_interval, int frame_size, 
                     short change_threshold, int invalidation_threshold);
    
    std::vector<std::vector<char>> encode(short* depth_buffer) override;
};

trvl::DecoderTRVL

class DecoderTRVL : public FrameDecoder {
public:
    explicit DecoderTRVL(int frame_size);
    
    std::vector<short> decode(char* trvl_frame, bool keyframe);
    std::vector<short> decode(char* compressed_bytes) override;
};

trvl::VideoDecoderTRVL

class VideoDecoderTRVL : public VideoDecoder {
public:
    VideoDecoderTRVL(int keyframe_interval, int frame_size);
    
    std::vector<short> decode(std::vector<char*>& video_bytes, std::vector<int> keyframes);
    std::vector<std::vector<short>> decode(std::vector<char*>& video_bytes) override;
    void setKeyframeInterval(int interval);
};

RVL Implementation

EncoderRVL

class EncoderRVL : public FrameEncoder {
public:
    explicit EncoderRVL(int frame_size);
    std::vector<char> encode(short* depth_buffer) override;
};

VideoEncoderRVL

class VideoEncoderRVL : public VideoEncoder {
public:
    explicit VideoEncoderRVL(int frame_size);
};

DecoderRVL

class DecoderRVL : public FrameDecoder {
public:
    explicit DecoderRVL(int frame_size);
    std::vector<short> decode(char* compressed_bytes) override;
};

VideoDecoderRVL

class VideoDecoderRVL : public VideoDecoder {
public:
    explicit VideoDecoderRVL(int frame_size);
    
    std::vector<std::vector<short>> decode(std::vector<char*>& video_bytes) override;
    std::vector<int16_t> decode_flat(std::vector<char*>& video_bytes, int& elems_per_frame_out);
};

πŸ“œ Algorithm References

If you use this library in your work, please consider citing the authors of the compression algorithms used:

  • RVL Algorithm: Based on Wilson, A. D. (2017). "Fast lossless depth image compression." The original RVL implementation (files backend/cpp/include/rvl.h) is licensed under Apache 2.0.

  • TRVL Algorithm: Based on Jun, H & Bailenson, J. (2020). "Temporal RVL: A Depth Stream Compression Method." The original TRVL implementation (files backend/cpp/include/trvl.h) is licensed under Apache 2.0, derived from https://github.com/hanseuljun/temporal-rvl.

πŸ“„ License

This project is licensed under the Apache License 2.0.

About

A python library for efficient depth compression to increase throughput and minimize memory footprint

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages