tlc.data_types.keypoints

Defines representations of keypoints in 3LC.

Module Contents

Classes

Class

Description

Keypoints2D

Container for 2D keypoint instances.

API

class Keypoints2D

Bases: tlc.data_types._geometry_base.Geometry2DBase

Container for 2D keypoint instances.

Serialization is handled by the keypoints_2d sample type.

Objects can be created in two ways:

  1. Direct construction: Pass all arrays at once.

  2. Build incrementally: Use create_empty() and add_instance().

Example:

import numpy as np

# Direct construction
N, K = 3, 17  # 3 persons, 17 COCO keypoints
kpts = Keypoints2D(
    keypoints=np.random.rand(N, K, 2).astype(np.float32) * 640,
    labels=np.zeros(N, dtype=np.int32),
    bounding_boxes=np.array([[10, 10, 100, 200]] * N, dtype=np.float32),
    keypoint_visibilities=np.ones((N, K), dtype=np.int32) * 2,
    x_max=640.0,
    y_max=480.0,
)

# Build incrementally — naming convention:
#   instance-level: `label` / `confidence` (singular, like every other class)
#   per-keypoint:   `keypoint_visibilities` / `keypoint_confidences` (mutually exclusive)
kpts = Keypoints2D.create_empty(image_width=640, image_height=480)
kpts.add_instance(
    keypoints=[[100, 150], [120, 160], [140, 170]],
    bounding_box=[90, 140, 150, 180],
    label=0,
    confidence=0.97,
    keypoint_visibilities=[2, 2, 1],
)

# COCO-style xywh bounding boxes — converted to xyxy via bounding_box_format
kpts = Keypoints2D(
    keypoints=..., bounding_boxes=coco_xywh, bounding_box_format="xywh", x_max=640, y_max=480,
)

# Serialization — convert to/from 3LC Table row format
row = kpts.to_row()
kpts = Keypoints2D.from_row(row)
add_instance(
*,
keypoints: Any,
bounding_box: Sequence[float] | ndarray | None = None,
label: int | None = None,
confidence: float | None = None,
keypoint_visibilities: Sequence[int] | ndarray | None = None,
keypoint_confidences: Sequence[float] | ndarray | None = None,
per_instance_extras: Mapping[str, Any] | None = None,
) None

Add a single keypoint instance to the object.

Adds one instance (e.g., one person, one object) with its keypoints, bounding box, and label. Keypoints can be provided in multiple formats and will be normalized internally.

Parameters:
  • keypoints

    Keypoint coordinates in one of these formats:

    • Flat list: [x1, y1, x2, y2, ...] or [x1, y1, v1, x2, y2, v2, ...]

    • List of pairs: [[x1, y1], [x2, y2], ...]

    • List of triplets: [[x1, y1, v1], [x2, y2, v2], ...] (visibility derived from 3rd value)

    • NumPy array of shape (K, 2) or (K, 3)

  • bounding_box – Optional bounding box in xyxy format [x_min, y_min, x_max, y_max].

  • label – Optional integer class label for this instance.

  • confidence – Optional confidence score for this instance (instance-level).

  • keypoint_visibilities – Optional per-keypoint visibility flags (0=not labeled, 1=occluded, 2=visible). Mutually exclusive with keypoint_confidences. If keypoints are provided with a 3rd column, that will be used as visibility unless explicitly overridden.

  • keypoint_confidences – Optional per-keypoint confidence scores. Mutually exclusive with keypoint_visibilities.

  • per_instance_extras – Optional dictionary of per-instance attributes (e.g., {"track_id": 42, "area": 1500}). Values should be scalars. The first call establishes which keys are expected; subsequent calls must provide the same keys.

Raises:

ValueError – If keypoints are None, if both visibility and confidence are provided, or if the number of keypoints doesn’t match existing instances.

Example:

kpts = Keypoints2D.create_empty(image_width=640, image_height=480)
# Add first instance with 3 keypoints
kpts.add_instance(
    keypoints=[[100, 150], [120, 160], [140, 170]],
    bounding_box=[90, 140, 150, 180],
    label=0,
)
# Add second instance (must also have 3 keypoints)
kpts.add_instance(
    keypoints=[[200, 250, 2], [220, 260, 2], [240, 270, 1]],  # with visibility
    bounding_box=[190, 240, 250, 280],
    label=0,
)
bounding_box_format: InitVar['xyxy' | 'xywh' | 'cxywh'] = xyxy

Format of the input bounding_boxes array (when supplied). Storage is always "xyxy".

bounding_boxes: ndarray = field(...)

Optional per-instance bounding boxes, shape (num_instances, 4) after coercion. Empty (shape (0, 4)) when not provided. Always stored as [x_min, y_min, x_max, y_max] (xyxy). Use bounding_box_format= on the constructor to supply "xywh" (COCO) or "cxywh" (YOLO) input.

property bounding_boxes_xywh: ndarray

Return the instance bounding boxes in xywh format.

Converts from the internal xyxy format [x_min, y_min, x_max, y_max] to xywh format [x_min, y_min, width, height], which is commonly used by some training frameworks.

Returns:

A numpy array of shape (num_instances, 4) with bounding boxes in [x, y, width, height] format, or an empty (0, 4) array if no bounding boxes are present.

classmethod create_empty(
*,
image_width: float | None = None,
image_height: float | None = None,
x_min: float | None = None,
y_min: float | None = None,
x_max: float | None = None,
y_max: float | None = None,
) Keypoints2D

Create an empty Keypoints2D object to build up incrementally.

Useful for creating keypoint data from scratch by adding instances one at a time using add_instance().

