Skip to content

Commit

Permalink
refactor: delete everything related to fromdict and asdict
Browse files Browse the repository at this point in the history
  • Loading branch information
tklockau committed Nov 4, 2024
1 parent 6ae1039 commit fee3aff
Show file tree
Hide file tree
Showing 53 changed files with 30 additions and 4,319 deletions.
18 changes: 1 addition & 17 deletions raillabel/format/_object_annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from __future__ import annotations

from abc import ABC, abstractmethod, abstractproperty
from abc import ABC, abstractproperty
from dataclasses import dataclass
from importlib import import_module
from inspect import isclass
Expand Down Expand Up @@ -32,22 +32,6 @@ def name(self) -> str:
def OPENLABEL_ID(self) -> list[str] | str:
raise NotImplementedError

# === Public Methods =====================================================

@abstractmethod
def asdict(self) -> dict:
raise NotImplementedError

@classmethod
@abstractmethod
def fromdict(
cls,
data_dict: dict,
sensors: dict,
object: Object,
) -> type[_ObjectAnnotation]:
raise NotImplementedError

# === Private Methods ====================================================

def _annotation_required_fields_asdict(self) -> dict:
Expand Down
56 changes: 0 additions & 56 deletions raillabel/format/bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from dataclasses import dataclass

from ._object_annotation import _ObjectAnnotation
from .object import Object
from .point2d import Point2d
from .size2d import Size2d

Expand Down Expand Up @@ -42,58 +41,3 @@ class Bbox(_ObjectAnnotation):
size: Size2d

OPENLABEL_ID = "bbox"

@classmethod
def fromdict(cls, data_dict: dict, sensors: dict, object: Object) -> Bbox:
"""Generate a Bbox object from a dict.
Parameters
----------
data_dict: dict
RailLabel format snippet containing the relevant data.
sensors: dict
Dictionary containing all sensors for the scene.
object: raillabel.format.Object
Object this annotation belongs to.
Returns
-------
annotation: Bbox
Converted annotation.
"""
return Bbox(
uid=str(data_dict["uid"]),
pos=Point2d(x=data_dict["val"][0], y=data_dict["val"][1]),
size=Size2d(x=data_dict["val"][2], y=data_dict["val"][3]),
object=object,
sensor=cls._coordinate_system_fromdict(data_dict, sensors),
attributes=cls._attributes_fromdict(data_dict),
)

def asdict(self) -> dict:
"""Export self as a dict compatible with the OpenLABEL schema.
Returns
-------
dict_repr: dict
Dict representation of this class instance.
Raises
------
ValueError
if an attribute can not be converted to the type required by the OpenLabel schema.
"""
dict_repr = self._annotation_required_fields_asdict()

dict_repr["val"] = [
float(self.pos.x),
float(self.pos.y),
float(self.size.x),
float(self.size.y),
]

dict_repr.update(self._annotation_optional_fields_asdict())

return dict_repr
76 changes: 0 additions & 76 deletions raillabel/format/cuboid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from dataclasses import dataclass

from ._object_annotation import _ObjectAnnotation
from .object import Object
from .point3d import Point3d
from .quaternion import Quaternion
from .size3d import Size3d
Expand Down Expand Up @@ -47,78 +46,3 @@ class Cuboid(_ObjectAnnotation):
size: Size3d

OPENLABEL_ID = "cuboid"

@classmethod
def fromdict(cls, data_dict: dict, sensors: dict, object: Object) -> Cuboid:
"""Generate a Cuboid object from a dict.
Parameters
----------
data_dict: dict
RailLabel format snippet containing the relevant data.
sensors: dict
Dictionary containing all sensors for the scene.
object: raillabel.format.Object
Object this annotation belongs to.
Returns
-------
annotation: Cuboid
Converted annotation.
"""
return Cuboid(
uid=str(data_dict["uid"]),
pos=Point3d(
x=data_dict["val"][0],
y=data_dict["val"][1],
z=data_dict["val"][2],
),
quat=Quaternion(
x=data_dict["val"][3],
y=data_dict["val"][4],
z=data_dict["val"][5],
w=data_dict["val"][6],
),
size=Size3d(
x=data_dict["val"][7],
y=data_dict["val"][8],
z=data_dict["val"][9],
),
object=object,
sensor=cls._coordinate_system_fromdict(data_dict, sensors),
attributes=cls._attributes_fromdict(data_dict),
)

def asdict(self) -> dict:
"""Export self as a dict compatible with the OpenLABEL schema.
Returns
-------
dict_repr: dict
Dict representation of this class instance.
Raises
------
ValueError
if an attribute can not be converted to the type required by the OpenLabel schema.
"""
dict_repr = self._annotation_required_fields_asdict()

dict_repr["val"] = [
float(self.pos.x),
float(self.pos.y),
float(self.pos.z),
float(self.quat.x),
float(self.quat.y),
float(self.quat.z),
float(self.quat.w),
float(self.size.x),
float(self.size.y),
float(self.size.z),
]

dict_repr.update(self._annotation_optional_fields_asdict())

return dict_repr
33 changes: 0 additions & 33 deletions raillabel/format/element_data_pointer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,36 +34,3 @@ class ElementDataPointer:
uid: str
frame_intervals: list[FrameInterval]
attribute_pointers: dict[str, AttributeType]

@property
def annotation_type(self) -> str:
"""Return type of annotation e.g. bbox, cuboid."""
return self.uid.split("__")[1]

def asdict(self) -> dict:
"""Export self as a dict compatible with the OpenLABEL schema.
Returns
-------
dict_repr: dict
Dict representation of this class instance.
Raises
------
ValueError
if an attribute can not be converted to the type required by the OpenLabel schema.
"""
return {
"type": self.annotation_type,
"frame_intervals": self._frame_intervals_asdict(),
"attribute_pointers": self._attribute_pointers_asdict(),
}

