add a depth map panel
The node showed a colour image only, so debugging a depth pipeline meant either trusting the numbers or writing a throwaway viewer. It now keeps one panel per frame stream -- image and depth -- and tiles them side by side, scaled to a common height. Wiring one is a plain viewer; wiring both shows them together. bbox and text stay overlays rather than panels. The contract follows what dora-zed already publishes: float32 [H, W] in millimetres with 0 for missing. It is sent there as a raw byte slice, so the payload arrives as UInt8 despite the Float32 contract and is reinterpreted rather than converted. Auto-ranging the colormap over the valid pixels' full extent, rather than over a percentile of them, is deliberate and was not the first attempt: trimming the tails collapsed on the scene the node exists for. A small object in front of a large wall is a few percent of the pixels, so both tails landed on the wall and the object clipped away. Rendering a frame and looking at it found that; every test passed either way. Verified with dora-cli 1.0.1: validate passes with both contracts injected, the dataflow runs both nodes to a clean exit, and a composed frame was rendered and inspected.
This commit is contained in:
+31
-12
@@ -1,15 +1,16 @@
|
||||
"""A dora display sink: overlays bounding boxes and text on an image input.
|
||||
|
||||
An `image` event decodes the frame and immediately redraws. `bbox` and `text`
|
||||
events only update stored state, which the next `image` event draws.
|
||||
`image` and `depth` each fill one panel of the window and redraw. `bbox` and
|
||||
`text` events only update stored state, which the next redraw draws.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
from dora import Node
|
||||
|
||||
from dora_image_view import bbox, decode
|
||||
from dora_image_view import bbox, decode, depth
|
||||
from dora_image_view.view import View
|
||||
|
||||
|
||||
@@ -36,14 +37,12 @@ def main() -> None:
|
||||
event_id = event["id"]
|
||||
metadata = event["metadata"]
|
||||
|
||||
if event_id == "image":
|
||||
frame = decode.to_bgr(
|
||||
event["value"],
|
||||
metadata.get("encoding", "bgr8").lower(),
|
||||
metadata.get("width"),
|
||||
metadata.get("height"),
|
||||
)
|
||||
if view.show(frame):
|
||||
panel = _decode_panel(event_id, event["value"], metadata)
|
||||
|
||||
if panel is not None:
|
||||
name, frame = panel
|
||||
view.panels[name] = frame
|
||||
if view.show():
|
||||
break
|
||||
elif event_id == "bbox":
|
||||
view.bboxes = bbox.parse(event["value"], metadata.get("format", "xyxy").lower())
|
||||
@@ -53,9 +52,29 @@ def main() -> None:
|
||||
print(f"ignoring unexpected input `{event_id}`")
|
||||
|
||||
|
||||
def _decode_panel(event_id: str, value, metadata: dict) -> tuple[str, np.ndarray] | None:
|
||||
"""Decode a frame-bearing input into the panel name and frame it fills.
|
||||
|
||||
Returns None for an input that carries no frame, which is what tells the
|
||||
event loop to treat it as overlay state instead.
|
||||
"""
|
||||
if event_id == "image":
|
||||
return "image", decode.to_bgr(
|
||||
value,
|
||||
metadata.get("encoding", "bgr8").lower(),
|
||||
metadata.get("width"),
|
||||
metadata.get("height"),
|
||||
)
|
||||
|
||||
if event_id == "depth":
|
||||
return "depth", depth.colorize(depth.to_millimetres(value, metadata))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="OpenCV plotter: draws text and bounding boxes on an image.",
|
||||
description="OpenCV viewer: image and depth, with bbox and text overlays.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
|
||||
Reference in New Issue
Block a user