Skip to content

OpenCV to ACL Pack Migration Guide

This guide helps developers migrate existing OpenCV code to ACL Pack on Android arm64-v8a / Linux aarch64.

Key Differences

1. No cv::Mat — Raw Pointers + Stride

OpenCV wraps images in cv::Mat with automatic memory management. ACL Pack uses raw pointers and explicit stride.

cpp
// OpenCV
cv::Mat src = cv::imread("image.jpg");
cv::Mat dst;
cv::GaussianBlur(src, dst, cv::Size(5, 5), 1.0);

// ACL Pack — caller manages memory, stride is in bytes.
// The scalar CPP template path is the closest OpenCV-style API: one call
// covers every type and channel count the tier supports.
int width = 1920, height = 1280, cn = 3;
uint8_t* src = new uint8_t[width * height * cn];
uint8_t* dst = new uint8_t[width * height * cn];
// ... load image data into src ...
acl::filter::gaussianBlur<uint8_t, uint8_t>(
    src, dst, width, height, cn,
    /*srcStride=*/0, /*dstStride=*/0,   // 0 = contiguous
    /*kRadiusX=*/2, /*kRadiusY=*/2,
    /*sigmaX=*/1.0, /*sigmaY=*/1.0,
    /*constant=*/nullptr,
    acl::BorderType::BORDER_REFLECT_101);
delete[] src;
delete[] dst;

Key points:

  • stride is in bytes, not pixels. Pass 0 for contiguous memory.
  • Caller allocates and frees all buffers.
  • No implicit format conversion — you must know your data type.

2. Template Types vs Runtime Dispatch

OpenCV determines data type at runtime (src.depth()). ACL Pack uses compile-time templates for the data type, while mode-style enums (interpolation / threshold / border / color) stay runtime.

cpp
// OpenCV — runtime type, runtime mode
cv::threshold(src, dst, 128, 255, cv::THRESH_BINARY);

// ACL Pack — compile-time element type, runtime ThreshMode
acl::neon::arithmetic::threshold(
    src_u8, dst_u8, width, height,
    /*thresh=*/128, /*maxVal=*/255, /*minVal=*/0,
    /*srcStride=*/0, /*dstStride=*/0,
    acl::ThreshMode::THRESH_BINARY);

3. Namespace-Based Module Organization

OpenCVACL Pack (NEON)ACL Pack (CPP)
cv::GaussianBluracl::neon::filter::gaussianBluracl::filter::gaussianBlur
cv::resizeacl::neon::geometric::resizeacl::geometric::resize
cv::thresholdacl::neon::arithmetic::thresholdacl::arithmetic::threshold
cv::cvtColoracl::neon::cvtcolor::*acl::cvtcolor::*

Use acl::neon::* for ARM64 performance, acl::{module}::* for the portable scalar path. Note: the scalar namespace sits directly under acl::{module}:: (not acl::cpp::{module}::). Drawing operators live under acl::draw::, contour analysis under acl::contour::, memory utilities under acl::memory::. All operator declarations ship in a single header — <acl/api.h>.

Tier Availability (before you port)

ACL Pack ships one static library, libacl.a, with the headers under include/acl/. The library exposes every operator entry; which calls actually work is decided by the license loaded at acl::init(licensePath). A call to an operator outside your tier returns -1005 (ACL_ERR_NOT_LICENSED) without writing the output buffer.

  • Starter — baseline filter / color / geometric / arithmetic / analysis / draw operators.
  • Pro — Starter plus advanced denoising, contrast, feature, contour, DFT, and HSV / Lab color paths.
  • Business — Pro plus enterprise paths (HDR, distance transform, connected components, YUV utilities, SIFT / SURF).
  • Trial — only 1 sample operator (resize), fixed 1920×1280 input (other sizes return -1006), watermark on the output.

For per-operator signatures and the full operator catalog see the API Reference.

Migration Example: Complete Pipeline

Before (OpenCV)

cpp
#include <opencv2/opencv.hpp>

