feat(perception): add ground-aware cuboid refusion

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 08:24:37 +03:00
parent b53d6d5a45
commit a0706fd5d8
8 changed files with 1116 additions and 114 deletions
@@ -8,7 +8,7 @@ from collections.abc import Callable
from contextlib import suppress
from dataclasses import dataclass
from pathlib import Path
from typing import Literal, TypedDict
from typing import Any, Literal, TypedDict
from uuid import UUID, uuid4
import numpy as np
@@ -534,6 +534,19 @@ def _recorded_blueprint(
),
).visualizer()
point_visualizer.id = RECORDED_POINTS_VISUALIZER_ID
accumulated_time_ranges = (
rrb.VisibleTimeRanges(time_ranges) if time_ranges is not None else None
)
point_overrides: list[Any] = [
rrb.EntityBehavior(visible=settings.show_points),
point_visualizer,
]
trajectory_overrides: list[Any] = [
rrb.EntityBehavior(visible=settings.show_trajectory),
]
if accumulated_time_ranges is not None:
point_overrides.append(accumulated_time_ranges)
trajectory_overrides.append(accumulated_time_ranges)
spatial_view = rrb.Spatial3DView(
origin="/world",
name="Пространственная сцена",
@@ -548,21 +561,17 @@ def _recorded_blueprint(
# therefore hide/reveal already-recorded entities without
# rewriting the data RRD. Keep the point visualizer alongside it
# so size/color overrides remain active for the same entity.
"/world/points": [
rrb.EntityBehavior(visible=settings.show_points),
point_visualizer,
],
"/world/trajectory": rrb.EntityBehavior(
visible=settings.show_trajectory,
),
"/world/points": point_overrides,
"/world/trajectory": trajectory_overrides,
# Dynamic perception must not inherit the mapping view's
# historical accumulation window. It is rendered latest-at in
# the dedicated perception view below.
"/world/perception": rrb.EntityBehavior(visible=False),
},
# A positive window accumulates historical frames. With no
# window, latest-at deliberately keeps one current LiDAR frame.
time_ranges=time_ranges,
# Clear any prior view-level accumulation and scope the operator's
# history window to mapping entities above. Dynamic perception then
# remains latest-at even when both layers share this world view.
time_ranges=rrb.VisibleTimeRanges([]),
)
spatial_view.id = RECORDED_SPATIAL_VIEW_ID
camera_view = rrb.Spatial2DView(
@@ -599,9 +608,7 @@ def _recorded_blueprint(
name="Маршрут и время",
)
metrics_view.id = RECORDED_METRICS_VIEW_ID
active_tab = {"spatial": 0, "perception": 1, "perception3d": 2, "metrics": 3}[
active_view
]
active_tab = {"spatial": 0, "perception": 1, "perception3d": 2, "metrics": 3}[active_view]
root_container = rrb.Tabs(
spatial_view,
camera_view,
+32 -50
View File
@@ -21,15 +21,11 @@ RECORDED_SPATIAL_RESET_ROOT_CONTAINER_ID = UUID("27d95ad7-1e72-46ca-b854-d02cd99
RECORDED_PERCEPTION_ROOT_CONTAINER_ID = UUID("70ea9fd5-bbbb-4b23-8ae8-8098af92b997")
RECORDED_PERCEPTION_RESET_ROOT_CONTAINER_ID = UUID("d2196c6e-99da-4402-857c-4daea0dd3ae0")
RECORDED_PERCEPTION_3D_ROOT_CONTAINER_ID = UUID("81051015-9808-413b-90a4-1cfaacacbc4f")
RECORDED_PERCEPTION_3D_RESET_ROOT_CONTAINER_ID = UUID(
"3de10822-0274-4a58-8d45-f35d86625303"
)
RECORDED_PERCEPTION_3D_RESET_ROOT_CONTAINER_ID = UUID("3de10822-0274-4a58-8d45-f35d86625303")
RECORDED_METRICS_ROOT_CONTAINER_ID = UUID("374710a2-1d77-4349-bea4-8719e7aa1f09")
RECORDED_METRICS_RESET_ROOT_CONTAINER_ID = UUID("1e8ac565-bbd6-4554-9213-dad564e534e3")
RECORDED_POINTS_VISUALIZER_ID = UUID("ca037ec0-8761-4417-86ee-846fa2875303")
RECORDED_PERCEPTION_POINTS_VISUALIZER_ID = UUID(
"ab8db306-6981-49c5-b417-94fe2f01dbf0"
)
RECORDED_PERCEPTION_POINTS_VISUALIZER_ID = UUID("ab8db306-6981-49c5-b417-94fe2f01dbf0")
RECORDED_CAMERA_VIEW_ID = UUID("5c1db75b-07cd-479a-903d-f4f2ed554513")
RECORDED_CAMERA_RESET_VIEW_ID = UUID("d0618e0c-c889-4222-a643-60a4a882935c")
RECORDED_PERCEPTION_3D_VIEW_ID = UUID("0496bd2e-2b4d-4a4f-87b8-3ce4f9f7e114")
@@ -65,25 +61,33 @@ def recorded_blueprint(
end=rr.TimeRangeBoundary.cursor_relative(),
)
]
latest_time_ranges = rrb.VisibleTimeRanges([])
accumulated_time_ranges = (
rrb.VisibleTimeRanges(time_ranges) if time_ranges is not None else None
)
point_visualizer = rr.Points3D.from_fields(
radii=rr.Radius.ui_points(settings.point_size),
colors=(
[_parse_hex_color(settings.custom_color)]
if settings.palette == "custom"
else None
[_parse_hex_color(settings.custom_color)] if settings.palette == "custom" else None
),
).visualizer()
point_visualizer.id = RECORDED_POINTS_VISUALIZER_ID
perception_point_visualizer = rr.Points3D.from_fields(
radii=rr.Radius.ui_points(settings.point_size),
colors=(
[_parse_hex_color(settings.custom_color)]
if settings.palette == "custom"
else None
[_parse_hex_color(settings.custom_color)] if settings.palette == "custom" else None
),
).visualizer()
perception_point_visualizer.id = RECORDED_PERCEPTION_POINTS_VISUALIZER_ID
point_overrides: list[Any] = [
rrb.EntityBehavior(visible=settings.show_points),
point_visualizer,
]
trajectory_overrides: list[Any] = [
rrb.EntityBehavior(visible=settings.show_trajectory),
]
if accumulated_time_ranges is not None:
point_overrides.append(accumulated_time_ranges)
trajectory_overrides.append(accumulated_time_ranges)
spatial_view = rrb.Spatial3DView(
origin="/world",
name="Мир · LiDAR и объекты" if unified_perception else "Пространственная сцена",
@@ -94,24 +98,19 @@ def recorded_blueprint(
stroke_width=0.75,
),
overrides={
"/world/points": [
rrb.EntityBehavior(visible=settings.show_points),
point_visualizer,
],
"/world/trajectory": rrb.EntityBehavior(
visible=settings.show_trajectory,
),
# Perception is hidden in the mapping-only presentation. Unified
# perception below adds explicit per-entity latest-at overrides,
# allowing the native cloud to retain this view's accumulation.
# Accumulation belongs to mapping data only. Dynamic perception
# inherits the view's latest-at query and can never turn into an
# object-history trail when the operator widens the cloud window.
"/world/points": point_overrides,
"/world/trajectory": trajectory_overrides,
"/world/perception": rrb.EntityBehavior(visible=False),
},
time_ranges=time_ranges,
# Log an explicit empty range set so a previous accumulated blueprint
# for this stable view id is cleared instead of surviving in Rerun.
time_ranges=rrb.VisibleTimeRanges([]),
)
spatial_view.id = (
RECORDED_SPATIAL_RESET_VIEW_ID
if view_reset_generation
else RECORDED_SPATIAL_VIEW_ID
RECORDED_SPATIAL_RESET_VIEW_ID if view_reset_generation else RECORDED_SPATIAL_VIEW_ID
)
camera_view = rrb.Spatial2DView(
origin="/perception/camera",
@@ -128,9 +127,7 @@ def recorded_blueprint(
},
)
camera_view.id = (
RECORDED_CAMERA_RESET_VIEW_ID
if view_reset_generation
else RECORDED_CAMERA_VIEW_ID
RECORDED_CAMERA_RESET_VIEW_ID if view_reset_generation else RECORDED_CAMERA_VIEW_ID
)
perception_3d_view = rrb.Spatial3DView(
# Cuboids are expressed in the same calibrated world frame as the
@@ -181,31 +178,18 @@ def recorded_blueprint(
# semantic points and cuboids independently.
spatial_view.visualizer_overrides["/world/perception"] = [
rrb.EntityBehavior(visible=True),
latest_time_ranges,
]
spatial_view.visualizer_overrides[
"/world/perception/lidar"
] = [
spatial_view.visualizer_overrides["/world/perception/lidar"] = [
rrb.EntityBehavior(visible=False),
latest_time_ranges,
]
spatial_view.visualizer_overrides[
"/world/perception/support"
] = [
spatial_view.visualizer_overrides["/world/perception/support"] = [
rrb.EntityBehavior(visible=False),
latest_time_ranges,
]
spatial_view.visualizer_overrides[
"/world/perception/semantic_points"
] = [
spatial_view.visualizer_overrides["/world/perception/semantic_points"] = [
rrb.EntityBehavior(visible=show_segmentation),
latest_time_ranges,
]
spatial_view.visualizer_overrides[
"/world/perception/boxes3d"
] = [
spatial_view.visualizer_overrides["/world/perception/boxes3d"] = [
rrb.EntityBehavior(visible=show_cuboids_3d),
latest_time_ranges,
]
root_container = rrb.Horizontal(
camera_view,
@@ -222,9 +206,7 @@ def recorded_blueprint(
# Keep operator video and 3D cuboids as direct root views. Rerun's nested
# Tabs preserve their own active child and cannot be switched reliably by
# a live blueprint channel after the operator has visited another child.
active_tab = {"spatial": 0, "perception": 1, "perception3d": 2, "metrics": 3}[
active_view
]
active_tab = {"spatial": 0, "perception": 1, "perception3d": 2, "metrics": 3}[active_view]
root_container = rrb.Tabs(
spatial_view,
camera_view,