Skip to content

DepthImage

SUMMARY

A metric depth map with optional aligned RGB data.

python
from telekinesis import datatypes
import numpy as np
depth_image = datatypes.DepthImage(np.ones((4, 4), dtype=np.float32))
API Reference
Complete API documentation for DepthImage, including parameters, attributes, and methods.
View Reference →

Parameters

ParameterTypeDefaultDescription
depthnp.ndarrayRequiredMetric depth values in metres with shape (H, W) and a supported dtype.
colorsnp.ndarray | NoneNoneOptional aligned RGB image with shape (H, W, 3) and dtype uint8. Its height and width must match the depth image.
compressionImageCompression | intImageCompression.NONECompression codec used during serialization.

Raises

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

Supported Dtypes

FieldDtypes
depthfloat16, float32, float64
colorsuint8

Attributes

AttributeTypeDescription
depthnp.ndarrayDefensive copy, shape (H, W), dtype one of SUPPORTED_DEPTH_DTYPES (meters). Read-only. 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

MethodTypeDescription
DepthImage.coerce(value)DepthImageConverts array-like data into a DepthImage. If value is already a DepthImage, it is returned unchanged; otherwise a np.ndarray is wrapped as the depth map.
DepthImage.from_raw_buffer(buffer, shape, dtype, depth_scale=1.0, compression=NONE)DepthImageBuilds a depth image straight from a raw sensor-count buffer (e.g. uint16 values straight off a depth camera), scaling to meters by multiplying by depth_scale.
DepthImage.from_encoded_buffer(buffer, depth_scale=1.0, compression=NONE)DepthImageDecodes a single-channel encoded image (typically a 16-bit PNG) into raw sensor counts, then scales to meters the same way as from_raw_buffer.
DepthImage.from_path(path, depth_scale=1.0, compression=NONE)DepthImageReads an encoded depth image file from disk and decodes it the same way as from_encoded_buffer.
DepthImage.from_url(url, depth_scale=1.0, compression=NONE, connect_timeout=5.0, read_timeout=30.0)DepthImageDownloads an encoded depth image and decodes it the same way as from_encoded_buffer, with configurable connect/read timeouts.
to_numpy(copy=True)np.ndarrayReturns the depth map. With the default copy=True you get an independent copy; pass copy=False for a direct reference to the internal array instead. The aligned colors image, if any, isn't included; access it via the colors property.
copy()DepthImageReturns a new, independent DepthImage with the same depth (and color, if present) data and compression setting.
save_to_path(path, *, depth_scale=1.0)NoneWrites the depth map to disk as a 16-bit encoded image, the inverse of from_encoded_buffer/from_raw_buffer. The aligned color image, if any, isn't written.

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) as an np.ndarray; NumPy functions accept a DepthImage directly. Passing copy=False raises ValueError.

Visualization

python
import rerun as rr

# Your code block
# ....

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

Example

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

import time
from pathlib import Path

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

from telekinesis import datatypes

def depth_image_example():
    """Demonstrate creation, inspection, operations, visualization, 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"Created DepthImage: {depth_image}")

    depth_image_from_coerce = datatypes.DepthImage.coerce(depth)
    logger.info(f"DepthImage created via coerce: {depth_image_from_coerce}")

    depth_scale = 0.001
    raw_counts = np.round(depth / depth_scale).astype(np.uint16)
    depth_image_from_raw_buffer = datatypes.DepthImage.from_raw_buffer(
        raw_counts.tobytes(), shape=depth.shape, dtype=raw_counts.dtype, depth_scale=depth_scale
    )
    logger.info(f"DepthImage created from raw buffer: {depth_image_from_raw_buffer}")

    save_path = Path("results/depth_image_example.png")
    save_path.parent.mkdir(parents=True, exist_ok=True)
    depth_image.save_to_path(save_path, depth_scale=depth_scale)
    depth_image_from_path = datatypes.DepthImage.from_path(save_path, depth_scale=depth_scale)
    logger.info(f"DepthImage created from path: {depth_image_from_path}")

    encoded_buffer = save_path.read_bytes()
    depth_image_from_encoded_buffer = datatypes.DepthImage.from_encoded_buffer(
        encoded_buffer, depth_scale=depth_scale
    )
    logger.info(f"DepthImage created from encoded buffer: {depth_image_from_encoded_buffer}")

    # ======================= Inspect ===========================================
    logger.info(f"depth={depth_image.depth}")
    logger.info(f"colors={depth_image.colors}")
    logger.info(f"shape={depth_image.shape}")
    logger.info(f"height={depth_image.height}")
    logger.info(f"width={depth_image.width}")
    logger.info(f"has_colors={depth_image.has_colors}")
    logger.info(f"compression={depth_image.compression}")

    # ======================= Operations =========================================
    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}")

    zstd_image = datatypes.DepthImage(
        depth, colors=colors, compression=datatypes.ImageCompression.ZSTD
    )
    logger.info(f"ZSTD-compressed DepthImage: {zstd_image}")

    depth_image_copy = depth_image.copy()
    logger.info(f"Copied DepthImage: {depth_image_copy}")

    depth_image_numpy = depth_image.to_numpy(copy=True)
    logger.info(f"NumPy depth array: {depth_image_numpy}")

    numpy_array = np.asarray(depth_image)
    logger.info(f"Mean depth value: {np.mean(numpy_array)}")
    logger.info(f"Flipped depth shape: {np.flipud(numpy_array).shape}")

    # ======================= Visualize =========================================
    rr.init("depth_image_example", spawn=True)
    datatypes.visualize(depth_image, entity_path="/depth_image/original")
    datatypes.visualize(rgbd_image, entity_path="/depth_image/rgbd")
    datatypes.visualize(zstd_image, entity_path="/depth_image/zstd")

    # ======================= 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: {rgbd_image == deserialized}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    depth_image_example()