//////////////////////////////////////////////////////////////// // // Chromatic Aberration Auto-correction // // copyright (c) 2008-2010 Emil Martinec // // // code dated: November 26, 2010 // // CA_correct_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 . // //////////////////////////////////////////////////////////////// //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #include "rtengine.h" #include "rawimagesource.h" #include "rt_math.h" using namespace std; using namespace rtengine; int RawImageSource::LinEqSolve(int nDim, double* pfMatr, double* pfVect, double* pfSolution) { //============================================================================== // return 1 if system not solving, 0 if system solved // nDim - system dimension // pfMatr - matrix with coefficients // pfVect - vector with free members // pfSolution - vector with system solution // pfMatr becames trianglular after function call // pfVect changes after function call // // Developer: Henry Guennadi Levkin // //============================================================================== double fMaxElem; double fAcc; int i, j, k, m; for(k = 0; k < (nDim - 1); k++) { // base row of matrix // search of line with max element fMaxElem = fabsf( pfMatr[k * nDim + k] ); m = k; for (i = k + 1; i < nDim; i++) { if(fMaxElem < fabsf(pfMatr[i * nDim + k]) ) { fMaxElem = pfMatr[i * nDim + k]; m = i; } } // permutation of base line (index k) and max element line(index m) if(m != k) { for(i = k; i < nDim; i++) { fAcc = pfMatr[k * nDim + i]; pfMatr[k * nDim + i] = pfMatr[m * nDim + i]; pfMatr[m * nDim + i] = fAcc; } fAcc = pfVect[k]; pfVect[k] = pfVect[m]; pfVect[m] = fAcc; } if( pfMatr[k * nDim + k] == 0.) { //linear system has no solution return 1; // needs improvement !!! } // triangulation of matrix with coefficients for(j = (k + 1); j < nDim; j++) { // current row of matrix fAcc = - pfMatr[j * nDim + k] / pfMatr[k * nDim + k]; for(i = k; i < nDim; i++) { pfMatr[j * nDim + i] = pfMatr[j * nDim + i] + fAcc * pfMatr[k * nDim + i]; } pfVect[j] = pfVect[j] + fAcc * pfVect[k]; // free member recalculation } } for(k = (nDim - 1); k >= 0; k--) { pfSolution[k] = pfVect[k]; for(i = (k + 1); i < nDim; i++) { pfSolution[k] -= (pfMatr[k * nDim + i] * pfSolution[i]); } pfSolution[k] = pfSolution[k] / pfMatr[k * nDim + k]; } return 0; } //end of linear equation solver //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::CA_correct_RT(double cared, double cablue) { // multithreaded by Ingo Weyrich #define TS 128 // Tile size #define TSH 64 // Half Tile size #define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } // Test for RGB cfa for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) if(FC(i, j) == 3) { printf("CA correction supports only RGB Color filter arrays\n"); return; } volatile double progress = 0.0; if(plistener) { plistener->setProgress (progress); } bool autoCA = (cared == 0 && cablue == 0); // local variables int width = W, height = H; //temporary array to store simple interpolation of G float (*Gtmp); Gtmp = (float (*)) calloc ((height) * (width), sizeof * Gtmp); // temporary array to avoid race conflicts, only every second pixel needs to be saved here float (*RawDataTmp); RawDataTmp = (float*) malloc( height * width * sizeof(float) / 2); float blockave[2][3] = {{0, 0, 0}, {0, 0, 0}}, blocksqave[2][3] = {{0, 0, 0}, {0, 0, 0}}, blockdenom[2][3] = {{0, 0, 0}, {0, 0, 0}}, blockvar[2][3]; // Because we can't break parallel processing, we need a switch do handle the errors bool processpasstwo = true; //block CA shift values and weight assigned to block char *buffer1; // vblsz*hblsz*(3*2+1) float (*blockwt); // vblsz*hblsz float (*blockshifts)[3][2]; // vblsz*hblsz*3*2 const int border = 8; const int border2 = 16; int vz1, hz1; if((height + border2) % (TS - border2) == 0) { vz1 = 1; } else { vz1 = 0; } if((width + border2) % (TS - border2) == 0) { hz1 = 1; } else { hz1 = 0; } int vblsz, hblsz; vblsz = ceil((float)(height + border2) / (TS - border2) + 2 + vz1); hblsz = ceil((float)(width + border2) / (TS - border2) + 2 + hz1); buffer1 = (char *) malloc(vblsz * hblsz * (3 * 2 + 1) * sizeof(float)); //merror(buffer1,"CA_correct()"); memset(buffer1, 0, vblsz * hblsz * (3 * 2 + 1)*sizeof(float)); // block CA shifts blockwt = (float (*)) (buffer1); blockshifts = (float (*)[3][2]) (buffer1 + (vblsz * hblsz * sizeof(float))); double fitparams[3][2][16]; //order of 2d polynomial fit (polyord), and numpar=polyord^2 int polyord = 4, numpar = 16; #pragma omp parallel shared(Gtmp,width,height,blockave,blocksqave,blockdenom,blockvar,blockwt,blockshifts,fitparams,polyord,numpar) { int progresscounter = 0; int rrmin, rrmax, ccmin, ccmax; int top, left, row, col; int rr, cc, c, indx, indx1, i, j, k, m, n, dir; //number of pixels in a tile contributing to the CA shift diagnostic int areawt[2][3]; //direction of the CA shift in a tile int GRBdir[2][3]; //offset data of the plaquette where the optical R/B data are sampled int offset[2][3]; int shifthfloor[3], shiftvfloor[3], shifthceil[3], shiftvceil[3]; //number of tiles in the image int vblock, hblock; //int verbose=1; //flag indicating success or failure of polynomial fit int res; //shifts to location of vertical and diagonal neighbors const int v1 = TS, v2 = 2 * TS, v3 = 3 * TS, v4 = 4 * TS; //, p1=-TS+1, p2=-2*TS+2, p3=-3*TS+3, m1=TS+1, m2=2*TS+2, m3=3*TS+3; float eps = 1e-5f, eps2 = 1e-10f; //tolerance to avoid dividing by zero //adaptive weights for green interpolation float wtu, wtd, wtl, wtr; //local quadratic fit to shift data within a tile float coeff[2][3][3]; //measured CA shift parameters for a tile float CAshift[2][3]; //polynomial fit coefficients //residual CA shift amount within a plaquette float shifthfrac[3], shiftvfrac[3]; //temporary storage for median filter float temp, p[9]; //temporary parameters for tile CA evaluation float gdiff, deltgrb; //interpolated G at edge of plaquette float Ginthfloor, Ginthceil, Gint, RBint, gradwt; //interpolated color difference at edge of plaquette float grbdiffinthfloor, grbdiffinthceil, grbdiffint, grbdiffold; //per thread data for evaluation of block CA shift variance float blockavethr[2][3] = {{0, 0, 0}, {0, 0, 0}}, blocksqavethr[2][3] = {{0, 0, 0}, {0, 0, 0}}, blockdenomthr[2][3] = {{0, 0, 0}, {0, 0, 0}}; //, blockvarthr[2][3]; //low and high pass 1D filters of G in vertical/horizontal directions float glpfh, glpfv; //max allowed CA shift const float bslim = 3.99; //gaussians for low pass filtering of G and R/B //static const float gaussg[5] = {0.171582, 0.15839, 0.124594, 0.083518, 0.0477063};//sig=2.5 //static const float gaussrb[3] = {0.332406, 0.241376, 0.0924212};//sig=1.25 //block CA shift values and weight assigned to block char *buffer; // TS*TS*16 //rgb data in a tile float* rgb[3]; //color differences float (*grbdiff); // TS*TS*4 //green interpolated to optical sample points for R/B float (*gshift); // TS*TS*4 //high pass filter for R/B in vertical direction float (*rbhpfh); // TS*TS*4 //high pass filter for R/B in horizontal direction float (*rbhpfv); // TS*TS*4 //low pass filter for R/B in horizontal direction float (*rblpfh); // TS*TS*4 //low pass filter for R/B in vertical direction float (*rblpfv); // TS*TS*4 //low pass filter for color differences in horizontal direction float (*grblpfh); // TS*TS*4 //low pass filter for color differences in vertical direction float (*grblpfv); // TS*TS*4 /* assign working space; this would not be necessary if the algorithm is part of the larger pre-interpolation processing */ buffer = (char *) malloc(3 * sizeof(float) * TS * TS + 8 * sizeof(float) * TS * TSH + 10 * 64 + 64); //merror(buffer,"CA_correct()"); memset(buffer, 0, 3 * sizeof(float)*TS * TS + 8 * sizeof(float)*TS * TSH + 10 * 64 + 64); char *data; data = buffer; // buffers aligned to size of cacheline // data = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); // shift the beginning of all arrays but the first by 64 bytes to avoid cache miss conflicts on CPUs which have <=4-way associative L1-Cache rgb[0] = (float (*)) data; rgb[1] = (float (*)) (data + 1 * sizeof(float) * TS * TS + 1 * 64); rgb[2] = (float (*)) (data + 2 * sizeof(float) * TS * TS + 2 * 64); grbdiff = (float (*)) (data + 3 * sizeof(float) * TS * TS + 3 * 64); gshift = (float (*)) (data + 3 * sizeof(float) * TS * TS + sizeof(float) * TS * TSH + 4 * 64); rbhpfh = (float (*)) (data + 4 * sizeof(float) * TS * TS + 5 * 64); rbhpfv = (float (*)) (data + 4 * sizeof(float) * TS * TS + sizeof(float) * TS * TSH + 6 * 64); rblpfh = (float (*)) (data + 5 * sizeof(float) * TS * TS + 7 * 64); rblpfv = (float (*)) (data + 5 * sizeof(float) * TS * TS + sizeof(float) * TS * TSH + 8 * 64); grblpfh = (float (*)) (data + 6 * sizeof(float) * TS * TS + 9 * 64); grblpfv = (float (*)) (data + 6 * sizeof(float) * TS * TS + sizeof(float) * TS * TSH + 10 * 64); if (autoCA) { // Main algorithm: Tile loop #pragma omp for collapse(2) schedule(dynamic) nowait for (top = -border ; top < height; top += TS - border2) for (left = -border; left < width; left += TS - border2) { vblock = ((top + border) / (TS - border2)) + 1; hblock = ((left + border) / (TS - border2)) + 1; int bottom = min(top + TS, height + border); int right = min(left + TS, width + border); int rr1 = bottom - top; int cc1 = right - left; //t1_init = clock(); if (top < 0) { rrmin = border; } else { rrmin = 0; } if (left < 0) { ccmin = border; } else { ccmin = 0; } if (bottom > height) { rrmax = height - top; } else { rrmax = rr1; } if (right > width) { ccmax = width - left; } else { ccmax = cc1; } // rgb from input CFA data // rgb values should be floating point number between 0 and 1 // after white balance multipliers are applied 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[c][indx1] = (rawData[row][col]) / 65535.0f; //rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //fill borders if (rrmin > 0) { for (rr = 0; rr < border; rr++) for (cc = ccmin; cc < ccmax; cc++) { c = FC(rr, cc); rgb[c][rr * TS + cc] = rgb[c][(border2 - rr) * TS + cc]; } } if (rrmax < rr1) { for (rr = 0; rr < border; rr++) for (cc = ccmin; cc < ccmax; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + cc] = (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 } } if (ccmin > 0) { for (rr = rrmin; rr < rrmax; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][rr * TS + cc] = rgb[c][rr * TS + border2 - cc]; } } if (ccmax < cc1) { for (rr = rrmin; rr < rrmax; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][rr * TS + ccmax + cc] = (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 } } //also, fill the image corners if (rrmin > 0 && ccmin > 0) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rr)*TS + cc] = (rawData[border2 - rr][border2 - cc]) / 65535.0f; //rgb[(rr)*TS+cc][c] = (rgb[(border2-rr)*TS+(border2-cc)][c]);//for dcraw implementation } } if (rrmax < rr1 && ccmax < cc1) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + ccmax + cc] = (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 } } if (rrmin > 0 && ccmax < cc1) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rr)*TS + ccmax + cc] = (rawData[(border2 - rr)][(width - cc - 2)]) / 65535.0f; //rgb[(rr)*TS+ccmax+cc][c] = (image[(border2-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation } } if (rrmax < rr1 && ccmin > 0) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + cc] = (rawData[(height - rr - 2)][(border2 - cc)]) / 65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(border2-cc)][c])/65535.0f;//for dcraw implementation } } //end of border fill // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) for (c = 0; c < 3; c += 2) { coeff[j][k][c] = 0; } //end of initialization for (rr = 3; rr < rr1 - 3; rr++) for (row = rr + top, cc = 3, indx = rr * TS + cc; cc < cc1 - 3; cc++, indx++) { col = cc + left; c = FC(rr, cc); if (c != 1) { //compute directional weights using image gradients wtu = 1.0 / SQR(eps + fabsf(rgb[1][indx + v1] - rgb[1][indx - v1]) + fabsf(rgb[c][indx] - rgb[c][indx - v2]) + fabsf(rgb[1][indx - v1] - rgb[1][indx - v3])); wtd = 1.0 / SQR(eps + fabsf(rgb[1][indx - v1] - rgb[1][indx + v1]) + fabsf(rgb[c][indx] - rgb[c][indx + v2]) + fabsf(rgb[1][indx + v1] - rgb[1][indx + v3])); wtl = 1.0 / SQR(eps + fabsf(rgb[1][indx + 1] - rgb[1][indx - 1]) + fabsf(rgb[c][indx] - rgb[c][indx - 2]) + fabsf(rgb[1][indx - 1] - rgb[1][indx - 3])); wtr = 1.0 / SQR(eps + fabsf(rgb[1][indx - 1] - rgb[1][indx + 1]) + fabsf(rgb[c][indx] - rgb[c][indx + 2]) + fabsf(rgb[1][indx + 1] - rgb[1][indx + 3])); //store in rgb array the interpolated G value at R/B grid points using directional weighted average rgb[1][indx] = (wtu * rgb[1][indx - v1] + wtd * rgb[1][indx + v1] + wtl * rgb[1][indx - 1] + wtr * rgb[1][indx + 1]) / (wtu + wtd + wtl + wtr); } if (row > -1 && row < height && col > -1 && col < width) { Gtmp[row * width + col] = rgb[1][indx]; } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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) { rbhpfv[indx >> 1] = fabsf(fabsf((rgb[1][indx] - rgb[c][indx]) - (rgb[1][indx + v4] - rgb[c][indx + v4])) + fabsf((rgb[1][indx - v4] - rgb[c][indx - v4]) - (rgb[1][indx] - rgb[c][indx])) - fabsf((rgb[1][indx - v4] - rgb[c][indx - v4]) - (rgb[1][indx + v4] - rgb[c][indx + v4]))); rbhpfh[indx >> 1] = fabsf(fabsf((rgb[1][indx] - rgb[c][indx]) - (rgb[1][indx + 4] - rgb[c][indx + 4])) + fabsf((rgb[1][indx - 4] - rgb[c][indx - 4]) - (rgb[1][indx] - rgb[c][indx])) - fabsf((rgb[1][indx - 4] - rgb[c][indx - 4]) - (rgb[1][indx + 4] - rgb[c][indx + 4]))); /*ghpfv = fabsf(fabsf(rgb[indx][1]-rgb[indx+v4][1])+fabsf(rgb[indx][1]-rgb[indx-v4][1]) - fabsf(rgb[indx+v4][1]-rgb[indx-v4][1])); ghpfh = fabsf(fabsf(rgb[indx][1]-rgb[indx+4][1])+fabsf(rgb[indx][1]-rgb[indx-4][1]) - fabsf(rgb[indx+4][1]-rgb[indx-4][1])); rbhpfv[indx] = fabsf(ghpfv - fabsf(fabsf(rgb[indx][c]-rgb[indx+v4][c])+fabsf(rgb[indx][c]-rgb[indx-v4][c]) - fabsf(rgb[indx+v4][c]-rgb[indx-v4][c]))); rbhpfh[indx] = fabsf(ghpfh - fabsf(fabsf(rgb[indx][c]-rgb[indx+4][c])+fabsf(rgb[indx][c]-rgb[indx-4][c]) - fabsf(rgb[indx+4][c]-rgb[indx-4][c])));*/ glpfv = 0.25 * (2.0 * rgb[1][indx] + rgb[1][indx + v2] + rgb[1][indx - v2]); glpfh = 0.25 * (2.0 * rgb[1][indx] + rgb[1][indx + 2] + rgb[1][indx - 2]); rblpfv[indx >> 1] = eps + fabsf(glpfv - 0.25 * (2.0 * rgb[c][indx] + rgb[c][indx + v2] + rgb[c][indx - v2])); rblpfh[indx >> 1] = eps + fabsf(glpfh - 0.25 * (2.0 * rgb[c][indx] + rgb[c][indx + 2] + rgb[c][indx - 2])); grblpfv[indx >> 1] = glpfv + 0.25 * (2.0 * rgb[c][indx] + rgb[c][indx + v2] + rgb[c][indx - v2]); grblpfh[indx >> 1] = glpfh + 0.25 * (2.0 * rgb[c][indx] + rgb[c][indx + 2] + rgb[c][indx - 2]); } areawt[0][0] = areawt[1][0] = 1; areawt[0][2] = areawt[1][2] = 1; // along line segments, find the point along each segment that minimizes the color variance // averaged over the tile; evaluate for up/down and left/right away from R/B grid point for (rr = 8; rr < rr1 - 8; rr++) for (cc = 8 + (FC(rr, 2) & 1), indx = rr * TS + cc, c = FC(rr, cc); cc < cc1 - 8; cc += 2, indx += 2) { // areawt[0][c]=areawt[1][c]=0; //in linear interpolation, color differences are a quadratic function of interpolation position; //solve for the interpolation position that minimizes color difference variance over the tile //vertical gdiff = 0.3125 * (rgb[1][indx + TS] - rgb[1][indx - TS]) + 0.09375 * (rgb[1][indx + TS + 1] - rgb[1][indx - TS + 1] + rgb[1][indx + TS - 1] - rgb[1][indx - TS - 1]); deltgrb = (rgb[c][indx] - rgb[1][indx]); gradwt = fabsf(0.25 * rbhpfv[indx >> 1] + 0.125 * (rbhpfv[(indx >> 1) + 1] + rbhpfv[(indx >> 1) - 1]) ) * (grblpfv[(indx >> 1) - v1] + grblpfv[(indx >> 1) + v1]) / (eps + 0.1 * grblpfv[(indx >> 1) - v1] + rblpfv[(indx >> 1) - v1] + 0.1 * grblpfv[(indx >> 1) + v1] + rblpfv[(indx >> 1) + v1]); coeff[0][0][c] += gradwt * deltgrb * deltgrb; coeff[0][1][c] += gradwt * gdiff * deltgrb; coeff[0][2][c] += gradwt * gdiff * gdiff; // areawt[0][c]+=1; //horizontal gdiff = 0.3125 * (rgb[1][indx + 1] - rgb[1][indx - 1]) + 0.09375 * (rgb[1][indx + 1 + TS] - rgb[1][indx - 1 + TS] + rgb[1][indx + 1 - TS] - rgb[1][indx - 1 - TS]); deltgrb = (rgb[c][indx] - rgb[1][indx]); gradwt = fabsf(0.25 * rbhpfh[indx >> 1] + 0.125 * (rbhpfh[(indx >> 1) + v1] + rbhpfh[(indx >> 1) - v1]) ) * (grblpfh[(indx >> 1) - 1] + grblpfh[(indx >> 1) + 1]) / (eps + 0.1 * grblpfh[(indx >> 1) - 1] + rblpfh[(indx >> 1) - 1] + 0.1 * grblpfh[(indx >> 1) + 1] + rblpfh[(indx >> 1) + 1]); coeff[1][0][c] += gradwt * deltgrb * deltgrb; coeff[1][1][c] += gradwt * gdiff * deltgrb; coeff[1][2][c] += gradwt * gdiff * gdiff; // areawt[1][c]+=1; // In Mathematica, // f[x_]=Expand[Total[Flatten[ // ((1-x) RotateLeft[Gint,shift1]+x RotateLeft[Gint,shift2]-cfapad)^2[[dv;;-1;;2,dh;;-1;;2]]]]]; // extremum = -.5Coefficient[f[x],x]/Coefficient[f[x],x^2] } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* 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) { rbhpfv[indx] = SQR(fabs((rgb[indx][1]-rgb[indx][c])-(rgb[indx+v4][1]-rgb[indx+v4][c])) + fabs((rgb[indx-v4][1]-rgb[indx-v4][c])-(rgb[indx][1]-rgb[indx][c])) - fabs((rgb[indx-v4][1]-rgb[indx-v4][c])-(rgb[indx+v4][1]-rgb[indx+v4][c]))); rbhpfh[indx] = SQR(fabs((rgb[indx][1]-rgb[indx][c])-(rgb[indx+4][1]-rgb[indx+4][c])) + fabs((rgb[indx-4][1]-rgb[indx-4][c])-(rgb[indx][1]-rgb[indx][c])) - fabs((rgb[indx-4][1]-rgb[indx-4][c])-(rgb[indx+4][1]-rgb[indx+4][c]))); glpfv = 0.25*(2*rgb[indx][1]+rgb[indx+v2][1]+rgb[indx-v2][1]); glpfh = 0.25*(2*rgb[indx][1]+rgb[indx+2][1]+rgb[indx-2][1]); rblpfv[indx] = eps+fabs(glpfv - 0.25*(2*rgb[indx][c]+rgb[indx+v2][c]+rgb[indx-v2][c])); rblpfh[indx] = eps+fabs(glpfh - 0.25*(2*rgb[indx][c]+rgb[indx+2][c]+rgb[indx-2][c])); grblpfv[indx] = glpfv + 0.25*(2*rgb[indx][c]+rgb[indx+v2][c]+rgb[indx-v2][c]); grblpfh[indx] = glpfh + 0.25*(2*rgb[indx][c]+rgb[indx+2][c]+rgb[indx-2][c]); } for (c=0;c<3;c++) {areawt[0][c]=areawt[1][c]=0;} // along line segments, find the point along each segment that minimizes the color variance // averaged over the tile; evaluate for up/down and left/right away from R/B grid point for (rr=rrmin+8; rr < rrmax-8; rr++) for (cc=ccmin+8+(FC(rr,2)&1), indx=rr*TS+cc, c = FC(rr,cc); cc < ccmax-8; cc+=2, indx+=2) { if (rgb[indx][c]>0.8*clip_pt || Gtmp[indx]>0.8*clip_pt) continue; //in linear interpolation, color differences are a quadratic function of interpolation position; //solve for the interpolation position that minimizes color difference variance over the tile //vertical gdiff=0.3125*(rgb[indx+TS][1]-rgb[indx-TS][1])+0.09375*(rgb[indx+TS+1][1]-rgb[indx-TS+1][1]+rgb[indx+TS-1][1]-rgb[indx-TS-1][1]); deltgrb=(rgb[indx][c]-rgb[indx][1])-0.5*((rgb[indx-v4][c]-rgb[indx-v4][1])+(rgb[indx+v4][c]-rgb[indx+v4][1])); gradwt=fabs(0.25*rbhpfv[indx]+0.125*(rbhpfv[indx+2]+rbhpfv[indx-2]) );// *(grblpfv[indx-v2]+grblpfv[indx+v2])/(eps+0.1*grblpfv[indx-v2]+rblpfv[indx-v2]+0.1*grblpfv[indx+v2]+rblpfv[indx+v2]); if (gradwt>eps) { coeff[0][0][c] += gradwt*deltgrb*deltgrb; coeff[0][1][c] += gradwt*gdiff*deltgrb; coeff[0][2][c] += gradwt*gdiff*gdiff; areawt[0][c]++; } //horizontal gdiff=0.3125*(rgb[indx+1][1]-rgb[indx-1][1])+0.09375*(rgb[indx+1+TS][1]-rgb[indx-1+TS][1]+rgb[indx+1-TS][1]-rgb[indx-1-TS][1]); deltgrb=(rgb[indx][c]-rgb[indx][1])-0.5*((rgb[indx-4][c]-rgb[indx-4][1])+(rgb[indx+4][c]-rgb[indx+4][1])); gradwt=fabs(0.25*rbhpfh[indx]+0.125*(rbhpfh[indx+v2]+rbhpfh[indx-v2]) );// *(grblpfh[indx-2]+grblpfh[indx+2])/(eps+0.1*grblpfh[indx-2]+rblpfh[indx-2]+0.1*grblpfh[indx+2]+rblpfh[indx+2]); if (gradwt>eps) { coeff[1][0][c] += gradwt*deltgrb*deltgrb; coeff[1][1][c] += gradwt*gdiff*deltgrb; coeff[1][2][c] += gradwt*gdiff*gdiff; areawt[1][c]++; } // In Mathematica, // f[x_]=Expand[Total[Flatten[ // ((1-x) RotateLeft[Gint,shift1]+x RotateLeft[Gint,shift2]-cfapad)^2[[dv;;-1;;2,dh;;-1;;2]]]]]; // extremum = -.5Coefficient[f[x],x]/Coefficient[f[x],x^2] }*/ for (c = 0; c < 3; c += 2) { for (j = 0; j < 2; j++) { // vert/hor //printf("hblock %d vblock %d j %d c %d areawt %d \n",hblock,vblock,j,c,areawt[j][c]); //printf("hblock %d vblock %d j %d c %d areawt %d ",hblock,vblock,j,c,areawt[j][c]); if (areawt[j][c] > 0 && coeff[j][2][c] > eps2) { CAshift[j][c] = coeff[j][1][c] / coeff[j][2][c]; blockwt[vblock * hblsz + hblock] = areawt[j][c] * coeff[j][2][c] / (eps + coeff[j][0][c]) ; } else { CAshift[j][c] = 17.0; blockwt[vblock * hblsz + hblock] = 0; } //if (c==0 && j==0) printf("vblock= %d hblock= %d denom= %f areawt= %d \n",vblock,hblock,coeff[j][2][c],areawt[j][c]); //printf("%f \n",CAshift[j][c]); //data structure = CAshift[vert/hor][color] //j=0=vert, 1=hor //offset gives NW corner of square containing the min; j=0=vert, 1=hor if (fabsf(CAshift[j][c]) < 2.0f) { blockavethr[j][c] += CAshift[j][c]; blocksqavethr[j][c] += SQR(CAshift[j][c]); blockdenomthr[j][c] += 1; } }//vert/hor }//color /* CAshift[j][c] are the locations that minimize color difference variances; This is the approximate _optical_ location of the R/B pixels */ for (c = 0; c < 3; c += 2) { //evaluate the shifts to the location that minimizes CA within the tile blockshifts[(vblock)*hblsz + hblock][c][0] = (CAshift[0][c]); //vert CA shift for R/B blockshifts[(vblock)*hblsz + hblock][c][1] = (CAshift[1][c]); //hor CA shift for R/B //data structure: blockshifts[blocknum][R/B][v/h] //if (c==0) printf("vblock= %d hblock= %d blockshiftsmedian= %f \n",vblock,hblock,blockshifts[(vblock)*hblsz+hblock][c][0]); } if(plistener) { progresscounter++; if(progresscounter % 8 == 0) #pragma omp critical { progress += (double)(8.0 * (TS - border2) * (TS - border2)) / (2 * height * width); if (progress > 1.0) { progress = 1.0; } plistener->setProgress(progress); } } } //end of diagnostic pass #pragma omp critical { for (j = 0; j < 2; j++) for (c = 0; c < 3; c += 2) { blockdenom[j][c] += blockdenomthr[j][c]; blocksqave[j][c] += blocksqavethr[j][c]; blockave[j][c] += blockavethr[j][c]; } } #pragma omp barrier #pragma omp single { for (j = 0; j < 2; j++) for (c = 0; c < 3; c += 2) { if (blockdenom[j][c]) { blockvar[j][c] = blocksqave[j][c] / blockdenom[j][c] - SQR(blockave[j][c] / blockdenom[j][c]); } else { processpasstwo = false; printf ("blockdenom vanishes \n"); break; } } //printf ("tile variances %f %f %f %f \n",blockvar[0][0],blockvar[1][0],blockvar[0][2],blockvar[1][2] ); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //now prepare for CA correction pass //first, fill border blocks of blockshift array if(processpasstwo) { for (vblock = 1; vblock < vblsz - 1; vblock++) { //left and right sides for (c = 0; c < 3; c += 2) { for (i = 0; i < 2; i++) { blockshifts[vblock * hblsz][c][i] = blockshifts[(vblock) * hblsz + 2][c][i]; blockshifts[vblock * hblsz + hblsz - 1][c][i] = blockshifts[(vblock) * hblsz + hblsz - 3][c][i]; } } } for (hblock = 0; hblock < hblsz; hblock++) { //top and bottom sides for (c = 0; c < 3; c += 2) { for (i = 0; i < 2; i++) { blockshifts[hblock][c][i] = blockshifts[2 * hblsz + hblock][c][i]; blockshifts[(vblsz - 1)*hblsz + hblock][c][i] = blockshifts[(vblsz - 3) * hblsz + hblock][c][i]; } } } //end of filling border pixels of blockshift array //initialize fit arrays double polymat[3][2][256], shiftmat[3][2][16]; for (i = 0; i < 256; i++) { polymat[0][0][i] = polymat[0][1][i] = polymat[2][0][i] = polymat[2][1][i] = 0; } for (i = 0; i < 16; i++) { shiftmat[0][0][i] = shiftmat[0][1][i] = shiftmat[2][0][i] = shiftmat[2][1][i] = 0; } int numblox[3] = {0, 0, 0}; float bstemp[2]; for (vblock = 1; vblock < vblsz - 1; vblock++) for (hblock = 1; hblock < hblsz - 1; hblock++) { // block 3x3 median of blockshifts for robustness for (c = 0; c < 3; c += 2) { for (dir = 0; dir < 2; dir++) { p[0] = blockshifts[(vblock - 1) * hblsz + hblock - 1][c][dir]; p[1] = blockshifts[(vblock - 1) * hblsz + hblock][c][dir]; p[2] = blockshifts[(vblock - 1) * hblsz + hblock + 1][c][dir]; p[3] = blockshifts[(vblock) * hblsz + hblock - 1][c][dir]; p[4] = blockshifts[(vblock) * hblsz + hblock][c][dir]; p[5] = blockshifts[(vblock) * hblsz + hblock + 1][c][dir]; p[6] = blockshifts[(vblock + 1) * hblsz + hblock - 1][c][dir]; p[7] = blockshifts[(vblock + 1) * hblsz + hblock][c][dir]; p[8] = blockshifts[(vblock + 1) * hblsz + hblock + 1][c][dir]; PIX_SORT(p[1], p[2]); PIX_SORT(p[4], p[5]); PIX_SORT(p[7], p[8]); PIX_SORT(p[0], p[1]); PIX_SORT(p[3], p[4]); PIX_SORT(p[6], p[7]); PIX_SORT(p[1], p[2]); PIX_SORT(p[4], p[5]); PIX_SORT(p[7], p[8]); PIX_SORT(p[0], p[3]); PIX_SORT(p[5], p[8]); PIX_SORT(p[4], p[7]); PIX_SORT(p[3], p[6]); PIX_SORT(p[1], p[4]); PIX_SORT(p[2], p[5]); PIX_SORT(p[4], p[7]); PIX_SORT(p[4], p[2]); PIX_SORT(p[6], p[4]); PIX_SORT(p[4], p[2]); bstemp[dir] = p[4]; //if (c==0 && dir==0) printf("vblock= %d hblock= %d blockshiftsmedian= %f \n",vblock,hblock,p[4]); } //if (verbose) fprintf (stderr,_("tile vshift hshift (%d %d %4f %4f)...\n"),vblock, hblock, blockshifts[(vblock)*hblsz+hblock][c][0], blockshifts[(vblock)*hblsz+hblock][c][1]); //now prepare coefficient matrix; use only data points within two std devs of zero if (SQR(bstemp[0]) > 4.0 * blockvar[0][c] || SQR(bstemp[1]) > 4.0 * blockvar[1][c]) { continue; } numblox[c]++; for (dir = 0; dir < 2; dir++) { for (i = 0; i < polyord; i++) { for (j = 0; j < polyord; j++) { for (m = 0; m < polyord; m++) for (n = 0; n < polyord; n++) { polymat[c][dir][numpar * (polyord * i + j) + (polyord * m + n)] += (float)pow((double)vblock, i + m) * pow((double)hblock, j + n) * blockwt[vblock * hblsz + hblock]; } shiftmat[c][dir][(polyord * i + j)] += (float)pow((double)vblock, i) * pow((double)hblock, j) * bstemp[dir] * blockwt[vblock * hblsz + hblock]; } //if (c==0 && dir==0) {printf("i= %d j= %d shiftmat= %f \n",i,j,shiftmat[c][dir][(polyord*i+j)]);} }//monomials }//dir }//c }//blocks numblox[1] = min(numblox[0], numblox[2]); //if too few data points, restrict the order of the fit to linear if (numblox[1] < 32) { polyord = 2; numpar = 4; if (numblox[1] < 10) { printf ("numblox = %d \n", numblox[1]); processpasstwo = false; } } if(processpasstwo) //fit parameters to blockshifts for (c = 0; c < 3; c += 2) for (dir = 0; dir < 2; dir++) { res = LinEqSolve(numpar, polymat[c][dir], shiftmat[c][dir], fitparams[c][dir]); if (res) { printf("CA correction pass failed -- can't solve linear equations for color %d direction %d...\n", c, dir); processpasstwo = false; } } } //fitparams[polyord*i+j] gives the coefficients of (vblock^i hblock^j) in a polynomial fit for i,j<=4 } //end of initialization for CA correction pass //only executed if cared and cablue are zero } // Main algorithm: Tile loop if(processpasstwo) { #pragma omp for schedule(dynamic) collapse(2) nowait for (top = -border; top < height; top += TS - border2) for (left = -border; left < width; left += TS - border2) { vblock = ((top + border) / (TS - border2)) + 1; hblock = ((left + border) / (TS - border2)) + 1; int bottom = min(top + TS, height + border); int right = min(left + TS, width + border); int rr1 = bottom - top; int cc1 = right - left; //t1_init = clock(); if (top < 0) { rrmin = border; } else { rrmin = 0; } if (left < 0) { ccmin = border; } else { ccmin = 0; } if (bottom > height) { rrmax = height - top; } else { rrmax = rr1; } if (right > width) { ccmax = width - left; } else { ccmax = cc1; } // rgb from input CFA data // rgb values should be floating point number between 0 and 1 // after white balance multipliers are applied 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] = image[indx][c]/65535.0f; rgb[c][indx1] = (rawData[row][col]) / 65535.0f; //rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation if ((c & 1) == 0) { rgb[1][indx1] = Gtmp[indx]; } } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //fill borders if (rrmin > 0) { for (rr = 0; rr < border; rr++) for (cc = ccmin; cc < ccmax; cc++) { c = FC(rr, cc); rgb[c][rr * TS + cc] = rgb[c][(border2 - rr) * TS + cc]; rgb[1][rr * TS + cc] = rgb[1][(border2 - rr) * TS + cc]; } } if (rrmax < rr1) { for (rr = 0; rr < border; rr++) for (cc = ccmin; cc < ccmax; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + cc] = (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 rgb[1][(rrmax + rr)*TS + cc] = Gtmp[(height - rr - 2) * width + left + cc]; } } if (ccmin > 0) { for (rr = rrmin; rr < rrmax; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][rr * TS + cc] = rgb[c][rr * TS + border2 - cc]; rgb[1][rr * TS + cc] = rgb[1][rr * TS + border2 - cc]; } } if (ccmax < cc1) { for (rr = rrmin; rr < rrmax; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][rr * TS + ccmax + cc] = (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 rgb[1][rr * TS + ccmax + cc] = Gtmp[(top + rr) * width + (width - cc - 2)]; } } //also, fill the image corners if (rrmin > 0 && ccmin > 0) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rr)*TS + cc] = (rawData[border2 - rr][border2 - cc]) / 65535.0f; //rgb[(rr)*TS+cc][c] = (rgb[(border2-rr)*TS+(border2-cc)][c]);//for dcraw implementation rgb[1][(rr)*TS + cc] = Gtmp[(border2 - rr) * width + border2 - cc]; } } if (rrmax < rr1 && ccmax < cc1) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + ccmax + cc] = (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 rgb[1][(rrmax + rr)*TS + ccmax + cc] = Gtmp[(height - rr - 2) * width + (width - cc - 2)]; } } if (rrmin > 0 && ccmax < cc1) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rr)*TS + ccmax + cc] = (rawData[(border2 - rr)][(width - cc - 2)]) / 65535.0f; //rgb[(rr)*TS+ccmax+cc][c] = (image[(border2-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation rgb[1][(rr)*TS + ccmax + cc] = Gtmp[(border2 - rr) * width + (width - cc - 2)]; } } if (rrmax < rr1 && ccmin > 0) { for (rr = 0; rr < border; rr++) for (cc = 0; cc < border; cc++) { c = FC(rr, cc); rgb[c][(rrmax + rr)*TS + cc] = (rawData[(height - rr - 2)][(border2 - cc)]) / 65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(border2-cc)][c])/65535.0f;//for dcraw implementation rgb[1][(rrmax + rr)*TS + cc] = Gtmp[(height - rr - 2) * width + (border2 - cc)]; } } //end of border fill // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if (!autoCA) { //manual CA correction; use red/blue slider values to set CA shift parameters for (rr = 3; rr < rr1 - 3; rr++) for (row = rr + top, cc = 3, indx = rr * TS + cc; cc < cc1 - 3; cc++, indx++) { col = cc + left; c = FC(rr, cc); if (c != 1) { //compute directional weights using image gradients wtu = 1.0 / SQR(eps + fabsf(rgb[1][(rr + 1) * TS + cc] - rgb[1][(rr - 1) * TS + cc]) + fabsf(rgb[c][(rr) * TS + cc] - rgb[c][(rr - 2) * TS + cc]) + fabsf(rgb[1][(rr - 1) * TS + cc] - rgb[1][(rr - 3) * TS + cc])); wtd = 1.0 / SQR(eps + fabsf(rgb[1][(rr - 1) * TS + cc] - rgb[1][(rr + 1) * TS + cc]) + fabsf(rgb[c][(rr) * TS + cc] - rgb[c][(rr + 2) * TS + cc]) + fabsf(rgb[1][(rr + 1) * TS + cc] - rgb[1][(rr + 3) * TS + cc])); wtl = 1.0 / SQR(eps + fabsf(rgb[1][(rr) * TS + cc + 1] - rgb[1][(rr) * TS + cc - 1]) + fabsf(rgb[c][(rr) * TS + cc] - rgb[c][(rr) * TS + cc - 2]) + fabsf(rgb[1][(rr) * TS + cc - 1] - rgb[1][(rr) * TS + cc - 3])); wtr = 1.0 / SQR(eps + fabsf(rgb[1][(rr) * TS + cc - 1] - rgb[1][(rr) * TS + cc + 1]) + fabsf(rgb[c][(rr) * TS + cc] - rgb[c][(rr) * TS + cc + 2]) + fabsf(rgb[1][(rr) * TS + cc + 1] - rgb[1][(rr) * TS + cc + 3])); //store in rgb array the interpolated G value at R/B grid points using directional weighted average rgb[1][indx] = (wtu * rgb[1][indx - v1] + wtd * rgb[1][indx + v1] + wtl * rgb[1][indx - 1] + wtr * rgb[1][indx + 1]) / (wtu + wtd + wtl + wtr); } if (row > -1 && row < height && col > -1 && col < width) { Gtmp[row * width + col] = rgb[1][indx]; } } float hfrac = -((float)(hblock - 0.5) / (hblsz - 2) - 0.5); float vfrac = -((float)(vblock - 0.5) / (vblsz - 2) - 0.5) * height / width; blockshifts[(vblock)*hblsz + hblock][0][0] = 2 * vfrac * cared; blockshifts[(vblock)*hblsz + hblock][0][1] = 2 * hfrac * cared; blockshifts[(vblock)*hblsz + hblock][2][0] = 2 * vfrac * cablue; blockshifts[(vblock)*hblsz + hblock][2][1] = 2 * hfrac * cablue; } else { //CA auto correction; use CA diagnostic pass to set shift parameters blockshifts[(vblock)*hblsz + hblock][0][0] = blockshifts[(vblock) * hblsz + hblock][0][1] = 0; blockshifts[(vblock)*hblsz + hblock][2][0] = blockshifts[(vblock) * hblsz + hblock][2][1] = 0; for (i = 0; i < polyord; i++) for (j = 0; j < polyord; j++) { //printf("i= %d j= %d polycoeff= %f \n",i,j,fitparams[0][0][polyord*i+j]); blockshifts[(vblock)*hblsz + hblock][0][0] += (float)pow((float)vblock, i) * pow((float)hblock, j) * fitparams[0][0][polyord * i + j]; blockshifts[(vblock)*hblsz + hblock][0][1] += (float)pow((float)vblock, i) * pow((float)hblock, j) * fitparams[0][1][polyord * i + j]; blockshifts[(vblock)*hblsz + hblock][2][0] += (float)pow((float)vblock, i) * pow((float)hblock, j) * fitparams[2][0][polyord * i + j]; blockshifts[(vblock)*hblsz + hblock][2][1] += (float)pow((float)vblock, i) * pow((float)hblock, j) * fitparams[2][1][polyord * i + j]; } blockshifts[(vblock)*hblsz + hblock][0][0] = LIM(blockshifts[(vblock) * hblsz + hblock][0][0], -bslim, bslim); blockshifts[(vblock)*hblsz + hblock][0][1] = LIM(blockshifts[(vblock) * hblsz + hblock][0][1], -bslim, bslim); blockshifts[(vblock)*hblsz + hblock][2][0] = LIM(blockshifts[(vblock) * hblsz + hblock][2][0], -bslim, bslim); blockshifts[(vblock)*hblsz + hblock][2][1] = LIM(blockshifts[(vblock) * hblsz + hblock][2][1], -bslim, bslim); }//end of setting CA shift parameters //printf("vblock= %d hblock= %d vshift= %f hshift= %f \n",vblock,hblock,blockshifts[(vblock)*hblsz+hblock][0][0],blockshifts[(vblock)*hblsz+hblock][0][1]); for (c = 0; c < 3; c += 2) { //some parameters for the bilinear interpolation shiftvfloor[c] = floor((float)blockshifts[(vblock) * hblsz + hblock][c][0]); shiftvceil[c] = ceil((float)blockshifts[(vblock) * hblsz + hblock][c][0]); shiftvfrac[c] = blockshifts[(vblock) * hblsz + hblock][c][0] - shiftvfloor[c]; shifthfloor[c] = floor((float)blockshifts[(vblock) * hblsz + hblock][c][1]); shifthceil[c] = ceil((float)blockshifts[(vblock) * hblsz + hblock][c][1]); shifthfrac[c] = blockshifts[(vblock) * hblsz + hblock][c][1] - shifthfloor[c]; if (blockshifts[(vblock)*hblsz + hblock][c][0] > 0) { GRBdir[0][c] = 1; } else { GRBdir[0][c] = -1; } if (blockshifts[(vblock)*hblsz + hblock][c][1] > 0) { GRBdir[1][c] = 1; } else { GRBdir[1][c] = -1; } } for (rr = 4; rr < rr1 - 4; rr++) for (cc = 4 + (FC(rr, 2) & 1), c = FC(rr, cc); cc < cc1 - 4; cc += 2) { //perform CA correction using color ratios or color differences Ginthfloor = (1 - shifthfrac[c]) * rgb[1][(rr + shiftvfloor[c]) * TS + cc + shifthfloor[c]] + (shifthfrac[c]) * rgb[1][(rr + shiftvfloor[c]) * TS + cc + shifthceil[c]]; Ginthceil = (1 - shifthfrac[c]) * rgb[1][(rr + shiftvceil[c]) * TS + cc + shifthfloor[c]] + (shifthfrac[c]) * rgb[1][(rr + shiftvceil[c]) * TS + cc + shifthceil[c]]; //Gint is blinear interpolation of G at CA shift point Gint = (1 - shiftvfrac[c]) * Ginthfloor + (shiftvfrac[c]) * Ginthceil; //determine R/B at grid points using color differences at shift point plus interpolated G value at grid point //but first we need to interpolate G-R/G-B to grid points... grbdiff[((rr)*TS + cc) >> 1] = Gint - rgb[c][(rr) * TS + cc]; gshift[((rr)*TS + cc) >> 1] = Gint; } for (rr = 8; rr < rr1 - 8; rr++) for (cc = 8 + (FC(rr, 2) & 1), c = FC(rr, cc), indx = rr * TS + cc; cc < cc1 - 8; cc += 2, indx += 2) { //if (rgb[indx][c]>clip_pt || Gtmp[indx]>clip_pt) continue; grbdiffold = rgb[1][indx] - rgb[c][indx]; //interpolate color difference from optical R/B locations to grid locations grbdiffinthfloor = (1.0f - shifthfrac[c] / 2.0f) * grbdiff[indx >> 1] + (shifthfrac[c] / 2.0f) * grbdiff[(indx - 2 * GRBdir[1][c]) >> 1]; grbdiffinthceil = (1.0f - shifthfrac[c] / 2.0f) * grbdiff[((rr - 2 * GRBdir[0][c]) * TS + cc) >> 1] + (shifthfrac[c] / 2.0f) * grbdiff[((rr - 2 * GRBdir[0][c]) * TS + cc - 2 * GRBdir[1][c]) >> 1]; //grbdiffint is bilinear interpolation of G-R/G-B at grid point grbdiffint = (1.0f - shiftvfrac[c] / 2.0f) * grbdiffinthfloor + (shiftvfrac[c] / 2.0f) * grbdiffinthceil; //now determine R/B at grid points using interpolated color differences and interpolated G value at grid point RBint = rgb[1][indx] - grbdiffint; if (fabsf(RBint - rgb[c][indx]) < 0.25f * (RBint + rgb[c][indx])) { if (fabsf(grbdiffold) > fabsf(grbdiffint) ) { rgb[c][indx] = RBint; } } else { //gradient weights using difference from G at CA shift points and G at grid points p[0] = 1.0f / (eps + fabsf(rgb[1][indx] - gshift[indx >> 1])); p[1] = 1.0f / (eps + fabsf(rgb[1][indx] - gshift[(indx - 2 * GRBdir[1][c]) >> 1])); p[2] = 1.0f / (eps + fabsf(rgb[1][indx] - gshift[((rr - 2 * GRBdir[0][c]) * TS + cc) >> 1])); p[3] = 1.0f / (eps + fabsf(rgb[1][indx] - gshift[((rr - 2 * GRBdir[0][c]) * TS + cc - 2 * GRBdir[1][c]) >> 1])); grbdiffint = (p[0] * grbdiff[indx >> 1] + p[1] * grbdiff[(indx - 2 * GRBdir[1][c]) >> 1] + p[2] * grbdiff[((rr - 2 * GRBdir[0][c]) * TS + cc) >> 1] + p[3] * grbdiff[((rr - 2 * GRBdir[0][c]) * TS + cc - 2 * GRBdir[1][c]) >> 1]) / (p[0] + p[1] + p[2] + p[3]); //now determine R/B at grid points using interpolated color differences and interpolated G value at grid point if (fabsf(grbdiffold) > fabsf(grbdiffint) ) { rgb[c][indx] = rgb[1][indx] - grbdiffint; } } //if color difference interpolation overshot the correction, just desaturate if (grbdiffold * grbdiffint < 0) { rgb[c][indx] = rgb[1][indx] - 0.5f * (grbdiffold + grbdiffint); } } // copy CA corrected results to temporary image matrix for (rr = border; rr < rr1 - border; rr++) { c = FC(rr + top, left + border + FC(rr + top, 2) & 1); for (row = rr + top, cc = border + (FC(rr, 2) & 1), indx = (row * width + cc + left) >> 1; cc < cc1 - border; cc += 2, indx++) { col = cc + left; RawDataTmp[indx] = 65535.0f * rgb[c][(rr) * TS + cc] + 0.5f; //image[indx][c] = CLIP((int)(65535.0*rgb[(rr)*TS+cc][c] + 0.5));//for dcraw implementation } } if(plistener) { progresscounter++; if(progresscounter % 8 == 0) #pragma omp critical { progress += (double)(8.0 * (TS - border2) * (TS - border2)) / (2 * height * width); if (progress > 1.0) { progress = 1.0; } plistener->setProgress(progress); } } } #pragma omp barrier // copy temporary image matrix back to image matrix #pragma omp for for(row = 0; row < height; row++) for(col = 0 + (FC(row, 0) & 1), indx = (row * width + col) >> 1; col < width; col += 2, indx++) { rawData[row][col] = RawDataTmp[indx]; } } // clean up free(buffer); } free(Gtmp); free(buffer1); free(RawDataTmp); if(plistener) { plistener->setProgress(1.0); } #undef TS #undef TSH #undef PIX_SORT }