From: <ki...@us...> - 2008-04-23 02:24:42
|
Revision: 11119 http://gphoto.svn.sourceforge.net/gphoto/?rev=11119&view=rev Author: kilgota Date: 2008-04-22 19:24:47 -0700 (Tue, 22 Apr 2008) Log Message: ----------- camlibs/digigr8: AHD interpolation used, and white_balance() implemented Modified Paths: -------------- trunk/libgphoto2/camlibs/digigr8/ChangeLog trunk/libgphoto2/camlibs/digigr8/digi_postprocess.c trunk/libgphoto2/camlibs/digigr8/digigr8.h trunk/libgphoto2/camlibs/digigr8/library.c Modified: trunk/libgphoto2/camlibs/digigr8/ChangeLog =================================================================== --- trunk/libgphoto2/camlibs/digigr8/ChangeLog 2008-04-21 07:14:45 UTC (rev 11118) +++ trunk/libgphoto2/camlibs/digigr8/ChangeLog 2008-04-23 02:24:47 UTC (rev 11119) @@ -1,3 +1,8 @@ +2008-04-22 Theodore Kilgore <ki...@au...> + * digi_postprocess.c: white_balance() added + * library.c: gp_ahd_interpolate() used instead of gp_bayer_interpolate() + white_balance() hooked up. + 2008-01-23 Theodore Kilgore <ki...@au...> * library.c: camera_capture_preview() revised to be in line with recent revisions of gphoto2. Also digi_init() is now not called unless needed, Modified: trunk/libgphoto2/camlibs/digigr8/digi_postprocess.c =================================================================== --- trunk/libgphoto2/camlibs/digigr8/digi_postprocess.c 2008-04-21 07:14:45 UTC (rev 11118) +++ trunk/libgphoto2/camlibs/digigr8/digi_postprocess.c 2008-04-23 02:24:47 UTC (rev 11119) @@ -29,6 +29,7 @@ #include <gphoto2/gphoto2.h> #include <gphoto2/gphoto2-port.h> +#include <gamma.h> #include "digigr8.h" #define GP_MODULE "digigr8" @@ -75,7 +76,7 @@ cycles ++ ; if (cycles > 9) { GP_DEBUG ("Too many cycles?\n"); - return -1; + return GP_ERROR; } lookup = temp2 & 0xff; } @@ -87,7 +88,7 @@ } if (i == 16) { GP_DEBUG ("Illegal lookup value during decomp\n"); - return -1; + return GP_ERROR; } } cycles = 0; @@ -119,7 +120,7 @@ templine_red = malloc(width); if (!templine_red) { free(templine_red); - return -1; + return GP_ERROR; } for(i=0; i < width; i++){ templine_red[i] = 0x80; @@ -127,7 +128,7 @@ templine_green = malloc(width); if (!templine_green) { free(templine_green); - return -1; + return GP_ERROR; } for(i=0; i < width; i++){ templine_green[i] = 0x80; @@ -135,7 +136,7 @@ templine_blue = malloc(width); if (!templine_blue) { free(templine_blue); - return -1; + return GP_ERROR; } for(i=0; i < width; i++){ templine_blue[i] = 0x80; @@ -210,7 +211,7 @@ free(templine_green); free(templine_red); free(templine_blue); - return 0; + return GP_OK; } int @@ -241,7 +242,6 @@ #define GREEN(p,x,y,w) *((p)+3*((y)*(w)+(x))+1) #define BLUE(p,x,y,w) *((p)+3*((y)*(w)+(x))+2) -#define SWAP(a,b) {unsigned char t=(a); (a)=(b); (b)=t;} #define MINMAX(a,min,max) { (min)=MIN(min,a); (max)=MAX(max,a); } @@ -251,11 +251,13 @@ #ifndef MIN # define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +#ifndef CLAMP +#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) +#endif - int -digi_postprocess(CameraPrivateLibrary *priv, int width, int height, - unsigned char* rgb, int n) +digi_postprocess(int width, int height, + unsigned char* rgb) { int x,y, @@ -302,3 +304,185 @@ return GP_OK; } +/* ========= White Balance / Color Enhance / Gamma adjust (experimental) ========== + + 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 GP_OK; +} + +int +white_balance (unsigned char *data, unsigned int size, float saturation) +{ + 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 = 64; r < 192; r++) + { + x += htable_r[r]; + x += htable_g[r]; + x += htable_b[r]; + } + new_gamma = sqrt((double) (x * 1.5) / (double) (size * 3)); + 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); + gamma = new_gamma; + if (new_gamma < .70) gamma = 0.70; + if (new_gamma > 1.2) gamma = 1.2; + GP_DEBUG("Gamma correction = %1.2f\n", gamma); + gp_gamma_fill_table(gtable, gamma); + gp_gamma_correct_single(gtable,data,size); + if (saturation < .5 ) /* If so, exit now. */ + return GP_OK; + + /* ---------------- 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 >= 4.0) { + /* We need a little bit of control, here. If max_factor > 5 the photo + * was very dark, after all. + */ + if (2.0*b_factor < max_factor) + b_factor = max_factor/2.; + if (2.0*r_factor < max_factor) + r_factor = max_factor/2.; + if (2.0*g_factor < max_factor) + g_factor = max_factor/2.; + r_factor = (r_factor / max_factor) * 4.0; + g_factor = (g_factor / max_factor) * 4.0; + b_factor = (b_factor / max_factor) * 4.0; + } + + if (max_factor > 1.5) + saturation = 0; + 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 <= 1.4) { + for (x = 0; x < (size * 3); x += 3) + { + d = (data[x+0]<<8) * r_factor+8; + d >>=8; + if (d > 0xff) { d = 0xff; } + data[x+0] = d; + d = (data[x+1]<<8) * g_factor+8; + d >>=8; + if (d > 0xff) { d = 0xff; } + data[x+1] = d; + d = (data[x+2]<<8) * b_factor+8; + 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); + + 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 GP_OK; +} Modified: trunk/libgphoto2/camlibs/digigr8/digigr8.h =================================================================== --- trunk/libgphoto2/camlibs/digigr8/digigr8.h 2008-04-21 07:14:45 UTC (rev 11118) +++ trunk/libgphoto2/camlibs/digigr8/digigr8.h 2008-04-23 02:24:47 UTC (rev 11119) @@ -42,9 +42,15 @@ int digi_is_clip (CameraPrivateLibrary *, int entry); int digi_decompress (unsigned char *out_data, unsigned char *data, int w, int h); -int digi_postprocess (CameraPrivateLibrary *priv, - int width, int height, - unsigned char* rgb, int n); +int digi_postprocess (int width, int height, unsigned char* rgb); int digi_delete_all (GPPort *, CameraPrivateLibrary *priv); + +int +histogram (unsigned char *data, unsigned int size, int *htable_r, + int *htable_g, int *htable_b); +int +white_balance (unsigned char *data, unsigned int size, float saturation); + + #endif Modified: trunk/libgphoto2/camlibs/digigr8/library.c =================================================================== --- trunk/libgphoto2/camlibs/digigr8/library.c 2008-04-21 07:14:45 UTC (rev 11118) +++ trunk/libgphoto2/camlibs/digigr8/library.c 2008-04-23 02:24:47 UTC (rev 11119) @@ -88,7 +88,7 @@ int camera_id (CameraText *id) { - strcpy (id->text, "SQ905C chipset camera"); + strncpy (id->text, "SQ905C chipset camera",32); return GP_OK; } @@ -102,7 +102,7 @@ for (i = 0; models[i].name; i++) { memset (&a, 0, sizeof(a)); - strcpy (a.model, models[i].name); + strncpy (a.model, models[i].name,32); a.status = models[i].status; a.port = GP_PORT_USB; a.speed[0] = 0; @@ -126,10 +126,9 @@ { if(!camera->pl->init_done) digi_init (camera->port, camera->pl); - sprintf (summary->text,_("Your USB camera seems to have an SQ905C chipset.\n" - "The total number of pictures in it is %i\n" - ), - + snprintf (summary->text, 100, + ("Your USB camera seems to have an SQ905C chipset.\n" + "The total number of pictures in it is %i\n"), camera->pl->nb_entries); return GP_OK; @@ -137,7 +136,7 @@ static int camera_manual (Camera *camera, CameraText *manual, GPContext *context) { - strcpy(manual->text, + strncpy(manual->text, _( "For cameras with insides from S&Q Technologies, which have the \n" "USB Vendor ID 0x2770 and Product ID 0x905C, 0x9050, or 0x913D\n" @@ -150,7 +149,7 @@ "File uploading and deletion of individual photos by use of a\n" "software command are not supported by the hardware in these\n" "cameras.\n" - )); + ), 700); return (GP_OK); } @@ -158,8 +157,8 @@ static int camera_about (Camera *camera, CameraText *about, GPContext *context) { - strcpy (about->text, _("sq905C generic driver\n" - "Theodore Kilgore <ki...@au...>\n")); + strncpy (about->text, _("sq905C generic driver\n" + "Theodore Kilgore <ki...@au...>\n"),64); return GP_OK; } @@ -192,6 +191,7 @@ int w, h, b; int k, next; unsigned char comp_ratio; + unsigned char lighting; unsigned char *data = NULL; unsigned char *p_data = NULL; unsigned char *ppm; @@ -232,6 +232,7 @@ case 320: h = 240; break; default: h = 288; break; } + lighting = camera->pl->catalog[k*0x10+0x0b]; b = digi_get_data_size (camera->pl, k); if (!b) { GP_DEBUG("Photo number %i deleted?\n",k+1); @@ -269,7 +270,7 @@ status = GP_ERROR_NO_MEMORY; goto end; } - sprintf ((char *)ppm, + snprintf ((char *)ppm, 64, "P6\n" "# CREATOR: gphoto2, SQ905C library\n" "%d %d\n" @@ -287,13 +288,16 @@ digi_decompress (p_data, data, w, h); } else memcpy(p_data, data, w*h); - gp_bayer_decode (p_data, w , h , ptr, BAYER_TILE_BGGR); + gp_ahd_decode (p_data, w , h , ptr, BAYER_TILE_BGGR); free(p_data); - if (!comp_ratio) { + digi_postprocess (w, h, ptr); + if (lighting < 0x40) { + GP_DEBUG( + "Low light condition. Using default gamma. No white balance.\n"); gp_gamma_fill_table (gtable, .65); - gp_gamma_correct_single (gtable, ptr, w * h); - } - digi_postprocess(camera->pl,w, h, ptr, k); + gp_gamma_correct_single(gtable,ptr,w*h); + } else + white_balance (ptr, w*h, 1.1); 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); @@ -325,6 +329,7 @@ unsigned char *raw_data; unsigned char *frame_data; unsigned char *ppm, *ptr; + char lighting; unsigned char gtable[256]; char filename[14] = "digi_cap.ppm"; int size; @@ -336,6 +341,7 @@ gp_port_usb_msg_write (camera->port, 0x0c, 0x1440, 0x110f, NULL, 0); gp_port_read(camera->port, (char *)get_size, 0x50); GP_DEBUG("get_size[0x40] = 0x%x\n", get_size[0x40]); + lighting = get_size[0x48]; b = get_size[0x40]+(get_size[0x41]*0x100); GP_DEBUG("b = 0x%x\n", b); raw_data = malloc(b); @@ -354,7 +360,7 @@ /* Now put the data into a PPM image file. */ ppm = malloc (w * h * 3 + 256); if (!ppm) { return GP_ERROR_NO_MEMORY; } - sprintf ((char *)ppm, + snprintf ((char *)ppm, 64, "P6\n" "# CREATOR: gphoto2, SQ905C library\n" "%d %d\n" @@ -362,11 +368,15 @@ ptr = ppm + strlen ((char*)ppm); size = strlen ((char*)ppm) + (w * h * 3); GP_DEBUG ("size = %i\n", size); - gp_bayer_decode (frame_data, w , h , ptr, BAYER_TILE_BGGR); + gp_ahd_decode (frame_data, w , h , ptr, BAYER_TILE_BGGR); free(frame_data); - gp_gamma_fill_table (gtable, .65); - gp_gamma_correct_single (gtable, ptr, w * h); - + if (lighting < 0x40) { + GP_DEBUG( + "Low light condition. Using default gamma. No white balance.\n"); + gp_gamma_fill_table (gtable, .65); + gp_gamma_correct_single(gtable,ptr,w*h); + } else + white_balance (ptr, w*h, 1.1); 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); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |