Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/schema/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ visibility {

The following tables are optional, and skipped loading by `Tier4` class if not exists.

### LidarSeg

- Filename: `lidarseg.json`

Mapping between LiDAR segmentation annotations and `SampleData` corresponding to the LiDAR point cloud associated with a keyframe.

```json
lidarseg {
"token": <str> -- Unique record identifier.
"filename": <str> -- Filename of the LiDAR segmentation annotation labels that is an array of unit8.
"sample_data_token": <str> -- Foreign key to the `SampleData` table associated with the sample data.
}
```

### ObjectAnn

- Filename: `object_ann.json`
Expand Down
3 changes: 3 additions & 0 deletions t4_devkit/schema/name.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class SchemaName(str, Enum):
SCENE: A scene is a specific long sequence of consecutive frames extracted from a log.
SENSOR: A specific sensor type.
VISIBILITY: The visibility of instance is the fraction of annotation visible in all images.
LIDARSEG (optional): The annotation of 3D point cloud segmentation.
OBJECT_ANN (optional): The annotation of a foreground object in an image.
SURFACE_ANN (optional): The annotation of a background object in an image.
KEYPOINT (optional): The annotation of pose keypoints of an object in an image.
Expand All @@ -42,6 +43,7 @@ class SchemaName(str, Enum):
VISIBILITY = "visibility"
SENSOR = "sensor"
SCENE = "scene"
LIDARSEG = "lidarseg" # optional
OBJECT_ANN = "object_ann" # optional
SURFACE_ANN = "surface_ann" # optional
KEYPOINT = "keypoint" # optional
Expand All @@ -63,6 +65,7 @@ def is_optional(self) -> bool:
Return True if this schema is optional.
"""
return self in (
SchemaName.LIDARSEG,
SchemaName.OBJECT_ANN,
SchemaName.SURFACE_ANN,
SchemaName.KEYPOINT,
Expand Down
1 change: 1 addition & 0 deletions t4_devkit/schema/tables/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .ego_pose import * # noqa
from .instance import * # noqa
from .keypoint import * # noqa
from .lidarseg import * # noqa
from .log import * # noqa
from .map import * # noqa
from .object_ann import * # noqa
Expand Down
24 changes: 24 additions & 0 deletions t4_devkit/schema/tables/lidarseg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

from attrs import define, field, validators

from ..name import SchemaName
from .base import SchemaBase
from .registry import SCHEMAS

__all__ = ["LidarSeg"]


@define(slots=False)
@SCHEMAS.register(SchemaName.LIDARSEG)
class LidarSeg(SchemaBase):
"""A dataclass to represent lidar point cloud segmentation data.

Attributes:
token (str): Unique record identifier.
filename (str): The filename of the lidar point cloud segmentation data.
sample_data_token (str): The token of the sample data.
"""

filename: str = field(validator=validators.instance_of(str))
sample_data_token: str = field(validator=validators.instance_of(str))
2 changes: 2 additions & 0 deletions t4_devkit/tier4.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
EgoPose,
Instance,
Keypoint,
LidarSeg,
Log,
Map,
ObjectAnn,
Expand Down Expand Up @@ -183,6 +184,7 @@ def __init__(
self.ego_pose: list[EgoPose] = load_table(self.annotation_dir, SchemaName.EGO_POSE)
self.instance: list[Instance] = load_table(self.annotation_dir, SchemaName.INSTANCE)
self.keypoint: list[Keypoint] = load_table(self.annotation_dir, SchemaName.KEYPOINT)
self.lidarseg: list[LidarSeg] = load_table(self.annotation_dir, SchemaName.LIDARSEG)
self.log: list[Log] = load_table(self.annotation_dir, SchemaName.LOG)
self.map: list[Map] = load_table(self.annotation_dir, SchemaName.MAP)
self.object_ann: list[ObjectAnn] = load_table(self.annotation_dir, SchemaName.OBJECT_ANN)
Expand Down
19 changes: 19 additions & 0 deletions tests/schema/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,25 @@ def visibility_json(visibility_dict) -> Generator[str, Any, None]:
yield f.name


# === LidarSeg ===
@pytest.fixture(scope="session")
def lidarseg_dict() -> dict:
"""Return a dummy lidarseg record as dictionary."""
return {
"token": "4f79b0e9ae192558c76bd31a84bfe125",
"filename": "lidarseg/0.bin",
"sample_data_token": "df2bee5733d8607e49bf792fac3014a3",
}


@pytest.fixture(scope="session")
def lidarseg_json(lidarseg_dict) -> Generator[str, Any, None]:
"""Return a file path of dummy lidarseg record."""
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as f:
save_json([lidarseg_dict], f.name)
yield f.name


# === ObjectAnn ===
@pytest.fixture(scope="session")
def object_ann_dict() -> dict:
Expand Down
26 changes: 26 additions & 0 deletions tests/schema/tables/test_lidarseg_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from __future__ import annotations

from t4_devkit.common.serialize import serialize_dataclass, serialize_dataclasses
from t4_devkit.schema import LidarSeg


def test_lidarseg_json(lidarseg_json) -> None:
"""Test loading lidarseg from a json file."""
schemas = LidarSeg.from_json(lidarseg_json)
serialized = serialize_dataclasses(schemas)
assert isinstance(serialized, list)


def test_lidarseg(lidarseg_dict) -> None:
"""Test loading lidarseg from a dictionary."""
schema = LidarSeg.from_dict(lidarseg_dict)
serialized = serialize_dataclass(schema)
assert serialized == lidarseg_dict


def test_new_lidarseg(lidarseg_dict) -> None:
"""Test generating lidarseg with a new token."""
without_token = {k: v for k, v in lidarseg_dict.items() if k != "token"}
ret = LidarSeg.new(without_token)
# check the new token is not the same with the token in input data
assert ret.token != lidarseg_dict["token"]
7 changes: 7 additions & 0 deletions tests/schema/test_schema_builder.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from t4_devkit.schema import SchemaName, build_schema


Expand Down Expand Up @@ -26,6 +28,11 @@ def test_build_instance(instance_json) -> None:
_ = build_schema(SchemaName.INSTANCE, instance_json)


def test_build_lidarseg(lidarseg_json) -> None:
"""Test building lidarseg."""
_ = build_schema(SchemaName.LIDARSEG, lidarseg_json)


def test_build_log(log_json) -> None:
"""Test building log."""
_ = build_schema(SchemaName.LOG, log_json)
Expand Down
3 changes: 3 additions & 0 deletions tests/schema/test_schema_name.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from t4_devkit.schema import SchemaName


Expand All @@ -19,6 +21,7 @@ def test_schema_name() -> None:
"visibility": False,
"sensor": False,
"scene": False,
"lidarseg": True,
"object_ann": True,
"surface_ann": True,
"keypoint": True,
Expand Down
Loading