diff options
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing')
5 files changed, 259 insertions, 554 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c deleted file mode 100644 index f4cc9922b..000000000 --- a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c +++ /dev/null @@ -1,244 +0,0 @@ -/* -# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com> -# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com> -# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com> - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "libv4lprocessing-priv.h" -#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ - -void bayer_normalize_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - unsigned char *buf_end = buf + width * height; - - while (buf < buf_end) { - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, struct v4lprocessing_data *data) -{ - int i, j, x1 = 0, x2 = 0, y1 = 0, y2 = 0; - float green_avg, x_avg, y_avg, avg_avg; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - x1 += *buf++; - x2 += *buf++; - } - for (j = 0; j < width; j += 2) { - y1 += *buf++; - y2 += *buf++; - } - } - - if (start_with_green) { - green_avg = (x1 + y2) / 2; - x_avg = x2; - y_avg = y1; - } else { - green_avg = (x2 + y1) / 2; - x_avg = x1; - y_avg = y2; - } - - avg_avg = (green_avg + x_avg + y_avg) / 3; - - data->comp1 = (avg_avg / green_avg) * 65536; - data->comp2 = (avg_avg / x_avg) * 65536; - data->comp3 = (avg_avg / y_avg) * 65536; -} - -void bayer_normalize_whitebalance_analyse(unsigned char *buf, int width, - int height, unsigned int pix_fmt, struct v4lprocessing_data *data) -{ - int i, j, value, max = 0, min = 255, n_fac, x1 = 0, x2 = 0, y1 = 0, y2 = 0; - float green_avg, x_avg, y_avg, avg_avg; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - x1 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - x2 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - for (j = 0; j < width; j += 2) { - y1 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - y2 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - } - - if (start_with_green) { - green_avg = (x1 + y2) / 2; - x_avg = x2; - y_avg = y1; - } else { - green_avg = (x2 + y1) / 2; - x_avg = x1; - y_avg = y2; - } - - n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - - avg_avg = (green_avg + x_avg + y_avg) / 3; - - data->comp1 = (avg_avg / green_avg) * n_fac; - data->comp2 = (avg_avg / x_avg) * n_fac; - data->comp3 = (avg_avg / y_avg) * n_fac; - - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) -#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) - -void bayer_normalize(unsigned char *buf, int width, - int height, struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } -} - -void bayer_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data) -{ - int i, j, value; - int limit = width * height; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - if (start_with_green) { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - } - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - } - } - } else { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - } - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - } - } - } -} - -void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data) -{ - int i, j, value; - int limit = width * height; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - if (start_with_green) { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - for (j = 0; j < width; j += 2) { - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - } - } else { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - for (j = 0; j < width; j += 2) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - } - } -} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h index f2aae373d..fb514d7f5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -23,67 +23,31 @@ #include "../control/libv4lcontrol.h" -#define V4L2PROCESSING_PROCESS_NONE 0x00 -#define V4L2PROCESSING_PROCESS_NORMALIZE 0x01 -#define V4L2PROCESSING_PROCESS_WHITEBALANCE 0x02 -#define V4L2PROCESSING_PROCESS_NORMALIZE_WHITEBALANCE 0x03 -#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE 0x01 -#define V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE 0x02 -#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE 0x03 -#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE 0x11 -#define V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE 0x12 -#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE 0x13 - #define V4L2PROCESSING_UPDATE_RATE 10 struct v4lprocessing_data { struct v4lcontrol_data *control; int do_process; - /* Provides the current type of processing */ - int process; - int norm_low_bound; - int norm_high_bound; + /* True if any of the lookup tables does not contain + linear 0-255 */ + int lookup_table_active; /* Counts the number of processed frames until a V4L2PROCESSING_UPDATE_RATE overflow happens */ - int processing_data_update; - /* Multiplication factors and offsets from the analyse functions */ - int comp1; - int comp2; - int comp3; - int comp4; - int offset1; - int offset2; + int lookup_table_update_counter; + /* RGB/BGR lookup tables */ + unsigned char comp1[256]; + unsigned char green[256]; + unsigned char comp2[256]; }; -/* Processing Bayer */ -void bayer_normalize_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); -void bayer_normalize_whitebalance_analyse(unsigned char *src_buffer, - int width, int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); -void bayer_normalize(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void bayer_whitebalance(unsigned char *src_buffer, int width, int height, - unsigned int pix_fmt, struct v4lprocessing_data *data); -void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); +struct v4lprocessing_filter { + /* Returns 1 if the filter is active */ + int (*active)(struct v4lprocessing_data *data); + /* Returns 1 if any of the lookup tables was changed */ + int (*calculate_lookup_tables)(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt); +}; -/* Processing RGB */ -void rgb_normalize_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_whitebalance_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_normalize_whitebalance_analyse(unsigned char *src_buffer, - int width, int height, struct v4lprocessing_data *data); -void rgb_normalize(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_whitebalance(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, struct v4lprocessing_data *data); +extern struct v4lprocessing_filter whitebalance_filter; #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index f986da02d..3a3802aab 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -28,6 +28,10 @@ #include "libv4lprocessing-priv.h" #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ +static struct v4lprocessing_filter *filters[] = { + &whitebalance_filter, +}; + struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control) { struct v4lprocessing_data *data = @@ -46,136 +50,130 @@ void v4lprocessing_destroy(struct v4lprocessing_data *data) free(data); } -static int v4lprocessing_get_process(struct v4lprocessing_data *data, - unsigned int pix_fmt) +int v4lprocessing_pre_processing(struct v4lprocessing_data *data) { - int process = V4L2PROCESSING_PROCESS_NONE; + int i; - switch(pix_fmt) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { - process |= V4L2PROCESSING_PROCESS_BAYER_NORMALIZE; - } - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { - process |= V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE; - } - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { - process |= V4L2PROCESSING_PROCESS_RGB_NORMALIZE; - } - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { - process |= V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE; - } - break; + data->do_process = 0; + for (i = 0; i < ARRAY_SIZE(filters); i++) { + if (filters[i]->active(data)) + data->do_process = 1; } - return process; + return data->do_process; } -static void v4lprocessing_update_processing_data( - struct v4lprocessing_data *data, - unsigned int pix_fmt, unsigned char *buf, unsigned int width, - unsigned int height) +static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) { - switch (data->process) { - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: - bayer_normalize_analyse(buf, width, height, data); - break; + int i; - case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: - bayer_whitebalance_analyse(buf, width, height, pix_fmt, data); - break; + for (i = 0; i < 256; i++) { + data->comp1[i] = i; + data->green[i] = i; + data->comp2[i] = i; + } - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: - bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data); - break; + data->lookup_table_active = 0; + for (i = 0; i < ARRAY_SIZE(filters); i++) { + if (filters[i]->active(data)) { + if (filters[i]->calculate_lookup_tables(data, buf, fmt)) + data->lookup_table_active = 1; + } + } +} + +static void v4lprocessing_do_processing(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) +{ + int x, y; - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: - rgb_normalize_analyse(buf, width, height, data); + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->green[*buf]; + buf++; + *buf = data->comp1[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->comp2[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } break; - case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: - rgb_whitebalance_analyse(buf, width, height, data); + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->comp1[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->green[*buf]; + buf++; + *buf = data->comp2[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } break; - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: - rgb_normalize_whitebalance_analyse(buf, width, height, data); + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + for (y = 0; y < fmt->fmt.pix.height; y++) { + for (x = 0; x < fmt->fmt.pix.width; x++) { + *buf = data->comp1[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + *buf = data->comp2[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width; + } break; } } -int v4lprocessing_pre_processing(struct v4lprocessing_data *data) -{ - data->do_process = - v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE) || - v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE); - - if (!data->do_process) - data->process = V4L2PROCESSING_PROCESS_NONE; - - return data->do_process; -} - void v4lprocessing_processing(struct v4lprocessing_data *data, unsigned char *buf, const struct v4l2_format *fmt) { - int low_bound, high_bound, process; - if (!data->do_process) return; - process = v4lprocessing_get_process(data, fmt->fmt.pix.pixelformat); - if (process == V4L2PROCESSING_PROCESS_NONE) { - return; - } - - low_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_LOW_BOUND); - high_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_HIGH_BOUND); - - if (process != data->process || low_bound != data->norm_low_bound || - high_bound != data->norm_high_bound) { - data->process = process; - data->norm_low_bound = low_bound; - data->norm_high_bound = high_bound; - data->processing_data_update = V4L2PROCESSING_UPDATE_RATE; + /* Do we support the current pixformat? */ + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + break; + default: + return; /* Non supported pix format */ } - if (data->processing_data_update == V4L2PROCESSING_UPDATE_RATE) { - data->processing_data_update = 0; - v4lprocessing_update_processing_data(data, fmt->fmt.pix.pixelformat, buf, fmt->fmt.pix.width, fmt->fmt.pix.height); + if (v4lcontrol_controls_changed(data->control) || + data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) { + v4lprocessing_update_lookup_tables(data, buf, fmt); + data->lookup_table_update_counter = 0; } else - data->processing_data_update++; - - switch (data->process) { - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: - bayer_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; - - case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: - bayer_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, data); - break; - - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: - bayer_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, - data); - break; - - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: - rgb_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; + data->lookup_table_update_counter++; - case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: - rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; + if (data->lookup_table_active) + v4lprocessing_do_processing(data, buf, fmt); - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: - rgb_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; - } data->do_process = 0; } diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c deleted file mode 100644 index 4e0fc3f4a..000000000 --- a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c +++ /dev/null @@ -1,156 +0,0 @@ -/* -# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com> -# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com> -# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com> - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "libv4lprocessing-priv.h" - -void rgb_normalize_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -void rgb_whitebalance_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, x = 0, y = 0, z = 0; - float x_avg, y_avg, z_avg, avg_avg; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - x += *buf++; - y += *buf++; - z += *buf++; - } - - x_avg = x; - y_avg = y; - z_avg = z; - avg_avg = (x_avg + y_avg + z_avg) / 3; - - data->comp1 = (avg_avg / x_avg) * 65536; - data->comp2 = (avg_avg / y_avg) * 65536; - data->comp3 = (avg_avg / z_avg) * 65536; -} - -void rgb_normalize_whitebalance_analyse(unsigned char *buf, - int width, int height, struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - int n_fac, wb_max, x = 0, y = 0, z = 0; - float x_avg, y_avg, z_avg, avg_avg; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - x += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - y += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - z += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - x_avg = x; - y_avg = y; - z_avg = z; - avg_avg = (x_avg + y_avg + z_avg) / 3; - - n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - - data->comp1 = (avg_avg / x_avg) * n_fac; - data->comp2 = (avg_avg / y_avg) * n_fac; - data->comp3 = (avg_avg / z_avg) * n_fac; - - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) -#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) - -void rgb_normalize(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + - data->offset2; - *buf++ = CLIP(value); - } -} - -void rgb_whitebalance(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - } -} - -void rgb_normalize_whitebalance(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int i, value; - int limit = width * height * 3; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } -} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c new file mode 100644 index 000000000..f5bfd961c --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c @@ -0,0 +1,143 @@ +/* +# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com> +# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com> +# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com> + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <syscall.h> +#include <unistd.h> +#include "libv4lprocessing.h" +#include "libv4lprocessing-priv.h" +#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ + +#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) + +static int whitebalance_active(struct v4lprocessing_data *data) { + return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); +} + +static int whitebalance_calculate_lookup_tables_bayer( + struct v4lprocessing_data *data, unsigned char *buf, + 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; + + for (y = 0; y < fmt->fmt.pix.height; y += 2) { + for (x = 0; x < fmt->fmt.pix.width; x += 2) { + a1 += *buf++; + a2 += *buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width; x += 2) { + b1 += *buf++; + b2 += *buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } + + if (starts_with_green) { + green_avg = (a1 + b2) / 512; + comp1_avg = a2 / 256; + comp2_avg = b1 / 256; + } else { + green_avg = (a2 + b1) / 512; + comp1_avg = a1 / 256; + comp2_avg = b2 / 256; + } + + 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); + } + + return 1; +} + +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; + + for (y = 0; y < fmt->fmt.pix.height; y++) { + for (x = 0; x < fmt->fmt.pix.width; x++) { + comp1_avg += *buf++; + green_avg += *buf++; + comp2_avg += *buf++; + } + 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; + + 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; +} + + +static int whitebalance_calculate_lookup_tables( + struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) +{ + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */ + return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1); + + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */ + return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0); + + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt); + } + + return 0; /* Should never happen */ +} + +struct v4lprocessing_filter whitebalance_filter = { + whitebalance_active, whitebalance_calculate_lookup_tables }; |