Skip to main content

Train models for native camera formats supported by edge platforms

Project description

EdgeFirst CameraAdaptor

Train deep learning models that consume camera formats natively supported by target edge platforms, avoiding costly runtime conversions.

Why CameraAdaptor?

When deploying computer vision models to edge devices, there's often a mismatch between:

  1. Training data format: RGB images from standard datasets (ImageNet, COCO, etc.)
  2. Inference input format: Native camera/hardware formats (YUV, Bayer, BGR, RGBA)

Traditional approach: Convert camera output → RGB → Model inference

Problem: This conversion requires hardware (ISP, GPU, 2D accelerator) and adds latency.

Solution: Train the model to expect the native camera format directly.

How It Works

┌─────────────────────────────────────────────────────────────────┐
│                        TRAINING TIME                            │
├─────────────────────────────────────────────────────────────────┤
│  RGB Dataset ─── CameraAdaptorTransform ──→ Target Format       │
│                        (e.g., YUYV, BGR)                        │
│                              ↓                                  │
│                    Model with CameraAdaptor                     │
│                    as first layer                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                        INFERENCE TIME                           │
├─────────────────────────────────────────────────────────────────┤
│  Camera/Hardware ────────────────────────→ Model (native format)│
│                    No conversion needed!                        │
└─────────────────────────────────────────────────────────────────┘

Key Components

Component Purpose
CameraAdaptorTransform Preprocessing: Convert RGB training data to target format
CameraAdaptor (PyTorch) Model layer: Handle format-specific input processing
CameraAdaptor (TensorFlow) Model layer: Handle format-specific input processing
CameraAdaptorConfig Configuration and metadata for model export

Important Design Note

The CameraAdaptor layer does NOT perform color space conversion. Color conversion is handled by CameraAdaptorTransform during training data loading:

  • Training: CameraAdaptorTransform converts RGB images → target format (e.g., YUYV, BGR)
  • Inference: Camera/ISP provides data directly in target format → no conversion needed

The CameraAdaptor layer only performs:

  1. Layout permutation (NHWC ↔ NCHW) when channels_last/channels_first is enabled
  2. Alpha channel dropping for RGBA/BGRA inputs

EdgeFirst Ecosystem

EdgeFirst CameraAdaptor is part of the EdgeFirst AI ecosystem:

  • EdgeFirst HAL: Runtime library with optimized pre-processing pipelines for edge deployment. Use HAL for on-target inference and benchmarking of models trained with CameraAdaptor.
  • EdgeFirst CameraAdaptor: Training library (this project) for creating models that accept native camera formats.

On-target benchmarks use edgefirst-hal to benchmark pre-processing pipelines with various CameraAdaptor configurations.

Installation

# Core library (numpy only)
pip install edgefirst-cameraadaptor

# With preprocessing support (OpenCV)
pip install edgefirst-cameraadaptor[transform]

# With PyTorch support
pip install edgefirst-cameraadaptor[torch]

# With TensorFlow support
pip install edgefirst-cameraadaptor[tensorflow]

# With PyTorch Lightning support
pip install edgefirst-cameraadaptor[lightning]

# Everything
pip install edgefirst-cameraadaptor[all]

Quick Start

Preprocessing Transform

Convert training images to your target camera format:

from edgefirst.cameraadaptor import CameraAdaptorTransform

# Create transform for BGR format (RGB source by default)
transform = CameraAdaptorTransform("bgr")
bgr_frame = transform(rgb_frame)

# If using OpenCV's default BGR loading
transform = CameraAdaptorTransform("yuyv", source_format="bgr")
yuyv_frame = transform(bgr_frame)  # cv2.imread() returns BGR

PyTorch Model

Add the adaptor as the first layer of your model:

from edgefirst.cameraadaptor.pytorch import CameraAdaptor
import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self, adaptor="rgb"):
        super().__init__()
        self.adaptor = CameraAdaptor(adaptor)
        self.backbone = nn.Sequential(
            nn.Conv2d(CameraAdaptor.compute_output_channels(adaptor), 64, 3),
            # ... rest of your model
        )

    def forward(self, x):
        x = self.adaptor(x)
        return self.backbone(x)