def _frame_intervals_asdict(self) -> list[dict[str, int]]:
return [fi.asdict() for fi in self.frame_intervals]

def _attribute_pointers_asdict(self) -> dict[str, str]:
return {
attr_name: attr_type.value for attr_name, attr_type in self.attribute_pointers.items()
}
160 changes: 1 addition & 159 deletions raillabel/format/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
from __future__ import annotations

import decimal
import typing as t
from dataclasses import dataclass, field

from ._object_annotation import _ObjectAnnotation, annotation_classes
from ._object_annotation import _ObjectAnnotation
from .num import Num
from .object import Object
from .sensor import Sensor
from .sensor_reference import SensorReference


Expand Down Expand Up @@ -64,158 +61,3 @@ def object_data(self) -> dict[str, dict[str, type[_ObjectAnnotation]]]:
object_data[annotation.object.uid][ann_id] = annotation

return object_data

@classmethod
def fromdict(
cls,
data_dict: dict,
objects: dict[str, Object],
sensors: dict[str, Sensor],
) -> Frame:
"""Generate a Frame object from a dict.
Parameters
----------
uid: str
Unique identifier of the frame.
data_dict: dict
RailLabel format snippet containing the relevant data.
objects: dict
Dictionary of all objects in the scene.
sensors: dict
Dictionary of all sensors in the scene.
Returns
-------
frame: raillabel.format.Frame
Converted Frame object.
"""
return Frame(
timestamp=cls._timestamp_fromdict(data_dict),
sensors=cls._sensors_fromdict(data_dict, sensors),
frame_data=cls._frame_data_fromdict(data_dict, sensors),
annotations=cls._objects_fromdict(data_dict, objects, sensors),
)

def asdict(self) -> dict[str, t.Any]:
"""Export self as a dict compatible with the OpenLABEL schema.
Returns
-------
dict_repr: dict
Dict representation of this class instance.
Raises
------
ValueError
if an attribute can not be converted to the type required by the OpenLabel schema.
"""
dict_repr: dict[str, t.Any] = {}

if self.timestamp is not None or self.sensors != {} or self.frame_data != {}:
dict_repr["frame_properties"] = {}

if self.timestamp is not None:
dict_repr["frame_properties"]["timestamp"] = str(self.timestamp)

if self.sensors != {}:
dict_repr["frame_properties"]["streams"] = {
str(k): v.asdict() for k, v in self.sensors.items()
}

if self.frame_data != {}:
dict_repr["frame_properties"]["frame_data"] = {
"num": [v.asdict() for v in self.frame_data.values()]
}

if self.annotations != {}:
dict_repr["objects"] = self._annotations_asdict()

return dict_repr

@classmethod
def _timestamp_fromdict(cls, data_dict: dict) -> decimal.Decimal | None:
if "frame_properties" not in data_dict or "timestamp" not in data_dict["frame_properties"]:
return None

return decimal.Decimal(data_dict["frame_properties"]["timestamp"])

@classmethod
def _sensors_fromdict(
cls, data_dict: dict, scene_sensors: dict[str, Sensor]
) -> dict[str, SensorReference]:
if "frame_properties" not in data_dict or "streams" not in data_dict["frame_properties"]:
return {}

sensors = {}

for sensor_id, sensor_dict in data_dict["frame_properties"]["streams"].items():
sensors[sensor_id] = SensorReference.fromdict(
data_dict=sensor_dict, sensor=scene_sensors[sensor_id]
)

return sensors

@classmethod
def _frame_data_fromdict(cls, data_dict: dict, sensors: dict[str, Sensor]) -> dict[str, Num]:
if "frame_properties" not in data_dict or "frame_data" not in data_dict["frame_properties"]:
return {}

frame_data = {}
for ann_type in data_dict["frame_properties"]["frame_data"]:
for ann_raw in data_dict["frame_properties"]["frame_data"][ann_type]:
frame_data[ann_raw["name"]] = Num.fromdict(ann_raw, sensors)

return frame_data

@classmethod
def _objects_fromdict(
cls,
data_dict: dict,
objects: dict[str, Object],
sensors: dict[str, Sensor],
) -> dict[str, type[_ObjectAnnotation]]:
if "objects" not in data_dict:
return {}

annotations = {}

for obj_id, obj_ann in data_dict["objects"].items():
object_annotations = cls._object_annotations_fromdict(
data_dict=obj_ann["object_data"],
object=objects[obj_id],
sensors=sensors,
)

for annotation in object_annotations:
annotations[annotation.uid] = annotation

return annotations

@classmethod
def _object_annotations_fromdict(
cls,
data_dict: dict,
object: Object,
sensors: dict[str, Sensor],
) -> t.Iterator[type[_ObjectAnnotation]]:
for ann_type, annotations_raw in data_dict.items():
for ann_raw in annotations_raw:
yield annotation_classes()[ann_type].fromdict(ann_raw, sensors, object)

def _annotations_asdict(self) -> dict[str, t.Any]:
annotations_dict: dict[str, t.Any] = {}
for object_id, annotations_ in self.object_data.items():
annotations_dict[object_id] = {"object_data": {}}

for annotation in annotations_.values():
if annotation.OPENLABEL_ID not in annotations_dict[object_id]["object_data"]:
annotations_dict[object_id]["object_data"][annotation.OPENLABEL_ID] = []

annotations_dict[object_id]["object_data"][annotation.OPENLABEL_ID].append(
annotation.asdict() # type: ignore
)

return annotations_dict
Loading

0 comments on commit fee3aff

Please sign in to comment.