Parameters:
  • image_width – Convenience parameter, sets x_max = x_min + image_width.

  • image_height – Convenience parameter, sets y_max = y_min + image_height.

  • x_min – Minimum x coordinate (optional).

  • y_min – Minimum y coordinate (optional).

  • x_max – Maximum x coordinate (optional, provide this OR image_width if specifying bounds).

  • y_max – Maximum y coordinate (optional, provide this OR image_height if specifying bounds).

Returns:

An empty Keypoints2D object ready for adding instances.

Raises:

ValueError – If bounds are partially specified (some but not all required).

Example:

kpts = Keypoints2D.create_empty(image_width=640, image_height=480)
kpts.add_instance(
    keypoints=[[100, 150], [120, 160]],
    bounding_box=[90, 140, 130, 170],
    label=0,
    keypoint_visibilities=[2, 2],
)
image_height: InitVar[float | None] = None

Convenience parameter: sets y_max = (y_min or 0) + image_height.

image_width: InitVar[float | None] = None

Convenience parameter: sets x_max = (x_min or 0) + image_width.

keypoint_confidences: ndarray = field(...)

Per-keypoint float confidences, shape (num_instances, num_keypoints,) after coercion. Empty (size == 0) when not provided. Same input convention as keypoint_visibilities; mutually exclusive with it.

keypoint_visibilities: ndarray = field(...)

Per-keypoint integer visibilities, shape (num_instances, num_keypoints,) after coercion. Empty (size == 0) when not provided. The constructor also accepts a 1D (K,) array for the single-instance case (broadcast to (1, K) in __post_init__). Mutually exclusive with keypoint_confidences: at most one of them may be non-empty in a container.

keypoints: ndarray = field(...)

Keypoint coordinates, ndarray of shape (num_instances, num_keypoints, 2) after coercion.

The constructor accepts anything np.asarray can convert to 2D (K, 2)/(K, 3)/(N, K*2) or 3D (N, K, 2); see __post_init__ for the recognized shapes. The type hint is the post-coercion storage form so reads (.astype/.shape/etc.) typecheck cleanly. Pass list-of-list inputs by pre-wrapping with np.asarray(...) to satisfy strict type checking, or use add_instance whose kwargs accept the wider Sequence types directly.

normalized: InitVar[bool] = False

Whether the input keypoints and bounding_boxes coordinates are normalized to [0, 1].

When True, both keypoint coordinates and bounding boxes are denormalized to absolute pixel values using the image dimensions derived from bounds. Bounds must be set. Applied after bounding_box_format conversion.

property num_instances: int

Return the number of keypoint instances.

classmethod schema(
num_keypoints: int,
classes: str | Sequence[str] | Sequence[dict[str, str]] | Sequence[MapElement] | dict[float, str] | dict[int, str] | dict[float, MapElement] | dict[int, MapElement] | None = None,
*,
points: list[float] | list[list[float]] | ndarray | None = None,
point_attributes: list[str] | list[dict[str, Any]] | None = None,
lines: list[int] | list[list[int]] | ndarray | None = None,
line_attributes: list[str] | list[dict[str, Any]] | None = None,
triangles: list[int] | list[list[int]] | ndarray | None = None,
triangle_attributes: list[str] | list[dict[str, Any]] | None = None,
flip_indices: list[int] | None = None,
oks_sigmas: list[float] | None = None,
include_per_point_confidence: bool = False,
include_per_point_visibility: bool = False,
include_per_instance_confidence: bool = False,
x_min_default: float | None = None,
y_min_default: float | None = None,
x_max_default: float | None = None,
y_max_default: float | None = None,
display_name: str = '',
description: str = '',
writable: bool = True,
default_visible: bool = True,
display_importance: float = 0,
per_instance_schemas: dict[str, Schema] | None = None,
) Schema

Build the column Schema describing 2D keypoint instances.

Parameters:
  • num_keypoints – Number of keypoints (must be > 0).

  • classes – A class map (list of names, dict of numeric keys to names or MapElements, or a single class name) for per-instance labels, or None to skip labels.

  • points – Default relative keypoint coordinates used when creating new instances. The flattened length must be num_keypoints * 2 in the order [x0, y0, ..., xN-1, yN-1].

  • point_attributes – Per-point role names, one per keypoint.

  • lines – Default connectivity as index pairs, flattened to [i0, j0, i1, j1, ...].

  • line_attributes – Per-line role names matching the number of line pairs.

  • triangles – Default triangle faces as index triples, flattened to [i0, j0, k0, ...].

  • triangle_attributes – Per-triangle role names matching the number of triangle triples.

  • flip_indices – Indices used for horizontal-flip augmentation.

  • oks_sigmas – Object Keypoint Similarity (OKS) sigmas; defaults to uniform 1/num_keypoints.

  • include_per_point_confidence – Whether to add a per-point confidence field.

  • include_per_point_visibility – Whether to add a per-point visibility channel.

  • include_per_instance_confidence – Whether to add a per-instance confidence field.

  • x_min_default – Default scene x_min bound.

  • y_min_default – Default scene y_min bound.

  • x_max_default – Default scene x_max bound.

  • y_max_default – Default scene y_max bound.

  • display_name – Column display name in the Dashboard.

  • description – Column description.

  • writable – Whether the column is editable in the Dashboard.

  • default_visible – Whether the column is visible by default.

  • display_importance – Ordering weight for column display.

  • per_instance_schemas – Additional per-instance schemas (advanced).

Returns:

A column schema describing the serialized form of this class.

Raises:

ValueError – If num_keypoints <= 0.