From dea0a8f9810a5c4ba275faec69806a952110293f Mon Sep 17 00:00:00 2001 From: ffsup2 Date: Thu, 19 Aug 2010 00:37:53 +0200 Subject: [PATCH] Added dark frame subtraction Moved debayer and preprocessing parameters to class ProcParams for every single image. Added tab RAW for changing those parameters. Progress bar shows only load step (work to do) --- rtengine/CA_correct_RT.cc | 97 ++-- rtengine/CMakeLists.txt | 2 +- rtengine/amaze_interpolate_RT.cc | 29 +- rtengine/cfa_linedn_RT.cc | 4 +- rtengine/common.h | 85 +++- rtengine/dcraw.cc | 237 +++++----- rtengine/dcrop.cc | 2 +- rtengine/dfmanager.cc | 353 +++++++++++++++ rtengine/dfmanager.h | 89 ++++ rtengine/green_equil_RT.cc | 4 +- rtengine/imagesource.h | 4 +- rtengine/improccoordinator.cc | 10 +- rtengine/init.cc | 2 + rtengine/procevents.h | 9 +- rtengine/procparams.cc | 49 +- rtengine/procparams.h | 23 + rtengine/rawimagesource.cc | 737 ++++++++++++++++++++----------- rtengine/rawimagesource.h | 29 +- rtengine/rawimagesource_i.h | 120 ++--- rtengine/refreshmap.cc | 7 +- rtengine/refreshmap.h | 5 + rtengine/rtengine.h | 3 +- rtengine/settings.h | 9 +- rtengine/simpleprocess.cc | 6 +- rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/CMakeLists.txt | 2 +- rtgui/filebrowser.cc | 38 +- rtgui/filebrowser.h | 3 + rtgui/options.cc | 34 +- rtgui/paramsedited.cc | 25 ++ rtgui/paramsedited.h | 16 + rtgui/preferences.cc | 185 ++------ rtgui/preferences.h | 22 +- rtgui/preprocess.cc | 220 +++++++++ rtgui/preprocess.h | 63 +++ rtgui/rawprocess.cc | 181 ++++++++ rtgui/rawprocess.h | 55 +++ rtgui/toolpanelcoord.cc | 9 + rtgui/toolpanelcoord.h | 6 +- 40 files changed, 2014 insertions(+), 764 deletions(-) create mode 100644 rtengine/dfmanager.cc create mode 100644 rtengine/dfmanager.h create mode 100644 rtgui/preprocess.cc create mode 100644 rtgui/preprocess.h create mode 100644 rtgui/rawprocess.cc create mode 100644 rtgui/rawprocess.h diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 2e78254f9..6349f999e 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -21,9 +21,6 @@ // along with this program. If not, see . // //////////////////////////////////////////////////////////////// - - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int RawImageSource::LinEqSolve(int nDim, float* pfMatr, float* pfVect, float* pfSolution) { @@ -106,8 +103,6 @@ void RawImageSource::CA_correct_RT() { #define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } #define SQR(x) ((x)*(x)) - //static const float pre_mul[3] = {MIN(ri->red_multiplier,ri->green_multiplier), ri->green_multiplier, \ - MIN(ri->blue_multiplier,ri->green_multiplier)}; static const float clip_pt = ri->defgain; @@ -117,8 +112,8 @@ void RawImageSource::CA_correct_RT() { float (*Gtmp); Gtmp = (float (*)) calloc ((height)*(width), sizeof *Gtmp); - static const int border=8; - static const int border2=16; + const int border=8; + const int border2=16; //order of 2d polynomial fit (polyord), and numpar=polyord^2 int polyord=4, numpar=16; //number of blocks used in the fit @@ -140,7 +135,7 @@ void RawImageSource::CA_correct_RT() { //flag indicating success or failure of polynomial fit int res; //shifts to location of vertical and diagonal neighbors - static const int v1=TS, v2=2*TS, v3=3*TS, v4=4*TS;//, p1=-TS+1, p2=-2*TS+2, p3=-3*TS+3, m1=TS+1, m2=2*TS+2, m3=3*TS+3; + const int v1=TS, v2=2*TS, /* v3=3*TS,*/ v4=4*TS;//, p1=-TS+1, p2=-2*TS+2, p3=-3*TS+3, m1=TS+1, m2=2*TS+2, m3=3*TS+3; float eps=1e-5; //tolerance to avoid dividing by zero @@ -151,13 +146,13 @@ void RawImageSource::CA_correct_RT() { //measured CA shift parameters for a tile float CAshift[2][3]; //polynomial fit coefficients - float polymat[3][2][1296], shiftmat[3][2][36], fitparams[3][2][36]; + float polymat[3][2][256], shiftmat[3][2][16], fitparams[3][2][16]; //residual CA shift amount within a plaquette float shifthfrac[3], shiftvfrac[3]; //temporary storage for median filter float temp, p[9]; //temporary parameters for tile CA evaluation - float gdiff, deltgrb, denom; + float gdiff, deltgrb; //interpolated G at edge of plaquette float Ginthfloor, Ginthceil, Gint, RBint, gradwt; //interpolated color difference at edge of plaquette @@ -165,20 +160,15 @@ void RawImageSource::CA_correct_RT() { //data for evaluation of block CA shift variance float blockave[2][3]={{0,0,0},{0,0,0}}, blocksqave[2][3]={{0,0,0},{0,0,0}}, blockdenom[2][3]={{0,0,0},{0,0,0}}, blockvar[2][3]; //low and high pass 1D filters of G in vertical/horizontal directions - float glpfh, glpfv, ghpfh, ghpfv; + float glpfh, glpfv; //max allowed CA shift - static const float bslim = 3.99; + const float bslim = 3.99; //gaussians for low pass filtering of G and R/B - static const float gaussg[5] = {0.171582, 0.15839, 0.124594, 0.083518, 0.0477063};//sig=2.5 - static const float gaussrb[3] = {0.332406, 0.241376, 0.0924212};//sig=1.25 + //static const float gaussg[5] = {0.171582, 0.15839, 0.124594, 0.083518, 0.0477063};//sig=2.5 + //static const float gaussrb[3] = {0.332406, 0.241376, 0.0924212};//sig=1.25 //block CA shift values and weight assigned to block - //char *buffer1; // vblsz*hblsz*3*2 - //float (*blockshifts)[3][2]; // vblsz*hblsz*3*2 - float blockshifts[10000][3][2]; //fixed memory allocation - float blockwt[10000]; //fixed memory allocation - char *buffer; // TS*TS*16 //rgb data in a tile @@ -225,11 +215,19 @@ void RawImageSource::CA_correct_RT() { vblsz=ceil((float)(height+border2)/(TS-border2)+2+vz1); hblsz=ceil((float)(width+border2)/(TS-border2)+2+hz1); - /*buffer1 = (char *) malloc(vblsz*hblsz*3*2*sizeof(float)); - merror(buffer1,"CA_correct()"); - memset(buffer1,0,vblsz*hblsz*3*2*sizeof(float)); - // block CA shifts - blockshifts = (float (*)[3][2]) buffer1;*/ + //block CA shift values and weight assigned to block + char *buffer1; // vblsz*hblsz*(3*2+1) + float (*blockwt); // vblsz*hblsz + float (*blockshifts)[3][2]; // vblsz*hblsz*3*2 + //float blockshifts[1000][3][2]; //fixed memory allocation + //float blockwt[1000]; //fixed memory allocation + + buffer1 = (char *) malloc(vblsz*hblsz*(3*2+1)*sizeof(float)); + //merror(buffer1,"CA_correct()"); + memset(buffer1,0,vblsz*hblsz*(3*2+1)*sizeof(float)); + // block CA shifts + blockwt = (float (*)) (buffer1); + blockshifts = (float (*)[3][2]) (buffer1+(vblsz*hblsz*sizeof(float))); @@ -257,7 +255,7 @@ void RawImageSource::CA_correct_RT() { c = FC(rr,cc); indx=row*width+col; indx1=rr*TS+cc; - rgb[indx1][c] = (ri->data[row][col])/65535.0f; + rgb[indx1][c] = (rawData[row][col])/65535.0f; //rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation } @@ -274,7 +272,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][left+cc])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][left+cc])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+left+cc][c])/65535.0f;//for dcraw implementation } } @@ -289,7 +287,7 @@ void RawImageSource::CA_correct_RT() { for (rr=rrmin; rrdata[(top+rr)][(width-cc-2)])/65535.0f; + rgb[rr*TS+ccmax+cc][c] = (rawData[(top+rr)][(width-cc-2)])/65535.0f; //rgb[rr*TS+ccmax+cc][c] = (image[(top+rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation } } @@ -299,7 +297,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[border2-rr][border2-cc])/65535.0f; + rgb[(rr)*TS+cc][c] = (rawData[border2-rr][border2-cc])/65535.0f; //rgb[(rr)*TS+cc][c] = (rgb[(border2-rr)*TS+(border2-cc)][c]);//for dcraw implementation } } @@ -307,7 +305,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][(width-cc-2)])/65535.0f; + rgb[(rrmax+rr)*TS+ccmax+cc][c] = (rawData[(height-rr-2)][(width-cc-2)])/65535.0f; //rgb[(rrmax+rr)*TS+ccmax+cc][c] = (image[(height-rr-2)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation } } @@ -315,7 +313,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(border2-rr)][(width-cc-2)])/65535.0f; + rgb[(rr)*TS+ccmax+cc][c] = (rawData[(border2-rr)][(width-cc-2)])/65535.0f; //rgb[(rr)*TS+ccmax+cc][c] = (image[(border2-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation } } @@ -323,7 +321,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][(border2-cc)])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][(border2-cc)])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(border2-cc)][c])/65535.0f;//for dcraw implementation } } @@ -370,14 +368,6 @@ void RawImageSource::CA_correct_RT() { fabs((rgb[indx-4][1]-rgb[indx-4][c])-(rgb[indx][1]-rgb[indx][c])) - \ fabs((rgb[indx-4][1]-rgb[indx-4][c])-(rgb[indx+4][1]-rgb[indx+4][c]))); - /*ghpfv = fabs(fabs(rgb[indx][1]-rgb[indx+v4][1])+fabs(rgb[indx][1]-rgb[indx-v4][1]) - \ - fabs(rgb[indx+v4][1]-rgb[indx-v4][1])); - ghpfh = fabs(fabs(rgb[indx][1]-rgb[indx+4][1])+fabs(rgb[indx][1]-rgb[indx-4][1]) - \ - fabs(rgb[indx+4][1]-rgb[indx-4][1])); - rbhpfv[indx] = fabs(ghpfv - fabs(fabs(rgb[indx][c]-rgb[indx+v4][c])+fabs(rgb[indx][c]-rgb[indx-v4][c]) - \ - fabs(rgb[indx+v4][c]-rgb[indx-v4][c]))); - rbhpfh[indx] = fabs(ghpfh - fabs(fabs(rgb[indx][c]-rgb[indx+4][c])+fabs(rgb[indx][c]-rgb[indx-4][c]) - \ - fabs(rgb[indx+4][c]-rgb[indx-4][c])));*/ glpfv = 0.25*(2*rgb[indx][1]+rgb[indx+v2][1]+rgb[indx-v2][1]); glpfh = 0.25*(2*rgb[indx][1]+rgb[indx+2][1]+rgb[indx-2][1]); @@ -485,6 +475,7 @@ void RawImageSource::CA_correct_RT() { if (blockdenom[j][c]) { blockvar[j][c] = blocksqave[j][c]/blockdenom[j][c]-SQR(blockave[j][c]/blockdenom[j][c]); } else { + fprintf (stderr,"blockdenom vanishes"); return; } } @@ -515,8 +506,8 @@ void RawImageSource::CA_correct_RT() { //end of filling border pixels of blockshift array //initialize fit arrays - for (i=0; i<1296; i++) {polymat[0][0][i] = polymat[0][1][i] = polymat[2][0][i] = polymat[2][1][i] = 0;} - for (i=0; i<36; i++) {shiftmat[0][0][i] = shiftmat[0][1][i] = shiftmat[2][0][i] = shiftmat[2][1][i] = 0;} + for (i=0; i<256; i++) {polymat[0][0][i] = polymat[0][1][i] = polymat[2][0][i] = polymat[2][1][i] = 0;} + for (i=0; i<16; i++) {shiftmat[0][0][i] = shiftmat[0][1][i] = shiftmat[2][0][i] = shiftmat[2][1][i] = 0;} for (vblock=1; vblockdata[row][col])/65535.0f; + rgb[indx1][c] = (rawData[row][col])/65535.0f; //rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation if ((c&1)==0) rgb[indx1][1] = Gtmp[indx]; @@ -628,7 +623,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][left+cc])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][left+cc])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+left+cc][c])/65535.0f;//for dcraw implementation rgb[(rrmax+rr)*TS+cc][1] = Gtmp[(height-rr-2)*width+left+cc]; @@ -646,7 +641,7 @@ void RawImageSource::CA_correct_RT() { for (rr=rrmin; rrdata[(top+rr)][(width-cc-2)])/65535.0f; + rgb[rr*TS+ccmax+cc][c] = (rawData[(top+rr)][(width-cc-2)])/65535.0f; //rgb[rr*TS+ccmax+cc][c] = (image[(top+rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation rgb[rr*TS+ccmax+cc][1] = Gtmp[(top+rr)*width+(width-cc-2)]; @@ -658,7 +653,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[border2-rr][border2-cc])/65535.0f; + rgb[(rr)*TS+cc][c] = (rawData[border2-rr][border2-cc])/65535.0f; //rgb[(rr)*TS+cc][c] = (rgb[(border2-rr)*TS+(border2-cc)][c]);//for dcraw implementation rgb[(rr)*TS+cc][1] = Gtmp[(border2-rr)*width+border2-cc]; @@ -668,7 +663,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][(width-cc-2)])/65535.0f; + rgb[(rrmax+rr)*TS+ccmax+cc][c] = (rawData[(height-rr-2)][(width-cc-2)])/65535.0f; //rgb[(rrmax+rr)*TS+ccmax+cc][c] = (image[(height-rr-2)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation rgb[(rrmax+rr)*TS+ccmax+cc][1] = Gtmp[(height-rr-2)*width+(width-cc-2)]; @@ -678,7 +673,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(border2-rr)][(width-cc-2)])/65535.0f; + rgb[(rr)*TS+ccmax+cc][c] = (rawData[(border2-rr)][(width-cc-2)])/65535.0f; //rgb[(rr)*TS+ccmax+cc][c] = (image[(border2-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation rgb[(rr)*TS+ccmax+cc][1] = Gtmp[(border2-rr)*width+(width-cc-2)]; @@ -688,7 +683,7 @@ void RawImageSource::CA_correct_RT() { for (rr=0; rrdata[(height-rr-2)][(border2-cc)])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][(border2-cc)])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(border2-cc)][c])/65535.0f;//for dcraw implementation rgb[(rrmax+rr)*TS+cc][1] = Gtmp[(height-rr-2)*width+(border2-cc)]; @@ -791,7 +786,7 @@ void RawImageSource::CA_correct_RT() { indx = row*width + col; c = FC(row,col); - ri->data[row][col] = CLIP((int)(65535.0f*rgb[(rr)*TS+cc][c] + 0.5f)); + rawData[row][col] = CLIP((int)(65535.0f*rgb[(rr)*TS+cc][c] + 0.5f)); //image[indx][c] = CLIP((int)(65535.0*rgb[(rr)*TS+cc][c] + 0.5));//for dcraw implementation } @@ -803,7 +798,7 @@ void RawImageSource::CA_correct_RT() { // clean up free(buffer); free(Gtmp); - //free(buffer1); + free(buffer1); diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index d5cae4e78..6442a3091 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -7,7 +7,7 @@ link_directories (${CMAKE_CURRENT_SOURCE_DIR}/../rtexif ${EXTRA_LIBDIR} ${GTHREA ${GOBJECT_LIBRARY_DIRS} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} ${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS}) -set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc +set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc dfmanager.cc image8.cc image16.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc loadinitial.cc procparams.cc rawimagesource.cc shmap.cc simpleprocess.cc refreshmap.cc stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc diff --git a/rtengine/amaze_interpolate_RT.cc b/rtengine/amaze_interpolate_RT.cc index a223ddea5..ed59989ea 100644 --- a/rtengine/amaze_interpolate_RT.cc +++ b/rtengine/amaze_interpolate_RT.cc @@ -35,20 +35,7 @@ void RawImageSource::amaze_demosaic_RT() { #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) //#define CLIP(x) LIM(x,0,65535) - //allocate outpute arrays int width=W, height=H; - red = new unsigned short*[H]; - for (int i=0; idefgain; @@ -239,7 +226,7 @@ void RawImageSource::amaze_demosaic_RT() { } // Main algorithm: Tile loop - //#pragma omp parallel for shared(ri->data,height,width,red,green,blue) private(top,left) schedule(dynamic) + //#pragma omp parallel for shared(rawData,height,width,red,green,blue) private(top,left) schedule(dynamic) //code is openmp ready; just have to pull local tile variable declarations inside the tile loop #pragma omp for schedule(dynamic) nowait for (top=-16; top < height; top += TS-32) @@ -340,7 +327,7 @@ void RawImageSource::amaze_demosaic_RT() { c = FC(rr,cc); indx=row*width+col; indx1=rr*TS+cc; - rgb[indx1][c] = (ri->data[row][col])/65535.0f; + rgb[indx1][c] = (rawData[row][col])/65535.0f; //rgb[indx1][c] = image[indx][c]/65535.0f;//for dcraw implementation cfa[indx1] = rgb[indx1][c]; @@ -359,7 +346,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=0; rr<16; rr++) for (cc=ccmin; ccdata[(height-rr-2)][left+cc])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][left+cc])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+left+cc][c])/65535.0f;//for dcraw implementation cfa[(rrmax+rr)*TS+cc] = rgb[(rrmax+rr)*TS+cc][c]; } @@ -376,7 +363,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=rrmin; rrdata[(top+rr)][(width-cc-2)])/65535.0f; + rgb[rr*TS+ccmax+cc][c] = (rawData[(top+rr)][(width-cc-2)])/65535.0f; //rgb[rr*TS+ccmax+cc][c] = (image[(top+rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation cfa[rr*TS+ccmax+cc] = rgb[rr*TS+ccmax+cc][c]; } @@ -387,7 +374,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=0; rr<16; rr++) for (cc=0; cc<16; cc++) { c=FC(rr,cc); - rgb[(rr)*TS+cc][c] = (ri->data[32-rr][32-cc])/65535.0f; + rgb[(rr)*TS+cc][c] = (rawData[32-rr][32-cc])/65535.0f; //rgb[(rr)*TS+cc][c] = (rgb[(32-rr)*TS+(32-cc)][c]);//for dcraw implementation cfa[(rr)*TS+cc] = rgb[(rr)*TS+cc][c]; } @@ -396,7 +383,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=0; rr<16; rr++) for (cc=0; cc<16; cc++) { c=FC(rr,cc); - rgb[(rrmax+rr)*TS+ccmax+cc][c] = (ri->data[(height-rr-2)][(width-cc-2)])/65535.0f; + rgb[(rrmax+rr)*TS+ccmax+cc][c] = (rawData[(height-rr-2)][(width-cc-2)])/65535.0f; //rgb[(rrmax+rr)*TS+ccmax+cc][c] = (image[(height-rr-2)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation cfa[(rrmax+rr)*TS+ccmax+cc] = rgb[(rrmax+rr)*TS+ccmax+cc][c]; } @@ -405,7 +392,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=0; rr<16; rr++) for (cc=0; cc<16; cc++) { c=FC(rr,cc); - rgb[(rr)*TS+ccmax+cc][c] = (ri->data[(32-rr)][(width-cc-2)])/65535.0f; + rgb[(rr)*TS+ccmax+cc][c] = (rawData[(32-rr)][(width-cc-2)])/65535.0f; //rgb[(rr)*TS+ccmax+cc][c] = (image[(32-rr)*width+(width-cc-2)][c])/65535.0f;//for dcraw implementation cfa[(rr)*TS+ccmax+cc] = rgb[(rr)*TS+ccmax+cc][c]; } @@ -414,7 +401,7 @@ void RawImageSource::amaze_demosaic_RT() { for (rr=0; rr<16; rr++) for (cc=0; cc<16; cc++) { c=FC(rr,cc); - rgb[(rrmax+rr)*TS+cc][c] = (ri->data[(height-rr-2)][(32-cc)])/65535.0f; + rgb[(rrmax+rr)*TS+cc][c] = (rawData[(height-rr-2)][(32-cc)])/65535.0f; //rgb[(rrmax+rr)*TS+cc][c] = (image[(height-rr-2)*width+(32-cc)][c])/65535.0f;//for dcraw implementation cfa[(rrmax+rr)*TS+cc] = rgb[(rrmax+rr)*TS+cc][c]; } diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 0c38f01a3..2050c0f77 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -101,7 +101,7 @@ void RawImageSource::CLASS cfa_linedn(float noise) // load CFA data; data should be in linear gamma space, before white balance multipliers are applied for (rr=top; rr < top+numrows; rr++) for (cc=left, indx=(rr-top)*TS; cc < left+numcols; cc++, indx++) { - cfain[indx] = ri->data[rr][cc]; + cfain[indx] = rawData[rr][cc]; } //pad the block to a multiple of 16 on both sides @@ -189,7 +189,7 @@ void RawImageSource::CLASS cfa_linedn(float noise) for (rr=16; rr < numrows-16; rr++) { row = rr + top; for (col=16+left, indx=rr*TS+16; indx < rr*TS+numcols-16; indx++, col++) { - ri->data[row][col] = CLIP((int)(cfadn[indx]+ 0.5)); + rawData[row][col] = CLIP((int)(cfadn[indx]+ 0.5)); } } if(plistener) plistener->setProgress(fabs((float)top/height)); diff --git a/rtengine/common.h b/rtengine/common.h index 61b5d4720..760a2144f 100644 --- a/rtengine/common.h +++ b/rtengine/common.h @@ -36,32 +36,49 @@ #define CMAXVAL 65535 #include +#include + +namespace rtengine { + +struct badPix +{ + int x; + int y; + badPix( int xc, int yc ):x(xc),y(yc){} +}; struct RawImage { - int width; - int height; + Glib::ustring fname; // complete filename + int width; // with of the image as reported by dcraw + int height; // height of the image as reported by dcraw - unsigned filters; + unsigned filters; // sequence of Bayer filter colors: 2bit for each of 2x8 pixels grid indicate 0=Red,1=Green1,2=Blue,(3=green2) + int colors; // Number of colors of bayer filter (3 or 4) - double red_multiplier; - double green_multiplier; - double blue_multiplier; - - double camwb_red; - double camwb_green; - double camwb_blue; - - int blackpoint; - int rgb_max; - int rotate_deg; + int black_point; // Black offset taken from dslr info by dcraw + int cblack[4]; // Black for each color. + unsigned short white[8][8]; // square of white registered by camera + float cam_mul[4]; // Camera color multiplier taken from exif by dcraw + float pre_mul[4]; + int maximum; // White (maximum) point taken from dslr info + int rotate_deg; // 0,90,180,270 degree of rotation: info taken by dcraw from exif int fuji_width; double defgain; - + double iso_speed; + double shutter; + double aperture; + double focal_len; + time_t timestamp; char *make, *model; int exifbase, prefilters, ciff_base, ciff_len; + int thumbLength; + int thumbOffset; + int thumbType; + int thumbWidth; + int thumbHeight; unsigned short* allocation; unsigned short** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column @@ -70,7 +87,43 @@ struct RawImage { float icoeff[3][3]; int profile_len; - char* profile_data; + char* profile_data; // Embedded ICC color profile + + RawImage( const Glib::ustring name):allocation(NULL),data(NULL),profile_data(NULL),fname(name) + { + } + ~RawImage() + { + if(allocation){ delete [] allocation; allocation=NULL;} + if(data){ delete [] data; data=NULL;} + if(profile_data){ delete [] profile_data; profile_data=NULL;} + } + + int loadRaw (bool loadData=true); + + void allocData() + { + if (filters) { + if (!allocation) { + allocation = new unsigned short[height * width]; + data = new unsigned short*[height]; + for (int i = 0; i < height; i++) + data[i] = allocation + i * width; + } + }else{ + if (!allocation) { + allocation = new unsigned short[3 * height * width]; + data = new unsigned short*[height]; + for (int i = 0; i < height; i++) + data[i] = allocation + 3 * i * width; + } + } + if(profile_len) + profile_data = new char[profile_len]; + } + }; +} + #endif diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 9a934c85f..defb860cb 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -3777,16 +3777,18 @@ void CLASS pre_interpolate() } } if (filters && colors == 3) { - if ((mix_green = four_color_rgb)) colors++; - else { - for (row = FC(1,0) >> 1; row < height; row+=2) - for (col = FC(row,1) & 1; col < width; col+=2) - image[row*width+col][1] = image[row*width+col][3]; -/*RT*/ pre_filters = filters; - filters &= ~((filters & 0x55555555) << 1); - } - } - if (half_size) filters = 0; + if ((mix_green = four_color_rgb)) + colors++; + else { + for (row = FC(1,0) >> 1; row < height; row += 2) + for (col = FC(row,1) & 1; col < width; col += 2) + image[row * width + col][1] = image[row * width + col][3]; + /*RT*/ pre_filters = filters; + filters &= ~((filters & 0x55555555) << 1); + } + } + if (half_size) + filters = 0; } void CLASS border_interpolate (int border) @@ -8915,7 +8917,6 @@ cleanup: #include #include -#include #include #include #include @@ -8926,150 +8927,148 @@ extern Settings* settings; Glib::Mutex* dcrMutex=NULL; -int loadRaw (const char* fname, struct RawImage *ri) { +int RawImage::loadRaw (bool loadData) { - static const double xyzd50_srgb[3][3] = - { { 0.436083, 0.385083, 0.143055 }, - { 0.222507, 0.716888, 0.060608 }, - { 0.013930, 0.097097, 0.714022 } }; + Glib::Mutex::Lock lock(*dcrMutex); // auto unlock -dcrMutex->lock (); - - ifname = fname;//strdup (fname); + ifname = fname.c_str(); image = NULL; - exif_base = -1; ciff_base = -1; ciff_len = -1; verbose = settings->verbose; oprof = NULL; - ri->data = NULL; - ri->allocation = NULL; - ri->profile_data = NULL; - ifp = gfopen (fname); - if (!ifp) { - dcrMutex->unlock (); - return 3; - } + ifp = gfopen (fname.c_str()); + if (!ifp) + return 3; + + thumb_length = 0; + thumb_offset = 0; + thumb_load_raw = 0; use_camera_wb = 0; highlight = 1; half_size = 0; + //***************** Read ALL raw file info identify (); - use_camera_wb = 1; if (!is_raw) { fclose(ifp); - dcrMutex->unlock (); return 2; } + this->filters = ::filters; + this->height = ::height; + this->width = ::width; + this->colors = ::colors; + this->profile_len = ::profile_length; - shrink = 0; + int i = ::cblack[3]; + for (int c=0; c <3; c++) + if (i > ::cblack[c]) + i = ::cblack[c]; + for (int c=0; c < 4; c++) + ::cblack[c] -= i; + ::black += i; + for (int c=0; c < 4; c++) this->cblack[c] = ::cblack[c]; + for (int c=0; c < 4; c++) this->cam_mul[c] = ::cam_mul[c]; + for (int c=0; c < 4; c++) this->pre_mul[c] = ::pre_mul[c]; + for (int a = 0; a < 3; a++) + for (int b = 0; b < 3; b++) + this->coeff[a][b] = ::rgb_cam[a][b]; - if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname); - iheight = height; - iwidth = width; + this->black_point = ::black; + this->maximum = ::maximum; + this->fuji_width = ::fuji_width; - image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1); - meta_data = (char *) (image + height*width); - - if (setjmp (failure)) { - if (image) - free (image); - if (ri->data) - free(ri->data); - fclose (ifp); - dcrMutex->unlock (); - return 100; - } - - fseek (ifp, data_offset, SEEK_SET); - (*load_raw)(); - - ri->profile_len = 0; - ri->profile_data = NULL; - if (profile_length) { - ri->profile_len = profile_length; - ri->profile_data = (char *) malloc (profile_length); - fseek (ifp, profile_offset, SEEK_SET); - fread (ri->profile_data, 1, profile_length, ifp); - } - - fclose(ifp); - if (zero_is_bad) remove_zeroes(); - - ri->red_multiplier = pre_mul[0]; - ri->green_multiplier = pre_mul[1]; - ri->blue_multiplier = pre_mul[2]; - - scale_colors(); - pre_interpolate (); - - ri->width = width; - ri->height = height; - ri->filters = filters; - - if (filters) { - ri->allocation = (short unsigned int*)calloc(height*width, sizeof(unsigned short)); - ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); - for (int i=0; idata[i] = ri->allocation + i*width; - for (int row = 0; row < height; row++) - for (int col = 0; col < width; col++) - if (ISGREEN(ri,row,col)) - ri->data[row][col] = image[row*width+col][1]; - else if (ISRED(ri,row,col)) - ri->data[row][col] = image[row*width+col][0]; - else - ri->data[row][col] = image[row*width+col][2]; - } - else { - ri->allocation = (short unsigned int*)calloc(3*height*width, sizeof(unsigned short)); - ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); - for (int i=0; idata[i] = ri->allocation + 3*i*width; - for (int row = 0; row < height; row++) - for (int col = 0; col < width; col++) { - ri->data[row][3*col+0] = image[row*width+col][0]; - ri->data[row][3*col+1] = image[row*width+col][1]; - ri->data[row][3*col+2] = image[row*width+col][2]; - } - } + for(int i=0; i<8;i++) + for(int j=0;j<8;j++) + this->white[i][j] = ::white[i][j]; if (flip==5) - ri->rotate_deg = 270; + this->rotate_deg = 270; else if (flip==3) - ri->rotate_deg = 180; + this->rotate_deg = 180; else if (flip==6) - ri->rotate_deg = 90; + this->rotate_deg = 90; else - ri->rotate_deg = 0; + this->rotate_deg = 0; - ri->make = strdup (make); - ri->model = strdup (model); + this->make = strdup (::make); + this->model = strdup (::model); + this->iso_speed = ::iso_speed; + this->shutter = ::shutter; + this->aperture = ::aperture; + this->focal_len = ::focal_len; + this->timestamp = ::timestamp; + this->exifbase = ::exif_base; + this->ciff_base = ::ciff_base; + this->ciff_len = ::ciff_len; + this->thumbOffset = ::thumb_offset; + this->thumbLength = ::thumb_length; + this->thumbHeight = ::thumb_height; + this->thumbWidth = ::thumb_width; + if (!thumb_load_raw && thumb_offset && write_thumb == jpeg_thumb) + this->thumbType = 1; + else if (!thumb_load_raw && thumb_offset && write_thumb == ppm_thumb) + this->thumbType = 2; + else { + this->thumbType = 0; + this->thumbWidth = ::width; + this->thumbHeight = ::height; + } - ri->exifbase = exif_base; - ri->prefilters = pre_filters; - ri->ciff_base = ciff_base; - ri->ciff_len = ciff_len; + if( loadData ){ + allocData(); + use_camera_wb = 1; + shrink = 0; + if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname.c_str()); + iheight = height; + iwidth = width; - ri->camwb_red = ri->red_multiplier / pre_mul[0]; - ri->camwb_green = ri->green_multiplier / pre_mul[1]; - ri->camwb_blue = ri->blue_multiplier / pre_mul[2]; + // dcraw needs this global variable to hold pixel data + image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1); + meta_data = (char *) (image + height*width); + if(!image) + return 200; - ri->defgain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); + if (setjmp (failure)) { + if (image) + free (image); + fclose (ifp); + return 100; + } - ri->fuji_width = fuji_width; + // Load raw pixels data + fseek (ifp, data_offset, SEEK_SET); + (*load_raw)(); - for (int a=0; a < 3; a++) - for (int b=0; b < 3; b++) - ri->coeff[a][b] = rgb_cam[a][b]; + // Load embedded profile + if (profile_length) { + fseek (ifp, profile_offset, SEEK_SET); + fread ( this->profile_data, 1, this->profile_len, ifp); + } + fclose(ifp); - free (image); -dcrMutex->unlock (); + // copy pixel raw data: the compressed format earns space + if (this->filters) { + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) + this->data[row][col] = image[row * width + col][FC(row,col)]; + } else { + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) { + this->data[row][3 * col + 0] = image[row * width + col][0]; + this->data[row][3 * col + 1] = image[row * width + col][1]; + this->data[row][3 * col + 2] = image[row * width + col][2]; + } + } + free(image); // we don't need this anymore + } return 0; } + + int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) { int status=0; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 4a54fdcee..3a1c2fdf5 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -108,7 +108,7 @@ void Crop::update (int todo, bool internal) { if (!needsinitupdate) setCropSizes (rqcropx, rqcropy, rqcropw, rqcroph, skip, true); PreviewProps pp (trafx, trafy, trafw*skip, trafh*skip, skip); - parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.hlrecovery, params.icm); + parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.hlrecovery, params.icm, params.raw ); if (fabs(params.resize.scale-1.0)<1e-7) { if (resizeCrop) { diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc new file mode 100644 index 000000000..86f08704b --- /dev/null +++ b/rtengine/dfmanager.cc @@ -0,0 +1,353 @@ +/* + * 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 + +namespace rtengine{ + +extern Settings* settings; + +// *********************** class dfInfo ************************************** + +inline dfInfo& dfInfo::operator =(const dfInfo &o){ + pathname = o.pathname; + maker = o.maker; + model = o.model; + iso = o.iso; + shutter = o.shutter; + timestamp = o.timestamp; + if( ri ){ + delete ri; + ri = NULL; + } + return *this; +} + +bool dfInfo::operator <(const dfInfo &e2) const +{ + if( this->maker.compare( e2.maker) >=0 ) + return false; + if( this->model.compare( e2.model) >=0 ) + return false; + if( this->iso >= e2.iso ) + return false; + if( this->shutter >= e2.shutter ) + return false; + if( this->timestamp >= e2.timestamp ) + return false; + return true; +} + +std::string dfInfo::key(const std::string &mak, const std::string &mod, int iso, double shut ) +{ + std::ostringstream s; + s << mak << " " << mod << " "; + s.width(5); + s << iso << "ISO "; + s.precision( 2 ); + s.width(4); + s << shut << "s"; + return s.str(); +} + +double dfInfo::distance(const std::string &mak, const std::string &mod, int iso, double shutter) const +{ + if( this->maker.compare( mak) != 0 ) + return INFINITY; + if( this->model.compare( mod) != 0 ) + return INFINITY; + double dISO= (log(this->iso/100.) - log(iso/100.))/log(2); + double dShutter = (log(this->shutter) - log(shutter))/log(2); + return sqrt( dISO*dISO + dShutter*dShutter); +} + +RawImage* dfInfo::getRawImage() +{ + if(ri) + return ri; + updateRawImage(); + updateBadPixelList( ri ); + + return ri; +} + +std::list& dfInfo::getBadPixels() +{ + if( !ri ){ + updateRawImage(); + updateBadPixelList( ri ); + } + return badPixels; +} +/* updateRawImage() load into ri the actual pixel data from pathname if there is a single shot + * otherwise load each file from the pathNames list and extract a template from the media; + * the first file is used also for reading all information other than pixels + */ +void dfInfo::updateRawImage() +{ + typedef unsigned int acc_t; + if( pathNames.size() >0 ){ + std::list::iterator iName = pathNames.begin(); + ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + }else{ + + acc_t **acc = new acc_t*[ri->height]; + for( int row=0; rowheight;row++) + acc[row] = new acc_t[ri->width*(ri->filters?1:3)]; + + // copy first image into accumulators + for (int row = 0; row < ri->height; row++) + for (int col = 0; col < ri->width * (ri->filters ? 1 : 3); col++) + acc[row][col] = ri->data[row][col]; + int nFiles = 1; // First file data already loaded + + for( iName++; iName != pathNames.end(); iName++){ + RawImage* temp = new RawImage(*iName); + if( !temp->loadRaw(true)){ + nFiles++; + if( ri->filters ){ + for( int row=0; rowheight;row++){ + for( int col=0; col < ri->width;col++) + acc[row][col] += temp->data[row][col]; + } + }else{ + for( int row=0; rowheight;row++){ + for( int col=0; col < ri->width;col++){ + acc[row][3*col+0] += temp->data[row][3*col+0]; + acc[row][3*col+1] += temp->data[row][3*col+1]; + acc[row][3*col+2] += temp->data[row][3*col+2]; + } + } + } + } + delete temp; + } + for (int row = 0; row < ri->height; row++){ + for (int col = 0; col < ri->width * (ri->filters ? 1 : 3); col++) + ri->data[row][col] = acc[row][col] / nFiles; + delete [] acc[row]; + } + delete [] acc; + } + }else{ + ri = new RawImage(pathname); + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + } + } +} + +void dfInfo::updateBadPixelList( RawImage *df ) +{ + const int threshold=10; + if( df->filters ){ + for( int row=2; rowheight-2; row++) + for( int col=2; col < df->width-2; col++){ + int m = (df->data[row-2][col-2] + df->data[row-2][col] + df->data[row-2][col+2]+ + df->data[row][col-2] + df->data[row][col+2]+ + df->data[row+2][col-2] + df->data[row+2][col] + df->data[row+2][col+2])/8; + if( df->data[row][col]/threshold > m ) + badPixels.push_back( badPix(col,row) ); + } + }else{ + for( int row=1; rowheight-1; row++) + for( int col=1; col < df->width-1; col++){ + int m[3]; + for( int c=0; c<3;c++){ + m[c] = (df->data[row-1][3*(col-1)+c] + df->data[row-1][3*col+c] + df->data[row-1][3*(col+1)+c]+ + df->data[row] [3*(col-1)+c] + df->data[row] [3*col+c]+ + df->data[row+1][3*(col-1)+c] + df->data[row+1][3*col+c] + df->data[row+1][3*(col+1)+c])/8; + } + if( df->data[row][3*col]/threshold > m[0] || df->data[row][3*col+1]/threshold > m[1] || df->data[row][3*col+2]/threshold > m[2]) + badPixels.push_back( badPix(col,row) ); + } + } + if( settings->verbose ){ + for (std::list::iterator iter = badPixels.begin(); iter !=badPixels.end(); iter ++) + printf( "(%d,%d) ",iter->x, iter->y); + printf( "Tot: %d\n", badPixels.size() ); + } +} + + +// ************************* class DFManager ********************************* + +void DFManager::init( Glib::ustring pathname ) +{ + std::vector names; + Glib::RefPtr dir = Gio::File::create_for_path (pathname); + if( dir && !dir->query_exists()) + return; + safe_build_file_list (dir, names, pathname); + + dfList.clear(); + for (int i=0; isecond; + if( i.pathNames.size()>0 && !i.pathname.empty() ){ + i.pathNames.push_back( i.pathname ); + i.pathname.clear(); + } + if( !i.pathname.empty() ) + printf( "%s: %s\n",i.key().c_str(),i.pathname.c_str()); + else{ + printf( "%s: MEAN of \n ",i.key().c_str()); + for( std::list::iterator iter = i.pathNames.begin(); iter != i.pathNames.end();iter++ ) + printf( "%s, ", iter->c_str() ); + printf("\n"); + } + } + currentPath = pathname; + return; +} + +bool DFManager::addFileInfo(const Glib::ustring &filename ) +{ + Glib::RefPtr file = Gio::File::create_for_path(filename); + if (!file ) + return false; + if( !file->query_exists()) + return false; + Glib::RefPtr info = safe_query_file_info(file); + if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { + int lastdot = info->get_name().find_last_of ('.'); + if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ + RawImage ri(filename); + int res = ri.loadRaw(false); // Read informations about shot + if( !res ){ + /* Files are added in the map, divided by same maker/model,ISO and shutter*/ + std::string key( dfInfo::key(ri.make, ri.model,(int)ri.iso_speed,ri.shutter) ); + dfList_t::iterator iter = dfList.find( key ); + if( iter == dfList.end() ){ + dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp); + dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + }else{ + while( iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - ri.timestamp) >60*60*6 ) // 6 hour difference + iter++; + + if( iter != dfList.end() ) + iter->second.pathNames.push_back( filename ); + else{ + dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp); + dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + } + } + return true; + } + } + } + return false; +} + +void DFManager::getStat( int &totFiles, int &totTemplates) +{ + totFiles=0; + totTemplates=0; + for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + dfInfo &i = iter->second; + if( i.pathname.empty() ){ + totTemplates++; + totFiles += i.pathNames.size(); + }else + totFiles++; + } +} + +/* The search for the best match is twofold: + * if perfect matches for iso and shutter are found, then the list is scanned for lesser distance in time + * otherwise if no match is found, the whole list is searched for lesser distance in iso and shutter + */ +dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) +{ + if( dfList.size() == 0 ) + throw std::exception(); + std::string key( dfInfo::key(mak,mod,isospeed,shut) ); + dfList_t::iterator iter = dfList.find( key ); + + if( iter != dfList.end() ){ + dfList_t::iterator bestMatch = iter; + time_t bestDeltaTime = ABS(iter->second.timestamp - t); + for(iter++; iter != dfList.end() && !key.compare( iter->second.key() ); iter++ ){ + time_t d = ABS(iter->second.timestamp - t ); + if( d< bestDeltaTime ){ + bestMatch = iter; + bestDeltaTime = d; + } + } + return bestMatch->second; + }else{ + iter = dfList.begin(); + dfList_t::iterator bestMatch = iter; + double bestD = iter->second.distance( mak, mod, isospeed, shut ); + for( iter++; iter != dfList.end();iter++ ){ + double d = iter->second.distance( mak, mod, isospeed, shut ); + if( d < bestD ){ + bestD = d; + bestMatch = iter; + } + } + return bestMatch->second; + } +} + +RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +{ + try{ + dfInfo &df = find( mak, mod, iso, shut, t ); + return df.getRawImage(); + }catch( std::exception e){ + return NULL; + } +} + +RawImage* DFManager::searchDarkFrame( Glib::ustring filename ) +{ + for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + if( iter->second.pathname.compare( filename )==0 ) + return iter->second.getRawImage(); + } +} + +std::list DFManager::searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +{ + try{ + dfInfo &df = find( mak, mod, iso, shut, t ); + return df.getBadPixels(); + }catch( std::exception e){ + return std::list(); + } +} + +// Global variable +DFManager dfm; + + +} diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h new file mode 100644 index 000000000..f15070b06 --- /dev/null +++ b/rtengine/dfmanager.h @@ -0,0 +1,89 @@ +/* + * 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 + +namespace rtengine{ + +class dfInfo +{ +public: + + Glib::ustring pathname; // filename of dark frame + std::list pathNames; // other similar dark frames, used to mediate + std::string maker; ///< manufacturer + std::string model; ///< model + int iso; ///< ISO (gain) + double shutter; ///< shutter or exposure time in sec + time_t timestamp; ///< seconds since 1 Jan 1970 + + + dfInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod,int iso,double shut,time_t t) + :pathname(name),maker(mak),model(mod),iso(iso),shutter(shut),timestamp(t),ri(NULL){} + + dfInfo( const dfInfo &o) + :pathname(o.pathname),maker(o.maker),model(o.model),iso(o.iso),shutter(o.shutter),timestamp(o.timestamp),ri(NULL){} + ~dfInfo() { if( ri ) delete ri; } + + + dfInfo &operator =(const dfInfo &o); + bool operator <(const dfInfo &e2) const; + + // Calculate virtual distance between two shots; different model return infinite + double distance(const std::string &mak, const std::string &mod, int iso, double shutter) const; + + static std::string key(const std::string &mak, const std::string &mod, int iso, double shut ); + std::string key(){ return key( maker,model,iso,shutter); } + + RawImage *getRawImage(); + std::list &getBadPixels(); + +protected: + RawImage *ri; ///< Dark Frame raw data + std::list badPixels; ///< Unreliable pixels + + void updateBadPixelList( RawImage *df ); + void updateRawImage(); +}; + +class DFManager +{ +public: + void init( Glib::ustring pathname ); + Glib::ustring getPathname(){ return currentPath; }; + void getStat( int &totFiles, int &totTemplate); + RawImage *searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + RawImage *searchDarkFrame( Glib::ustring filename ); + std::list searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + +protected: + typedef std::multimap dfList_t; + dfList_t dfList; + bool initialized; + Glib::ustring currentPath; + bool addFileInfo(const Glib::ustring &filename ); + dfInfo &find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); +}; + +extern DFManager dfm; + +} diff --git a/rtengine/green_equil_RT.cc b/rtengine/green_equil_RT.cc index b64999db6..e7f5a00e2 100644 --- a/rtengine/green_equil_RT.cc +++ b/rtengine/green_equil_RT.cc @@ -110,7 +110,7 @@ void CLASS RawImageSource::green_equilibrate(float thresh) for (row=rr+top, cc=0; cc < numcols; cc++) { col = cc+left; //cfa[rr*TS+cc] = image[row*width+col][FC(row,col)];//for dcraw implementation - cfa[rr*TS+cc] = ri->data[row][col]; + cfa[rr*TS+cc] = rawData[row][col]; } @@ -190,7 +190,7 @@ void CLASS RawImageSource::green_equilibrate(float thresh) col = cc + left; //c = FC(row,col); //image[row*width + col][c] = CLIP((int)(cfa[indx] + 0.5)); //for dcraw implementation - ri->data[row][col] = CLIP((int)(cfa[indx] + 0.5)); + rawData[row][col] = CLIP((int)(cfa[indx] + 0.5)); } // clean up diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 2e260c853..1d4850e01 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -66,7 +66,9 @@ class ImageSource : public InitialImage { virtual ~ImageSource () {} virtual int load (Glib::ustring fname) =0; - virtual void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hlp, ColorManagementParams cmp) {} + virtual void preprocess (const RAWParams &raw){}; + virtual void demosaic (const RAWParams &raw){}; + virtual void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hlp, ColorManagementParams cmp, RAWParams raw) {} virtual ColorTemp getWB () =0; virtual ColorTemp getAutoWB () =0; virtual ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) =0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index fc66c93e9..76aeb432f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -79,6 +79,10 @@ void ImProcCoordinator::updatePreviewImage (int todo) { ipf.setScale (scale); progress ("Applying white balance, color correction & sRBG conversion...",100*readyphase/numofphases); + if ( todo & M_PREPROC) + imgsrc->preprocess( params.raw ); + if( todo & M_RAW) + imgsrc->demosaic( params.raw ); if (todo & M_INIT) { minit.lock (); if (settings->verbose) printf ("Applying white balance, color correction & sRBG conversion...\n"); @@ -105,7 +109,7 @@ void ImProcCoordinator::updatePreviewImage (int todo) { imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, scale); setScale (scale, true); - imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm); + imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); minit.unlock (); } @@ -479,7 +483,9 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { ppar.hlrecovery.enabled = false; ppar.icm.input = "(none)"; Image16* im = new Image16 (fW, fH); - imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm); + imgsrc->preprocess( ppar.raw ); + imgsrc->demosaic( ppar.raw ); + imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); im->saveJPEG (fname, 85); mProcessing.unlock (); } diff --git a/rtengine/init.cc b/rtengine/init.cc index 167ca3e3a..86044077c 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -21,6 +21,7 @@ #include #include #include +#include namespace rtengine { @@ -39,6 +40,7 @@ int init (const Settings* s) { dcrMutex = new Glib::Mutex; delete lcmsMutex; lcmsMutex = new Glib::Mutex; + dfm.init( s->darkFramesPath ); return 0; } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 185835498..4fbf9b746 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -19,10 +19,6 @@ #ifndef __PROCEVENT__ #define __PROCEVENT__ -#include - -#define NUMOFEVENTS 86 - namespace rtengine { enum ProcEvent { @@ -111,7 +107,10 @@ enum ProcEvent { EvSHHighQuality=82, EvPerspCorr=83, EvEqualizer=84, - EvEqlEnabled=85 + EvEqlEnabled=85, + EvDemosaic=86, + EvPreProcess=87, + NUMOFEVENTS=88 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d8c1715a2..1fee2c314 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -27,6 +27,8 @@ namespace rtengine { namespace procparams { +const char *RAWParams::methodstring[RAWParams::numMethods]={"eahd", "hphd", "vng4", "dcb", "amaze", "ahd" }; + ProcParams::ProcParams () { setDefaults (); @@ -163,7 +165,16 @@ void ProcParams::setDefaults () { { equalizer.c[i] = 0; } - + raw.df_autoselect = false; + raw.ca_autocorrect = false; + raw.hotdeadpix_filt = false; + raw.linenoise = 0; + raw.greenthresh = 0; + raw.ccSteps = 1; + raw.dmethod = RAWParams::methodstring[RAWParams::hphd];; + raw.dcb_iterations=2; + raw.dcb_enhance=false; + exif.clear (); iptc.clear (); @@ -319,6 +330,18 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_integer("Equalizer", ss.str(), equalizer.c[i]); } + // save RAW parameters + keyFile.set_string ("RAW", "DarkFrame", raw.dark_frame ); + keyFile.set_boolean ("RAW", "DarkFrameAuto", raw.df_autoselect ); + keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); + keyFile.set_boolean ("RAW", "HotDeadPixels", raw.hotdeadpix_filt ); + keyFile.set_integer ("RAW", "LineDenoise", raw.linenoise); + keyFile.set_integer ("RAW", "GreenEqThreshold", raw.greenthresh); + keyFile.set_integer ("RAW", "CcSteps", raw.ccSteps); + keyFile.set_string ("RAW", "Method", raw.dmethod ); + keyFile.set_integer ("RAW", "DCBIterations", raw.dcb_iterations ); + keyFile.set_boolean ("RAW", "DCBEnhance", raw.dcb_enhance ); + // save exif change list for (int i=0; i keys = keyFile.get_keys ("Exif"); @@ -693,6 +730,16 @@ bool ProcParams::operator== (const ProcParams& other) { && resize.dataspec == other.resize.dataspec && resize.width == other.resize.width && resize.height == other.resize.height + && raw.dark_frame == other.raw.dark_frame + && raw.df_autoselect == other.raw.df_autoselect + && raw.dcb_enhance == other.raw.dcb_enhance + && raw.dcb_iterations == other.raw.dcb_iterations + && raw.ccSteps == other.raw.ccSteps + && raw.ca_autocorrect == other.raw.ca_autocorrect + && raw.hotdeadpix_filt == other.raw.hotdeadpix_filt + && raw.dmethod == other.raw.dmethod + && raw.greenthresh == other.raw.greenthresh + && raw.linenoise == other.raw.linenoise && icm.input == other.icm.input && icm.gammaOnInput == other.icm.gammaOnInput && icm.working == other.icm.working diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 9d6909f3d..219f9fe72 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -312,6 +312,28 @@ class EqualizerParams { int c[8]; }; +/** + * Parameters for RAW demosaicing + */ +class RAWParams { + + public: + enum eMethod{eahd,hphd,vng4,dcb,amaze,ahd, + numMethods }; // This MUST be the last enum + static const char *methodstring[numMethods]; + + Glib::ustring dark_frame; + bool df_autoselect; + bool ca_autocorrect; + bool hotdeadpix_filt; + int linenoise; + int greenthresh; + int ccSteps; + Glib::ustring dmethod; + int dcb_iterations; + bool dcb_enhance; +}; + /** * This class holds all the processing parameters applied on the images */ @@ -340,6 +362,7 @@ class ProcParams { ResizeParams resize; ///< Resize parameters ColorManagementParams icm; ///< profiles/color spaces used during the image processing EqualizerParams equalizer; ///< wavelet equalizer parameters + RAWParams raw; ///< RAW parameters before demosaicing std::vector exif; ///< List of modifications appplied on the exif tags of the input image std::vector iptc; ///< The IPTC tags and values to be saved to the output image int version; ///< Version of the file from which the parameters have been read diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a9aa2a881..c1785464a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef _OPENMP #include @@ -33,8 +34,6 @@ namespace rtengine { -int loadRaw (const char* fname, struct RawImage* ri); - extern const Settings* settings; #undef ABS @@ -47,14 +46,23 @@ extern const Settings* settings; #define MIN(a,b) ((a)>(b)?(b):(a)) #define DIST(a,b) (ABS(a-b)) -RawImageSource::RawImageSource () : ImageSource(), plistener(NULL), green(NULL), red(NULL), blue(NULL), cache(NULL), border(4) { - +RawImageSource::RawImageSource () +:ImageSource() +,plistener(NULL) +,green(NULL) +,red(NULL) +,blue(NULL) +,cache(NULL) +,border(4) +,rawData(NULL) +,ri(NULL) +,df(NULL) +{ hrmap[0] = NULL; hrmap[1] = NULL; hrmap[2] = NULL; needhr = NULL; hpmap = NULL; - oldmethod = "None"; camProfile = NULL; embProfile = NULL; } @@ -63,20 +71,20 @@ RawImageSource::~RawImageSource () { delete idata; if (ri) { - if (ri->allocation) - free (ri->allocation); - if (ri->data) - free (ri->data); - if (ri->profile_data) - free (ri->profile_data); delete ri; } + if(df){ + delete df; + } + if (green) freeArray(green, H); if (red) freeArray(red, H); if (blue) freeArray(blue, H); + if(rawData) + freeArray(rawData, H); delete [] cache; if (hrmap[0]!=NULL) { @@ -173,7 +181,8 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s } } -void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp) { +void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw ) +{ isrcMutex.lock (); @@ -185,9 +194,9 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe rm = icoeff[0][0]*r + icoeff[0][1]*g + icoeff[0][2]*b; gm = icoeff[1][0]*r + icoeff[1][1]*g + icoeff[1][2]*b; bm = icoeff[2][0]*r + icoeff[2][1]*g + icoeff[2][2]*b; - rm = ri->camwb_red / rm; - gm = ri->camwb_green / gm; - bm = ri->camwb_blue / bm; + rm = camwb_red / rm; + gm = camwb_green / gm; + bm = camwb_blue / bm; double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; rm /= mul_lum; gm /= mul_lum; @@ -234,27 +243,17 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe unsigned short* blue = new unsigned short[imwidth]; for (int i=sy1,ix=0; ixfilters && this->red && this->blue) { + if (ri->filters) { for (int j=0,jx=sx1; jred[i][jx]); - grn[j] = CLIP(gm*green[i][jx]); + grn[j] = CLIP(gm*this->green[i][jx]); blue[j] = CLIP(bm*this->blue[i][jx]); - } - } else if(ri->filters) { - if (i==0) - interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, sx1, imwidth, pp.skip); - else if (i==H-1) - interpolate_row_rb_mul_pp (red, blue, green[i-1], green[i], NULL, i, rm, gm, bm, sx1, imwidth, pp.skip); - else - interpolate_row_rb_mul_pp (red, blue, green[i-1], green[i], green[i+1], i, rm, gm, bm, sx1, imwidth, pp.skip); - - for (int j=0,jx=sx1; jdata[i][jx*3+0]); - grn[j] = CLIP(gm*ri->data[i][jx*3+1]); - blue[j] = CLIP(bm*ri->data[i][jx*3+2]); + red[j] = CLIP(rm*rawData[i][jx*3+0]); + grn[j] = CLIP(gm*rawData[i][jx*3+1]); + blue[j] = CLIP(bm*rawData[i][jx*3+2]); } } @@ -318,14 +317,52 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe // Color correction if (ri->filters && pp.skip==1) - correction_YIQ_LQ (image, settings->colorCorrectionSteps); + correction_YIQ_LQ (image, raw.ccSteps); // Applying postmul colorSpaceConversion (image, cmp, embProfile, camProfile, cam, defGain); isrcMutex.unlock (); } - + +void RawImageSource::cfaCleanFromList( const std::list &bpList ) +{ + int rr, cc; + unsigned short gin,g[8]; + float eps=1e-10;//tolerance to avoid dividing by zero + float p[8]; + + for (std::list::const_iterator iter=bpList.begin(); iter != bpList.end(); iter++ ){ + rr = iter->y; + if( rr<4 || rr>=H-4 ) + continue; + cc = iter->x; + if( cc<4 || cc>=W-4 ) + continue; + + //pixel neighbor average + gin=rawData[rr][cc]; + g[0]=rawData[rr-2][cc-2]; + g[1]=rawData[rr-2][cc]; + g[2]=rawData[rr-2][cc+2]; + g[3]=rawData[rr][cc-2]; + g[4]=rawData[rr][cc+2]; + g[5]=rawData[rr+2][cc-2]; + g[6]=rawData[rr+2][cc]; + g[7]=rawData[rr+2][cc+2]; + + p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-rawData[rr-4][cc-4])+fabs(rawData[rr-1][cc-1]-rawData[rr-3][cc-3])); + p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-rawData[rr-4][cc])+fabs(rawData[rr-1][cc]-rawData[rr-3][cc])); + p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-rawData[rr-4][cc+4])+fabs(rawData[rr-1][cc+1]-rawData[rr-3][cc+3])); + p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-rawData[rr][cc-4])+fabs(rawData[rr][cc-1]-rawData[rr][cc-3])); + p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-rawData[rr][cc+4])+fabs(rawData[rr][cc+1]-rawData[rr][cc+3])); + p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-rawData[rr+4][cc-4])+fabs(rawData[rr+1][cc-1]-rawData[rr+3][cc-3])); + p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-rawData[rr+4][cc])+fabs(rawData[rr+1][cc]-rawData[rr+3][cc])); + p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-rawData[rr+4][cc+4])+fabs(rawData[rr+1][cc+1]-rawData[rr+3][cc+3])); + + rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7])); + } +} void RawImageSource::cfa_clean(float thresh) //Emil's hot/dead pixel removal -- only filters egregiously impulsive pixels { @@ -344,31 +381,31 @@ void RawImageSource::cfa_clean(float thresh) //Emil's hot/dead pixel removal -- for (cc=4; cc < W-4; cc++) { //pixel neighbor average - gin=ri->data[rr][cc]; - g[0]=ri->data[rr-2][cc-2]; - g[1]=ri->data[rr-2][cc]; - g[2]=ri->data[rr-2][cc+2]; - g[3]=ri->data[rr][cc-2]; - g[4]=ri->data[rr][cc+2]; - g[5]=ri->data[rr+2][cc-2]; - g[6]=ri->data[rr+2][cc]; - g[7]=ri->data[rr+2][cc+2]; + gin=rawData[rr][cc]; + g[0]=rawData[rr-2][cc-2]; + g[1]=rawData[rr-2][cc]; + g[2]=rawData[rr-2][cc+2]; + g[3]=rawData[rr][cc-2]; + g[4]=rawData[rr][cc+2]; + g[5]=rawData[rr+2][cc-2]; + g[6]=rawData[rr+2][cc]; + g[7]=rawData[rr+2][cc+2]; pixave=(float)(g[0]+g[1]+g[2]+g[3]+g[4]+g[5]+g[6]+g[7])/8; pixratio=MIN(gin,pixave)/(eps+MAX(gin,pixave)); if (pixratio > thresh) continue; - p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-ri->data[rr-4][cc-4])+fabs(ri->data[rr-1][cc-1]-ri->data[rr-3][cc-3])); - p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-ri->data[rr-4][cc])+fabs(ri->data[rr-1][cc]-ri->data[rr-3][cc])); - p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-ri->data[rr-4][cc+4])+fabs(ri->data[rr-1][cc+1]-ri->data[rr-3][cc+3])); - p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-ri->data[rr][cc-4])+fabs(ri->data[rr][cc-1]-ri->data[rr][cc-3])); - p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-ri->data[rr][cc+4])+fabs(ri->data[rr][cc+1]-ri->data[rr][cc+3])); - p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-ri->data[rr+4][cc-4])+fabs(ri->data[rr+1][cc-1]-ri->data[rr+3][cc-3])); - p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-ri->data[rr+4][cc])+fabs(ri->data[rr+1][cc]-ri->data[rr+3][cc])); - p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-ri->data[rr+4][cc+4])+fabs(ri->data[rr+1][cc+1]-ri->data[rr+3][cc+3])); + p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-rawData[rr-4][cc-4])+fabs(rawData[rr-1][cc-1]-rawData[rr-3][cc-3])); + p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-rawData[rr-4][cc])+fabs(rawData[rr-1][cc]-rawData[rr-3][cc])); + p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-rawData[rr-4][cc+4])+fabs(rawData[rr-1][cc+1]-rawData[rr-3][cc+3])); + p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-rawData[rr][cc-4])+fabs(rawData[rr][cc-1]-rawData[rr][cc-3])); + p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-rawData[rr][cc+4])+fabs(rawData[rr][cc+1]-rawData[rr][cc+3])); + p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-rawData[rr+4][cc-4])+fabs(rawData[rr+1][cc-1]-rawData[rr+3][cc-3])); + p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-rawData[rr+4][cc])+fabs(rawData[rr+1][cc]-rawData[rr+3][cc])); + p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-rawData[rr+4][cc+4])+fabs(rawData[rr+1][cc+1]-rawData[rr+3][cc+3])); - ri->data[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ \ + rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ \ g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7])); }//now impulsive values have been corrected @@ -713,48 +750,27 @@ int RawImageSource::load (Glib::ustring fname) { plistener->setProgress (0.0); } - ri = new RawImage; - int res = loadRaw (fname.c_str(), ri); + ri = new RawImage(fname); + int res = ri->loadRaw (); if (res) return res; - if(red) { - delete red; - red = 0; - } - if(green) { - delete green; - green = 0; - } - if(blue) { - delete blue; - blue = 0; - } - + plistener=NULL; //\TODO must be reintroduced +/***** Copy once constant data extracted from raw *******/ W = ri->width; H = ri->height; - - d1x = !strcmp(ri->model, "D1X"); fuji = ri->fuji_width; - if (d1x) - border = 8; - for (int i=0; i<3; i++) for (int j=0; j<3; j++) coeff[i][j] = ri->coeff[i][j]; - // compute inverse of the color transformation matrix inverse33 (coeff, icoeff); - double cam_r = coeff[0][0]*ri->camwb_red + coeff[0][1]*ri->camwb_green + coeff[0][2]*ri->camwb_blue; - double cam_g = coeff[1][0]*ri->camwb_red + coeff[1][1]*ri->camwb_green + coeff[1][2]*ri->camwb_blue; - double cam_b = coeff[2][0]*ri->camwb_red + coeff[2][1]*ri->camwb_green + coeff[2][2]*ri->camwb_blue; - - wb = ColorTemp (cam_r, cam_g, cam_b); - - double tr = icoeff[0][0] * cam_r + icoeff[0][1] * cam_g + icoeff[0][2] * cam_b; - double tg = icoeff[1][0] * cam_r + icoeff[1][1] * cam_g + icoeff[1][2] * cam_b; - double tb = icoeff[2][0] * cam_r + icoeff[2][1] * cam_g + icoeff[2][2] * cam_b; + d1x = !strcmp(ri->model, "D1X"); + if (d1x) + border = 8; + if (ri->profile_data) + embProfile = cmsOpenProfileFromMem (ri->profile_data, ri->profile_len); // create profile memset (cam, 0, sizeof(cam)); @@ -765,20 +781,66 @@ int RawImageSource::load (Glib::ustring fname) { camProfile = iccStore.createFromMatrix (cam, false, "Camera"); inverse33 (cam, icam); - if (ri->profile_data) - embProfile = cmsOpenProfileFromMem (ri->profile_data, ri->profile_len); - - defGain = log(ri->defgain) / log(2.0); - + //Load complete Exif informations RawMetaDataLocation rml; rml.exifBase = ri->exifbase; rml.ciffBase = ri->ciff_base; rml.ciffLength = ri->ciff_len; + idata = new ImageData (fname, &rml); - idata = new ImageData (fname, &rml); + green = allocArray(W,H); + red = allocArray(W,H); + blue = allocArray(W,H); + hpmap = allocArray(W, H); + + return 0; // OK! +} + +void RawImageSource::preprocess (const RAWParams &raw) +{ + Glib::ustring newDF = raw.dark_frame; + Glib::ustring currentDF = (df ? df->fname : ""); + if (!raw.df_autoselect) { + if (newDF != currentDF) { + if (df) + delete df; + df = NULL; + if (newDF.length() > 0) { + df = new RawImage(newDF); + int res = df->loadRaw(); + if (res) { + delete df; + df = NULL; + } + } + } + + copyOriginalPixels(ri, df); + }else{ + RawImage *rid = dfm.searchDarkFrame( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); + copyOriginalPixels(ri, rid); + } + if(!raw.hotdeadpix_filt && raw.df_autoselect ){ + std::list bp = dfm.searchBadPixels( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); + cfaCleanFromList(bp); + } + preInterpolate(false); + scaleColors( false,true); + + double cam_r = coeff[0][0]*camwb_red + coeff[0][1]*camwb_green + coeff[0][2]*camwb_blue; + double cam_g = coeff[1][0]*camwb_red + coeff[1][1]*camwb_green + coeff[1][2]*camwb_blue; + double cam_b = coeff[2][0]*camwb_red + coeff[2][1]*camwb_green + coeff[2][2]*camwb_blue; + + wb = ColorTemp (cam_r, cam_g, cam_b); + + double tr = icoeff[0][0] * cam_r + icoeff[0][1] * cam_g + icoeff[0][2] * cam_b; + double tg = icoeff[1][0] * cam_r + icoeff[1][1] * cam_g + icoeff[1][2] * cam_b; + double tb = icoeff[2][0] * cam_r + icoeff[2][1] * cam_g + icoeff[2][2] * cam_b; + + defGain = log(ri->defgain) / log(2.0); //\TODO rivedere l'assegnamento di ri->defgain che dovrebbe essere "costante" // check if it is an olympus E camera, if yes, compute G channel pre-compensation factors - if (settings->greenthresh || (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,7)=="Panasonic")) && settings->demosaicMethod!="vng4" && ri->filters) ) { + if ( raw.greenthresh || (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,7)=="Panasonic")) && raw.dmethod != RAWParams::methodstring[ RAWParams::vng4] && ri->filters) ) { // global correction int ng1=0, ng2=0; double avgg1=0, avgg2=0; @@ -786,11 +848,11 @@ int RawImageSource::load (Glib::ustring fname) { for (int j=border; jdata[i][j]; + avgg1 += rawData[i][j]; ng1++; } else { - avgg2 += ri->data[i][j]; + avgg2 += rawData[i][j]; ng2++; } } @@ -799,48 +861,18 @@ int RawImageSource::load (Glib::ustring fname) { for (int i=border; idata[i][j] = CLIP(ri->data[i][j] * (i%2 ? corrg2 : corrg1)); + rawData[i][j] = CLIP(rawData[i][j] * (i%2 ? corrg2 : corrg1)); } - - // local correction in a 9x9 box - if (settings->greenthresh) { -//Emil's green equilbration + if ( raw.greenthresh >0) { if (plistener) { plistener->setProgressStr ("Green equilibrate..."); plistener->setProgress (0.0); } - green_equilibrate(0.01*(settings->greenthresh)); - -/* unsigned short* corr_alloc = new unsigned short[W*H]; - unsigned short** corr_data = new unsigned short* [H]; - for (int i=0; iallocation, W*H*sizeof(unsigned short)); - for (int i=border; idata[i-4][j-4] + ri->data[i-4][j-2] + ri->data[i-4][j] + ri->data[i-4][j+2] + - ri->data[i-2][j-4] + ri->data[i-2][j-2] + ri->data[i-2][j] + ri->data[i-2][j+2] + - ri->data[i][j-4] + ri->data[i][j-2] + ri->data[i][j] + ri->data[i][j+2] + - ri->data[i+2][j-4] + ri->data[i+2][j-2] + ri->data[i+2][j] + ri->data[i+2][j+2]; - unsigned int ag2 = ri->data[i-3][j-3] + ri->data[i-3][j-1] + ri->data[i-3][j+1] + ri->data[i-3][j+1] + - ri->data[i-1][j-3] + ri->data[i-1][j-1] + ri->data[i-1][j+1] + ri->data[i-1][j+1] + - ri->data[i+1][j-3] + ri->data[i+1][j-1] + ri->data[i+1][j+1] + ri->data[i+1][j+1] + - ri->data[i+3][j-3] + ri->data[i+3][j-1] + ri->data[i+3][j+1] + ri->data[i+3][j+1]; - unsigned int val = (ri->data[i][j] + ri->data[i][j] * ag2 / ag1) / 2; - corr_data[i][j] = CLIP (val); - } - memcpy (ri->allocation, corr_alloc, W*H*sizeof(unsigned short)); - delete corr_alloc; - delete corr_data; */ - + green_equilibrate(0.01*(raw.greenthresh)); } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//Emil's CFA hot/dead pixel filter - - if (settings->hotdeadpix_filt) { + if ( raw.hotdeadpix_filt ) { if (plistener) { plistener->setProgressStr ("Hot/Dead Pixel Filter..."); plistener->setProgress (0.0); @@ -848,23 +880,17 @@ int RawImageSource::load (Glib::ustring fname) { cfa_clean(0.1); } - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//Emil's line noise filter - if (settings->linenoise) { + if ( raw.linenoise >0 ) { if (plistener) { plistener->setProgressStr ("Line Denoise..."); plistener->setProgress (0.0); } - cfa_linedn(0.00002*(settings->linenoise)); + cfa_linedn(0.00002*(raw.linenoise)); } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//Emil's CA auto correction - - if (settings->ca_autocorrect) { + if ( raw.ca_autocorrect ) { if (plistener) { plistener->setProgressStr ("CA Auto Correction..."); plistener->setProgress (0.0); @@ -872,37 +898,203 @@ int RawImageSource::load (Glib::ustring fname) { CA_correct_RT(); } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - + + + return; +} +void RawImageSource::demosaic(const RAWParams &raw) +{ if (ri->filters) { //MyTime t1,t2; //t1.set(); - // demosaic - if (settings->demosaicMethod=="hphd") + if ( raw.dmethod == RAWParams::methodstring[RAWParams::hphd] ) hphd_demosaic (); - else if (settings->demosaicMethod=="vng4") + else if (raw.dmethod == RAWParams::methodstring[RAWParams::vng4] ) vng4_demosaic (); - else if (settings->demosaicMethod=="ahd") + else if (raw.dmethod == RAWParams::methodstring[RAWParams::ahd] ) ahd_demosaic (); - //else if (settings->demosaicMethod=="ppg") - // ppg_demosaic (); - else if (settings->demosaicMethod=="amaze") - amaze_demosaic_RT ();//Emil's code for AMaZE - else if (settings->demosaicMethod=="dcb") - dcb_demosaic(settings->dcb_iterations, settings->dcb_enhance? 1:0); - else + else if (raw.dmethod == RAWParams::methodstring[RAWParams::amaze] ) + amaze_demosaic_RT (); + else if (raw.dmethod == RAWParams::methodstring[RAWParams::dcb] ) + dcb_demosaic(raw.dcb_iterations, raw.dcb_enhance? 1:0); + else if (raw.dmethod == RAWParams::methodstring[RAWParams::eahd]) eahd_demosaic (); + else + nodemosaic(); //t2.set(); //printf("Demosaicing:%d usec\n",t2.etime(t1)); } - - if (plistener) { plistener->setProgressStr ("Ready."); plistener->setProgress (1.0); } - return 0; +} + +/* Copy original pixel data and + * subtract dark frame (if present) from current image + */ +void RawImageSource::copyOriginalPixels(RawImage *src, RawImage *riDark ) +{ + if (ri->filters) { + if (!rawData) + rawData = allocArray< unsigned short >(W,H); + if (riDark && W == riDark->width && H == riDark->height) { + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + rawData[row][col] = MAX (src->data[row][col]+ri->black_point - riDark->data[row][col], 0); + } + } + }else{ + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + rawData[row][col] = src->data[row][col]; + } + } + } + }else{ + if (!rawData) + rawData = allocArray< unsigned short >(3*W,H); + if (riDark && W == riDark->width && H == riDark->height) { + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + rawData[row][3*col+0] = MAX (src->data[row][3*col+0]+ri->black_point - riDark->data[row][3*col+0], 0); + rawData[row][3*col+1] = MAX (src->data[row][3*col+1]+ri->black_point - riDark->data[row][3*col+1], 0); + rawData[row][3*col+2] = MAX (src->data[row][3*col+2]+ri->black_point - riDark->data[row][3*col+2], 0); + } + } + }else{ + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + rawData[row][3*col+0] = src->data[row][3*col+0]; + rawData[row][3*col+1] = src->data[row][3*col+1]; + rawData[row][3*col+2] = src->data[row][3*col+2]; + } + } + } + } +} + +/* Scale original pixels into the range 0 65535 using black offsets and multipliers + * Calculate camwb_red,camwb_green,camwb_blue + * + * Calculate 4 coeff. scale_mul[] and 4 offset cblack[] + * and reset all pixels + */ +void RawImageSource::scaleColors(bool use_auto_wb, bool use_camera_wb, int highlight) +{ + unsigned row, col, ur, uc, i, x, y, c, sum[8]; + int val, dark, sat; + double dsum[8], dmin, dmax; + float pre_mul[4]; + + int cblack[4]; // offset calculated + float scale_mul[4]; // coeff. calculated to scale + + for (int c = 0; c < 4; c++){ + cblack[c] = ri->cblack[c] + ri->black_point; + pre_mul[c] = ri->pre_mul[c]; + } + /* + if (user_mul[0]) + memcpy(pre_mul, user_mul, sizeof pre_mul);*/ + if (use_auto_wb || (use_camera_wb && ri->cam_mul[0] == -1)) { + memset(dsum, 0, sizeof dsum); + for (row = 0; row < H; row += 8) + for (col = 0; col < W; col += 8) { + memset(sum, 0, sizeof sum); + for (y = row; y < row + 8 && y < H; y++) + for (x = col; x < col + 8 && x < W; x++) + for (int c = 0; c < 3; c++) { + if (ri->filters) { + c = FC(y, x); + val = rawData[y][x]; + } else + val = rawData[y][3*x+c]; + if (val > ri->maximum - 25) + goto skip_block; + if ((val -= cblack[c]) < 0) + val = 0; + sum[c] += val; + sum[c + 4]++; + if (ri->filters) + break; + } + for (c = 0; c < 8; c++) + dsum[c] += sum[c]; +skip_block: ; + } + for (int c = 0; c < 4; c++) + if (dsum[c]) + pre_mul[c] = dsum[c + 4] / dsum[c]; + } + if (use_camera_wb && ri->cam_mul[0] != -1) { + memset(sum, 0, sizeof sum); + for (row = 0; row < 8; row++) + for (col = 0; col < 8; col++) { + int c = FC(row, col); + if ((val = ri->white[row][col] - cblack[c]) > 0) + sum[c] += val; + sum[c + 4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + for (int c = 0; c < 4; c++) + pre_mul[c] = (float) sum[c + 4] / sum[c]; + else if (ri->cam_mul[0] && ri->cam_mul[2]) + memcpy(pre_mul, ri->cam_mul, sizeof pre_mul); + else + fprintf(stderr, "Cannot use camera white balance.\n"); + } + if (pre_mul[3] == 0) + pre_mul[3] = ri->colors < 4 ? pre_mul[1] : 1; + dark = ri->black_point; + sat = ri->maximum; + sat -= ri->black_point; + for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + if (!highlight) + dmax = dmin; + for (c = 0; c < 4; c++) + scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / sat; + if (settings->verbose) { + fprintf(stderr,"Scaling with darkness %d, saturation %d, and\nmultipliers", dark, sat); + for (c = 0; c < 4; c++) + fprintf(stderr, " %f", pre_mul[c]); + fputc('\n', stderr); + } + + // scale image colors + for (row = 0; row < H; row ++){ + for (col = 0; col < W; col++) { + val = rawData[row][col]; + if (!val) + continue; + int c = FC(row, col); + val -= cblack[c]; + val *= scale_mul[c]; + rawData[row][col] = CLIP(val); + } + } + camwb_red = ri->pre_mul[0] / pre_mul[0]; + camwb_green = ri->pre_mul[1] / pre_mul[1]; + camwb_blue = ri->pre_mul[2] / pre_mul[2]; + ri->defgain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); +} + +void RawImageSource::preInterpolate(bool force4colors) +{ + if (ri->filters && ri->colors == 3) { + if (force4colors) + ri->colors++; + else { + ri->prefilters = ri->filters; + ri->filters &= ~((ri->filters & 0x55555555) << 1); + } + } } int RawImageSource::defTransform (int tran) { @@ -1219,10 +1411,6 @@ void RawImageSource::eahd_demosaic () { unsigned short* homh[3]; unsigned short* homv[3]; - green = new unsigned short*[H]; - for (int i=0; idata[i-1][j]; + green[i-1][j] = rawData[i-1][j]; else { hc = homh[imx][j]; vc = homv[imx][j]; @@ -1429,6 +1617,19 @@ void RawImageSource::eahd_demosaic () { freeArray2(lav, 3); freeArray2(lbv, 3); freeArray2(homv, 3); + + // Interpolate R and B + for (int i=0; idata[i-5][k] - 8*ri->data[i-4][k] + 27*ri->data[i-3][k] - 48*ri->data[i-2][k] + 42*ri->data[i-1][k] - - (ri->data[i+5][k] - 8*ri->data[i+4][k] + 27*ri->data[i+3][k] - 48*ri->data[i+2][k] + 42*ri->data[i+1][k])) / 100.0; + temp[i] = (rawData[i-5][k] - 8*rawData[i-4][k] + 27*rawData[i-3][k] - 48*rawData[i-2][k] + 42*rawData[i-1][k] - + (rawData[i+5][k] - 8*rawData[i+4][k] + 27*rawData[i+3][k] - 48*rawData[i+2][k] + 42*rawData[i+1][k])) / 100.0; temp[i] = ABS(temp[i]); } for (int j=4; jdata[i][j-5] - 8*ri->data[i][j-4] + 27*ri->data[i][j-3] - 48*ri->data[i][j-2] + 42*ri->data[i][j-1] - - (ri->data[i][j+5] - 8*ri->data[i][j+4] + 27*ri->data[i][j+3] - 48*ri->data[i][j+2] + 42*ri->data[i][j+1])) / 100; + temp[j] = (rawData[i][j-5] - 8*rawData[i][j-4] + 27*rawData[i][j-3] - 48*rawData[i][j-2] + 42*rawData[i][j-1] - + (rawData[i][j+5] - 8*rawData[i][j+4] + 27*rawData[i][j+3] - 48*rawData[i][j+2] + 42*rawData[i][j+1])) / 100; temp[j] = ABS(temp[j]); } for (int j=4; jdata[i][j]; + green[i][j] = rawData[i][j]; else { if (this->hpmap[i][j]==1) { - int g2 = ri->data[i][j+1] + ((ri->data[i][j] - ri->data[i][j+2]) >> 1); - int g4 = ri->data[i][j-1] + ((ri->data[i][j] - ri->data[i][j-2]) >> 1); + int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) >> 1); + int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) >> 1); - int dx = ri->data[i][j+1] - ri->data[i][j-1]; - int d1 = ri->data[i][j+3] - ri->data[i][j+1]; - int d2 = ri->data[i][j+2] - ri->data[i][j]; - int d3 = (ri->data[i-1][j+2] - ri->data[i-1][j]) >> 1; - int d4 = (ri->data[i+1][j+2] - ri->data[i+1][j]) >> 1; + 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]) >> 1; + int d4 = (rawData[i+1][j+2] - rawData[i+1][j]) >> 1; double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); - d1 = ri->data[i][j-3] - ri->data[i][j-1]; - d2 = ri->data[i][j-2] - ri->data[i][j]; - d3 = (ri->data[i-1][j-2] - ri->data[i-1][j]) >> 1; - d4 = (ri->data[i+1][j-2] - ri->data[i+1][j]) >> 1; + 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]) >> 1; + d4 = (rawData[i+1][j-2] - rawData[i+1][j]) >> 1; double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); green[i][j] = CLIP((e2 * g2 + e4 * g4) / (e2 + e4)); } else if (this->hpmap[i][j]==2) { - int g1 = ri->data[i-1][j] + ((ri->data[i][j] - ri->data[i-2][j]) >> 1); - int g3 = ri->data[i+1][j] + ((ri->data[i][j] - ri->data[i+2][j]) >> 1); + int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) >> 1); + int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) >> 1); - int dy = ri->data[i+1][j] - ri->data[i-1][j]; - int d1 = ri->data[i-1][j] - ri->data[i-3][j]; - int d2 = ri->data[i][j] - ri->data[i-2][j]; - int d3 = (ri->data[i][j-1] - ri->data[i-2][j-1]) >> 1; - int d4 = (ri->data[i][j+1] - ri->data[i-2][j+1]) >> 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]) >> 1; + int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) >> 1; double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); - d1 = ri->data[i+1][j] - ri->data[i+3][j]; - d2 = ri->data[i][j] - ri->data[i+2][j]; - d3 = (ri->data[i][j-1] - ri->data[i+2][j-1]) >> 1; - d4 = (ri->data[i][j+1] - ri->data[i+2][j+1]) >> 1; + 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]) >> 1; + d4 = (rawData[i][j+1] - rawData[i+2][j+1]) >> 1; double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); green[i][j] = CLIP((e1 * g1 + e3 * g3) / (e1 + e3)); } else { - int g1 = ri->data[i-1][j] + ((ri->data[i][j] - ri->data[i-2][j]) >> 1); - int g2 = ri->data[i][j+1] + ((ri->data[i][j] - ri->data[i][j+2]) >> 1); - int g3 = ri->data[i+1][j] + ((ri->data[i][j] - ri->data[i+2][j]) >> 1); - int g4 = ri->data[i][j-1] + ((ri->data[i][j] - ri->data[i][j-2]) >> 1); + int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) >> 1); + int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) >> 1); + int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) >> 1); + int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) >> 1); - int dx = ri->data[i][j+1] - ri->data[i][j-1]; - int dy = ri->data[i+1][j] - ri->data[i-1][j]; + int dx = rawData[i][j+1] - rawData[i][j-1]; + int dy = rawData[i+1][j] - rawData[i-1][j]; - int d1 = ri->data[i-1][j] - ri->data[i-3][j]; - int d2 = ri->data[i][j] - ri->data[i-2][j]; - int d3 = (ri->data[i][j-1] - ri->data[i-2][j-1]) >> 1; - int d4 = (ri->data[i][j+1] - ri->data[i-2][j+1]) >> 1; + 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]) >> 1; + int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) >> 1; double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); - d1 = ri->data[i][j+3] - ri->data[i][j+1]; - d2 = ri->data[i][j+2] - ri->data[i][j]; - d3 = (ri->data[i-1][j+2] - ri->data[i-1][j]) >> 1; - d4 = (ri->data[i+1][j+2] - ri->data[i+1][j]) >> 1; + 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]) >> 1; + d4 = (rawData[i+1][j+2] - rawData[i+1][j]) >> 1; double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); - d1 = ri->data[i+1][j] - ri->data[i+3][j]; - d2 = ri->data[i][j] - ri->data[i+2][j]; - d3 = (ri->data[i][j-1] - ri->data[i+2][j-1]) >> 1; - d4 = (ri->data[i][j+1] - ri->data[i+2][j+1]) >> 1; + 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]) >> 1; + d4 = (rawData[i][j+1] - rawData[i+2][j+1]) >> 1; double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); - d1 = ri->data[i][j-3] - ri->data[i][j-1]; - d2 = ri->data[i][j-2] - ri->data[i][j]; - d3 = (ri->data[i-1][j-2] - ri->data[i-1][j]) >> 1; - d4 = (ri->data[i+1][j-2] - ri->data[i+1][j]) >> 1; + 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]) >> 1; + d4 = (rawData[i+1][j-2] - rawData[i+1][j]) >> 1; double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); @@ -1634,7 +1835,6 @@ void RawImageSource::hphd_demosaic () { if (plistener) plistener->setProgress (0.33); - this->hpmap = allocArray(W, H); for (int i=0; ihpmap[i], 0, W*sizeof(char)); @@ -1657,13 +1857,20 @@ void RawImageSource::hphd_demosaic () { if (plistener) plistener->setProgress (0.66); - - green = new unsigned short*[H]; - for (int i=0; isetProgress (1.0); } @@ -1781,14 +1988,14 @@ int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { if (ri->filters) for (int j=start; jdata[i][j]>>histcompr]+=2; + histogram[rawData[i][j]>>histcompr]+=2; else - histogram[ri->data[i][j]>>histcompr]+=4; + histogram[rawData[i][j]>>histcompr]+=4; else for (int j=start; j<3*end; j++) { - histogram[ri->data[i][j+0]>>histcompr]++; - histogram[ri->data[i][j+1]>>histcompr]++; - histogram[ri->data[i][j+2]>>histcompr]++; + histogram[rawData[i][j+0]>>histcompr]++; + histogram[rawData[i][j+1]>>histcompr]++; + histogram[rawData[i][j+2]>>histcompr]++; } } return 1; @@ -1808,21 +2015,21 @@ ColorTemp RawImageSource::getAutoWB () { int end = MIN(ri->height+ri->width-fw-i, fw+i) - 32; for (int j=start; jfilters) { - double d = CLIP(ri->defgain*ri->data[i][3*j]); + double d = CLIP(ri->defgain*rawData[i][3*j]); if (d>64000) continue; avg_r += d*d*d*d*d*d; rn++; - d = CLIP(ri->defgain*ri->data[i][3*j+1]); + d = CLIP(ri->defgain*rawData[i][3*j+1]); if (d>64000) continue; avg_g += d*d*d*d*d*d; gn++; - d = CLIP(ri->defgain*ri->data[i][3*j+2]); + d = CLIP(ri->defgain*rawData[i][3*j+2]); if (d>64000) continue; avg_b += d*d*d*d*d*d; bn++; } else { - double d = CLIP(ri->defgain*ri->data[i][j]); + double d = CLIP(ri->defgain*rawData[i][j]); if (d>64000) continue; double dp = d*d*d*d*d*d; @@ -1846,21 +2053,21 @@ ColorTemp RawImageSource::getAutoWB () { for (int i=32; iheight-32; i++) for (int j=32; jwidth-32; j++) { if (!ri->filters) { - double d = CLIP(ri->defgain*ri->data[i][3*j]); + double d = CLIP(ri->defgain*rawData[i][3*j]); if (d>64000) continue; avg_r += d*d*d*d*d*d; rn++; - d = CLIP(ri->defgain*ri->data[i][3*j+1]); + d = CLIP(ri->defgain*rawData[i][3*j+1]); if (d>64000) continue; avg_g += d*d*d*d*d*d; gn++; - d = CLIP(ri->defgain*ri->data[i][3*j+2]); + d = CLIP(ri->defgain*rawData[i][3*j+2]); if (d>64000) continue; avg_b += d*d*d*d*d*d; bn++; } else { - double d = CLIP(ri->defgain*ri->data[i][j]); + double d = CLIP(ri->defgain*rawData[i][j]); if (d>64000) continue; double dp = d*d*d*d*d*d; @@ -1887,9 +2094,9 @@ ColorTemp RawImageSource::getAutoWB () { // return ColorTemp (pow(avg_r/rn, 1.0/6.0)*img_r, pow(avg_g/gn, 1.0/6.0)*img_g, pow(avg_b/bn, 1.0/6.0)*img_b); - double reds = pow (avg_r/rn, 1.0/6.0) * ri->camwb_red; - double greens = pow (avg_g/gn, 1.0/6.0) * ri->camwb_green; - double blues = pow (avg_b/bn, 1.0/6.0) * ri->camwb_blue; + double reds = pow (avg_r/rn, 1.0/6.0) * camwb_red; + double greens = pow (avg_g/gn, 1.0/6.0) * camwb_green; + double blues = pow (avg_b/bn, 1.0/6.0) * camwb_blue; double rm = coeff[0][0]*reds + coeff[0][1]*greens + coeff[0][2]*blues; double gm = coeff[1][0]*reds + coeff[1][1]*greens + coeff[1][2]*blues; @@ -1966,17 +2173,17 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector=0 && y>=0 && xdata[y][3*x]; + reds += rawData[y][3*x]; rn++; } transformPosition (green[i].x, green[i].y, tran, x, y); if (x>=0 && y>=0 && xdata[y][3*x+1]; + greens += rawData[y][3*x+1]; gn++; } transformPosition (blue[i].x, blue[i].y, tran, x, y); if (x>=0 && y>=0 && xdata[y][3*x+2]; + blues += rawData[y][3*x+2]; bn++; } } @@ -1988,7 +2195,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector=0 && yv>=0 && xvdata[yv][xv]; + reds += rawData[yv][xv]; rn++; break; } @@ -1998,7 +2205,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector=0 && yv>=0 && xvdata[yv][xv]; + greens += rawData[yv][xv]; gn++; break; } @@ -2008,7 +2215,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector=0 && yv>=0 && xvdata[yv][xv]; + blues += rawData[yv][xv]; bn++; break; } @@ -2016,9 +2223,9 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vectorcamwb_red; - greens = greens/gn * ri->camwb_green; - blues = blues/bn * ri->camwb_blue; + reds = reds/rn * camwb_red; + greens = greens/gn * camwb_green; + blues = blues/bn * camwb_blue; double rm = coeff[0][0]*reds + coeff[0][1]*greens + coeff[0][2]*blues; double gm = coeff[1][0]*reds + coeff[1][1]*greens + coeff[1][2]*blues; @@ -2073,7 +2280,7 @@ void RawImageSource::vng4_demosaic () { image = (ushort (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; iidata[ii][jj]; + image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj]; // first linear interpolation for (row=0; row < 16; row++) @@ -2201,12 +2408,21 @@ void RawImageSource::vng4_demosaic () { free (brow[4]); free (code[0][0]); - green = new unsigned short*[H]; for (int i=0; i> 1; } + // Interpolate R and B + for (int i=0; idata[ii][jj]; + image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj]; border_interpolate(3, image); @@ -2379,7 +2595,7 @@ void RawImageSource::ahd_demosaic() image = (ushort (*)[4]) calloc (H*W, sizeof *image); for (int ii=0; iidata[ii][jj]; + image[ii*W+jj][fc(ii,jj)] = rawData[ii][jj]; for (i=0; i < 0x10000; i++) { r = i / 65535.0; @@ -2505,28 +2721,37 @@ void RawImageSource::ahd_demosaic() if(plistener) plistener->setProgress (1.0); free (buffer); - red = new unsigned short*[H]; for (int i=0; isetProgressStr ("DCB Demosaicing..."); @@ -3011,7 +3228,7 @@ void RawImageSource::dcb_demosaic(int iterations, int dcb_enhance) float (*chrm)[2] = chroma; #endif - fill_raw( tile, x0,y0,ri->data ); + fill_raw( tile, x0,y0,rawData ); if( !xTile || !yTile || xTile==wTiles-1 || yTile==hTiles-1) fill_border(tile,6, x0, y0); dcb_hid(tile,buffer,buffer2,x0,y0); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index fe6fc8b30..9fe1e31f8 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -21,6 +21,7 @@ #include #include + #define HR_SCALE 2 namespace rtengine { @@ -53,6 +54,9 @@ class RawImageSource : public ImageSource { int W, H; ColorTemp wb; ProgressListener* plistener; + double camwb_red; + double camwb_green; + double camwb_blue; double coeff[3][3]; double icoeff[3][3]; double cam[3][3]; @@ -65,18 +69,20 @@ class RawImageSource : public ImageSource { char** needhr; // for color propagation int max[3]; double defGain; - bool full; - Glib::ustring oldmethod; + cmsHPROFILE camProfile; cmsHPROFILE embProfile; - RawImage* ri; + RawImage* ri; // Copy of raw pixels + RawImage* df; // Darkframe pixels (if present) // to accelerate CIELAB conversion: double lc00, lc01, lc02, lc10, lc11, lc12, lc20, lc21, lc22; double* cache; int threshold; - + + unsigned short** rawData; // holds pixel values, data[i][j] corresponds to the ith row and jth column + // the interpolated green plane: unsigned short** green; // the interpolated red plane: @@ -97,13 +103,18 @@ class RawImageSource : public ImageSource { void updateHLRecoveryMap (std::string method, double rm, double gm, double bm); void updateHLRecoveryMap_ColorPropagation (); void HLRecovery_ColorPropagation (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int width, int skip); - + int FC(int row, int col){ return (ri->prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3); } public: RawImageSource (); ~RawImageSource (); int load (Glib::ustring fname); - void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp); + void preprocess (const RAWParams &raw); + void demosaic (const RAWParams &raw); + void copyOriginalPixels( RawImage *ri, RawImage *riDark ); + void scaleColors( bool use_auto_wb=true, bool use_camera_wb=false, int highlight=1 ); + void preInterpolate(bool force4colors=false); + void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw); ColorTemp getWB () { return wb; } ColorTemp getAutoWB (); ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran); @@ -135,9 +146,9 @@ class RawImageSource : public ImageSource { inline void interpolate_row_rb (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i); inline void interpolate_row_rb_mul_pp (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i, double r_mul, double g_mul, double b_mul, int x1, int width, int skip); - int LinEqSolve (int nDim, float* pfMatr, float* pfVect, float* pfSolution);//Emil's CA auto correction + int LinEqSolve( int nDim, float* pfMatr, float* pfVect, float* pfSolution);//Emil's CA auto correction void CA_correct_RT (); - + void cfaCleanFromList( const std::list &bpList ); void cfa_clean (float thresh);//Emil's hot/dead pixel filter void ddct8x8s(int isgn, float **a); @@ -145,7 +156,7 @@ class RawImageSource : public ImageSource { void green_equilibrate (float greenthresh);//Emil's green equilibration - + void nodemosaic (); void eahd_demosaic (); void hphd_demosaic (); void vng4_demosaic (); diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h index c9dcfaf8e..552467c6a 100644 --- a/rtengine/rawimagesource_i.h +++ b/rtengine/rawimagesource_i.h @@ -76,47 +76,47 @@ inline void RawImageSource::interpolate_row_g (unsigned short* agh, unsigned sho for (int j=0; jdata[i][j]; - agv[j] = ri->data[i][j]; + agh[j] = rawData[i][j]; + agv[j] = rawData[i][j]; } else { int gh=0; int gv=0; if (j>1 && jdata[i][j-2] + 2*ri->data[i][j-1] + 2*ri->data[i][j] + 2*ri->data[i][j+1] -ri->data[i][j+2]) / 4; - int maxgh = MAX(ri->data[i][j-1], ri->data[i][j+1]); - int mingh = MIN(ri->data[i][j-1], ri->data[i][j+1]); + gh = (-rawData[i][j-2] + 2*rawData[i][j-1] + 2*rawData[i][j] + 2*rawData[i][j+1] -rawData[i][j+2]) / 4; + int maxgh = MAX(rawData[i][j-1], rawData[i][j+1]); + int mingh = MIN(rawData[i][j-1], rawData[i][j+1]); if (gh>maxgh) gh = maxgh; else if (ghdata[i][1]; + gh = rawData[i][1]; else if (j==1) - gh = (ri->data[i][0] + ri->data[i][2]) / 2; + gh = (rawData[i][0] + rawData[i][2]) / 2; else if (j==W-1) - gh = ri->data[i][W-2]; + gh = rawData[i][W-2]; else if (j==W-2) - gh = (ri->data[i][W-1] + ri->data[i][W-3]) / 2; + gh = (rawData[i][W-1] + rawData[i][W-3]) / 2; if (i>1 && idata[i-2][j] + 2*ri->data[i-1][j] + 2*ri->data[i][j] + 2*ri->data[i+1][j] - ri->data[i+2][j]) / 4; - int maxgv = MAX(ri->data[i-1][j], ri->data[i+1][j]); - int mingv = MIN(ri->data[i-1][j], ri->data[i+1][j]); + gv = (-rawData[i-2][j] + 2*rawData[i-1][j] + 2*rawData[i][j] + 2*rawData[i+1][j] - rawData[i+2][j]) / 4; + int maxgv = MAX(rawData[i-1][j], rawData[i+1][j]); + int mingv = MIN(rawData[i-1][j], rawData[i+1][j]); if (gv>maxgv) gv = maxgv; else if (gvdata[1][j]; + gv = rawData[1][j]; else if (i==1) - gv = (ri->data[0][j] + ri->data[2][j]) / 2; + gv = (rawData[0][j] + rawData[2][j]) / 2; else if (i==H-1) - gv = ri->data[H-2][j]; + gv = rawData[H-2][j]; else if (i==H-2) - gv = (ri->data[H-1][j] + ri->data[H-3][j]) / 2; + gv = (rawData[H-1][j] + rawData[H-3][j]) / 2; agh[j] = CLIP(gh); agv[j] = CLIP(gv); @@ -130,24 +130,24 @@ inline void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned sho for (int j=0; jdata[i][j]; + ar[j] = rawData[i][j]; // blue: cross interpolation int b = 0; int n = 0; if (i>0 && j>0) { - b += ri->data[i-1][j-1] - pg[j-1]; + b += rawData[i-1][j-1] - pg[j-1]; n++; } if (i>0 && jdata[i-1][j+1] - pg[j+1]; + b += rawData[i-1][j+1] - pg[j+1]; n++; } if (i0) { - b += ri->data[i+1][j-1] - ng[j-1]; + b += rawData[i+1][j-1] - ng[j-1]; n++; } if (idata[i+1][j+1] - ng[j+1]; + b += rawData[i+1][j+1] - ng[j+1]; n++; } b = cg[j] + b / n; @@ -157,20 +157,20 @@ inline void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned sho // linear R-G interp. horizontally int r; if (j==0) - r = cg[0] + ri->data[i][1] - cg[1]; + r = cg[0] + rawData[i][1] - cg[1]; else if (j==W-1) - r = cg[W-1] + ri->data[i][W-2] - cg[W-2]; + r = cg[W-1] + rawData[i][W-2] - cg[W-2]; else - r = cg[j] + (ri->data[i][j-1] - cg[j-1] + ri->data[i][j+1] - cg[j+1]) / 2; + r = cg[j] + (rawData[i][j-1] - cg[j-1] + rawData[i][j+1] - cg[j+1]) / 2; ar[j] = CLIP(r); // linear B-G interp. vertically int b; if (i==0) - b = ng[j] + ri->data[1][j] - cg[j]; + b = ng[j] + rawData[1][j] - cg[j]; else if (i==H-1) - b = pg[j] + ri->data[H-2][j] - cg[j]; + b = pg[j] + rawData[H-2][j] - cg[j]; else - b = cg[j] + (ri->data[i-1][j] - pg[j] + ri->data[i+1][j] - ng[j]) / 2; + b = cg[j] + (rawData[i-1][j] - pg[j] + rawData[i+1][j] - ng[j]) / 2; ab[j] = CLIP(b); } } @@ -180,24 +180,24 @@ inline void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned sho for (int j=0; jdata[i][j]; + ab[j] = rawData[i][j]; // blue: cross interpolation int r = 0; int n = 0; if (i>0 && j>0) { - r += ri->data[i-1][j-1] - pg[j-1]; + r += rawData[i-1][j-1] - pg[j-1]; n++; } if (i>0 && jdata[i-1][j+1] - pg[j+1]; + r += rawData[i-1][j+1] - pg[j+1]; n++; } if (i0) { - r += ri->data[i+1][j-1] - ng[j-1]; + r += rawData[i+1][j-1] - ng[j-1]; n++; } if (idata[i+1][j+1] - ng[j+1]; + r += rawData[i+1][j+1] - ng[j+1]; n++; } r = cg[j] + r / n; @@ -208,20 +208,20 @@ inline void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned sho // linear B-G interp. horizontally int b; if (j==0) - b = cg[0] + ri->data[i][1] - cg[1]; + b = cg[0] + rawData[i][1] - cg[1]; else if (j==W-1) - b = cg[W-1] + ri->data[i][W-2] - cg[W-2]; + b = cg[W-1] + rawData[i][W-2] - cg[W-2]; else - b = cg[j] + (ri->data[i][j-1] - cg[j-1] + ri->data[i][j+1] - cg[j+1]) / 2; + b = cg[j] + (rawData[i][j-1] - cg[j-1] + rawData[i][j+1] - cg[j+1]) / 2; ab[j] = CLIP(b); // linear R-G interp. vertically int r; if (i==0) - r = ng[j] + ri->data[1][j] - cg[j]; + r = ng[j] + rawData[1][j] - cg[j]; else if (i==H-1) - r = pg[j] + ri->data[H-2][j] - cg[j]; + r = pg[j] + rawData[H-2][j] - cg[j]; else - r = cg[j] + (ri->data[i-1][j] - pg[j] + ri->data[i+1][j] - ng[j]) / 2; + r = cg[j] + (rawData[i-1][j] - pg[j] + rawData[i+1][j] - ng[j]) / 2; ar[j] = CLIP(r); } } @@ -235,24 +235,24 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (unsigned short* ar, unsig for (int j=x1, jx=0; jxdata[i][j]); + ar[jx] = CLIP(r_mul * rawData[i][j]); // blue: cross interpolation int b = 0; int n = 0; if (i>0 && j>0) { - b += b_mul*ri->data[i-1][j-1] - g_mul*pg[j-1]; + b += b_mul*rawData[i-1][j-1] - g_mul*pg[j-1]; n++; } if (i>0 && jdata[i-1][j+1] - g_mul*pg[j+1]; + b += b_mul*rawData[i-1][j+1] - g_mul*pg[j+1]; n++; } if (i0) { - b += b_mul*ri->data[i+1][j-1] - g_mul*ng[j-1]; + b += b_mul*rawData[i+1][j-1] - g_mul*ng[j-1]; n++; } if (idata[i+1][j+1] - g_mul*ng[j+1]; + b += b_mul*rawData[i+1][j+1] - g_mul*ng[j+1]; n++; } b = g_mul*cg[j] + b / n; @@ -262,20 +262,20 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (unsigned short* ar, unsig // linear R-G interp. horizontally int r; if (j==0) - r = g_mul*cg[0] + r_mul*ri->data[i][1] - g_mul*cg[1]; + r = g_mul*cg[0] + r_mul*rawData[i][1] - g_mul*cg[1]; else if (j==W-1) - r = g_mul*cg[W-1] + r_mul*ri->data[i][W-2] - g_mul*cg[W-2]; + r = g_mul*cg[W-1] + r_mul*rawData[i][W-2] - g_mul*cg[W-2]; else - r = g_mul*cg[j] + (r_mul*ri->data[i][j-1] - g_mul*cg[j-1] + r_mul*ri->data[i][j+1] - g_mul*cg[j+1]) / 2; + r = g_mul*cg[j] + (r_mul*rawData[i][j-1] - g_mul*cg[j-1] + r_mul*rawData[i][j+1] - g_mul*cg[j+1]) / 2; ar[jx] = CLIP(r); // linear B-G interp. vertically int b; if (i==0) - b = g_mul*ng[j] + b_mul*ri->data[1][j] - g_mul*cg[j]; + b = g_mul*ng[j] + b_mul*rawData[1][j] - g_mul*cg[j]; else if (i==H-1) - b = g_mul*pg[j] + b_mul*ri->data[H-2][j] - g_mul*cg[j]; + b = g_mul*pg[j] + b_mul*rawData[H-2][j] - g_mul*cg[j]; else - b = g_mul*cg[j] + (b_mul*ri->data[i-1][j] - g_mul*pg[j] + b_mul*ri->data[i+1][j] - g_mul*ng[j]) / 2; + b = g_mul*cg[j] + (b_mul*rawData[i-1][j] - g_mul*pg[j] + b_mul*rawData[i+1][j] - g_mul*ng[j]) / 2; ab[jx] = CLIP(b); } } @@ -285,24 +285,24 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (unsigned short* ar, unsig for (int j=x1, jx=0; jxdata[i][j]); + ab[jx] = CLIP(b_mul*rawData[i][j]); // blue: cross interpolation int r = 0; int n = 0; if (i>0 && j>0) { - r += r_mul*ri->data[i-1][j-1] - g_mul*pg[j-1]; + r += r_mul*rawData[i-1][j-1] - g_mul*pg[j-1]; n++; } if (i>0 && jdata[i-1][j+1] - g_mul*pg[j+1]; + r += r_mul*rawData[i-1][j+1] - g_mul*pg[j+1]; n++; } if (i0) { - r += r_mul*ri->data[i+1][j-1] - g_mul*ng[j-1]; + r += r_mul*rawData[i+1][j-1] - g_mul*ng[j-1]; n++; } if (idata[i+1][j+1] - g_mul*ng[j+1]; + r += r_mul*rawData[i+1][j+1] - g_mul*ng[j+1]; n++; } r = g_mul*cg[j] + r / n; @@ -313,20 +313,20 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (unsigned short* ar, unsig // linear B-G interp. horizontally int b; if (j==0) - b = g_mul*cg[0] + b_mul*ri->data[i][1] - g_mul*cg[1]; + b = g_mul*cg[0] + b_mul*rawData[i][1] - g_mul*cg[1]; else if (j==W-1) - b = g_mul*cg[W-1] + b_mul*ri->data[i][W-2] - g_mul*cg[W-2]; + b = g_mul*cg[W-1] + b_mul*rawData[i][W-2] - g_mul*cg[W-2]; else - b = g_mul*cg[j] + (b_mul*ri->data[i][j-1] - g_mul*cg[j-1] + b_mul*ri->data[i][j+1] - g_mul*cg[j+1]) / 2; + b = g_mul*cg[j] + (b_mul*rawData[i][j-1] - g_mul*cg[j-1] + b_mul*rawData[i][j+1] - g_mul*cg[j+1]) / 2; ab[jx] = CLIP(b); // linear R-G interp. vertically int r; if (i==0) - r = g_mul*ng[j] + r_mul*ri->data[1][j] - g_mul*cg[j]; + r = g_mul*ng[j] + r_mul*rawData[1][j] - g_mul*cg[j]; else if (i==H-1) - r = g_mul*pg[j] + r_mul*ri->data[H-2][j] - g_mul*cg[j]; + r = g_mul*pg[j] + r_mul*rawData[H-2][j] - g_mul*cg[j]; else - r = g_mul*cg[j] + (r_mul*ri->data[i-1][j] - g_mul*pg[j] + r_mul*ri->data[i+1][j] - g_mul*ng[j]) / 2; + r = g_mul*cg[j] + (r_mul*rawData[i-1][j] - g_mul*pg[j] + r_mul*rawData[i+1][j] - g_mul*ng[j]) / 2; ar[jx] = CLIP(r); } } diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index a27ae2bb7..56dc140ca 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -17,8 +17,9 @@ * along with RawTherapee. If not, see . */ #include +#include -int refreshmap[] = { +int refreshmap[rtengine::NUMOFEVENTS] = { ALL, // EvPhotoLoaded, ALL, // EvProfileLoaded, ALL, // EvProfileChanged, @@ -104,6 +105,8 @@ ALL, // EvProfileChangeNotification RETINEX, // EvShrHighQuality TRANSFORM, // EvPerspCorr EQUALIZER, // EvEqualizer -EQUALIZER // EvEqlEnabled +EQUALIZER, // EvEqlEnabled +DEMOSAIC, // EvDemosaic +DARKFRAME //EvPreProcess }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 962bbcf59..530b02d1b 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -21,6 +21,7 @@ #include + #define FIRST 65535 #define ALL 65535 #define TRANSFORM 127 @@ -31,6 +32,8 @@ #define SHARPENING 2 #define LUMADENOISE 2 #define WHITEBALANCE 255 +#define DEMOSAIC 511 +#define DARKFRAME 1023 #define COLORBOOST 1 #define COLORDENOISE 1 #define CROP 16384 @@ -39,6 +42,8 @@ #define EQUALIZER 3 #define NONE 0 +#define M_PREPROC 512 +#define M_RAW 256 #define M_INIT 128 #define M_TRANSFORM 64 #define M_BLURMAP 32 diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 71ff9a3a1..860d5c206 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -113,7 +113,6 @@ namespace rtengine { /** * This class represents an image loaded into the memory. It is the basis of further processing. - * In case of raw files the most time consuming operation, the demosaicing is already performed. * The embedded icc profile and metadata information can be obtained through this class, too. */ class InitialImage { @@ -137,7 +136,7 @@ namespace rtengine { virtual void decreaseRef () {} - /** Loads an image into the memory. If it is a raw file, is is partially demosaiced (the time consuming part is done) + /** Loads an image into the memory. * @param fname the name of the file * @param isRaw shall be true if it is a raw file * @param errorCode is a pointer to a variable that is set to nonzero if an error happened (output) diff --git a/rtengine/settings.h b/rtengine/settings.h index fe2fc8380..fac2557ca 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -25,18 +25,11 @@ namespace rtengine { class Settings { public: bool dualThreadEnabled; ///< If true, the image processing operations with utilize two processor cores (if possible) - std::string demosaicMethod; ///< The algorithm used for demosaicing. Can be "eahd", "hphd" or "vng4". - int colorCorrectionSteps; ///< The number of color correction steps applied right after the demosaicing Glib::ustring iccDirectory; ///< The directory containing the possible output icc profiles int colorimetricIntent; ///< Colorimetric intent used at color space conversions Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) bool verbose; - int dcb_iterations; // number of dcb iterations - bool dcb_enhance; // whether to do image refinment - bool ca_autocorrect; // Emil's CA auto correction - bool hotdeadpix_filt; // Emil's hot/dead pixel filter - int linenoise; //Emil's line denoise - int greenthresh; //Emil's Green equilibration + Glib::ustring darkFramesPath; ///< The default directory for dark frames /** Creates a new instance of Settings. * @return a pointer to the new Settings instance. */ diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index b64238e3b..4395c2c2f 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -75,13 +75,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p Image16* baseImg; PreviewProps pp (0, 0, fw, fh, 1); + imgsrc->preprocess( params.raw ); + imgsrc->demosaic( params.raw ); if (fabs(params.resize.scale-1.0)<1e-5) { baseImg = new Image16 (fw, fh); - imgsrc->getImage (currWB, tr, baseImg, pp, params.hlrecovery, params.icm); + imgsrc->getImage (currWB, tr, baseImg, pp, params.hlrecovery, params.icm, params.raw); } else { Image16* oorig = new Image16 (fw, fh); - imgsrc->getImage (currWB, tr, oorig, pp, params.hlrecovery, params.icm); + imgsrc->getImage (currWB, tr, oorig, pp, params.hlrecovery, params.icm, params.raw); fw *= params.resize.scale; fh *= params.resize.scale; baseImg = new Image16 (fw, fh); diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index beb547684..32bdca1b1 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -223,7 +223,7 @@ void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, Previ delete [] blue; } -void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp) { +void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw) { MyTime t1,t2; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 8565c5670..811d063ae 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -44,7 +44,7 @@ class StdImageSource : public ImageSource { ~StdImageSource (); int load (Glib::ustring fname); - void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp); + void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw); ColorTemp getWB () { return wb; } ColorTemp getAutoWB (); ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran); diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 5a96dfceb..c977dc8d4 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -23,7 +23,7 @@ set (BASESOURCEFILES thumbbrowserentrybase.cc batchqueueentry.cc batchqueue.cc lwbutton.cc lwbuttonset.cc batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc - profilestore.cc partialpastedlg.cc + profilestore.cc partialpastedlg.cc rawprocess.cc preprocess.cc equalizer.cc) if (WIN32) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index e2717a69a..5bc0f331f 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -24,6 +24,8 @@ #include #include +extern Options options; + FileBrowser::FileBrowser () : tbl(NULL) { @@ -56,6 +58,10 @@ FileBrowser::FileBrowser () pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p+1); p++; pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(selectDF = new Gtk::MenuItem ("Select Dark Frame...")), 0, 1, p, p+1); p++; + pmenu->attach (*(autoDF = new Gtk::MenuItem ("Auto Dark Frame")), 0, 1, p, p+1); p++; + pmenu->attach (*(thisIsDF = new Gtk::MenuItem ("This is a Dark Frame")), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*(copyprof = new Gtk::MenuItem (M("FILEBROWSER_COPYPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*(pasteprof = new Gtk::MenuItem (M("FILEBROWSER_PASTEPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*(partpasteprof = new Gtk::MenuItem (M("FILEBROWSER_PARTIALPASTEPROFILE"))), 0, 1, p, p+1); p++; @@ -83,7 +89,9 @@ FileBrowser::FileBrowser () develop->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), develop)); rename->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rename)); remove->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), remove)); - selall->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selall)); + selall->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selall)); + selectDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selectDF)); + autoDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), autoDF)); copyprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), copyprof)); pasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), pasteprof)); partpasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), partpasteprof)); @@ -288,7 +296,33 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) { queue_draw (); notifySelectionListener (); } - else if (m==copyprof) + else if (m==autoDF){ + for (int i=0; ithumbnail->getProcParams(); + pp.raw.df_autoselect= true; + pp.raw.dark_frame.clear(); + mselected[i]->thumbnail->setProcParams(pp,FILEBROWSER,false); + } + }else if (m==selectDF){ + if( mselected.size() > 0 ){ + rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams(); + Gtk::FileChooserDialog fc("Dark Frame",Gtk::FILE_CHOOSER_ACTION_OPEN ); + fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY); + if( pp.raw.dark_frame.empty()) + fc.set_current_folder( options.rtSettings.darkFramesPath ); + else + fc.set_filename( pp.raw.dark_frame ); + if( fc.run() == Gtk::RESPONSE_APPLY ){ + for (int i=0; ithumbnail->getProcParams(); + pp.raw.dark_frame= fc.get_filename(); + pp.raw.df_autoselect= false; + mselected[i]->thumbnail->setProcParams(pp,FILEBROWSER,false); + } + } + } + }else if (m==copyprof) copyProfile (); else if (m==pasteprof) pasteProfile (); diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index bfe22f934..822039293 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -58,6 +58,9 @@ class FileBrowser : public ThumbBrowserBase, public LWButtonListener { Gtk::MenuItem* remove; Gtk::MenuItem* open; Gtk::MenuItem* selall; + Gtk::MenuItem* selectDF; + Gtk::MenuItem* thisIsDF; + Gtk::MenuItem* autoDF; Gtk::MenuItem* copyprof; Gtk::MenuItem* pasteprof; Gtk::MenuItem* partpasteprof; diff --git a/rtgui/options.cc b/rtgui/options.cc index a56bdef83..0d6f6188a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -119,16 +119,7 @@ void Options::setDefaults () { baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); rtSettings.dualThreadEnabled = true; - rtSettings.demosaicMethod = "amaze";//Emil's code for AMaZE - rtSettings.ca_autocorrect = false;//Emil's CA correction - rtSettings.hotdeadpix_filt = true;//Emil's hot/dead pixel filter - - rtSettings.linenoise = 0;//Emil's line denoise - rtSettings.greenthresh = 0;//Emil's Green equilibration - - rtSettings.colorCorrectionSteps = 0; - rtSettings.dcb_iterations = 2; - rtSettings.dcb_enhance = true; + rtSettings.darkFramesPath = ""; rtSettings.iccDirectory = "/usr/share/color/icc"; rtSettings.colorimetricIntent = 1; rtSettings.monitorProfile = ""; @@ -178,6 +169,8 @@ if (keyFile.has_group ("General")) { if (keyFile.has_key ("General", "Language")) language = keyFile.get_string ("General", "Language"); if (keyFile.has_key ("General", "Theme")) theme = keyFile.get_string ("General", "Theme"); if (keyFile.has_key ("General", "FirstRun")) firstRun = keyFile.get_boolean ("General", "FirstRun"); + if( keyFile.has_key ("General", "DarkFramesPath")) rtSettings.darkFramesPath = keyFile.get_string("General", "DarkFramesPath"); + if( keyFile.has_key ("General", "Verbose")) rtSettings.verbose = keyFile.get_boolean ( "General", "Verbose"); } if (keyFile.has_group ("External Editor")) { @@ -262,16 +255,7 @@ if (keyFile.has_group ("GUI")) { if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); } -if (keyFile.has_group ("Algorithms")) { - if (keyFile.has_key ("Algorithms", "DemosaicMethod")) rtSettings.demosaicMethod = keyFile.get_string ("Algorithms", "DemosaicMethod"); - if (keyFile.has_key ("Algorithms", "ColorCorrection")) rtSettings.colorCorrectionSteps = keyFile.get_integer ("Algorithms", "ColorCorrection"); - if(keyFile.has_key("Algorithms", "DCBIterations")) rtSettings.dcb_iterations = keyFile.get_integer("Algorithms", "DCBIterations"); - if(keyFile.has_key("Algorithms", "DCBEnhance")) rtSettings.dcb_enhance = keyFile.get_boolean("Algorithms", "DCBEnhance"); - if(keyFile.has_key("Algorithms", "CACorrect")) rtSettings.ca_autocorrect = keyFile.get_boolean("Algorithms", "CACorrect");//Emil's CA autocorrect - if(keyFile.has_key("Algorithms", "HotDeadPixFilt")) rtSettings.hotdeadpix_filt = keyFile.get_boolean("Algorithms", "HotDeadPixFilt");//Emil's hot/dead pixel filter - if(keyFile.has_key("Algorithms", "LineDenoise")) rtSettings.linenoise = keyFile.get_integer("Algorithms", "LineDenoise");//Emil's line denoise - if(keyFile.has_key("Algorithms", "GreenEquil")) rtSettings.greenthresh = keyFile.get_integer("Algorithms", "GreenEquil");//Emil's Green equilibration -} + if (keyFile.has_group ("Crop Settings")) { if (keyFile.has_key ("Crop Settings", "DPI")) cropDPI = keyFile.get_integer ("Crop Settings", "DPI"); @@ -312,6 +296,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("General", "Theme", theme); keyFile.set_integer ("General", "Version", 290); keyFile.set_boolean ("General", "FirstRun", firstRun); + keyFile.set_string ("General", "DarkFramesPath", rtSettings.darkFramesPath); keyFile.set_integer ("External Editor", "EditorKind", editorToSendTo); keyFile.set_string ("External Editor", "GimpDir", gimpDir); @@ -390,15 +375,6 @@ int Options::saveToFile (Glib::ustring fname) { Glib::ArrayHandle crvopen = crvOpen; keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); - keyFile.set_string ("Algorithms", "DemosaicMethod", rtSettings.demosaicMethod); - keyFile.set_integer ("Algorithms", "ColorCorrection", rtSettings.colorCorrectionSteps); - keyFile.set_integer ("Algorithms", "DCBIterations", rtSettings.dcb_iterations); - keyFile.set_boolean ("Algorithms", "DCBEnhance", rtSettings.dcb_enhance); - keyFile.set_boolean ("Algorithms", "CACorrect", rtSettings.ca_autocorrect);//Emil's CA correction - keyFile.set_boolean ("Algorithms", "HotDeadPixFilt", rtSettings.hotdeadpix_filt);//Emil's hot/dead pixel filter - keyFile.set_integer ("Algorithms", "LineDenoise", rtSettings.linenoise);//Emil's line denoise - keyFile.set_integer ("Algorithms", "GreenEquil", rtSettings.greenthresh);//Emil's Green equilibration - keyFile.set_integer ("Crop Settings", "DPI", cropDPI); keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a0ca51c38..e6a4858d2 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -119,6 +119,10 @@ void ParamsEdited::set (bool v) { icm.gammaOnInput = v; icm.working = v; icm.output = v; + raw.ccSteps = v; + raw.dmethod = v; + raw.dcbIterations = v; + raw.dcbEnhance = v; equalizer.enabled = v; for(int i = 0; i < 8; i++) { @@ -231,6 +235,17 @@ void ParamsEdited::initFrom (const std::vector icm.gammaOnInput = icm.gammaOnInput && p.icm.gammaOnInput == other.icm.gammaOnInput; icm.working = icm.working && p.icm.working == other.icm.working; icm.output = icm.output && p.icm.output == other.icm.output; + raw.ccSteps = raw.ccSteps && p.raw.ccSteps == other.raw.ccSteps; + raw.dcbEnhance = raw.dcbEnhance && p.raw.dcb_enhance == other.raw.dcb_enhance; + raw.dcbIterations = raw.dcbIterations && p.raw.dcb_iterations == other.raw.dcb_iterations; + raw.dmethod = raw.dmethod && p.raw.dmethod == other.raw.dmethod; + raw.caCorrection = raw.caCorrection && p.raw.ca_autocorrect == other.raw.ca_autocorrect; + raw.darkFrame = raw.darkFrame && p.raw.dark_frame == other.raw.dark_frame; + raw.dfAuto = raw.dfAuto && p.raw.df_autoselect == other.raw.df_autoselect; + raw.greenEq = raw.greenEq && p.raw.greenthresh == other.raw.greenthresh; + raw.hotDeadPixel = raw.hotDeadPixel && p.raw.hotdeadpix_filt == other.raw.hotdeadpix_filt; + raw.linenoise = raw.linenoise && p.raw.linenoise == other.raw.linenoise; + equalizer.enabled = equalizer.enabled && p.equalizer.enabled == other.equalizer.enabled; for(int i = 0; i < 8; i++) { equalizer.c[i] = equalizer.c[i] && p.equalizer.c[i] == other.equalizer.c[i]; @@ -333,6 +348,16 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (icm.gammaOnInput) toEdit.icm.gammaOnInput = mods.icm.gammaOnInput; if (icm.working) toEdit.icm.working = mods.icm.working; if (icm.output) toEdit.icm.output = mods.icm.output; + if (raw.ccSteps) toEdit.raw.ccSteps = mods.raw.ccSteps; + if (raw.dmethod) toEdit.raw.dmethod = mods.raw.dmethod; + if (raw.dcbIterations) toEdit.raw.dcb_iterations = mods.raw.dcb_iterations; + if (raw.dcbEnhance) toEdit.raw.dcb_enhance = mods.raw.dcb_enhance; + if (raw.caCorrection) toEdit.raw.ca_autocorrect = mods.raw.ca_autocorrect; + if (raw.greenEq) toEdit.raw.greenthresh = mods.raw.greenthresh; + if (raw.hotDeadPixel) toEdit.raw.hotdeadpix_filt= mods.raw.hotdeadpix_filt; + if (raw.linenoise) toEdit.raw.linenoise = mods.raw.linenoise; + if (raw.darkFrame) toEdit.raw.dark_frame = mods.raw.dark_frame; + if (raw.dfAuto) toEdit.raw.df_autoselect= mods.raw.df_autoselect; if (equalizer.enabled) toEdit.equalizer.enabled = mods.equalizer.enabled; for(int i = 0; i < 8; i++) { if(equalizer.c[i]) toEdit.equalizer.c[i] = mods.equalizer.c[i]; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index c8dd43085..4feb33b28 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -222,6 +222,21 @@ class EqualizerParamsEdited { bool c[8]; }; +class RAWParamsEdited { + + public: + bool ccSteps; + bool dmethod; + bool dcbIterations; + bool dcbEnhance; + bool caCorrection; + bool greenEq; + bool hotDeadPixel; + bool linenoise; + bool darkFrame; + bool dfAuto; +}; + class ExifPairEdited { public: @@ -261,6 +276,7 @@ class ParamsEdited { ResizeParamsEdited resize; ColorManagementParamsEdited icm; EqualizerParamsEdited equalizer; + RAWParamsEdited raw; std::vector exif; std::vector iptc; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 166107801..e63f5b1a5 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -22,6 +22,8 @@ #include #include #include +#include +#include extern Options options; extern Glib::ustring argv0; @@ -251,81 +253,19 @@ Gtk::Widget* Preferences::getProcParamsPanel () { fdp->add (*vbdp); mvbpp->pack_start (*fdp, Gtk::PACK_SHRINK, 4); - Gtk::Frame* fdem = Gtk::manage (new Gtk::Frame (M("PREFERENCES_DEMOSAICINGALGO"))); - Gtk::VBox* fdb = Gtk::manage (new Gtk::VBox ()); - fdb->set_border_width (4); - fdem->add (*fdb); - Gtk::Label* dmlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_DMETHOD")+":")); - dmethod = Gtk::manage (new Gtk::ComboBoxText ()); - Gtk::HBox* hb11 = Gtk::manage (new Gtk::HBox ()); - hb11->pack_start (*dmlab, Gtk::PACK_SHRINK, 4); - hb11->pack_start (*dmethod); - dmethod->append_text ("EAHD"); - dmethod->append_text ("HPHD"); - dmethod->append_text ("VNG-4"); - //dmethod->append_text ("PPG"); - dmethod->append_text ("AMaZE");//Emil's code for AMaZE - dmethod->append_text ("DCB"); - dmethod->append_text ("AHD"); - Gtk::Label* cclab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FALSECOLOR")+":")); - ccSteps = Gtk::manage (new Gtk::SpinButton ()); - ccSteps->set_digits (0); - ccSteps->set_increments (1, 2); - ccSteps->set_range (0, 5); - Gtk::HBox* hb12 = Gtk::manage (new Gtk::HBox ()); - hb12->pack_start (*cclab, Gtk::PACK_SHRINK, 4); - hb12->pack_start (*ccSteps); - - dcbIterationsLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_DCBITERATIONS")+":")); - dcbIterations = Gtk::manage(new Gtk::SpinButton ()); - dcbIterations->set_digits(0); - dcbIterations->set_increments(1, 2); - dcbIterations->set_range(0, 10); - Gtk::HBox* hb13 = Gtk::manage(new Gtk::HBox()); - hb13->pack_start (*dcbIterationsLabel, Gtk::PACK_SHRINK, 4); - hb13->pack_start (*dcbIterations); - - dcbEnhance = Gtk::manage(new Gtk::CheckButton((M("PREFERENCES_DCBENHANCE")))); - - caAutoCorrect = Gtk::manage(new Gtk::CheckButton((M("PREFERENCES_CACORRECTION"))));//Emil's CA correction - HotDeadPixFilt = Gtk::manage(new Gtk::CheckButton((M("PREFERENCES_HOTDEADPIXFILT"))));//Emil's hot/dead pixel filter - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //Emil's line denoise - LineDenoiseLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LINEDENOISE")+":")); - LineDenoise = Gtk::manage(new Gtk::SpinButton ()); - LineDenoise->set_digits(0); - LineDenoise->set_increments(1, 10); - LineDenoise->set_range(0, 1000); - Gtk::HBox* hb14 = Gtk::manage(new Gtk::HBox()); - hb14->pack_start (*LineDenoiseLabel, Gtk::PACK_SHRINK, 4); - hb14->pack_start (*LineDenoise); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //Emil's Green equilibration - GreenEquilLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_GREENEQUIL")+":")); - GreenEquil = Gtk::manage(new Gtk::SpinButton ()); - GreenEquil->set_digits(0); - GreenEquil->set_increments(1, 10); - GreenEquil->set_range(0, 100); - Gtk::HBox* hb15 = Gtk::manage(new Gtk::HBox()); - hb15->pack_start (*GreenEquilLabel, Gtk::PACK_SHRINK, 4); - hb15->pack_start (*GreenEquil); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - fdb->pack_start (*hb11, Gtk::PACK_SHRINK, 4); - fdb->pack_start (*hb12, Gtk::PACK_SHRINK, 4); - fdb->pack_start (*hb13, Gtk::PACK_SHRINK, 4); - fdb->pack_start (*dcbEnhance, Gtk::PACK_SHRINK, 4); - fdb->pack_start (*caAutoCorrect, Gtk::PACK_SHRINK, 4);//Emil's CA correction - fdb->pack_start (*HotDeadPixFilt, Gtk::PACK_SHRINK, 4);//Emil's hot/dead pixel filter - fdb->pack_start (*hb14, Gtk::PACK_SHRINK, 4);//Emil's line denoise - fdb->pack_start (*hb15, Gtk::PACK_SHRINK, 4);//Emil's Green equlibration - - mvbpp->pack_start (*fdem, Gtk::PACK_SHRINK, 4); + Gtk::Frame* fdf = Gtk::manage (new Gtk::Frame ("Dark Frame") ); + Gtk::HBox* hb42 = Gtk::manage (new Gtk::HBox ()); + darkFrameDir = Gtk::manage(new Gtk::FileChooserButton( "Dark frames directory", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label *dfLab = Gtk::manage(new Gtk::Label("Dark Frames directory")); + hb42->pack_start(*dfLab , Gtk::PACK_SHRINK, 4 ); + hb42->pack_start(*darkFrameDir); + dfLabel = Gtk::manage(new Gtk::Label("Found:")); + Gtk::VBox* vbdf = Gtk::manage (new Gtk::VBox ()); + vbdf->pack_start( *hb42, Gtk::PACK_SHRINK, 4); + vbdf->pack_start( *dfLabel, Gtk::PACK_SHRINK, 4 ); + fdf->add( *vbdf ); + mvbpp->pack_start ( *fdf , Gtk::PACK_SHRINK, 4); mvbpp->set_border_width (4); - // drlab->set_size_request (drimg->get_width(), -1); std::vector pnames; if (options.multiUser) @@ -336,7 +276,7 @@ Gtk::Widget* Preferences::getProcParamsPanel () { iprofiles->append_text (pnames[i]); } - dmconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &Preferences::dmethodChanged) ); + dfconn = darkFrameDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); return mvbpp; } @@ -730,31 +670,9 @@ void Preferences::storePreferences () { moptions.editorToSendTo = 3; - moptions.rtSettings.colorCorrectionSteps= (int)ccSteps->get_value (); moptions.rtSettings.monitorProfile = monProfile->get_filename (); moptions.rtSettings.iccDirectory = iccDir->get_filename (); moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); - if (dmethod->get_active_row_number()==0) - moptions.rtSettings.demosaicMethod = "eahd"; - else if (dmethod->get_active_row_number()==1) - moptions.rtSettings.demosaicMethod = "hphd"; - else if (dmethod->get_active_row_number()==2) - moptions.rtSettings.demosaicMethod = "vng4"; - //else if (dmethod->get_active_row_number()==3) - // moptions.rtSettings.demosaicMethod = "ppg"; - else if (dmethod->get_active_row_number()==3) - moptions.rtSettings.demosaicMethod = "amaze";//Emil's code for AMaZE - else if (dmethod->get_active_row_number()==4) - moptions.rtSettings.demosaicMethod = "dcb"; - else if (dmethod->get_active_row_number()==5) - moptions.rtSettings.demosaicMethod = "ahd"; - moptions.rtSettings.dcb_iterations=(int)dcbIterations->get_value(); - moptions.rtSettings.dcb_enhance=dcbEnhance->get_active(); - moptions.rtSettings.ca_autocorrect=caAutoCorrect->get_active();//Emil's CA correction - moptions.rtSettings.hotdeadpix_filt=HotDeadPixFilt->get_active();//Emil's hot/dead pixel filter - moptions.rtSettings.linenoise=(int)LineDenoise->get_value();//Emil's line denoise - moptions.rtSettings.greenthresh=(int)GreenEquil->get_value();//Emil's Green equilibration - if (sdcurrent->get_active ()) moptions.startupDir = STARTUPDIR_CURRENT; @@ -790,6 +708,8 @@ void Preferences::storePreferences () { moptions.saveParamsCache = saveParamsCache->get_active (); moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); + moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); + int i = 0; moptions.baBehav.resize (ADDSET_PARAM_NUM); for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) @@ -799,13 +719,12 @@ void Preferences::storePreferences () { void Preferences::fillPreferences () { - dmconn.block (true); tconn.block (true); + dfconn.block (true); rprofiles->set_active_text (moptions.defProfRaw); iprofiles->set_active_text (moptions.defProfImg); dateformat->set_text (moptions.dateFormat); - ccSteps->set_value (moptions.rtSettings.colorCorrectionSteps); if (Glib::file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) monProfile->set_filename (moptions.rtSettings.monitorProfile); if (Glib::file_test (moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) @@ -834,32 +753,6 @@ void Preferences::fillPreferences () { #endif editorToSendTo->set_text (moptions.customEditorProg); - if (moptions.rtSettings.demosaicMethod=="eahd") - dmethod->set_active (0); - else if (moptions.rtSettings.demosaicMethod=="hphd") - dmethod->set_active (1); - else if (moptions.rtSettings.demosaicMethod=="vng4") - dmethod->set_active (2); - //else if (moptions.rtSettings.demosaicMethod=="ppg") - // dmethod->set_active (3); - else if (moptions.rtSettings.demosaicMethod=="amaze")//Emil's code for AMaZE - dmethod->set_active (3); - else if (moptions.rtSettings.demosaicMethod=="dcb") - dmethod->set_active (4); - else if (moptions.rtSettings.demosaicMethod=="ahd") - dmethod->set_active (5); - dcbEnhance->set_active(moptions.rtSettings.dcb_enhance); - dcbIterations->set_value(moptions.rtSettings.dcb_iterations); - dcbEnhance->set_sensitive(moptions.rtSettings.demosaicMethod=="dcb"); - dcbIterations->set_sensitive(moptions.rtSettings.demosaicMethod=="dcb"); - dcbIterationsLabel->set_sensitive(moptions.rtSettings.demosaicMethod=="dcb"); - caAutoCorrect->set_active(moptions.rtSettings.ca_autocorrect);//Emil's CA Auto Correction - HotDeadPixFilt->set_active(moptions.rtSettings.hotdeadpix_filt);//Emil's hot/dead pixel filter - LineDenoise->set_value(moptions.rtSettings.linenoise);//Emil's line denoise - GreenEquil->set_value(moptions.rtSettings.greenthresh);//Emil's Green equilibration - - - if (moptions.startupDir==STARTUPDIR_CURRENT) sdcurrent->set_active (); else if (moptions.startupDir==STARTUPDIR_LAST) @@ -893,6 +786,9 @@ void Preferences::fillPreferences () { saveParamsCache->set_active (moptions.saveParamsCache); loadParamsPreference->set_active (moptions.paramsLoadLocation); + darkFrameDir->set_filename( moptions.rtSettings.darkFramesPath ); + updateDFinfos(); + addc.block (true); setc.block (true); if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { @@ -907,9 +803,8 @@ void Preferences::fillPreferences () { } addc.block (false); setc.block (false); - - dmconn.block (false); tconn.block (false); + dfconn.block (false); } void Preferences::loadPressed () { @@ -952,26 +847,6 @@ void Preferences::selectStartupDir () { startupdir->set_text (dialog.get_filename()); } -void Preferences::dmethodChanged () { - - if (dmethod->get_active_row_number()==0) - ccSteps->set_value (2); - else if (dmethod->get_active_row_number()==1) - ccSteps->set_value (1); - else if (dmethod->get_active_row_number()==2) - ccSteps->set_value (2); - - if (dmethod->get_active_row_number()==4) { - dcbEnhance->set_sensitive(true); - dcbIterations->set_sensitive(true); - dcbIterationsLabel->set_sensitive(true); - } else { - dcbEnhance->set_sensitive(false); - dcbIterations->set_sensitive(false); - dcbIterationsLabel->set_sensitive(false); - } -} - void Preferences::aboutPressed () { Splash* splash = new Splash (-1); @@ -1040,3 +915,19 @@ void Preferences::clearAllPressed () { md.hide (); } +void Preferences::darkFrameChanged () +{ + Glib::ustring s(darkFrameDir->get_filename()); + if( s.compare( rtengine::dfm.getPathname()) !=0 ){ + rtengine::dfm.init( s ); + updateDFinfos(); + } +} +void Preferences::updateDFinfos() +{ + int t1,t2; + rtengine::dfm.getStat(t1,t2); + std::ostringstream s; + s << "Found: "<< t1 << " shots, " << t2 << " templates"; + dfLabel->set_text(s.str()); +} diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 646202017..83072cd78 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -52,7 +52,6 @@ class Preferences : public Gtk::Dialog { protected: Gtk::ComboBoxText* rprofiles; Gtk::ComboBoxText* iprofiles; - Gtk::ComboBoxText* dmethod; Gtk::ComboBoxText* languages; Gtk::Entry* dateformat; Gtk::Entry* startupdir; @@ -66,22 +65,12 @@ class Preferences : public Gtk::Dialog { Gtk::RadioButton* edGimp; Gtk::RadioButton* edPS; Gtk::RadioButton* edOther; - + Gtk::FileChooserButton* darkFrameDir; + Gtk::Label *dfLabel; Gtk::CheckButton* showDateTime; Gtk::CheckButton* showBasicExif; - Gtk::SpinButton* ccSteps; - Gtk::Label* dcbIterationsLabel; - Gtk::SpinButton* dcbIterations; - Gtk::CheckButton* dcbEnhance; - Gtk::CheckButton* caAutoCorrect;//Emil's CA correction - Gtk::CheckButton* HotDeadPixFilt;//Emil's hot/dead pixel filter - Gtk::Label* LineDenoiseLabel;//Emil's line denoise - Gtk::SpinButton* LineDenoise; - Gtk::Label* GreenEquilLabel;//Emil's Green equilibration - Gtk::SpinButton* GreenEquil; - Gtk::FileChooserButton* iccDir; Gtk::FileChooserButton* monProfile; @@ -110,13 +99,12 @@ class Preferences : public Gtk::Dialog { Gtk::ComboBoxText* loadParamsPreference; Options moptions; - sigc::connection dmconn, tconn, addc, setc; + sigc::connection tconn, addc, setc, dfconn; void fillPreferences (); void storePreferences (); void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); - void dmethodChanged (); - + void updateDFinfos (); void themeChanged (); void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set); @@ -139,7 +127,7 @@ class Preferences : public Gtk::Dialog { void selectStartupDir (); void addExtPressed (); void delExtPressed (); - + void darkFrameChanged (); void clearProfilesPressed (); void clearThumbImagesPressed (); void clearAllPressed (); diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc new file mode 100644 index 000000000..5d64d6362 --- /dev/null +++ b/rtgui/preprocess.cc @@ -0,0 +1,220 @@ +/* + * 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 +using namespace rtengine; +using namespace rtengine::procparams; + +PreProcess::PreProcess () +{ + hbdf = Gtk::manage(new Gtk::HBox()); + darkFrameFile = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_DARKFRAME"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + dfLabel = Gtk::manage(new Gtk::Label("Dark Frame")); + btnReset = Gtk::manage(new Gtk::Button()); + btnReset->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-cancel"), Gtk::ICON_SIZE_BUTTON))); + hbdf->pack_start(*dfLabel, Gtk::PACK_SHRINK, 4); + hbdf->pack_start(*darkFrameFile); + hbdf->pack_start(*btnReset, Gtk::PACK_SHRINK, 4); + dfAuto = Gtk::manage(new Gtk::CheckButton(("Auto selection"))); + caAutocorrect = Gtk::manage(new Gtk::CheckButton((M("PREFERENCES_CACORRECTION")))); + hotDeadPixel = Gtk::manage(new Gtk::CheckButton((M("PREFERENCES_HOTDEADPIXFILT")))); + + lineDenoise = Gtk::manage(new Adjuster (M("PREFERENCES_LINEDENOISE"),0,30,1,0)); + lineDenoise->setAdjusterListener (this); + lineDenoise->show(); + + greenEqThreshold = Gtk::manage(new Adjuster (M("PREFERENCES_GREENEQUIL"),0,100,1,0)); + greenEqThreshold->setAdjusterListener (this); + greenEqThreshold->show(); + + pack_start( *hbdf, Gtk::PACK_SHRINK, 4); + pack_start( *dfAuto, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage (new Gtk::HSeparator())); + pack_start( *hotDeadPixel, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage (new Gtk::HSeparator())); + pack_start( *caAutocorrect, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage (new Gtk::HSeparator())); + pack_start( *lineDenoise, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage (new Gtk::HSeparator())); + pack_start( *greenEqThreshold, Gtk::PACK_SHRINK, 4); + + caacsconn = caAutocorrect->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::caCorrectionChanged), true); + dfautoconn = dfAuto->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::dfAutoChanged), true); + hdpixelconn = hotDeadPixel->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::hotDeadPixelChanged), true); + dfFile = darkFrameFile->signal_file_set().connect ( sigc::mem_fun(*this, &PreProcess::darkFrameChanged), true); + btnReset->signal_clicked().connect( sigc::mem_fun(*this, &PreProcess::darkFrameReset), true ); +} + + +void PreProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + caacsconn.block (true); + dfautoconn.block(true); + hdpixelconn.block (true); + + if(pedited ){ + dfAuto->set_inconsistent(!pedited->raw.dfAuto ); + caAutocorrect->set_inconsistent(!pedited->raw.caCorrection); + hotDeadPixel->set_inconsistent (!pedited->raw.hotDeadPixel); + lineDenoise->setEditedState( pedited->raw.linenoise ? Edited : UnEdited ); + greenEqThreshold->setEditedState( pedited->raw.greenEq ? Edited : UnEdited ); + } + + if (Glib::file_test (pp->raw.dark_frame, Glib::FILE_TEST_EXISTS)) + darkFrameFile->set_filename (pp->raw.dark_frame); + else if( !options.rtSettings.darkFramesPath.empty() ) + darkFrameFile->set_current_folder( options.rtSettings.darkFramesPath ); + + lastCA = pp->raw.ca_autocorrect; + lastHot = pp->raw.hotdeadpix_filt; + lastDFauto = pp->raw.df_autoselect; + + dfAuto->set_active( pp->raw.df_autoselect ); + caAutocorrect->set_active(pp->raw.ca_autocorrect); + hotDeadPixel->set_active (pp->raw.hotdeadpix_filt); + lineDenoise->setValue (pp->raw.linenoise); + greenEqThreshold->setValue (pp->raw.greenthresh); + + dfChanged = false; + + + caacsconn.block (false); + dfautoconn.block(false); + hdpixelconn.block (false); + + enableListener (); +} + +void PreProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.dark_frame = darkFrameFile->get_filename(); + pp->raw.df_autoselect = dfAuto->get_active(); + pp->raw.ca_autocorrect = caAutocorrect->get_active(); + pp->raw.hotdeadpix_filt = hotDeadPixel->get_active(); + pp->raw.linenoise = (int)lineDenoise->getValue(); + pp->raw.greenthresh = (int)greenEqThreshold->getValue(); + + if (pedited) { + pedited->raw.darkFrame = dfChanged; + pedited->raw.dfAuto = !dfAuto->get_inconsistent(); + pedited->raw.linenoise = lineDenoise->getEditedState (); + pedited->raw.greenEq= greenEqThreshold->getEditedState (); + pedited->raw.caCorrection = !caAutocorrect->get_inconsistent(); + pedited->raw.hotDeadPixel = !hotDeadPixel->get_inconsistent(); + } +} + +void PreProcess::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("params") ); +} + +void PreProcess::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + lineDenoise->showEditedCB (); + greenEqThreshold->showEditedCB (); +} + +void PreProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + lineDenoise->setDefault( defParams->raw.linenoise); + greenEqThreshold->setDefault (defParams->raw.greenthresh); + if (pedited) { + lineDenoise->setDefaultEditedState( pedited->raw.linenoise ? Edited : UnEdited); + greenEqThreshold->setDefaultEditedState(pedited->raw.greenEq ? Edited : UnEdited); + }else{ + lineDenoise->setDefaultEditedState( Irrelevant ); + greenEqThreshold->setDefaultEditedState(Irrelevant ); + } +} + +void PreProcess::caCorrectionChanged() +{ + if (batchMode) { + if (caAutocorrect->get_inconsistent()) { + caAutocorrect->set_inconsistent (false); + caacsconn.block (true); + caAutocorrect->set_active (false); + caacsconn.block (false); + } + else if (lastCA) + caAutocorrect->set_inconsistent (true); + + lastCA = caAutocorrect->get_active (); + } + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("CA autocorrection ")+ (caAutocorrect->get_active()?"ON":"OFF") ); +} + +void PreProcess::dfAutoChanged() +{ + if (batchMode) { + if (dfAuto->get_inconsistent()) { + dfAuto->set_inconsistent (false); + dfautoconn.block (true); + dfAuto->set_active (false); + dfautoconn.block (false); + } + else if (lastDFauto) + dfAuto->set_inconsistent (true); + + lastDFauto = dfAuto->get_active (); + } + hbdf->set_sensitive( !dfAuto->get_active() ); + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("Dark Frame autoselection")+ (dfAuto->get_active()?"ON":"OFF") ); +} + +void PreProcess::hotDeadPixelChanged () +{ + if (batchMode) { + if (hotDeadPixel->get_inconsistent()) { + hotDeadPixel->set_inconsistent (false); + hdpixelconn.block (true); + hotDeadPixel->set_active (false); + hdpixelconn.block (false); + } + else if (lastHot) + hotDeadPixel->set_inconsistent (true); + + lastHot = hotDeadPixel->get_active (); + } + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("Hot Dead Pixel ")+(hotDeadPixel->get_active()?"ON":"OFF") ); +} +void PreProcess::darkFrameChanged() +{ + dfChanged=true; + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("Dark Framet set to ")+darkFrameFile->get_filename()); +} + +void PreProcess::darkFrameReset() +{ + dfChanged=true; + darkFrameFile->set_current_name(""); + darkFrameFile->set_filename (""); + if (listener) + listener->panelChanged (EvPreProcess, Glib::ustring("Dark Framet reset")); + +} diff --git a/rtgui/preprocess.h b/rtgui/preprocess.h new file mode 100644 index 000000000..edf6fbdad --- /dev/null +++ b/rtgui/preprocess.h @@ -0,0 +1,63 @@ +/* + * 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 . + */ +#ifndef _PREPROCESS_H_ +#define _PREPROCESS_H_ + +#include +#include +#include + + +class PreProcess : public Gtk::VBox, public AdjusterListener, public ToolPanel{ + + protected: + + Gtk::ComboBoxText* darkFrameMethod; + Gtk::FileChooserButton *darkFrameFile; + Gtk::HBox *hbdf; + Gtk::Button *btnReset; + Gtk::Label *dfLabel; + bool dfChanged; + + Adjuster* lineDenoise; + Adjuster* greenEqThreshold; + Gtk::CheckButton* caAutocorrect; + Gtk::CheckButton* hotDeadPixel; + Gtk::CheckButton* dfAuto; + bool lastCA,lastHot,lastDFauto; + + sigc::connection caacsconn,dfautoconn,hdpixelconn,dfFile; + public: + + PreProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void adjusterChanged (Adjuster* a, double newval); + void caCorrectionChanged(); + void hotDeadPixelChanged(); + void darkFrameChanged(); + void darkFrameReset(); + void dfAutoChanged(); +}; + +#endif diff --git a/rtgui/rawprocess.cc b/rtgui/rawprocess.cc new file mode 100644 index 000000000..8ef48e259 --- /dev/null +++ b/rtgui/rawprocess.cc @@ -0,0 +1,181 @@ +/* + * 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 +using namespace rtengine; +using namespace rtengine::procparams; + +RawProcess::RawProcess () +{ + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("PREFERENCES_DMETHOD") +": "))); + dmethod = Gtk::manage (new Gtk::ComboBoxText ()); + for( size_t i=0; i< procparams::RAWParams::numMethods;i++) + dmethod->append_text(procparams::RAWParams::methodstring[i]); + + dmethod->set_active(0); + hb1->pack_end (*dmethod); + pack_start( *hb1, Gtk::PACK_SHRINK, 4); + + dcbOptions = Gtk::manage (new Gtk::VBox ()); + dcbOptions->set_border_width(4); + + dcbIterations = Gtk::manage (new Adjuster (M("PREFERENCES_DCBITERATIONS"),0,5,1,2)); + dcbIterations ->setAdjusterListener (this); + dcbIterations ->show(); + dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("PREFERENCES_DCBENHANCE"))); + dcbOptions->pack_start(*dcbIterations); + dcbOptions->pack_start(*dcbEnhance); + pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 4 ); + + ccOptions = Gtk::manage (new Gtk::VBox ()); + ccOptions->set_border_width(4); + ccSteps = Gtk::manage (new Adjuster (M("PREFERENCES_FALSECOLOR"),0,5,1,2 )); + ccSteps->setAdjusterListener (this); + ccSteps->show(); + pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + + methodconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &RawProcess::methodChanged) ); + dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::dcbEnhanceChanged), true); +} + + +void RawProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + methodconn.block (true); + dcbEnhconn.block (true); + + dmethod->set_active(procparams::RAWParams::numMethods); + for( size_t i=0; i< procparams::RAWParams::numMethods;i++) + if( pp->raw.dmethod == procparams::RAWParams::methodstring[i]){ + dmethod->set_active(i); + break; + } + + dcbIterations->setValue (pp->raw.dcb_iterations); + dcbEnhance->set_active(pp->raw.dcb_enhance); + ccSteps->setValue (pp->raw.ccSteps); + if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::dcb]) + dcbOptions->show(); + else + dcbOptions->hide(); + + if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::eahd] || + pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::hphd] || + pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::vng4]) + ccOptions->show(); + else + ccOptions->hide(); + + lastDCBen = pp->raw.dcb_enhance; + + if(pedited ){ + ccSteps->setEditedState (pedited->raw.ccSteps ? Edited : UnEdited); + dcbIterations->setEditedState ( pedited->raw.dcbIterations ? Edited : UnEdited); + dcbEnhance->set_inconsistent(!pedited->raw.dcbEnhance); + if( !pedited->raw.dmethod ) + dmethod->set_active(procparams::RAWParams::numMethods); // No name + } + + methodconn.block (false); + dcbEnhconn.block (false); + enableListener (); +} + +void RawProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.ccSteps = (int)ccSteps->getValue(); + pp->raw.dcb_iterations = (int)dcbIterations->getValue(); + pp->raw.dcb_enhance = dcbEnhance->get_active(); + + if( dmethod->get_active_row_number() < procparams::RAWParams::numMethods) + pp->raw.dmethod = procparams::RAWParams::methodstring[dmethod->get_active_row_number()]; + + if (pedited) { + pedited->raw.ccSteps = ccSteps->getEditedState (); + pedited->raw.dmethod = dmethod->get_active_row_number() != procparams::RAWParams::numMethods; + pedited->raw.dcbIterations = dcbIterations->getEditedState (); + pedited->raw.dcbEnhance = !dcbEnhance->get_inconsistent(); + } +} + +void RawProcess::setBatchMode(bool batchMode) +{ + dmethod->set_active(procparams::RAWParams::numMethods); // No name + dcbOptions->hide(); + ToolPanel::setBatchMode (batchMode); + ccSteps->showEditedCB (); + dcbIterations->showEditedCB (); +} + +void RawProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + dcbIterations->setDefault( defParams->raw.dcb_iterations); + ccSteps->setDefault (defParams->raw.ccSteps); + if (pedited) { + dcbIterations->setDefaultEditedState( pedited->raw.dcbIterations ? Edited : UnEdited); + ccSteps->setDefaultEditedState(pedited->raw.ccSteps ? Edited : UnEdited); + }else{ + dcbIterations->setDefaultEditedState( Irrelevant ); + ccSteps->setDefaultEditedState(Irrelevant ); + } +} + +void RawProcess::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) + listener->panelChanged (EvDemosaic, Glib::ustring("params") ); +} + +void RawProcess::methodChanged () +{ + int curSelection = dmethod->get_active_row_number(); + if ( curSelection == procparams::RAWParams::dcb){ + dcbOptions->show(); + }else{ + dcbOptions->hide(); + } + Glib::ustring s=""; + if( curSelection>=0 && curSelection < procparams::RAWParams::numMethods) + s = procparams::RAWParams::methodstring[curSelection]; + + if (listener) + listener->panelChanged (EvDemosaic, Glib::ustring(M("PREFERENCES_DMETHOD"))+ "="+ s); +} + +void RawProcess::dcbEnhanceChanged () +{ + if (batchMode) { + if (dcbEnhance->get_inconsistent()) { + dcbEnhance->set_inconsistent (false); + dcbEnhconn.block (true); + dcbEnhance->set_active (false); + dcbEnhconn.block (false); + } + else if (lastDCBen) + dcbEnhance->set_inconsistent (true); + + lastDCBen = dcbEnhance->get_active (); + } + if (listener) + listener->panelChanged (EvDemosaic, Glib::ustring("params") ); +} diff --git a/rtgui/rawprocess.h b/rtgui/rawprocess.h new file mode 100644 index 000000000..e3eeab49d --- /dev/null +++ b/rtgui/rawprocess.h @@ -0,0 +1,55 @@ +/* + * 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 . + */ +#ifndef _RAWPROCESS_H_ +#define _RAWPROCESS_H_ + +#include +#include +#include + + +class RawProcess : public Gtk::VBox, public AdjusterListener, public ToolPanel{ + + protected: + + Gtk::ComboBoxText* dmethod; + Gtk::Label* methodl; + Adjuster* ccSteps; + Gtk::VBox *dcbOptions; + Gtk::VBox *ccOptions; + Adjuster* dcbIterations; + Gtk::CheckButton* dcbEnhance; + + bool lastDCBen; + sigc::connection methodconn,dcbEnhconn; + public: + + RawProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void methodChanged (); + void adjusterChanged (Adjuster* a, double newval); + void dcbEnhanceChanged(); +}; + +#endif diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index f01cc2105..5ac0585ba 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -29,6 +29,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { detailsPanel = Gtk::manage (new Gtk::VBox ()); colorPanel = Gtk::manage (new Gtk::VBox ()); transformPanel = Gtk::manage (new Gtk::VBox ()); + rawPanel = Gtk::manage (new Gtk::VBox ()); coarse = Gtk::manage (new CoarsePanel ()); curve = Gtk::manage (new ToneCurve ()); @@ -54,6 +55,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { exifpanel = Gtk::manage (new ExifPanel ()); iptcpanel = Gtk::manage (new IPTCPanel ()); equalizer = Gtk::manage (new Equalizer ()); + rawprocess = Gtk::manage (new RawProcess ()); + preprocess = Gtk::manage (new PreProcess ()); addPanel (colorPanel, whitebalance, M("TP_WBALANCE_LABEL")); toolPanels.push_back (whitebalance); addPanel (exposurePanel, curve, M("TP_EXPOSURE_LABEL")); toolPanels.push_back (curve); @@ -76,6 +79,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (lensgeom->getPackBox(), cacorrection, M("TP_CACORRECTION_LABEL")); toolPanels.push_back (cacorrection); addPanel (lensgeom->getPackBox(), vignetting, M("TP_VIGNETTING_LABEL")); toolPanels.push_back (vignetting); addPanel (colorPanel, icm, M("TP_ICM_LABEL")); toolPanels.push_back (icm); + addPanel (rawPanel, rawprocess, "Demosaicing"); toolPanels.push_back (rawprocess); + addPanel (rawPanel, preprocess, "Pre-processing"); toolPanels.push_back (preprocess); toolPanels.push_back (coarse); toolPanels.push_back (exifpanel); @@ -91,20 +96,24 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { Gtk::ScrolledWindow* detailsPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); Gtk::ScrolledWindow* colorPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); Gtk::ScrolledWindow* transformPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); + Gtk::ScrolledWindow* rawPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); exposurePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); detailsPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); colorPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); transformPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + rawPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); exposurePanelSW->add (*exposurePanel); detailsPanelSW->add (*detailsPanel); colorPanelSW->add (*colorPanel); transformPanelSW->add (*transformPanel); + rawPanelSW->add (*rawPanel); toolPanelNotebook->append_page (*exposurePanelSW, M("MAIN_TAB_EXPOSURE")); toolPanelNotebook->append_page (*detailsPanelSW, M("MAIN_TAB_DETAIL")); toolPanelNotebook->append_page (*colorPanelSW, M("MAIN_TAB_COLOR")); toolPanelNotebook->append_page (*transformPanelSW, M("MAIN_TAB_TRANSFORM")); + toolPanelNotebook->append_page (*rawPanelSW, "RAW"); toolPanelNotebook->append_page (*metadataPanel, M("MAIN_TAB_METADATA")); toolPanelNotebook->set_current_page (0); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 6407b4a47..9eb34255f 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -52,7 +52,8 @@ #include #include #include - +#include +#include class ImageEditorCoordinator; @@ -88,6 +89,8 @@ class ToolPanelCoordinator : public ToolPanelListener, Sharpening* sharpening; LCurve* lcurve; Equalizer * equalizer; + RawProcess* rawprocess; + PreProcess* preprocess; std::vector paramcListeners; @@ -98,6 +101,7 @@ class ToolPanelCoordinator : public ToolPanelListener, Gtk::VBox* detailsPanel; Gtk::VBox* colorPanel; Gtk::VBox* transformPanel; + Gtk::VBox* rawPanel; Gtk::Notebook* metadataPanel; ExifPanel* exifpanel; IPTCPanel* iptcpanel;