chore(foxglove depth): make it simple, and make it work.

This commit is contained in:
CarolinePascal
2026-07-01 17:07:17 +02:00
parent 0cdb15110f
commit 8fd736575e
+12 -47
View File
@@ -186,28 +186,20 @@ def _log_foxglove_image(
) -> None:
"""Log an image on a cached per-topic channel.
Encoding is chosen from the frame's channel count and dtype:
- Single channel => depth map, logged uncompressed as ``16UC1`` (integer) or ``32FC1`` (float).
Plain ``uint8`` grayscale (with no ``depth_range``) is the exception and is sent as ``mono8``.
- Three channels => ``rgb8``.
- Four channels => ``rgba8``.
When ``compress_images`` is set, ``mono8`` and ``rgb8`` frames are JPEG-encoded instead; depth
and ``rgba8`` frames are always sent raw.
Frames are cast to ``uint8`` and the encoding is chosen from the channel count: 1 => ``mono8``,
3 => ``rgb8`` (float input assumed in [0, 1]), 4 => ``rgba8``; other counts are skipped with a
warning. When ``compress_images`` is set, ``mono8`` and ``rgb8`` are JPEG-encoded instead.
Args:
topic: Foxglove topic to log on.
frame_id: Frame id stamped on the message.
arr: Image as HWC or CHW (CHW is transposed to HWC), any dtype. Non-depth floating-point
images are assumed normalized to [0, 1] and scaled to uint8.
compress_images: JPEG-encode ``mono8`` and ``rgb8`` frames; ignored for depth and ``rgba8``.
arr: Image as HWC or CHW (CHW is transposed to HWC), any dtype.
compress_images: JPEG-encode ``mono8`` and ``rgb8`` frames; ignored for ``rgba8``.
channels: Per-topic channel cache to reuse (see :func:`_log_foxglove_scalars`).
log_time: Message time in nanoseconds, also written to the header timestamp; when ``None``
the server's receive time is used.
depth_range: ``(lo, hi)`` bounds that normalize depth to ``[0, 1]`` ``32FC1`` so Foxglove's
default panel scaling matches rerun's ``depth_range`` contrast (a ``RawImage`` carries
no value range itself).
depth_range: ``(lo, hi)`` bounds used to clip a single-channel frame before it is encoded as
a regular image.
"""
from foxglove.channels import CompressedImageChannel, RawImageChannel
@@ -225,39 +217,12 @@ def _log_foxglove_image(
height, width = arr.shape[0], arr.shape[1]
n_channels = 1 if arr.ndim == 2 else arr.shape[2]
# Single-channel => depth, unless it's plain uint8 grayscale (kept as mono8 below). Foxglove
# renders both 16UC1 (uint16) and 32FC1 (float32) depth with a colormap.
if n_channels == 1 and (depth_range is not None or arr.dtype != np.uint8):
depth = arr if arr.ndim == 2 else arr[..., 0]
if depth_range is not None:
lo, hi = depth_range
depth = depth.astype(np.float32)
depth = np.clip((depth - lo) / (hi - lo), 0.0, 1.0) if hi > lo else np.zeros_like(depth)
encoding, step = "32FC1", width * 4
elif np.issubdtype(depth.dtype, np.floating):
encoding, step = "32FC1", width * 4
else:
depth = np.clip(np.rint(depth), 0, 65535).astype("<u2")
encoding, step = "16UC1", width * 2
depth = np.ascontiguousarray(depth, dtype="<f4" if encoding == "32FC1" else "<u2")
channel = channels.get(topic)
if channel is None:
channel = channels[topic] = RawImageChannel(topic=topic)
channel.log(
RawImage(
timestamp=timestamp,
frame_id=frame_id,
width=width,
height=height,
encoding=encoding,
step=step,
data=depth.tobytes(),
),
**log_kwargs,
)
return
# Apply depth range clipping to single channel depth maps.
if depth_range is not None and n_channels == 1:
lo, hi = depth_range
arr = arr.clip(lo, hi)
if np.issubdtype(arr.dtype, np.floating):
if n_channels == 3 and np.issubdtype(arr.dtype, np.floating):
arr = (arr * 255.0).clip(0, 255)
arr = np.ascontiguousarray(arr, dtype=np.uint8)