OpenLABEL形式
OpenLABELは厳格な形式ですが、解釈の余地が一部残っています。このセクションでは、そのような部分をいくつか明確にし、標準内で行った選択について説明します。
キューボイドの回転
回転はY軸が前方を向くように設定されており、回転順序はXYZです。これは、ヘディング(ヨー)が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]非シーケンスは1フレームのシーケンス
シンプルさを考慮して、非シーケンスをシーケンスと同じ方法で扱う選択をしました。これは、非シーケンスが1フレームのみのシーケンスとして表現されることを意味します。nameやtypeなどのデータのみがトップレベル要素のキーで定義されます。その他の情報はすべてframesの下に格納されます。以下の例を参照してください。
{
"objects": {
"0": {
"name": "car-0",
"type": "Car"
}
},
"frames": {
"0": {
"objects": {
"0": {"object_data": {...}}
}
}
}
}ストリームは単なるテキストプロパティの1つ
streamプロパティは、ジオメトリとプロパティがどのストリーム/センサー/ソースでアノテーションされたかを示すために使用されます。例えば、以下はCameraという名前のストリームでアノテーションされたポイントを持つオブジェクトです。ジオメトリに対応するすべての属性も同じストリームでアノテーションされていることに注意してください。
{
"object_data": {
"point2d": [
{
"name": "point-4d2d325f",
"val": [300.5300, 286.4396],
"attributes": {
"text": [
{"name": "stream", "val": "Camera"},
{"name": "Color", "val": "Black"}
]
}
}
]
}
}リレーション
2種類のリレーションを考慮しています。2つのオブジェクト間の単方向リレーションとグループリレーションです。これらに加えて、偽リレーション、すなわち実際には他のオブジェクトへのポインタではなく、Inconclusive、Nothing、Unclearなどの値を取るリレーションプロパティを表現する必要があります。
リレーションは単方向
リレーションは単方向です。つまり、あるオブジェクト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"}]
}
}
}アクションによる偽リレーションの表現
Kognicプラットフォームでは、実際には他のオブジェクトへの参照ではない値をリレーションに割り当てることがサポートされています。例としてはInconclusiveやNothingがあります。アクションはこれらを以下の方法で表現するために使用され、アクションの名前が値を決定し、typeがプロパティ名を決定します。
{
"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オブジェクトのリストで記述されます。そのうちの1つが外形を表し、残りは潜在的な穴を表します。これはブール型プロパティis_holeによって決定されます。以下は1つの穴を持つポリゴンの例です。
{
"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のみです。絶対モードとは、valの値がピクセル座標として解釈されることを意味します(最初の座標ペアからの相対値ではありません)。
マルチポリゴンの表現
マルチポリゴンは単純にポリゴンのリストであるため、is_holeプロパティを持つPoly2dオブジェクトのリストを使用して同様の方法で記述します。ただし、マルチポリゴン内でPoly2dオブジェクトがどのポリゴンに属するかを決定するpolygon_idプロパティを追加します。以下は、それぞれ1つの穴を持つ2つのポリゴンからなるマルチポリゴンの例です。
{
"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のみです。絶対モードとは、valの値がピクセル座標として解釈されることを意味します(最初の座標ペアからの相対値ではありません)。
曲線の表現
注意
補間メソッドの名前が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のみです。絶対モードとは、valの値がピクセル座標として解釈されることを意味します(最初の座標ペアからの相対値ではありません)。プロパティinterpolation_methodは必須であり、ノード同士をどのように結ぶかを決定します。以下の値がサポートされています:
- natural-cubic-spline
- catmull-rom-0.5
- polyline
3Dレーンの表現
3Dレーンは3D空間における2本の線(poly3d)として表現され、1本は右側、もう1本は左側です。テキストプロパティ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点グループの表現
点グループは、複数のポイントが同じオブジェクトを参照する場合に使用されます。点グループ内の各ポイントにはpoint_class属性が必須であり、point_classはオブジェクトのtypeと異なる必要があります。point_classの値"line_reference_point"は将来のユースケースのために予約されています。
ジオメトリコレクションの表現
注記
kognic_format_version 2.2で導入されました。
タスクビューに関する関連ドキュメント:ジオメトリコレクション
上記リンクで説明されているジオメトリのコレクションは、geometry_collectionをtypeとする予約済みリレーションを持つものとして表現されます。
{
"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セグメンテーションの表現
分類はランレングス符号化(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>"
}
]
}
}