Skip to content

API Geometric

ZangoTech edited this page Jun 20, 2026 · 1 revision

Geometric

← Back to API Reference · Home

Namespace: acl::geometric (CPP) / acl::neon::geometric (NEON)

resize

Image resize, supporting 4 interpolation modes (NEAREST / LINEAR2D / CUBIC4x4 / AREA_AVG).

Tier: Starter+
Channels: 1ch / 3ch / 4ch (runtime via hcn / cn)
Inplace: supported only when srcWidth == dstWidth && srcHeight == dstHeight (degenerate copy / crop case)
Types:

Template parameter Allowed types Constraint
T uint8_t, uint16_t, float

CPP Version: acl::geometric::resize

template<class T, class OT = float>
int resize(
    const T* srcImage, T* dstImage,
    int srcWidth, int srcHeight,
    int dstWidth, int dstHeight,
    int srcStride = 0, int dstStride = 0,
    int hcn = 1, int vcn = 1,
    acl::InterpMode im = acl::InterpMode::LINEAR2D);
Parameter Type Meaning Default
srcImage, dstImage const T* / T* input / output non-null
srcWidth, srcHeight int Source image size > 0
dstWidth, dstHeight int Destination image size > 0
srcStride, dstStride int Bytes per row 0 = auto
hcn int Horizontal channel count (grayscale 1 / Bayer 2 / RGB 3 / RGBA 4) 1
vcn int Vertical channel count 1
im acl::InterpMode NEAREST / LINEAR2D (default) / CUBIC4x4 / AREA_AVG LINEAR2D

Template parameters:

  • T — input / output element type
  • OT — intermediate interpolation type (float default, double high-precision)

NEON Version: acl::neon::geometric::resize (uint8_t / uint16_t)

template<class T>
int resize(
    const T* srcImage, T* dstImage,
    int srcWidth, int srcHeight,
    int dstWidth, int dstHeight,
    int srcStride = 0, int dstStride = 0,
    acl::InterpMode im = acl::InterpMode::LINEAR2D,
    int cn = 1,
    int shiftRight = 0);

Parameters:

  • Tuint8_t / uint16_t
  • im — same as the CPP version
  • cn — channel count (1 / 3 / 4)
  • shiftRight — number of bits to right-shift the data for P010 format (set when 10-bit is in the high bits of 16-bit)

Example

uint8_t srcImage[1920*1080], dstImage[960*540];

// NEON LINEAR2D 1ch, 2× downscale
acl::neon::geometric::resize<uint8_t>(
    srcImage, dstImage, 1920, 1080, 960, 540);

// CPP LINEAR2D 3ch upscale
uint8_t rgbSrc[640*480*3], rgbDst[1280*960*3];
acl::geometric::resize<uint8_t>(
    rgbSrc, rgbDst, 640, 480, 1280, 960,
    /*srcStride=*/0, /*dstStride=*/0,
    /*hcn=*/3, /*vcn=*/1,
    acl::InterpMode::LINEAR2D);

// float CUBIC4x4 (CPP only)
float fSrc[640*480], fDst[1280*960];
acl::geometric::resize<float>(
    fSrc, fDst, 640, 480, 1280, 960,
    0, 0, 1, 1, acl::InterpMode::CUBIC4x4);

rotate

Image rotation / flip / transpose. Supports ROT_0 / ROT_180 / ROT_CW_90 / ROT_CCW_90 / FLIP_H / FLIP_V / XPOSE.

Tier: Starter+
Channels: 1ch / 3ch / 4ch
Inplace: supported for ROT_180 / FLIP_H / FLIP_V (srcImage == dstImage)
Types:

Template parameter Allowed types Constraint
T (CPP) {uint8_t, uint16_t, float}
uint8_t only (NEON) (—)

Channel / type support matrix

Entry point Channels Types
CPP rotate<T> any (packed via runtime blockW / blockH) T any (uint8_t / uint16_t / float / …)
NEON rotate<T> 1ch only uint8_t only
NEON rotateNV NV21 / NV12 (Y + UV) uint8_t
NEON rotateYV12 YV12 / I420 (Y + U + V) uint8_t
NEON rotateYUV444 YUV444 (3ch interleaved) uint8_t

Recommended approach for RGB / RGBA rotation:

  • NEON-accelerated path: there is no direct NEON rotate entry for RGB, but since pure rotation is essentially memory movement, the CPP blockW=3/4 path already uses memcpy + inlined reads/writes, so for RGB/RGBA the performance is equivalent.
  • For multi-channel, use CPP rotate<uint8_t> with blockW=3 (RGB) or blockW=4 (RGBA); see the example below.

CPP Version: acl::geometric::rotate

template<class T>
int rotate(
    const T* srcImage, T* dstImage,
    int srcWidth, int srcHeight,
    int dstWidth, int dstHeight,
    int srcStride = 0, int dstStride = 0,
    acl::RotateOrient ori = acl::RotateOrient::ROT_CW_90,
    int blockW = 1, int blockH = 1);
