/* * 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 "rawimagesource.h" #include "rawimagesource_i.h" #include "median.h" #include "rawimage.h" #include "mytime.h" #include "iccmatrices.h" #include "iccstore.h" #include "image8.h" #include "curves.h" #include "dfmanager.h" #include "slicer.h" #include "rt_math.h" #include "color.h" #include "../rtgui/multilangmgr.h" #include "procparams.h" #include "sleef.c" #include "opthelper.h" #ifdef _OPENMP #include #endif using namespace std; namespace rtengine { #undef ABS #undef DIST #define ABS(a) ((a)<0?-(a):(a)) #define DIST(a,b) (ABS(a-b)) #define CLIREF(x) LIM(x,-200000.0f,200000.0f) // avoid overflow : do not act directly on image[] or pix[] #define x1125(a) (a + xdivf(a, 3)) #define x0875(a) (a - xdivf(a, 3)) #define x0250(a) xdivf(a, 2) #define x00625(a) xdivf(a, 4) #define x0125(a) xdivf(a, 3) #define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } extern const Settings* settings; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::eahd_demosaic () { if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::eahd])); plistener->setProgress (0.0); } // prepare cache and constants for cielab conversion //TODO: revisit after conversion to D50 illuminant lc00 = (0.412453 * imatrices.rgb_cam[0][0] + 0.357580 * imatrices.rgb_cam[0][1] + 0.180423 * imatrices.rgb_cam[0][2]) ;// / 0.950456; lc01 = (0.412453 * imatrices.rgb_cam[1][0] + 0.357580 * imatrices.rgb_cam[1][1] + 0.180423 * imatrices.rgb_cam[1][2]) ;// / 0.950456; lc02 = (0.412453 * imatrices.rgb_cam[2][0] + 0.357580 * imatrices.rgb_cam[2][1] + 0.180423 * imatrices.rgb_cam[2][2]) ;// / 0.950456; lc10 = 0.212671 * imatrices.rgb_cam[0][0] + 0.715160 * imatrices.rgb_cam[0][1] + 0.072169 * imatrices.rgb_cam[0][2]; lc11 = 0.212671 * imatrices.rgb_cam[1][0] + 0.715160 * imatrices.rgb_cam[1][1] + 0.072169 * imatrices.rgb_cam[1][2]; lc12 = 0.212671 * imatrices.rgb_cam[2][0] + 0.715160 * imatrices.rgb_cam[2][1] + 0.072169 * imatrices.rgb_cam[2][2]; lc20 = (0.019334 * imatrices.rgb_cam[0][0] + 0.119193 * imatrices.rgb_cam[0][1] + 0.950227 * imatrices.rgb_cam[0][2]) ;// / 1.088754; lc21 = (0.019334 * imatrices.rgb_cam[1][0] + 0.119193 * imatrices.rgb_cam[1][1] + 0.950227 * imatrices.rgb_cam[1][2]) ;// / 1.088754; lc22 = (0.019334 * imatrices.rgb_cam[2][0] + 0.119193 * imatrices.rgb_cam[2][1] + 0.950227 * imatrices.rgb_cam[2][2]) ;// / 1.088754; int maxindex = 3*65536;//2*65536 3 = avoid crash 3/2013 J.Desmis cache = new double[maxindex]; threshold = (int)(0.008856*MAXVALD); 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 (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::hphd])); 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);//TODO: seems to cause sigabrt ??? why??? if (plistener) plistener->setProgress (0.66); for (int i=0; isetProgress (1.0); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #define fc(row,col) (prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) typedef unsigned short ushort; void RawImageSource::vng4_demosaic () { const signed short int *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 }; double progress = 0.0; const bool plistenerActive = plistener; if (plistenerActive) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::vng4])); plistener->setProgress (progress); } const unsigned prefilters = ri->prefilters; const int width=W, height=H; const int colors=4; float (*image)[4]; image = (float (*)[4]) calloc (height*width, sizeof *image); #ifdef _OPENMP #pragma omp parallel for #endif for (int ii=0; iisetProgress (progress); } #ifdef _OPENMP #pragma omp parallel #endif { float gval[8], thold, sum[3]; int g; const int progressStep = 64; const double progressInc = (0.98-progress)/((height-2)/progressStep); #ifdef _OPENMP #pragma omp for nowait #endif for (int row=2; row < height-2; row++) { /* Do VNG interpolation */ for (int col=2; col < width-2; col++) { float * pix = image[row*width+col]; int * ip = code[row & prow][col & pcol]; memset (gval, 0, sizeof gval); while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */ float diff = fabsf(pix[g] - pix[ip[1]]) * (1<< ip[2]); gval[ip[3]] += diff; ip+=4; while ((g = *ip++) != -1) gval[g] += diff; } ip++; { float gmin, gmax; gmin = gmax = gval[0]; /* Choose a threshold */ for (g=1; g < 8; g++) { if (gmin > gval[g]) gmin = gval[g]; if (gmax < gval[g]) gmax = gval[g]; } thold = gmin + (gmax /2); } memset (sum, 0, sizeof sum); float t1,t2; int color = fc(row,col); t1 = t2 = pix[color]; if(color&1) { int num = 0; for (g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { if(ip[1]) sum[0] += (t1 + pix[ip[1]])*0.5f; sum[1] += pix[ip[0] + (color ^ 2)]; num++; } } t1 += (sum[1] - sum[0]) / num; } else { int num = 0; for (g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { sum[1] += pix[ip[0] + 1]; sum[2] += pix[ip[0] + 3]; if(ip[1]) sum[0] += (t1 + pix[ip[1]])*0.5f; num++; } } t1 += (sum[1] - sum[0]) / num; t2 += (sum[2] - sum[0]) / num; } green[row][col] = 0.5f * (t1 + t2); } if(plistenerActive) { if((row % progressStep) == 0) #ifdef _OPENMP #pragma omp critical (updateprogress) #endif { progress += progressInc; plistener->setProgress (progress); } } } } free (code[0][0]); free (image); if(plistenerActive) plistener->setProgress (0.98); // Interpolate R and B #ifdef _OPENMP #pragma omp parallel for #endif for (int i=0; isetProgress (1.0); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #undef fc #define fc(row,col) \ (ri->get_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) #define FORCC for (int c=0; c < colors; c++) /* 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]; if (plistener) { // looks like ppg isn't supported anymore //plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::ppg])); plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "xxx")); 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(static_cast(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(W,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]; } } void RawImageSource::border_interpolate2( int winw, int winh, int lborders) { int bord=lborders; int width=winw; int height=winh; for (int i=0; i -1) && (i1 < height) && (j1 > -1)) { int c = FC(i1,j1); sum[c] += rawData[i1][j1]; sum[c+3]++; } } int c=FC(i,j); if (c==1) { red[i][j]=sum[0]/sum[3]; green[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { green[i][j]=sum[1]/sum[4]; if (c==0) { red[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { red[i][j]=sum[0]/sum[3]; blue[i][j]=rawData[i][j]; } } }//j for (int j=width-bord; j -1) && (i1 < height ) && (j1 < width)) { int c = FC(i1,j1); sum[c] += rawData[i1][j1]; sum[c+3]++; } } int c=FC(i,j); if (c==1) { red[i][j]=sum[0]/sum[3]; green[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { green[i][j]=sum[1]/sum[4]; if (c==0) { red[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { red[i][j]=sum[0]/sum[3]; blue[i][j]=rawData[i][j]; } } }//j }//i for (int i=0; i -1) && (i1 < height) && (j1 > -1)) { int c = FC(i1,j1); sum[c] += rawData[i1][j1]; sum[c+3]++; } } int c=FC(i,j); if (c==1) { red[i][j]=sum[0]/sum[3]; green[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { green[i][j]=sum[1]/sum[4]; if (c==0) { red[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { red[i][j]=sum[0]/sum[3]; blue[i][j]=rawData[i][j]; } } }//j } for (int i=height-bord; i -1) && (i1 < height) && (j1 < width)) { int c = FC(i1,j1); sum[c] += rawData[i1][j1]; sum[c+3]++; } } int c=FC(i,j); if (c==1) { red[i][j]=sum[0]/sum[3]; green[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { green[i][j]=sum[1]/sum[4]; if (c==0) { red[i][j]=rawData[i][j]; blue[i][j]=sum[2]/sum[5]; } else { red[i][j]=sum[0]/sum[3]; blue[i][j]=rawData[i][j]; } } }//j } } // Joint Demosaicing and Denoising using High Order Interpolation Techniques // Revision 0.9.1a - 09/02/2010 - Contact info: luis.sanz.rodriguez@gmail.com // Copyright Luis Sanz Rodriguez 2010 // Adapted to RT by Jacques Desmis 3/2013 void RawImageSource::jdl_interpolate_omp() // from "Lassus" { int width=W, height=H; int row,col,c,d,i,u=width,v=2*u,w=3*u,x=4*u,y=5*u,z=6*u,indx,(*dif)[2],(*chr)[2]; float f[4],g[4]; float (*image)[4]; image = (float (*)[4]) calloc (width*height, sizeof *image); dif = (int (*)[2]) calloc(width*height, sizeof *dif); chr = (int (*)[2]) calloc(width*height, sizeof *chr); if (plistener) { // this function seems to be unused //plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::jdl])); plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "xxx")); plistener->setProgress (0.0); } #ifdef _OPENMP #pragma omp parallel default(none) shared(image,width,height,u,w,v,y,x,z,dif,chr) private(row,col,f,g,indx,c,d,i) #endif { #ifdef _OPENMP #pragma omp for #endif for (int ii=0; ii(0.725f*dif[indx][0]+0.1375f*dif[indx-v][0]+0.1375f*dif[indx+v][0],dif[indx-v][0],dif[indx+v][0]); g[1]=ULIM(0.725f*dif[indx][1]+0.1375f*dif[indx-2][1]+0.1375f*dif[indx+2][1],dif[indx-2][1],dif[indx+2][1]); chr[indx][c]=(f[1]*g[0]+f[0]*g[1])/(f[0]+f[1]); } #ifdef _OPENMP #pragma omp for #endif for (row=6; rowsetProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::lmmse])); plistener->setProgress (0.0); } float (*image)[3]; float maxdata=0.f; image = (float (*)[3]) calloc (width*height, sizeof *image); unsigned int a=0; #ifdef _OPENMP #pragma omp parallel for #endif for (int ii=0; iisetProgress (0.1); } #ifdef _OPENMP #pragma omp parallel firstprivate (image,rix,qix,h0,h1,h2,h3,h4) #endif { #ifdef _OPENMP #pragma omp for #endif for (int rrr=0; rrr < rr1; rrr++) for (int ccc=0, row=rrr-ba; ccc < cc1; ccc++) { int col = ccc - ba; rix = qix + rrr*cc1 + ccc; if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) { if (applyGamma) rix[0][4] = Color::gammatab_24_17a[image[row*width+col][FC(row,col)]]; else rix[0][4] = (float)image[row*width+col][FC(row,col)]/65535.0f; } else rix[0][4] = 0.f; } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.2); } // G-R(B) #ifdef _OPENMP #pragma omp for #endif for (int rr=2; rr < rr1-2; rr++) { // G-R(B) at R(B) location for (int cc=2+(FC(rr,2)&1); cc < cc1-2; cc+=2) { rix = qix + rr*cc1 + cc; float v0 = x00625(rix[-w1-1][4]+rix[-w1+1][4]+rix[w1-1][4]+rix[w1+1][4]) +x0250(rix[0][4]); // horizontal rix[0][0] = - x0250(rix[ -2][4] + rix[ 2][4])+ xdiv2f(rix[ -1][4] + rix[0][4] + rix[ 1][4]); float Y = v0 + xdiv2f(rix[0][0]); if (rix[0][4] > 1.75f*Y) rix[0][0] = ULIM(rix[0][0],rix[ -1][4],rix[ 1][4]); else rix[0][0] = LIM(rix[0][0],0.0f,1.0f); rix[0][0] -= rix[0][4]; // vertical rix[0][1] = -x0250(rix[-w2][4] + rix[w2][4])+ xdiv2f(rix[-w1][4] + rix[0][4] + rix[w1][4]); Y = v0 + xdiv2f(rix[0][1]); if (rix[0][4] > 1.75f*Y) rix[0][1] = ULIM(rix[0][1],rix[-w1][4],rix[w1][4]); else rix[0][1] = LIM(rix[0][1],0.0f,1.0f); rix[0][1] -= rix[0][4]; } // G-R(B) at G location for (int ccc=2+(FC(rr,3)&1); ccc < cc1-2; ccc+=2) { rix = qix + rr*cc1 + ccc; rix[0][0] = x0250(rix[ -2][4] + rix[ 2][4])- xdiv2f(rix[ -1][4] + rix[0][4] + rix[ 1][4]); rix[0][1] = x0250(rix[-w2][4] + rix[w2][4])- xdiv2f(rix[-w1][4] + rix[0][4] + rix[w1][4]); rix[0][0] = LIM(rix[0][0],-1.0f,0.0f) + rix[0][4]; rix[0][1] = LIM(rix[0][1],-1.0f,0.0f) + rix[0][4]; } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.25); } // apply low pass filter on differential colors #ifdef _OPENMP #pragma omp for #endif for (int rr=4; rr < rr1-4; rr++) for (int cc=4; cc < cc1-4; cc++) { rix = qix + rr*cc1 + cc; rix[0][2] = h0*rix[0][0] + h1*(rix[ -1][0] + rix[ 1][0]) + h2*(rix[ -2][0] + rix[ 2][0]) + h3*(rix[ -3][0] + rix[ 3][0]) + h4*(rix[ -4][0] + rix[ 4][0]); rix[0][3] = h0*rix[0][1] + h1*(rix[-w1][1] + rix[w1][1]) + h2*(rix[-w2][1] + rix[w2][1]) + h3*(rix[-w3][1] + rix[w3][1]) + h4*(rix[-w4][1] + rix[w4][1]); } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.3); } // interpolate G-R(B) at R(B) #ifdef _OPENMP #pragma omp for #endif for (int rr=4; rr < rr1-4; rr++) for (int cc=4+(FC(rr,4)&1); cc < cc1-4; cc+=2) { rix = qix + rr*cc1 + cc; // horizontal float mu = (rix[-4][2] + rix[-3][2] + rix[-2][2] + rix[-1][2] + rix[0][2]+ rix[ 1][2] + rix[ 2][2] + rix[ 3][2] + rix[ 4][2]) / 9.0f; float p1 = rix[-4][2] - mu; float p2 = rix[-3][2] - mu; float p3 = rix[-2][2] - mu; float p4 = rix[-1][2] - mu; float p5 = rix[ 0][2] - mu; float p6 = rix[ 1][2] - mu; float p7 = rix[ 2][2] - mu; float p8 = rix[ 3][2] - mu; float p9 = rix[ 4][2] - mu; float vx = 1e-7+p1*p1+p2*p2+p3*p3+p4*p4+p5*p5+p6*p6+p7*p7+p8*p8+p9*p9; p1 = rix[-4][0] - rix[-4][2]; p2 = rix[-3][0] - rix[-3][2]; p3 = rix[-2][0] - rix[-2][2]; p4 = rix[-1][0] - rix[-1][2]; p5 = rix[ 0][0] - rix[ 0][2]; p6 = rix[ 1][0] - rix[ 1][2]; p7 = rix[ 2][0] - rix[ 2][2]; p8 = rix[ 3][0] - rix[ 3][2]; p9 = rix[ 4][0] - rix[ 4][2]; float vn = 1e-7+p1*p1+p2*p2+p3*p3+p4*p4+p5*p5+p6*p6+p7*p7+p8*p8+p9*p9; float xh = (rix[0][0]*vx + rix[0][2]*vn)/(vx + vn); float vh = vx*vn/(vx + vn); // vertical mu = (rix[-w4][3] + rix[-w3][3] + rix[-w2][3] + rix[-w1][3] + rix[0][3]+rix[ w1][3] + rix[ w2][3] + rix[ w3][3] + rix[ w4][3]) / 9.0f; p1 = rix[-w4][3] - mu; p2 = rix[-w3][3] - mu; p3 = rix[-w2][3] - mu; p4 = rix[-w1][3] - mu; p5 = rix[ 0][3] - mu; p6 = rix[ w1][3] - mu; p7 = rix[ w2][3] - mu; p8 = rix[ w3][3] - mu; p9 = rix[ w4][3] - mu; vx = 1e-7+p1*p1+p2*p2+p3*p3+p4*p4+p5*p5+p6*p6+p7*p7+p8*p8+p9*p9; p1 = rix[-w4][1] - rix[-w4][3]; p2 = rix[-w3][1] - rix[-w3][3]; p3 = rix[-w2][1] - rix[-w2][3]; p4 = rix[-w1][1] - rix[-w1][3]; p5 = rix[ 0][1] - rix[ 0][3]; p6 = rix[ w1][1] - rix[ w1][3]; p7 = rix[ w2][1] - rix[ w2][3]; p8 = rix[ w3][1] - rix[ w3][3]; p9 = rix[ w4][1] - rix[ w4][3]; vn = 1e-7+p1*p1+p2*p2+p3*p3+p4*p4+p5*p5+p6*p6+p7*p7+p8*p8+p9*p9; float xv = (rix[0][1]*vx + rix[0][3]*vn)/(vx + vn); float vv = vx*vn/(vx + vn); // interpolated G-R(B) rix[0][4] = (xh*vv + xv*vh)/(vh + vv); } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.4); } // copy CFA values #ifdef _OPENMP #pragma omp for #endif for (int rr=0; rr < rr1; rr++) for (int cc=0, row=rr-ba; cc < cc1; cc++) { int col=cc-ba; rix = qix + rr*cc1 + cc; int c = FC(rr,cc); if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) { if (applyGamma) rix[0][c] = Color::gammatab_24_17a[image[row*width+col][c]]; else rix[0][c] = (float)image[row*width+col][c]/65535.0f; } else rix[0][c] = 0.f; if (c != 1) rix[0][1] = rix[0][c] + rix[0][4]; } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.5); } // bilinear interpolation for R/B // interpolate R/B at G location #ifdef _OPENMP #pragma omp for #endif for (int rr=1; rr < rr1-1; rr++) for (int cc=1+(FC(rr,2)&1), c=FC(rr,cc+1); cc < cc1-1; cc+=2) { rix = qix + rr*cc1 + cc; rix[0][c] = rix[0][1] + xdiv2f(rix[ -1][c] - rix[ -1][1] + rix[ 1][c] - rix[ 1][1]); c = 2 - c; rix[0][c] = rix[0][1]+ xdiv2f(rix[-w1][c] - rix[-w1][1] + rix[w1][c] - rix[w1][1]); c = 2 - c; } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.6); } // interpolate R/B at B/R location #ifdef _OPENMP #pragma omp for #endif for (int rr=1; rr < rr1-1; rr++) for (int cc=1+(FC(rr,1)&1), c=2-FC(rr,cc); cc < cc1-1; cc+=2) { rix = qix + rr*cc1 + cc; rix[0][c] = rix[0][1]+ x0250(rix[-w1][c] - rix[-w1][1] + rix[ -1][c] - rix[ -1][1]+ rix[ 1][c] - rix[ 1][1] + rix[ w1][c] - rix[ w1][1]); } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.7); } }// End of parallelization 1 // median filter/ for (int pass=0; pass < iter; pass++) { for (int c=0; c < 3; c+=2) { // Compute median(R-G) and median(B-G) int d = c + 3; for (int ii=0; ii < rr1*cc1; ii++) qix[ii][d] = qix[ii][c] - qix[ii][1]; // Apply 3x3 median filter #ifdef _OPENMP #pragma omp parallel for firstprivate (rix,qix) #endif for (int rr=1; rr < rr1-1; rr++) for (int cc=1; cc < cc1-1; cc++) { float temp; rix = qix + rr*cc1 + cc; // Assign 3x3 differential color values float p1 = rix[-w1-1][d]; float p2 = rix[-w1][d]; float p3 = rix[-w1+1][d]; float p4 = rix[ -1][d]; float p5 = rix[ 0][d]; float p6 = rix[ 1][d]; float p7 = rix[ w1-1][d]; float p8 = rix[ w1][d]; float p9 = rix[ w1+1][d]; // Sort for median of 9 values PIX_SORT(p2,p3); PIX_SORT(p5,p6); PIX_SORT(p8,p9); PIX_SORT(p1,p2); PIX_SORT(p4,p5); PIX_SORT(p7,p8); PIX_SORT(p2,p3); PIX_SORT(p5,p6); PIX_SORT(p8,p9); PIX_SORT(p1,p4); PIX_SORT(p6,p9); PIX_SORT(p5,p8); PIX_SORT(p4,p7); PIX_SORT(p2,p5); PIX_SORT(p3,p6); PIX_SORT(p5,p8); PIX_SORT(p5,p3); PIX_SORT(p7,p5); PIX_SORT(p5,p3); rix[0][4] = p5; } for (int ii=0; ii < rr1*cc1; ii++) qix[ii][d] = qix[ii][4]; } // red/blue at GREEN pixel locations for (int rr=0; rr < rr1; rr++) for (int cc=(FC(rr,1)&1) /*, c=FC(rr,cc+1)*/; cc < cc1; cc+=2) { rix = qix + rr*cc1 + cc; rix[0][0] = rix[0][1] + rix[0][3]; rix[0][2] = rix[0][1] + rix[0][5]; } // red/blue and green at BLUE/RED pixel locations for (int rr=0; rr < rr1; rr++) for (int cc=(FC(rr,0)&1), c=2-FC(rr,cc),d=c+3; cc < cc1; cc+=2) { rix = qix + rr*cc1 + cc; rix[0][c] = rix[0][1] + rix[0][d]; rix[0][1] = xdiv2f(rix[0][0] - rix[0][3] + rix[0][2] - rix[0][5]); } } if (plistener) plistener->setProgress (0.8); #ifdef _OPENMP #pragma omp parallel firstprivate (image,rix,qix) #endif { // copy result back to image matrix #ifdef _OPENMP #pragma omp for #endif for (int row=0; row < height; row++) for (int col=0, rr=row+ba; col < width; col++) { int cc = col+ba; rix = qix + rr*cc1 + cc; int c = FC(row,col); float v0; if (applyGamma) { for (int ii=0; ii < 3; ii++) if (ii != c) { v0 = 65535.f*rix[0][ii]; image[row*width+col][ii]=Color::igammatab_24_17[v0]; } } else for (int ii=0; ii < 3; ii++) if (ii != c) image[row*width+col][ii] = ((65535.0f*rix[0][ii] + 0.5f)); } #ifdef _OPENMP #pragma omp for #endif for (int ii=0; iisetProgress (1.0); free(buffer); free(image); //if(iterations > 4) refinement_lassus(passref); if(iterations > 4 && iterations <=6) refinement(passref); else if(iterations > 6) refinement_lassus(passref); } /*** * * Bayer CFA Demosaicing using Integrated Gaussian Vector on Color Differences * Revision 1.0 - 2013/02/28 * * Copyright (c) 2007-2013 Luis Sanz Rodriguez * Using High Order Interpolation technique by Jim S, Jimmy Li, and Sharmil Randhawa * * Contact info: luis.sanz.rodriguez@gmail.com * * This code is distributed under a GNU General Public License, version 3. * Visit for more information. * ***/ // Adapted to RT by Jacques Desmis 3/2013 // SSE version by Ingo Weyrich 5/2013 #ifdef __SSE2__ #define CLIPV(a) LIMV(a,zerov,c65535v) SSEFUNCTION void RawImageSource::igv_interpolate(int winw, int winh) { static const float eps=1e-5f, epssq=1e-5f;//mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero) static const int h1=1, h2=2, h3=3, h5=5; const int width=winw, height=winh; const int v1=1*width, v2=2*width, v3=3*width, v5=5*width; float* rgb[2]; float* chr[4]; float *rgbarray, *vdif, *hdif, *chrarray; rgbarray = (float (*)) malloc((width*height) * sizeof( float ) ); rgb[0] = rgbarray; rgb[1] = rgbarray + (width*height)/2; vdif = (float (*)) calloc( width*height/2, sizeof *vdif ); hdif = (float (*)) calloc( width*height/2, sizeof *hdif ); chrarray = (float (*)) calloc( width*height, sizeof( float ) ); chr[0] = chrarray; chr[1] = chrarray + (width*height)/2; // mapped chr[2] and chr[3] to hdif and hdif, because these are out of use, when chr[2] and chr[3] are used chr[2] = hdif; chr[3] = vdif; border_interpolate2(winw,winh,7); if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::igv])); plistener->setProgress (0.0); } #ifdef _OPENMP #pragma omp parallel default(none) shared(rgb,vdif,hdif,chr) #endif { __m128 ngv, egv, wgv, sgv, nvv, evv, wvv, svv, nwgv, negv, swgv, segv, nwvv, nevv, swvv, sevv,tempv,temp1v,temp2v,temp3v,temp4v,temp5v,temp6v,temp7v,temp8v; __m128 epsv = _mm_set1_ps( eps ); __m128 epssqv = _mm_set1_ps( epssq ); __m128 c65535v = _mm_set1_ps( 65535.f ); __m128 c23v = _mm_set1_ps( 23.f ); __m128 c40v = _mm_set1_ps( 40.f ); __m128 c51v = _mm_set1_ps( 51.f ); __m128 c32v = _mm_set1_ps( 32.f ); __m128 c8v = _mm_set1_ps( 8.f ); __m128 c7v = _mm_set1_ps( 7.f ); __m128 c6v = _mm_set1_ps( 6.f ); __m128 c10v = _mm_set1_ps( 10.f ); __m128 c21v = _mm_set1_ps( 21.f ); __m128 c78v = _mm_set1_ps( 78.f ); __m128 c69v = _mm_set1_ps( 69.f ); __m128 c3145680v = _mm_set1_ps( 3145680.f ); __m128 onev = _mm_set1_ps ( 1.f ); __m128 zerov = _mm_set1_ps ( 0.f ); __m128 d725v = _mm_set1_ps ( 0.725f ); __m128 d1375v = _mm_set1_ps ( 0.1375f ); float *dest1, *dest2; float ng, eg, wg, sg, nv, ev, wv, sv, nwg, neg, swg, seg, nwv, nev, swv, sev; #ifdef _OPENMP #pragma omp for #endif for (int row=0; row>1], tempv ); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3,1,3,1 ) ); _mm_storeu_ps( &dest2[indx>>1], tempv ); } for (; col>1] = CLIP(rawData[row][col]); //rawData = RT datas col++; dest2[indx>>1] = CLIP(rawData[row][col]); //rawData = RT datas } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.13); } #ifdef _OPENMP #pragma omp for #endif for (int row=5; row>1; col>1])-LVFU(rgb[1][(indx-v3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1-v1)])))/c65535v); egv=(epsv+(vabsf(LVFU(rgb[1][(indx+h1)>>1])-LVFU(rgb[1][(indx+h3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1+h1)])))/c65535v); wgv=(epsv+(vabsf(LVFU(rgb[1][(indx-h1)>>1])-LVFU(rgb[1][(indx-h3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1-h1)])))/c65535v); sgv=(epsv+(vabsf(LVFU(rgb[1][(indx+v1)>>1])-LVFU(rgb[1][(indx+v3)>>1]))+vabsf(LVFU(rgb[0][indx1])-LVFU(rgb[0][(indx1+v1)])))/c65535v); //N,E,W,S High Order Interpolation (Li & Randhawa) //N,E,W,S Hamilton Adams Interpolation // (48.f * 65535.f) = 3145680.f tempv = c40v*LVFU(rgb[0][indx1]); nvv=LIMV(((c23v*LVFU(rgb[1][(indx-v1)>>1])+c23v*LVFU(rgb[1][(indx-v3)>>1])+LVFU(rgb[1][(indx-v5)>>1])+LVFU(rgb[1][(indx+v1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1-v1)])-c8v*LVFU(rgb[0][(indx1-v2)])))/c3145680v, zerov, onev); evv=LIMV(((c23v*LVFU(rgb[1][(indx+h1)>>1])+c23v*LVFU(rgb[1][(indx+h3)>>1])+LVFU(rgb[1][(indx+h5)>>1])+LVFU(rgb[1][(indx-h1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1+h1)])-c8v*LVFU(rgb[0][(indx1+h2)])))/c3145680v, zerov, onev); wvv=LIMV(((c23v*LVFU(rgb[1][(indx-h1)>>1])+c23v*LVFU(rgb[1][(indx-h3)>>1])+LVFU(rgb[1][(indx-h5)>>1])+LVFU(rgb[1][(indx+h1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1-h1)])-c8v*LVFU(rgb[0][(indx1-h2)])))/c3145680v, zerov, onev); svv=LIMV(((c23v*LVFU(rgb[1][(indx+v1)>>1])+c23v*LVFU(rgb[1][(indx+v3)>>1])+LVFU(rgb[1][(indx+v5)>>1])+LVFU(rgb[1][(indx-v1)>>1])+tempv-c32v*LVFU(rgb[0][(indx1+v1)])-c8v*LVFU(rgb[0][(indx1+v2)])))/c3145680v, zerov, onev); //Horizontal and vertical color differences tempv = LVFU( rgb[0][indx1] ) / c65535v; _mm_storeu_ps( &vdif[indx1], (sgv*nvv+ngv*svv)/(ngv+sgv)- tempv ); _mm_storeu_ps( &hdif[indx1], (wgv*evv+egv*wvv)/(egv+wgv)- tempv ); } // borders without SSE for (; col>1]-rgb[1][(indx-v3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1-v1)]))/65535.f);; eg=(eps+(fabsf(rgb[1][(indx+h1)>>1]-rgb[1][(indx+h3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1+h1)]))/65535.f); wg=(eps+(fabsf(rgb[1][(indx-h1)>>1]-rgb[1][(indx-h3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1-h1)]))/65535.f); sg=(eps+(fabsf(rgb[1][(indx+v1)>>1]-rgb[1][(indx+v3)>>1])+fabsf(rgb[0][indx1]-rgb[0][(indx1+v1)]))/65535.f); //N,E,W,S High Order Interpolation (Li & Randhawa) //N,E,W,S Hamilton Adams Interpolation // (48.f * 65535.f) = 3145680.f nv=LIM(((23.0f*rgb[1][(indx-v1)>>1]+23.0f*rgb[1][(indx-v3)>>1]+rgb[1][(indx-v5)>>1]+rgb[1][(indx+v1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1-v1)]-8.0f*rgb[0][(indx1-v2)]))/3145680.f, 0.0f, 1.0f); ev=LIM(((23.0f*rgb[1][(indx+h1)>>1]+23.0f*rgb[1][(indx+h3)>>1]+rgb[1][(indx+h5)>>1]+rgb[1][(indx-h1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1+h1)]-8.0f*rgb[0][(indx1+h2)]))/3145680.f, 0.0f, 1.0f); wv=LIM(((23.0f*rgb[1][(indx-h1)>>1]+23.0f*rgb[1][(indx-h3)>>1]+rgb[1][(indx-h5)>>1]+rgb[1][(indx+h1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1-h1)]-8.0f*rgb[0][(indx1-h2)]))/3145680.f, 0.0f, 1.0f); sv=LIM(((23.0f*rgb[1][(indx+v1)>>1]+23.0f*rgb[1][(indx+v3)>>1]+rgb[1][(indx+v5)>>1]+rgb[1][(indx-v1)>>1]+40.0f*rgb[0][indx1]-32.0f*rgb[0][(indx1+v1)]-8.0f*rgb[0][(indx1+v2)]))/3145680.f, 0.0f, 1.0f); //Horizontal and vertical color differences vdif[indx1]=(sg*nv+ng*sv)/(ng+sg)-(rgb[0][indx1])/65535.f; hdif[indx1]=(wg*ev+eg*wv)/(eg+wg)-(rgb[0][indx1])/65535.f; } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.26); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; row>1, d=FC(row,col)/2; colsetProgress (0.39); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; row>1])-LVFU(chr[c][(indx-v3-h3)>>1]))+vabsf(LVFU(chr[c][(indx+v1+h1)>>1])-LVFU(chr[c][(indx-v3-h3)>>1]))); negv=onev/(epsv+vabsf(LVFU(chr[c][(indx-v1+h1)>>1])-LVFU(chr[c][(indx-v3+h3)>>1]))+vabsf(LVFU(chr[c][(indx+v1-h1)>>1])-LVFU(chr[c][(indx-v3+h3)>>1]))); swgv=onev/(epsv+vabsf(LVFU(chr[c][(indx+v1-h1)>>1])-LVFU(chr[c][(indx+v3+h3)>>1]))+vabsf(LVFU(chr[c][(indx-v1+h1)>>1])-LVFU(chr[c][(indx+v3-h3)>>1]))); segv=onev/(epsv+vabsf(LVFU(chr[c][(indx+v1+h1)>>1])-LVFU(chr[c][(indx+v3-h3)>>1]))+vabsf(LVFU(chr[c][(indx-v1-h1)>>1])-LVFU(chr[c][(indx+v3+h3)>>1]))); //Limit NW,NE,SW,SE Color differences nwvv=ULIMV(LVFU(chr[c][(indx-v1-h1)>>1]),LVFU(chr[c][(indx-v3-h1)>>1]),LVFU(chr[c][(indx-v1-h3)>>1])); nevv=ULIMV(LVFU(chr[c][(indx-v1+h1)>>1]),LVFU(chr[c][(indx-v3+h1)>>1]),LVFU(chr[c][(indx-v1+h3)>>1])); swvv=ULIMV(LVFU(chr[c][(indx+v1-h1)>>1]),LVFU(chr[c][(indx+v3-h1)>>1]),LVFU(chr[c][(indx+v1-h3)>>1])); sevv=ULIMV(LVFU(chr[c][(indx+v1+h1)>>1]),LVFU(chr[c][(indx+v3+h1)>>1]),LVFU(chr[c][(indx+v1+h3)>>1])); //Interpolate chrominance: R@B and B@R tempv = (nwgv*nwvv+negv*nevv+swgv*swvv+segv*sevv)/(nwgv+negv+swgv+segv); _mm_storeu_ps( &(chr[c][indx>>1]), tempv); } for (; col>1]-chr[c][(indx-v3-h3)>>1])+fabsf(chr[c][(indx+v1+h1)>>1]-chr[c][(indx-v3-h3)>>1])); neg=1.0f/(eps+fabsf(chr[c][(indx-v1+h1)>>1]-chr[c][(indx-v3+h3)>>1])+fabsf(chr[c][(indx+v1-h1)>>1]-chr[c][(indx-v3+h3)>>1])); swg=1.0f/(eps+fabsf(chr[c][(indx+v1-h1)>>1]-chr[c][(indx+v3+h3)>>1])+fabsf(chr[c][(indx-v1+h1)>>1]-chr[c][(indx+v3-h3)>>1])); seg=1.0f/(eps+fabsf(chr[c][(indx+v1+h1)>>1]-chr[c][(indx+v3-h3)>>1])+fabsf(chr[c][(indx-v1-h1)>>1]-chr[c][(indx+v3+h3)>>1])); //Limit NW,NE,SW,SE Color differences nwv=ULIM(chr[c][(indx-v1-h1)>>1],chr[c][(indx-v3-h1)>>1],chr[c][(indx-v1-h3)>>1]); nev=ULIM(chr[c][(indx-v1+h1)>>1],chr[c][(indx-v3+h1)>>1],chr[c][(indx-v1+h3)>>1]); swv=ULIM(chr[c][(indx+v1-h1)>>1],chr[c][(indx+v3-h1)>>1],chr[c][(indx+v1-h3)>>1]); sev=ULIM(chr[c][(indx+v1+h1)>>1],chr[c][(indx+v3+h1)>>1],chr[c][(indx+v1+h3)>>1]); //Interpolate chrominance: R@B and B@R chr[c][indx>>1]=(nwg*nwv+neg*nev+swg*swv+seg*sev)/(nwg+neg+swg+seg); } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.65); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; row>1])-LVFU(chr[0][(indx-v3)>>1]))+vabsf(LVFU(chr[0][(indx+v1)>>1])-LVFU(chr[0][(indx-v3)>>1]))); egv=onev/(epsv+vabsf(LVFU(chr[0][(indx+h1)>>1])-LVFU(chr[0][(indx+h3)>>1]))+vabsf(LVFU(chr[0][(indx-h1)>>1])-LVFU(chr[0][(indx+h3)>>1]))); wgv=onev/(epsv+vabsf(LVFU(chr[0][(indx-h1)>>1])-LVFU(chr[0][(indx-h3)>>1]))+vabsf(LVFU(chr[0][(indx+h1)>>1])-LVFU(chr[0][(indx-h3)>>1]))); sgv=onev/(epsv+vabsf(LVFU(chr[0][(indx+v1)>>1])-LVFU(chr[0][(indx+v3)>>1]))+vabsf(LVFU(chr[0][(indx-v1)>>1])-LVFU(chr[0][(indx+v3)>>1]))); //Interpolate chrominance: R@G and B@G tempv = ((ngv*LVFU(chr[0][(indx-v1)>>1])+egv*LVFU(chr[0][(indx+h1)>>1])+wgv*LVFU(chr[0][(indx-h1)>>1])+sgv*LVFU(chr[0][(indx+v1)>>1]))/(ngv+egv+wgv+sgv)); _mm_storeu_ps( &chr[0+2][indx>>1], tempv); } for (; col>1]-chr[0][(indx-v3)>>1])+fabsf(chr[0][(indx+v1)>>1]-chr[0][(indx-v3)>>1])); eg=1.0f/(eps+fabsf(chr[0][(indx+h1)>>1]-chr[0][(indx+h3)>>1])+fabsf(chr[0][(indx-h1)>>1]-chr[0][(indx+h3)>>1])); wg=1.0f/(eps+fabsf(chr[0][(indx-h1)>>1]-chr[0][(indx-h3)>>1])+fabsf(chr[0][(indx+h1)>>1]-chr[0][(indx-h3)>>1])); sg=1.0f/(eps+fabsf(chr[0][(indx+v1)>>1]-chr[0][(indx+v3)>>1])+fabsf(chr[0][(indx-v1)>>1]-chr[0][(indx+v3)>>1])); //Interpolate chrominance: R@G and B@G chr[0+2][indx>>1]=((ng*chr[0][(indx-v1)>>1]+eg*chr[0][(indx+h1)>>1]+wg*chr[0][(indx-h1)>>1]+sg*chr[0][(indx+v1)>>1])/(ng+eg+wg+sg)); } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.78); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; row>1])-LVFU(chr[1][(indx-v3)>>1]))+vabsf(LVFU(chr[1][(indx+v1)>>1])-LVFU(chr[1][(indx-v3)>>1]))); egv=onev/(epsv+vabsf(LVFU(chr[1][(indx+h1)>>1])-LVFU(chr[1][(indx+h3)>>1]))+vabsf(LVFU(chr[1][(indx-h1)>>1])-LVFU(chr[1][(indx+h3)>>1]))); wgv=onev/(epsv+vabsf(LVFU(chr[1][(indx-h1)>>1])-LVFU(chr[1][(indx-h3)>>1]))+vabsf(LVFU(chr[1][(indx+h1)>>1])-LVFU(chr[1][(indx-h3)>>1]))); sgv=onev/(epsv+vabsf(LVFU(chr[1][(indx+v1)>>1])-LVFU(chr[1][(indx+v3)>>1]))+vabsf(LVFU(chr[1][(indx-v1)>>1])-LVFU(chr[1][(indx+v3)>>1]))); //Interpolate chrominance: R@G and B@G tempv = ((ngv*LVFU(chr[1][(indx-v1)>>1])+egv*LVFU(chr[1][(indx+h1)>>1])+wgv*LVFU(chr[1][(indx-h1)>>1])+sgv*LVFU(chr[1][(indx+v1)>>1]))/(ngv+egv+wgv+sgv)); _mm_storeu_ps( &chr[1+2][indx>>1], tempv); } for (; col>1]-chr[1][(indx-v3)>>1])+fabsf(chr[1][(indx+v1)>>1]-chr[1][(indx-v3)>>1])); eg=1.0f/(eps+fabsf(chr[1][(indx+h1)>>1]-chr[1][(indx+h3)>>1])+fabsf(chr[1][(indx-h1)>>1]-chr[1][(indx+h3)>>1])); wg=1.0f/(eps+fabsf(chr[1][(indx-h1)>>1]-chr[1][(indx-h3)>>1])+fabsf(chr[1][(indx+h1)>>1]-chr[1][(indx-h3)>>1])); sg=1.0f/(eps+fabsf(chr[1][(indx+v1)>>1]-chr[1][(indx+v3)>>1])+fabsf(chr[1][(indx-v1)>>1]-chr[1][(indx+v3)>>1])); //Interpolate chrominance: R@G and B@G chr[1+2][indx>>1]=((ng*chr[1][(indx-v1)>>1]+eg*chr[1][(indx+h1)>>1]+wg*chr[1][(indx-h1)>>1]+sg*chr[1][(indx+v1)>>1])/(ng+eg+wg+sg)); } } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.91); } float *src1, *src2, *redsrc0, *redsrc1, *bluesrc0, *bluesrc1; #ifdef _OPENMP #pragma omp for #endif for(int row=7; row>1] ); temp2v = LVFU( src2[(indx+1)>>1] ); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 1,0,1,0 ) ); tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3,1,2,0 ) ); _mm_storeu_ps( &green[row][col], CLIPV( tempv )); temp5v = LVFU(redsrc0[indx>>1]); temp6v = LVFU(redsrc1[(indx+1)>>1]); temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 1,0,1,0 ) ); temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3,1,2,0 ) ); temp3v = CLIPV( tempv - c65535v * temp3v ); _mm_storeu_ps( &red[row][col], temp3v); temp7v = LVFU(bluesrc0[indx>>1]); temp8v = LVFU(bluesrc1[(indx+1)>>1]); temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 1,0,1,0 ) ); temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3,1,2,0 ) ); temp4v = CLIPV( tempv - c65535v * temp4v ); _mm_storeu_ps( &blue[row][col], temp4v); tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3,2,3,2 ) ); tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3,1,2,0 ) ); _mm_storeu_ps( &green[row][col+4], CLIPV( tempv )); temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 3,2,3,2 ) ); temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3,1,2,0 ) ); temp3v = CLIPV( tempv - c65535v * temp3v ); _mm_storeu_ps( &red[row][col+4], temp3v); temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 3,2,3,2 ) ); temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3,1,2,0 ) ); temp4v = CLIPV( tempv - c65535v * temp4v ); _mm_storeu_ps( &blue[row][col+4], temp4v); } for(; col>1]-65535.f*redsrc0[indx>>1]); green[row][col] = CLIP(src1[indx>>1]); blue [row][col] = CLIP(src1[indx>>1]-65535.f*bluesrc0[indx>>1]); col++; red [row][col] = CLIP(src2[(indx+1)>>1]-65535.f*redsrc1[(indx+1)>>1]); green[row][col] = CLIP(src2[(indx+1)>>1]); blue [row][col] = CLIP(src2[(indx+1)>>1]-65535.f*bluesrc1[(indx+1)>>1]); } } }// End of parallelization if (plistener) plistener->setProgress (1.0); free(chrarray); free(rgbarray); free(vdif); free(hdif); } #undef CLIPV #else void RawImageSource::igv_interpolate(int winw, int winh) { static const float eps=1e-5f, epssq=1e-5f;//mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero) static const int h1=1, h2=2, h3=3, h4=4, h5=5, h6=6; const int width=winw, height=winh; const int v1=1*width, v2=2*width, v3=3*width, v4=4*width, v5=5*width, v6=6*width; float* rgb[3]; float* chr[2]; float (*rgbarray), *vdif, *hdif, (*chrarray); rgbarray = (float (*)) calloc(width*height*3, sizeof( float)); rgb[0] = rgbarray; rgb[1] = rgbarray + (width*height); rgb[2] = rgbarray + 2*(width*height); chrarray = (float (*)) calloc(width*height*2, sizeof( float)); chr[0] = chrarray; chr[1] = chrarray + (width*height); vdif = (float (*)) calloc(width*height/2, sizeof *vdif); hdif = (float (*)) calloc(width*height/2, sizeof *hdif); border_interpolate2(winw,winh,7); if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::igv])); plistener->setProgress (0.0); } #ifdef _OPENMP #pragma omp parallel default(none) shared(rgb,vdif,hdif,chr) #endif { float ng, eg, wg, sg, nv, ev, wv, sv, nwg, neg, swg, seg, nwv, nev, swv, sev; #ifdef _OPENMP #pragma omp for #endif for (int row=0; rowsetProgress (0.13); } #ifdef _OPENMP #pragma omp for #endif for (int row=5; row>1]=(sg*nv+ng*sv)/(ng+sg)-(rgb[c][indx])/65535.f; hdif[indx>>1]=(wg*ev+eg*wv)/(eg+wg)-(rgb[c][indx])/65535.f; } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.26); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; row>1])+69.0f*(SQR(vdif[(indx-v2)>>1])+SQR(vdif[(indx+v2)>>1]))+51.0f*(SQR(vdif[(indx-v4)>>1])+SQR(vdif[(indx+v4)>>1]))+21.0f*(SQR(vdif[(indx-v6)>>1])+SQR(vdif[(indx+v6)>>1]))-6.0f*SQR(vdif[(indx-v2)>>1]+vdif[indx>>1]+vdif[(indx+v2)>>1]) -10.0f*(SQR(vdif[(indx-v4)>>1]+vdif[(indx-v2)>>1]+vdif[indx>>1])+SQR(vdif[indx>>1]+vdif[(indx+v2)>>1]+vdif[(indx+v4)>>1]))-7.0f*(SQR(vdif[(indx-v6)>>1]+vdif[(indx-v4)>>1]+vdif[(indx-v2)>>1])+SQR(vdif[(indx+v2)>>1]+vdif[(indx+v4)>>1]+vdif[(indx+v6)>>1])),0.f,1.f); eg=LIM(epssq+78.0f*SQR(hdif[indx>>1])+69.0f*(SQR(hdif[(indx-h2)>>1])+SQR(hdif[(indx+h2)>>1]))+51.0f*(SQR(hdif[(indx-h4)>>1])+SQR(hdif[(indx+h4)>>1]))+21.0f*(SQR(hdif[(indx-h6)>>1])+SQR(hdif[(indx+h6)>>1]))-6.0f*SQR(hdif[(indx-h2)>>1]+hdif[indx>>1]+hdif[(indx+h2)>>1]) -10.0f*(SQR(hdif[(indx-h4)>>1]+hdif[(indx-h2)>>1]+hdif[indx>>1])+SQR(hdif[indx>>1]+hdif[(indx+h2)>>1]+hdif[(indx+h4)>>1]))-7.0f*(SQR(hdif[(indx-h6)>>1]+hdif[(indx-h4)>>1]+hdif[(indx-h2)>>1])+SQR(hdif[(indx+h2)>>1]+hdif[(indx+h4)>>1]+hdif[(indx+h6)>>1])),0.f,1.f); //Limit chrominance using H/V neighbourhood nv=ULIM(0.725f*vdif[indx>>1]+0.1375f*vdif[(indx-v2)>>1]+0.1375f*vdif[(indx+v2)>>1],vdif[(indx-v2)>>1],vdif[(indx+v2)>>1]); ev=ULIM(0.725f*hdif[indx>>1]+0.1375f*hdif[(indx-h2)>>1]+0.1375f*hdif[(indx+h2)>>1],hdif[(indx-h2)>>1],hdif[(indx+h2)>>1]); //Chrominance estimation chr[d][indx]=(eg*nv+ng*ev)/(ng+eg); //Green channel population rgb[1][indx]=rgb[c][indx]+65535.f*chr[d][indx]; } #ifdef _OPENMP #pragma omp single #endif { if (plistener) plistener->setProgress (0.39); } // free(vdif); free(hdif); #ifdef _OPENMP #pragma omp for #endif for (int row=7; rowsetProgress (0.52); } #ifdef _OPENMP #pragma omp for #endif for (int row=8; rowsetProgress (0.65); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; rowsetProgress (0.78); } #ifdef _OPENMP #pragma omp for #endif for (int row=7; rowsetProgress (0.91); //Interpolate borders // border_interpolate2(7, rgb); } /* #ifdef _OPENMP #pragma omp for #endif for (int row=0; row < height; row++) //borders for (int col=0; col < width; col++) { if (col==7 && row >= 7 && row < height-7) col = width-7; int indxc=row*width+col; red [row][col] = rgb[indxc][0]; green[row][col] = rgb[indxc][1]; blue [row][col] = rgb[indxc][2]; } */ #ifdef _OPENMP #pragma omp for #endif for(int row=7; rowsetProgress (1.0); free(chrarray); free(rgbarray); free(vdif); free(hdif); } #endif /* 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) 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 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; double r; 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 }; if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::ahd])); plistener->setProgress (0.0); } image = (float (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; ii 0.008856 ? pow(r,0.333333333) : 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] * imatrices.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(static_cast(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(static_cast(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]) ); 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; isetProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE")); plistener->setProgress ((float)b/PassCount); } /* Reinforce interpolated green pixels on RED/BLUE pixel locations */ #ifdef _OPENMP #pragma omp for #endif for (int row=2; row < height-2; row++) for (int col=2+(FC(row,2) & 1), c=FC(row,col); col < width-2; col+=2) { int indx = row*width+col; float (*pix)[3]= image + indx; double dL = 1.0/(1.0+fabs(pix[ -2][c]-pix[0][c])+fabs(pix[ 1][1]-pix[ -1][1])); double dR = 1.0/(1.0+fabs(pix[ 2][c]-pix[0][c])+fabs(pix[ 1][1]-pix[ -1][1])); double dU = 1.0/(1.0+fabs(pix[-w2][c]-pix[0][c])+fabs(pix[w1][1]-pix[-w1][1])); double dD = 1.0/(1.0+fabs(pix[ w2][c]-pix[0][c])+fabs(pix[w1][1]-pix[-w1][1])); float v0 = (float)((double)pix[0][c] + 0.5 +((double)(pix[ -1][1]-pix[ -1][c])*dL +(double)(pix[ 1][1]-pix[ 1][c])*dR +(double)(pix[-w1][1]-pix[-w1][c])*dU + (double)(pix[ w1][1]-pix[ w1][c])*dD ) / (dL+dR+dU+dD)); pix[0][1] = CLIP(v0); } /* Reinforce interpolated red/blue pixels on GREEN pixel locations */ #ifdef _OPENMP #pragma omp for #endif for (int row=2; row < height-2; row++) for (int col=2+(FC(row,3) & 1), c=FC(row,col+1); col < width-2; col+=2) { int indx = row*width+col; float (*pix)[3] = image + indx; for (int i=0; i < 2; c=2-c, i++) { double dL = 1.0/(1.0+fabs(pix[ -2][1]-pix[0][1])+fabs(pix[ 1][c]-pix[ -1][c])); double dR = 1.0/(1.0+fabs(pix[ 2][1]-pix[0][1])+fabs(pix[ 1][c]-pix[ -1][c])); double dU = 1.0/(1.0+fabs(pix[-w2][1]-pix[0][1])+fabs(pix[w1][c]-pix[-w1][c])); double dD = 1.0/(1.0+fabs(pix[ w2][1]-pix[0][1])+fabs(pix[w1][c]-pix[-w1][c])); float v0 = (float)((double)pix[0][1] + 0.5 -((double)(pix[ -1][1]-pix[ -1][c])*dL + (double)(pix[ 1][1]-pix[ 1][c])*dR +(double)(pix[-w1][1]-pix[-w1][c])*dU + (double)(pix[ w1][1]-pix[ w1][c])*dD ) / (dL+dR+dU+dD)); pix[0][c] = CLIP(v0); } } /* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */ #ifdef _OPENMP #pragma omp for #endif for (int row=2; row < height-2; row++) for (int col=2+(FC(row,2) & 1), c=2-FC(row,col); col < width-2; col+=2) { int indx = row*width+col; float (*pix)[3] = image + indx; int d = 2 - c; double dL = 1.0/(1.0+ABS(pix[ -2][d]-pix[0][d])+ABS(pix[ 1][1]-pix[ -1][1])); double dR = 1.0/(1.0+ABS(pix[ 2][d]-pix[0][d])+ABS(pix[ 1][1]-pix[ -1][1])); double dU = 1.0/(1.0+ABS(pix[-w2][d]-pix[0][d])+ABS(pix[w1][1]-pix[-w1][1])); double dD = 1.0/(1.0+ABS(pix[ w2][d]-pix[0][d])+ABS(pix[w1][1]-pix[-w1][1])); float v0 = (float)((double)pix[0][1] + 0.5 -((double)(pix[ -1][1]-pix[ -1][c])*dL +(double)(pix[ 1][1]-pix[ 1][c])*dR +(double)(pix[-w1][1]-pix[-w1][c])*dU + (double)(pix[ w1][1]-pix[ w1][c])*dD ) / (dL+dR+dU+dD)); pix[0][c] = CLIP(v0); } } #ifdef _OPENMP #pragma omp for #endif for (int i=0;iverbose) printf("Refinement Lee %d usec\n", t2e.etime(t1e)); } // Refinement based on EECI demozaicing algorithm by L. Chang and Y.P. Tan // from "Lassus" : Luis Sanz Rodriguez, adapted by Jacques Desmis - JDC - and Oliver Duis for RawTherapee // increases the signal to noise ratio (PSNR) # +1 to +2 dB : tested with Dcraw : eg: Lighthouse + AMaZE : whitout refinement:39.96dB, with refinement:41.86 dB // reduce color artifacts, improves the interpolation // but it's relatively slow // // Should be DISABLED if it decreases image quality by increases some image noise and generates blocky edges void RawImageSource::refinement_lassus(int PassCount) { // const int PassCount=1; // if (settings->verbose) printf("Refinement\n"); MyTime t1e,t2e; t1e.set(); int u=W, v=2*u, w=3*u, x=4*u, y=5*u; float (*image)[3]; image = (float(*)[3]) calloc(W*H, sizeof *image); #ifdef _OPENMP #pragma omp parallel shared(image) #endif { // convert red, blue, green to image #ifdef _OPENMP #pragma omp for #endif for (int i=0;isetProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE")); plistener->setProgress ((float)b/PassCount); } // Reinforce interpolated green pixels on RED/BLUE pixel locations #ifdef _OPENMP #pragma omp for #endif for (int row=6; rowverbose) printf("Refinement Lassus %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; col < colMax; col+=2, indx+=2) { assert(indx-u>=0 && indx+u=0 && indx+u+1=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+u=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], image[indx-v][c], image[indx-2][c], image[indx+2][c]) - min(image[indx+v][c], image[indx-v][c], image[indx-2][c], image[indx+2][c]) + max(image[indx+1+u][d], image[indx+1-u][d], image[indx-1+u][d], image[indx-1-u][d]) - min(image[indx+1+u][d], image[indx+1-u][d], image[indx-1+u][d], image[indx-1-u][d]); float currentH = max(bufferH[indx+v][d], bufferH[indx-v][d], bufferH[indx-2][d], bufferH[indx+2][d]) - min(bufferH[indx+v][d], bufferH[indx-v][d], bufferH[indx-2][d], bufferH[indx+2][d]) + max(bufferH[indx+1+u][c], bufferH[indx+1-u][c], bufferH[indx-1+u][c], bufferH[indx-1-u][c]) - min(bufferH[indx+1+u][c], bufferH[indx+1-u][c], bufferH[indx-1+u][c], bufferH[indx-1-u][c]); float currentV = max(bufferV[indx+v][d], bufferV[indx-v][d], bufferV[indx-2][d], bufferV[indx+2][d]) - min(bufferV[indx+v][d], bufferV[indx-v][d], bufferV[indx-2][d], bufferV[indx+2][d]) + max(bufferV[indx+1+u][c], bufferV[indx+1-u][c], bufferV[indx-1+u][c], bufferV[indx-1-u][c]) - min(bufferV[indx+1+u][c], bufferV[indx+1-u][c], 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-v>=0 && indx+v=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; 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 (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::methodstring[RAWParams::dcb])); 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); } } #ifdef _OPENMP #pragma omp atomic #endif tilesDone++; } #ifdef _OPENMP for(int i=0; isetProgress (1.0); } #undef TILEBORDER #undef TILESIZE #undef CACHESIZE } /* namespace */