#include "ninox.h" static double scan_area(struct Image *,int,int,int,int); static void scale_area(struct Image *,int,int,int,int,double); static struct Image * _create_bmp_888(struct Image *in, int pattern); static unsigned char * _debayer_GBG(struct Image *in, unsigned char *data); static unsigned char * _debayer_RGR(struct Image *in, unsigned char *data); static unsigned char * _debayer_BGB(struct Image *in, unsigned char *data); static unsigned char * _debayer_GRG(struct Image *in, unsigned char *data); /* * Create a rgb image that is the same dimensions as the * given monochrome image, Init the data to empty */ static char *pstr[] = { "", "GBG", "RGR", "BGB", "GRG" }; static struct Image * _create_bmp_888(struct Image *in, int pattern) { char *ptr; struct Image *out = CreateImage(); char *buf = Malloc(strlen(in->dst_fname) + 32); struct bmp_info *bi = ZeroMalloc(sizeof(struct bmp_info)); out->type=IMG_BMP; out->width = in->dst_width = in->width; out->height = in->dst_height = in->height; out->depth = 24; bi->cmap_entries = 0; bi->cmap = NULL; out->info = bi; out->data = NULL; out->src_fname = strdup(""); // Change suffix to BMP and denote pattern strcpy(buf,in->dst_fname); ptr = buf + strlen(buf)-1; while(*ptr && *ptr != '.') --ptr; sprintf(ptr,"_%s.bmp",pstr[pattern]); out->dst_fname = buf; out->cutout.x1 = out->cutout.y1 = 0; out->cutout.x2 = in->width-1; out->cutout.y2 = in->height-1; out->data = ZeroMalloc(in->width * in->height * 3); return out; } #define LEFTRIGHT(ptr) (((int)(*(ptr-1)) + (int)(*(ptr+1)))/2) #define UPDOWN(ptr) (((int)(*(ptr-w)) + (int)(*(ptr+w)))/2) #define ORTHO(ptr) (((int)(*(ptr-w)) + (int)(*(ptr+w)) + ((int)(*(ptr-1)) + (int)(*(ptr+1))))/4) #define DIAG(ptr) (((int)(*(ptr-w-1)) + (int)(*(ptr+w+1)) + ((int)(*(ptr-w+1)) + (int)(*(ptr+w-1))))/4) #define GREEN(ptr) (((int)(*(ptr-w-1)) + (int)(*(ptr+w+1)) + (int)(*ptr) + ((int)(*(ptr-w+1)) + (int)(*(ptr+w-1))))/5) // Assume we are starting at (1,1) and omitting conversion of top and bottom row as well // as left and right edges. static unsigned char * _debayer_GBG(struct Image *in, unsigned char *odata) { int x,y; int w = in->width; int h = in->height; int r,g,b; unsigned char *ptr,*p; for(y=1; ydata + y * w + 1; p = odata + (y * w + 1) * 3; for(x=1; xwidth; int h = in->height; int r,g,b; unsigned char *ptr,*p; for(y=1; ydata + y * w + 1; p = odata + (y * w + 1) * 3; for(x=1; xwidth; int h = in->height; int r,g,b; unsigned char *ptr,*p; for(y=1; ydata + y * w + 1; p = odata + (y * w + 1) * 3; for(x=1; xwidth; int h = in->height; int r,g,b; unsigned char *ptr,*p; for(y=1; ydata + y * w + 1; p = odata + (y * w + 1) * 3; for(x=1; xdepth != 8) { // Have to convert the buffer depth img = ConvertToType(img, IMG_FIT, 8); need_destroy = 1; } // Create the skeleton of our output image, everything // is present except the rgb data new = _create_bmp_888(img,pattern); // Depending on our bayer pattern, generate the RGB data switch(pattern) { case BAYER_GBG: _debayer_GBG(img,new->data); break; case BAYER_RGR: _debayer_RGR(img,new->data); break; case BAYER_BGB: _debayer_BGB(img,new->data); break; case BAYER_GRG: _debayer_GRG(img,new->data); break; default: Print("DeBayer: unknown pattern %d\n",pattern); exit(0); break; } if (need_destroy) DestroyImage(img); return new; } // Scan the image looking for a Bayer pattern in the grey values. If found then it means that // our camera is looking through a bayer mask and we must boost the luminosity of the red and // blue pixels to match the green. int FixBayer8(struct Image *img) { int sx,sy,ey,ex; double s1,s2,s3,s4,m; double f; /* calculate a box to scan */ sx = 1; sy = 1; ex = img->width-2; ey = img->height-2; /* Scan diagonal area and calculate average luminosity */ m=0; s1 = scan_area(img,sx,sy,ex,ey); if (s1>m) m=s1; s2 = scan_area(img,sx,sy+1,ex,ey+1); if (s2>m) m=s2; s3 = scan_area(img,sx+1,sy+1,ex+1,ey+1); if (s3>m) m=s3; s4 = scan_area(img,sx+1,sy,ex+1,ey); if (s4>m) m=s4; // printf("lum %lf %lf %lf %lf\n",s1,s2,s3,s4); f = BayerBoost; if (m-s1 > 0.1) scale_area(img,sx,sy,ex,ey,m/s1 * f); if (m-s2 > 0.1) scale_area(img,sx,sy+1,ex,ey+1,m/s2 * f); if (m-s3 > 0.1) scale_area(img,sx+1,sy+1,ex+1,ey+1,m/s3 * f); if (m-s4 > 0.1) scale_area(img,sx+1,sy,ex+1,ey,m/s4 * f); return 1; } static double scan_area( struct Image *img, int x1, int y1, // top left corner of sample region int x2, int y2 // bottom right corner of sample region ) { unsigned char *buffer = img->data; double lum=0; int count=0; int x,y; int o; if (img->depth==24) { for(y=y1; y<=y2; y+=2) { o = (y * img->width + x1) * 3; for(x=x1; x<=x2; x+=2,o+=6) { if (buffer[o] > ThreshHold) { lum += buffer[o]; // This is wrong, should compute luminance count++; } } } } else if (img->depth==8) { for(y=y1; y<=y2; y+=2) { o = y * img->width + x1; for(x=x1; x<=x2; x+=2,o+=2) { if (buffer[o] > ThreshHold) { lum += buffer[o]; count++; } } } } else { Print("scan_area: depth %d not supported\n"); return 0; } if (count==0) { Print("oops - divide by zero in scan_area\n"); fflush(stderr); return 0; } return lum / (double) count; } static void scale_area( struct Image *img, int x1, int y1, // top left corner of sample region int x2, int y2, // bottom right corner of sample region double s // scale factor ) { unsigned char *buffer = img->data; int x,y; int o; double v; if (img->depth == 24) { for(y=y1; y<=y2; y+=2) { o = (y * img->width + x1) * 3; for(x=x1; x<=x2; x+=2,o+=6) { v = buffer[o]; v *= s; if (v>255) v=255; if (v<0) v=0; buffer[o] = (int)v; // Wrong, should scale according to luminance buffer[o+1] = (int)v; buffer[o+2] = (int)v; } } } else if (img->depth==8) { for(y=y1; y<=y2; y+=2) { o = y * img->width + x1; for(x=x1; x<=x2; x+=2,o+=2) { v = buffer[o]; v *= s; if (v>255) v=255; if (v<0) v=0; buffer[o] = (int)v; // Wrong, should scale according to luminance } } } }