Parameter Type Meaning Default
srcImage, dstImage const T* / T* input / output non-null
srcWidth, srcHeight int Source image size, counted in pixel blocks (not pixels) must be divisible by blockW/H
dstWidth, dstHeight int Destination size, same as above same as above
srcStride, dstStride int Bytes per row 0 = auto
ori acl::RotateOrient Rotation direction ROT_CW_90
blockW, blockH int Pixel-block size (unit). 1,1 handles single-channel scalar; blockW=3 packs one RGB pixel as an indivisible unit; blockW=4 packs RGBA. 1, 1

Note that srcWidth / dstWidth are given in block count: a grayscale image 1920 wide → srcWidth=1920; RGB 1920 wide → srcWidth=1920 (block count is still 1920, not 5760) with blockW=3.


NEON Version: acl::neon::geometric::rotate (uint8_t only, 1ch)

template<class T>
int rotate(
    const T* srcImage, T* dstImage,
    int srcW, int srcH,
    int srcStride = 0, int dstStride = 0,
    acl::RotateOrient ori = acl::RotateOrient::ROT_CW_90);

Signature differs slightly: no dstWidth/dstHeight; the output size is derived from ori (CW/CCW/XPOSE → swap width and height, otherwise → unchanged).


Example

// 1) 1ch u8 goes through NEON
uint8_t srcImage[1920*1080], dstImage[1080*1920];
acl::neon::geometric::rotate<uint8_t>(
    srcImage, dstImage, 1920, 1080,
    /*srcStride=*/0, /*dstStride=*/0,
    acl::RotateOrient::ROT_CW_90);

// 2) RGB (3ch) goes through CPP; blockW=3 packs the pixel
uint8_t rgbSrc[1920*1080*3], rgbDst[1080*1920*3];
acl::geometric::rotate<uint8_t>(
    rgbSrc, rgbDst,
    /*srcWidth=*/1920, /*srcHeight=*/1080,   // block count, not 1920*3
    /*dstWidth=*/1080, /*dstHeight=*/1920,
    /*srcStride=*/1920*3, /*dstStride=*/1080*3,
    acl::RotateOrient::ROT_CW_90,
    /*blockW=*/3, /*blockH=*/1);

// 3) float 1ch 180° in-place
float img[512*512];
acl::geometric::rotate<float>(
    img, img, 512, 512, 512, 512,
    0, 0,
    acl::RotateOrient::ROT_180);

// 4) YUV NV21 rotation uses the dedicated NEON entry (see the "YUV rotate" section)

pyrDown

2× downsample (Gaussian pyramid, going down): first 5×5 Gaussian smoothing, then 2×2 downsampling.

Tier: Starter+
Channels: 1ch / 3ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T uint8_t, uint16_t, float

CPP Version: acl::geometric::pyrDown

template<class T>
int pyrDown(
    const T* srcImage, T* dstImage,
    int srcWidth, int srcHeight, int cn,
    int srcStride = 0, int dstStride = 0,
    int dstWidth = 0, int dstHeight = 0,
    const T* constant = nullptr,
    acl::BorderType bt = acl::BorderType::BORDER_REFLECT_101);
Parameter Type Meaning Default
srcImage, dstImage const T* / T* input / output non-null
srcWidth, srcHeight int Source image size ≥ 2
cn int Channel count 1 or 3
srcStride, dstStride int Bytes per row 0 = auto
dstWidth, dstHeight int Destination size ((src+1)/2 when 0) OpenCV-compatible: |dstW*2 - srcW| ≤ 2
constant const T* BORDER_CONSTANT fill value nullptr
bt acl::BorderType Border-handling mode BORDER_REFLECT_101

NEON Version: acl::neon::geometric::pyrDown (uint8_t only)

template<class T>
int pyrDown(...)   // signature is completely identical to the CPP version

The type is fixed to uint8_t; parameter semantics match the CPP version.


pyrUp

2× upsample (Gaussian pyramid, going up): interpolated upscaling followed by 5×5 Gaussian smoothing.

Tier: Starter+
Channels: 1ch / 3ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T (CPP) uint8_t (only uint8_t is currently supported)
uint8_t only (NEON) (—)

CPP / NEON Signature (identical)

template<class T>
int pyrUp(
    const T* srcImage, T* dstImage,
    int srcWidth, int srcHeight, int cn,
    int srcStride = 0, int dstStride = 0,
    int dstWidth = 0, int dstHeight = 0,
    const T* constant = nullptr,
    acl::BorderType bt = acl::BorderType::BORDER_REFLECT_101);

Parameter semantics are the same as pyrDown; default output is srcWidth*2 × srcHeight*2.


buildPyramid

Build a multi-level Gaussian pyramid (accumulated successive pyrDown). pyramid[0] = pyrDown(srcImage), pyramid[1] = pyrDown(pyramid[0]), ...

Tier: Starter+
Channels: 1ch / 3ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T (CPP) uint8_t (only uint8_t is currently supported)
uint8_t only (NEON) (—)

