Skip to main content

Hardware Abstraction Layer for edge AI with zero-copy tensors, image processing, and YOLO decoding

Project description

edgefirst-hal

PyPI Python License

Hardware-accelerated image processing, zero-copy tensors, and YOLO decoding for edge AI inference pipelines. Built in Rust with Python bindings via PyO3.

Installation

pip install edgefirst-hal

Pre-built wheels are available for Linux (x86_64, aarch64), macOS, and Windows. No Rust toolchain required.

Python 3.11+ wheels use the improved stable ABI for zero-copy buffer protocol support. Python 3.8–3.10 wheels use a compatible fallback. Pip selects the best wheel automatically.

Quick Start

import edgefirst_hal as ef

# Load a source image
src = ef.Tensor.load("photo.jpg", ef.PixelFormat.Rgb)

# Create an image processor (auto-selects best backend: GPU > G2D > CPU)
processor = ef.ImageProcessor()

# Allocate a GPU-optimal output buffer — always use create_image() for
# destinations passed to convert(), so the processor can select the best
# memory type (DMA-buf, PBO, or system memory) for zero-copy GPU paths.
dst = processor.create_image(640, 640, ef.PixelFormat.Rgb)

# Convert with a letterbox resize (preserves aspect ratio, pads with grey).
# Omit `letterbox=` to stretch-to-fill instead.
processor.convert(src, dst, letterbox=[114, 114, 114, 255])

# Access pixel data as a numpy array. Use the context manager + .numpy()
# form — this is the portable pattern that works on both wheel variants.
import numpy as np
with dst.map() as m:
    pixels = np.frombuffer(m.numpy(), dtype=np.uint8).reshape(dst.shape())

# The shorter `np.frombuffer(dst.map(), ...)` form only works on the
# abi3-py311 wheel, where `TensorMap` exposes Python's buffer protocol
# directly. The abi3-py38 compatibility wheel disables `__getbuffer__`,
# so use `.numpy()` if your code needs to run on Python 3.8–3.10.

Role in edgefirst-hal

The edgefirst-hal package on PyPI is the Python face of the EdgeFirst HAL Rust workspace:

  • Built from crates/python, which is a PyO3 binding over the edgefirst-hal Rust umbrella crate.
  • Does not consume the C API (edgefirst-hal-capi); the binding goes directly through Rust.
  • Exposes the same Tensor, ImageProcessor, Decoder, and Tracker surfaces as the Rust crate, with numpy-friendly conversions and the buffer protocol for zero-copy interop.
  • Wheels are distributed as two stable-ABI variants per platform — abi3-py311 (preferred, supports buffer protocol features added in 3.11) and abi3-py38 (compatibility fallback for 3.8–3.10). Pip selects the best wheel automatically.

Key Features

  • Zero-copy tensors — DMA-BUF, POSIX shared memory, and PBO-backed buffers with automatic fallback to system memory
  • Hardware-accelerated image processing — OpenGL, NXP G2D, and optimized CPU backends with automatic selection
  • Letterbox resize — aspect-ratio-preserving resize with configurable padding color, rotation, and flip
  • Int8 outputcreate_image(..., dtype="int8") for direct signed int8 tensor output with GPU-accelerated XOR bias
  • YOLO decoding — YOLOv5, YOLOv8, YOLO11, and YOLO26 detection and instance segmentation (including end-to-end models)
  • Object tracking — ByteTrack multi-object tracker with Kalman filtering
  • Fully typed — ships with .pyi stubs for IDE autocompletion and type checking with mypy / pyright

Image Processing

import edgefirst_hal as ef

processor = ef.ImageProcessor()
src = ef.Tensor.load("frame.jpg", ef.PixelFormat.Rgb)

# Letterbox resize to model input size
dst = processor.create_image(640, 640, ef.PixelFormat.Rgb)
processor.convert(src, dst)

# With rotation and horizontal flip
processor.convert(src, dst, rotation=ef.Rotation.Rotate90, flip=ef.Flip.Horizontal)

# Crop source region
processor.convert(src, dst, src_crop=ef.Rect(100, 100, 400, 400))

# Int8 output for quantized models
dst_i8 = processor.create_image(640, 640, ef.PixelFormat.Rgb, dtype="int8")
processor.convert(src, dst_i8)

Zero-Copy External Buffer (Linux)

When integrating with an NPU delegate that owns DMA-BUF buffers, render directly into the delegate's buffer to eliminate a memcpy:

import edgefirst_hal as ef

processor = ef.ImageProcessor()
src = ef.Tensor.load("frame.jpg", ef.PixelFormat.Rgb)

# Render directly into the delegate's DMA-BUF — zero copies
dst = processor.import_image(fd=vx_fd, width=640, height=640, format=ef.PixelFormat.Rgb)
processor.convert(src, dst)

