diff options
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing')
5 files changed, 716 insertions, 0 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c new file mode 100644 index 000000000..f4cc9922b --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c @@ -0,0 +1,244 @@ +/* +# (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 new file mode 100644 index 000000000..f2aae373d --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -0,0 +1,89 @@ +/* +# (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 +*/ + +#ifndef __LIBV4LPROCESSING_PRIV_H +#define __LIBV4LPROCESSING_PRIV_H + +#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; + /* 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; +}; + +/* 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); + +/* 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); + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c new file mode 100644 index 000000000..d61c29275 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -0,0 +1,179 @@ +/* +# (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 */ + +struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control) +{ + struct v4lprocessing_data *data = + calloc(1, sizeof(struct v4lprocessing_data)); + + if (!data) + return NULL; + + data->control = control; + + return data; +} + +void v4lprocessing_destroy(struct v4lprocessing_data *data) +{ + free(data); +} + +static int v4lprocessing_get_process(struct v4lprocessing_data *data, + unsigned int pix_fmt) +{ + int process = V4L2PROCESSING_PROCESS_NONE; + + 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; + } + + return process; +} + +static void v4lprocessing_update_processing_data( + struct v4lprocessing_data *data, + unsigned int pix_fmt, unsigned char *buf, unsigned int width, + unsigned int height) +{ + switch (data->process) { + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: + bayer_normalize_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: + bayer_whitebalance_analyse(buf, width, height, pix_fmt, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: + bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: + rgb_normalize_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: + rgb_whitebalance_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: + rgb_normalize_whitebalance_analyse(buf, width, height, data); + 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); + + 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) { + data->process = process; + 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; + } + + 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); + } 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; + + case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: + rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); + break; + + 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/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h new file mode 100644 index 000000000..3c50d9fb9 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h @@ -0,0 +1,48 @@ +/* +# (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 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 +*/ + +#ifndef __LIBV4LPROCESSING_H +#define __LIBV4LPROCESSING_H + +/* These headers are not needed by us, but by linux/videodev2.h, + which is broken on some systems and doesn't include them itself :( */ +#include <sys/time.h> +#include <linux/types.h> +#include <linux/ioctl.h> +/* end broken header workaround includes */ +#include <linux/videodev2.h> + +struct v4lprocessing_data; +struct v4lcontrol_data; + +struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data *data); +void v4lprocessing_destroy(struct v4lprocessing_data *data); + +/* Prepare to process 1 frame, returns 1 if processing is necesary, + return 0 if no processing will be done */ +int v4lprocessing_pre_processing(struct v4lprocessing_data *data); + +/* Do the actual processing, this is a nop if v4lprocessing_pre_processing() + returned 0, or if called more then 1 time after a single + v4lprocessing_pre_processing() call. */ +void v4lprocessing_processing(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt); + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c new file mode 100644 index 000000000..4e0fc3f4a --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c @@ -0,0 +1,156 @@ +/* +# (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); + } +} |