Skip to content

DepthImage

Represents a per-pixel metric depth map, optionally paired with an aligned RGB image to form a full RGB-D frame.

Reference semantics on construction

Construction does not defensively copy a contiguous input array -- depth/colors are stored by reference. Pass arr.copy() explicitly if the source array may be mutated afterward. The depth/colors properties do return defensive copies.

Parameters

FieldTypeDescription
depthnp.ndarrayRequired depth map, shape (H, W), dtype float32, meters.
colorsnp.ndarray | NoneOptional aligned RGB image, shape (H, W, 3), dtype uint8, matching depth's height/width. Default None.
compressionImageCompression | intOn-wire compression codec, or a matching int. Default ImageCompression.NONE.

Raises

ExceptionCondition
TypeErrordepth or colors (when not None) isn't an np.ndarray
ValueErrordepth isn't dtype float32/shape (H, W); colors isn't dtype uint8/shape (H, W, 3) matching depth; or compression is invalid

Attributes

AttributeTypeDescription
depthnp.ndarrayDefensive copy, shape (H, W) float32 (meters). Read-only (no setter) -- construct a new DepthImage to change it.
colorsnp.ndarray | NoneDefensive copy, shape (H, W, 3) uint8, or None. Read-only.
shapetuple[int, int]Shape of depth, (H, W).
heightintDepth map height.
widthintDepth map width.
has_colorsboolWhether an aligned color image is attached.
compressionImageCompressionOn-wire codec. Read-only.

Methods

MethodDescription
DepthImage.coerce(value)Returns value unchanged if already a DepthImage; otherwise wraps an np.ndarray as depth. Raises TypeError for anything else.

There's no to_numpy() method (unlike Image/SegmentationImage) -- use the depth property or np.asarray(depth_image) for the depth map; colors is only reachable via the colors property.

Operators

OperationBehavior
di == otherTrue only if other is a DepthImage with an equal depth map and equal (or equally absent) colors; compression is not compared. NotImplemented if other isn't a DepthImage.
np.asarray(di)Returns a copy of depth only (not colors). copy=False raises ValueError -- there is no zero-copy accessor for depth on this class.
hash(di)Not supported.

Serialization

Arrow layout:

text
StructArray length 1
├── depth:       binary           (float32 (H, W) bytes, raw or ZSTD-framed)
├── colors:      binary nullable  (uint8 (H, W, 3) bytes, raw/ZSTD; null when absent)
├── height:      int32
├── width:       int32
└── compression: int8             (ImageCompression member value)

depth and colors share the same compression codec.

Visualization

datatypes.visualize(depth_image, entity_path=...) logs depth at {entity_path}/depth as rr.DepthImage, and, if has_colors, logs colors at {entity_path}/color as rr.Image.

Example

python
"""Demonstrates the Telekinesis DepthImage datatype."""

import time

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

from telekinesis import datatypes

def depth_image_example():
    """Demonstrate creation, inspection, visualization, update, RGB-D, compression, NumPy interop, and serialization."""

    # ======================= Create ============================================
    H, W = 480, 640
    depth = (np.random.rand(H, W) * 5.0).astype(np.float32)
    depth_image = datatypes.DepthImage(depth)

    logger.info(f"Input depth shape={depth.shape}, dtype={depth.dtype}")
    logger.info(f"Original DepthImage: {depth_image}")

    # ======================= Inspect ===========================================
    data = depth_image.depth
    shape = depth_image.shape
    height = depth_image.height
    width = depth_image.width
    has_colors = depth_image.has_colors
    compression = depth_image.compression
    numpy_array = np.asarray(depth_image)

    logger.info(
        f"shape={shape}, "
        f"height={height}, "
        f"width={width}, "
        f"has_colors={has_colors}, "
        f"compression={compression}"
    )
    logger.info(f"Data: {data}")
    logger.info(f"NumPy array: {numpy_array}")

    # ======================= Visualize =========================================
    rr.init("depth_image_example", spawn=True)
    datatypes.visualize(depth_image, entity_path="/DepthImage")

    # ======================= Update ============================================
    new_depth = (np.random.rand(H, W) * 5.0).astype(np.float32)
    depth_image = datatypes.DepthImage(new_depth)
    datatypes.visualize(depth_image, entity_path="/DepthImage")

    # ======================= RGB-D =============================================
    colors = np.random.randint(0, 255, (H, W, 3), dtype=np.uint8)
    rgbd_image = datatypes.DepthImage(depth, colors=colors)
    logger.info(f"RGB-D DepthImage: {rgbd_image}")
    datatypes.visualize(rgbd_image, entity_path="/RGBDImage")

    # ======================= ZSTD Compression ==================================
    zstd_image = datatypes.DepthImage(
        depth,
        colors=colors,
        compression=datatypes.ImageCompression.ZSTD,
    )
    logger.info(f"ZSTD DepthImage: {zstd_image}")
    datatypes.visualize(zstd_image, entity_path="/ZSTDImage")

    # ======================= NumPy Interop =====================================
    mean_depth = np.mean(depth_image)
    flipped_depth = np.flipud(depth_image)

    logger.info(f"Mean depth value: {mean_depth}")
    logger.info(f"Flipped depth shape={flipped_depth.shape}, dtype={flipped_depth.dtype}")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(rgbd_image)
    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 DepthImage: {deserialized}")
    logger.info(f"Round-trip successful: {deserialized == rgbd_image}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    depth_image_example()