CPP / NEON Signature (identical)

template<class T>
int buildPyramid(
    const T* srcImage,
    T** pyramid,
    int* widths, int* heights,
    int srcWidth, int srcHeight,
    int cn, int numLevels,
    int srcStride = 0,
    acl::BorderType bt = acl::BorderType::BORDER_REFLECT_101);
Parameter Type Meaning Default
srcImage const T* Input image (level 0) non-null
pyramid T** Output pointer array (numLevels entries, pre-allocated by the caller) non-null
widths, heights int* Output sizes at each level non-null
srcWidth, srcHeight int Source image size ≥ 2
cn int Channel count 1 or 3
numLevels int Number of levels ≥ 1
srcStride int Source bytes per row 0 = auto

Example

uint8_t srcImage[1920*1080];
uint8_t l0[960*540], l1[480*270], l2[240*135];
uint8_t* pyr[3] = { l0, l1, l2 };
int widths[3], heights[3];

acl::neon::geometric::buildPyramid<uint8_t>(
    srcImage, pyr, widths, heights, 1920, 1080, 1, 3);

YUV resize (NV21 / NV12 / YV12 / YUV444)

Native YUV resize; avoids the YUV ↔ RGB conversion. Each channel is resized independently (the NV plane is split → resize → merge to avoid mixing U/V).

Tier: Starter+
Channels: Y plane (1ch) + UV plane (interleaved or separate)
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T uint8_t

NEON Signature

// NV21 / NV12 — full-resolution Y; UV plane at 1/4 resolution
int resizeNV(
    const uint8_t* srcYImage, const uint8_t* srcUVImage,
    uint8_t* dstYImage, uint8_t* dstUVImage,
    int srcW, int srcH, int dstW, int dstH,
    int srcYStride = 0, int srcUVStride = 0,
    int dstYStride = 0, int dstUVStride = 0,
    bool nv21Fmt = true);

// YV12 / I420 — full-resolution Y; U / V each at 1/4 resolution
int resizeYV12(
    const uint8_t* srcYImage, const uint8_t* srcUImage, const uint8_t* srcVImage,
    uint8_t* dstYImage, uint8_t* dstUImage, uint8_t* dstVImage,
    int srcW, int srcH, int dstW, int dstH,
    int srcYStride = 0, int srcUVStride = 0,
    int dstYStride = 0, int dstUVStride = 0);

// YUV444 — 3 channels interleaved, no sub-sampling
int resizeYUV444(
    const uint8_t* srcImage, uint8_t* dstImage,
    int srcW, int srcH, int dstW, int dstH,
    int srcStride = 0, int dstStride = 0);

nv21Fmt = true → NV21 (V/U order); false → NV12 (U/V order).
NV / YV12 require input sizes to be even.


YUV rotate (NV21 / NV12 / YV12 / YUV444)

Native YUV rotation; avoids the YUV ↔ RGB conversion.

Tier: Starter+
Channels: Y plane (1ch) + UV plane (interleaved or separate)
Inplace: supported for ROT_180 / FLIP_H / FLIP_V
Types:

Template parameter Allowed types Constraint
T uint8_t

NEON Signature

// NV21 / NV12
int rotateNV(
    const uint8_t* srcYImage, const uint8_t* srcUVImage,
    uint8_t* dstYImage, uint8_t* dstUVImage,
    int srcW, int srcH,
    int* dstW = nullptr, int* dstH = nullptr,
    acl::RotateOrient ori = acl::RotateOrient::ROT_CW_90,
    bool nv21Fmt = true);

// YV12 / I420
int rotateYV12(
    const uint8_t* srcYImage, const uint8_t* srcUImage, const uint8_t* srcVImage,
    uint8_t* dstYImage, uint8_t* dstUImage, uint8_t* dstVImage,
    int srcW, int srcH,
    int* dstW = nullptr, int* dstH = nullptr,
    acl::RotateOrient ori = acl::RotateOrient::ROT_CW_90);

// YUV444 (single-plane interleaved, 3ch)
int rotateYUV444(
    const uint8_t* srcImage, uint8_t* dstImage,
    int srcW, int srcH,
    int* dstW = nullptr, int* dstH = nullptr,
    acl::RotateOrient ori = acl::RotateOrient::ROT_CW_90);

dstW / dstH are optional output parameters — the caller passes in pointers and the function fills in the rotated destination size (for ROT_CW_90 / ROT_CCW_90 / XPOSE, this is a width/height swap). Pass nullptr if this info is not needed.


Example

uint8_t srcY[1920*1280], srcUV[1920*640*2];
uint8_t dstY[1280*1920], dstUV[1280*640*2];

// NV21 clockwise 90°
int dstW = 0, dstH = 0;
acl::neon::geometric::rotateNV(
    srcY, srcUV, dstY, dstUV, 1920, 1280,
    &dstW, &dstH,
    acl::RotateOrient::ROT_CW_90,
    /*nv21Fmt=*/true);
// dstW == 1280, dstH == 1920

Clone this wiki locally