diff options
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c')
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c index 64d20b3ff..5ee0cfaa8 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c @@ -27,10 +27,82 @@ #include "libv4lprocessing-priv.h" #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define CLIP256(color) (((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define CLIP(color, min, max) (((color)>(max))?(max):(((color)<(min))?(min):(color))) static int whitebalance_active(struct v4lprocessing_data *data) { - return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); + int wb; + + wb = v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); + if (!wb) { + /* Reset cached color averages */ + data->green_avg = 0; + } + + return wb; +} + +static int whitebalance_calculate_lookup_tables_generic( + struct v4lprocessing_data *data, int green_avg, int comp1_avg, int comp2_avg) +{ + int i, avg_avg; + const int max_step = 64; + + /* Clip averages (restricts maximum white balance correction) */ + green_avg = CLIP(green_avg, 512, 3072); + comp1_avg = CLIP(comp1_avg, 512, 3072); + comp2_avg = CLIP(comp2_avg, 512, 3072); + + /* First frame ? */ + if (data->green_avg == 0) { + data->green_avg = green_avg; + data->comp1_avg = comp1_avg; + data->comp2_avg = comp2_avg; + } else { + /* Slowly adjust the averages used for the correction, so that we + do not get a sudden change in colors */ + if (abs(data->green_avg - green_avg) > max_step) { + if (data->green_avg < green_avg) + data->green_avg += max_step; + else + data->green_avg -= max_step; + } + else + data->green_avg = green_avg; + + if (abs(data->comp1_avg - comp1_avg) > max_step) { + if (data->comp1_avg < comp1_avg) + data->comp1_avg += max_step; + else + data->comp1_avg -= max_step; + } + else + data->comp1_avg = comp1_avg; + + if (abs(data->comp2_avg - comp2_avg) > max_step) { + if (data->comp2_avg < comp2_avg) + data->comp2_avg += max_step; + else + data->comp2_avg -= max_step; + } + else + data->comp2_avg = comp2_avg; + } + + if (abs(data->green_avg - data->comp1_avg) < max_step && + abs(data->green_avg - data->comp2_avg) < max_step && + abs(data->comp1_avg - data->comp2_avg) < max_step) + return 0; + + avg_avg = (data->green_avg + data->comp1_avg + data->comp2_avg) / 3; + + for (i = 0; i < 256; i++) { + data->comp1[i] = CLIP256(data->comp1[i] * avg_avg / data->comp1_avg); + data->green[i] = CLIP256(data->green[i] * avg_avg / data->green_avg); + data->comp2[i] = CLIP256(data->comp2[i] * avg_avg / data->comp2_avg); + } + + return 1; } static int whitebalance_calculate_lookup_tables_bayer( @@ -38,7 +110,7 @@ static int whitebalance_calculate_lookup_tables_bayer( const struct v4l2_format *fmt, int starts_with_green) { int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0; - int green_avg, comp1_avg, comp2_avg, avg_avg; + int green_avg, comp1_avg, comp2_avg; for (y = 0; y < fmt->fmt.pix.height; y += 2) { for (x = 0; x < fmt->fmt.pix.width; x += 2) { @@ -54,37 +126,29 @@ static int whitebalance_calculate_lookup_tables_bayer( } if (starts_with_green) { - green_avg = (a1 + b2) / 512; - comp1_avg = a2 / 256; - comp2_avg = b1 / 256; + green_avg = a1 / 2 + b2 / 2; + comp1_avg = a2; + comp2_avg = b1; } else { - green_avg = (a2 + b1) / 512; - comp1_avg = a1 / 256; - comp2_avg = b2 / 256; + green_avg = a2 / 2 + b1 / 2; + comp1_avg = a1; + comp2_avg = b2; } - x = fmt->fmt.pix.width * fmt->fmt.pix.height / 64; - if (abs(green_avg - comp1_avg) < x && - abs(green_avg - comp2_avg) < x && - abs(comp1_avg - comp2_avg) < x) - return 0; - - avg_avg = (green_avg + comp1_avg + comp2_avg) / 3; - - for (x = 0; x < 256; x++) { - data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg); - data->green[x] = CLIP(data->green[x] * avg_avg / green_avg); - data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg); - } + /* Norm avg to ~ 0 - 4095 */ + green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; + comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; + comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64; - return 1; + return whitebalance_calculate_lookup_tables_generic(data, green_avg, + comp1_avg, comp2_avg); } static int whitebalance_calculate_lookup_tables_rgb( struct v4lprocessing_data *data, unsigned char *buf, const struct v4l2_format *fmt) { - int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0, avg_avg; + int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0; for (y = 0; y < fmt->fmt.pix.height; y++) { for (x = 0; x < fmt->fmt.pix.width; x++) { @@ -95,25 +159,13 @@ static int whitebalance_calculate_lookup_tables_rgb( buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3; } - x = fmt->fmt.pix.width * fmt->fmt.pix.height * 4; - if (abs(green_avg - comp1_avg) < x && - abs(green_avg - comp2_avg) < x && - abs(comp1_avg - comp2_avg) < x) - return 0; - - /* scale to avoid integer overflows */ - green_avg /= 256; - comp1_avg /= 256; - comp2_avg /= 256; - avg_avg = (green_avg + comp1_avg + comp2_avg) / 3; + /* Norm avg to ~ 0 - 4095 */ + green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; + comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; + comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16; - for (x = 0; x < 256; x++) { - data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg); - data->green[x] = CLIP(data->green[x] * avg_avg / green_avg); - data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg); - } - - return 1; + return whitebalance_calculate_lookup_tables_generic(data, green_avg, + comp1_avg, comp2_avg); } |