pub trait ImageProcessorTrait {
// Required methods
fn convert(
&mut self,
src: &TensorDyn,
dst: &mut TensorDyn,
options: Option<ConvertOptions>,
) -> Result<()>;
fn draw_decoded_masks(
&mut self,
dst: &mut TensorDyn,
detect: &[DetectBox],
segmentation: &[Segmentation],
overlay: MaskOverlay<'_>,
) -> Result<()>;
fn draw_proto_masks(
&mut self,
dst: &mut TensorDyn,
detect: &[DetectBox],
proto_data: &ProtoData,
overlay: MaskOverlay<'_>,
) -> Result<()>;
fn set_class_colors(&mut self, colors: &[[u8; 4]]) -> Result<()>;
fn set_box_line_width(&mut self, width: u32) -> Result<()>;
// Provided methods
fn convert_deferred(
&mut self,
src: &TensorDyn,
dst: &mut TensorDyn,
options: Option<ConvertOptions>,
) -> Result<()> { ... }
fn flush(&mut self) -> Result<()> { ... }
}Required Methods§
Sourcefn convert(
&mut self,
src: &TensorDyn,
dst: &mut TensorDyn,
options: Option<ConvertOptions>,
) -> Result<()>
fn convert( &mut self, src: &TensorDyn, dst: &mut TensorDyn, options: Option<ConvertOptions>, ) -> Result<()>
Convert src into dst’s format and size, applying the crop first,
then the flip, then the rotation.
The destination is normally an RGB-family colour — Grey, Rgb,
Rgba/Bgra, packed HWC or planar CHW. That is what the
accelerated paths target and what models expect. The CPU backend also
accepts a handful of YUV destinations (Yuyv→Yuyv, Yuyv→Nv16,
and the Vyuy equivalents); no GPU or G2D path does, so those pairs
always land on the CPU.
§Arguments
src- The source image to convert from.dst- The destination image. Its shape andPixelFormatdefine the output; pass avieworbatchof a larger tensor to render into one tile of a batch.options- Rotation, flip, source crop, fit (stretch or letterbox), normalization and pad (ConvertOptions);Noneis the default convert. Destination placement lives ondst, not here.
§Errors
Error::CropInvalidif the source crop falls outsidesrc.Error::NotAnImageif either tensor carries noPixelFormat.Error::InvalidOptionsif the options cannot apply todst.Error::NoConverterif no backend accepts the format pair — the dispatch tries OpenGL, then G2D, then CPU, so this means all three declined.Error::TensorwithCpuAccessDeniedif a CPU pass needs access a tensor’s declaration does not cover (sourceRead; destinationWrite, orReadWritefor a view or a read-back pass).Error::CpuFallbackDeniedif GL or G2D declined the convert and the CPU fallback was refused for access.Error::cpu_access_deniedfinds the refusal in either form.
Backend-specific failures (EGL import, G2D blit, allocation) surface as
their own variants. A backend declining a pair is not an error while
another remains in the chain; it silently costs the zero-copy path, and
ImageProcessor::convert_fallback_count counts those.
Sourcefn draw_decoded_masks(
&mut self,
dst: &mut TensorDyn,
detect: &[DetectBox],
segmentation: &[Segmentation],
overlay: MaskOverlay<'_>,
) -> Result<()>
fn draw_decoded_masks( &mut self, dst: &mut TensorDyn, detect: &[DetectBox], segmentation: &[Segmentation], overlay: MaskOverlay<'_>, ) -> Result<()>
Draw pre-decoded detection boxes and segmentation masks onto dst.
Supports two segmentation modes based on the mask channel count:
- Instance segmentation (
C=1): oneSegmentationper detection,segmentationanddetectare zipped. - Semantic segmentation (
C>1): a singleSegmentationcovering all classes; only the first element is used.
§Format requirements
- CPU backend:
dstmust beRGBAorRGB. - OpenGL backend:
dstmust beRGBA,BGRA, orRGB. - G2D backend: only produces the base frame (empty detections);
returns
NotImplementedwhen any detection or segmentation is supplied.
§Output contract
This function always fully writes dst — it never relies on the
caller having pre-cleared the destination. The four cases are:
| detections | background | output |
|---|---|---|
| none | none | dst cleared to 0x00000000 |
| none | set | dst ← background |
| set | none | masks drawn over cleared dst |
| set | set | masks drawn over background |
Each backend implements this with its native primitives: G2D uses
g2d_clear / g2d_blit, OpenGL uses glClear / DMA-BUF GPU blit
plus the mask program, and CPU uses direct buffer fill / memcpy as
the terminal fallback. CPU-memcpy of DMA buffers is avoided on the
accelerated paths.
An empty segmentation slice is valid — only bounding boxes are drawn.
overlay controls compositing: background is the compositing source
(must match dst in size and format); opacity scales mask and box
alpha. Box outlines are set_box_line_width
pixels thick and use the set_class_colors
palette, alpha included.
A Bgra background onto a zero-copy destination (a D3D11 texture, an
IOSurface, a dma-buf) returns Error::NotSupported: the GL
base-layer draw has no Bgra arm and the CPU backend renders only
Rgba/Rgb. It previously returned Ok with dst unwritten. A
Bgra destination with no background is unaffected.
§Buffer aliasing
dst and overlay.background must reference distinct underlying
buffers. An aliased pair returns Error::AliasedBuffers without
dispatching to any backend — the GL path would otherwise read and
write the same texture in a single draw, which is undefined behaviour
on most drivers. Aliasing is detected via
TensorDyn::aliases, which
catches both shared-allocation clones and separate imports over the
same dmabuf fd.
§Migration from v0.16.3 and earlier
Prior to v0.16.4 the call silently preserved dst’s contents on empty
detections. That invariant no longer holds — dst is always fully
written. Callers who pre-loaded an image into dst before calling this
function must now pass that image via overlay.background instead.
Sourcefn draw_proto_masks(
&mut self,
dst: &mut TensorDyn,
detect: &[DetectBox],
proto_data: &ProtoData,
overlay: MaskOverlay<'_>,
) -> Result<()>
fn draw_proto_masks( &mut self, dst: &mut TensorDyn, detect: &[DetectBox], proto_data: &ProtoData, overlay: MaskOverlay<'_>, ) -> Result<()>
Draw masks from proto data onto image (fused decode+draw).
For YOLO segmentation models, this avoids materializing intermediate
Array3<u8> masks. The ProtoData contains mask coefficients and the
prototype tensor; the renderer computes mask_coeff @ protos directly
at the output resolution using bilinear sampling.
detect and proto_data.mask_coefficients must have the same length
(enforced by zip — excess entries are silently ignored). An empty
detect slice is valid and produces the base frame — cleared or
background-blitted — via the selected backend’s native primitive.
§Format requirements and output contract
Same as draw_decoded_masks, including
the “always fully writes dst” guarantee across all four
detection/background combinations.
overlay controls compositing — see draw_decoded_masks.
Sourcefn set_class_colors(&mut self, colors: &[[u8; 4]]) -> Result<()>
fn set_class_colors(&mut self, colors: &[[u8; 4]]) -> Result<()>
Sets the RGBA colors used for rendering segmentation masks and bounding boxes. Up to 20 colors can be set; entries past the slice keep their previous value.
The alpha channel is the coverage of both masks and box outlines:
each is blended over the destination with alpha / 255 scaled by
MaskOverlay::opacity, so 255 draws opaque boxes and lower
values draw translucent ones. The destination’s own alpha channel is
left as the base layer set it. The default palette’s alpha is 0.7.
On ImageProcessor with no forced backend this reaches every
available backend rather than the first that accepts, because a
later draw may land on any of them. A forced backend receives the
colors alone.
Sourcefn set_box_line_width(&mut self, width: u32) -> Result<()>
fn set_box_line_width(&mut self, width: u32) -> Result<()>
Sets the thickness, in destination pixels, of the bounding-box
outlines drawn by draw_decoded_masks
and draw_proto_masks. The default is
DEFAULT_BOX_LINE_WIDTH (3 px).
The outline is drawn outside the box edges, so the box interior is never covered. It is clipped at the image border.
Reaches every available backend, as
set_class_colors does.
§Errors
Error::InvalidOptions when width is 0, and
Error::NotImplemented from a backend that does not draw (G2D).
Provided Methods§
Sourcefn convert_deferred(
&mut self,
src: &TensorDyn,
dst: &mut TensorDyn,
options: Option<ConvertOptions>,
) -> Result<()>
fn convert_deferred( &mut self, src: &TensorDyn, dst: &mut TensorDyn, options: Option<ConvertOptions>, ) -> Result<()>
Like convert, but does not wait for the GPU to finish.
This is the batch-preprocessing primitive: a caller renders N tiles
into one batched destination by looping
convert_deferred(&src[n], &mut dst.batch(n)?, …) and then calling
flush once. On the OpenGL backend every deferred
convert into sibling views of one buffer shares a single EGLImage import
(the tile is a glViewport/glScissor ROI into the parent) and skips the
per-tile glFinish; flush then issues a single GPU sync. The result of
a deferred convert is not safe to read on the CPU (or map via CUDA)
until flush returns.
The default implementation is eager — it simply calls
convert, so CPU/G2D and any backend without a deferred
fast path remain correct (each call completes synchronously and flush
is a no-op).
Sourcefn flush(&mut self) -> Result<()>
fn flush(&mut self) -> Result<()>
Complete all work enqueued by convert_deferred
since the last flush, issuing a single GPU synchronization.
After this returns, every deferred destination is finished and safe to
read back or cuda_map. Backends with no deferred path (the default)
return Ok(()) immediately, since their converts already completed.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".