# Model for RGBA input (4 channels -> 3 channels after adaptor)
model = MyModel(adaptor="rgba")

TensorFlow/Keras Model

from edgefirst.cameraadaptor.tensorflow import CameraAdaptor
import tensorflow as tf

inputs = tf.keras.Input(shape=(224, 224, 4))  # RGBA input
x = CameraAdaptor("rgba")(inputs)  # Drops alpha -> 3 channels
x = tf.keras.layers.Conv2D(64, 3, padding="same")(x)
# ... rest of your model

Channels-Last Input (Camera Pipeline Direct)

For models receiving data directly from camera pipelines in NHWC format:

# PyTorch: accept channels-last input, convert to channels-first internally
adaptor = CameraAdaptor("yuyv", channels_last=True)
x = torch.randn(1, 224, 224, 2)  # NHWC from camera
y = adaptor(x)  # Output: (1, 2, 224, 224) in NCHW

# TensorFlow: accept channels-first input if needed
from edgefirst.cameraadaptor.tensorflow import CameraAdaptor
layer = CameraAdaptor("yuyv", channels_first=True)
x = tf.random.normal((1, 2, 224, 224))  # NCHW
y = layer(x)  # Output: (1, 224, 224, 2) in NHWC

Ultralytics YAML Configuration

# YOLOv8 model with RGBA input
backbone:
  - [-1, 1, CameraAdaptor, [rgba]]  # First layer
  - [-1, 1, Conv, [64, 3, 2]]
  # ... rest of backbone

Source Format (Data Loader Compatibility)

Different image loading libraries return different formats:

Library Default Format Transform Setup
PIL/Pillow RGB source_format="rgb" (default)
torchvision RGB source_format="rgb" (default)
OpenCV cv2.imread() BGR source_format="bgr"
OpenCV cv2.IMREAD_UNCHANGED BGRA source_format="bgra"
imageio RGB source_format="rgb" (default)
skimage RGB source_format="rgb" (default)

Important: OpenCV loads images as BGR by default. If you're using cv2.imread() without explicit conversion, set source_format="bgr":

import cv2
from edgefirst.cameraadaptor import CameraAdaptorTransform

# CORRECT: Tell the transform your source is BGR
img = cv2.imread("image.jpg")
transform = CameraAdaptorTransform("yuyv", source_format="bgr")
yuyv = transform(img)

Supported Color Spaces

Currently Supported

Format Input Channels Output Channels Description
RGB 3 3 Standard RGB
BGR 3 3 OpenCV native
RGBA 4 3 RGB + alpha (dropped)
BGRA 4 3 BGR + alpha (dropped)
YUYV 2 2 YUV 4:2:2, ch0=Y, ch1=UV

Planned

  • Roadmap: NV12, NV21 (semi-planar YUV 4:2:0)
  • Roadmap: Bayer patterns (RGGB, BGGR, GRBG, GBRG)

See FORMATS.md for detailed format documentation.

Platform-Specific Guidance

See PLATFORMS.md for i.MX platform-specific recommendations:

  • i.MX 93: PXP outputs BGR - train models with BGR format
  • i.MX 8M Plus: G2D outputs RGBA - use RGBA to auto-slice alpha
  • i.MX 95: ISI/ISP pipeline considerations

Configuration

Use CameraAdaptorConfig for model metadata:

from edgefirst.cameraadaptor import CameraAdaptorConfig

config = CameraAdaptorConfig(
    adaptor="yuyv",
    input_dtype="uint8",   # For quantized models
    output_dtype="uint8",
)

# Embed in model metadata
metadata = config.to_metadata()

PyTorch Lightning Integration

from pytorch_lightning import Trainer
from edgefirst.cameraadaptor.pytorch.lightning import create_callback

callback = create_callback("yuyv")
trainer = Trainer(callbacks=[callback])

Migration from Existing Code

From ultralytics/edgefirst

