Skip to content

Commit a2803ce

Browse files
committed
feat: add support of colorizing points on image by intensity
Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
1 parent d59baf7 commit a2803ce

2 files changed

Lines changed: 30 additions & 22 deletions

File tree

t4_devkit/helper/rendering.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from t4_devkit.common.timestamp import sec2us, us2sec
1717
from t4_devkit.dataclass import LidarPointCloud, RadarPointCloud
1818
from t4_devkit.schema import SensorModality
19-
from t4_devkit.viewer import RerunViewer, distance_color, format_entity
19+
from t4_devkit.viewer import PointCloudColorMode, RerunViewer, format_entity, normalize_color
2020

2121
if TYPE_CHECKING:
2222
from t4_devkit import Tier4
@@ -468,7 +468,7 @@ def _render_points_on_single_camera(camera: str) -> None:
468468
if max_timestamp_us < sample.timestamp:
469469
break
470470

471-
points_on_image, depths, image = self._project_pointcloud(
471+
points_on_image, colors, image = self._project_pointcloud(
472472
point_sample_data_token=current_point_sample_data_token,
473473
camera_sample_data_token=camera_sample_data_token,
474474
min_dist=min_dist,
@@ -480,7 +480,7 @@ def _render_points_on_single_camera(camera: str) -> None:
480480
rr.log(format_entity(RerunViewer.ego_entity, camera), rr.Image(image))
481481
rr.log(
482482
format_entity(RerunViewer.ego_entity, camera, "pointcloud"),
483-
rr.Points2D(positions=points_on_image.T, colors=distance_color(depths)),
483+
rr.Points2D(positions=points_on_image.T, colors=colors),
484484
)
485485

486486
current_point_sample_data_token = sample_data.next
@@ -498,6 +498,7 @@ def _project_pointcloud(
498498
min_dist: float = 1.0,
499499
*,
500500
ignore_distortion: bool = True,
501+
color_mode: PointCloudColorMode = PointCloudColorMode.INTENSITY,
501502
) -> tuple[NDArrayF64, NDArrayF64, NDArrayU8]:
502503
"""Project pointcloud on image plane.
503504
@@ -506,9 +507,10 @@ def _project_pointcloud(
506507
camera_sample_data_token (str): Sample data token of camera.
507508
min_dist (float, optional): Distance from the camera below which points are discarded.
508509
ignore_distortion (bool, optional): Whether to ignore distortion parameters.
510+
color_mode (PointCloudColorMode, optional): Color mode for pointcloud.
509511
510512
Returns:
511-
Projected points [2, n], their normalized depths [n] and an image.
513+
Projected points [2, n], their normalized features [n] and an image.
512514
"""
513515
point_sample_data: SampleData = self._t4.get("sample_data", point_sample_data_token)
514516
pc_filepath = osp.join(self._t4.data_root, point_sample_data.filename)
@@ -549,8 +551,6 @@ def _project_pointcloud(
549551
pointcloud.translate(-camera_cs_record.translation)
550552
pointcloud.rotate(camera_cs_record.rotation.rotation_matrix.T)
551553

552-
depths = pointcloud.points[2, :]
553-
554554
distortion = None if ignore_distortion else camera_cs_record.camera_distortion
555555

556556
points_on_img = view_points(
@@ -560,16 +560,24 @@ def _project_pointcloud(
560560
normalize=True,
561561
)[:2]
562562

563-
mask = np.ones(depths.shape[0], dtype=bool)
564-
mask = np.logical_and(mask, depths > min_dist)
563+
match color_mode:
564+
case PointCloudColorMode.DISTANCE:
565+
colors = normalize_color(pointcloud.points[2, :])
566+
case _:
567+
colors = normalize_color(pointcloud.points[3, :])
568+
depths = pointcloud.points[2, :]
569+
570+
mask = np.ones(colors.shape[0], dtype=bool)
571+
mask = np.logical_and(mask, depths > min_dist) # mask by depths
572+
# mask by size of points on image
565573
mask = np.logical_and(mask, 1 < points_on_img[0])
566574
mask = np.logical_and(mask, points_on_img[0] < img.size[0] - 1)
567575
mask = np.logical_and(mask, 1 < points_on_img[1])
568576
mask = np.logical_and(mask, points_on_img[1] < img.size[1] - 1)
569577
points_on_img = points_on_img[:, mask]
570-
depths = depths[mask]
578+
colors = colors[mask]
571579

572-
return points_on_img, depths, np.array(img, dtype=np.uint8)
580+
return points_on_img, colors, np.array(img, dtype=np.uint8)
573581

574582
def _render_annotation3ds(
575583
self,

t4_devkit/viewer/color.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
from t4_devkit.typing import ArrayLike, NDArrayF64
1212

1313

14+
__all__ = ["PointCloudColorMode", "pointcloud_color", "normalize_color"]
15+
16+
1417
@unique
1518
class PointCloudColorMode(str, Enum):
1619
"""Color mode of point cloud."""
@@ -35,25 +38,22 @@ def pointcloud_color(
3538
case _:
3639
values = pointcloud.points[3]
3740

38-
return distance_color(values)
41+
return normalize_color(values)
3942

4043

41-
def distance_color(
42-
distances: ArrayLike,
43-
cmap: str | None = None,
44-
) -> tuple[float, float, float] | NDArrayF64:
45-
"""Return color map depending on distance values.
44+
def normalize_color(values: ArrayLike, cmap: str | None = None, alpha: float = 1.0) -> NDArrayF64:
45+
"""Return color map normalizing values.
4646
4747
Args:
48-
distances (ArrayLike): Array of distances in the shape of (N,).
48+
values (ArrayLike): Array of values in the shape of (N,).
4949
cmap (str | None, optional): Color map name in matplotlib. If None, `turbo_r` will be used.
50+
alpha (float, optional): Alpha value of color map.
5051
5152
Returns:
52-
Color map in the shape of (N,). If input type is any number, returns a color as
53-
`tuple[float, float, float]`. Otherwise, returns colors as `NDArrayF64`.
53+
Color map in the shape of (N,).
5454
"""
5555
color_map = matplotlib.colormaps["turbo_r"] if cmap is None else matplotlib.colormaps[cmap]
56-
v_min = np.min(distances)
57-
v_max = np.max(distances)
56+
v_min = np.min(values)
57+
v_max = np.max(values)
5858
norm = matplotlib.colors.Normalize(v_min, v_max)
59-
return color_map(norm(distances))
59+
return color_map(norm(values), alpha=alpha)

0 commit comments

Comments
 (0)