/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee 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. * * RawTherapee 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 RawTherapee. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _OPENMP #include #endif namespace rtengine { #undef ABS #undef MAX #undef MIN #undef DIST #define ABS(a) ((a)<0?-(a):(a)) #define MAX(a,b) ((a)<(b)?(b):(a)) #define MIN(a,b) ((a)>(b)?(b):(a)) #define DIST(a,b) (ABS(a-b)) #define CLIREF(x) LIM(x,-200000.0,200000.0) // avoid overflow : do not act directly on image[] or pix[] #define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } extern Settings* settings; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::eahd_demosaic () { if (plistener) { plistener->setProgressStr ("Demosaicing..."); plistener->setProgress (0.0); } // prepare cache and constants for cielab conversion //TODO: revisit after conversion to D50 illuminant lc00 = (0.412453 * rgb_cam[0][0] + 0.357580 * rgb_cam[0][1] + 0.180423 * rgb_cam[0][2]) ;// / 0.950456; lc01 = (0.412453 * rgb_cam[1][0] + 0.357580 * rgb_cam[1][1] + 0.180423 * rgb_cam[1][2]) ;// / 0.950456; lc02 = (0.412453 * rgb_cam[2][0] + 0.357580 * rgb_cam[2][1] + 0.180423 * rgb_cam[2][2]) ;// / 0.950456; lc10 = 0.212671 * rgb_cam[0][0] + 0.715160 * rgb_cam[0][1] + 0.072169 * rgb_cam[0][2]; lc11 = 0.212671 * rgb_cam[1][0] + 0.715160 * rgb_cam[1][1] + 0.072169 * rgb_cam[1][2]; lc12 = 0.212671 * rgb_cam[2][0] + 0.715160 * rgb_cam[2][1] + 0.072169 * rgb_cam[2][2]; lc20 = (0.019334 * rgb_cam[0][0] + 0.119193 * rgb_cam[0][1] + 0.950227 * rgb_cam[0][2]) ;// / 1.088754; lc21 = (0.019334 * rgb_cam[1][0] + 0.119193 * rgb_cam[1][1] + 0.950227 * rgb_cam[1][2]) ;// / 1.088754; lc22 = (0.019334 * rgb_cam[2][0] + 0.119193 * rgb_cam[2][1] + 0.950227 * rgb_cam[2][2]) ;// / 1.088754; int maxindex = 2*65536; cache = new double[maxindex]; threshold = (int)(0.008856*MAXVAL); for (int i=0; isv) { // fixate horizontal pixel dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]); dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]); dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]); dLmapv[dmi] = DIST(lLv[ix][j], lLh[idx][j+y]); dCamapv[dmi] = DIST(lav[ix][j], lah[idx][j+y]); dCbmapv[dmi] = DIST(lbv[ix][j], lbh[idx][j+y]); } else if (shISGREEN(i-1,j)) green[i-1][j] = rawData[i-1][j]; else { hc = homh[imx][j]; vc = homv[imx][j]; if (hc > vc) green[i-1][j] = gh[(i-1)%4][j]; else if (hc < vc) green[i-1][j] = gv[(i-1)%4][j]; else green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; } } if (!(i%20) && plistener) plistener->setProgress ((double)i / (H-2)); } // finish H-2th and H-1th row, homogenity value is still valailable int hc, vc; for (int i=H-1; i vc) green[i-1][j] = gh[(i-1)%4][j]; else if (hc < vc) green[i-1][j] = gv[(i-1)%4][j]; else green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; } freeArray2(rh, 3); freeArray2(gh, 4); freeArray2(bh, 3); freeArray2(rv, 3); freeArray2(gv, 4); freeArray2(bv, 3); freeArray2(lLh, 3); freeArray2(lah, 3); freeArray2(lbh, 3); freeArray2(homh, 3); freeArray2(lLv, 3); freeArray2(lav, 3); freeArray2(lbv, 3); freeArray2(homv, 3); // Interpolate R and B for (int i=0; iISGREEN(i,j)) green[i][j] = rawData[i][j]; else { if (hpmap[i][j]==1) { int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2); int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2); int dx = rawData[i][j+1] - rawData[i][j-1]; int d1 = rawData[i][j+3] - rawData[i][j+1]; int d2 = rawData[i][j+2] - rawData[i][j]; int d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2; int d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2; double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); d1 = rawData[i][j-3] - rawData[i][j-1]; d2 = rawData[i][j-2] - rawData[i][j]; d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2; d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2; double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); green[i][j] = (e2 * g2 + e4 * g4) / (e2 + e4); } else if (hpmap[i][j]==2) { int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2); int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2); int dy = rawData[i+1][j] - rawData[i-1][j]; int d1 = rawData[i-1][j] - rawData[i-3][j]; int d2 = rawData[i][j] - rawData[i-2][j]; int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2; int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2; double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); d1 = rawData[i+1][j] - rawData[i+3][j]; d2 = rawData[i][j] - rawData[i+2][j]; d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2; d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2; double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); green[i][j] = (e1 * g1 + e3 * g3) / (e1 + e3); } else { int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2); int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2); int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2); int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2); int dx = rawData[i][j+1] - rawData[i][j-1]; int dy = rawData[i+1][j] - rawData[i-1][j]; int d1 = rawData[i-1][j] - rawData[i-3][j]; int d2 = rawData[i][j] - rawData[i-2][j]; int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2; int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2; double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); d1 = rawData[i][j+3] - rawData[i][j+1]; d2 = rawData[i][j+2] - rawData[i][j]; d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2; d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2; double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); d1 = rawData[i+1][j] - rawData[i+3][j]; d2 = rawData[i][j] - rawData[i+2][j]; d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2; d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2; double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); d1 = rawData[i][j-3] - rawData[i][j-1]; d2 = rawData[i][j-2] - rawData[i][j]; d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2; d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2; double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); green[i][j] = (e1*g1 + e2*g2 + e3*g3 + e4*g4) / (e1 + e2 + e3 + e4); } } } } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::hphd_demosaic () { if (plistener) { plistener->setProgressStr ("Demosaicing..."); plistener->setProgress (0.0); } float** hpmap = allocArray< float >(W,H, true); #ifdef _OPENMP #pragma omp parallel { int tid = omp_get_thread_num(); int nthreads = omp_get_num_threads(); int blk = W/nthreads; if (tidsetProgress (0.33); for (int i=0; i(hpmap, H); if (plistener) plistener->setProgress (0.66); for (int i=0; isetProgress (1.0); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #define FORCC for (c=0; c < colors; c++) #define fc(row,col) \ (ri->prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) typedef unsigned short ushort; void RawImageSource::vng4_demosaic () { static const signed char *cp, terms[] = { -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, +1,+0,+2,+1,0,0x10 }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; if (plistener) { plistener->setProgressStr ("Demosaicing..."); plistener->setProgress (0.0); } float (*brow[5])[4], *pix; int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; int g, diff, thold, num, c, width=W, height=H, colors=4; float (*image)[4]; int lcode[16][16][32], shift, i, j; image = (float (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; ii gval[g]) gmin = gval[g]; if (gmax < gval[g]) gmax = gval[g]; } if (gmax == 0) { memcpy (brow[2][col], pix, sizeof *image); continue; } thold = gmin + (gmax /2); memset (sum, 0, sizeof sum); for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { FORCC if (c == color && ip[1]) sum[c] += (pix[c] + pix[ip[1]]) /2; else sum[c] += pix[ip[0] + c]; num++; } } FORCC { /* Save to buffer */ t = pix[color]; if (c != color) t += (sum[c] - sum[color]) / num; brow[2][col][c] = t; } } if (row > 3) /* Write buffer to image */ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); for (g=0; g < 4; g++) brow[(g-1) & 3] = brow[g]; if (!(row%20) && plistener) plistener->setProgress ((double)row / (H-2)); } memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); free (brow[4]); free (code[0][0]); for (int i=0; iget_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) #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)) /* Patterned Pixel Grouping Interpolation by Alain Desbiolles */ void RawImageSource::ppg_demosaic() { int width=W, height=H; int dir[5] = { 1, width, -1, -width, 1 }; int row, col, diff[2], guess[2], c, d, i; float (*pix)[4]; float (*image)[4]; int colors = 3; if (plistener) { plistener->setProgressStr ("Demosaicing..."); plistener->setProgress (0.0); } image = (float (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; ii 0; i++) { guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2*d][c] - pix[2*d][c]; diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + ABS(pix[ 2*d][c] - pix[ 0][c]) + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + ( ABS(pix[ 3*d][1] - pix[ d][1]) + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; } d = dir[i = diff[0] > diff[1]]; pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); } if(plistener) plistener->setProgress(0.33*row/(height-3)); } /* Calculate red and blue for each green pixel: */ for (row=1; row < height-1; row++) { for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; c=2-c, i++) pix[0][c] = CLIP(0.5*(pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]) ); } if(plistener) plistener->setProgress(0.33 + 0.33*row/(height-1)); } /* Calculate blue for red pixels and vice versa: */ for (row=1; row < height-1; row++) { for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) + ABS(pix[ d][1] - pix[0][1]); guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]; } if (diff[0] != diff[1]) pix[0][c] = CLIP(guess[diff[0] > diff[1]] /2); else pix[0][c] = CLIP((guess[0]+guess[1]) /4); } if(plistener) plistener->setProgress(0.67 + 0.33*row/(height-1)); } red = new float*[H]; for (int i=0; i= border && row < height-border) col = width-border; memset (sum, 0, sizeof sum); for (y=row-1; y != row+2; y++) for (x=col-1; x != col+2; x++) if (y < height && x < width) { f = fc(y,x); sum[f] += image[y*width+x][f]; sum[f+4]++; } f = fc(row,col); FORCC if (c != f && sum[c+4]) image[row*width+col][c] = sum[c] / sum[c+4]; } } /* Adaptive Homogeneity-Directed interpolation is based on the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. */ #define TS 256 /* Tile Size */ #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) #define SQR(x) ((x)*(x)) void RawImageSource::ahd_demosaic(int winx, int winy, int winw, int winh) { int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; float (*pix)[4], (*rix)[3]; static const int dir[4] = { -1, 1, -TS, TS }; float ldiff[2][4], abdiff[2][4], leps, abeps; float r, xyz[3], xyz_cam[3][4]; float (*cbrt); float (*rgb)[TS][TS][3]; float (*lab)[TS][TS][3]; float (*lix)[3]; char (*homo)[TS][TS], *buffer; int width=W, height=H; float (*image)[4]; int colors = 3; const double xyz_rgb[3][3] = { /* XYZ from RGB */ { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const float d65_white[3] = { 0.950456, 1, 1.088754 }; const float d50_white[3] = { 0.96422, 1, 0.82521 }; if (plistener) { plistener->setProgressStr ("AHD Demosaicing..."); plistener->setProgress (0.0); } image = (float (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; ii 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; } for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (xyz_cam[i][j] = k=0; k < 3; k++) xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; border_interpolate(5, image); buffer = (char *) malloc (13*TS*TS*sizeof(float)); /* 1664 kB */ //merror (buffer, "ahd_interpolate()"); rgb = (float(*)[TS][TS][3]) buffer; lab = (float(*)[TS][TS][3])(buffer + 6*TS*TS*sizeof(float)); homo = (char (*)[TS][TS]) (buffer + 12*TS*TS*sizeof(float)); // helper variables for progress indication int n_tiles = ((height-7 + (TS-7))/(TS-6)) * ((width-7 + (TS-7))/(TS-6)); int tile = 0; for (top=2; top < height-5; top += TS-6) for (left=2; left < width-5; left += TS-6) { /* Interpolate green horizontally and vertically: */ for (row = top; row < top+TS && row < height-2; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { pix = image + (row*width+col); val = 0.25*((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) ; rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = 0.25*((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) ; rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } /* Interpolate red and blue, and convert to CIELab: */ for (d=0; d < 2; d++) for (row=top+1; row < top+TS-1 && row < height-3; row++) for (col=left+1; col < left+TS-1 && col < width-3; col++) { pix = image + (row*width+col); rix = &rgb[d][row-top][col-left]; lix = &lab[d][row-top][col-left]; if ((c = 2 - FC(row,col)) == 1) { c = FC(row+1,col); val = pix[0][1] + (0.5*( pix[-1][2-c] + pix[1][2-c] - rix[-1][1] - rix[1][1] ) ); rix[0][2-c] = CLIP(val); val = pix[0][1] + (0.5*( pix[-width][c] + pix[width][c] - rix[-TS][1] - rix[TS][1] ) ); } else val = rix[0][1] + (0.25*( pix[-width-1][c] + pix[-width+1][c] + pix[+width-1][c] + pix[+width+1][c] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) ); rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; xyz[0] = xyz[1] = xyz[2] = 0.0; FORCC { xyz[0] += xyz_cam[0][c] * rix[0][c]; xyz[1] += xyz_cam[1][c] * rix[0][c]; xyz[2] += xyz_cam[2][c] * rix[0][c]; } xyz[0] = CurveFactory::flinterp(cbrt,xyz[0]); xyz[1] = CurveFactory::flinterp(cbrt,xyz[1]); xyz[2] = CurveFactory::flinterp(cbrt,xyz[2]); //xyz[0] = xyz[0] > 0.008856 ? pow(xyz[0]/65535,1/3.0) : 7.787*xyz[0] + 16/116.0; //xyz[1] = xyz[1] > 0.008856 ? pow(xyz[1]/65535,1/3.0) : 7.787*xyz[1] + 16/116.0; //xyz[2] = xyz[2] > 0.008856 ? pow(xyz[2]/65535,1/3.0) : 7.787*xyz[2] + 16/116.0; lix[0][0] = (116 * xyz[1] - 16); lix[0][1] = 500 * (xyz[0] - xyz[1]); lix[0][2] = 200 * (xyz[1] - xyz[2]); } /* Build homogeneity maps from the CIELab images: */ memset (homo, 0, 2*TS*TS); for (row=top+2; row < top+TS-2 && row < height-4; row++) { tr = row-top; for (col=left+2; col < left+TS-2 && col < width-4; col++) { tc = col-left; for (d=0; d < 2; d++) { lix = &lab[d][tr][tc]; for (i=0; i < 4; i++) { ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + SQR(lix[0][2]-lix[dir[i]][2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (d=0; d < 2; d++) for (i=0; i < 4; i++) if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) homo[d][tr][tc]++; } } /* Combine the most homogenous pixels for the final result: */ for (row=top+3; row < top+TS-3 && row < height-5; row++) { tr = row-top; for (col=left+3; col < left+TS-3 && col < width-5; col++) { tc = col-left; for (d=0; d < 2; d++) for (hm[d]=0, i=tr-1; i <= tr+1; i++) for (j=tc-1; j <= tc+1; j++) hm[d] += homo[d][i][j]; if (hm[0] != hm[1]) FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; else FORC3 image[row*width+col][c] = 0.5*(rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) ; } } tile++; if(plistener) { plistener->setProgress((double)tile / n_tiles); } } if(plistener) plistener->setProgress (1.0); free (buffer); for (int i=0; iverbose) printf("Refinement Lassus\n"); MyTime t1e,t2e; t1e.set(); int u=W, v=2*u, w=3*u, x=4*u, y=5*u; float (*image)[4]; image = (float(*)[4]) calloc(W*H, sizeof *image); #pragma omp parallel shared(image) { // convert red, blue, green to image #pragma omp for for (int i=0;isetProgressStr ("Refinement..."); plistener->setProgress ((float)b/PassCount); } // Reinforce interpolated green pixels on RED/BLUE pixel locations #pragma omp for for (int row=6; rowverbose) printf("Refinement %d usec\n", t2e.etime(t1e)); } /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of the author nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // If you want to use the code, you need to display name of the original authors in // your software! /* DCB demosaicing by Jacek Gozdz (cuniek@kft.umcs.lublin.pl) * the code is open source (BSD licence) */ #define TILESIZE 256 #define TILEBORDER 10 #define CACHESIZE (TILESIZE+2*TILEBORDER) inline void RawImageSource::dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border) { rowMin = border; colMin = border; rowMax = CACHESIZE-border; colMax = CACHESIZE-border; if(!y0 ) rowMin = TILEBORDER+border; if(!x0 ) colMin = TILEBORDER+border; if( y0+TILESIZE+TILEBORDER >= H-border) rowMax = TILEBORDER+H-border-y0; if( x0+TILESIZE+TILEBORDER >= W-border) colMax = TILEBORDER+W-border-x0; } void RawImageSource::fill_raw( float (*cache )[4], int x0, int y0, float** rawData) { int rowMin,colMin,rowMax,colMax; dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,0); for (int row=rowMin,y=y0-TILEBORDER+rowMin; row= border && col < W - border && row >= border && row < H - border){ col = W - border; if(col >= x0+TILESIZE+TILEBORDER ) break; } memset(sum, 0, sizeof sum); for (y = row - 1; y != row + 2; y++) for (x = col - 1; x != col + 2; x++) if (y < H && y< y0+TILESIZE+TILEBORDER && x < W && x0) cache[(row-y0+TILEBORDER) * CACHESIZE +TILEBORDER + col-x0][c] = sum[c] / sum[c + 4]; } } } // saves red and blue void RawImageSource::copy_to_buffer( float (*buffer)[3], float (*image)[4]) { for (int indx=0; indx < CACHESIZE*CACHESIZE; indx++) { buffer[indx][0]=image[indx][0]; //R buffer[indx][2]=image[indx][2]; //B } } // restores red and blue void RawImageSource::restore_from_buffer(float (*image)[4], float (*buffer)[3]) { for (int indx=0; indx < CACHESIZE*CACHESIZE; indx++) { image[indx][0]=buffer[indx][0]; //R image[indx][2]=buffer[indx][2]; //B } } // First pass green interpolation void RawImageSource::dcb_hid(float (*image)[4],float (*bufferH)[3], float (*bufferV)[3], int x0, int y0) { const int u=CACHESIZE, v=2*CACHESIZE; int rowMin,colMin,rowMax,colMax; dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); // green pixels for (int row = rowMin; row < rowMax; row++) { for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { assert(indx>=0 && indx=0 && indx=0 && c<3); bufferH[indx][c] = ( 4.f * bufferH[indx][1] - bufferH[indx+u+1][1] - bufferH[indx+u-1][1] - bufferH[indx-u+1][1] - bufferH[indx-u-1][1] + image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f; bufferV[indx][c] = ( 4.f * bufferV[indx][1] - bufferV[indx+u+1][1] - bufferV[indx+u-1][1] - bufferV[indx-u+1][1] - bufferV[indx-u-1][1] + image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f; } // red or blue in green pixels for (int row=rowMin; row=0 && indx=0 && c<3 && d>=0 && d<3); bufferH[indx][c] = (image[indx+1][c] + image[indx-1][c]) * 0.5f; bufferH[indx][d] = (2.f * bufferH[indx][1] - bufferH[indx+u][1] - bufferH[indx-u][1] + image[indx+u][d] + image[indx-u][d]) * 0.5f; bufferV[indx][c] = (2.f * bufferV[indx][1] - bufferV[indx+1][1] - bufferV[indx-1][1] + image[indx+1][c] + image[indx-1][c]) * 0.5f; bufferV[indx][d] = (image[indx+u][d] + image[indx-u][d]) * 0.5f; } // Decide green pixels for (int row = rowMin; row < rowMax; row++) for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col),d=2-c; col < colMax; col+=2, indx+=2) { float current = MAX(image[indx+v][c], MAX(image[indx-v][c], MAX(image[indx-2][c], image[indx+2][c]))) - MIN(image[indx+v][c], MIN(image[indx-v][c], MIN(image[indx-2][c], image[indx+2][c]))) + MAX(image[indx+1+u][d], MAX(image[indx+1-u][d], MAX(image[indx-1+u][d], image[indx-1-u][d]))) - MIN(image[indx+1+u][d], MIN(image[indx+1-u][d], MIN(image[indx-1+u][d], image[indx-1-u][d]))); float currentH = MAX(bufferH[indx+v][d], MAX(bufferH[indx-v][d], MAX(bufferH[indx-2][d], bufferH[indx+2][d]))) - MIN(bufferH[indx+v][d], MIN(bufferH[indx-v][d], MIN(bufferH[indx-2][d], bufferH[indx+2][d]))) + MAX(bufferH[indx+1+u][c], MAX(bufferH[indx+1-u][c], MAX(bufferH[indx-1+u][c], bufferH[indx-1-u][c]))) - MIN(bufferH[indx+1+u][c], MIN(bufferH[indx+1-u][c], MIN(bufferH[indx-1+u][c], bufferH[indx-1-u][c]))); float currentV = MAX(bufferV[indx+v][d], MAX(bufferV[indx-v][d], MAX(bufferV[indx-2][d], bufferV[indx+2][d]))) - MIN(bufferV[indx+v][d], MIN(bufferV[indx-v][d], MIN(bufferV[indx-2][d], bufferV[indx+2][d]))) + MAX(bufferV[indx+1+u][c], MAX(bufferV[indx+1-u][c], MAX(bufferV[indx-1+u][c], bufferV[indx-1-u][c]))) - MIN(bufferV[indx+1+u][c], MIN(bufferV[indx+1-u][c], MIN(bufferV[indx-1+u][c], bufferV[indx-1-u][c]))); assert(indx>=0 && indx=0 && indx=0 && c<4); image[indx][c] = ( 4.f * image[indx][1] - image[indx+u+1][1] - image[indx+u-1][1] - image[indx-u+1][1] - image[indx-u-1][1] + image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] ) * 0.25f; } // red or blue in green pixels for (int row=rowMin; row=0 && indx=0 && c<4); image[indx][c] = (2.f * image[indx][1] - image[indx+1][1] - image[indx-1][1] + image[indx+1][c] + image[indx-1][c]) * 0.5f; image[indx][d] = (2.f * image[indx][1] - image[indx+u][1] - image[indx-u][1] + image[indx+u][d] + image[indx-u][d]) * 0.5f; } } // green correction void RawImageSource::dcb_hid2(float (*image)[4], int x0, int y0) { const int u=CACHESIZE, v=2*CACHESIZE; int rowMin,colMin,rowMax,colMax; dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); for (int row=rowMin; row < rowMax; row++) { for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { assert(indx>=0 && indx=0 && indx ( pix[-4] + pix[+4] + pix[-u] + pix[+u])/4 ) image[indx][3] = ((MIN( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) < (MIN( pix[-u], pix[+u]) + pix[-u] + pix[+u])); else image[indx][3] = ((MAX( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) > (MAX( pix[-u], pix[+u]) + pix[-u] + pix[+u])); } } } // interpolated green pixels are corrected using the map void RawImageSource::dcb_correction(float (*image)[4], int x0, int y0) { const int u=CACHESIZE, v=2*CACHESIZE; int rowMin,colMin,rowMax,colMax; dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); for (int row=rowMin; row < rowMax; row++) { for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { float current = 4.f * image[indx][3] + 2.f * (image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; assert(indx>=0 && indx=0 && indx=0 && indx=0 && indx=0 && indx=0 && c<4); chroma[indx][d]=image[indx][c]-image[indx][1]; } for (int row=rowMin; row=0 && indx=0 && c<2); chroma[indx][c]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]); } for (int row=rowMin; row=0 && indx=0 && c<2); chroma[indx][c]=(f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3]); } for(int row=rowMin; row=0 && indxsetProgressStr ("DCB Demosaicing..."); plistener->setProgress (currentProgress); } int wTiles = W/TILESIZE + (W%TILESIZE?1:0); int hTiles = H/TILESIZE + (H%TILESIZE?1:0); int numTiles = wTiles * hTiles; int tilesDone=0; #ifdef _OPENMP int nthreads = omp_get_max_threads(); float (**image)[4] = (float(**)[4]) calloc( nthreads,sizeof( void*) ); float (**image2)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) ); float (**image3)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) ); float (**chroma)[2] = (float (**)[2]) calloc( nthreads,sizeof( void*) ); for(int i=0; i0;i--) { dcb_hid2(tile,x0,y0); dcb_hid2(tile,x0,y0); dcb_hid2(tile,x0,y0); dcb_map(tile,x0,y0); dcb_correction(tile,x0,y0); } dcb_color(tile,x0,y0); dcb_pp(tile,x0,y0); dcb_map(tile,x0,y0); dcb_correction2(tile,x0,y0); dcb_map(tile,x0,y0); dcb_correction(tile,x0,y0); dcb_color(tile,x0,y0); dcb_map(tile,x0,y0); dcb_correction(tile,x0,y0); dcb_map(tile,x0,y0); dcb_correction(tile,x0,y0); dcb_map(tile,x0,y0); restore_from_buffer(tile, buffer); dcb_color(tile,x0,y0); if (dcb_enhance) { dcb_refinement(tile,x0,y0); dcb_color_full(tile,x0,y0,chrm); } for(int y=0;y currentProgress){ currentProgress+=0.1; // Show progress each 10% plistener->setProgress (currentProgress); } } #pragma omp atomic tilesDone++; } #ifdef _OPENMP for(int i=0; isetProgress (1.0); } #undef TILEBORDER #undef TILESIZE #undef CACHESIZE } /* namespace */