# Reverse: HAL allocates, consumer imports the fd
hal_dst = processor.create_image(640, 640, ef.PixelFormat.Rgb)
fd = hal_dst.dmabuf_clone()  # Raises if not DMA-backed
delegate.register(fd)

You can also attach format metadata to any raw tensor created via from_fd():

t = ef.Tensor.from_fd(some_fd, [480, 640, 3])
t.set_format(ef.PixelFormat.Rgb)
processor.convert(src, t)

Performance tip: When rotating through a pool of DMA-BUFs (e.g. 2-3 from an NPU delegate), create the Tensor wrappers once at init and reuse them across frames. This avoids EGL image cache misses (~100-300us each on Vivante GPUs).

CUDA Zero-Copy (TensorRT)

When running inference with TensorRT or cupy, Tensor.cuda_map() exposes a raw CUDA device pointer to a tensor that has been registered with CUDA (e.g. via the GL-CUDA interop path). The mapping is scoped by a context manager so the GPU buffer is released automatically for the next convert() call.

Check availability first, then try cuda_map() and fall back to map() for CPU paths:

import edgefirst_hal as ef

# One-time check — cached after first call
if not ef.is_cuda_available():
    print("libcudart not found; falling back to CPU tensors")

tensor = ef.ImageProcessor().create_image(640, 640, ef.PixelFormat.Rgb)

cm = tensor.cuda_map()
if cm is not None:
    with cm as m:
        # m.device_ptr is the raw CUDA device pointer (int)
        # m.size is the buffer size in bytes
        trt_context.set_input_tensor_address("input", m.device_ptr)
        trt_context.execute_async_v3(stream)
else:
    # No CUDA handle on this tensor — use the CPU path
    with tensor.map() as host:
        run_cpu_inference(host)

CudaMap exposes:

  • device_ptr (int) — raw CUDA device pointer, suitable for cupy.ndarray.from_dlpack, pycuda.gpuarray, or TensorRT set_input_tensor_address.
  • size (int) — buffer size in bytes.
  • release() — explicitly release before the with block ends (idempotent).

YOLO Decoding

import edgefirst_hal as ef

# Configure decoder from model metadata
decoder = ef.Decoder(
    {"detection": {"shape": [1, 84, 8400], "dtype": "float32"}},
    score_threshold=0.5,
    iou_threshold=0.45,
)

# Decode model outputs → (boxes, scores, class_ids)
boxes, scores, classes = decoder.decode([output_tensor])

Object Tracking

ByteTrack is a multi-object tracker based on ByteTrack with Kalman filtering. It assigns consistent track IDs across frames.

import edgefirst_hal as ef

tracker = ef.ByteTrack(
    high_conf=0.7,         # High-confidence detection threshold
    iou=0.25,              # IoU threshold for association
    update=0.25,           # Update/low-confidence threshold
    lifespan_ns=500_000_000,  # Track lifespan without detection (nanoseconds)
)

# Decode and track in one call (returns boxes, scores, classes, masks, track_infos)
boxes, scores, classes, masks, tracks = decoder.decode_tracked(
    tracker, timestamp_ns, [output_tensor]
)
# masks is empty for detection-only models

# Or query currently active tracks
active = tracker.get_active_tracks()

Segmentation Mask Rendering

draw_decoded_masks()

Draw pre-decoded masks onto a destination image:

processor.draw_decoded_masks(
    dst,
    bbox,           # numpy array [N, 4]
    scores,         # numpy array [N]
    classes,        # numpy array [N]
    seg=[],         # list of segmentation arrays (optional)
    background=None,  # optional background tensor to blit before drawing
    opacity=1.0,    # mask alpha scale (0.0 – 1.0)
)

draw_masks()

Decode model outputs and draw segmentation masks in a single call. Masks never leave Rust, eliminating the Python round-trip overhead of decode() + draw_decoded_masks().

Without a tracker, returns (boxes, scores, classes). With a tracker, returns (boxes, scores, classes, track_infos).

import edgefirst_hal as ef

processor = ef.ImageProcessor()
tracker = ef.ByteTrack()

# Without tracking
boxes, scores, classes = processor.draw_masks(decoder, outputs, dst)

# With overlay parameters
boxes, scores, classes = processor.draw_masks(
    decoder, outputs, dst,
    background=bg_tensor,  # blit bg_tensor into dst before masks
    opacity=0.7,           # semi-transparent masks
)

# With tracking (requires tracker= and timestamp=)
import time
ts = time.monotonic_ns()
boxes, scores, classes, tracks = processor.draw_masks(
    decoder, outputs, dst,
    tracker=tracker,
    timestamp=ts,
)

Platform Support

