Color Conversion API

Color-space conversions between NV12 and packed RGB/BGR.

Camera streams arrive as NV12 (semi-planar YUV 4:2:0, limited range); models and drawing want packed RGB/BGR. Frame.to_rgb() already covers NV12→RGB in numpy — the reverse direction and the plane-level utilities were missing, so apps kept re-implementing them (parking-lot carries its own trio of converters, parking_lot/app.py:312-358).

cv2 accelerates every conversion when installed; otherwise a vectorised numpy path is used (BT.601 limited range, matching cv2’s COLOR_YUV2BGR_NV12 semantics). The numpy chroma path is nearest-neighbour on decode / 2×2 block mean on encode, so round-trips lose a little chroma detail — fine for model input, not for pixel-exact comparisons.

from neoruntime_ipc_sdk.color import rgb_to_nv12, nv12_resize

nv12 = rgb_to_nv12(rgb)                      # (h*3/2, w) uint8
small = nv12_resize(nv12, (1920, 1080), (640, 384))
neoruntime_ipc_sdk.color.bgr_to_nv12(bgr)[source]

Convert a BGR (h, w, 3) array to an NV12 (h*3/2, w) buffer.

neoruntime_ipc_sdk.color.nv12_resize(nv12, src_size, dst_size)[source]

Resize an NV12 buffer from src_size to dst_size (width, height).

Resizes the Y and UV planes separately — avoids the NV12→BGR→resize→BGR→NV12 round-trip (the approach proven in parking-lot). With cv2 the planes are resized with bilinear interpolation; the numpy fallback uses nearest-neighbour.

neoruntime_ipc_sdk.color.nv12_to_bgr(nv12, width, height)[source]

Convert an NV12 buffer to a BGR (height, width, 3) uint8 array.

neoruntime_ipc_sdk.color.nv12_to_rgb(nv12, width, height)[source]

Convert an NV12 buffer to an RGB (height, width, 3) uint8 array.

Hardware-first: rides the accel router (DSP convert when the daemon is reachable, _nv12_to_rgb_impl() otherwise).

neoruntime_ipc_sdk.color.rgb_to_nv12(rgb)[source]

Convert an RGB (h, w, 3) array to an NV12 (h*3/2, w) buffer.

Hardware-first: rides the accel router (DSP convert when the daemon is reachable, _rgb_to_nv12_impl() otherwise).

Functions

nv12_to_rgb / nv12_to_bgr

neoruntime_ipc_sdk.color.nv12_to_rgb(nv12, width, height)[source]

Convert an NV12 buffer to an RGB (height, width, 3) uint8 array.

Hardware-first: rides the accel router (DSP convert when the daemon is reachable, _nv12_to_rgb_impl() otherwise).

neoruntime_ipc_sdk.color.nv12_to_bgr(nv12, width, height)[source]

Convert an NV12 buffer to a BGR (height, width, 3) uint8 array.

rgb_to_nv12 / bgr_to_nv12

neoruntime_ipc_sdk.color.rgb_to_nv12(rgb)[source]

Convert an RGB (h, w, 3) array to an NV12 (h*3/2, w) buffer.

Hardware-first: rides the accel router (DSP convert when the daemon is reachable, _rgb_to_nv12_impl() otherwise).

neoruntime_ipc_sdk.color.bgr_to_nv12(bgr)[source]

Convert a BGR (h, w, 3) array to an NV12 (h*3/2, w) buffer.

nv12_resize

neoruntime_ipc_sdk.color.nv12_resize(nv12, src_size, dst_size)[source]

Resize an NV12 buffer from src_size to dst_size (width, height).

Resizes the Y and UV planes separately — avoids the NV12→BGR→resize→BGR→NV12 round-trip (the approach proven in parking-lot). With cv2 the planes are resized with bilinear interpolation; the numpy fallback uses nearest-neighbour.

Examples

Feed an NV12 model with an RGB frame

from neoruntime_ipc_sdk import rgb_to_nv12, nv12_resize

# Encode the annotated RGB frame and resize it as NV12 — no
# NV12->RGB->resize->RGB->NV12 round-trip anywhere
nv12 = rgb_to_nv12(rgb_frame)
small = nv12_resize(nv12, (1920, 1080), (640, 384))

Route through DSP hardware

# Prefers the DSP leg (see the Accel Routing API); falls back to the
# numpy/cv2 software implementation when the DSP is unreachable and
# records the degradation in health()
from neoruntime_ipc_sdk import get_default_router

router = get_default_router()
small = router.run("resize_nv12", nv12, (1920, 1080), (640, 384))