Files
rawTherapee/rtengine/amaze_interpolate_RT.cc
ffsup2 eef14f76dd Added dark frame subtraction
Moved debayer and preprocessing parameters to class ProcParams for every single image.
Added tab RAW for changing those parameters.
Progress bar shows only load step (work to do)
2010-08-19 00:37:53 +02:00

1018 lines
41 KiB
C++

////////////////////////////////////////////////////////////////
//
// AMaZE demosaic algorithm
// (Aliasing Minimization and Zipper Elimination)
//
// copyright (c) 2008-2010 Emil Martinec <ejmartin@uchicago.edu>
//
// incorporating ideas of Luis Sanz Rodrigues and Paul Lee
//
// code dated: May 27, 2010
//
// amaze_interpolate_RT.cc is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 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 General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////
void RawImageSource::amaze_demosaic_RT() {
#define SQR(x) ((x)*(x))
//#define MIN(a,b) ((a) < (b) ? (a) : (b))
//#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define LIM(x,min,max) MAX(min,MIN(x,max))
#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))
//#define CLIP(x) LIM(x,0,65535)
int width=W, height=H;
static const float clip_pt = 1/ri->defgain;
#define TS 512 // Tile size; the image is processed in square tiles to lower memory requirements and facilitate multi-threading
// local variables
//offset of R pixel within a Bayer quartet
int ex, ey;
//shifts of pointer value to access pixels in vertical and diagonal directions
static const int v1=TS, v2=2*TS, v3=3*TS, p1=-TS+1, p2=-2*TS+2, p3=-3*TS+3, m1=TS+1, m2=2*TS+2, m3=3*TS+3;
//neighborhood of a pixel
static const int nbr[5] = {-v2,-2,2,v2,0};
//tolerance to avoid dividing by zero
static const float eps=1e-5, epssq=1e-10; //tolerance to avoid dividing by zero
//adaptive ratios threshold
static const float arthresh=0.75;
//nyquist texture test threshold
static const float nyqthresh=0.5;
//diagonal interpolation test threshold
static const float pmthresh=0.25;
//factors for bounding interpolation in saturated regions
static const float lbd=1.0, ubd=1.0; //lbd=0.66, ubd=1.5 alternative values;
//gaussian on 5x5 quincunx, sigma=1.2
static const float gaussodd[4] = {0.14659727707323927f, 0.103592713382435f, 0.0732036125103057f, 0.0365543548389495f};
//gaussian on 5x5, sigma=1.2
static const float gaussgrad[6] = {0.07384411893421103f, 0.06207511968171489f, 0.0521818194747806f, \
0.03687419286733595f, 0.03099732204057846f, 0.018413194161458882f};
//gaussian on 3x3, sigma =0.7
static const float gauss1[3] = {0.3376688223162362f, 0.12171198028231786f, 0.04387081413862306f};
//gaussian on 5x5 alt quincunx, sigma=1.5
static const float gausseven[2] = {0.13719494435797422f, 0.05640252782101291f};
//guassian on quincunx grid
static const float gquinc[4] = {0.169917f, 0.108947f, 0.069855f, 0.0287182f};
volatile double progress = 0.0;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#pragma omp parallel
{
//position of top/left corner of the tile
int top, left;
// beginning of storage block for tile
char *buffer;
// rgb values
float (*rgb)[3];
// horizontal gradient
float (*delh);
// vertical gradient
float (*delv);
// square of delh
float (*delhsq);
// square of delv
float (*delvsq);
// gradient based directional weights for interpolation
float (*dirwts)[2];
// vertically interpolated color differences G-R, G-B
float (*vcd);
// horizontally interpolated color differences
float (*hcd);
// alternative vertical interpolation
float (*vcdalt);
// alternative horizontal interpolation
float (*hcdalt);
// square of vcd
float (*vcdsq);
// square of hcd
float (*hcdsq);
// square of average color difference
float (*cddiffsq);
// weight to give horizontal vs vertical interpolation
float (*hvwt);
// final interpolated color difference
float (*Dgrb)[2];
// gradient in plus (NE/SW) direction
float (*delp);
// gradient in minus (NW/SE) direction
float (*delm);
// diagonal interpolation of R+B
float (*rbint);
// horizontal curvature of interpolated G (used to refine interpolation in Nyquist texture regions)
float (*Dgrbh2);
// vertical curvature of interpolated G
float (*Dgrbv2);
// difference between up/down interpolations of G
float (*dgintv);
// difference between left/right interpolations of G
float (*dginth);
// diagonal (plus) color difference R-B or G1-G2
float (*Dgrbp1);
// diagonal (minus) color difference R-B or G1-G2
float (*Dgrbm1);
// square of diagonal color difference
float (*Dgrbpsq1);
// square of diagonal color difference
float (*Dgrbmsq1);
// tile raw data
float (*cfa);
// relative weight for combining plus and minus diagonal interpolations
float (*pmwt);
// interpolated color difference R-B in plus direction
float (*rbp);
// interpolated color difference R-B in minus direction
float (*rbm);
// nyquist texture flag 1=nyquist, 0=not nyquist
int (*nyquist);
// assign working space
buffer = (char *) malloc((34*sizeof(float)+sizeof(int))*TS*TS);
//merror(buffer,"amaze_interpolate()");
//memset(buffer,0,(34*sizeof(float)+sizeof(int))*TS*TS);
// rgb array
rgb = (float (*)[3]) buffer; //pointers to array
delh = (float (*)) (buffer + 3*sizeof(float)*TS*TS);
delv = (float (*)) (buffer + 4*sizeof(float)*TS*TS);
delhsq = (float (*)) (buffer + 5*sizeof(float)*TS*TS);
delvsq = (float (*)) (buffer + 6*sizeof(float)*TS*TS);
dirwts = (float (*)[2]) (buffer + 7*sizeof(float)*TS*TS);
vcd = (float (*)) (buffer + 9*sizeof(float)*TS*TS);
hcd = (float (*)) (buffer + 10*sizeof(float)*TS*TS);
vcdalt = (float (*)) (buffer + 11*sizeof(float)*TS*TS);
hcdalt = (float (*)) (buffer + 12*sizeof(float)*TS*TS);
vcdsq = (float (*)) (buffer + 13*sizeof(float)*TS*TS);
hcdsq = (float (*)) (buffer + 14*sizeof(float)*TS*TS);
cddiffsq = (float (*)) (buffer + 15*sizeof(float)*TS*TS);
hvwt = (float (*)) (buffer + 16*sizeof(float)*TS*TS);
Dgrb = (float (*)[2]) (buffer + 17*sizeof(float)*TS*TS);
delp = (float (*)) (buffer + 19*sizeof(float)*TS*TS);
delm = (float (*)) (buffer + 20*sizeof(float)*TS*TS);
rbint = (float (*)) (buffer + 21*sizeof(float)*TS*TS);
Dgrbh2 = (float (*)) (buffer + 22*sizeof(float)*TS*TS);
Dgrbv2 = (float (*)) (buffer + 23*sizeof(float)*TS*TS);
dgintv = (float (*)) (buffer + 24*sizeof(float)*TS*TS);
dginth = (float (*)) (buffer + 25*sizeof(float)*TS*TS);
Dgrbp1 = (float (*)) (buffer + 26*sizeof(float)*TS*TS);
Dgrbm1 = (float (*)) (buffer + 27*sizeof(float)*TS*TS);
Dgrbpsq1 = (float (*)) (buffer + 28*sizeof(float)*TS*TS);
Dgrbmsq1 = (float (*)) (buffer + 29*sizeof(float)*TS*TS);
cfa = (float (*)) (buffer + 30*sizeof(float)*TS*TS);
pmwt = (float (*)) (buffer + 31*sizeof(float)*TS*TS);
rbp = (float (*)) (buffer + 32*sizeof(float)*TS*TS);
rbm = (float (*)) (buffer + 33*sizeof(float)*TS*TS);
nyquist = (int (*)) (buffer + 34*sizeof(int)*TS*TS);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*double dt;
clock_t t1, t2;
clock_t t1_init, t2_init = 0;
clock_t t1_vcdhcd, t2_vcdhcd = 0;
clock_t t1_cdvar, t2_cdvar = 0;
clock_t t1_nyqtest, t2_nyqtest = 0;
clock_t t1_areainterp, t2_areainterp = 0;
clock_t t1_compare, t2_compare = 0;
clock_t t1_diag, t2_diag = 0;
clock_t t1_chroma, t2_chroma = 0;*/
// start
//if (verbose) fprintf (stderr,_("AMaZE interpolation ...\n"));
//t1 = clock();
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (plistener) {
plistener->setProgressStr ("AMaZE Demosaicing...");
plistener->setProgress (0.0);
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//determine GRBG coset; (ey,ex) is the offset of the R subarray
if (FC(0,0)==1) {//first pixel is G
if (FC(0,1)==0) {ey=0; ex=1;} else {ey=1; ex=0;}
} else {//first pixel is R or B
if (FC(0,0)==0) {ey=0; ex=0;} else {ey=1; ex=1;}
}
// Main algorithm: Tile loop
//#pragma omp parallel for shared(rawData,height,width,red,green,blue) private(top,left) schedule(dynamic)
//code is openmp ready; just have to pull local tile variable declarations inside the tile loop
#pragma omp for schedule(dynamic) nowait
for (top=-16; top < height; top += TS-32)
for (left=-16; left < width; left += TS-32) {
//location of tile bottom edge
int bottom = MIN( top+TS,height+16);
//location of tile right edge
int right = MIN(left+TS, width+16);
//tile width (=TS except for right edge of image)
int rr1 = bottom - top;
//tile height (=TS except for bottom edge of image)
int cc1 = right - left;
//tile vars
//counters for pixel location in the image
int row, col;
//min and max row/column in the tile
int rrmin, rrmax, ccmin, ccmax;
//counters for pixel location within the tile
int rr, cc;
//color index 0=R, 1=G, 2=B
int c;
//pointer counters within the tile
int indx, indx1;
//direction counter for nbrs[]
int dir;
//dummy indices
int i, j;
// +1 or -1
int sgn;
//color ratios in up/down/left/right directions
float cru, crd, crl, crr;
//adaptive weights for vertical/horizontal/plus/minus directions
float vwt, hwt, pwt, mwt;
//vertical and horizontal G interpolations
float Gintv, Ginth;
//G interpolated in vert/hor directions using adaptive ratios
float guar, gdar, glar, grar;
//G interpolated in vert/hor directions using Hamilton-Adams method
float guha, gdha, glha, grha;
//interpolated G from fusing left/right or up/down
float Ginthar, Ginthha, Gintvar, Gintvha;
//color difference (G-R or G-B) variance in up/down/left/right directions
float Dgrbvvaru, Dgrbvvard, Dgrbhvarl, Dgrbhvarr;
//gradients in various directions
float gradp, gradm, gradv, gradh, gradpm, gradhv;
//color difference variances in vertical and horizontal directions
float vcdvar, hcdvar, vcdvar1, hcdvar1, hcdaltvar, vcdaltvar;
//adaptive interpolation weight using variance of color differences
float varwt;
//adaptive interpolation weight using difference of left-right and up-down G interpolations
float diffwt;
//alternative adaptive weight for combining horizontal/vertical interpolations
float hvwtalt;
//temporary variables for combining interpolation weights at R and B sites
float vo, ve;
//interpolation of G in four directions
float gu, gd, gl, gr;
//variance of G in vertical/horizontal directions
float gvarh, gvarv;
//Nyquist texture test
float nyqtest;
//accumulators for Nyquist texture interpolation
float sumh, sumv, sumsqh, sumsqv, areawt;
//color ratios in diagonal directions
float crse, crnw, crne, crsw;
//color differences in diagonal directions
float rbse, rbnw, rbne, rbsw;
//adaptive weights for combining diagonal interpolations
float wtse, wtnw, wtsw, wtne;
//alternate weight for combining diagonal interpolations
float pmwtalt;
//variance of R-B in plus/minus directions
float rbvarp, rbvarm;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// rgb from input CFA data
// rgb values should be floating point number between 0 and 1
// after white balance multipliers are applied
// a 16 pixel border is added to each side of the image
// bookkeeping for borders
if (top<0) {rrmin=16;} else {rrmin=0;}
if (left<0) {ccmin=16;} else {ccmin=0;}
if (bottom>height) {rrmax=height-top;} else {rrmax=rr1;}
if (right>width) {ccmax=width-left;} else {ccmax=cc1;}
for (rr=rrmin; rr < rrmax; rr++)
for (row=rr+top, cc=ccmin; cc < ccmax; cc++) {
col = cc+left;
c = FC(rr,cc);
indx=row*width+col;
indx1=rr*TS+cc;
rgb[indx1][c] = (rawData[row][col])/65535.0f;
//rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation
cfa[indx1] = rgb[indx1][c];
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//fill borders
if (rrmin>0) {
for (rr=0; rr<16; rr++)
for (cc=ccmin; cc<ccmax; cc++) {
c = FC(rr,cc);
rgb[rr*TS+cc][c] = rgb[(32-rr)*TS+cc][c];
cfa[rr*TS+cc] = rgb[rr*TS+cc][c];
}
}
if (rrmax<rr1) {
for (rr=0; rr<16; rr++)
for (cc=ccmin; cc<ccmax; cc++) {
c=FC(rr,cc);
rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][left+cc])/65535.0f;
//rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+left+cc][c])/65535.0f;//for dcraw implementation
cfa[(rrmax+rr)*TS+cc] = rgb[(rrmax+rr)*TS+cc][c];
}
}
if (ccmin>0) {
for (rr=rrmin; rr<rrmax; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[rr*TS+cc][c] = rgb[rr*TS+32-cc][c];
cfa[rr*TS+cc] = rgb[rr*TS+cc][c];
}
}
if (ccmax<cc1) {
for (rr=rrmin; rr<rrmax; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[rr*TS+ccmax+cc][c] = (rawData[(top+rr)][(width-cc-2)])/65535.0f;
//rgb[rr*TS+ccmax+cc][c] = (image[(top+rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation
cfa[rr*TS+ccmax+cc] = rgb[rr*TS+ccmax+cc][c];
}
}
//also, fill the image corners
if (rrmin>0 && ccmin>0) {
for (rr=0; rr<16; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[(rr)*TS+cc][c] = (rawData[32-rr][32-cc])/65535.0f;
//rgb[(rr)*TS+cc][c] = (rgb[(32-rr)*TS+(32-cc)][c]);//for dcraw implementation
cfa[(rr)*TS+cc] = rgb[(rr)*TS+cc][c];
}
}
if (rrmax<rr1 && ccmax<cc1) {
for (rr=0; rr<16; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[(rrmax+rr)*TS+ccmax+cc][c] = (rawData[(height-rr-2)][(width-cc-2)])/65535.0f;
//rgb[(rrmax+rr)*TS+ccmax+cc][c] = (image[(height-rr-2)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation
cfa[(rrmax+rr)*TS+ccmax+cc] = rgb[(rrmax+rr)*TS+ccmax+cc][c];
}
}
if (rrmin>0 && ccmax<cc1) {
for (rr=0; rr<16; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[(rr)*TS+ccmax+cc][c] = (rawData[(32-rr)][(width-cc-2)])/65535.0f;
//rgb[(rr)*TS+ccmax+cc][c] = (image[(32-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation
cfa[(rr)*TS+ccmax+cc] = rgb[(rr)*TS+ccmax+cc][c];
}
}
if (rrmax<rr1 && ccmin>0) {
for (rr=0; rr<16; rr++)
for (cc=0; cc<16; cc++) {
c=FC(rr,cc);
rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][(32-cc)])/65535.0f;
//rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(32-cc)][c])/65535.0f;//for dcraw implementation
cfa[(rrmax+rr)*TS+cc] = rgb[(rrmax+rr)*TS+cc][c];
}
}
//end of border fill
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for (rr=1; rr < rr1-1; rr++)
for (cc=1, indx=(rr)*TS+cc; cc < cc1-1; cc++, indx++) {
delh[indx] = fabs(cfa[indx+1]-cfa[indx-1]);
delv[indx] = fabs(cfa[indx+v1]-cfa[indx-v1]);
delhsq[indx] = SQR(delh[indx]);
delvsq[indx] = SQR(delv[indx]);
delp[indx] = fabs(cfa[indx+p1]-cfa[indx-p1]);
delm[indx] = fabs(cfa[indx+m1]-cfa[indx-m1]);
}
for (rr=2; rr < rr1-2; rr++)
for (cc=2,indx=(rr)*TS+cc; cc < cc1-2; cc++, indx++) {
dirwts[indx][0] = eps+delv[indx+v1]+delv[indx-v1]+delv[indx];//+fabs(cfa[indx+v2]-cfa[indx-v2]);
//vert directional averaging weights
dirwts[indx][1] = eps+delh[indx+1]+delh[indx-1]+delh[indx];//+fabs(cfa[indx+2]-cfa[indx-2]);
//horizontal weights
if (FC(rr,cc)&1) {
//for later use in diagonal interpolation
//Dgrbp1[indx]=2*cfa[indx]-(cfa[indx-p1]+cfa[indx+p1]);
//Dgrbm1[indx]=2*cfa[indx]-(cfa[indx-m1]+cfa[indx+m1]);
Dgrbpsq1[indx]=(SQR(cfa[indx]-cfa[indx-p1])+SQR(cfa[indx]-cfa[indx+p1]));
Dgrbmsq1[indx]=(SQR(cfa[indx]-cfa[indx-m1])+SQR(cfa[indx]-cfa[indx+m1]));
}
}
//t2_init += clock()-t1_init;
// end of tile initialization
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//interpolate vertical and horizontal color differences
//t1_vcdhcd = clock();
for (rr=4; rr<rr1-4; rr++)
//for (cc=4+(FC(rr,2)&1),indx=rr*TS+cc,c=FC(rr,cc); cc<cc1-4; cc+=2,indx+=2) {
for (cc=4,indx=rr*TS+cc; cc<cc1-4; cc++,indx++) {
c=FC(rr,cc);
if (c&1) {sgn=-1;} else {sgn=1;}
//initialization of nyquist test
nyquist[indx]=0;
//preparation for diag interp
rbint[indx]=0;
//color ratios in each cardinal direction
cru = cfa[indx-v1]*(dirwts[indx-v2][0]+dirwts[indx][0])/(dirwts[indx-v2][0]*(eps+cfa[indx])+dirwts[indx][0]*(eps+cfa[indx-v2]));
crd = cfa[indx+v1]*(dirwts[indx+v2][0]+dirwts[indx][0])/(dirwts[indx+v2][0]*(eps+cfa[indx])+dirwts[indx][0]*(eps+cfa[indx+v2]));
crl = cfa[indx-1]*(dirwts[indx-2][1]+dirwts[indx][1])/(dirwts[indx-2][1]*(eps+cfa[indx])+dirwts[indx][1]*(eps+cfa[indx-2]));
crr = cfa[indx+1]*(dirwts[indx+2][1]+dirwts[indx][1])/(dirwts[indx+2][1]*(eps+cfa[indx])+dirwts[indx][1]*(eps+cfa[indx+2]));
guha=cfa[indx-v1]+0.5*(cfa[indx]-cfa[indx-v2]);
gdha=cfa[indx+v1]+0.5*(cfa[indx]-cfa[indx+v2]);
glha=cfa[indx-1]+0.5*(cfa[indx]-cfa[indx-2]);
grha=cfa[indx+1]+0.5*(cfa[indx]-cfa[indx+2]);
if (fabs(1-cru)<arthresh) {guar=cfa[indx]*cru;} else {guar=guha;}
if (fabs(1-crd)<arthresh) {gdar=cfa[indx]*crd;} else {gdar=gdha;}
if (fabs(1-crl)<arthresh) {glar=cfa[indx]*crl;} else {glar=glha;}
if (fabs(1-crr)<arthresh) {grar=cfa[indx]*crr;} else {grar=grha;}
hwt = dirwts[indx-1][1]/(dirwts[indx-1][1]+dirwts[indx+1][1]);
vwt = dirwts[indx-v1][0]/(dirwts[indx+v1][0]+dirwts[indx-v1][0]);
//interpolated G via adaptive weights of cardinal evaluations
Gintvar = vwt*gdar+(1-vwt)*guar;
Ginthar = hwt*grar+(1-hwt)*glar;
Gintvha = vwt*gdha+(1-vwt)*guha;
Ginthha = hwt*grha+(1-hwt)*glha;
//interpolated color differences
vcd[indx] = sgn*(Gintvar-cfa[indx]);
hcd[indx] = sgn*(Ginthar-cfa[indx]);
vcdalt[indx] = sgn*(Gintvha-cfa[indx]);
hcdalt[indx] = sgn*(Ginthha-cfa[indx]);
if (cfa[indx] > 0.8*clip_pt || Gintvha > 0.8*clip_pt || Ginthha > 0.8*clip_pt) {
//use HA if highlights are (nearly) clipped
guar=guha; gdar=gdha; glar=glha; grar=grha;
vcd[indx]=vcdalt[indx]; hcd[indx]=hcdalt[indx];
}
//differences of interpolations in opposite directions
dgintv[indx]=MIN(SQR(guha-gdha),SQR(guar-gdar));
dginth[indx]=MIN(SQR(glha-grha),SQR(glar-grar));
//dgintv[indx]=SQR(guar-gdar);
//dginth[indx]=SQR(glar-grar);
//vcdsq[indx] = SQR(vcd[indx]);
//hcdsq[indx] = SQR(hcd[indx]);
//cddiffsq[indx] = SQR(vcd[indx]-hcd[indx]);
}
//t2_vcdhcd += clock() - t1_vcdhcd;
//t1_cdvar = clock();
for (rr=4; rr<rr1-4; rr++)
//for (cc=4+(FC(rr,2)&1),indx=rr*TS+cc,c=FC(rr,cc); cc<cc1-4; cc+=2,indx+=2) {
for (cc=4,indx=rr*TS+cc; cc<cc1-4; cc++,indx++) {
c=FC(rr,cc);
hcdvar = 3*(SQR(hcd[indx-2])+SQR(hcd[indx])+SQR(hcd[indx+2]))-SQR(hcd[indx-2]+hcd[indx]+hcd[indx+2]);
hcdaltvar = 3*(SQR(hcdalt[indx-2])+SQR(hcdalt[indx])+SQR(hcdalt[indx+2]))-SQR(hcdalt[indx-2]+hcdalt[indx]+hcdalt[indx+2]);
vcdvar = 3*(SQR(vcd[indx-v2])+SQR(vcd[indx])+SQR(vcd[indx+v2]))-SQR(vcd[indx-v2]+vcd[indx]+vcd[indx+v2]);
vcdaltvar = 3*(SQR(vcdalt[indx-v2])+SQR(vcdalt[indx])+SQR(vcdalt[indx+v2]))-SQR(vcdalt[indx-v2]+vcdalt[indx]+vcdalt[indx+v2]);
//choose the smallest variance; this yields a smoother interpolation
if (hcdaltvar<hcdvar) hcd[indx]=hcdalt[indx];
if (vcdaltvar<vcdvar) vcd[indx]=vcdalt[indx];
//bound the interpolation in regions of high saturation
if (c&1) {
Ginth = -hcd[indx]+cfa[indx];//R or B
Gintv = -vcd[indx]+cfa[indx];//B or R
if (hcd[indx]>0) {
if (3*hcd[indx] > (Ginth+cfa[indx])) {
hcd[indx]=-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx];
} else {
hwt = 1-3*hcd[indx]/(eps+Ginth+cfa[indx]);
hcd[indx]=hwt*hcd[indx] + (1-hwt)*(-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx]);
}
}
if (vcd[indx]>0) {
if (3*vcd[indx] > (Gintv+cfa[indx])) {
vcd[indx]=-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx];
} else {
vwt = 1-3*vcd[indx]/(eps+Gintv+cfa[indx]);
vcd[indx]=vwt*vcd[indx] + (1-vwt)*(-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx]);
}
}
if (Ginth > clip_pt) hcd[indx]=-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx];//for RT implementation
if (Gintv > clip_pt) vcd[indx]=-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx];
//if (Ginth > pre_mul[c]) hcd[indx]=-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx];//for dcraw implementation
//if (Gintv > pre_mul[c]) vcd[indx]=-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx];
} else {
Ginth = hcd[indx]+cfa[indx];//interpolated G
Gintv = vcd[indx]+cfa[indx];
if (hcd[indx]<0) {
if (3*hcd[indx] < -(Ginth+cfa[indx])) {
hcd[indx]=ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx];
} else {
hwt = 1+3*hcd[indx]/(eps+Ginth+cfa[indx]);
hcd[indx]=hwt*hcd[indx] + (1-hwt)*(ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx]);
}
}
if (vcd[indx]<0) {
if (3*vcd[indx] < -(Gintv+cfa[indx])) {
vcd[indx]=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx];
} else {
vwt = 1+3*vcd[indx]/(eps+Gintv+cfa[indx]);
vcd[indx]=vwt*vcd[indx] + (1-vwt)*(ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx]);
}
}
if (Ginth > clip_pt) hcd[indx]=ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx];//for RT implementation
if (Gintv > clip_pt) vcd[indx]=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx];
//if (Ginth > pre_mul[c]) hcd[indx]=ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx];//for dcraw implementation
//if (Gintv > pre_mul[c]) vcd[indx]=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx];
}
vcdsq[indx] = SQR(vcd[indx]);
hcdsq[indx] = SQR(hcd[indx]);
cddiffsq[indx] = SQR(vcd[indx]-hcd[indx]);
}
for (rr=6; rr<rr1-6; rr++)
for (cc=6+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-6; cc+=2,indx+=2) {
//compute color difference variances in cardinal directions
Dgrbvvaru = 4*(vcdsq[indx]+vcdsq[indx-v1]+vcdsq[indx-v2]+vcdsq[indx-v3])-SQR(vcd[indx]+vcd[indx-v1]+vcd[indx-v2]+vcd[indx-v3]);
Dgrbvvard = 4*(vcdsq[indx]+vcdsq[indx+v1]+vcdsq[indx+v2]+vcdsq[indx+v3])-SQR(vcd[indx]+vcd[indx+v1]+vcd[indx+v2]+vcd[indx+v3]);
Dgrbhvarl = 4*(hcdsq[indx]+hcdsq[indx-1]+hcdsq[indx-2]+hcdsq[indx-3])-SQR(hcd[indx]+hcd[indx-1]+hcd[indx-2]+hcd[indx-3]);
Dgrbhvarr = 4*(hcdsq[indx]+hcdsq[indx+1]+hcdsq[indx+2]+hcdsq[indx+3])-SQR(hcd[indx]+hcd[indx+1]+hcd[indx+2]+hcd[indx+3]);
hwt = dirwts[indx-1][1]/(dirwts[indx-1][1]+dirwts[indx+1][1]);
vwt = dirwts[indx-v1][0]/(dirwts[indx+v1][0]+dirwts[indx-v1][0]);
vcdvar = epssq+vwt*Dgrbvvard+(1-vwt)*Dgrbvvaru;
hcdvar = epssq+hwt*Dgrbhvarr+(1-hwt)*Dgrbhvarl;
//vcdvar = 5*(vcdsq[indx]+vcdsq[indx-v1]+vcdsq[indx-v2]+vcdsq[indx+v1]+vcdsq[indx+v2])-SQR(vcd[indx]+vcd[indx-v1]+vcd[indx-v2]+vcd[indx+v1]+vcd[indx+v2]);
//hcdvar = 5*(hcdsq[indx]+hcdsq[indx-1]+hcdsq[indx-2]+hcdsq[indx+1]+hcdsq[indx+2])-SQR(hcd[indx]+hcd[indx-1]+hcd[indx-2]+hcd[indx+1]+hcd[indx+2]);
//compute fluctuations in up/down and left/right interpolations of colors
Dgrbvvaru = (dgintv[indx])+(dgintv[indx-v1])+(dgintv[indx-v2]);
Dgrbvvard = (dgintv[indx])+(dgintv[indx+v1])+(dgintv[indx+v2]);
Dgrbhvarl = (dginth[indx])+(dginth[indx-1])+(dginth[indx-2]);
Dgrbhvarr = (dginth[indx])+(dginth[indx+1])+(dginth[indx+2]);
vcdvar1 = epssq+vwt*Dgrbvvard+(1-vwt)*Dgrbvvaru;
hcdvar1 = epssq+hwt*Dgrbhvarr+(1-hwt)*Dgrbhvarl;
//determine adaptive weights for G interpolation
varwt=hcdvar/(vcdvar+hcdvar);
diffwt=hcdvar1/(vcdvar1+hcdvar1);
//if both agree on interpolation direction, choose the one with strongest directional discrimination;
//otherwise, choose the u/d and l/r difference fluctuation weights
if ((0.5-varwt)*(0.5-diffwt)>0 && fabs(0.5-diffwt)<fabs(0.5-varwt)) {hvwt[indx]=varwt;} else {hvwt[indx]=diffwt;}
//hvwt[indx]=varwt;
}
//t2_cdvar += clock() - t1_cdvar;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Nyquist test
//t1_nyqtest = clock();
for (rr=6; rr<rr1-6; rr++)
for (cc=6+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-6; cc+=2,indx+=2) {
//nyquist texture test: ask if difference of vcd compared to hcd is larger or smaller than RGGB gradients
nyqtest = (gaussodd[0]*cddiffsq[indx]+ \
gaussodd[1]*(cddiffsq[indx-m1]+cddiffsq[indx+p1]+ \
cddiffsq[indx-p1]+cddiffsq[indx+m1])+ \
gaussodd[2]*(cddiffsq[indx-v2]+cddiffsq[indx-2]+ \
cddiffsq[indx+2]+cddiffsq[indx+v2])+ \
gaussodd[3]*(cddiffsq[indx-m2]+cddiffsq[indx+p2]+ \
cddiffsq[indx-p2]+cddiffsq[indx+m2]));
nyqtest -= nyqthresh*(gaussgrad[0]*(delhsq[indx]+delvsq[indx])+ \
gaussgrad[1]*(delhsq[indx-v1]+delvsq[indx-v1]+delhsq[indx+1]+delvsq[indx+1]+ \
delhsq[indx-1]+delvsq[indx-1]+delhsq[indx+v1]+delvsq[indx+v1])+ \
gaussgrad[2]*(delhsq[indx-m1]+delvsq[indx-m1]+delhsq[indx+p1]+delvsq[indx+p1]+ \
delhsq[indx-p1]+delvsq[indx-p1]+delhsq[indx+m1]+delvsq[indx+m1])+ \
gaussgrad[3]*(delhsq[indx-v2]+delvsq[indx-v2]+delhsq[indx-2]+delvsq[indx-2]+ \
delhsq[indx+2]+delvsq[indx+2]+delhsq[indx+v2]+delvsq[indx+v2])+ \
gaussgrad[4]*(delhsq[indx-2*TS-1]+delvsq[indx-2*TS-1]+delhsq[indx-2*TS+1]+delvsq[indx-2*TS+1]+ \
delhsq[indx-TS-2]+delvsq[indx-TS-2]+delhsq[indx-TS+2]+delvsq[indx-TS+2]+ \
delhsq[indx+TS-2]+delvsq[indx+TS-2]+delhsq[indx+TS+2]+delvsq[indx-TS+2]+ \
delhsq[indx+2*TS-1]+delvsq[indx+2*TS-1]+delhsq[indx+2*TS+1]+delvsq[indx+2*TS+1])+ \
gaussgrad[5]*(delhsq[indx-m2]+delvsq[indx-m2]+delhsq[indx+p2]+delvsq[indx+p2]+ \
delhsq[indx-p2]+delvsq[indx-p2]+delhsq[indx+m2]+delvsq[indx+m2]));
if (nyqtest>0) {nyquist[indx]=1;}//nyquist=1 for nyquist region
}
for (rr=8; rr<rr1-8; rr++)
for (cc=8+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-8; cc+=2,indx+=2) {
areawt=(nyquist[indx-v2]+nyquist[indx-m1]+nyquist[indx+p1]+ \
nyquist[indx-2]+nyquist[indx]+nyquist[indx+2]+ \
nyquist[indx-p1]+nyquist[indx+m1]+nyquist[indx+v2]);
//if most of your neighbors are named Nyquist, it's likely that you're one too
if (areawt>4) nyquist[indx]=1;
//or not
if (areawt<4) nyquist[indx]=0;
}
//t2_nyqtest += clock() - t1_nyqtest;
// end of Nyquist test
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// in areas of Nyquist texture, do area interpolation
//t1_areainterp = clock();
for (rr=8; rr<rr1-8; rr++)
for (cc=8+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-8; cc+=2,indx+=2) {
if (nyquist[indx]) {
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// area interpolation
sumh=sumv=sumsqh=sumsqv=areawt=0;
for (i=-6; i<7; i+=2)
for (j=-6; j<7; j+=2) {
indx1=(rr+i)*TS+cc+j;
if (nyquist[indx1]) {
sumh += cfa[indx1]-0.5*(cfa[indx1-1]+cfa[indx1+1]);
sumv += cfa[indx1]-0.5*(cfa[indx1-v1]+cfa[indx1+v1]);
sumsqh += 0.5*(SQR(cfa[indx1]-cfa[indx1-1])+SQR(cfa[indx1]-cfa[indx1+1]));
sumsqv += 0.5*(SQR(cfa[indx1]-cfa[indx1-v1])+SQR(cfa[indx1]-cfa[indx1+v1]));
areawt +=1;
}
}
//horizontal and vertical color differences, and adaptive weight
hcdvar=epssq+MAX(0, areawt*sumsqh-sumh*sumh);
vcdvar=epssq+MAX(0, areawt*sumsqv-sumv*sumv);
hvwt[indx]=hcdvar/(vcdvar+hcdvar);
// end of area interpolation
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//t2_areainterp += clock() - t1_areainterp;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//populate G at R/B sites
for (rr=8; rr<rr1-8; rr++)
for (cc=8+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-8; cc+=2,indx+=2) {
//first ask if one gets more directional discrimination from nearby B/R sites
hvwtalt = 0.25*(hvwt[indx-m1]+hvwt[indx+p1]+hvwt[indx-p1]+hvwt[indx+m1]);
vo=fabs(0.5-hvwt[indx]);
ve=fabs(0.5-hvwtalt);
if (vo<ve) {hvwt[indx]=hvwtalt;}//a better result was obtained from the neighbors
Dgrb[indx][0] = (hcd[indx]*(1-hvwt[indx]) + vcd[indx]*hvwt[indx]);//evaluate color differences
//if (hvwt[indx]<0.5) Dgrb[indx][0]=hcd[indx];
//if (hvwt[indx]>0.5) Dgrb[indx][0]=vcd[indx];
rgb[indx][1] = cfa[indx] + Dgrb[indx][0];//evaluate G (finally!)
//local curvature in G (preparation for nyquist refinement step)
if (nyquist[indx]) {
Dgrbh2[indx] = SQR(rgb[indx][1] - 0.5*(rgb[indx-1][1]+rgb[indx+1][1]));
Dgrbv2[indx] = SQR(rgb[indx][1] - 0.5*(rgb[indx-v1][1]+rgb[indx+v1][1]));
} else {
Dgrbh2[indx] = Dgrbv2[indx] = 0;
}
}
//end of standard interpolation
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// refine Nyquist areas using G curvatures
for (rr=8; rr<rr1-8; rr++)
for (cc=8+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-8; cc+=2,indx+=2) {
if (nyquist[indx]) {
//local averages (over Nyquist pixels only) of G curvature squared
gvarh = epssq + (gquinc[0]*Dgrbh2[indx]+ \
gquinc[1]*(Dgrbh2[indx-m1]+Dgrbh2[indx+p1]+Dgrbh2[indx-p1]+Dgrbh2[indx+m1])+ \
gquinc[2]*(Dgrbh2[indx-v2]+Dgrbh2[indx-2]+Dgrbh2[indx+2]+Dgrbh2[indx+v2])+ \
gquinc[3]*(Dgrbh2[indx-m2]+Dgrbh2[indx+p2]+Dgrbh2[indx-p2]+Dgrbh2[indx+m2]));
gvarv = epssq + (gquinc[0]*Dgrbv2[indx]+ \
gquinc[1]*(Dgrbv2[indx-m1]+Dgrbv2[indx+p1]+Dgrbv2[indx-p1]+Dgrbv2[indx+m1])+ \
gquinc[2]*(Dgrbv2[indx-v2]+Dgrbv2[indx-2]+Dgrbv2[indx+2]+Dgrbv2[indx+v2])+ \
gquinc[3]*(Dgrbv2[indx-m2]+Dgrbv2[indx+p2]+Dgrbv2[indx-p2]+Dgrbv2[indx+m2]));
//use the results as weights for refined G interpolation
Dgrb[indx][0] = (hcd[indx]*gvarv + vcd[indx]*gvarh)/(gvarv+gvarh);
rgb[indx][1] = cfa[indx] + Dgrb[indx][0];
}
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//t1_diag = clock();
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// diagonal interpolation correction
for (rr=8; rr<rr1-8; rr++)
for (cc=8+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-8; cc+=2,indx+=2) {
rbvarp = epssq + (gausseven[0]*(Dgrbpsq1[indx-v1]+Dgrbpsq1[indx-1]+Dgrbpsq1[indx+1]+Dgrbpsq1[indx+v1]) + \
gausseven[1]*(Dgrbpsq1[indx-v2-1]+Dgrbpsq1[indx-v2+1]+Dgrbpsq1[indx-2-v1]+Dgrbpsq1[indx+2-v1]+ \
Dgrbpsq1[indx-2+v1]+Dgrbpsq1[indx+2+v1]+Dgrbpsq1[indx+v2-1]+Dgrbpsq1[indx+v2+1]));
//rbvarp -= SQR( (gausseven[0]*(Dgrbp1[indx-v1]+Dgrbp1[indx-1]+Dgrbp1[indx+1]+Dgrbp1[indx+v1]) + \
gausseven[1]*(Dgrbp1[indx-v2-1]+Dgrbp1[indx-v2+1]+Dgrbp1[indx-2-v1]+Dgrbp1[indx+2-v1]+ \
Dgrbp1[indx-2+v1]+Dgrbp1[indx+2+v1]+Dgrbp1[indx+v2-1]+Dgrbp1[indx+v2+1])));
rbvarm = epssq + (gausseven[0]*(Dgrbmsq1[indx-v1]+Dgrbmsq1[indx-1]+Dgrbmsq1[indx+1]+Dgrbmsq1[indx+v1]) + \
gausseven[1]*(Dgrbmsq1[indx-v2-1]+Dgrbmsq1[indx-v2+1]+Dgrbmsq1[indx-2-v1]+Dgrbmsq1[indx+2-v1]+ \
Dgrbmsq1[indx-2+v1]+Dgrbmsq1[indx+2+v1]+Dgrbmsq1[indx+v2-1]+Dgrbmsq1[indx+v2+1]));
//rbvarm -= SQR( (gausseven[0]*(Dgrbm1[indx-v1]+Dgrbm1[indx-1]+Dgrbm1[indx+1]+Dgrbm1[indx+v1]) + \
gausseven[1]*(Dgrbm1[indx-v2-1]+Dgrbm1[indx-v2+1]+Dgrbm1[indx-2-v1]+Dgrbm1[indx+2-v1]+ \
Dgrbm1[indx-2+v1]+Dgrbm1[indx+2+v1]+Dgrbm1[indx+v2-1]+Dgrbm1[indx+v2+1])));
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//diagonal color ratios
crse=2*(cfa[indx+m1])/(eps+cfa[indx]+(cfa[indx+m2]));
crnw=2*(cfa[indx-m1])/(eps+cfa[indx]+(cfa[indx-m2]));
crne=2*(cfa[indx+p1])/(eps+cfa[indx]+(cfa[indx+p2]));
crsw=2*(cfa[indx-p1])/(eps+cfa[indx]+(cfa[indx-p2]));
//assign B/R at R/B sites
if (fabs(1-crse)<arthresh) {rbse=cfa[indx]*crse;}//use this if more precise diag interp is necessary
else {rbse=(cfa[indx+m1])+0.5*(cfa[indx]-cfa[indx+m2]);}
if (fabs(1-crnw)<arthresh) {rbnw=cfa[indx]*crnw;}
else {rbnw=(cfa[indx-m1])+0.5*(cfa[indx]-cfa[indx-m2]);}
if (fabs(1-crne)<arthresh) {rbne=cfa[indx]*crne;}
else {rbne=(cfa[indx+p1])+0.5*(cfa[indx]-cfa[indx+p2]);}
if (fabs(1-crsw)<arthresh) {rbsw=cfa[indx]*crsw;}
else {rbsw=(cfa[indx-p1])+0.5*(cfa[indx]-cfa[indx-p2]);}
wtse= eps+delm[indx]+delm[indx+m1]+delm[indx+m2];//same as for wtu,wtd,wtl,wtr
wtnw= eps+delm[indx]+delm[indx-m1]+delm[indx-m2];
wtne= eps+delp[indx]+delp[indx+p1]+delp[indx+p2];
wtsw= eps+delp[indx]+delp[indx-p1]+delp[indx-p2];
rbm[indx] = (wtse*rbnw+wtnw*rbse)/(wtse+wtnw);
rbp[indx] = (wtne*rbsw+wtsw*rbne)/(wtne+wtsw);
pmwt[indx] = rbvarm/(rbvarp+rbvarm);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//bound the interpolation in regions of high saturation
if (rbp[indx]<cfa[indx]) {
if (2*rbp[indx] < cfa[indx]) {
rbp[indx] = ULIM(rbp[indx] ,cfa[indx-p1],cfa[indx+p1]);
} else {
pwt = 2*(cfa[indx]-rbp[indx])/(eps+rbp[indx]+cfa[indx]);
rbp[indx]=pwt*rbp[indx] + (1-pwt)*ULIM(rbp[indx],cfa[indx-p1],cfa[indx+p1]);
}
}
if (rbm[indx]<cfa[indx]) {
if (2*rbm[indx] < cfa[indx]) {
rbm[indx] = ULIM(rbm[indx] ,cfa[indx-m1],cfa[indx+m1]);
} else {
mwt = 2*(cfa[indx]-rbm[indx])/(eps+rbm[indx]+cfa[indx]);
rbm[indx]=mwt*rbm[indx] + (1-mwt)*ULIM(rbm[indx],cfa[indx-m1],cfa[indx+m1]);
}
}
if (rbp[indx] > clip_pt) rbp[indx]=ULIM(rbp[indx],cfa[indx-p1],cfa[indx+p1]);//for RT implementation
if (rbm[indx] > clip_pt) rbm[indx]=ULIM(rbm[indx],cfa[indx-m1],cfa[indx+m1]);
//c=2-FC(rr,cc);//for dcraw implementation
//if (rbp[indx] > pre_mul[c]) rbp[indx]=ULIM(rbp[indx],cfa[indx-p1],cfa[indx+p1]);
//if (rbm[indx] > pre_mul[c]) rbm[indx]=ULIM(rbm[indx],cfa[indx-m1],cfa[indx+m1]);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//rbint[indx] = 0.5*(cfa[indx] + (rbp*rbvarm+rbm*rbvarp)/(rbvarp+rbvarm));//this is R+B, interpolated
}
for (rr=10; rr<rr1-10; rr++)
for (cc=10+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-10; cc+=2,indx+=2) {
//first ask if one gets more directional discrimination from nearby B/R sites
pmwtalt = 0.25*(pmwt[indx-m1]+pmwt[indx+p1]+pmwt[indx-p1]+pmwt[indx+m1]);
vo=fabs(0.5-pmwt[indx]);
ve=fabs(0.5-pmwtalt);
if (vo<ve) {pmwt[indx]=pmwtalt;}//a better result was obtained from the neighbors
rbint[indx] = 0.5*(cfa[indx] + rbm[indx]*(1-pmwt[indx]) + rbp[indx]*pmwt[indx]);//this is R+B, interpolated
}
for (rr=12; rr<rr1-12; rr++)
for (cc=12+(FC(rr,2)&1),indx=rr*TS+cc; cc<cc1-12; cc+=2,indx+=2) {
if (fabs(0.5-pmwt[indx])<fabs(0.5-hvwt[indx]) ) continue;
//now interpolate G vertically/horizontally using R+B values
//unfortunately, since G interpolation cannot be done diagonally this may lead to color shifts
//color ratios for G interpolation
cru = cfa[indx-v1]*2/(eps+rbint[indx]+rbint[indx-v2]);
crd = cfa[indx+v1]*2/(eps+rbint[indx]+rbint[indx+v2]);
crl = cfa[indx-1]*2/(eps+rbint[indx]+rbint[indx-2]);
crr = cfa[indx+1]*2/(eps+rbint[indx]+rbint[indx+2]);
//interpolated G via adaptive ratios or Hamilton-Adams in each cardinal direction
if (fabs(1-cru)<arthresh) {gu=rbint[indx]*cru;}
else {gu=cfa[indx-v1]+0.5*(rbint[indx]-rbint[indx-v2]);}
if (fabs(1-crd)<arthresh) {gd=rbint[indx]*crd;}
else {gd=cfa[indx+v1]+0.5*(rbint[indx]-rbint[indx+v2]);}
if (fabs(1-crl)<arthresh) {gl=rbint[indx]*crl;}
else {gl=cfa[indx-1]+0.5*(rbint[indx]-rbint[indx-2]);}
if (fabs(1-crr)<arthresh) {gr=rbint[indx]*crr;}
else {gr=cfa[indx+1]+0.5*(rbint[indx]-rbint[indx+2]);}
//gu=rbint[indx]*cru;
//gd=rbint[indx]*crd;
//gl=rbint[indx]*crl;
//gr=rbint[indx]*crr;
//interpolated G via adaptive weights of cardinal evaluations
Gintv = (dirwts[indx-v1][0]*gd+dirwts[indx+v1][0]*gu)/(dirwts[indx+v1][0]+dirwts[indx-v1][0]);
Ginth = (dirwts[indx-1][1]*gr+dirwts[indx+1][1]*gl)/(dirwts[indx-1][1]+dirwts[indx+1][1]);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//bound the interpolation in regions of high saturation
if (Gintv<rbint[indx]) {
if (2*Gintv < rbint[indx]) {
Gintv = ULIM(Gintv ,cfa[indx-v1],cfa[indx+v1]);
} else {
vwt = 2*(rbint[indx]-Gintv)/(eps+Gintv+rbint[indx]);
Gintv=vwt*Gintv + (1-vwt)*ULIM(Gintv,cfa[indx-v1],cfa[indx+v1]);
}
}
if (Ginth<rbint[indx]) {
if (2*Ginth < rbint[indx]) {
Ginth = ULIM(Ginth ,cfa[indx-1],cfa[indx+1]);
} else {
hwt = 2*(rbint[indx]-Ginth)/(eps+Ginth+rbint[indx]);
Ginth=hwt*Ginth + (1-hwt)*ULIM(Ginth,cfa[indx-1],cfa[indx+1]);
}
}
if (Ginth > clip_pt) Ginth=ULIM(Ginth,cfa[indx-1],cfa[indx+1]);//for RT implementation
if (Gintv > clip_pt) Gintv=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1]);
//c=FC(rr,cc);//for dcraw implementation
//if (Ginth > pre_mul[c]) Ginth=ULIM(Ginth,cfa[indx-1],cfa[indx+1]);
//if (Gintv > pre_mul[c]) Gintv=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1]);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rgb[indx][1] = Ginth*(1-hvwt[indx]) + Gintv*hvwt[indx];
//rgb[indx][1] = 0.5*(rgb[indx][1]+0.25*(rgb[indx-v1][1]+rgb[indx+v1][1]+rgb[indx-1][1]+rgb[indx+1][1]));
Dgrb[indx][0] = rgb[indx][1]-cfa[indx];
//rgb[indx][2-FC(rr,cc)]=2*rbint[indx]-cfa[indx];
}
//end of diagonal interpolation correction
//t2_diag += clock() - t1_diag;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//t1_chroma = clock();
//fancy chrominance interpolation
//(ey,ex) is location of R site
for (rr=13-ey; rr<rr1-12; rr+=2)
for (cc=13-ex,indx=rr*TS+cc; cc<cc1-12; cc+=2,indx+=2) {//B coset
Dgrb[indx][1]=Dgrb[indx][0];//split out G-B from G-R
Dgrb[indx][0]=0;
}
for (rr=12; rr<rr1-12; rr++)
for (cc=12+(FC(rr,2)&1),indx=rr*TS+cc,c=1-FC(rr,cc)/2; cc<cc1-12; cc+=2,indx+=2) {
wtnw=1.0/(eps+fabs(Dgrb[indx-m1][c]-Dgrb[indx+m1][c])+fabs(Dgrb[indx-m1][c]-Dgrb[indx-m3][c])+fabs(Dgrb[indx+m1][c]-Dgrb[indx-m3][c]));
wtne=1.0/(eps+fabs(Dgrb[indx+p1][c]-Dgrb[indx-p1][c])+fabs(Dgrb[indx+p1][c]-Dgrb[indx+p3][c])+fabs(Dgrb[indx-p1][c]-Dgrb[indx+p3][c]));
wtsw=1.0/(eps+fabs(Dgrb[indx-p1][c]-Dgrb[indx+p1][c])+fabs(Dgrb[indx-p1][c]-Dgrb[indx+m3][c])+fabs(Dgrb[indx+p1][c]-Dgrb[indx-p3][c]));
wtse=1.0/(eps+fabs(Dgrb[indx+m1][c]-Dgrb[indx-m1][c])+fabs(Dgrb[indx+m1][c]-Dgrb[indx-p3][c])+fabs(Dgrb[indx-m1][c]-Dgrb[indx+m3][c]));
//Dgrb[indx][c]=(wtnw*Dgrb[indx-m1][c]+wtne*Dgrb[indx+p1][c]+wtsw*Dgrb[indx-p1][c]+wtse*Dgrb[indx+m1][c])/(wtnw+wtne+wtsw+wtse);
Dgrb[indx][c]=(wtnw*(1.325*Dgrb[indx-m1][c]-0.175*Dgrb[indx-m3][c]-0.075*Dgrb[indx-m1-2][c]-0.075*Dgrb[indx-m1-v2][c] )+ \
wtne*(1.325*Dgrb[indx+p1][c]-0.175*Dgrb[indx+p3][c]-0.075*Dgrb[indx+p1+2][c]-0.075*Dgrb[indx+p1+v2][c] )+ \
wtsw*(1.325*Dgrb[indx-p1][c]-0.175*Dgrb[indx-p3][c]-0.075*Dgrb[indx-p1-2][c]-0.075*Dgrb[indx-p1-v2][c] )+ \
wtse*(1.325*Dgrb[indx+m1][c]-0.175*Dgrb[indx+m3][c]-0.075*Dgrb[indx+m1+2][c]-0.075*Dgrb[indx+m1+v2][c] ))/(wtnw+wtne+wtsw+wtse);
}
for (rr=12; rr<rr1-12; rr++)
for (cc=12+(FC(rr,1)&1),indx=rr*TS+cc,c=FC(rr,cc+1)/2; cc<cc1-12; cc+=2,indx+=2)
for(c=0;c<2;c++){
Dgrb[indx][c]=((hvwt[indx-v1])*Dgrb[indx-v1][c]+(1-hvwt[indx+1])*Dgrb[indx+1][c]+(1-hvwt[indx-1])*Dgrb[indx-1][c]+(hvwt[indx+v1])*Dgrb[indx+v1][c])/ \
((hvwt[indx-v1])+(1-hvwt[indx+1])+(1-hvwt[indx-1])+(hvwt[indx+v1]));
}
for(rr=12; rr<rr1-12; rr++)
for(cc=12,indx=rr*TS+cc; cc<cc1-12; cc++,indx++){
rgb[indx][0]=(rgb[indx][1]-Dgrb[indx][0]);
rgb[indx][2]=(rgb[indx][1]-Dgrb[indx][1]);
}
//t2_chroma += clock() - t1_chroma;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// copy smoothed results back to image matrix
for (rr=16; rr < rr1-16; rr++)
for (row=rr+top, cc=16; cc < cc1-16; cc++) {
col = cc + left;
indx=rr*TS+cc;
red[row][col] = CLIP((int)(65535.0f*rgb[indx][0] + 0.5f));
green[row][col] = CLIP((int)(65535.0f*rgb[indx][1] + 0.5f));
blue[row][col] = CLIP((int)(65535.0f*rgb[indx][2] + 0.5f));
//for dcraw implementation
//for (c=0; c<3; c++){
// image[indx][c] = CLIP((int)(65535.0f*rgb[rr*TS+cc][c] + 0.5f));
//}
}
//end of main loop
// clean up
//free(buffer);
progress+=(double)((TS-32)*(TS-32))/(height*width);
if (progress>1.0)
{
progress=1.0;
}
if(plistener) plistener->setProgress(progress);
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// clean up
free(buffer);
}
// done
#undef TS
}