Files
cesar 43cb1ff01c
validate / validate (push) Successful in 58m52s
validate / test (push) Failing after 58m59s
validate / validate (pull_request) Successful in 58m50s
validate / test (pull_request) Failing after 58m53s
add opencv-plot node for dora dataflows
A display sink that overlays bounding boxes and text on an image input and
shows it in an OpenCV window. Based on opencv-plot from dora-hub, brought up
to the dora 1.0 node contract and packaged with uv.

Python rather than Rust: the opencv Rust crate generates its bindings from the
OpenCV headers on the build machine, so it needs libopencv-dev and libclang-dev
per machine and per architecture and does not cross-compile. Every dependency
here ships prebuilt wheels for linux-x86_64, linux-aarch64 and macos-arm64.

Covers every encoding the upstream node did — bgr8, rgb8, jpeg/jpg/jpe/bmp/
webp/png, yuv420 and avif — plus both bbox formats, the text overlay,
PLOT_WIDTH/PLOT_HEIGHT and headless operation under CI=true.
2026-09-10 18:55:28 -03:00

38 lines
1.2 KiB
Python

"""Parsing of the `bbox` input: an Arrow struct carrying boxes and labels."""
import numpy as np
from opencv_plot.plot import Bboxes
def parse(value, bbox_format: str) -> Bboxes:
"""Read a `bbox` payload. `bbox_format` is the `format` metadata parameter."""
fields = value[0]
corners = _flat(fields, "bbox").reshape(-1, 4)
if bbox_format == "xyxy":
pass
elif bbox_format == "xywh":
# xywh is centre-based: x and y are the box centre, not a corner.
x, y, w, h = corners.T
corners = np.stack([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=1)
else:
raise RuntimeError(f"unsupported bbox format: {bbox_format}")
return Bboxes(
corners=corners,
conf=_flat(fields, "conf"),
labels=_flat(fields, "labels", numeric=False),
)
def _flat(fields, name: str, numeric: bool = True) -> np.ndarray:
"""Read a struct field as a flat numpy array.
Senders wrap each field in a single-element list -- that is what
`pa.array([{...}])` produces from numpy arrays -- so unwrap it when present.
"""
column = fields[name]
column = getattr(column, "values", column)
return column.to_numpy(zero_copy_only=False) if not numeric else column.to_numpy()