/* Class which describes a single colour channel of an image in a generalized * way allowing for easy and accurate scaling to any size. These subclasses * of GImageComponent are ideal for de-bayerizing Bayer pattern images. * * Written by: Chris Studholme * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) * $Id: GICBayer.cpp,v 1.5 2003/05/28 02:30:01 cvs Exp $ */ #include #include #include #include "GICBayer.h" //#define SHOW_STATS #define MAXITTER 20 #define MINITTER 4 #define MINITTER_FAST 2 #define ITTER_INCR 1 template inline T MAX(T a, T b) { return (a>b ? a : b); } template inline T MAX(T a, T b, T c) { if (b>a) a=b; if (c>a) a=c; return a; } template inline T MAX(T a, T b, T c, T d) { if (b>a) a=b; if (c>a) a=c; if (d>a) a=d; return a; } template inline T MAX(T a, T b, T c, T d, T e, T f, T g, T h) { if (b>a) a=b; if (c>a) a=c; if (d>a) a=d; if (e>a) a=e; if (f>a) a=f; if (g>a) a=g; if (h>a) a=h; return a; } template inline T MIN(T a, T b) { return (a inline T MIN(T a, T b, T c) { if (b inline T MIN(T a, T b, T c, T d) { if (b inline T MIN(T a, T b, T c, T d, T e, T f, T g, T h) { if (b32767) return 32767; return x; } // returns c1 inline short extrapolate(short cmin, short cmax, short c2, short omin, short omax, short o1, short o2) { if (o1==o2) return c2; else if (o1o2)&&(o1>o3)) return MAX(c2,c3); else if ((o10) { gmin = MIN(gmin,tl[y*w+x-1]); gmax = MAX(gmax,tl[y*w+x-1]); if (x>1) { cmin = MIN(cmin,id[y*w+x-2]); cmax = MAX(cmax,id[y*w+x-2]); } } if (x0) { gmin = MIN(gmin,tl[y*w+x-w]); gmax = MAX(gmax,tl[y*w+x-w]); if (y>1) { cmin = MIN(cmin,id[(y-2)*w+x]); cmax = MAX(cmax,id[(y-2)*w+x]); } } if (y1) { pixel += extrapolate(gmin,gmax,tl[y*w+x-1],cmin,cmax,id[y*w+x],id[y*w+x-2]); ++count; } if (x1) { pixel += extrapolate(gmin,gmax,tl[(y-1)*w+x],cmin,cmax,id[y*w+x],id[(y-2)*w+x]); ++count; } if (y>4; } return error; } inline long green_error_middle(short* tl, short* id, int y, int w) { long error=0; if (y&1) { // right column int residule = (6*tl[y*w+w-1]+tl[(y-1)*w+w-1]+tl[(y+1)*w+w-1])/8 - id[y*w+w-1]; error += (residule*residule+8)>>4; } else { // left column int residule = (6*tl[y*w]+tl[(y-1)*w]+tl[(y+1)*w])/8 - id[y*w]; error += (residule*residule+8)>>4; } // middle pixels for (int x=2-(y&1); x>4; } return error; } inline long green_error_bottom(short* tl, short* id, int w, int h) { long error=0; for (int x=1; x>4; } return error; } GICBayer_Green::GICBayer_Green(const unsigned char* imagedata, int width, int height, float maxerr) : GImageComponent(width,height,maxerr) { /* initialize arrays */ short* id = new short[w*h]; for (int y=0; y1) green_make_up(tl,id,y-2,w,h); } green_make_up(tl,id,h-2,w,h); green_make_up(tl,id,h-1,w,h); /* main loop to calculate points */ int merror=(int)(maxerror*maxerror*128*128*w*h/2)>>4; long error; int itter=1; do { ++itter; error=0; // calculate better answer (edges) green_better_edges(tl,id,w,h); // do all three steps in one loop for better cache use for (int i=0; i=MINITTER) { if (i==1) // top row error += green_error_top(tl,id,w); else if (i>1) // middle rows error += green_error_middle(tl,id,i-1,w); } } // quit if we want it done fast if ((maxerr==-1)&&(itter>=MINITTER_FAST)) break; if (itter>=MINITTER) { // error (bottom row) error+= green_error_bottom(tl,id,w,h); // really aweful if (error<0) continue; // solution is good enough => quit if (error0) { gmin = MIN(gmin,gtl[y*w+x-w-1]); gmax = MAX(gmax,gtl[y*w+x-w-1]); rmin = MIN(rmin,tl[y*w+x-w-1]); rmax = MAX(rmax,tl[y*w+x-w-1]); } if (y0) { gmin = MIN(gmin,gtl[y*w+x+w-1]); gmax = MAX(gmax,gtl[y*w+x+w-1]); rmin = MIN(rmin,tl[y*w+x+w-1]); rmax = MAX(rmax,tl[y*w+x+w-1]); } } int count=1; int pixel = extrapolate(rmin,rmax,tl[y*w+x-w+1],gmin,gmax,gtl[y*w+x],gtl[y*w+x-w+1]); if (x>0) { pixel += extrapolate(rmin,rmax,tl[y*w+x-w-1],gmin,gmax,gtl[y*w+x],gtl[y*w+x-w-1]); ++count; } if (y0) { pixel += extrapolate(rmin,rmax,tl[y*w+x+w-1],gmin,gmax,gtl[y*w+x],gtl[y*w+x+w-1]); ++count; } } tl[y*w+x]=pixel/count; } } inline long red_error_top(short* tl, short* id, int w) { long error=0; for (int x=1; x>4; } return error; } inline long red_error_middle(short* tl, short* id, int y, int w) { long error=0; id += y*w/4; tl += y*w; // middle pixels for (int x=1; x>4; } // right column int residule = (6*tl[w-1]+tl[-1]+tl[2*w-1])/8 - id[w/2-1]; error += (residule*residule+8)>>4; return error; } inline void red_better_top(short* tl, short* id, int w, int h) { // top row for (int x=1; x>4); // main loop do { // do nitter/2 itterations in batch error=0; for (int head=0; head=0)&&(y0)) { if (y==0) error+=red_error_top(tl,id,w); else error+=red_error_middle(tl,id,y,w); } // calculate better answer if (y==0) red_better_top(tl,id,w,h); else red_better_middle(tl,id,y,w); } } } itter+=nitter/2; nitter=2*ITTER_INCR; // quit if we want it done fast if (merror<=0) break; // solution is good enough => quit if ((0<=error)&&(error0) { gmin = MIN(gmin,gtl[y*w+x-w-1]); gmax = MAX(gmax,gtl[y*w+x-w-1]); bmin = MIN(bmin,tl[y*w+x-w-1]); bmax = MAX(bmax,tl[y*w+x-w-1]); if (x0) { pixel += extrapolate(bmin,bmax,tl[y*w+x-w-1],gmin,gmax,gtl[y*w+x],gtl[y*w+x-w-1]); ++count; if (x>4; // middle pixels for (int x=2; x>4; } return error; } inline long blue_error_bottom(short* tl, short* id, int w, int h) { long error=0; id += (h-2)*w/4; tl += (h-1)*w; // bottom row for (int x=2; x>4; } return error; } GICBayer_Blue::GICBayer_Blue(const unsigned char* imagedata, int width, int height, GImageComponent& green, float maxerr) : GImageComponent(width,height,maxerr) { if ((green.getWidth()!=w)||(green.getHeight()!=h)) { fprintf(stderr,"GICBayer_Red: FATAL ERROR! green component has different dimensions\n"); return; } const short* gtl = green.getPointArray(); short* id = new short[w*h/4]; int itter=0; int nitter=2*(maxerr==-1?MINITTER_FAST:MINITTER); long error; int merror=(maxerr==-1?-1:((int)(maxerror*maxerror*128*128*w*h/4))>>4); // main loop do { // do nitter/2 itterations in batch error=0; for (int head=0; head=0)&&(y=0) { // calculate error if necessary if ((i==nitter-2)&&(merror>0)) { if (y quit if ((0<=error)&&(error