From f50fb2ec5e87a8538befd8909ae6243711d49baa Mon Sep 17 00:00:00 2001 From: Theodore Kilgore Date: Sat, 15 Mar 2008 21:11:43 +0000 Subject: [PATCH] camlibs/mars: mars_white_balance function added git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@10989 67ed7778-7388-44ab-90cf-0a291f65f57c --- camlibs/mars/ChangeLog | 7 ++ camlibs/mars/README.mars | 12 ++- camlibs/mars/library.c | 14 ++- camlibs/mars/mars.c | 188 +++++++++++++++++++++++++++++++++++++++ camlibs/mars/mars.h | 5 +- 5 files changed, 216 insertions(+), 10 deletions(-) diff --git a/camlibs/mars/ChangeLog b/camlibs/mars/ChangeLog index 738b17a7f..87ab02c18 100644 --- a/camlibs/mars/ChangeLog +++ b/camlibs/mars/ChangeLog @@ -1,3 +1,10 @@ +2008-03-15 Theodore Kilgore + * mars.[c,h]: mars_white_balance() postprocessing function, based + upon work with Amauri Magagna done for an Aox camera. + * library.c: Added line to use mars_white_balance() + * README.mars: Description of what mars_white_balance() does. + + 2007-11-15 Theodore Kilgore * library.c: Added Sakar no. 1638x Cyberpix * README.mars: Description of new camera added. diff --git a/camlibs/mars/README.mars b/camlibs/mars/README.mars index 6b77ac395..5f87cedc6 100644 --- a/camlibs/mars/README.mars +++ b/camlibs/mars/README.mars @@ -1,6 +1,6 @@ MARS MR97310 STILLCAM DRIVER Copyright Theodore Kilgore April, 2004. Latest revision -of this README November 15, 2007. +of this README March 15, 2008. (Everything in libgphoto2/camlibs/mars is LGPL-licensed, including this README; see any of the source files for a more complete statement of the license.) @@ -228,6 +228,16 @@ you would like to see this file and it is not included for some reason in a "released" version of libgphoto2, then it can be found in the SVN source repository. +THE mars_white_balance() FUNCTION + +This function first of all does what its name implies. It also re-computes a +better gamma factor for the individual image, based upon internal +characteristics detected in the image, and does color enhancement. If you do +not like what it is doing, then you can turn it off by commenting out the line +in library.c where it is called, but I expect that the user will not want to +do that, because it seems to me that the image quality is much, much better. + + WARRANTY? Absolutely none. Remember, I did not sell you this software. I have written diff --git a/camlibs/mars/library.c b/camlibs/mars/library.c index 90b41fb56..cebeeb934 100644 --- a/camlibs/mars/library.c +++ b/camlibs/mars/library.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include @@ -298,8 +298,10 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, if (compressed) { mars_decompress (data + 12, p_data, w, h); } - else memcpy (p_data, data + 12, w*h); - gamma_factor = (float)data[7]/128.; + else memcpy (p_data, data + 12, w*h); + gamma_factor = sqrt((float)data[7]/100.); + if (gamma_factor <= .60) + gamma_factor = .60; free(data); /* Now put the data into a PPM image file. */ @@ -315,14 +317,10 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, ptr = ppm + strlen ((char *)ppm); size = strlen ((char *)ppm) + (w * h * 3); GP_DEBUG ("size = %i\n", size); - gp_bayer_decode (p_data, w , h , ptr, BAYER_TILE_RGGB); - - if (gamma_factor < .4) gamma_factor = .4; - if (gamma_factor > .6) gamma_factor = .6; gp_gamma_fill_table (gtable, gamma_factor ); gp_gamma_correct_single (gtable, ptr, w * h); - + mars_white_balance (ptr, w*h, 1.4, gamma_factor); gp_file_set_mime_type (file, GP_MIME_PPM); gp_file_set_name (file, filename); gp_file_set_data_and_size (file, (char *)ppm, size); diff --git a/camlibs/mars/mars.c b/camlibs/mars/mars.c index f444911f1..0627750ea 100644 --- a/camlibs/mars/mars.c +++ b/camlibs/mars/mars.c @@ -2,6 +2,8 @@ * * Copyright (C) 2004 Theodore Kilgore * + * white_balance() Copyright (C) 2008 Theodore Kilgore and Amauri Magagna. + * * This library 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 @@ -25,6 +27,7 @@ #include #include #include +#include #include #include @@ -343,3 +346,188 @@ mars_routine (Info *info, GPPort *port, char param, int n) return(c[0]); } + + +/* + * ========= White Balance / Color Enhance / Gamma adjust =============== + * + * Get histogram for each color plane + * Expand to reach 0.5% of white dots in image + * + * Get new histogram for each color plane + * Expand to reach 0.5% of black dots in image + * + * Get new histogram + * Calculate and apply gamma correction + * + * if not a dark image: + * For each dot, increases color separation + * + * ====================================================================== + */ + +int +histogram (unsigned char *data, unsigned int size, int *htable_r, int *htable_g, int *htable_b) +{ + int x; + /* Initializations */ + for (x = 0; x < 0x100; x++) { + htable_r[x] = 0; + htable_g[x] = 0; + htable_b[x] = 0; + } + /* Building the histograms */ + for (x = 0; x < (size * 3); x += 3) + { + htable_r[data[x+0]]++; /* red histogram */ + htable_g[data[x+1]]++; /* green histogram */ + htable_b[data[x+2]]++; /* blue histogram */ + } + return 0; +} + +int +mars_white_balance (unsigned char *data, unsigned int size, float saturation, + float image_gamma) +{ + int x, r, g, b, max, d; + double r_factor, g_factor, b_factor, max_factor; + int htable_r[0x100], htable_g[0x100], htable_b[0x100]; + unsigned char gtable[0x100]; + double new_gamma, gamma=1.0; + + /* ------------------- GAMMA CORRECTION ------------------- */ + + histogram(data, size, htable_r, htable_g, htable_b); + x = 1; + for (r = 48; r < 208; r++) + { + x += htable_r[r]; + x += htable_g[r]; + x += htable_r[r]; + } + new_gamma = sqrt((double) (x * 1.5) / (double) (size * 3)); + x=0; + GP_DEBUG("Provisional gamma correction = %1.2f\n", new_gamma); + /* Recalculate saturation factor for later use. */ + saturation=saturation*new_gamma*new_gamma; + GP_DEBUG("saturation = %1.2f\n", saturation); + if(new_gamma >= 1.0) + gamma = new_gamma; + else + gamma = image_gamma; + + GP_DEBUG("Gamma correction = %1.2f\n", gamma); + gp_gamma_fill_table(gtable, gamma); + + /* ---------------- BRIGHT DOTS ------------------- */ + max = size / 200; + histogram(data, size, htable_r, htable_g, htable_b); + + for (r=0xfe, x=0; (r > 32) && (x < max); r--) + x += htable_r[r]; + for (g=0xfe, x=0; (g > 32) && (x < max); g--) + x += htable_g[g]; + for (b=0xfe, x=0; (b > 32) && (x < max); b--) + x += htable_b[b]; + r_factor = (double) 0xfd / r; + g_factor = (double) 0xfd / g; + b_factor = (double) 0xfd / b; + + max_factor = r_factor; + if (g_factor > max_factor) max_factor = g_factor; + if (b_factor > max_factor) max_factor = b_factor; + + if (max_factor >= 2.5) { + r_factor = (r_factor / max_factor) * 2.5; + g_factor = (g_factor / max_factor) * 2.5; + b_factor = (b_factor / max_factor) * 2.5; + } + GP_DEBUG("White balance (bright): r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n", r, g, b, r_factor, g_factor, b_factor); + if (max_factor <= 2.5) { + for (x = 0; x < (size * 3); x += 3) + { + d = (data[x+0]<<8) * r_factor; + d >>=8; + if (d > 0xff) { d = 0xff; } + data[x+0] = d; + d = (data[x+1]<<8) * g_factor; + d >>=8; + if (d > 0xff) { d = 0xff; } + data[x+1] = d; + d = (data[x+2]<<8) * b_factor; + d >>=8; + if (d > 0xff) { d = 0xff; } + data[x+2] = d; + } + } + /* ---------------- DARK DOTS ------------------- */ + max = size / 200; /* 1/200 = 0.5% */ + histogram(data, size, htable_r, htable_g, htable_b); + + for (r=0, x=0; (r < 96) && (x < max); r++) + x += htable_r[r]; + for (g=0, x=0; (g < 96) && (x < max); g++) + x += htable_g[g]; + for (b=0, x=0; (b < 96) && (x < max); b++) + x += htable_b[b]; + + r_factor = (double) 0xfe / (0xff-r); + g_factor = (double) 0xfe / (0xff-g); + b_factor = (double) 0xfe / (0xff-b); + + max_factor = r_factor; + if (g_factor > max_factor) max_factor = g_factor; + if (b_factor > max_factor) max_factor = b_factor; + + if (max_factor >= 1.15) { + r_factor = (r_factor / max_factor) * 1.15; + g_factor = (g_factor / max_factor) * 1.15; + b_factor = (b_factor / max_factor) * 1.15; + } + GP_DEBUG( + "White balance (dark): r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n", + r, g, b, r_factor, g_factor, b_factor); + + for (x = 0; x < (size * 3); x += 3) + { + d = (int) 0xff08-(((0xff-data[x+0])<<8) * r_factor); + d >>= 8; + if (d < 0) { d = 0; } + data[x+0] = d; + d = (int) 0xff08-(((0xff-data[x+1])<<8) * g_factor); + d >>= 8; + if (d < 0) { d = 0; } + data[x+1] = d; + d = (int) 0xff08-(((0xff-data[x+2])<<8) * b_factor); + d >>= 8; + if (d < 0) { d = 0; } + data[x+2] = d; + } + + /* ------------------ COLOR ENHANCE ------------------ */ + + if(saturation > 0.0) { + for (x = 0; x < (size * 3); x += 3) + { + r = data[x+0]; g = data[x+1]; b = data[x+2]; + d = (int) (r + g + b) /3.; + if ( r > d ) + r = r + (int) ((r - d) * (0xff-r)/(0x100-d) * saturation); + else + r = r + (int) ((r - d) * (0xff-d)/(0x100-r) * saturation); + if (g > d) + g = g + (int) ((g - d) * (0xff-g)/(0x100-d) * saturation); + else + g = g + (int) ((g - d) * (0xff-d)/(0x100-g) * saturation); + if (b > d) + b = b + (int) ((b - d) * (0xff-b)/(0x100-d) * saturation); + else + b = b + (int) ((b - d) * (0xff-d)/(0x100-b) * saturation); + data[x+0] = CLAMP(r); + data[x+1] = CLAMP(g); + data[x+2] = CLAMP(b); + } + } + return 0; +} diff --git a/camlibs/mars/mars.h b/camlibs/mars/mars.h index cdd6cc56c..8341c3789 100644 --- a/camlibs/mars/mars.h +++ b/camlibs/mars/mars.h @@ -44,6 +44,9 @@ int mars_read_picture_data (Camera *camera, Info *info, GPPort *port, char *data, int size, int n); int mars_decompress (unsigned char *inp ,unsigned char *outp, int w, int h); - +int histogram (unsigned char *data, unsigned int size, int *htable_r, + int *htable_g, int *htable_b); +int mars_white_balance (unsigned char *data, unsigned int size, float saturation, + float image_gamma); #endif