179 lines
5.7 KiB
Python
179 lines
5.7 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
import rerun as rr
|
|
from rerun.components import AnnotationContext, AnnotationContextLike
|
|
from rerun.datatypes import (
|
|
AnnotationInfo,
|
|
AnnotationInfoLike,
|
|
ClassDescription,
|
|
ClassDescriptionArrayLike,
|
|
ClassDescriptionMapElem,
|
|
KeypointPair,
|
|
KeypointPairLike,
|
|
Rgba32,
|
|
Utf8,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Sequence
|
|
|
|
ANNOTATION_INFO_INPUTS: list[AnnotationInfoLike] = [
|
|
AnnotationInfo(1, "label", Rgba32([1, 2, 3])),
|
|
AnnotationInfo(1, color=Rgba32([1, 2, 3])),
|
|
(1, "label"),
|
|
(1, "label", [1, 2, 3]),
|
|
]
|
|
|
|
KEYPOINT_MAP_INPUTS: list[Sequence[AnnotationInfoLike] | None] = [
|
|
None,
|
|
[],
|
|
[
|
|
(1, "label1"),
|
|
(2, "label2"),
|
|
],
|
|
[
|
|
(1, "label1", [1, 2, 3]),
|
|
(2, "label2", [4, 5, 6]),
|
|
],
|
|
[
|
|
AnnotationInfo(1, "label1", Rgba32([1, 2, 3])),
|
|
AnnotationInfo(2, "label2", Rgba32([4, 5, 6])),
|
|
],
|
|
]
|
|
|
|
KEYPOINT_CONNECTIONS_INPUTS: list[Sequence[KeypointPairLike] | None] = [
|
|
None,
|
|
[],
|
|
[
|
|
(1, 2),
|
|
],
|
|
[
|
|
[1, 2],
|
|
],
|
|
[
|
|
KeypointPair(1, 2),
|
|
],
|
|
]
|
|
|
|
|
|
def assert_correct_class_description(desc: ClassDescription) -> None:
|
|
assert desc.info.id == 1
|
|
if desc.info.label:
|
|
assert desc.info.label == Utf8("label")
|
|
if desc.info.color:
|
|
assert desc.info.color == Rgba32([1, 2, 3])
|
|
if desc.keypoint_annotations:
|
|
expected_annotations = [
|
|
AnnotationInfo(1, "label1", Rgba32([1, 2, 3])),
|
|
AnnotationInfo(2, "label2", Rgba32([4, 5, 6])),
|
|
]
|
|
for i, kp in enumerate(desc.keypoint_annotations):
|
|
assert kp.id == expected_annotations[i].id
|
|
if kp.label:
|
|
assert kp.label == expected_annotations[i].label
|
|
if kp.color:
|
|
assert kp.color == expected_annotations[i].color
|
|
if desc.keypoint_connections:
|
|
expected_pairs = [
|
|
KeypointPair(1, 2),
|
|
]
|
|
if len(desc.keypoint_connections) > 0:
|
|
assert desc.keypoint_connections == expected_pairs
|
|
|
|
|
|
@pytest.mark.parametrize("input", ANNOTATION_INFO_INPUTS)
|
|
@pytest.mark.parametrize("keypoint_annotations", KEYPOINT_MAP_INPUTS)
|
|
@pytest.mark.parametrize("keypoint_connections", KEYPOINT_CONNECTIONS_INPUTS)
|
|
def test_class_description(
|
|
input: AnnotationInfoLike,
|
|
keypoint_annotations: Sequence[AnnotationInfoLike] | None,
|
|
keypoint_connections: Sequence[KeypointPairLike] | None,
|
|
) -> None:
|
|
assert_correct_class_description(
|
|
ClassDescription(
|
|
info=input,
|
|
keypoint_annotations=keypoint_annotations,
|
|
keypoint_connections=keypoint_connections,
|
|
),
|
|
)
|
|
|
|
|
|
ANNOTATION_CONTEXT_INPUTS: list[ClassDescriptionArrayLike] = [
|
|
[
|
|
(1, "label1", [1, 2, 3]),
|
|
(2, "label2", [4, 5, 6]),
|
|
],
|
|
[
|
|
ClassDescription(info=(1, "label1", [1, 2, 3]), keypoint_annotations=[(3, "kp_label1", [7, 8, 9])]),
|
|
ClassDescription(info=(2, "label2", [4, 5, 6]), keypoint_annotations=[(4, "kp_label2", [10, 11, 12])]),
|
|
],
|
|
[
|
|
AnnotationInfo(1, "label1"),
|
|
AnnotationInfo(2, color=[4, 5, 6]),
|
|
],
|
|
[
|
|
ClassDescription(info=(1, "label1"), keypoint_annotations=[(3, "kp_label1")]),
|
|
ClassDescription(info=(2, "label2", [4, 5, 6]), keypoint_annotations=[(4, "kp_label2", [10, 11, 12])]),
|
|
],
|
|
[
|
|
ClassDescription(info=(1, "label1"), keypoint_connections=[(1, 2)]),
|
|
ClassDescription(info=(2, "label2")),
|
|
],
|
|
]
|
|
|
|
|
|
def assert_correct_annotation_context(ctx: AnnotationContext) -> None:
|
|
assert len(ctx.class_map) == 2
|
|
expected_classes = [
|
|
ClassDescriptionMapElem(
|
|
class_id=1,
|
|
class_description=ClassDescription(
|
|
info=(1, "label1", [1, 2, 3]),
|
|
keypoint_annotations=[(3, "kp_label1", [7, 8, 9])],
|
|
),
|
|
),
|
|
ClassDescriptionMapElem(
|
|
class_id=2,
|
|
class_description=ClassDescription(
|
|
info=(2, "label2", [4, 5, 6]),
|
|
keypoint_annotations=[(4, "kp_label2", [10, 11, 12])],
|
|
),
|
|
),
|
|
]
|
|
for i, item in enumerate(ctx.class_map):
|
|
assert item.class_id == expected_classes[i].class_id
|
|
assert item.class_description.info.id == expected_classes[i].class_description.info.id
|
|
if item.class_description.info.label:
|
|
assert item.class_description.info.label == expected_classes[i].class_description.info.label
|
|
if item.class_description.info.color:
|
|
assert item.class_description.info.color == expected_classes[i].class_description.info.color
|
|
if item.class_description.keypoint_annotations:
|
|
for j, kp in enumerate(item.class_description.keypoint_annotations):
|
|
assert kp.id == expected_classes[i].class_description.keypoint_annotations[j].id
|
|
if kp.label:
|
|
assert kp.label == expected_classes[i].class_description.keypoint_annotations[j].label
|
|
if kp.color:
|
|
assert kp.color == expected_classes[i].class_description.keypoint_annotations[j].color
|
|
|
|
|
|
@pytest.mark.parametrize("ctx", ANNOTATION_CONTEXT_INPUTS)
|
|
def test_annotation_context_component(ctx: Sequence[ClassDescriptionMapElem]) -> None:
|
|
assert_correct_annotation_context(AnnotationContext(ctx))
|
|
|
|
|
|
ANNOTATION_ARCH_INPUTS: Sequence[ClassDescriptionArrayLike] = [
|
|
ClassDescription(info=(1, "label1", [1, 2, 3])),
|
|
*ANNOTATION_CONTEXT_INPUTS,
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize("ctx", ANNOTATION_ARCH_INPUTS)
|
|
def test_annotation_context_arch(ctx: AnnotationContextLike) -> None:
|
|
# Verify we can construct the archetype
|
|
rr.AnnotationContext(ctx)
|
|
|
|
# TODO(jleibs): Actually verify the serialized arrow data has the right values
|