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.