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.
This commit is contained in:
Kwabena W. Agyeman 2025-11-02 22:03:17 -08:00
parent 4745e2999e
commit 0307402a57
4 changed files with 30 additions and 3 deletions

View File

@ -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: {

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}