void processFrame(const cv::Mat& frame) {
    cv::Mat gray, blurred, edges;

    // Convert BGR to grayscale
    cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);

    // Gaussian blur (5x5)
    cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 1.5);

    // Canny edge detection
    cv::Canny(blurred, edges, 50, 150);

    // Find contours
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(edges, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

    // Resize to 640x480
    cv::Mat resized;
    cv::resize(edges, resized, cv::Size(640, 480));
}

After (ACL Pack)

cpp
#include <acl/acl.h>
#include <acl/api.h>   // every operator lives in this single header

void processFrame(const uint8_t* bgrData, int width, int height) {
    // Caller manages all buffers — ACL Pack never allocates internally.
    uint8_t* rgb     = new uint8_t[width * height * 3];
    uint8_t* gray    = new uint8_t[width * height];
    uint8_t* blurred = new uint8_t[width * height];
    uint8_t* edges   = new uint8_t[width * height];

    // BGR → RGB: explicit channel swap (RGB2Gray expects RGB-ordered input).
    acl::neon::cvtcolor::channelSwap<acl::BGR2RGB>(
        bgrData, rgb, width, height);

    // RGB → Gray (default LUMA = 0.299R + 0.587G + 0.114B, matches cv::COLOR_*2GRAY).
    acl::neon::cvtcolor::RGB2Gray<uint8_t>(
        rgb, gray, width, height);

    // Gaussian blur — NEON fixed 5x5 fast path (1ch u8, default border).
    acl::neon::filter::gaussianBlur5x5(
        gray, blurred, width, height);

    // Canny edges (1ch u8, low=50 high=150, default aperture=3).
    acl::neon::filter::canny(
        blurred, edges, width, height, /*low=*/50, /*high=*/150);

    // Find contours — CPP only, Pro tier.
    // `Point2i` / `HierarchyEntry` / `ContourRetrMode` live in `acl::`.
    std::vector<std::vector<acl::Point2i>> contours;
    acl::analysis::findContours(
        edges, width, height, /*srcStride=*/0,
        contours, /*hierarchy=*/nullptr,
        acl::CONTOUR_RETR_LIST,
        acl::CONTOUR_CHAIN_APPROX_SIMPLE);

    // Resize to 640x480 (1ch u8, bilinear).
    int dstW = 640, dstH = 480;
    uint8_t* resized = new uint8_t[dstW * dstH];
    acl::neon::geometric::resize<uint8_t>(
        edges, resized, width, height, dstW, dstH,
        /*srcStride=*/0, /*dstStride=*/0,
        acl::InterpMode::LINEAR2D);

    // ... use results ...

    delete[] rgb;
    delete[] gray;
    delete[] blurred;
    delete[] edges;
    delete[] resized;
}

Not Yet Available (use OpenCV for these)

For the full list of operators ACL Pack already ships, see the Operator Catalog in the API Reference. The table below is what's still missing — keep using OpenCV for these.

OperatorPriorityNotes
cv::undistort / cv::initUndistortRectifyMapP0Camera distortion correction
cv::drawContoursP1Contour rendering
cv::floodFillP1Region filling
cv::cornerSubPixP2Sub-pixel corner refinement
cv::dilate with custom kernel shapesP2Currently only rectangular
cv::dnn moduleN/AUse TFLite / NNAPI directly
cv::VideoCapture / cv::imwriteN/AUse Android SDK for I/O

Migration Notes

  1. Start with the hot path. Profile your OpenCV code and migrate the slowest operations first. Even a partial migration yields measurable wins, and it lets you validate the integration on a small surface before committing to a full port.

  2. Prefer NEON fixed-size entry points when your kernel is 3×3 / 5×5 / 11×11. The fixed-size NEON Gaussian / box / median paths are 2-25× faster than the templated path that supports arbitrary radii. The templated acl::{module}::* scalar path is still the right choice when you need non-u8 types or arbitrary parameters.

For complete API documentation, see API Reference.
For performance benchmarks, see Performance Whitepaper.