Files
dora-image-view/dora_plot/plot.py
T
cristhianandClaude Opus 5 e2debe0581 refactor: rename the node from opencv-plot to dora-plot
The repository is dora-plot, but the package, the entrypoint, the manifest
name and the window title were all opencv-plot. Consumers wire the node by
`path:`, so the split name was visible in every dataflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WLVZCFFcCH1EpTXGfS9aD
2026-09-14 16:08:48 -05:00

73 lines
2.0 KiB
Python

"""The display state: the frame, the overlays drawn on it, and the window."""
from dataclasses import dataclass, field
import cv2
import numpy as np
WINDOW = "Dora Node: dora-plot"
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
FONT = cv2.FONT_HERSHEY_SIMPLEX
FONT_SCALE = 0.5
@dataclass
class Bboxes:
"""One overlay's worth of boxes, always stored as xyxy corners."""
corners: np.ndarray = field(default_factory=lambda: np.empty((0, 4)))
conf: np.ndarray = field(default_factory=lambda: np.empty(0))
labels: np.ndarray = field(default_factory=lambda: np.empty(0, dtype=object))
@dataclass
class Plot:
"""Overlay state, plus the window it is displayed in.
`headless` suppresses the window; the node still decodes every input.
"""
width: int | None = None
height: int | None = None
headless: bool = False
bboxes: Bboxes = field(default_factory=Bboxes)
text: str = ""
def show(self, frame: np.ndarray) -> bool:
"""Draw the overlays on `frame`, resize it, and display it.
Returns whether the viewer asked to quit by pressing `q`.
"""
self._draw(frame)
if self.width and self.height:
frame = cv2.resize(frame, (self.width, self.height))
if self.headless:
return False
cv2.imshow(WINDOW, frame)
return cv2.waitKey(1) & 0xFF == ord("q")
def _draw(self, frame: np.ndarray) -> None:
for corners, conf, label in zip(
self.bboxes.corners,
self.bboxes.conf,
self.bboxes.labels,
strict=False,
):
min_x, min_y, max_x, max_y = (int(value) for value in corners)
cv2.rectangle(frame, (min_x, min_y), (max_x, max_y), GREEN, 2)
cv2.putText(
frame,
f"{label}, {conf:0.2f}",
(max_x - 120, max_y - 10),
FONT,
FONT_SCALE,
GREEN,
1,
)
cv2.putText(frame, self.text, (20, 20), FONT, FONT_SCALE, WHITE, 1)