edgefirst-image
High-performance image processing for edge AI inference pipelines.
This crate provides hardware-accelerated image loading, format conversion, resizing, rotation, and cropping operations optimized for ML preprocessing workflows.
Features
- Multiple backends — Automatic selection: G2D (if format supported) → CPU (same-size simple copies) → OpenGL (GPU) → CPU (general fallback)
- Format conversion - RGBA, RGB, NV12, NV16, YUYV, GREY, planar formats
- Geometric transforms - Resize, rotate (90° increments), flip, crop
- Zero-copy integration - Works with
edgefirst-tensorDMA/SHM buffers - JPEG/PNG support - Load and save with EXIF orientation handling
Quick Start
use ;
use ;
// Load an image
let bytes = read?;
let src = load_image?;
// Create processor (auto-selects best backend)
let mut processor = new?;
// Create destination with desired size
let mut dst = processor.create_image?;
// Convert with resize, rotation, letterboxing
processor.convert?;
// Save result
save_jpeg?;
Backends
| Backend | Platform | Hardware | Notes |
|---|---|---|---|
| G2D | Linux (i.MX8) | 2D GPU | Fastest for NXP platforms |
| OpenGL | Linux | GPU | EGL/GBM headless rendering |
| CPU | All | SIMD | Portable fallback |
Supported Formats
| Format | Description | Channels |
|---|---|---|
PixelFormat::Rgba |
32-bit RGBA | 4 |
PixelFormat::Rgb |
24-bit RGB | 3 |
PixelFormat::Nv12 |
YUV 4:2:0 semi-planar | 1.5 |
PixelFormat::Nv16 |
YUV 4:2:2 semi-planar | 2 |
PixelFormat::Yuyv |
YUV 4:2:2 packed | 2 |
PixelFormat::Grey |
8-bit grayscale | 1 |
PixelFormat::PlanarRgb |
Planar RGB | 3 |
PixelFormat::Vyuy |
YUV 4:2:2 packed (VYUY order) | 2 |
PixelFormat::Bgra |
32-bit BGRA | 4 |
PixelFormat::PlanarRgba |
Planar RGBA | 4 |
Note: Int8 variants (e.g. packed RGB int8, planar RGB int8) use DType::I8 with the corresponding PixelFormat rather than separate format constants.
Feature Flags
opengl(default) - Enable OpenGL backend on Linuxdecoder(default) - Enable detection box rendering
Environment Variables
EDGEFIRST_DISABLE_G2D- Disable G2D backendEDGEFIRST_DISABLE_GL- Disable OpenGL backendEDGEFIRST_DISABLE_CPU- Disable CPU backendEDGEFIRST_FORCE_BACKEND— Force a single backend:cpu,g2d, oropengl. Disables fallback chain.EDGEFIRST_FORCE_TRANSFER— Force GPU transfer method:pboordmabufEDGEFIRST_TENSOR_FORCE_MEM— Set to1to force heap memory (disables DMA/SHM)
Segmentation Mask Rendering
Three rendering pipelines for YOLO instance segmentation masks:
Fused GPU Proto Path (draw_masks_proto)
Computes sigmoid(coefficients @ protos) per-pixel in a fragment shader — no intermediate mask materialization. Preferred for real-time overlay.
let = decoder.decode_quantized_proto?;
processor.draw_masks_proto?;
Hybrid CPU+GPU Path
CPU materializes binary masks (materialize_segmentations()), then OpenGL overlays them. Auto-selected when both CPU and GL backends are available.
Atlas Decode Path (decode_masks_atlas)
Renders all detection masks into a compact vertical strip atlas via GPU, reads back as uint8 arrays. Use when you need per-instance mask pixels for downstream processing.
let masks = processor.decode_masks_atlas?;
Shader Variants
| Variant | Proto Format | Interpolation |
|---|---|---|
| int8-nearest | R8I quantized | Nearest neighbor |
| int8-bilinear | R8I quantized | Manual 4-tap bilinear |
| f32 | R32F float | Hardware GL_LINEAR |
| f16 | R16F half | Hardware GL_LINEAR |
Int8 Interpolation Mode
Control quantized proto interpolation quality:
processor.set_int8_interpolation_mode;
See BENCHMARKS.md for per-platform performance numbers.
Zero-Copy Model Input
Use create_image() to allocate the destination tensor with the processor's
optimal memory backend (DMA-buf, PBO, or system memory). This enables
zero-copy GPU paths that direct Tensor::new() allocation cannot achieve:
let mut dst = processor.create_image?;
processor.convert?;
If you need to write into a pre-allocated buffer with a specific memory type (e.g. an NPU-bound tensor), you can still use direct allocation:
let mut model_input = new?;
model_input.set_format?;
let mut dst = from;
processor.convert?;
Multiplane NV12/NV16
For V4L2 multi-planar DMA-BUF buffers (separate Y and UV file descriptors):
let img = from_planes?;
let src = from;
processor.convert?;
The OpenGL backend imports each plane's DMA-BUF fd separately for zero-copy GPU access.
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.