diff --git a/t4_devkit/dataclass/box.py b/t4_devkit/dataclass/box.py index 62172fa6..400974bf 100644 --- a/t4_devkit/dataclass/box.py +++ b/t4_devkit/dataclass/box.py @@ -133,21 +133,26 @@ class Box3D(BaseBox): def with_future( self, - timestamps: ArrayLike, + relative_timestamps: ArrayLike, confidences: ArrayLike, waypoints: ArrayLike, ) -> Self: """Return a self instance setting `future` attribute. Args: - timestamps (ArrayLike): Array of future timestamps at each waypoint in the shape of (T). + relative_timestamps (ArrayLike): Array of future timestamps at each waypoint from the current timestamp, + in the shape of (T). confidences (ArrayLike): Array of confidences for each mode in the shape of (M). waypoints (ArrayLike): Array of waypoints for each mode in the shape of (M, T, D). Returns: Self instance after setting `future`. """ - self.future = Future(timestamps=timestamps, confidences=confidences, waypoints=waypoints) + self.future = Future( + relative_timestamps=relative_timestamps, + confidences=confidences, + waypoints=waypoints, + ) return self def __eq__(self, other: Box3D | None) -> bool: diff --git a/t4_devkit/dataclass/trajectory.py b/t4_devkit/dataclass/trajectory.py index bfee9405..a5e84d13 100644 --- a/t4_devkit/dataclass/trajectory.py +++ b/t4_devkit/dataclass/trajectory.py @@ -18,7 +18,7 @@ class ObjectPath: """A dataclass to represent object path including timestamps, confidences, and waypoints.""" - timestamps: NDArrayInt = field(converter=np.array) + relative_timestamps: NDArrayInt = field(converter=np.array) confidences: NDArrayFloat = field( converter=np.array, validator=validators.deep_iterable((validators.ge(0.0), validators.le(1.0))), @@ -30,10 +30,10 @@ def __attrs_post_init__(self) -> None: def _check_dims(self) -> None: # check timestamp length between timestamps and waypoints - if len(self.timestamps) != self.waypoints.shape[1]: + if len(self.relative_timestamps) != self.waypoints.shape[1]: raise ValueError( - "Timestamp length must be the same between `timestamps` and `waypoints`, " - f"but got timestamps={len(self.timestamps)} and waypoints={self.waypoints.shape[1]}" + "Timestamp length must be the same between `relative_timestamps` and `waypoints`, " + f"but got relative_timestamps={len(self.relative_timestamps)} and waypoints={self.waypoints.shape[1]}" ) # check mode length between waypoints and confidences diff --git a/t4_devkit/helper/timeseries.py b/t4_devkit/helper/timeseries.py index b9ed2dcd..1206d1e0 100644 --- a/t4_devkit/helper/timeseries.py +++ b/t4_devkit/helper/timeseries.py @@ -46,7 +46,7 @@ def get_sample_annotations_until( seconds (float): Time seconds until. If `>=0` explore future, otherwise past. Returns: - List of timestamps and associated sample annotation records of the specified instance. + List of relative timestamps and associated sample annotation records of the specified instance. """ start_sample: Sample = self._t4.get("sample", sample_token) @@ -69,7 +69,9 @@ def get_sample_annotations_until( current_sample_token = current_sample.next if is_successor else current_sample.prev - return timestamps, anns + relative_timestamps = [t - start_sample.timestamp for t in timestamps] + + return relative_timestamps, anns def get_object_anns_until( self, @@ -87,7 +89,7 @@ def get_object_anns_until( seconds (float): Time seconds until. If `>=0` explore future, otherwise past. Returns: - List of timestamps and associated object annotation records of the specified instance. + List of relative timestamps and associated object annotation records of the specified instance. """ start_sample_data: SampleData = self._t4.get("sample_data", sample_data_token) @@ -116,4 +118,6 @@ def get_object_anns_until( current_sample_data.next if is_successor else current_sample_data.prev ) - return timestamps, anns + relative_timestamps = [t - start_sample_data.timestamp for t in timestamps] + + return relative_timestamps, anns diff --git a/t4_devkit/tier4.py b/t4_devkit/tier4.py index 698d66b1..0cee7a64 100644 --- a/t4_devkit/tier4.py +++ b/t4_devkit/tier4.py @@ -515,13 +515,17 @@ def get_box3d(self, sample_annotation_token: str, *, future_seconds: float = 0.0 if future_seconds > 0.0: # NOTE: Future trajectory is map coordinate frame - timestamps, anns = self._timeseries_helper.get_sample_annotations_until( + relative_timestamps, anns = self._timeseries_helper.get_sample_annotations_until( ann.instance_token, ann.sample_token, future_seconds ) if len(anns) == 0: return box waypoints = [ann.translation for ann in anns] - return box.with_future(timestamps=timestamps, confidences=[1.0], waypoints=[waypoints]) + return box.with_future( + relative_timestamps=relative_timestamps, + confidences=[1.0], + waypoints=[waypoints], + ) else: return box diff --git a/tests/conftest.py b/tests/conftest.py index e3cd6a3a..60266977 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -62,7 +62,7 @@ def dummy_box3d() -> Box3D: num_points=1, visibility=VisibilityLevel.FULL, ).with_future( - timestamps=[101, 102, 103, 104], + relative_timestamps=[1, 2, 3, 4], confidences=[1.0, 0.5], waypoints=[ np.array( @@ -106,7 +106,7 @@ def dummy_box3ds() -> list[Box3D]: num_points=1, visibility=VisibilityLevel.FULL, ).with_future( - timestamps=[101, 102, 103, 104], + relative_timestamps=[1, 2, 3, 4], confidences=[1.0], waypoints=[ np.array( @@ -132,7 +132,7 @@ def dummy_box3ds() -> list[Box3D]: num_points=1, visibility=VisibilityLevel.MOST, ).with_future( - timestamps=[101, 102, 103, 104], + relative_timestamps=[1, 2, 3, 4], confidences=[1.0, 0.5], waypoints=[ np.array( @@ -166,7 +166,7 @@ def dummy_box3ds() -> list[Box3D]: num_points=1, visibility="none", # str is also OK ).with_future( - timestamps=[101, 102, 103, 104], + relative_timestamps=[1, 2, 3, 4], confidences=[1.0, 0.5, 0.2], waypoints=[ np.array( @@ -259,7 +259,7 @@ def dummy_future() -> Future: """ # list item is converted to NDArray internally return Future( - timestamps=[101, 102], + relative_timestamps=[1, 2], confidences=[1.0], waypoints=[[[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]]], ) diff --git a/tests/dataclass/test_trajectory.py b/tests/dataclass/test_trajectory.py index 3c71a9e6..abbfcca2 100644 --- a/tests/dataclass/test_trajectory.py +++ b/tests/dataclass/test_trajectory.py @@ -55,7 +55,7 @@ def test_to_future() -> None: """Test `to_trajectories` function including its valid and invalid cases.""" # valid case future = Future( - timestamps=[101, 102, 103], + relative_timestamps=[1, 2, 3], confidences=[ 1.0, # mode0 0.5, # mode1 @@ -70,7 +70,7 @@ def test_to_future() -> None: # invalid case: different element length with pytest.raises(ValueError): _ = Future( - timestamps=[101, 102, 103], + relative_timestamps=[1, 2, 3], confidences=[1.0], # mode0 waypoints=[ [[1.0, 1.0, 1.0], [2.0, 2.0, 2.0], [3.0, 3.0, 3.0]], # mode0