Skip to content

SegmentationImage

Represents a 2D per-pixel segmentation label map.

Reference semantics on construction

A contiguous input array is stored by reference, not copied. Pass data.copy() explicitly if the source array may be mutated afterward.

Parameters

FieldTypeDescription
datanp.ndarrayLabel array, shape (H, W), dtype from the allowlist below.
compressionImageCompression | intOn-wire compression codec (see ImageCompression), or a matching int. Default ImageCompression.NONE.

Raises

ExceptionCondition
TypeErrordata isn't an np.ndarray
ValueErrordata isn't 2-D, is empty (H or W is 0), has an unsupported dtype, contains a negative label (checked for signed dtypes only), or compression is invalid

Supported Dtypes

uint8, uint16, uint32, uint64, int8, int16, int32, int64. No floating-point dtypes.

Attributes

AttributeTypeDescription
datanp.ndarrayDefensive copy of the label array. Assigning re-validates and invalidates the memoized label_codes/number_of_labels scan.
shapetuple[int, int](height, width).
heightintImage height.
widthintImage width.
dtypenp.dtypeDtype of the label array.
compressionImageCompressionOn-wire codec. Read-only (no setter).
label_codesnp.ndarrayDefensive copy of the sorted unique label codes present in data. Memoized (an np.unique scan) and invalidated by the data setter.
number_of_labelsintCount of distinct label codes present, from the same memoized scan.

Methods

MethodDescription
to_numpy(copy=True)Returns the label array as np.ndarray; copy=False returns the internal array directly.
to_binary_mask()Returns a new SegmentationImage where every non-zero label becomes 1 and 0 stays 0 (dtype uint8). Note: despite its docstring mentioning a threshold argument, the method takes no parameters -- it always thresholds at "non-zero".
SegmentationImage.from_raw_buffer(buffer, shape, dtype, compression=NONE)Builds a SegmentationImage from raw label bytes via np.frombuffer + reshape. Raises ValueError if buffer's size doesn't match shape.
SegmentationImage.coerce(value)Returns value unchanged if already a SegmentationImage; otherwise wraps an np.ndarray. Raises TypeError for anything else.

Operators

OperationBehavior
img == otherTrue only if other is a SegmentationImage with an element-equal label array; compression is not compared. NotImplemented if other isn't a SegmentationImage.
np.asarray(img)Returns a copy of the label array. copy=False raises ValueError; use to_numpy(copy=False).
hash(img)Not supported.
repr(img)Shows label_codes/number_of_labels when compression is NONE; otherwise just shape/dtype/compression (skips the label scan).

Serialization

Arrow layout:

text
StructArray length 1
├── data:        binary
├── height:      int32
├── width:       int32
├── dtype:       string
└── compression: int8

from_pyarrow treats a payload with no compression field (written before the field existed) as ImageCompression.NONE.

Visualization

datatypes.visualize(segmentation_image, entity_path=...) logs an AnnotationContext mapping label 0 to a fully transparent color (so the background doesn't occlude anything logged beneath it), then logs data as rr.SegmentationImage.

Example

python
"""Demonstrates the Telekinesis SegmentationImage datatype."""

import time

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

from telekinesis import datatypes


def segmentation_image_example():
    """Demonstrate creation, access, visualization, update, NumPy interop, and serialization."""

    # ======================= Create ============================================
    data = np.random.randint(0, 255, (480, 640), dtype=np.uint8)
    image = datatypes.SegmentationImage(data)
    logger.info(f"Original SegmentationImage: {image}")

    # ======================= Inspect ===========================================
    label_codes = image.label_codes
    number_of_labels = image.number_of_labels
    shape = image.data.shape
    dtype = image.data.dtype
    height = image.height
    width = image.width
    compression = image.compression
    numpy_array = image.to_numpy()

    logger.info(
        f"label_codes={label_codes}, "
        f"number_of_labels={number_of_labels}, "
        f"shape={shape}, "
        f"dtype={dtype}, "
        f"height={height}, "
        f"width={width}, "
        f"compression={compression}"
    )
    logger.info(f"SegmentationImage data:\n{image.data}")
    logger.info(f"NumPy array:\n{numpy_array}")

    # ======================= Visualize =========================================
    rr.init("segmentation_image_example", spawn=True)
    datatypes.visualize(
        image,
        entity_path="/SegmentationImage/my_segmentation_image",
    )

    # ======================= Update ============================================
    updated_data = np.random.randint(0, 255, (480, 640), dtype=np.uint8)
    image.data = updated_data
    logger.info(f"Updated SegmentationImage: {image}")
    datatypes.visualize(
        image,
        entity_path="/SegmentationImage/my_updated_segmentation_image",
    )

    # ======================= NumPy Interop =====================================
    mean = np.mean(image)
    flipped = np.flipud(image)

    logger.info(f"Mean pixel value: {mean}")
    logger.info(f"Flipped shape={flipped.shape}, dtype={flipped.dtype}")

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


if __name__ == "__main__":
    segmentation_image_example()