summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c136
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);
}