Skip to content

PointCloudBatch

SUMMARY

A batch of 3D point clouds.

python
from telekinesis import datatypes
import numpy as np
batch = datatypes.PointCloudBatch([np.zeros((10, 3), dtype=np.float32)])
API Reference
Complete API documentation for PointCloudBatch, including parameters, attributes, and methods.
View Reference →

Parameters

ParameterTypeDefaultDescription
point_cloudsSequence[PointCloud | np.ndarray]RequiredSequence of PointCloud instances or position arrays with shape (N_i, 3). Bare arrays create positions-only point clouds.
compressionPointCloudCompression | int | NoneNoneOptional compression override applied to every point cloud. If None, existing PointCloud codecs are preserved and bare arrays use PointCloudCompression.NONE.

Raises

ExceptionCondition
TypeErrorpoint_clouds isn't a list/tuple, or an element isn't a PointCloud/np.ndarray
ValueErrorAn element's positions/normals/colors have an unsupported shape, or compression isn't a valid PointCloudCompression member/matching int

Attributes

AttributeTypeDescription
positionslist[np.ndarray]Defensive copy of each cloud's positions, (N_i, 3) float32, one entry per cloud.
normalslist[np.ndarray | None]Defensive copy of each cloud's normals, or None per cloud.
colorslist[np.ndarray | None]Defensive copy of each cloud's colors, or None per cloud.
compressionslist[PointCloudCompression]Each cloud's PointCloudCompression codec, in order, one entry per cloud.

The compressions attribute exposes each cloud's codec, but there's no batch-level accessor for the other Draco tuning parameters (quantization_bits, compression_level, ...). Index with batch[i] to get one PointCloud and read its own compression_settings.

Methods

MethodTypeDescription
PointCloudBatch.coerce(value)PointCloudBatchConverts a sequence of point clouds into a PointCloudBatch. Accepts a list or tuple mixing PointCloud instances and bare (N, 3) arrays. If value is already a PointCloudBatch, it is returned unchanged.
to_numpy(copy=True)list[np.ndarray]Returns each cloud's positions as a list of plain arrays. With the default copy=True you get independent copies; pass copy=False to get direct references to the batch's internal position arrays instead. Normals, colors, and compression settings aren't included; read those from their own properties or by indexing into the batch.
copy()PointCloudBatchReturns a new, independent PointCloudBatch with its own storage for every cloud's positions, normals, and colors, keeping each cloud's Draco compression settings.

Operators

OperationBehavior
len(batch)Number of point clouds B.
batch[i]int returns a materialized PointCloud (defensive copy; IndexError if out of range); slice or boolean np.ndarray mask returns a new PointCloudBatch sub-batch. Anything else raises TypeError.
batch == otherTrue only if other is a PointCloudBatch with the same number of clouds and row-for-row equal positions/normals/colors, using the same draco_atol tolerance rule as PointCloud.__eq__. Logs a warning if any row matched only within tolerance. NotImplemented if other isn't a PointCloudBatch.

Visualization

python
import rerun as rr

# Your code block
# ....

rr.init("point_cloud_batch_example", spawn=True)
datatypes.visualize(batch, entity_path="/batch", label="PointCloudBatch")

Example

python
"""Demonstrates the Telekinesis PointCloudBatch datatype."""

import time

import numpy as np
import rerun as rr
from loguru import logger

from telekinesis import datatypes

def point_cloud_batch_example():
    """Demonstrate creation, inspection, operations, visualization, and serialization."""

    # ======================= Create ============================================
    N = 2000
    cloud_1 = datatypes.PointCloud(
        np.random.randn(N, 3).astype(np.float32) + np.array([-5.0, 0.0, 0.0], dtype=np.float32),
        normals=np.random.randn(N, 3).astype(np.float32),
        colors=np.random.randint(0, 255, (N, 3), dtype=np.uint8),
    )
    cloud_2 = np.random.randn(N, 3).astype(np.float32) + np.array(
        [5.0, 0.0, 0.0], dtype=np.float32
    )
    point_cloud_batch = datatypes.PointCloudBatch([cloud_1, cloud_2])
    logger.info(f"Created PointCloudBatch: {point_cloud_batch}")

    point_cloud_batch_from_coerce = datatypes.PointCloudBatch.coerce([cloud_1, cloud_2])
    logger.info(f"PointCloudBatch created via coerce: {point_cloud_batch_from_coerce}")

    # ======================= Inspect ===========================================
    logger.info(f"positions={point_cloud_batch.positions}")
    logger.info(f"normals={point_cloud_batch.normals}")
    logger.info(f"colors={point_cloud_batch.colors}")
    logger.info(f"compressions={point_cloud_batch.compressions}")
    logger.info(f"length={len(point_cloud_batch)}")

    # ======================= Operations =========================================
    single_cloud = point_cloud_batch[0]
    logger.info(f"Single PointCloud at index 0: {single_cloud}")

    sliced_batch = point_cloud_batch[0:1]
    logger.info(f"Sliced PointCloudBatch: {sliced_batch}")

    mask = np.array([True, False])
    masked_batch = point_cloud_batch[mask]
    logger.info(f"Masked PointCloudBatch: {masked_batch}")

    point_cloud_batch_copy = point_cloud_batch.copy()
    logger.info(f"Copied PointCloudBatch: {point_cloud_batch_copy}")

    point_cloud_batch_numpy = point_cloud_batch.to_numpy(copy=True)
    logger.info(f"NumPy positions per cloud: {[array.shape for array in point_cloud_batch_numpy]}")

    updated_cloud = datatypes.PointCloud(
        np.random.randn(N, 3).astype(np.float32),
        colors=np.full((N, 3), [255, 0, 0], dtype=np.uint8),
    )
    rebuilt_batch = datatypes.PointCloudBatch([cloud_1, updated_cloud])
    logger.info(f"Rebuilt PointCloudBatch: {rebuilt_batch}")

    # ======================= Visualize =========================================
    rr.init("point_cloud_batch_example", spawn=True)
    datatypes.visualize(
        point_cloud_batch,
        entity_path="/point_cloud_batch/original",
        label=["Cloud 1", "Cloud 2"],
    )
    datatypes.visualize(
        rebuilt_batch,
        entity_path="/point_cloud_batch/rebuilt",
        label=["Cloud 1", "Updated Cloud 2"],
    )

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(point_cloud_batch)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized PointCloudBatch: {deserialized}")
    logger.info(f"Round-trip successful: {point_cloud_batch == deserialized}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    point_cloud_batch_example()