From 0307402a57949efe1f5eea31c224235b0cd4f673 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 2 Nov 2025 22:03:17 -0800 Subject: [PATCH] ports/alif: Add gamma correction to PAG7936 video. Gamma correction massively improves the PAG7936 image quality by increasing the image brightness. Brightness and contrast adjustment support is also exposed for future automatic control. --- lib/imlib/bayer.c | 15 ++++++++++++++- lib/imlib/imlib.h | 3 ++- lib/imlib/simd.h | 13 +++++++++++++ ports/alif/omv_csi.c | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/imlib/bayer.c b/lib/imlib/bayer.c index 7c45f6cf9..2b93a0423 100644 --- a/lib/imlib/bayer.c +++ b/lib/imlib/bayer.c @@ -559,6 +559,10 @@ static inline v128_t vdebayer_to_cr(vrgb_pixels_t pixels) { return pixels.r; } +// FIXME: This needs to be placed in the DTCM. .bss is in the DTCM on Alif. But, this is not portable. +// Move this to a proper DTCM section for other platforms. +static uint8_t gamma_lut[256]; + // In the case of vectors larger than 32-bits the pattern is repeated for every 32-bits. // // pixels.r = MSB [0, R1, 0, R0] LSB pixels where each pixel is 8-bits. @@ -569,6 +573,9 @@ static inline v128_t vdebayer_to_cr(vrgb_pixels_t pixels) { static inline vrgb_pixels_t vdebayer_apply_rb_gain(vrgb_pixels_t pixels, uint32_t red_gain, uint32_t blue_gain) { pixels.r = vusat_s16_narrow_u8_lo(pixels.r, vmul_n_u32(pixels.r, red_gain), 5); pixels.b = vusat_s16_narrow_u8_lo(pixels.b, vmul_n_u32(pixels.b, blue_gain), 5); + pixels.r = vldr_u8_gather(gamma_lut, pixels.r); + pixels.g = vldr_u8_gather(gamma_lut, pixels.g); + pixels.b = vldr_u8_gather(gamma_lut, pixels.b); return pixels; } @@ -2291,13 +2298,19 @@ static void vdebayer_rggb_to_rgb565_awb_quarter(image_t *src, image_t *dst, uint // GRAYSCALE: src->data == dst->data // RGB565: src->data == dst->data + image_size(src) // YUV422: Not supported -void imlib_debayer_image_awb(image_t *dst, image_t *src, bool fast, uint32_t r_out, uint32_t g_out, uint32_t b_out) { +void imlib_debayer_image_awb(image_t *dst, image_t *src, bool fast, uint32_t r_out, uint32_t g_out, uint32_t b_out, + float brightness, float contrast, float gamma) { uint32_t red_gain = IM_DIV(g_out * 32, r_out); red_gain = IM_MIN(red_gain, 128U); uint32_t blue_gain = IM_DIV(g_out * 32, b_out); blue_gain = IM_MIN(blue_gain, 128U); + for (int i = 0; i < 256; i++) { + int v = fast_roundf(((fast_powf(i * (1.0f / 255.0f), gamma) * contrast) + brightness) * 255.0f); + gamma_lut[i] = IM_CLAMP(v, 0, 255); + } + if (fast) { switch (src->pixfmt) { case PIXFORMAT_BAYER_BGGR: { diff --git a/lib/imlib/imlib.h b/lib/imlib/imlib.h index a3a87ff74..d622dd4e7 100644 --- a/lib/imlib/imlib.h +++ b/lib/imlib/imlib.h @@ -1207,7 +1207,8 @@ pixformat_t imlib_bayer_shift(pixformat_t pixfmt, int x, int y, bool transpose); void imlib_debayer_ycbcr(image_t *src, rectangle_t *roi, int8_t *Y0, int8_t *CB, int8_t *CR); void imlib_debayer_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src); void imlib_debayer_image(image_t *dst, image_t *src); -void imlib_debayer_image_awb(image_t *dst, image_t *src, bool fast, uint32_t r_out, uint32_t g_out, uint32_t b_out); +void imlib_debayer_image_awb(image_t *dst, image_t *src, bool fast, uint32_t r_out, uint32_t g_out, uint32_t b_out, + float brightness, float contrast, float gamma); // YUV Image Processing pixformat_t imlib_yuv_shift(pixformat_t pixfmt, int x); diff --git a/lib/imlib/simd.h b/lib/imlib/simd.h index ffc195c9e..d31e5adf9 100644 --- a/lib/imlib/simd.h +++ b/lib/imlib/simd.h @@ -1514,6 +1514,19 @@ static inline v128_t vldr_u8_pred(const uint8_t *p, v128_predicate_t pred) { #endif } +static inline v128_t vldr_u8_gather(const uint8_t *p, v128_t offsets) { + #if (__ARM_ARCH >= 8) + return (v128_t) vldrbq_gather_offset(p, offsets.u8); + #else + v128_t v0; + v0.u8[0] = *(p + offsets.u8[0]); + v0.u8[1] = *(p + offsets.u8[1]); + v0.u8[2] = *(p + offsets.u8[2]); + v0.u8[3] = *(p + offsets.u8[3]); + return v0; + #endif +} + static inline v128_t vldr_u8_widen_u32_gather_pred(const uint8_t *p, v128_t offsets, v128_predicate_t pred) { diff --git a/ports/alif/omv_csi.c b/ports/alif/omv_csi.c index 3b392abde..c4b0568c3 100644 --- a/ports/alif/omv_csi.c +++ b/ports/alif/omv_csi.c @@ -404,7 +404,7 @@ int alif_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) { } // Debayer frame. - imlib_debayer_image_awb(dst_image, &src_image, false, r_stat, g_stat, b_stat); + imlib_debayer_image_awb(dst_image, &src_image, false, r_stat, g_stat, b_stat, 0.0f, 1.0f, 0.5f); } return 0; }