Skip to content

API Color Conversion

ZangoTech edited this page Jun 20, 2026 · 1 revision

Color Conversion

← Back to API Reference · Home

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

RGB2Gray / RGBA2Gray

RGB(A) → grayscale image. Supports 5 grayscale strategies (luma BT.601, max, min, average, weighted).

Tier: Starter+
Channels: input 3ch (RGB) or 4ch (RGBA), output 1ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T uint8_t, uint16_t, float

CPP Version: acl::cvtcolor::RGB2Gray / RGBA2Gray

template<class T>
int RGB2Gray(
    const T* rgbImage, T* grayImage,
    int width, int height,
    int rgbStride = 0, int grayStride = 0,
    acl::ColorCvtGrayMode mode = acl::ColorCvtGrayMode::GRAY_LUMA,
    float cR = 0.299f, float cG = 0.587f, float cB = 0.114f);

template<class T>
int RGBA2Gray(
    const T* rgbaImage, T* grayImage,
    int width, int height,
    int rgbaStride = 0, int grayStride = 0,
    acl::ColorCvtGrayMode mode = acl::ColorCvtGrayMode::GRAY_LUMA,
    float cR = 0.299f, float cG = 0.587f, float cB = 0.114f);
Parameter Type Meaning Default
rgbImage / rgbaImage const T* Input RGB / RGBA image non-null
grayImage T* Output grayscale image non-null
width, height int Image size > 0
rgbStride/rgbaStride, grayStride int Bytes per row 0 = auto
mode acl::ColorCvtGrayMode Grayscale strategy GRAY_LUMA
cR, cG, cB float Weights used only in GRAY_WEIGHTED mode BT.601 defaults

mode values (see acl::ColorCvtGrayMode):

  • GRAY_LUMA (default) — BT.601 luma: 0.299R + 0.587G + 0.114B
  • GRAY_WEIGHTED — uses custom weights cR/cG/cB
  • GRAY_MIN / GRAY_MAX / GRAY_AVG — take min / max / mean across channels

NEON Version: acl::neon::cvtcolor::RGB2Gray / RGBA2Gray (uint8_t only)

int RGB2Gray(   // or RGBA2Gray
    const uint8_t* rgbImage, uint8_t* grayImage,
    int width, int height,
    int rgbStride = 0, int grayStride = 0,
    acl::ColorCvtGrayMode mode = acl::ColorCvtGrayMode::GRAY_LUMA,
    float cR = 0.299f, float cG = 0.587f, float cB = 0.114f);

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


Example

uint8_t rgb[1920*1080*3], gray[1920*1080];

// BT.601 luma grayscale (default)
acl::neon::cvtcolor::RGB2Gray(rgb, gray, 1920, 1080);

// Channel-wise max mode (u16)
acl::cvtcolor::RGB2Gray<uint16_t>(
    src16, gray16, 1920, 1080,
    /*rgbStride=*/0, /*grayStride=*/0,
    acl::ColorCvtGrayMode::GRAY_MAX);

Channel Swap (BGR / RGB / RGBA interchange)

Channel-order swap (3ch ↔ 3ch, 3ch ↔ 4ch, 4ch ↔ 3ch). One template entry point channelSwap<Mode>() covers every direction; only the Mode tag changes.

Tier: Starter+
Channels: 3ch ↔ 3ch / 3ch ↔ 4ch / 4ch ↔ 3ch
Inplace: not supported (when channel counts differ)
Types:

Template parameter Allowed types Constraint
T uint8_t

CPP / NEON Version (identical signatures, uint8_t only)

All channel-swap directions are dispatched through a single channelSwap<Mode>() template — the Mode template parameter is an empty tag struct selecting the conversion direction. The 5 tag structs cover all 10 useful directions (each tag handles a pair of equivalent swaps).

template<class Mode>
int channelSwap(
    const uint8_t* srcImage, uint8_t* dstImage,
    int width, int height, int srcStride = 0, int dstStride = 0);

// Mode tags (declared in typeDef.h, namespace acl::):
//   3ch ↔ 3ch:   BGR2RGB    (also covers RGB → BGR — same byte layout)
//   3ch → 4ch:   BGR2BGRA   (also covers RGB → RGBA)
//                BGR2RGBA   (also covers RGB → BGRA — swap R/B + add alpha)
//   4ch → 3ch:   BGRA2BGR   (also covers RGBA → RGB)
//                BGRA2RGB   (also covers RGBA → BGR — swap R/B + drop alpha)

