"""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. """ import argparse import os from dora import Node from opencv_plot import bbox, decode from opencv_plot.plot import Plot def main() -> None: """Connect to the dataflow and display every frame that arrives.""" args = _parse_args() plot = Plot( width=_size("PLOT_WIDTH", args.plot_width), height=_size("PLOT_HEIGHT", args.plot_height), headless=os.getenv("CI") == "true", ) # Passing the name lets the node also run standalone as a dynamic node; when # dora spawns it, the id from the dataflow wins. node = Node(args.name) for event in node: if event["type"] == "ERROR": raise RuntimeError(event["error"]) if event["type"] != "INPUT": continue 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 plot.show(frame): break elif event_id == "bbox": plot.bboxes = bbox.parse(event["value"], metadata.get("format", "xyxy").lower()) elif event_id == "text": plot.text = event["value"][0].as_py() else: print(f"ignoring unexpected input `{event_id}`") def _parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( description="OpenCV plotter: draws text and bounding boxes on an image.", ) parser.add_argument( "--name", default="opencv-plot", help="The name of the node in the dataflow, used when running as a dynamic node.", ) parser.add_argument( "--plot-width", type=int, help="Resize the displayed frame to this width. Overridden by PLOT_WIDTH.", ) parser.add_argument( "--plot-height", type=int, help="Resize the displayed frame to this height. Overridden by PLOT_HEIGHT.", ) return parser.parse_args() def _size(name: str, fallback: int | None) -> int | None: value = os.getenv(name) return int(value) if value and value.isnumeric() else fallback if __name__ == "__main__": main()