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;