Platform GPU Acceleration Memory Types
Linux (NXP i.MX8/i.MX95) OpenGL + G2D DMA-buf, SHM, PBO, Mem
Linux (x86_64, other ARM) OpenGL SHM, PBO, Mem
macOS / Windows CPU only Mem

Hardware acceleration is used automatically when available. All platforms fall back to CPU.

Part of the EdgeFirst Ecosystem

edgefirst-hal is the runtime inference library in the EdgeFirst platform for deploying AI at the edge.

  • EdgeFirst Studio — label, train, and deploy models for edge devices
  • Rust crates — use the same library directly from Rust or C
  • GitHub — source code, architecture docs, benchmarks, and contribution guide

Documentation

License

Apache-2.0 — see LICENSE.

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_hal-0.25.1.tar.gz (1.2 MB view details)

Uploaded Source

Built Distributions

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

edgefirst_hal-0.25.1-cp311-abi3-win_amd64.whl (5.2 MB view details)

Uploaded CPython 3.11+Windows x86-64

edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.7 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

edgefirst_hal-0.25.1-cp311-abi3-macosx_11_0_arm64.whl (4.4 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

edgefirst_hal-0.25.1-cp38-abi3-win_amd64.whl (5.2 MB view details)

Uploaded CPython 3.8+Windows x86-64

edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.8 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

edgefirst_hal-0.25.1-cp38-abi3-macosx_11_0_arm64.whl (4.4 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

File details

Details for the file edgefirst_hal-0.25.1.tar.gz.

File metadata

  • Download URL: edgefirst_hal-0.25.1.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for edgefirst_hal-0.25.1.tar.gz
Algorithm Hash digest
SHA256 8100dbcd8b35377c8e56c9820e3717e3b41ef5d61bae80b9603acd424a905a56
MD5 75fdfdac0d657ec534fd8f7f4a27023e
BLAKE2b-256 c78870a670dcab82c49da9aedecf8568c74e0b902194f77fbc24211982597bd1

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1.tar.gz:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp311-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 27fcf0ab62ef914a7fbb493fcdaca408a5b390d140908caec132a62341f5c9ac
MD5 f7505c140b4d5683c590aec7313f6436
BLAKE2b-256 543dc4db9de3746ac3cde30d28e5d72c39d47e315477862a8312ea0c6d6f0963

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp311-abi3-win_amd64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fbc35519eec01a3811410827b192bf4315c0ce2e4823ac226565a4aa56a0321d
MD5 9c6b569929f314556c3c04030dbde268
BLAKE2b-256 0444bb8f2fb088a349ddf4037dafef720a7f1add6c4df8ba3310d141afe2c11e

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6e37b88ba9de463324a9063e3bfc111c1ad92870a532ae2a7c3bffbfa1759ea6
MD5 aff12a7eb1a3e5a0c5f0f2ddd33148c5
BLAKE2b-256 025f5342c4c7745b6924e4d51da61c70a7f2ba778c3ad414a03f39f8bc7ec7d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f8a583cabec9c235a7d094bdce36a6743831e0711719f429293f7a6909588253
MD5 67bbfb017a51674f206afac7c5422847
BLAKE2b-256 fa0e605c396fc499129faefe01383bc8dadeefd5f9dbf95538c42b0aa6ca281b

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp38-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 df1c540f73666ce79f2192398d4d2aa8accfe75e705c273693daf7b15912d2e9
MD5 fffc288a64a59686cd7449b5cf377fcc
BLAKE2b-256 47182f224c6d4314c856116ee4582a8475aa36e5b71fdc7380361dd8831589f0

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp38-abi3-win_amd64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c2241e69fb0b47a52abb77346afbea8dd94e0a575e94b068da94d05554e71691
MD5 106dae2d882224146d12c1a4ef28814c
BLAKE2b-256 9dd4eec1ce4eb9ef33529aff6d7994c1547c32d66fe2d356a729452a83f93c31

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 58086c8050631a33ded4e36e6d98474130b5c4fe2ee80653b9d7257c0b967fa1
MD5 095ca010537423b8aa20bd23d5982d85
BLAKE2b-256 25760da00377ef7600da4635e1978adc60fab10026cceb4ede56613f7c932f76

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edgefirst_hal-0.25.1-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for edgefirst_hal-0.25.1-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b1fdc4d18e984619632d9f5f873bb60064d85f366d02db2931002e7241e9724d
MD5 ffa69e596dda1588235f727bcaf79f0a
BLAKE2b-256 4eae3e69b63c28281b897c3a480e8216c6f6bccbcd6f985f9b25657c3806b02f

See more details on using hashes here.

Provenance

The following attestation bundles were made for edgefirst_hal-0.25.1-cp38-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on EdgeFirstAI/hal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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