Skip to content

Commit 4c87c7a

Browse files
mojomexktro2828SamratThapa120Copilot
committed
chore(viewer): lidarseg tweaks (#256)
* chore(deps): restrict rerun-sdk to versions >=0.20.0,<0.28.0 (#248) * Bump version from 0.5.2 to 0.5.3 (#247) * Bump version from 0.5.2 to 0.5.3 * Pin rerun-sdk dependency to version 0.20.0 * refactor: update custom validator definition (#250) * refactor: update custom validator definition Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> * Update t4_devkit/schema/tables/base.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: modity type of size to tuple[int, int] (#251) Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> * fix: abstract away category indexing differences Semseg and non-semseg datasets behave differently (position-based vs. explicit indexing). Now computing index field in case position-based indexing is used. Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * fix(rendering): don't fail when map is not present Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * fix(rendering): fix iteration freezing when skipping a pointcloud without lidarseg file Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * feat(rendering): auto-enable SEGMENTATION coloring when lidarseg is available Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * docs: checkmark for semseg viz Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * fix(rendering): fix wrongly named `color_mode` args Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> * refactor(compatibility): move to schema package Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> --------- Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> Signed-off-by: Max SCHMELLER <max.schmeller@tier4.jp> Co-authored-by: Kotaro Uetake <60615504+ktro2828@users.noreply.github.com> Co-authored-by: Samrat Thapa <38401989+SamratThapa120@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent f3070cc commit 4c87c7a

5 files changed

Lines changed: 73 additions & 11 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ More details, please refer to [`t4viz` CLI](./docs/cli/t4viz.md) or [API usage](
5959
| Feature | Task | Support |
6060
| :------ | :-------------------------- | :-----: |
6161
| 3D | 3D Boxes ||
62-
| | PointCloud Segmentation | |
62+
| | PointCloud Segmentation | |
6363
| | Raw PointCloud ||
6464
| | 3D Trajectories ||
6565
| | TF Links ||

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ More details, please refer to [`t4viz` CLI](./cli/t4viz.md) or [API usage](./tut
1717
| Feature | Task | Support |
1818
| :------ | :-------------------------- | :-----: |
1919
| 3D | 3D Boxes ||
20-
| | PointCloud Segmentation | |
20+
| | PointCloud Segmentation | |
2121
| | Raw PointCloud ||
2222
| | 3D Trajectories ||
2323
| | TF Links ||

t4_devkit/helper/rendering.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def __init__(self, t4: Tier4) -> None:
5454
"""
5555
self._t4 = t4
5656
self._label2id: dict[str, int] = {
57-
category.name: idx for idx, category in enumerate(self._t4.category)
57+
category.name: category.index for category in self._t4.category
5858
}
5959
self._sample_data_to_lidarseg_filename: dict[str, str] | None = (
6060
{lidarseg.sample_data_token: lidarseg.filename for lidarseg in self._t4.lidarseg}
@@ -64,6 +64,9 @@ def __init__(self, t4: Tier4) -> None:
6464

6565
self._executor = concurrent.futures.ThreadPoolExecutor()
6666

67+
def _has_lidarseg(self) -> bool:
68+
return self._sample_data_to_lidarseg_filename is not None
69+
6770
def _init_viewer(
6871
self,
6972
app_id: str,
@@ -127,17 +130,24 @@ def render_scene(
127130
app_id = f"scene@{self._t4.dataset_id}"
128131
viewer = self._init_viewer(app_id, render_ann=True, save_dir=save_dir)
129132

130-
# self._render_map(viewer)
133+
self._try_render_map(viewer)
131134

132135
scene: Scene = self._t4.scene[0]
133136
first_sample: Sample = self._t4.get("sample", scene.first_sample_token)
134137
max_timestamp_us = first_sample.timestamp + seconds2microseconds(max_time_seconds)
135138

139+
pointcloud_color_mode = (
140+
PointCloudColorMode.SEGMENTATION
141+
if self._has_lidarseg()
142+
else PointCloudColorMode.DISTANCE
143+
)
144+
136145
concurrent.futures.wait(
137146
self._render_lidar_and_ego(
138147
viewer=viewer,
139148
first_lidar_tokens=first_lidar_tokens,
140149
max_timestamp_us=max_timestamp_us,
150+
color_mode=pointcloud_color_mode,
141151
)
142152
+ self._render_radars(
143153
viewer=viewer,
@@ -226,13 +236,20 @@ def render_instance(
226236
app_id = f"instance@{self._t4.dataset_id}"
227237
viewer = self._init_viewer(app_id, render_ann=True, save_dir=save_dir)
228238

229-
self._render_map(viewer)
239+
self._try_render_map(viewer)
240+
241+
pointcloud_color_mode = (
242+
PointCloudColorMode.SEGMENTATION
243+
if self._has_lidarseg()
244+
else PointCloudColorMode.DISTANCE
245+
)
230246

231247
concurrent.futures.wait(
232248
self._render_lidar_and_ego(
233249
viewer=viewer,
234250
first_lidar_tokens=first_lidar_tokens,
235251
max_timestamp_us=max_timestamp_us,
252+
color_mode=pointcloud_color_mode,
236253
)
237254
+ self._render_radars(
238255
viewer=viewer,
@@ -287,7 +304,7 @@ def render_pointcloud(
287304
app_id = f"pointcloud@{self._t4.dataset_id}"
288305
viewer = self._init_viewer(app_id, render_ann=False, save_dir=save_dir)
289306

290-
self._render_map(viewer)
307+
self._try_render_map(viewer)
291308

292309
# search first lidar sample data token
293310
first_lidar_token: str | None = None
@@ -304,17 +321,25 @@ def render_pointcloud(
304321
max_time_seconds
305322
)
306323

324+
pointcloud_color_mode = (
325+
PointCloudColorMode.SEGMENTATION
326+
if self._has_lidarseg()
327+
else PointCloudColorMode.DISTANCE
328+
)
329+
307330
concurrent.futures.wait(
308331
self._render_lidar_and_ego(
309332
viewer=viewer,
310333
first_lidar_tokens=[first_lidar_token],
311334
max_timestamp_us=max_timestamp_us,
335+
color_mode=pointcloud_color_mode,
312336
)
313337
+ self._render_points_on_cameras(
314338
first_point_sample_data_token=first_lidar_token,
315339
max_timestamp_us=max_timestamp_us,
316340
min_dist=1.0,
317341
ignore_distortion=ignore_distortion,
342+
color_mode=pointcloud_color_mode,
318343
),
319344
)
320345

@@ -339,7 +364,7 @@ def render_lidarseg(
339364
app_id = f"lidarseg@{self._t4.dataset_id}"
340365
viewer = self._init_viewer(app_id, render_ann=True, save_dir=save_dir)
341366

342-
self._render_map(viewer)
367+
self._try_render_map(viewer)
343368

344369
# search first lidar sample data token
345370
first_lidar_token: str | None = None
@@ -365,8 +390,10 @@ def render_lidarseg(
365390
)
366391
)
367392

368-
def _render_map(self, viewer: RerunViewer) -> None:
393+
def _try_render_map(self, viewer: RerunViewer) -> None:
369394
lanelet_path = osp.join(self._t4.map_dir, "lanelet2_map.osm")
395+
if not osp.exists(lanelet_path):
396+
return
370397
viewer.render_map(lanelet_path)
371398

372399
def _render_sensor_calibration(self, viewer: RerunViewer, sample_data_token: str) -> None:
@@ -398,6 +425,7 @@ def _render_single_lidar(first_lidar_token: str) -> None:
398425
current_lidar_token = first_lidar_token
399426
while current_lidar_token != "":
400427
sample_data: SampleData = self._t4.get("sample_data", current_lidar_token)
428+
current_lidar_token = sample_data.next
401429

402430
if max_timestamp_us < sample_data.timestamp:
403431
break
@@ -435,8 +463,6 @@ def _render_single_lidar(first_lidar_token: str) -> None:
435463
color_mode=color_mode,
436464
)
437465

438-
current_lidar_token = sample_data.next
439-
440466
return [self._executor.submit(_render_single_lidar, token) for token in first_lidar_tokens]
441467

442468
def _render_radars(

t4_devkit/schema/compatibility.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Compatibility helpers that abstract away differences between T4Dataset revisions."""
2+
3+
from __future__ import annotations
4+
5+
from t4_devkit.schema import Category
6+
7+
8+
def fix_category_table(categories: list[Category]) -> list[Category]:
9+
"""Fix unpopulated index fields in some T4Dataset revisions.
10+
11+
This function behaves differently in the below three cases:
12+
13+
- All `index` fields are set: the list is returned unmodified.
14+
- All `index` fields are `None`: the position of each category in the list is used to compute
15+
`index`. The resulting indices start at `0`.
16+
- Some `index` fields are set and some are `None`: raise a `ValueError`.
17+
18+
Args:
19+
categories (list[Category]): List of categories to fix.
20+
21+
Returns:
22+
list[Category]: Fixed list of categories.
23+
24+
Raises:
25+
ValueError: If the `index` field is set for some categories and `None` for others.
26+
"""
27+
if any(category.index is None for category in categories):
28+
if not all(category.index is None for category in categories):
29+
raise ValueError("Category index is not set for some categories.")
30+
31+
for idx, category in enumerate(categories):
32+
category.index = idx
33+
return categories

t4_devkit/tier4.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from t4_devkit.dataclass import Box2D, Box3D, SemanticLabel, Shape, ShapeType
1616
from t4_devkit.helper import RenderingHelper, TimeseriesHelper
1717
from t4_devkit.schema import SchemaName, SensorModality, VisibilityLevel, build_schema
18+
from t4_devkit.schema.compatibility import fix_category_table
1819

1920
if TYPE_CHECKING:
2021
from t4_devkit.typing import CameraIntrinsicLike, Vector3
@@ -181,6 +182,8 @@ def __init__(
181182
self.annotation_dir, SchemaName.CALIBRATED_SENSOR
182183
)
183184
self.category: list[Category] = load_table(self.annotation_dir, SchemaName.CATEGORY)
185+
self.category = fix_category_table(self.category)
186+
184187
self.ego_pose: list[EgoPose] = load_table(self.annotation_dir, SchemaName.EGO_POSE)
185188
self.instance: list[Instance] = load_table(self.annotation_dir, SchemaName.INSTANCE)
186189
self.keypoint: list[Keypoint] = load_table(self.annotation_dir, SchemaName.KEYPOINT)
@@ -265,7 +268,7 @@ def __make_reverse_index__(self, verbose: bool) -> None:
265268
}
266269

267270
self._label2id: dict[str, int] = {
268-
category.name: idx for idx, category in enumerate(self.category)
271+
category.name: category.index for category in self.category
269272
}
270273

271274
# add shortcuts

0 commit comments

Comments
 (0)