Skip to main content

Crate cloudini

Crate cloudini 

Source
Expand description

§cloudini

A point cloud compression library implementing the Cloudini format.

Cloudini uses a two-stage pipeline:

  1. Field encoding — each point field is encoded with a type-appropriate scheme:
    • Integers → delta + zigzag varint
    • Float32/Float64 with resolution → quantization + delta + varint (lossy)
    • Float64 without resolution → XOR with previous value (lossless)
  2. Block compression — the encoded byte stream is compressed with LZ4 or ZSTD.

Typical results on Lidar geometry (XYZ @ 1 mm + intensity): ~34% compressed size with Lossy + ZSTD.

§Quickstart

use cloudini::ros::{CompressExt, CompressionConfig, PointCloud2Msg};
use ros_pointcloud2::points::PointXYZI;

let resolution = 0.001_f32; // 1 mm

// Build a PointCloud2Msg from a vec of typed points (simulated Lidar scan)
let points: Vec<PointXYZI> = (0..200)
    .map(|i| {
        let t = i as f32 * 0.05;
        PointXYZI::new(t.sin() * 5.0, t.cos() * 5.0, t * 0.1, i as f32)
    })
    .collect();
let cloud = PointCloud2Msg::try_from_vec(points.clone()).unwrap();
let raw_size = cloud.data.len();

// Compress — 1 mm lossy + ZSTD
let compressed = cloud.compress(CompressionConfig::lossy_zstd(resolution)).unwrap();
assert_eq!(compressed.format, "cloudini/lossy/zstd");
assert!(
    compressed.compressed_data.len() < raw_size,
    "compressed ({} B) should be smaller than raw ({} B)",
    compressed.compressed_data.len(), raw_size,
);

// Decompress — no metadata needed, it is all in the header
let restored = compressed.decompress().unwrap();
assert_eq!(restored.dimensions.width, 200);

// Each float component is within resolution / 2 of the original
let tol = resolution / 2.0 + 1e-6;
let restored_points: Vec<PointXYZI> = restored.try_into_iter().unwrap().collect();
for (orig, rest) in points.iter().zip(restored_points.iter()) {
    assert!((orig.x         - rest.x        ).abs() <= tol);
    assert!((orig.y         - rest.y        ).abs() <= tol);
    assert!((orig.z         - rest.z        ).abs() <= tol);
    assert!((orig.intensity - rest.intensity).abs() <= tol);
}

§Compression presets

ConstructorEncodingCompressionMax float error
ros::CompressionConfig::lossy_zstdLossyZSTDres / 2
ros::CompressionConfig::lossy_lz4LossyLZ4res / 2
ros::CompressionConfig::lossless_zstdLossless XORZSTD0
ros::CompressionConfig::lossless_lz4Lossless XORLZ40

ros::CompressionConfig::default is lossy_zstd(0.001) — suitable for most Lidar workloads.

§Raw API

Disable the default feature and drive the encoder/decoder directly:

cloudini = { version = "0.1.0", default-features = false }
use cloudini::{
    CompressionOption, EncodingInfo, EncodingOptions, FieldType, PointField,
    PointcloudDecoder, PointcloudEncoder,
};

// Describe the point layout: x, y, z (f32) + intensity (u8) = 13 bytes/point
let info = EncodingInfo {
    fields: vec![
        PointField { name: "x".into(),         offset: 0,  field_type: FieldType::Float32, resolution: Some(0.001) },
        PointField { name: "y".into(),         offset: 4,  field_type: FieldType::Float32, resolution: Some(0.001) },
        PointField { name: "z".into(),         offset: 8,  field_type: FieldType::Float32, resolution: Some(0.001) },
        PointField { name: "intensity".into(), offset: 12, field_type: FieldType::Uint8,   resolution: None        },
    ],
    width: 1000,
    height: 1,
    point_step: 13,
    encoding_opt: EncodingOptions::Lossy,
    compression_opt: CompressionOption::Zstd,
    ..EncodingInfo::default()
};

// raw_cloud: width * height * point_step bytes of packed point data
let raw_cloud: Vec<u8> = vec![0u8; 1000 * 13];
let compressed = PointcloudEncoder::new(info).encode(&raw_cloud).unwrap();

let (_info, decoded) = PointcloudDecoder::new().decode(&compressed).unwrap();
assert_eq!(decoded.len(), raw_cloud.len());

§Encoding modes

ModeFloat32/64 with resolutionFloat64 without resolutionIntegers
EncodingOptions::Noneraw copyraw copyraw copy
EncodingOptions::Lossyquantise → delta → varintraw copydelta → varint
EncodingOptions::Losslessraw copy (f32) / XOR (f64)XOR with prev bitsdelta → varint

§Compression backends

CompressionOptionNotes
Nonefield encoding only, no block compression
Lz4fast, moderate ratio
Zstdhigher ratio, higher CPU cost

Re-exports§

pub use decoder::PointcloudDecoder;
pub use encoder::PointcloudEncoder;
pub use error::Error;
pub use error::Result;
pub use header::decode_header;
pub use header::encode_header;
pub use header::encoding_info_from_yaml;
pub use header::encoding_info_to_yaml;
pub use types::CompressionOption;
pub use types::ENCODING_VERSION;
pub use types::EncodingInfo;
pub use types::EncodingOptions;
pub use types::FieldType;
pub use types::MAGIC_HEADER;
pub use types::POINTS_PER_CHUNK;
pub use types::PointField;

Modules§

decoder
Pointcloud decoder — reconstructs raw point data from a Cloudini buffer.
encoder
Pointcloud encoder — converts raw point data to a self-contained Cloudini buffer.
error
field_decoder
Per-field decoding logic for the Cloudini format.
field_encoder
Per-field encoding logic for the Cloudini format.
header
Cloudini header encode/decode.
ros
ROS integration — compress and decompress PointCloud2Msg using the Cloudini format.
types
Core types shared across the cloudini encoder and decoder.
varint
Zigzag varint encoding matching the Cloudini wire format.