CPP lives in acl::cvtcolor::, NEON in acl::neon::cvtcolor::, with identical signatures.

Parameter Type Meaning Default
srcImage, dstImage const uint8_t* / uint8_t* input / output non-null
width, height int Image size > 0
srcStride, dstStride int Bytes per row 0 = auto

Example

uint8_t bgr[1920*1080*3], rgba[1920*1080*4];

// BGR → RGBA (NEON) — pick the Mode tag that matches the direction
acl::neon::cvtcolor::channelSwap<acl::BGR2RGBA>(bgr, rgba, 1920, 1080);

RGB ↔ YUV (fixed-point)

Conversion between RGB/RGBA and YUV (NV21 / YV12 / YUV444), using integer fixed-point arithmetic. Supports BT.601 / BT.709 / BT.2020 + full-range / limited-range combinations via the unified YUVConvertParams struct.

Tier: Starter+
Channels: 3ch RGB ↔ NV21 / NV12 / YV12 / YUV444
Inplace: not supported
Types:

Template parameter Allowed types Constraint
RGB_T uint8_t, uint16_t
YUV_T uint8_t, uint16_t

NV21 and NV12 share the same entry point; switch via YUVConvertParams::nv21_fmt (true = NV21, false = NV12).


CPP Version: acl::cvtcolor::rgb*2*_fixed (RGB → YUV, 6 entry points)

NV21 / NV12 (Y plane + interleaved UV plane)