# Before
from ultralytics.edgefirst.camera.adaptor import CameraAdaptorTransform
from ultralytics.edgefirst.nn.modules import CameraAdaptor

# After
from edgefirst.cameraadaptor import CameraAdaptorTransform
from edgefirst.cameraadaptor.pytorch import CameraAdaptor

From modelpack

# Before
from deepview.modelpack.datasets.color import ColorAdaptor
from deepview.modelpack.layers.conv2d import ColorAdaptor as TFColorAdaptor

# After
from edgefirst.cameraadaptor import CameraAdaptorTransform
from edgefirst.cameraadaptor.tensorflow import CameraAdaptor

API Reference

CameraAdaptorTransform

Preprocessing transform for converting images to target formats.

transform = CameraAdaptorTransform(
    adaptor="yuyv",           # Target format
    source_format="rgb",      # Source format (default: "rgb")
)
output = transform(image)  # or transform.convert(image)

Parameters:

  • adaptor: Target color space (str or ColorSpace enum)
  • source_format: Source color space from data loader (str or ColorSpace enum, default: "rgb")

Properties:

  • adaptor: Target adaptor name (str)
  • source_format: Source format name (str)
  • channels: Output channel count
  • input_channels: Source format channel count
  • output_channels: Channels model backbone receives

CameraAdaptor (PyTorch)

from edgefirst.cameraadaptor.pytorch import CameraAdaptor

adaptor = CameraAdaptor(
    adaptor="yuyv",           # Target format
    channels_last=False,      # True for NHWC input
)
output = adaptor(input_tensor)

Parameters:

  • adaptor: Target color space (str or ColorSpace enum)
  • channels_last: If True, input is NHWC, permuted to NCHW (default: False)

Static Methods:

  • compute_input_channels(args): Get input channels from YAML args
  • compute_output_channels(args): Get output channels from YAML args

CameraAdaptor (TensorFlow)

from edgefirst.cameraadaptor.tensorflow import CameraAdaptor

layer = CameraAdaptor(
    adaptor="yuyv",           # Target format (None for auto-detect)
    channels_first=False,     # True for NCHW input
)
output = layer(input_tensor)

Parameters:

  • adaptor: Target color space (str, None for auto-detect)
  • channels_first: If True, input is NCHW, permuted to NHWC (default: False)

CameraAdaptorConfig

from edgefirst.cameraadaptor import CameraAdaptorConfig

config = CameraAdaptorConfig(
    adaptor="yuyv",
    input_dtype="float32",
    output_dtype="float32",
)

Properties:

  • input_channels: Input channel count
  • output_channels: Output channel count
  • is_quantized: Whether config uses quantized dtypes

Methods:

  • to_dict(): Convert to dictionary
  • to_metadata(): Convert to model metadata format
  • from_dict(data): Create from dictionary
  • from_metadata(metadata): Create from model metadata

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

edgefirst_cameraadaptor-0.1.0.tar.gz (34.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

edgefirst_cameraadaptor-0.1.0-py3-none-any.whl (28.3 kB view details)

Uploaded Python 3

File details

Details for the file edgefirst_cameraadaptor-0.1.0.tar.gz.

File metadata

  • Download URL: edgefirst_cameraadaptor-0.1.0.tar.gz
  • Upload date:
  • Size: 34.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for edgefirst_cameraadaptor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 278ca5e21acc67fe201e78a938a45ebad4076003784e8aa4a2141e942c37a525
MD5 cfacb1b4a3efe409f1fff5a2421aa169
BLAKE2b-256 f67298d9f58234f883d5f711f2a04ff76fa64d83e28fa6ea6e82211a2078072e

See more details on using hashes here.

File details

Details for the file edgefirst_cameraadaptor-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for edgefirst_cameraadaptor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bd4171726bfc40fbff29e4a48f8a3cade1bf661efd54ab68faf4fc6cc1ddd867
MD5 2f20cb043a256fae89f41f2c1b734be2
BLAKE2b-256 df69e07cf1e8c9948b765ee4eedc74533db2e5ec7e93834eb4112428a0638dcd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page