Detection Drawing API
Drawing utilities - annotate RGB numpy arrays with detection boxes and text.
All functions take an RGB uint8 array (H, W, 3) and return a NEW array; the input is never modified. cv2 accelerates rendering when installed, otherwise Pillow (a hard SDK dependency) is used.
render_overlay_rgba is the hardware companion: it renders the same annotation as a minimal straight-alpha RGBA canvas (plus its frame offset) for DspClient.blend_hw instead of rasterizing onto the pixels.
Example
frame = client.get_frame(“main”) # Frame rgb = draw_detections(frame.to_rgb(), result)
- neoruntime_ipc_sdk.draw.draw_boxes(image, boxes, labels=None, scores=None, color=(0, 255, 0), thickness=2)[source]
Draw bounding boxes (pixel coordinates) on an RGB array copy.
- Parameters:
image (ndarray) – RGB uint8 array (H, W, 3).
boxes (Iterable) – iterable of (x1, y1, x2, y2) or BoundingBox-like objects.
labels (Sequence[str | None] | None) – optional per-box text (combined with scores when given).
scores (Sequence[float] | None) – optional per-box confidence.
thickness (int) – line thickness in pixels.
Returns: new RGB array; the input array is not modified.
- neoruntime_ipc_sdk.draw.draw_text(image, text, xy, color=(255, 255, 255), font_scale=0.5, thickness=1)[source]
Draw a text string at pixel position xy on an RGB array copy.
- neoruntime_ipc_sdk.draw.draw_detections(image, result_or_objects, color=None)[source]
Draw an InferenceResult (or a list of DetectedObject) on an RGB copy.
Each object gets a box plus a “label score” caption. When color is None, a per-class color from PALETTE is chosen via class_id.
Routing: NV12 2D arrays ride the accel router (DSP blend when the daemon is reachable, the CPU mirror otherwise); RGB arrays go straight to the software raster (no doomed hardware attempt, no fake degradation row); keep-fd frames raise — the zero-copy blend chain that would serve them is gated (state-dependent field wedge).
- neoruntime_ipc_sdk.draw.render_overlay_rgba(frame_w, frame_h, boxes=(), labels=None, scores=None, colors=None, thickness=2, polygons=(), tracks=())[source]
Render boxes + captions + polygons + tracks as a minimal straight-alpha RGBA overlay.
Returns
(rgba, x0, y0): an(h, w, 4)uint8 canvas holding every shape and its top-left position on the frame. Hand it toDspClient.blend_hw()for the hardware composite — the canvas is the union bbox of all shapes (clamped to the frame, floored at 16x16), so untouched pixels never enter the blend and the quota footprint stays small.polygonsis a sequence of(points, color)pairs drawn as closed outlines (zone shapes);tracksthe same shape drawn open (trajectories).pointsis any (N, 2) sequence of frame pixel coordinates;color=Nonefalls back to green like boxes.Straight alpha by construction: each shape is first drawn white-on-black as a coverage mask (cv2 LINE_AA captions give edge coverage t; rectangles stay hard-edged like
draw_boxes()), then shapes are colored in draw order and alpha is the mask union — so compositing witht*C + (1-t)*basereproduces the software output. Colors default to green; pick fromPALETTEby class_id to matchdraw_detections().
- neoruntime_ipc_sdk.draw.draw_polygons(image, shapes, thickness=2, closed=True)[source]
Draw polygon outlines (or open tracks) on an RGB array copy.
The software counterpart of
render_overlay_rgba()’s polygons/tracks legs, mirroringdraw_boxes()’ copy-in copy-out conventions — reach for it when the frame stays client-side and no blend is needed.- Parameters:
image (ndarray) – RGB uint8 array (H, W, 3).
shapes (Iterable) – iterable of
(points, color)pairs,pointsbeing any (N, 2) sequence of pixel coordinates (same schema asrender_overlay_rgba());color=Nonemeans green.thickness (int) – line thickness in pixels.
closed (bool) – close each outline (True for zones, False for tracks).
Returns: new RGB array; the input array is not modified.
draw_boxes
- neoruntime_ipc_sdk.draw_boxes(image, boxes, labels=None, scores=None, color=(0, 255, 0), thickness=2)[source]
Draw bounding boxes (pixel coordinates) on an RGB array copy.
- Parameters:
image (ndarray) – RGB uint8 array (H, W, 3).
boxes (Iterable) – iterable of (x1, y1, x2, y2) or BoundingBox-like objects.
labels (Sequence[str | None] | None) – optional per-box text (combined with scores when given).
scores (Sequence[float] | None) – optional per-box confidence.
thickness (int) – line thickness in pixels.
Returns: new RGB array; the input array is not modified.
draw_text
draw_detections
- neoruntime_ipc_sdk.draw_detections(image, result_or_objects, color=None)[source]
Draw an InferenceResult (or a list of DetectedObject) on an RGB copy.
Each object gets a box plus a “label score” caption. When color is None, a per-class color from PALETTE is chosen via class_id.
Routing: NV12 2D arrays ride the accel router (DSP blend when the daemon is reachable, the CPU mirror otherwise); RGB arrays go straight to the software raster (no doomed hardware attempt, no fake degradation row); keep-fd frames raise — the zero-copy blend chain that would serve them is gated (state-dependent field wedge).
draw_polygons
- neoruntime_ipc_sdk.draw_polygons(image, shapes, thickness=2, closed=True)[source]
Draw polygon outlines (or open tracks) on an RGB array copy.
The software counterpart of
render_overlay_rgba()’s polygons/tracks legs, mirroringdraw_boxes()’ copy-in copy-out conventions — reach for it when the frame stays client-side and no blend is needed.- Parameters:
image (ndarray) – RGB uint8 array (H, W, 3).
shapes (Iterable) – iterable of
(points, color)pairs,pointsbeing any (N, 2) sequence of pixel coordinates (same schema asrender_overlay_rgba());color=Nonemeans green.thickness (int) – line thickness in pixels.
closed (bool) – close each outline (True for zones, False for tracks).
Returns: new RGB array; the input array is not modified.
render_overlay_rgba
- neoruntime_ipc_sdk.render_overlay_rgba(frame_w, frame_h, boxes=(), labels=None, scores=None, colors=None, thickness=2, polygons=(), tracks=())[source]
Render boxes + captions + polygons + tracks as a minimal straight-alpha RGBA overlay.
Returns
(rgba, x0, y0): an(h, w, 4)uint8 canvas holding every shape and its top-left position on the frame. Hand it toDspClient.blend_hw()for the hardware composite — the canvas is the union bbox of all shapes (clamped to the frame, floored at 16x16), so untouched pixels never enter the blend and the quota footprint stays small.polygonsis a sequence of(points, color)pairs drawn as closed outlines (zone shapes);tracksthe same shape drawn open (trajectories).pointsis any (N, 2) sequence of frame pixel coordinates;color=Nonefalls back to green like boxes.Straight alpha by construction: each shape is first drawn white-on-black as a coverage mask (cv2 LINE_AA captions give edge coverage t; rectangles stay hard-edged like
draw_boxes()), then shapes are colored in draw order and alpha is the mask union — so compositing witht*C + (1-t)*basereproduces the software output. Colors default to green; pick fromPALETTEby class_id to matchdraw_detections().
Usage Examples
Draw boxes and labels
from neoruntime_ipc_sdk import draw_boxes
# boxes are pixel coordinates (x1, y1, x2, y2); labels/scores align
# with boxes one-to-one
annotated = draw_boxes(
image,
boxes=[(120, 80, 360, 300), (400, 200, 620, 460)],
labels=["car", "person"],
scores=[0.92, 0.87],
color=(0, 255, 0),
thickness=2,
)
Draw arbitrary text
from neoruntime_ipc_sdk import draw_text
annotated = draw_text(
image, "FPS: 15.2", (12, 24),
color=(255, 255, 255), font_scale=0.5, thickness=1,
)
Render inference results directly
from neoruntime_ipc_sdk import InferenceClient, draw_detections
infer = InferenceClient()
result = infer.infer("yolov5m_vehicles", frame)
rgb = frame.to_rgb() # materialize the Frame (keep-fd frames cannot draw)
# Accepts an InferenceResult or list[DetectedObject]; draws boxes +
# labels + confidence automatically. Since SDK 0.7.4 an NV12 2D array
# itself rides the DSP blend route; RGB arrays take the software raster
annotated = draw_detections(rgb, result)
Polygons and tracks (zones / trajectory overlays, dsp-offload P2)
from neoruntime_ipc_sdk import draw_polygons, render_overlay_rgba
# shapes = [(points, color)]; points is an (N, 2) pixel coordinate
# sequence, color=None means the default green. closed=False draws
# open polylines (trajectories).
zone = [(80, 60), (560, 60), (560, 380), (80, 380)]
track = [(100, 240), (200, 200), (320, 210), (430, 260)]
annotated = draw_polygons(image, [(zone, (255, 192, 0)),
(track, (0, 200, 255))], closed=True)
# tracks alone: draw_polygons(image, [(track, (0, 200, 255))], closed=False)
# Hardware leg: the same shapes feed render_overlay_rgba's
# polygons/tracks, join the boxes in the minimal canvas union, and
# composite in one blend_hw call
rgba, x0, y0 = render_overlay_rgba(
w, h, boxes, labels, scores, colors,
polygons=[(zone, (255, 192, 0))],
tracks=[(track, (0, 200, 255))],
)
annotated = dsp.blend_hw(nv12, [(rgba, x0, y0)])
Note
draw_* functions return a copy and never modify the input
image; inputs/outputs are RGB pixel coordinates (matching
to_array output).