OpenLABEL 형식
OpenLABEL은 엄격한 포맷이지만 여전히 해석의 여지가 있는 부분들이 있습니다. 이 섹션에서는 이러한 부분 중 일부를 명확히 하고, 당사가 표준 내에서 내린 선택들을 설명합니다.
큐보이드의 회전
회전은 y축이 전방을 향하도록 되어 있으며, 회전 순서는 XYZ입니다. 즉, 헤딩(요, yaw)이 0인 큐보이드는 y축의 양의 방향과 정렬됩니다. 이는 전방이 x축을 따르는 ISO 8855 표준과는 다소 차이가 있습니다. ISO 8855로의 변환은 z축을 기준으로 회전을 적용하고 다음과 같이 sx와 sy를 변경함으로써 수행할 수 있습니다.
import math
from typing import List
from scipy.spatial.transform import Rotation
def convert_to_iso8855(val: List[float]) -> List[float]:
""" Converts cuboid values to ISO 8855 """
[x, y, z, qx, qy, qz, qw, sx, sy, sz] = val
rotation_1 = Rotation.from_quat([qx, qy, qz, qw])
rotation_2 = Rotation.from_rotvec([0, 0, math.pi / 2])
rot_object = rotation_1 * rotation_2
[qx, qy, qz, qw] = rot_object.as_quat()
return [x, y, z, qx, qy, qz, qw, sy, sx, sz]시퀀스가 아닌 데이터는 프레임이 하나인 시퀀스입니다
단순성을 위해, 시퀀스가 아닌 데이터도 시퀀스와 동일한 방식으로 처리하기로 결정했습니다. 즉, 시퀀스가 아닌 데이터는 프레임이 하나뿐인 시퀀스로 표현됩니다. name이나 type과 같은 데이터만 최상위 요소 키에 정의됩니다. 그 외의 모든 정보는 frames 아래에 저장됩니다. 아래 예제를 참고하십시오.
{
"objects": {
"0": {
"name": "car-0",
"type": "Car"
}
},
"frames": {
"0": {
"objects": {
"0": {"object_data": {...}}
}
}
}
}Stream은 그저 또 다른 텍스트 속성입니다
stream 속성은 어노테이션이 이루어진 스트림/센서/소스가 무엇인지 나타내는 데 사용됩니다. 예를 들어 다음은 Camera라는 이름의 스트림에서 어노테이션된 점(point)을 가진 객체입니다. 해당 형상에 대응하는 모든 속성 역시 동일한 스트림에서 어노테이션되었다는 점에 유의하십시오.
{
"object_data": {
"point2d": [
{
"name": "point-4d2d325f",
"val": [300.5300, 286.4396],
"attributes": {
"text": [
{"name": "stream", "val": "Camera"},
{"name": "Color", "val": "Black"}
]
}
}
]
}
}관계(Relations)
관계에는 두 가지 유형이 있습니다. 두 객체 간의 단방향 관계와, 그룹 관계입니다. 이 외에도, 실제로는 다른 객체를 가리키는 포인터가 아니라 Inconclusive, Nothing, Unclear와 같은 값을 가지는 거짓 관계(false relation) 속성을 표현할 필요도 있습니다.
관계는 단방향입니다
관계는 단방향(unidirectional)이며, 즉 객체 object1이 다른 객체 object2에 대한 관계를 가진다고 해서 object2가 object1에 대한 관계를 가지는 것은 아닙니다. 아래는 car-0이 car-1을 따라가고 있으며, car-2가 다른 차를 따라가고 있는지는 불명확한 예제입니다.
{
"objects": {
"0": {"name": "car-0", "type": "Car"},
"1": {"name": "car-1", "type": "Car"},
"2": {"name": "car-2", "type": "Car"}
},
"relations": {
"0": {
"name": "0",
"type": "isFollowing",
"rdf_subjects": [{"type": "object", "uid": "0"}],
"rdf_objects": [{"type": "object", "uid": "1"}]
}
}
}액션(Actions)은 거짓 관계를 표현하는 데 사용됩니다
Kognic 플랫폼에서는 실제로는 다른 객체에 대한 참조가 아닌 값을 관계에 할당하는 기능을 지원합니다. Inconclusive와 Nothing이 그 예입니다. 이러한 값은 다음과 같이 액션(actions)을 사용해 표현하며, 액션의 이름이 값을 결정하고 타입이 속성 이름을 결정합니다.
{
"objects": {
"0": {"name": "lane-0", "type": "Lane"}
},
"relations": {
"0": {
"name": "0",
"type": "isSubjectOfAction",
"rdf_subjects": [{"type": "object", "uid": "0"}],
"rdf_objects": [{"type": "action", "uid": "0"}]
}
},
"actions": {
"0": {"name": "Nothing", "type": "is_pulling_or_pushing"}
}
}스트림별 관계
어떤 관계가 특정 스트림에 국한된 경우, 해당 관계 목록이 어느 스트림에 속하는지를 나타내는 stream_relations 속성이 있게 됩니다.
{ // frames.0
// ...
"frame_properties": {
"streams": {
"CAMERA_FRONT": {
"description": null,
"stream_properties": {
"stream_relations": {
"1": {}
}
}
}
}
},
"relations": {
"0": {}
}
}폴리곤 표현하기
OpenLABEL에서 폴리곤은 Poly2d 객체 목록으로 기술됩니다. 이 중 하나는 외곽선(exterior)을 나타내고, 나머지는 잠재적인 구멍(hole)을 나타내며, 이는 불리언 속성 is_hole로 결정됩니다. 아래는 구멍이 하나 있는 폴리곤의 예제입니다.
{
"object_data": {
"poly2d": [
{
"name": "poly1",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": { "boolean": [{"name": "is_hole", "val": false}] }
},
{
"name": "poly2",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": { "boolean": [{"name": "is_hole", "val": true}] }
}
]
}
}mode로 지원되는 값은 MODE_POLY2D_ABSOLUTE뿐입니다. 절대(absolute) 모드는 val의 값들이 (첫 번째 좌표쌍에 대한 상대값이 아니라) 픽셀 좌표로 해석됨을 의미합니다.
멀티 폴리곤 표현하기
멀티 폴리곤은 단순히 폴리곤들의 목록이므로, is_hole 속성을 가진 Poly2d 객체 목록을 사용해 유사한 방식으로 기술합니다. 다만, 멀티 폴리곤 내에서 Poly2d 객체가 어느 폴리곤에 속하는지를 결정하는 polygon_id라는 속성을 하나 더 추가합니다. 아래는 각각 하나의 구멍을 가진 두 개의 폴리곤으로 구성된 멀티 폴리곤 예제입니다.
{
"object_data": {
"poly2d": [
{
"name": "poly1",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": {
"text": [{"name": "polygon_id", "val": "1"}],
"boolean": [{"name": "is_hole", "val": false}]
}
},
{
"name": "poly2",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": {
"text": [{"name": "polygon_id", "val": "1"}],
"boolean": [{"name": "is_hole", "val": true}]
}
},
{
"name": "poly3",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": {
"text": [{"name": "polygon_id", "val": "2"}],
"boolean": [{"name": "is_hole", "val": false}]
}
},
{
"name": "poly4",
"mode": "MODE_POLY2D_ABSOLUTE",
"val": [...],
"attributes": {
"text": [{"name": "polygon_id", "val": "2"}],
"boolean": [{"name": "is_hole", "val": true}]
}
}
]
}
}mode로 지원되는 값은 MODE_POLY2D_ABSOLUTE뿐입니다. 절대(absolute) 모드는 val의 값들이 (첫 번째 좌표쌍에 대한 상대값이 아니라) 픽셀 좌표로 해석됨을 의미합니다.
곡선 표현하기
주의
보간(interpolation) 방식의 이름이 interpolation-method에서 interpolation_method로 변경되었습니다. 다만 기존 어노테이션에는 이전 이름이 여전히 남아 있을 수 있습니다.
곡선은 poly2d 형상을 사용해 표현되며, 보간 방식은 다음과 같이 텍스트 속성으로 지정됩니다.
{
"poly2d": [
{
"closed": false,
"mode": "MODE_POLY2D_ABSOLUTE",
"name": "curve-d633ca89",
"val": [...],
"attributes": {
"text": [
{
"name": "interpolation_method",
"val": "natural-cubic-spline"
}
]
}
}
]
}mode로 지원되는 값은 MODE_POLY2D_ABSOLUTE뿐입니다. 절대(absolute) 모드는 val의 값들이 (첫 번째 좌표쌍에 대한 상대값이 아니라) 픽셀 좌표로 해석됨을 의미합니다. interpolation_method 속성은 필수이며, 노드들이 서로 어떻게 연결되어야 하는지를 결정합니다. 다음 값들이 지원됩니다.
- natural-cubic-spline
- catmull-rom-0.5
- polyline
3D 차선(Lane) 표현하기
3D 차선은 3D 상의 두 개의 선(poly3d)으로 표현되며, 하나는 오른쪽, 다른 하나는 왼쪽을 나타냅니다. 텍스트 속성 lane_edge가 해당 선이 오른쪽인지 왼쪽인지를 결정합니다. 이 선들은 항상 closed 값이 false로 설정됩니다.
{
"object_data": {
"poly3d": [
{
"attributes": {
"text": [
{ "name": "lane_edge", "val": "left" },
{ "name": "stream", "val": "lidar" }
]
},
"closed": false,
"name": "",
"val": [
1.2647494200238287, -51.51747573498745, -2.315540290283199,
1.0807419132566136, -48.91298533071834, -2.313640304199211,
-0.0892715141237751, -34.705936676401016, -2.235569814758307,
-0.4442893388935316, -29.60917111552865, -2.1894531147766174,
-1.0952988968721313, -17.193981050037397, -2.1397902661132875
]
},
{
"attributes": {
"text": [
{ "name": "lane_edge", "val": "right" },
{ "name": "stream", "val": "lidar" }
]
},
"closed": false,
"name": "",
"val": [
1.5845765823868767, -51.49487958011918, -2.315540290283199,
1.4004322100638888, -48.888528958803036, -2.313640304199211,
0.23043085215069048, -34.68163859008775, -2.235569814758307,
-0.12426061849402326, -29.589636067040036, -2.1894531147766174
]
}
]
}
}2D 점 표현하기
2D 점은 하나의 point2d로 표현됩니다. 각 point2d는 선택적인 point_class 속성을 가질 수 있습니다. 단일 점의 경우 이를 생략할 수 있지만, 설정하는 경우 반드시 해당 객체의 type과 동일해야 합니다. 이 속성은 향후 다른 점 기반 형상에서 사용하기 위해 예약되어 있습니다.
{
"openlabel": {
...,
"frames": {
"0": {
"objects": {
"a940239d-ff27-4480-8294-c482977a1b32": {
"object_data": {
"point2d": [
{
"attributes": {
"text": [
{ "name": "point_class", "val": "APoint" },
{ "name": "stream", "val": "stream1" }
]
},
...
}
]
}
},
"e027e626-eb7a-4a8e-a9ae-083464e137d1": {
"object_data": {
"point2d": [
{
"attributes": {
"text": [
{ "name": "stream", "val": "stream1" }
]
},
....
}
]
}
}
}
}
},
"metadata": {...},
"objects": {
"a940239d-ff27-4480-8294-c482977a1b32": {
...
"type": "APoint"
},
"e027e626-eb7a-4a8e-a9ae-083464e137d1": {
...
"type": "AnotherPoint"
}
},
...
}
}
2D 점 그룹 표현하기
여러 점이 동일한 객체를 가리킬 때 점 그룹(group of points)을 사용합니다. 점 그룹 내 각 점에는 point_class 속성이 필수이며, point_class는 객체의 type과는 달라야 합니다. point_class 값 "line_reference_point"는 향후 사용 사례를 위해 예약되어 있습니다.
형상 컬렉션(Geometry Collections) 표현하기
참고
kognic_format_version 2.2에서 도입되었습니다.
작업 화면(task view)에 대한 관련 문서 형상 컬렉션(Geometry collections).
위 링크에서 설명한 형상들의 컬렉션은 타입이 geometry_collection인 예약된 관계로 표현됩니다.
{
"openlabel": {
"frames": {
"0": {
"objects": {
"516b6045-87e8-40e4-a104-5eaa600e8e3a": {
"object_data": {
"bbox": [
{
"name": "bbox-abc123",
"val": [
...
]
}
]
}
},
"fe07e9cf-f42c-4b48-b4d8-bab75b7e9827": {
"object_data": {
"poly2d": [
{
"name": "curve-abc123",
"val": [
...
]
}
]
}
},
"329508b7-729c-4298-8141-f329dbc32ad0": {
"object_data": {
"poly2d": [
{
"name": "curve-abc123",
"val": [
...
]
}
]
}
},
"4c321584-0e88-4578-b0f0-b5e8c974244b": {
"object_data": {
"text": [
{
"name": "lane",
"val": "right"
}
]
}
}
}
}
},
"metadata": {
"schema_version": "1.0.0",
"kognic_format_version": "2.2",
"uuid": "63698712-b18e-426b-9ad5-1b178cc29838"
},
"objects": {
"516b6045-87e8-40e4-a104-5eaa600e8e3a": {
"name": "516b6045-87e8-40e4-a104-5eaa600e8e3a",
"object_data": {
...
},
"type": "some_bbox"
},
"fe07e9cf-f42c-4b48-b4d8-bab75b7e9827": {
"name": "fe07e9cf-f42c-4b48-b4d8-bab75b7e9827",
"object_data": {
...
},
"type": "some_line"
},
"329508b7-729c-4298-8141-f329dbc32ad0": {
"name": "329508b7-729c-4298-8141-f329dbc32ad0",
"object_data": {
...
},
"type": "some_line"
},
"4c321584-0e88-4578-b0f0-b5e8c974244b": {
"name": "4c321584-0e88-4578-b0f0-b5e8c974244b",
"object_data": {
...
},
"type": "some_collection"
}
},
"relations": {
"0": {
"name": "0",
"rdf_objects": [
{
"uid": "516b6045-87e8-40e4-a104-5eaa600e8e3a",
"type": "object"
},
{
"uid": "fe07e9cf-f42c-4b48-b4d8-bab75b7e9827",
"type": "object"
},
{
"uid": "329508b7-729c-4298-8141-f329dbc32ad0",
"type": "object"
}
],
"rdf_subjects": [
{
"uid": "4c321584-0e88-4578-b0f0-b5e8c974244b",
"type": "object"
}
],
"type": "geometry_collection"
}
}
}
}3D 세그멘테이션 표현하기
분류(classification)는 값을 런렝스 인코딩(run length encoding, RLE)하여 표현됩니다. 예를 들어 11122222222000000000000은 #3V1#8V2#13V0으로 변환되며, 여기서 # 문자 뒤의 숫자는 반복되는 값의 개수를 나타내고, V 문자 뒤의 숫자가 해당 값을 나타냅니다.
"b088dcbf-c7fe-46a5-a71d-88ef49bdc107": {
"object_data": {
"binary": [
{
"attributes": {
"text": [
{
"val": "lidar",
"name": "stream"
}
]
},
"data_type": "",
"encoding": "rle",
"name": "labels",
"val": "<RLE string>"
}
]
}
}