-
Notifications
You must be signed in to change notification settings - Fork 0
API Geometric
Namespace: acl::geometric (CPP) / acl::neon::geometric (NEON)
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 |
— |
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 (floatdefault,doublehigh-precision)
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:
-
T—uint8_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)
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);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/4path already uses memcpy + inlined reads/writes, so for RGB/RGBA the performance is equivalent.- For multi-channel, use CPP
rotate<uint8_t>withblockW=3(RGB) orblockW=4(RGBA); see the example below.
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/dstWidthare given in block count: a grayscale image 1920 wide →srcWidth=1920; RGB 1920 wide →srcWidth=1920(block count is still 1920, not 5760) withblockW=3.
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 fromori(CW/CCW/XPOSE → swap width and height, otherwise → unchanged).
// 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)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 |
— |
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 |
template<class T>
int pyrDown(...) // signature is completely identical to the CPP versionThe type is fixed to
uint8_t; parameter semantics match the CPP version.
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) (—) |
— | — |
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.
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) (—) |
— | — |
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 |
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);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 |
— |
// 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.
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 |
— |
// 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/dstHare optional output parameters — the caller passes in pointers and the function fills in the rotated destination size (forROT_CW_90/ROT_CCW_90/XPOSE, this is a width/height swap). Passnullptrif this info is not needed.
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