template<class RGB_T, class YUV_T>
int rgb2NV21_fixed(
    const RGB_T* rgbImage, YUV_T* dstYImage, YUV_T* dstUVImage,
    int width, int height,
    int rgbStride = 0, int yStride = 0, int uvStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T>
int rgba2NV21_fixed(
    const RGB_T* rgbaImage, YUV_T* dstYImage, YUV_T* dstUVImage,
    int width, int height,
    int rgbaStride = 0, int yStride = 0, int uvStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

YV12 (three independent planes Y / U / V; U/V are each width/2 × height/2)

template<class RGB_T, class YUV_T>
int rgb2YV12_fixed(
    const RGB_T* rgbImage,
    YUV_T* dstYImage, YUV_T* dstUImage, YUV_T* dstVImage,
    int width, int height,
    int rgbStride = 0, int yStride = 0, int uStride = 0, int vStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T>
int rgba2YV12_fixed(
    const RGB_T* rgbaImage,
    YUV_T* dstYImage, YUV_T* dstUImage, YUV_T* dstVImage,
    int width, int height,
    int rgbaStride = 0, int yStride = 0, int uStride = 0, int vStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

YUV444 (single-plane interleaved)

template<class RGB_T, class YUV_T>
int rgb2YUV444_fixed(
    const RGB_T* rgbImage, YUV_T* dstYUVImage,
    int width, int height,
    int rgbStride = 0, int yuvStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T>
int rgba2YUV444_fixed(
    const RGB_T* rgbaImage, YUV_T* dstYUVImage,
    int width, int height,
    int rgbaStride = 0, int yuvStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

CPP Version: acl::cvtcolor::*2RGB_fixed (YUV → RGB, 6 entry points)

NV21 / NV12 → RGB / RGBA

template<class YUV_T, class RGB_T>
int nv212RGB_fixed(
    const YUV_T* srcYImage, const YUV_T* srcUVImage, RGB_T* rgbImage,
    int width, int height,
    int yStride = 0, int uvStride = 0, int rgbStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class YUV_T, class RGB_T>
int nv212RGBA_fixed(
    const YUV_T* srcYImage, const YUV_T* srcUVImage, RGB_T* rgbaImage,
    int width, int height,
    int yStride = 0, int uvStride = 0, int rgbaStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

YV12 → RGB / RGBA (three input planes)

template<class YUV_T, class RGB_T>
int yv122RGB_fixed(
    const YUV_T* srcYImage, const YUV_T* srcUImage, const YUV_T* srcVImage,
    RGB_T* rgbImage,
    int width, int height,
    int yStride = 0, int uStride = 0, int vStride = 0, int rgbStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class YUV_T, class RGB_T>
int yv122RGBA_fixed(
    const YUV_T* srcYImage, const YUV_T* srcUImage, const YUV_T* srcVImage,
    RGB_T* rgbaImage,
    int width, int height,
    int yStride = 0, int uStride = 0, int vStride = 0, int rgbaStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

YUV444 → RGB / RGBA (single input plane)

template<class YUV_T, class RGB_T>
int yuv4442RGB_fixed(
    const YUV_T* srcYUVImage, RGB_T* rgbImage,
    int width, int height,
    int yuvStride = 0, int rgbStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

template<class YUV_T, class RGB_T>
int yuv4442RGBA_fixed(
    const YUV_T* srcYUVImage, RGB_T* rgbaImage,
    int width, int height,
    int yuvStride = 0, int rgbaStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});
Parameter Meaning
rgbImage / rgbaImage RGB / RGBA plane, 3 or 4 bytes/pixel
dstYImage, dstUVImage / dstUImage, dstVImage / dstYUVImage YUV output planes (NV merges UV, YV12 has separate U/V, YUV444 is interleaved)
width, height Image size (NV/YV12 require even values)
*Stride Bytes per row, 0 = auto
cvMatrix Custom 3×3 conversion matrix (used only when p.yuv_std = YUVEncodeStandard::STD_CUSTOM)
p YUVConvertParams — selects standard, channel order, bit depth, range. Defaults to BT.601 8-bit full-range RGB.

NEON Version: acl::neon::cvtcolor::rgb*2*_fixed (uint8_t only)

template<class RGB_T, class YUV_T>
int rgb2NV21_fixed(
    const RGB_T* rgbImage, YUV_T* dstYImage, YUV_T* dstUVImage,
    int width, int height,
    int rgbStride = 0, int yStride = 0, int uvStride = 0,
    const float* cvMatrix = nullptr,
    const acl::YUVConvertParams& p = {});

// Corresponds to 12 NEON entry points (signatures match the CPP versions):
//   rgb2NV21_fixed / rgba2NV21_fixed / rgb2YV12_fixed / rgba2YV12_fixed
//   rgb2YUV444_fixed / rgba2YUV444_fixed
//   nv212RGB_fixed / nv212RGBA_fixed / yv122RGB_fixed / yv122RGBA_fixed
//   yuv4442RGB_fixed / yuv4442RGBA_fixed

NEON RGB/YUV input/output types are uint8_t only; all other parameters (including YUVConvertParams) match the CPP version exactly.


Example

uint8_t rgb[1920*1080*3];
uint8_t y[1920*1080], uv[1920*540*2];

// BT.601 full-range RGB → NV21 (default params)
acl::neon::cvtcolor::rgb2NV21_fixed<uint8_t, uint8_t>(
    rgb, y, uv, 1920, 1080);

// BT.709 limited-range NV12 (override defaults)
acl::YUVConvertParams p;
p.yuv_std         = acl::YUVEncodeStandard::STD_BT709;
p.nv21_fmt        = false;   // NV12
p.yuv_full_range  = false;   // limited range [16, 235/240]
acl::cvtcolor::rgb2NV21_fixed<uint8_t, uint8_t>(
    rgb, y, uv, 1920, 1080,
    /*rgbStride=*/0, /*yStride=*/0, /*uvStride=*/0,
    /*cvMatrix=*/nullptr, p);

RGB ↔ YUV (float, CPP only)

Floating-point implementation (higher precision, slightly slower than the fixed-point path; suitable for precision-sensitive scenarios). NEON does not provide this path.

Tier: Starter+
Channels: 3ch RGB ↔ NV21 / NV12 / YV12 / YUV444
Inplace: not supported
Types:

Template parameter Allowed types Constraint
RGB_T uint8_t, uint16_t, float
YUV_T uint8_t, uint16_t, float

CPP Signature (one-to-one correspondence with the _fixed version; only the _fixed suffix is removed)

Signatures, parameters, and the trailing YUVConvertParams& p are completely identical to the fixed version; the _float variants prioritise numerical accuracy, the _fixed variants prioritise throughput. 12 entry points:

RGB → YUV

template<class RGB_T, class YUV_T>
int rgb2NV21(const RGB_T* rgbImage, YUV_T* dstYImage, YUV_T* dstUVImage,
             int width, int height,
             int rgbStride = 0, int yStride = 0, int uvStride = 0,
             const float* cvMatrix = nullptr,
             const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T> int rgba2NV21(/* same as above with rgba prefix */);

template<class RGB_T, class YUV_T>
int rgb2YV12(const RGB_T* rgbImage,
             YUV_T* dstYImage, YUV_T* dstUImage, YUV_T* dstVImage,
             int width, int height,
             int rgbStride = 0, int yStride = 0, int uStride = 0, int vStride = 0,
             const float* cvMatrix = nullptr,
             const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T> int rgba2YV12(/* same as above */);

template<class RGB_T, class YUV_T>
int rgb2YUV444(const RGB_T* rgbImage, YUV_T* dstYUVImage,
               int width, int height,
               int rgbStride = 0, int yuvStride = 0,
               const float* cvMatrix = nullptr,
               const acl::YUVConvertParams& p = {});

template<class RGB_T, class YUV_T> int rgba2YUV444(/* same as above */);

YUV → RGB

template<class YUV_T, class RGB_T> int nv212RGB (...);   // signatures mirror nv212RGB_fixed
template<class YUV_T, class RGB_T> int nv212RGBA(...);
template<class YUV_T, class RGB_T> int yv122RGB (...);
template<class YUV_T, class RGB_T> int yv122RGBA(...);
template<class YUV_T, class RGB_T> int yuv4442RGB (...);
template<class YUV_T, class RGB_T> int yuv4442RGBA(...);

Parameter lists and defaults are completely identical to the corresponding _fixed entry points; only the function name drops _fixed.


Example

// float RGB → NV21 (float precision)
float rgb_f[1920*1080*3];
float y_f[1920*1080], uv_f[1920*540*2];

acl::cvtcolor::rgb2NV21<float, float>(
    rgb_f, y_f, uv_f, 1920, 1080);

Bayer Demosaic

Bayer raw image → RGB / RGBA. Supports 4 Bayer patterns (RGGB / GRBG / GBRG / BGGR).

Tier: Starter+
Channels: 1ch Bayer → 3ch RGB / 4ch RGBA
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T (CPP) uint8_t, uint16_t
T (NEON) uint8_t NEON-only

CPP Version: acl::cvtcolor::bayer2RGB / bayer2RGBA

template<class ST, class DT>
int bayer2RGB(
    const ST* bayerImage, DT* rgbImage,
    int width, int height,
    int bayerStride, int rgbStride,
    int borderMode = 1,
    int bayerDataBit = 8,
    int RGBDataBit = 8,
    acl::BayerPattern pattern = acl::BayerPattern::GBRG);

// RGBA output (4ch):
template<class ST, class DT>
int bayer2RGBA(
    const ST* bayerImage, DT* rgbaImage,
    int width, int height,
    int bayerStride, int rgbaStride,
    int borderMode = 1,
    int bayerDataBit = 8,
    int RGBDataBit = 8,
    acl::BayerPattern pattern = acl::BayerPattern::GBRG);
Parameter Type Meaning Default
bayerImage const ST* Input Bayer raw image non-null
rgbImage / rgbaImage DT* Output RGB / RGBA image non-null
width, height int Image size > 0, even
bayerStride, rgbStride / rgbaStride int Bytes per row 0 = auto
borderMode int 0 = replicate the inner ring; 1 = reflect_101 1
bayerDataBit int Effective Bayer data bits 8
RGBDataBit int Effective RGB data bits 8
pattern acl::BayerPattern Bayer mosaic pattern (RGGB / GRBG / GBRG / BGGR) GBRG

NEON Version: acl::neon::cvtcolor::bayer2RGB (uint8_t only, 3ch only)

int bayer2RGB(
    const uint8_t* bayerImage, uint8_t* rgbImage,
    int width, int height,
    acl::BayerPattern pattern,
    int bayerStride = 0, int rgbStride = 0);

NEON has no bayer2RGBA entry point, and borderMode is fixed to reflect_101.


Example

uint8_t bayer[1920*1080], rgb[1920*1080*3];

// NEON (runtime pattern)
acl::neon::cvtcolor::bayer2RGB(bayer, rgb, 1920, 1080,
    acl::BayerPattern::RGGB);

// CPP (u16 bayer → u8 RGB, RGGB pattern)
uint16_t bayer16[1920*1080];
acl::cvtcolor::bayer2RGB<uint16_t, uint8_t>(
    bayer16, rgb, 1920, 1080,
    /*bayerStride=*/0, /*rgbStride=*/0,
    /*borderMode=*/1, /*bayerDataBit=*/10, /*RGBDataBit=*/8,
    acl::BayerPattern::RGGB);

RGB ↔ HSV

Conversion between RGB/BGR and HSV.

Tier: Pro+
Channels: 3ch ↔ 3ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T uint8_t

CPP / NEON Signature (identical)

// CPP and NEON have identical names and signatures; only the namespace differs
int bgr2HSV(const uint8_t* bgrImage, uint8_t* hsvImage,
            int width, int height, int srcStride = 0, int dstStride = 0);
int rgb2HSV(const uint8_t* rgbImage, uint8_t* hsvImage, ...);
int hsv2BGR(const uint8_t* hsvImage, uint8_t* bgrImage, ...);   // CPP only

NEON provides only the two entry points bgr2HSV / rgb2HSV; there is no hsv2BGR. Use the CPP version for the reverse conversion.

Parameter Type Meaning Default
bgrImage / rgbImage / hsvImage const uint8_t* / uint8_t* input / output planes non-null
width, height int Image size > 0
srcStride, dstStride int Bytes per row 0 = auto

HSV encoding: H ∈ [0, 180] (OpenCV-compatible), S, V ∈ [0, 255].


Example

uint8_t rgb[1920*1080*3], hsv[1920*1080*3];

acl::neon::cvtcolor::rgb2HSV(rgb, hsv, 1920, 1080);

RGB ↔ Lab

Conversion between RGB/BGR and CIE Lab.

Tier: Pro+
Channels: 3ch ↔ 3ch
Inplace: not supported
Types:

Template parameter Allowed types Constraint
T uint8_t

CPP / NEON Signature (identical)

int bgr2Lab(const uint8_t* bgrImage, uint8_t* labImage,
            int width, int height, int srcStride = 0, int dstStride = 0);
int rgb2Lab(const uint8_t* rgbImage, uint8_t* labImage, ...);
int lab2BGR(const uint8_t* labImage, uint8_t* bgrImage, ...);   // CPP only

NEON provides only bgr2Lab / rgb2Lab; there is no lab2BGR.

Lab encoding: L ∈ [0, 255] (mapping for L* 0-100), a, b ∈ [0, 255] (centered on 128).


Example

uint8_t rgb[1920*1080*3], lab[1920*1080*3];
acl::neon::cvtcolor::rgb2Lab(rgb, lab, 1920, 1080);

gammaTransform

Gamma transform: dst = A * base * (src/base)^gamma; used for display gamma correction, exposure compression, etc.

Tier: Starter+
Channels: 1ch
Inplace: supported
Types:

Template parameter Allowed types Constraint
T {uint8_t, uint16_t}
GT (computation) ∈ {float, double}

CPP Signature

template<class T, class GT = float>
int gammaTransform(
    const T* srcImage, T* dstImage,
    int width, int height,
    int srcStride, int dstStride,
    const GT& gamma,
    int normalizeBase,
    bool if_round = false,
    const GT& A = GT{1});
Parameter Type Meaning Default
srcImage, dstImage const T* / T* input / output non-null
width, height int Image size > 0
srcStride, dstStride int Bytes per row required (0 = auto)
gamma GT Gamma exponent 2.2 (display) / 1/2.2 (inverse gamma)
normalizeBase int Base value used to normalize to [0, 1] u8: 255 / u16: 1023, etc.
if_round bool Whether to round the result (otherwise floor) false
A GT Linear scaling coefficient 1

Example

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

// Display gamma correction (2.2)
acl::cvtcolor::gammaTransform<uint8_t, float>(
    srcImage, dstImage, 1920, 1080, 0, 0, 2.2f, 255);

Clone this wiki locally