diff --git a/CMakeLists.txt b/CMakeLists.txt index cc81a96e0..26f27f275 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ option (AUTOMATED_BUILD_SYSTEM "TRUE if built by an automate" OFF) option (BUILD_SHARED "Build rawtherapee with shared libraries" OFF) option (WITH_RAWZOR "Build with Rawzor support" OFF) +option (WITH_BZIP "Build with Bzip2 support" ON) option (WITH_MYFILE_MMAP "Build using memory mapped file" ON) option (OPTION_OMP "Build with OpenMP support" ON) @@ -287,6 +288,16 @@ if (WITH_RAWZOR) endif (WIN32) endif (WITH_RAWZOR) +# link witz bzip +if (WITH_BZIP) + find_package(BZip2) + if (BZIP2_FOUND) + add_definitions (-DBZIP_SUPPORT) + set (EXTRA_INCDIR ${EXTRA_LIB} ${BZIP2_INCLUDE_DIR}) + set (EXTRA_LIB ${EXTRA_LIB} ${BZIP2_LIBRARIES}) + endif (BZIP2_FOUND) +endif (WITH_BZIP) + if (WITH_MYFILE_MMAP) add_definitions (-DMYFILE_MMAP) endif (WITH_MYFILE_MMAP) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index c1bdf7028..9dd086ae3 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -40,6 +40,8 @@ CURVEEDITOR_SHADOWS;Schatten CURVEEDITOR_TOOLTIPLINEAR;Kurve zurücksetzen (Linear) CURVEEDITOR_TOOLTIPLOAD;Kurve aus Datei laden CURVEEDITOR_TOOLTIPSAVE;Kurve speichern +CURVEEDITOR_TOOLTIPCOPY;Kurve in Zwischenablage kopieren +CURVEEDITOR_TOOLTIPPASTE;Kurve aus Zwischenablage einfügen CURVEEDITOR_TYPE;Typ EDITWINDOW_TITLE;Bildbearbeitung EXIFFILTER_APERTURE;Blende diff --git a/rtdata/languages/default b/rtdata/languages/default index 7f8cbf567..2369a7930 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -25,6 +25,8 @@ CURVEEDITOR_SHADOWS;Shadows CURVEEDITOR_TOOLTIPLINEAR;Reset curve to linear CURVEEDITOR_TOOLTIPLOAD;Load a curve from file CURVEEDITOR_TOOLTIPSAVE;Save current curve +CURVEEDITOR_TOOLTIPCOPY;Copy current curve to clipboard +CURVEEDITOR_TOOLTIPPASTE;Paste curve from clipboard CURVEEDITOR_TYPE;Type: EDITWINDOW_TITLE;Image Edit EXIFFILTER_APERTURE;Aperture @@ -149,11 +151,13 @@ HISTOGRAM_BUTTON_B;B HISTOGRAM_BUTTON_G;G HISTOGRAM_BUTTON_L;L HISTOGRAM_BUTTON_R;R +HISTOGRAM_BUTTON_RAW;Raw HISTOGRAM_LABEL;Histogram HISTOGRAM_TOOLTIP_B;Show/Hide BLUE histogram HISTOGRAM_TOOLTIP_G;Show/Hide GREEN histogram HISTOGRAM_TOOLTIP_L;Show/Hide CIELAB Luminance histogram HISTOGRAM_TOOLTIP_R;Show/Hide RED histogram +HISTOGRAM_TOOLTIP_RAW;Show/Hide RAW histogram HISTORY_CHANGED;Changed HISTORY_CUSTOMCURVE;Custom Curve HISTORY_DELSNAPSHOT;Del @@ -480,8 +484,8 @@ PARTIALPASTE_PREPROCESS_LINEDENOISE;Line noise filter PARTIALPASTE_RAWCACORR_AUTO;CA auto correction PARTIALPASTE_RAWCACORR_CABLUE;CA Blue PARTIALPASTE_RAWCACORR_CARED;CA Red -PARTIALPASTE_RAWEXPOS_LINEAR;Exposure linear corr. factor -PARTIALPASTE_RAWEXPOS_PRESER;Exposure HL preserving corr. (EV) +PARTIALPASTE_RAWEXPOS_LINEAR;Raw white point linear corr. factor +PARTIALPASTE_RAWEXPOS_PRESER;Raw white point HL preserving corr. (EV) PARTIALPASTE_RAWGROUP;Raw settings PARTIALPASTE_RAW_DCBENHANCE;Apply DCB enhancement step PARTIALPASTE_RAW_DCBITERATIONS;Number of DCB iterations @@ -690,7 +694,7 @@ TP_COLORDENOISE_RADIUS;Radius TP_COLORSHIFT_BLUEYELLOW;Blue-Yellow TP_COLORSHIFT_GREENMAGENTA;Green-Magenta TP_COLORSHIFT_LABEL;Color Shift -TP_CROP_DPI;DPI= +TP_CROP_PPI;PPI= TP_CROP_FIXRATIO;Fix Ratio: TP_CROP_GTDIAGONALS;Rule of diagonals TP_CROP_GTGRID;Grid @@ -734,7 +738,7 @@ TP_EQUALIZER_FINEST;finest TP_EQUALIZER_LABEL;Wavelet equalizer TP_EQUALIZER_LARGEST;coarsest TP_EQUALIZER_NEUTRAL;Neutral -TP_EXPOSCORR_LABEL;Exposure +TP_EXPOSCORR_LABEL;Raw white point TP_EXPOSURE_AUTOLEVELS;Auto Levels TP_EXPOSURE_BLACKLEVEL;Black TP_EXPOSURE_BRIGHTNESS;Brightness @@ -755,6 +759,8 @@ TP_FLATFIELD_BT_HORIZONTAL;Horizontal TP_FLATFIELD_BT_VERTHORIZ;Vert. + Horiz. TP_FLATFIELD_BT_VERTICAL;Vertical TP_FLATFIELD_LABEL;Flat Field +TP_GAMMA_OUTPUT;Output gamma +TP_GAMMA_COMMENT;(output profile disabled except "default") TP_HLREC_CIELAB;CIELab Blending TP_HLREC_COLOR;Color Propagation TP_HLREC_LABEL;Highlight Reconstruction diff --git a/rtdata/options/options.lin b/rtdata/options/options.lin index c5059b2aa..31b97add0 100644 --- a/rtdata/options/options.lin +++ b/rtdata/options/options.lin @@ -103,7 +103,7 @@ ColorCorrection=1 [Crop Settings] Ratio=3:2 FixRatio=true -DPI=600 +PPI=300 [Color Management] ICCDirectory= diff --git a/rtdata/options/options.osx b/rtdata/options/options.osx index 46cf8c42c..d677b7363 100644 --- a/rtdata/options/options.osx +++ b/rtdata/options/options.osx @@ -103,7 +103,7 @@ ColorCorrection=1 [Crop Settings] Ratio=3:2 FixRatio=true -DPI=600 +PPI=300 [Color Management] ICCDirectory= diff --git a/rtdata/options/options.win b/rtdata/options/options.win index 5eec64322..1ce47d113 100644 --- a/rtdata/options/options.win +++ b/rtdata/options/options.win @@ -104,7 +104,7 @@ ColorCorrection=1 [Crop Settings] Ratio=3:2 FixRatio=true -DPI=600 +PPI=300 [Color Management] # Auto-determined by RT on first start diff --git a/rtdata/profiles/crisp.pp3 b/rtdata/profiles/crisp.pp3 index 28c949dec..7e671d7d8 100644 --- a/rtdata/profiles/crisp.pp3 +++ b/rtdata/profiles/crisp.pp3 @@ -145,6 +145,7 @@ InputProfile=(camera) ApplyGammaBeforeInputProfile=false WorkingProfile=sRGB OutputProfile=No ICM: sRGB output +Gammafree=default [Equalizer] Enabled=false diff --git a/rtdata/profiles/default.pp3 b/rtdata/profiles/default.pp3 index 85dcb0c28..911d878e5 100644 --- a/rtdata/profiles/default.pp3 +++ b/rtdata/profiles/default.pp3 @@ -145,6 +145,7 @@ InputProfile=(camera) ApplyGammaBeforeInputProfile=false WorkingProfile=sRGB OutputProfile=No ICM: sRGB output +Gammafree=default [Equalizer] Enabled=false diff --git a/rtdata/profiles/neutral.pp3 b/rtdata/profiles/neutral.pp3 index d2f97c2f5..608ec9259 100644 --- a/rtdata/profiles/neutral.pp3 +++ b/rtdata/profiles/neutral.pp3 @@ -145,6 +145,7 @@ InputProfile=(camera) ApplyGammaBeforeInputProfile=false WorkingProfile=sRGB OutputProfile=No ICM: sRGB output +Gammafree=default [Equalizer] Enabled=false diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 106b255ed..a687be2ff 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -153,9 +153,9 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { //temporary parameters for tile CA evaluation float gdiff, deltgrb; //interpolated G at edge of plaquette - float Ginthfloor, Ginthceil, Gint, gradwt; + float Ginthfloor, Ginthceil, Gint, RBint, gradwt; //interpolated color difference at edge of plaquette - float grbdiffint, grbdiffold; + float grbdiffinthfloor, grbdiffinthceil, grbdiffint, grbdiffold; //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 @@ -358,7 +358,7 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { if (row>-1 && row-1 && col0.8*clip_pt || Gtmp[indx]>0.8*clip_pt) continue; + + //in linear interpolation, color differences are a quadratic function of interpolation position; + //solve for the interpolation position that minimizes color difference variance over the tile + + //vertical + gdiff=0.3125*(rgb[indx+TS][1]-rgb[indx-TS][1])+0.09375*(rgb[indx+TS+1][1]-rgb[indx-TS+1][1]+rgb[indx+TS-1][1]-rgb[indx-TS-1][1]); + deltgrb=(rgb[indx][c]-rgb[indx][1])-0.5*((rgb[indx-v4][c]-rgb[indx-v4][1])+(rgb[indx+v4][c]-rgb[indx+v4][1])); + + gradwt=fabs(0.25*rbhpfv[indx]+0.125*(rbhpfv[indx+2]+rbhpfv[indx-2]) );//*(grblpfv[indx-v2]+grblpfv[indx+v2])/(eps+0.1*grblpfv[indx-v2]+rblpfv[indx-v2]+0.1*grblpfv[indx+v2]+rblpfv[indx+v2]); + if (gradwt>eps) { + coeff[0][0][c] += gradwt*deltgrb*deltgrb; + coeff[0][1][c] += gradwt*gdiff*deltgrb; + coeff[0][2][c] += gradwt*gdiff*gdiff; + areawt[0][c]++; + } + + //horizontal + gdiff=0.3125*(rgb[indx+1][1]-rgb[indx-1][1])+0.09375*(rgb[indx+1+TS][1]-rgb[indx-1+TS][1]+rgb[indx+1-TS][1]-rgb[indx-1-TS][1]); + deltgrb=(rgb[indx][c]-rgb[indx][1])-0.5*((rgb[indx-4][c]-rgb[indx-4][1])+(rgb[indx+4][c]-rgb[indx+4][1])); + + gradwt=fabs(0.25*rbhpfh[indx]+0.125*(rbhpfh[indx+v2]+rbhpfh[indx-v2]) );//*(grblpfh[indx-2]+grblpfh[indx+2])/(eps+0.1*grblpfh[indx-2]+rblpfh[indx-2]+0.1*grblpfh[indx+2]+rblpfh[indx+2]); + if (gradwt>eps) { + coeff[1][0][c] += gradwt*deltgrb*deltgrb; + coeff[1][1][c] += gradwt*gdiff*deltgrb; + coeff[1][2][c] += gradwt*gdiff*gdiff; + areawt[1][c]++; + } + + // In Mathematica, + // f[x_]=Expand[Total[Flatten[ + // ((1-x) RotateLeft[Gint,shift1]+x RotateLeft[Gint,shift2]-cfapad)^2[[dv;;-1;;2,dh;;-1;;2]]]]]; + // extremum = -.5Coefficient[f[x],x]/Coefficient[f[x],x^2] + }*/ for (c=0; c<3; c+=2){ for (j=0; j<2; j++) {// vert/hor //printf("hblock %d vblock %d j %d c %d areawt %d \n",hblock,vblock,j,c,areawt[j][c]); @@ -449,7 +518,7 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { if (fabs(CAshift[j][c])<2.0) { blockave[j][c] += CAshift[j][c]; blocksqave[j][c] += SQR(CAshift[j][c]); - blockdenom[j][c] ++; + blockdenom[j][c] += 1; } }//vert/hor }//color @@ -467,8 +536,10 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { //data structure: blockshifts[blocknum][R/B][v/h] //if (c==0) printf("vblock= %d hblock= %d blockshiftsmedian= %f \n",vblock,hblock,blockshifts[(vblock)*hblsz+hblock][c][0]); } + + if(plistener) plistener->setProgress(0.5*fabs((float)top/height)); + } - if(plistener) plistener->setProgress(0.16 + 0.02*(double)(top+border)/height); } //end of diagnostic pass @@ -585,7 +656,7 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { // Main algorithm: Tile loop //#pragma omp parallel for shared(image,height,width) private(top,left,indx,indx1) schedule(dynamic) - for (top=-border, vblock=1; top < height; top += TS-border2, vblock++){ + for (top=-border, vblock=1; top < height; top += TS-border2, vblock++) for (left=-border, hblock=1; left < width; left += TS-border2, hblock++) { int bottom = MIN( top+TS,height+border); int right = MIN(left+TS, width+border); @@ -791,20 +862,35 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { grbdiffold = rgb[indx][1]-rgb[indx][c]; - //gradient weights using difference from G at CA shift points and G at grid points - p[0]=1/(eps+fabs(rgb[indx][1]-gshift[indx])); - p[1]=1/(eps+fabs(rgb[indx][1]-gshift[indx-2*GRBdir[1][c]])); - p[2]=1/(eps+fabs(rgb[indx][1]-gshift[(rr-2*GRBdir[0][c])*TS+cc])); - p[3]=1/(eps+fabs(rgb[indx][1]-gshift[(rr-2*GRBdir[0][c])*TS+cc-2*GRBdir[1][c]])); - - grbdiffint = (p[0]*grbdiff[indx]+p[1]*grbdiff[indx-2*GRBdir[1][c]]+ \ - p[2]*grbdiff[(rr-2*GRBdir[0][c])*TS+cc]+p[3]*grbdiff[(rr-2*GRBdir[0][c])*TS+cc-2*GRBdir[1][c]])/(p[0]+p[1]+p[2]+p[3]); + //interpolate color difference from optical R/B locations to grid locations + grbdiffinthfloor=(1-shifthfrac[c]/2)*grbdiff[indx]+(shifthfrac[c]/2)*grbdiff[indx-2*GRBdir[1][c]]; + grbdiffinthceil=(1-shifthfrac[c]/2)*grbdiff[(rr-2*GRBdir[0][c])*TS+cc]+(shifthfrac[c]/2)*grbdiff[(rr-2*GRBdir[0][c])*TS+cc-2*GRBdir[1][c]]; + //grbdiffint is bilinear interpolation of G-R/G-B at grid point + grbdiffint=(1-shiftvfrac[c]/2)*grbdiffinthfloor+(shiftvfrac[c]/2)*grbdiffinthceil; //now determine R/B at grid points using interpolated color differences and interpolated G value at grid point - if (fabs(grbdiffold)>fabs(grbdiffint) ) { - rgb[indx][c]=rgb[indx][1]-grbdiffint; - } + RBint=rgb[indx][1]-grbdiffint; + if (fabs(RBint-rgb[indx][c])<0.25*(RBint+rgb[indx][c])) { + if (fabs(grbdiffold)>fabs(grbdiffint) ) { + rgb[indx][c]=RBint; + } + } else { + + //gradient weights using difference from G at CA shift points and G at grid points + p[0]=1/(eps+fabs(rgb[indx][1]-gshift[indx])); + p[1]=1/(eps+fabs(rgb[indx][1]-gshift[indx-2*GRBdir[1][c]])); + p[2]=1/(eps+fabs(rgb[indx][1]-gshift[(rr-2*GRBdir[0][c])*TS+cc])); + p[3]=1/(eps+fabs(rgb[indx][1]-gshift[(rr-2*GRBdir[0][c])*TS+cc-2*GRBdir[1][c]])); + + grbdiffint = (p[0]*grbdiff[indx]+p[1]*grbdiff[indx-2*GRBdir[1][c]]+ \ + p[2]*grbdiff[(rr-2*GRBdir[0][c])*TS+cc]+p[3]*grbdiff[(rr-2*GRBdir[0][c])*TS+cc-2*GRBdir[1][c]])/(p[0]+p[1]+p[2]+p[3]); + + //now determine R/B at grid points using interpolated color differences and interpolated G value at grid point + if (fabs(grbdiffold)>fabs(grbdiffint) ) { + rgb[indx][c]=rgb[indx][1]-grbdiffint; + } + } //if color difference interpolation overshot the correction, just desaturate if (grbdiffold*grbdiffint<0) { @@ -823,9 +909,11 @@ void RawImageSource::CA_correct_RT(double cared, double cablue) { //image[indx][c] = CLIP((int)(65535.0*rgb[(rr)*TS+cc][c] + 0.5));//for dcraw implementation } + + if(plistener) plistener->setProgress(0.5+0.5*fabs((float)top/height)); + } - if(plistener) plistener->setProgress(0.18 + 0.02*(double)(top+border)/height); - } + // clean up free(buffer); free(Gtmp); diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 78c3cdb53..96c2d8e4f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -8,8 +8,8 @@ link_directories (${CMAKE_CURRENT_SOURCE_DIR}/../rtexif ${EXTRA_LIBDIR} ${GTHREA ${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS}) set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc dcraw.cc iccstore.cc - dfmanager.cc ffmanager.cc rawimage.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 + dfmanager.cc ffmanager.cc rawimage.cc image8.cc image16.cc imagefloat.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc + loadinitial.cc procparams.cc rawimagesource.cc demosaic_algos.cc shmap.cc simpleprocess.cc refreshmap.cc stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc processingjob.cc rtthumbnail.cc utils.cc labimage.cc slicer.cc iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc diff --git a/rtengine/LUT.h b/rtengine/LUT.h new file mode 100644 index 000000000..c63b99112 --- /dev/null +++ b/rtengine/LUT.h @@ -0,0 +1,177 @@ +/* + * LUT.h + * This file is part of RawTherapee. + * + * Copyright (c) 2011 Jan Rinze Peterzon (janrinze@gmail.com) + * + * 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 . + */ + +/* + * Declaration of flexible Lookup Tables + * + * Usage: + * + * LUT name (size); + * LUT name (size, flags); + * + * creates an array which is valid within the normal C/C++ scope "{ ... }" + * + * access to elements is a simple as: + * + * LUT my_lut (10); + * float value = my_lut[3]; + * float value = my_lut[2.5]; // this will interpolate + * + * when using a float type index it will interpolate the lookup values + * + * extra setting in flags: (clipping is set by default) + * LUT_CLIP_ABOVE + * LUT_CLIP_BELOW + * + * example: + * LUT my_lut (10,LUT_CLIP_BELOW); + * float value = my_lut[22.5]; // this will extrapolate + * float value = my_lut[-22.5]; // this will not extrapolate + * + * LUT my_lut (10,0); // this will extrapolate on either side + * + * shotcuts: + * + * LUTf stands for LUT + * LUTi stands for LUT + * LUTu stands for LUT + */ + +#ifndef LUT_H_ +#define LUT_H_ + +// bit representations of flags +#define LUT_CLIP_BELOW 1 +#define LUT_CLIP_ABOVE 2 + +#define LUTf LUT +#define LUTi LUT +#define LUTu LUT + +template +class LUT { +private: + // list of variables ordered to improve cache speed + unsigned int maxs; + T * data; + unsigned int clip, size, owner; +public: + LUT(int s, int flags = 0xfffffff) { + clip = flags; + data = new T[s]; + owner = 1; + size = s; + maxs=size-2; + } + void operator ()(int s, int flags = 0xfffffff) { + if (owner&&data) + delete[] data; + clip = flags; + data = new T[s]; + owner = 1; + size = s; + maxs=size-2; + } + + LUT(int s, T * source) { + data = new T[s]; + owner = 1; + size = s; + maxs=size-2; + for (int i = 0; i < s; i++) { + data[i] = source[i]; + } + } + + LUT(void) { + data = NULL; + owner = 1; + size = 0; + maxs=0; + } + + ~LUT() { + if (owner) + delete[] data; + } + + LUT & operator=(const LUT &rhs) { + if (this != &rhs) { + if (rhs.size>this->size) + { + delete [] this->data; + this->data=NULL; + } + if (this->data==NULL) this->data=new T[rhs.size]; + this->clip=rhs.clip; + this->owner=1; + memcpy(this->data,rhs.data,rhs.size*sizeof(T)); + this->size=rhs.size; + this->maxs=this->size-2; + } + + return *this; + } + // use with integer indices + T& operator[](int index) { + if (((unsigned int)index) maxs) { + if (idx<0) + { + if (clip & LUT_CLIP_BELOW) + return data[0]; + idx=0; + } + else + { + if (clip & LUT_CLIP_ABOVE) + return data[size - 1]; + idx =maxs; + } + } + float diff = index - (float) idx; + T p1 = data[idx]; + T p2 = data[idx + 1]-p1; + return (p1 + p2*diff); + } + + operator bool (void) + { + return size>0; + } + + void clear(void) { + memset(data, 0, size * sizeof(T)); + } +}; + +#endif /* LUT_H_ */ diff --git a/rtengine/PF_correct_RT.cc b/rtengine/PF_correct_RT.cc index 68efeb83f..c9f28d6c5 100644 --- a/rtengine/PF_correct_RT.cc +++ b/rtengine/PF_correct_RT.cc @@ -60,13 +60,13 @@ void ImProcFunctions::PF_correct_RT(LabImage * src, LabImage * dst, double radiu #endif { AlignedBuffer* buffer = new AlignedBuffer (MAX(src->W,src->H)); - gaussHorizontal (src->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); - gaussHorizontal (src->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); - gaussVertical (tmp1->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); - gaussVertical (tmp1->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); + gaussHorizontal (src->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); + gaussHorizontal (src->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); + gaussVertical (tmp1->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); + gaussVertical (tmp1->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); - gaussHorizontal (src->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); - gaussVertical (tmp1->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); + gaussHorizontal (src->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); + gaussVertical (tmp1->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); delete buffer; } diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index 4c76eff74..7402887d1 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -34,7 +34,8 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) //#define CLIP(x) LIM(x,0,65535) -#define HCLIP(x) MIN(clip_pt,x) +#define HCLIP(x) x //is this still necessary??? + //MIN(clip_pt,x) int width=winw, height=winh; @@ -209,6 +210,14 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { //if (verbose) fprintf (stderr,_("AMaZE interpolation ...\n")); //t1 = clock(); + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if (plistener) { + plistener->setProgressStr ("AMaZE Demosaicing..."); + plistener->setProgress (0.0); + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //determine GRBG coset; (ey,ex) is the offset of the R subarray @@ -461,19 +470,19 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { glha=HCLIP(cfa[indx-1])+0.5*(cfa[indx]-cfa[indx-2]); grha=HCLIP(cfa[indx+1])+0.5*(cfa[indx]-cfa[indx+2]); - if (fabs(1-cru)0) { - if (3*hcd[indx] > (Ginth+cfa[indx])) { + if (3.0f*hcd[indx] > (Ginth+cfa[indx])) { hcd[indx]=-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx]; } else { - hwt = 1-3*hcd[indx]/(eps+Ginth+cfa[indx]); - hcd[indx]=hwt*hcd[indx] + (1-hwt)*(-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx]); + hwt = 1.0f -3.0f*hcd[indx]/(eps+Ginth+cfa[indx]); + hcd[indx]=hwt*hcd[indx] + (1.0f-hwt)*(-ULIM(Ginth,cfa[indx-1],cfa[indx+1])+cfa[indx]); } } if (vcd[indx]>0) { - if (3*vcd[indx] > (Gintv+cfa[indx])) { + if (3.0f*vcd[indx] > (Gintv+cfa[indx])) { vcd[indx]=-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx]; } else { - vwt = 1-3*vcd[indx]/(eps+Gintv+cfa[indx]); - vcd[indx]=vwt*vcd[indx] + (1-vwt)*(-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx]); + vwt = 1.0f -3.0f*vcd[indx]/(eps+Gintv+cfa[indx]); + vcd[indx]=vwt*vcd[indx] + (1.0f-vwt)*(-ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])+cfa[indx]); } } @@ -546,19 +555,19 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { Gintv = vcd[indx]+cfa[indx]; if (hcd[indx]<0) { - if (3*hcd[indx] < -(Ginth+cfa[indx])) { + if (3.0f*hcd[indx] < -(Ginth+cfa[indx])) { hcd[indx]=ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx]; } else { - hwt = 1+3*hcd[indx]/(eps+Ginth+cfa[indx]); - hcd[indx]=hwt*hcd[indx] + (1-hwt)*(ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx]); + hwt = 1.0f +3.0f*hcd[indx]/(eps+Ginth+cfa[indx]); + hcd[indx]=hwt*hcd[indx] + (1.0f-hwt)*(ULIM(Ginth,cfa[indx-1],cfa[indx+1])-cfa[indx]); } } if (vcd[indx]<0) { - if (3*vcd[indx] < -(Gintv+cfa[indx])) { + if (3.0f*vcd[indx] < -(Gintv+cfa[indx])) { vcd[indx]=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx]; } else { - vwt = 1+3*vcd[indx]/(eps+Gintv+cfa[indx]); - vcd[indx]=vwt*vcd[indx] + (1-vwt)*(ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx]); + vwt = 1.0f +3.0f*vcd[indx]/(eps+Gintv+cfa[indx]); + vcd[indx]=vwt*vcd[indx] + (1.0f-vwt)*(ULIM(Gintv,cfa[indx-v1],cfa[indx+v1])-cfa[indx]); } } @@ -589,8 +598,8 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { hwt = dirwts[indx-1][1]/(dirwts[indx-1][1]+dirwts[indx+1][1]); vwt = dirwts[indx-v1][0]/(dirwts[indx+v1][0]+dirwts[indx-v1][0]); - vcdvar = epssq+vwt*Dgrbvvard+(1-vwt)*Dgrbvvaru; - hcdvar = epssq+hwt*Dgrbhvarr+(1-hwt)*Dgrbhvarl; + vcdvar = epssq+vwt*Dgrbvvard+(1.0f-vwt)*Dgrbvvaru; + hcdvar = epssq+hwt*Dgrbhvarr+(1.0f-hwt)*Dgrbhvarl; //vcdvar = 5*(vcdsq[indx]+vcdsq[indx-v1]+vcdsq[indx-v2]+vcdsq[indx+v1]+vcdsq[indx+v2])-SQR(vcd[indx]+vcd[indx-v1]+vcd[indx-v2]+vcd[indx+v1]+vcd[indx+v2]); //hcdvar = 5*(hcdsq[indx]+hcdsq[indx-1]+hcdsq[indx-2]+hcdsq[indx+1]+hcdsq[indx+2])-SQR(hcd[indx]+hcd[indx-1]+hcd[indx-2]+hcd[indx+1]+hcd[indx+2]); @@ -602,8 +611,8 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { Dgrbhvarl = (dginth[indx])+(dginth[indx-1])+(dginth[indx-2]); Dgrbhvarr = (dginth[indx])+(dginth[indx+1])+(dginth[indx+2]); - vcdvar1 = epssq+vwt*Dgrbvvard+(1-vwt)*Dgrbvvaru; - hcdvar1 = epssq+hwt*Dgrbhvarr+(1-hwt)*Dgrbhvarl; + vcdvar1 = epssq+vwt*Dgrbvvard+(1.0f-vwt)*Dgrbvvaru; + hcdvar1 = epssq+hwt*Dgrbhvarr+(1.0f-hwt)*Dgrbhvarl; //determine adaptive weights for G interpolation varwt=hcdvar/(vcdvar+hcdvar); @@ -719,7 +728,7 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { - Dgrb[indx][0] = (hcd[indx]*(1-hvwt[indx]) + vcd[indx]*hvwt[indx]);//evaluate color differences + Dgrb[indx][0] = (hcd[indx]*(1.0f-hvwt[indx]) + vcd[indx]*hvwt[indx]);//evaluate color differences //if (hvwt[indx]<0.5) Dgrb[indx][0]=hcd[indx]; //if (hvwt[indx]>0.5) Dgrb[indx][0]=vcd[indx]; rgb[indx][1] = cfa[indx] + Dgrb[indx][0];//evaluate G (finally!) @@ -789,19 +798,19 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //diagonal color ratios - crse=2*(cfa[indx+m1])/(eps+cfa[indx]+(cfa[indx+m2])); - crnw=2*(cfa[indx-m1])/(eps+cfa[indx]+(cfa[indx-m2])); - crne=2*(cfa[indx+p1])/(eps+cfa[indx]+(cfa[indx+p2])); - crsw=2*(cfa[indx-p1])/(eps+cfa[indx]+(cfa[indx-p2])); + crse=2.0f*(cfa[indx+m1])/(eps+cfa[indx]+(cfa[indx+m2])); + crnw=2.0f*(cfa[indx-m1])/(eps+cfa[indx]+(cfa[indx-m2])); + crne=2.0f*(cfa[indx+p1])/(eps+cfa[indx]+(cfa[indx+p2])); + crsw=2.0f*(cfa[indx-p1])/(eps+cfa[indx]+(cfa[indx-p2])); //assign B/R at R/B sites - if (fabs(1-crse) pre_mul[c]) Gintv=ULIM(Gintv,cfa[indx-v1],cfa[indx+v1]); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - rgb[indx][1] = Ginth*(1-hvwt[indx]) + Gintv*hvwt[indx]; + rgb[indx][1] = Ginth*(1.0f-hvwt[indx]) + Gintv*hvwt[indx]; //rgb[indx][1] = 0.5*(rgb[indx][1]+0.25*(rgb[indx-v1][1]+rgb[indx+v1][1]+rgb[indx-1][1]+rgb[indx+1][1])); Dgrb[indx][0] = rgb[indx][1]-cfa[indx]; @@ -953,8 +962,8 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) { for (cc=12+(FC(rr,1)&1),indx=rr*TS+cc,c=FC(rr,cc+1)/2; ccsetProgress( 0.2 + 0.2*progress ); + if(plistener) plistener->setProgress(progress); } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/array2D.h b/rtengine/array2D.h new file mode 100644 index 000000000..197790d30 --- /dev/null +++ b/rtengine/array2D.h @@ -0,0 +1,267 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2011 Jan Rinze Peterzon (janrinze@gmail.com) + * + * 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 . + */ + +/* + * Declaration of flexible 2D arrays + * + * Usage: + * + * array2D name (X-size,Y-size); + * array2D name (X-size,Y-size type ** data); + * + * creates an array which is valid within the normal C/C++ scope "{ ... }" + * + * access to elements is a simple as: + * + * array2D my_array (10,10); // creates 10x10 array of floats + * value = my_array[3][5]; + * my_array[4][6]=value; + * + * or copy an existing 2D array + * + * float ** mydata; + * array2D my_array (10,10,mydata); + * + * + * Useful extra pointers + * + * ** my_array gives access to the pointer for access with [][] + * * my_array gives access to the flat stored data. + * + * Advanced usage: + * array2D my_array ; // empty container. + * my_array(10,10) ; // resize to 10x10 array + * my_array(10,10,ARRAY2D_CLEAR_DATA) ; // resize to 10x10 and clear data + * my_array(10,10,ARRAY2D_CLEAR_DATA|ARRAY2D_LOCK_DATA) ; same but set a lock on changes + * + * !! locked arrays cannot be resized and cannot be unlocked again !! + */ +#ifndef ARRAY2D_H_ +#define ARRAY2D_H_ +#include // for raise() +// flags for use +#define ARRAY2D_LOCK_DATA 1 +#define ARRAY2D_CLEAR_DATA 2 +#define ARRAY2D_BYREFERENCE 4 +#define ARRAY2D_VERBOSE 8 + +#include + +template +class array2D { + +private: + int x, y, owner, flags; + T ** ptr; + T * data; + bool lock; // useful lock to ensure data is not changed anymore. + void ar_realloc(int w, int h) { + if ((ptr) && ((h > y) || (4 * h < y))) { + delete[] ptr; + ptr = NULL; + } + if ((data) && (((h * w) > (x * y)) || ((h * w) < ((x * y) / 4)))) { + delete[] data; + data = NULL; + } + if (ptr == NULL) + ptr = new T*[h]; + if (data == NULL) + data = new T[h * w]; + + x = w; + y = h; + for (int i = 0; i < h; i++) + ptr[i] = data + w * i; + owner = 1; + } +public: + + // use as empty declaration, resize before use! + // very useful as a member object + array2D() : + x(0), y(0), owner(0), data(NULL), ptr(NULL), lock(0) { + printf("got empty array2D init\n"); + } + + // creator type1 + array2D(int w, int h, unsigned int flgs = 0) { + flags = flgs; + lock = flags & ARRAY2D_LOCK_DATA; + data = new T[h * w]; + owner = 1; + x = w; + y = h; + ptr = new T*[h]; + for (int i = 0; i < h; i++) + ptr[i] = data + i * w; + if (flags & ARRAY2D_CLEAR_DATA) + memset(data, 0, w * h * sizeof(T)); + } + + // creator type 2 + array2D(int w, int h, T ** source, unsigned int flgs = 0) { + flags = flgs; + //if (lock) { printf("array2D attempt to overwrite data\n");raise(SIGSEGV);} + lock |= flags & ARRAY2D_LOCK_DATA; + // when by reference + // TODO: improve this code with ar_realloc() + owner = (flags & ARRAY2D_BYREFERENCE) ? 0 : 1; + if (owner) + data = new T[h * w]; + else + data = NULL; + x = w; + y = h; + ptr = new T*[h]; + for (int i = 0; i < h; i++) { + if (owner) { + ptr[i] = data + i * w; + for (int j = 0; j < w; j++) + ptr[i][j] = source[i][j]; + } else + ptr[i] = source[i]; + } + } + + // destructor + ~array2D() { + + if (flags & ARRAY2D_VERBOSE) + printf(" deleting array2D size %dx%d \n", x, y); + + if ((owner) && (data)) + delete[] data; + if (ptr) + delete[] ptr; + } + + // use with indices + T * operator[](size_t index) { + return ptr[index]; + } + + // use as pointer to T** + operator T**() { + return ptr; + } + + // use as pointer to data + operator T*() { + // only if owner this will return a valid pointer + return data; + } + + + // useful within init of parent object + // or use as resize of 2D array + void operator()(int w, int h, unsigned int flgs = 0) { + flags = flgs; + if (flags & ARRAY2D_VERBOSE) { + printf("got init request %dx%d flags=%d\n", w, h, flags); + printf("previous was data %p ptr %p \n", data, ptr); + } + if (lock) // our object was locked so don't allow a change. + { + printf("got init request but object was locked!\n"); + raise( SIGSEGV); + } + lock = flags & ARRAY2D_LOCK_DATA; + + ar_realloc(w,h); + if (flags & ARRAY2D_CLEAR_DATA) + memset(data, 0, w * h * sizeof(T)); + } + + // import from flat data + void operator()(int w, int h, T* copy, unsigned int flgs = 0) { + flags = flgs; + if (flags & ARRAY2D_VERBOSE) { + printf("got init request %dx%d flags=%d\n", w, h, flags); + printf("previous was data %p ptr %p \n", data, ptr); + } + if (lock) // our object was locked so don't allow a change. + { + printf("got init request but object was locked!\n"); + raise( SIGSEGV); + } + lock = flags & ARRAY2D_LOCK_DATA; + + ar_realloc(w,h); + memcpy(data, copy, w * h * sizeof(T)); + } + int width() { + return x; + } + int height() { + return y; + } + + operator bool() { + return (x > 0 && y > 0); + } + + array2D & operator=( array2D & rhs) { + if (this != &rhs) + + { + if (!owner) // we can only copy same size data + { + if ((x != rhs.x) || (y != rhs.y)) { + printf(" assignment error in array2D\n"); + printf(" sizes differ and not owner\n"); + raise( SIGSEGV); + } + + } else { + ar_realloc(rhs.x, rhs.y); + } + // we could have been created from a different + // array format where each row is created by 'new' + for (int i=0;i +class multi_array2D { +private: + array2D list[num]; + +public: + multi_array2D(int x, int y, int flags = 0) { + for (int i = 0; i < num; i++) + list[i](x, y, flags | ARRAY2D_VERBOSE); + } + + ~multi_array2D() { + printf("trying to delete the list of array2D objects\n"); + } + + array2D & operator[](size_t index) { + if (index < 0 || index >= num) { + printf("index %d is out of range[0..%d]", index, num - 1); + raise( SIGSEGV); + } + return list[index]; + } +}; +#endif /* array2D_H_ */ diff --git a/rtengine/bilateral2.h b/rtengine/bilateral2.h index 1b5e2ff90..c649b8eec 100644 --- a/rtengine/bilateral2.h +++ b/rtengine/bilateral2.h @@ -31,20 +31,19 @@ #endif // This seems ugly, but way faster than any other solutions I tried - -#define ELEM(a,b) (src[i - a][j - b] * ec[src[i - a][j - b]-src[i][j]+0x10000]) -#define SULY(a,b) (ec[src[i - a][j - b]-src[i][j]+0x10000]) - +#define ELEM(a,b) (src[i - a][j - b] * ec[src[i - a][j - b]-src[i][j]+65536.0f]) +#define SULY(a,b) (ec[src[i - a][j - b]-src[i][j]+65536.0f]) +//#define SULY(a,b) (ec[((int)(src[i - a][j - b]-src[i][j]+0x10000))]) #define BL_BEGIN(a,b) double scale = (a); \ - int* ec = new int [0x20000]; \ + LUTf ec (0x20000); \ for (int i=0; i<0x20000; i++) \ - ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sens*sens))*scale); \ + ec[i] = (exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sens*sens))*scale); \ int rstart = b; \ int rend = H-b; \ int cstart = b; \ int cend = W-b; -#define BL_FREE buffer[i][j] = v; }} delete [] ec; +#define BL_FREE buffer[i][j] = v; }}; #define BL_END(b) for (int i=0; i=rend || j>=cend) \ @@ -432,8 +431,8 @@ template void bilateral (T** src, T** dst, T** buffer, int W, // START OF EXPERIMENTAL CODE: O(1) bilateral box filter // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#define MAXVAL 0xffff -#define CLIP(a) ((a)>0?((a)0.0?((a) void bilateral (T** src, T** dst, T** buffer, int W, template void bilateral (T** src, T** dst, int W, int H, int sigmar, double sigmas, int row_from, int row_to) { // range weights - double* ec = new double [0x20000]; + LUTf ec(0x20000); for (int i=0; i<0x20000; i++) ec[i] = exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sigmar*sigmar)); // histogram - unsigned short* hist = new unsigned short[1<>TRANSBIT]++; + rhist[((int)src[x][y])>>TRANSBIT]++; sigmar*=2; @@ -471,27 +471,27 @@ template void bilateral (T** src, T** dst, int W, int H, int sigmar, do // calculate histogram at the beginning of the row if (i>r) for (int x = 0; x>TRANSBIT]--; + rhist[((int)src[i-r-1][x])>>TRANSBIT]--; if (i>TRANSBIT]++; + rhist[((int)src[i+r][x])>>TRANSBIT]++; - memcpy (hist, rhist, (1<r) for (int x=MAX(0,i-r); x<=MIN(i+r,H-1); x++) - hist[src[x][j-r-1]>>TRANSBIT]--; + hist[(int)(src[x][j-r-1])>>TRANSBIT]--; if (j>TRANSBIT]++; + hist[((int)src[x][j+r])>>TRANSBIT]++; // calculate pixel value float weight = 0.0; for (int k=0; k<=(sigmar>>TRANSBIT); k++) { float w = 1.0 - (double)k/(sigmar>>TRANSBIT); - int v = src[i][j]>>TRANSBIT; + int v = (int)(src[i][j])>>TRANSBIT; if (v-k >= 0) { weight += hist [v-k] * w; buff_final[i][j] += hist [v-k] * w * (src[i][j]-(k< void bilateral (T** src, T** dst, int W, int H, int sigmar, do for (int j=0; j #include #include -#define MAXVAL 0xffff -#define CLIP(a) ((a)>0?((a)0.0?((a)>8)+1)<<8) / ((src[i][j]>>8)+1)]) //#define ELEM(a,b) (src[i-a][j-b] * ec[src[i-a][j-b]-src[i][j]+0x10000]) @@ -28,10 +28,10 @@ #define SULY(a,b) (ec[(((src[i-a][j-b]>>8)+1)<<8) / ((src[i][j]>>8)+1)]) #define BL_BEGIN(a,b) double scale = (a); \ - int* ec = new int [0x10001]; \ + LUTf ec (0x10001); \ ec[0] = 1; \ for (int i=1; i<0x10001; i++) \ - ec[i] = (int)(exp(-log(i/256.0)*log(i/256.0) / (2.0*sens/1000*sens/1000*i/256.0))*scale); \ + ec[i] = (exp(-log(i/256.0)*log(i/256.0) / (2.0*sens/1000*sens/1000*i/256.0))*scale); \ /* ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sens*sens))*scale); */\ int start = row_from; \ if (start<(b)) start = (b); \ @@ -438,21 +438,24 @@ template void bilateral (T** src, T** dst, T** buffer, int W, int H, in // buffer for the final image float** buff_final = new float*[H]; + float * real_buff_final = new float [W*H]; for (int i=0; i void bilateral (T** src, T** dst, T** buffer, int W, int H, in } // cleanup - for (int i=0; isetProgressStr ("Line Denoise..."); + plistener->setProgress (0.0); + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% float noisevar=SQR(3*noise*65535); // _noise_ (as a fraction of saturation) is input to the algorithm volatile double progress = 0.0; @@ -253,9 +262,9 @@ void RawImageSource::CLASS cfa_linedn(float noise) { progress=1.0; } - if(plistener) plistener->setProgress(0.14 +0.02*progress); - - + if(plistener) plistener->setProgress(progress); + + //if(plistener) plistener->setProgress(fabs((float)top/height)); } // clean up delete [] cfain; diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 458fd24cd..de5dbc218 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include using namespace rtengine; @@ -72,10 +73,16 @@ void ColorTemp::temp2mul (double temp, double green, double& rmul, double& gmul, double X = xD/yD; double Y = 1.0; double Z = (1.0-xD-yD)/yD; - - rmul = X * 3.24071 - Y * 1.53726 - Z * 0.498571; - gmul = - X * 0.969258 + Y * 1.87599 + Z * 0.0415557; - bmul = X * 0.0556352 - Y * 0.203996 + Z * 1.05707; + + /*if (isRaw) { + rmul = sRGB_xyz[0][0]*X + sRGB_xyz[0][1]*Y + sRGB_xyz[0][2]*Z; + gmul = sRGB_xyz[1][0]*X + sRGB_xyz[1][1]*Y + sRGB_xyz[1][2]*Z; + bmul = sRGB_xyz[2][0]*X + sRGB_xyz[2][1]*Y + sRGB_xyz[2][2]*Z; + } else {*/ + rmul = sRGBd65_xyz[0][0]*X + sRGBd65_xyz[0][1]*Y + sRGBd65_xyz[0][2]*Z; + gmul = sRGBd65_xyz[1][0]*X + sRGBd65_xyz[1][1]*Y + sRGBd65_xyz[1][2]*Z; + bmul = sRGBd65_xyz[2][0]*X + sRGBd65_xyz[2][1]*Y + sRGBd65_xyz[2][2]*Z; + //}; gmul /= green; double max = rmul; diff --git a/rtengine/cubint.cc b/rtengine/cubint.cc index ef49ea033..797667f7c 100644 --- a/rtengine/cubint.cc +++ b/rtengine/cubint.cc @@ -19,7 +19,7 @@ #define A (-0.85) //#define CLIP(a) ((a>CMAXVAL)?a=CMAXVAL:((a<0)?0:a)) -inline void cubint (Image16* src, int xs, int ys, double Dx, double Dy, unsigned short *r, unsigned short *g, unsigned short *b, double mul) { +inline void cubint (Imagefloat* src, int xs, int ys, double Dx, double Dy, float *r, float *g, float *b, double mul) { register double w[4]; diff --git a/rtengine/cubintch.cc b/rtengine/cubintch.cc index c9416bc63..c7b6f312d 100644 --- a/rtengine/cubintch.cc +++ b/rtengine/cubintch.cc @@ -17,7 +17,7 @@ * along with RawTherapee. If not, see . */ -inline void cubintch (unsigned short** src, int xs, int ys, double Dx, double Dy, unsigned short *r, double mul) { +inline void cubintch (float** src, int xs, int ys, double Dx, double Dy, float *r, double mul) { register double w[4]; diff --git a/rtengine/curves.cc b/rtengine/curves.cc index be5d21987..6c259714f 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -24,63 +24,73 @@ #include #include -#define CLIPD(a) ((a)>0.0?((a)<1.0?(a):1.0):0.0) +#include "array2D.h" +#include "LUT.h" + +#undef CLIPD +#define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) #define CLIP(a) ((a)<65535 ? (a) : (65535)) namespace rtengine { -Curve::Curve () { - x = 0; - y = 0; - ypp = 0; -} - -void Curve::AddPolygons () -{ - if (firstPointIncluded) { - poly_x.push_back(x1); - poly_y.push_back(y1); + Curve::Curve () { + x = 0; + y = 0; + ypp = 0; } - for (int k=1; k<(nbr_points-1); k++) { - double t = k*increment; - double t2 = t*t; - double tr = 1.-t; - double tr2 = tr*tr; - double tr2t = tr*2*t; - - // adding a point to the polyline - poly_x.push_back( tr2*x1 + tr2t*x2 + t2*x3); - poly_y.push_back( tr2*y1 + tr2t*y2 + t2*y3); + + void Curve::AddPolygons () + { + if (firstPointIncluded) { + poly_x.push_back(x1); + poly_y.push_back(y1); + } + for (int k=1; k<(nbr_points-1); k++) { + double t = k*increment; + double t2 = t*t; + double tr = 1.-t; + double tr2 = tr*tr; + double tr2t = tr*2*t; + + // adding a point to the polyline + poly_x.push_back( tr2*x1 + tr2t*x2 + t2*x3); + poly_y.push_back( tr2*y1 + tr2t*y2 + t2*y3); + } + // adding the last point of the sub-curve + poly_x.push_back(x3); + poly_y.push_back(y3); } - // adding the last point of the sub-curve - poly_x.push_back(x3); - poly_y.push_back(y3); -} + - -void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double satlimthresh, const std::vector& curvePoints, float* outCurve, int skip) { - - //colormult = chroma_scale for Lab manipulations - - // check if contrast curve is needed - bool needsaturation = (saturation<-0.0001 || saturation>0.0001); - - // curve without contrast - double* dcurve = new double[65536]; - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - std::vector satcurvePoints; - satcurvePoints.push_back((double)DCT_NURBS); - if (saturation>0) { - double satslope = (0.5+2*saturation/500.0)/(0.5-2*saturation/500.0); - double scale = (satlimthresh/100.1); - if (!satlimit) scale=100/100.1; + void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double satlimthresh, \ + const std::vector& acurvePoints, const std::vector& bcurvePoints, \ + LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, int skip) { - satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range - satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + //colormult = chroma_scale for Lab manipulations - //if (satlimit) { + // check if contrast curve is needed + bool needsaturation = (saturation<-0.0001 || saturation>0.0001); + + // curve without contrast + LUTf dacurve (65536); + LUTf dbcurve (65536); + + LUTf dscurve (65536); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + std::vector satcurvePoints; + satcurvePoints.push_back((double)DCT_NURBS); + if (saturation>0) { + double satslope = (0.5+2*saturation/500.0)/(0.5-2*saturation/500.0); + double scale = (satlimthresh/100.1); + if (!satlimit) scale=100/100.1; + + satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + + //if (satlimit) { satcurvePoints.push_back(0.5-0.5*scale); //toe point satcurvePoints.push_back(0.5-0.5*scale); //value at toe point @@ -89,98 +99,123 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat satcurvePoints.push_back(0.5+(0.5/satslope)*scale); //shoulder point satcurvePoints.push_back(0.5+0.5*scale); //value at shoulder point - + satcurvePoints.push_back(0.5+0.5*scale); //shoulder point satcurvePoints.push_back(0.5+0.5*scale); //value at shoulder point - /*} else { - satcurvePoints.push_back(0.25+saturation/500.0); //toe point - satcurvePoints.push_back(0.25-saturation/500.0); //value at toe point + /*} else { + satcurvePoints.push_back(0.25+saturation/500.0); //toe point + satcurvePoints.push_back(0.25-saturation/500.0); //value at toe point + + satcurvePoints.push_back(0.75-saturation/500.0); //shoulder point + satcurvePoints.push_back(0.75+saturation/500.0); //value at shoulder point + }*/ - satcurvePoints.push_back(0.75-saturation/500.0); //shoulder point - satcurvePoints.push_back(0.75+saturation/500.0); //value at shoulder point - }*/ + satcurvePoints.push_back(1); // white point + satcurvePoints.push_back(1); // value at white point + } else { + satcurvePoints.push_back(0); + satcurvePoints.push_back(-(saturation/200.0)); + + satcurvePoints.push_back(1); + satcurvePoints.push_back(1+saturation/200.0); + } + DiagonalCurve* satcurve = new DiagonalCurve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - satcurvePoints.push_back(1); // white point - satcurvePoints.push_back(1); // value at white point - } else { - satcurvePoints.push_back(0); - satcurvePoints.push_back(-(saturation/200.0)); + // create a curve if needed + DiagonalCurve* tacurve = NULL; + if (acurvePoints.size()>0 && acurvePoints[0]!=0) + tacurve = new DiagonalCurve (acurvePoints, CURVES_MIN_POLY_POINTS/skip); + DiagonalCurve* tbcurve = NULL; + if (bcurvePoints.size()>0 && bcurvePoints[0]!=0) + tbcurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS/skip); - satcurvePoints.push_back(1); - satcurvePoints.push_back(1+saturation/200.0); - } - DiagonalCurve* satcurve = NULL; - satcurve = new DiagonalCurve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - // create a curve if needed - DiagonalCurve* tcurve = NULL; - if (curvePoints.size()>0 && curvePoints[0]!=0) - tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); - - for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { - - // change to [0,1] range - double val = (double)i / 65535.0; - - // apply saturation curve - if (needsaturation) - val = satcurve->getVal (val); - - // apply custom/parametric/NURBS curve, if any - if (tcurve) { - val = tcurve->getVal (val); + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { + + // change to [0,1] range + double aval = (double)i / 65535.0; + double bval = (double)i / 65535.0; + double sval = (double)i / 65535.0; + + + // apply saturation curve + if (needsaturation) + sval = satcurve->getVal (sval); + + // apply custom/parametric/NURBS curve, if any + if (tacurve) { + aval = tacurve->getVal (aval); + } + // apply custom/parametric/NURBS curve, if any + if (tbcurve) { + bval = tbcurve->getVal (bval); + } + + // store result in a temporary array + dacurve[i] = (aval); + dbcurve[i] = (bval); + dscurve[i] = (sval); } - // store result in a temporary array - dcurve[i] = CLIPD(val); - } - delete tcurve; - - // if skip>1, let apply linear interpolation in the skipped points of the curve - int prev = 0; - for (int i=1; i<=0xffff-skip; i++) { - if (i%skip==0) { - prev+=skip; - continue; + delete tacurve; + delete tbcurve; + + // if skip>1, let apply linear interpolation in the skipped points of the curve + int prev = 0; + for (int i=1; i<=0xffff-skip; i++) { + if (i%skip==0) { + prev+=skip; + continue; + } + dacurve[i] = ( dacurve[prev] * (skip - i%skip) + dacurve[prev+skip] * (i%skip) ) / skip; + dbcurve[i] = ( dbcurve[prev] * (skip - i%skip) + dbcurve[prev+skip] * (i%skip) ) / skip; + dscurve[i] = ( dscurve[prev] * (skip - i%skip) + dscurve[prev+skip] * (i%skip) ) / skip; } - dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; + + for (int i=0; i<=0xffff; i++) { + aoutCurve[i] = (65535.0 * dacurve[i]); + boutCurve[i] = (65535.0 * dbcurve[i]); + satCurve[i] = (65535.0 * dscurve[i]); + } + + delete satcurve; } - - for (int i=0; i<=0xffff; i++) { - outCurve[i] = (65535.0 * dcurve[i]); - //if (i%1000==0) printf("satcurve[%d]= %f\n",i,outCurve[i]); - } - delete [] dcurve; - delete satcurve; -} //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, \ - double shcompr, double br, double contr, double defmul, double gamma_, bool igamma_, \ - const std::vector& curvePoints, unsigned int* histogram, \ - float* hlCurve, float* shCurve, int* outCurve, \ - unsigned int* outBeforeCCurveHistogram, int skip) { + double shcompr, double br, double contr, double gamma_, bool igamma_, \ + const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, \ + LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, \ + LUTu & outBeforeCCurveHistogram, int skip) { - double def_mul = pow (2.0, defmul); - //printf ("def_mul= %f ecomp= %f black= %f hlcompr= %f shcompr= %f br= %f contr= %f defmul= %f gamma= %f, skip= %d \n",def_mul,ecomp,black,hlcompr,shcompr,br,contr,defmul,gamma_,skip); + //double def_mul = pow (2.0, defmul); + + /*printf ("def_mul= %f ecomp= %f black= %f hlcompr= %f shcompr= %f br= %f contr= %f defmul= %f \ + gamma= %f, skip= %d \n",def_mul,ecomp,black,hlcompr,shcompr,br,contr,defmul,gamma_,skip);*/ // compute parameters of the gamma curve - double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); + /*double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; double mul = 1.099; double add = 0.099; + // gamma BT709*/ + + //normalize gamma to sRGB + double start = exp(gamma_*log( -0.055 / ((1.0/gamma_-1.0)*1.055 ))); + double slope = 1.055 * pow (start, 1.0/gamma_-1) - 0.055/start; + double mul = 1.055; + double add = 0.055; // a: slope of the curve, black: starting point at the x axis double a = pow (2.0, ecomp); // curve without contrast - double* dcurve = new double[65536]; + LUTf dcurve(0x10000); // check if contrast curve is needed bool needcontrast = contr>0.00001 || contr<-0.00001; @@ -194,8 +229,7 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); // clear array that stores histogram valid before applying the custom curve - if (outBeforeCCurveHistogram) - memset (outBeforeCCurveHistogram, 0, 256*sizeof(int)); + outBeforeCCurveHistogram.clear(); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery @@ -223,19 +257,20 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat brightcurvePoints.push_back(1); // white point brightcurvePoints.push_back(1); // value at white point - DiagonalCurve* brightcurve = NULL; - brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - float exp_scale = a*def_mul ; + float exp_scale = a; float scale = 65536.0; - float comp = (ecomp + defmul)*hlcompr/100.0; - int shoulder = (int)((scale/exp_scale)*(hlcomprthresh/200.0)); + float comp = (ecomp+1.0)*hlcompr/100.0; + float shoulder = ((scale/exp_scale)*(hlcomprthresh/200.0))+0.1; + //printf("shoulder = %e\n",shoulder); + //printf ("exp_scale= %f comp= %f def_mul=%f a= %f \n",exp_scale,comp,def_mul,a); - for (int i=0; i<=0xffff; i++) { + for (int i=0; i<0x10000; i++) { // change to [0,1] range - double val = (double)i / 65535.0; + float val = (float)i-shoulder; // apply default multiplier (that is >1 if highlight recovery is on) // val *= def_mul; @@ -245,12 +280,12 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat //hlCurve[i] = (65535.0 * CLIPD(val)); - if ((hlcompr>0)&&(exp_scale>1.0)) + if (comp>0.0) { - if (i>shoulder) { - float Y = (float)(i-shoulder)*exp_scale/(scale-shoulder); - float R = (float)(i-shoulder)*comp/(scale-shoulder); - hlCurve[i] = log(1+Y*comp)/R; + if (val>0.0) { + float Y = val*exp_scale/(scale-shoulder); + float R = val*comp/(scale-shoulder); + hlCurve[i] = log(1.0+Y*comp)/R; } else { hlCurve[i]=exp_scale; } @@ -260,18 +295,18 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range - val = (double)i / 65535.0; - - val = basecurve (val, 1, black, 1, 0, 1.5*shcompr/100.0); - - shCurve[i] = (65535.0 * CLIPD(val)); + val = (float)i / 65535.0f; + float val2 = basecurve (val, 1.0, black, 1.0, 0.0, 1.5*shcompr/100.0); + if (i==0) val=1.0; + shCurve[i] = CLIPD(val2)/val; + //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range val = (double)i / 65535.0; // gamma correction - if (gamma_>0) + if (gamma_>1) val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve @@ -289,10 +324,11 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat if (needcontrast) { // compute mean luminance of the image with the curve applied int sum = 0; - double avg = 0; + float avg = 0; //double sqavg = 0; for (int i=0; i<=0xffff; i++) { - avg += dcurve[(int)shCurve[CLIP((int)(hlCurve[i]*i))]] * histogram[i]; + float fi=i; + avg += dcurve[shCurve[hlCurve[i]*fi]*fi] * histogram[i]; //sqavg += dcurve[i]*dcurve[i] * histogram[i]; sum += histogram[i]; } @@ -316,8 +352,7 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat contrastcurvePoints.push_back(1); // white point contrastcurvePoints.push_back(1); // value at white point - DiagonalCurve* contrastcurve = NULL; - contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // apply contrast enhancement @@ -333,12 +368,13 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat // apply custom/parametric/NURBS curve, if any if (tcurve) { - if (outBeforeCCurveHistogram) { - float hval = dcurve[(int)shCurve[CLIP((int)(hlCurve[i]*i))]]; + if (outBeforeCCurveHistogram && histogramCropped) { + float fi=i; + float hval = dcurve[shCurve[hlCurve[i]*fi]*fi]; //if (needigamma) // hval = igamma2 (hval); - int hi = (int)(255.0*CLIPD(hval)); - outBeforeCCurveHistogram[hi]+=histogram[i] ; + int hi = (int)(255.0*(hval)); + outBeforeCCurveHistogram[hi] += histogramCropped[i] ; } val = tcurve->getVal (dcurve[i]); } else { @@ -349,11 +385,10 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat if (needigamma) val = igamma (val, gamma_, start, slope, mul, add); - outCurve[i] = (int) (65535.0 * val + 0.5); + outCurve[i] = (65535.0 * val); } - delete [] dcurve; delete tcurve; delete brightcurve; /*if (outBeforeCCurveHistogram) { @@ -362,27 +397,167 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat } - + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, \ + LUTu & histogram, LUTu & histogramCropped, LUTf & outCurve, \ + LUTu & outBeforeCCurveHistogram, int skip) { + + // curve without contrast + LUTf dcurve(65536,0); + + // check if contrast curve is needed + bool needcontrast = contr>0.00001 || contr<-0.00001; + + // create a curve if needed + DiagonalCurve* tcurve = NULL; + if (curvePoints.size()>0 && curvePoints[0]!=0) + tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); + + // clear array that stores histogram valid before applying the custom curve + if (outBeforeCCurveHistogram) + outBeforeCCurveHistogram.clear(); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + std::vector brightcurvePoints; + brightcurvePoints.push_back((double)((CurveType)DCT_NURBS)); + + brightcurvePoints.push_back(0); // black point. Value in [0 ; 1] range + brightcurvePoints.push_back(0); // black point. Value in [0 ; 1] range + + if (br>0) { + brightcurvePoints.push_back(0.1); // toe point + brightcurvePoints.push_back(0.1+br/150.0); //value at toe point + + brightcurvePoints.push_back(0.7); // shoulder point + brightcurvePoints.push_back(MIN(1.0,0.7+br/300.0)); //value at shoulder point + } else { + brightcurvePoints.push_back(0.1-br/150.0); // toe point + brightcurvePoints.push_back(0.1); // value at toe point + + brightcurvePoints.push_back(MIN(1.0,0.7-br/300.0)); // shoulder point + brightcurvePoints.push_back(0.7); // value at shoulder point + } + brightcurvePoints.push_back(1); // white point + brightcurvePoints.push_back(1); // value at white point + + DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow + + // change to [0,1] range + float val = (float)i / 32767.0; + + // apply brightness curve + val = brightcurve->getVal (val); + + // store result in a temporary array + dcurve[i] = CLIPD(val); + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if (needcontrast) { + // compute mean luminance of the image with the curve applied + int sum = 0; + float avg = 0; + //float sqavg = 0; + for (int i=0; i<32768; i++) { + avg += dcurve[i] * histogram[i]; + //sqavg += dcurve[i]*dcurve[i] * histogram[i]; + sum += histogram[i]; + } + avg /= sum; + //sqavg /= sum; + //float stddev = sqrt(sqavg-avg*avg); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + std::vector contrastcurvePoints; + contrastcurvePoints.push_back((double)((CurveType)DCT_NURBS)); + + contrastcurvePoints.push_back(0); // black point. Value in [0 ; 1] range + contrastcurvePoints.push_back(0); // black point. Value in [0 ; 1] range + + contrastcurvePoints.push_back(avg-avg*(0.6-contr/250.0)); // toe point + contrastcurvePoints.push_back(avg-avg*(0.6+contr/250.0)); // value at toe point + + contrastcurvePoints.push_back(avg+(1-avg)*(0.6-contr/250.0)); // shoulder point + contrastcurvePoints.push_back(avg+(1-avg)*(0.6+contr/250.0)); // value at shoulder point + + contrastcurvePoints.push_back(1); // white point + contrastcurvePoints.push_back(1); // value at white point + + DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // apply contrast enhancement + for (int i=0; i<32768; i++) { + dcurve[i] = contrastcurve->getVal (dcurve[i]); + } + delete contrastcurve; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int i=0; i<32768; i++) { // L values go up to 32767, last stop is for highlight overflow + float val; + + // apply custom/parametric/NURBS curve, if any + if (tcurve) { + if (outBeforeCCurveHistogram) { + float hval = dcurve[i]; + int hi = (int)(255.0*CLIPD(hval)); + outBeforeCCurveHistogram[hi]+=histogramCropped[i] ; + } + val = tcurve->getVal (dcurve[i]); + } else { + val = (dcurve[i]); + } + + outCurve[i] = (32767.0 * val); + } + for (int i=32768; i<65535; i++) outCurve[i]=i; + + + delete tcurve; + delete brightcurve; + /*if (outBeforeCCurveHistogram) { + for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); + }*/ + + } + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + -int *CurveFactory::gammatab = 0; -int *CurveFactory::igammatab_srgb = 0; -int *CurveFactory::gammatab_srgb = 0; +LUTf CurveFactory::gammatab; +LUTf CurveFactory::igammatab_srgb; +LUTf CurveFactory::gammatab_srgb; void CurveFactory::init () { - - gammatab = new int[65536]; - igammatab_srgb = new int[65536]; - gammatab_srgb = new int[65536]; + + gammatab(65536,0); + igammatab_srgb(65536,0); + gammatab_srgb(65536,0); for (int i=0; i<65536; i++) - gammatab_srgb[i] = (int)(65535 * gamma2 (i/65535.0)); + gammatab_srgb[i] = (65535.0 * gamma2 (i/65535.0)); for (int i=0; i<65536; i++) - igammatab_srgb[i] = (int)(65535 * igamma2 (i/65535.0)); + igammatab_srgb[i] = (65535.0 * igamma2 (i/65535.0)); for (int i=0; i<65536; i++) - gammatab[i] = (int)(65535 * pow (i/65535.0, 0.454545)); + gammatab[i] = (65535.0 * pow (i/65535.0, 0.454545)); /* FILE* f = fopen ("c.txt", "wt"); for (int i=0; i<256; i++) @@ -390,11 +565,4 @@ void CurveFactory::init () { fclose (f);*/ } -void CurveFactory::cleanup () { - - delete [] gammatab; - delete [] igammatab_srgb; - delete [] gammatab_srgb; -} - } diff --git a/rtengine/curves.h b/rtengine/curves.h index afc1a682c..75597e14a 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -27,10 +27,15 @@ #include #include +#include "LUT.h" + #define CURVES_MIN_POLY_POINTS 1000 #define SQR(x) ((x)*(x)) +#define CLIPI(a) ((a)>0?((a)<65534?(a):65534):0) + + namespace rtengine { class CurveFactory { @@ -40,10 +45,10 @@ class CurveFactory { protected: // look-up tables for the standard srgb gamma and its inverse (filled by init()) - static int *igammatab_srgb; - static int *gammatab_srgb; + static LUTf igammatab_srgb; + static LUTf gammatab_srgb; // look-up tables for the simple exponential gamma - static int *gammatab; + static LUTf gammatab; // functions calculating the parameters of the contrast curve based on the desired slope at the center static double solve_upper (double m, double c, double deriv); @@ -98,19 +103,19 @@ class CurveFactory { static inline double basecurve (double x, double a, double b, double D, double hr, double sr) { if (b<0) { double m = 0.5; - double slope = 1+b; + double slope = 1.0+b; double y = -b+m*slope; if (x>m) return y + (x - m)*slope; else return y*clower2(x/m, slope*m/y, 2.0-sr); } else { - double slope = a/(1-b); - double m = a*D>1 ? b/a+(0.25)/slope : b+(1-b)/4; - double y = a*D>1 ? 0.25 : (m-b/a)*slope; + double slope = a/(1.0-b); + double m = a*D>1.0 ? b/a+(0.25)/slope : b+(1-b)/4; + double y = a*D>1.0 ? 0.25 : (m-b/a)*slope; if (x<=m) return b==0 ? x*slope : clower (x/m, slope*m/y, sr) * y; - else if (a*D>1) + else if (a*D>1.0) return y+(1.0-y)*cupper2((x-m)/(D-m), slope*(D-m)/(1.0-y), hr); else return y+(x-m)*slope; @@ -125,9 +130,9 @@ class CurveFactory { } // brightness curve at point x, positive negative and zero amount are supported static inline double brightness (double x, double amount) { - if (amount==0) + if (amount==0.0) return x; - else if (amount>0) + else if (amount>0.0) return brightnessbase (x, amount); else return 1.0 - brightnessbase (1.0-x, -amount); @@ -135,9 +140,31 @@ class CurveFactory { public: + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // accurately determine value from integer array with float as index + //linearly interpolate from ends of range if arg is out of bounds + static inline float interp(int *array,float f) + { + int index = CLIPI(floor(f)); + float part = (float)((f)-index)*(float)(array[index+1]-array[index]); + return (float)array[index]+part; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // accurately determine value from float array with float as index + //linearly interpolate from ends of range if arg is out of bounds + static inline float flinterp(float *array,float f) + { + int index = CLIPI(floor(f)); + float part = ((f)-(float)index)*(array[index+1]-array[index]); + return array[index]+part; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% static void init (); static void cleanup (); + + static inline double centercontrast (double x, double b, double m); // standard srgb gamma and its inverse static inline double gamma2 (double x) { @@ -150,21 +177,40 @@ class CurveFactory { static inline double gamma (double x, double gamma, double start, double slope, double mul, double add){ return (x <= start ? x*slope : exp(log(x)/gamma)*mul-add); } - static inline double igamma (double x, double gamma, double start, double slope, double mul, double add){ + static inline double igamma (double x, double gamma, double start, double slope, double mul, double add){ return (x <= start*slope ? x/slope : exp(log((x+add)/mul)*gamma) ); } - - + // gamma functions on [0,65535] based on look-up tables - static inline int gamma_srgb (int x) { return gammatab_srgb[x]; } - static inline int gamma (int x) { return gammatab[x]; } - static inline int igamma_srgb (int x) { return igammatab_srgb[x]; } + static inline float gamma_srgb (int x) { return gammatab_srgb[x]; } + static inline float gamma (int x) { return gammatab[x]; } + static inline float igamma_srgb (int x) { return igammatab_srgb[x]; } + static inline float gamma_srgb (float x) { return gammatab_srgb[x]; } + static inline float gamma (float x) { return gammatab[x]; } + static inline float igamma_srgb (float x) { return igammatab_srgb[x]; } + //static inline float gamma_srgb (double x) { return gammatab_srgb[x]; } + //static inline float gamma (double x) { return gammatab[x]; } + //static inline float igamma_srgb (double x) { return igammatab_srgb[x]; } + + static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) + { + if (comp>0.0) { + float val = level+(hlrange-65536.0); + float Y = val*exp_scale/hlrange; + float R = hlrange/(val*comp); + return log(1.0+Y*comp)*R; + } else { + return exp_scale; + } + } public: -// static void updateCurve3 (int* curve, int* ohistogram, const std::vector& cpoints, double defmul, double ecomp, int black, double hlcompr, double shcompr, double br, double contr, double gamma_, bool igamma, int skip=1); - static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma_, const std::vector& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip=1); - static void complexsgnCurve (double saturation, bool satlimit, double satlimthresh, const std::vector& curvePoints, float* outCurve, int skip=1); - + static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, double gamma_, bool igamma_, const std::vector& curvePoints, + LUTu & histogram, LUTu & histogramCropped, LUTf & hlCurve, LUTf & shCurve,LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip=1); + static void complexsgnCurve (double saturation, bool satlimit, double satlimthresh, const std::vector& acurvePoints, \ + const std::vector& bcurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, int skip=1); + static void complexLCurve (double br, double contr, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, + LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip); }; class Curve { @@ -234,4 +280,6 @@ class FlatCurve : public Curve { }; } +#undef CLIPI + #endif diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 293c30a58..0e6cf5643 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -21,7 +21,7 @@ #include #include #define CLIPTO(a,b,c) ((a)>b?((a) 0)) namespace rtengine { @@ -62,8 +62,12 @@ void Crop::setListener (DetailedCropListener* il) { void Crop::update (int todo) { Glib::Mutex::Lock lock(cropMutex); + //flag for testing color accuracy + bool colortest = false; + ProcParams& params = parent->params; + parent->ipf.setScale (skip); // give possibility to the listener to modify crop window (as the full image dimensions are already known at this point) @@ -72,11 +76,6 @@ void Crop::update (int todo) { if (cropImageListener) overrideWindow = cropImageListener->getWindow (wx, wy, ww, wh, ws); - bool regenHighDetail=false; - if( ws==1 && skip>1 && !parent->fineDetailsProcessed ){ - regenHighDetail=true; - } - // re-allocate sub-images and arrays if their dimensions changed bool needsinitupdate = false; if (!overrideWindow) @@ -87,10 +86,6 @@ void Crop::update (int todo) { if (needsinitupdate) todo = ALL; - /* Seems to be taken care of by calling improccoordinator::updatePreviewImage - if( regenHighDetail ) - parent->updatePreviewImage (ALL,this); // We have just set skip to 1 - */ baseCrop = origCrop; bool needstransform = parent->ipf.needsTransform(); @@ -109,62 +104,121 @@ void Crop::update (int todo) { PreviewProps pp (trafx, trafy, trafw*skip, trafh*skip, skip); parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.hlrecovery, params.icm, params.raw ); - parent->minit.unlock (); + parent->minit.unlock (); } // transform - // Delete transfrom if it's not necessary or outdated - if (transCrop && (!needstransform || transCrop->width!=cropw || transCrop->height!=croph)) { + if ((!needstransform && transCrop) || (transCrop && (transCrop->width!=cropw || transCrop->height!=croph))) { delete transCrop; transCrop = NULL; } - - if ((todo & M_TRANSFORM) && needstransform) { - if (!transCrop) transCrop = new Image16 (cropw, croph); + if (needstransform && !transCrop) + transCrop = new Imagefloat (cropw, croph); + if ((todo & M_TRANSFORM) && needstransform) parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip)); - } - if (transCrop) baseCrop = transCrop; // blurmap for shadow & highlights if ((todo & M_BLURMAP) && params.sh.enabled) { double radius = sqrt (double(SKIPS(parent->fw,skip)*SKIPS(parent->fw,skip)+SKIPS(parent->fh,skip)*SKIPS(parent->fh,skip))) / 2.0; - double shradius = radius / 1800.0 * params.sh.radius; - cshmap->update (baseCrop, (unsigned short**)cbuffer, shradius, parent->ipf.lumimul, params.sh.hq); + double shradius = params.sh.radius; + if (!params.sh.hq) shradius *= radius / 1800.0; + cshmap->update (baseCrop, shradius, parent->ipf.lumimul, params.sh.hq, skip); cshmap->forceStat (parent->shmap->max, parent->shmap->min, parent->shmap->avg); } // shadows & highlights & tone curve & convert to cielab + int xref,yref; + xref=000;yref=000; + if (colortest && cropw>115 && croph>115) + for(int j=1;j<5;j++){ + xref+=j*30;yref+=j*30; + printf("before rgbProc RGB Xr%i Yr%i Skip=%d R=%f G=%f B=%f gamma=%f \n",xref,yref,skip, \ + baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,\ + baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256, \ + baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256, + parent->imgsrc->getGamma()); + } + if (todo & M_RGBCURVE) parent->ipf.rgbProc (baseCrop, laboCrop, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, params.toneCurve.saturation); + xref=000;yref=000; + if (colortest && cropw>115 && croph>115) + for(int j=1;j<5;j++){ + xref+=j*30;yref+=j*30; + printf("after rgbProc RGB Xr%i Yr%i Skip=%d R=%f G=%f B=%f \n",xref,yref,skip, \ + baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,\ + baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256, \ + baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256); + printf("after rgbProc Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, + laboCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327, \ + laboCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327, \ + laboCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327); + } // apply luminance operations if (todo & (M_LUMINANCE+M_COLOR)) { parent->ipf.luminanceCurve (laboCrop, labnCrop, parent->lumacurve); - parent->ipf.chrominanceCurve (laboCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve); + parent->ipf.chrominanceCurve (laboCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve/*, params.labCurve.saturation*/); - parent->ipf.colorCurve (labnCrop, labnCrop); + //parent->ipf.colorCurve (labnCrop, labnCrop); if (skip==1) { parent->ipf.impulsedenoise (labnCrop); parent->ipf.defringe (labnCrop); - parent->ipf.lumadenoise (labnCrop, cbuffer); - parent->ipf.colordenoise (labnCrop, cbuffer); + //parent->ipf.lumadenoise (labnCrop, cbuffer); + //parent->ipf.colordenoise (labnCrop, cbuffer); parent->ipf.dirpyrdenoise (labnCrop); - parent->ipf.sharpening (labnCrop, (unsigned short**)cbuffer); + parent->ipf.sharpening (labnCrop, (float**)cbuffer); parent->ipf.dirpyrequalizer (labnCrop); - parent->ipf.waveletEqualizer(labnCrop, true, true); + //parent->ipf.waveletEqualizer(labnCrop, true, true); } } - // switch back to rgb parent->ipf.lab2rgb (labnCrop, cropImg); + + //parent->ipf.lab2rgb (laboCrop, cropImg); + + //cropImg = baseCrop->to8(); + /* + // int xref,yref; + xref=000;yref=000; + if (colortest && cropw>115 && croph>115) + for(int j=1;j<5;j++){ + xref+=j*30;yref+=j*30; + int rlin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))]/255.0) * 255.0); + int glin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1]/255.0) * 255.0); + int blin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2]/255.0) * 255.0); + printf("after lab2rgb RGB lab2 Xr%i Yr%i Skip=%d R=%d G=%d B=%d \n",xref,yref,skip, \ + rlin,glin,blin); + //cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))], \ + //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1)], \ + //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2)]); + //printf("after lab2rgb Lab lab2 Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327); + printf("after lab2rgb Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, \ + labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327, \ + labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327, \ + labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327); + } + */ + /* + if (colortest && cropImg->height>115 && cropImg->width>115) {//for testing + xref=000;yref=000; + printf("dcrop final R= %d G= %d B= %d \n", \ + cropImg->data[3*xref/(skip)*(cropImg->width+1)], \ + cropImg->data[3*xref/(skip)*(cropImg->width+1)+1], \ + cropImg->data[3*xref/(skip)*(cropImg->width+1)+2]); + } + */ if (cropImageListener) { + // this in workinging space is held in parallel to allow analysis like shadow/highlight + Image8 *cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0,0,cropw,croph, params.icm.working); + int finalW = rqcropw; if (cropImg->getWidth()-leftBorder < finalW) finalW = cropImg->getWidth()-leftBorder; @@ -173,10 +227,15 @@ void Crop::update (int todo) { finalH = cropImg->getHeight()-upperBorder; Image8* final = new Image8 (finalW, finalH); - for (int i=0; idata + 3*i*finalW, cropImg->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW); - cropImageListener->setDetailedCrop (final, params.crop, rqcropx, rqcropy, rqcropw, rqcroph, skip); + memcpy (finaltrue->data + 3*i*finalW, cropImgtrue->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW); + } + cropImageListener->setDetailedCrop (final, finaltrue, params.icm, params.crop, rqcropx, rqcropy, rqcropw, rqcroph, skip); delete final; + delete finaltrue; + delete cropImgtrue; } } @@ -196,8 +255,9 @@ void Crop::freeAll () { delete labnCrop; delete cropImg; delete cshmap; - for (int i=0; iverbose) printf ("setcropsizes before lock\n"); leftBorder = SKIPS(rqx1-bx1,skip); upperBorder = SKIPS(rqy1-by1,skip); - if (settings->verbose) printf ("setsizes starts (%d, %d, %d, %d)\n", orW, orH, trafw, trafh); + if (settings->verbose) + printf ("setsizes starts (%d, %d, %d, %d, %d, %d)\n", orW, orH, trafw, trafh,cw,ch); if (cw!=cropw || ch!=croph || orW!=trafw || orH!=trafh) { @@ -273,15 +334,17 @@ if (settings->verbose) printf ("setcropsizes before lock\n"); trafw = orW; trafh = orH; - origCrop = new Image16 (trafw, trafh); + origCrop = new Imagefloat (trafw, trafh); laboCrop = new LabImage (cropw, croph); labnCrop = new LabImage (cropw, croph); cropImg = new Image8 (cropw, croph); + cshmap = new SHMap (cropw, croph, true); - cbuffer = new int*[croph]; + cbuffer = new float*[croph]; + cbuf_real= new float[(croph+2)*cropw]; for (int i=0; iverbose) printf ("setcropsizes before lock\n"); return changed; } - + // Try a simple, threadless update flag first bool Crop::tryUpdate() { bool needsFullUpdate = true; - + // If there are more update request, the following WHILE will collect it - if (updating) { - needsNext = true; - needsFullUpdate = false; - } else updating = true; - + if (updating) { + needsNext = true; + needsFullUpdate = false; + } else updating = true; + return needsFullUpdate; - } +} // Full update, should be called via thread void Crop::fullUpdate () { diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index d39714344..be53bdfee 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -36,11 +36,13 @@ class ImProcCoordinator; class Crop : public DetailedCrop { protected: - Image16* origCrop, *resizeCrop, *transCrop, *baseCrop; + Imagefloat* origCrop, *baseCrop; + Imagefloat* *resizeCrop, *transCrop; LabImage *laboCrop, *labnCrop; - Image8 *cropImg; + Image8 *cropImg; // permanently allocated in RAM and only renewed on size changes - int** cbuffer; + float** cbuffer; + float * cbuf_real; SHMap* cshmap; bool updating, needsNext; @@ -66,10 +68,10 @@ class Crop : public DetailedCrop { bool hasListener () { return cropImageListener; } void update (int todo); void setWindow (int cx, int cy, int cw, int ch, int skip) { setCropSizes (cx, cy, cw, ch, skip, false); } - + bool tryUpdate (); // First try, only make fullUpdate if this returns false void fullUpdate (); // called via thread - + void setListener (DetailedCropListener* il); void destroy () { delete this; } int get_skip () { return skip;} diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc new file mode 100644 index 000000000..9aedf00dc --- /dev/null +++ b/rtengine/demosaic_algos.cc @@ -0,0 +1,1654 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#ifdef _OPENMP +#include +#endif + +namespace rtengine { + +#undef ABS +#undef MAX +#undef MIN +#undef DIST + +#define ABS(a) ((a)<0?-(a):(a)) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define DIST(a,b) (ABS(a-b)) + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void RawImageSource::eahd_demosaic () { + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + // prepare cache and constants for cielab conversion + //TODO: revisit after conversion to D50 illuminant + lc00 = (0.412453 * rgb_cam[0][0] + 0.357580 * rgb_cam[0][1] + 0.180423 * rgb_cam[0][2]) ;// / 0.950456; + lc01 = (0.412453 * rgb_cam[1][0] + 0.357580 * rgb_cam[1][1] + 0.180423 * rgb_cam[1][2]) ;// / 0.950456; + lc02 = (0.412453 * rgb_cam[2][0] + 0.357580 * rgb_cam[2][1] + 0.180423 * rgb_cam[2][2]) ;// / 0.950456; + + lc10 = 0.212671 * rgb_cam[0][0] + 0.715160 * rgb_cam[0][1] + 0.072169 * rgb_cam[0][2]; + lc11 = 0.212671 * rgb_cam[1][0] + 0.715160 * rgb_cam[1][1] + 0.072169 * rgb_cam[1][2]; + lc12 = 0.212671 * rgb_cam[2][0] + 0.715160 * rgb_cam[2][1] + 0.072169 * rgb_cam[2][2]; + + lc20 = (0.019334 * rgb_cam[0][0] + 0.119193 * rgb_cam[0][1] + 0.950227 * rgb_cam[0][2]) ;// / 1.088754; + lc21 = (0.019334 * rgb_cam[1][0] + 0.119193 * rgb_cam[1][1] + 0.950227 * rgb_cam[1][2]) ;// / 1.088754; + lc22 = (0.019334 * rgb_cam[2][0] + 0.119193 * rgb_cam[2][1] + 0.950227 * rgb_cam[2][2]) ;// / 1.088754; + + int maxindex = 2*65536; + cache = new double[maxindex]; + threshold = (int)(0.008856*MAXVAL); + for (int i=0; isv) { // fixate horizontal pixel + dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]); + dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]); + dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]); + dLmapv[dmi] = DIST(lLv[ix][j], lLh[idx][j+y]); + dCamapv[dmi] = DIST(lav[ix][j], lah[idx][j+y]); + dCbmapv[dmi] = DIST(lbv[ix][j], lbh[idx][j+y]); + } + else if (shISGREEN(i-1,j)) + green[i-1][j] = rawData[i-1][j]; + else { + hc = homh[imx][j]; + vc = homv[imx][j]; + if (hc > vc) + green[i-1][j] = gh[(i-1)%4][j]; + else if (hc < vc) + green[i-1][j] = gv[(i-1)%4][j]; + else + green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; + } + } + + if (!(i%20) && plistener) + plistener->setProgress ((double)i / (H-2)); + } + // finish H-2th and H-1th row, homogenity value is still valailable + int hc, vc; + for (int i=H-1; i vc) + green[i-1][j] = gh[(i-1)%4][j]; + else if (hc < vc) + green[i-1][j] = gv[(i-1)%4][j]; + else + green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; + } + + freeArray2(rh, 3); + freeArray2(gh, 4); + freeArray2(bh, 3); + freeArray2(rv, 3); + freeArray2(gv, 4); + freeArray2(bv, 3); + freeArray2(lLh, 3); + freeArray2(lah, 3); + freeArray2(lbh, 3); + freeArray2(homh, 3); + freeArray2(lLv, 3); + freeArray2(lav, 3); + freeArray2(lbv, 3); + freeArray2(homv, 3); + + // Interpolate R and B + for (int i=0; iISGREEN(i,j)) + green[i][j] = rawData[i][j]; + else { + if (hpmap[i][j]==1) { + int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2); + int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2); + + int dx = rawData[i][j+1] - rawData[i][j-1]; + int d1 = rawData[i][j+3] - rawData[i][j+1]; + int d2 = rawData[i][j+2] - rawData[i][j]; + int d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2; + int d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2; + + double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = rawData[i][j-3] - rawData[i][j-1]; + d2 = rawData[i][j-2] - rawData[i][j]; + d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2; + d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2; + + double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e2 * g2 + e4 * g4) / (e2 + e4)); + } + else if (hpmap[i][j]==2) { + int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2); + int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2); + + int dy = rawData[i+1][j] - rawData[i-1][j]; + int d1 = rawData[i-1][j] - rawData[i-3][j]; + int d2 = rawData[i][j] - rawData[i-2][j]; + int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2; + int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2; + + double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = rawData[i+1][j] - rawData[i+3][j]; + d2 = rawData[i][j] - rawData[i+2][j]; + d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2; + d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2; + + double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e1 * g1 + e3 * g3) / (e1 + e3)); + } + else { + int g1 = rawData[i-1][j] + ((rawData[i][j] - rawData[i-2][j]) /2); + int g2 = rawData[i][j+1] + ((rawData[i][j] - rawData[i][j+2]) /2); + int g3 = rawData[i+1][j] + ((rawData[i][j] - rawData[i+2][j]) /2); + int g4 = rawData[i][j-1] + ((rawData[i][j] - rawData[i][j-2]) /2); + + int dx = rawData[i][j+1] - rawData[i][j-1]; + int dy = rawData[i+1][j] - rawData[i-1][j]; + + int d1 = rawData[i-1][j] - rawData[i-3][j]; + int d2 = rawData[i][j] - rawData[i-2][j]; + int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) /2; + int d4 = (rawData[i][j+1] - rawData[i-2][j+1]) /2; + + double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = rawData[i][j+3] - rawData[i][j+1]; + d2 = rawData[i][j+2] - rawData[i][j]; + d3 = (rawData[i-1][j+2] - rawData[i-1][j]) /2; + d4 = (rawData[i+1][j+2] - rawData[i+1][j]) /2; + + double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = rawData[i+1][j] - rawData[i+3][j]; + d2 = rawData[i][j] - rawData[i+2][j]; + d3 = (rawData[i][j-1] - rawData[i+2][j-1]) /2; + d4 = (rawData[i][j+1] - rawData[i+2][j+1]) /2; + + double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = rawData[i][j-3] - rawData[i][j-1]; + d2 = rawData[i][j-2] - rawData[i][j]; + d3 = (rawData[i-1][j-2] - rawData[i-1][j]) /2; + d4 = (rawData[i+1][j-2] - rawData[i+1][j]) /2; + + double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e1*g1 + e2*g2 + e3*g3 + e4*g4) / (e1 + e2 + e3 + e4)); + } + } + } + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void RawImageSource::hphd_demosaic () { + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + float** hpmap = new float*[H]; + for (int i=0; isetProgress (0.33); + + for (int i=0; i(hpmap, H); + + if (plistener) + plistener->setProgress (0.66); + + for (int i=0; isetProgress (1.0); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +#define FORCC for (c=0; c < colors; c++) +#define fc(row,col) \ + (ri->prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) +typedef unsigned short ushort; +void RawImageSource::vng4_demosaic () { + + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + float (*brow[5])[4], *pix; + int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c, width=W, height=H, colors=4; + float (*image)[4]; + int lcode[16][16][32], shift, i, j; + + image = (float (*)[4]) calloc (H*W, sizeof *image); + for (int ii=0; ii gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax /2); + memset (sum, 0, sizeof sum); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) /2; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + if (!(row%20) && plistener) + plistener->setProgress ((double)row / (H-2)); + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); + free (code[0][0]); + + for (int i=0; iget_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) + +/* + Patterned Pixel Grouping Interpolation by Alain Desbiolles +*/ +void RawImageSource::ppg_demosaic() +{ + int width=W, height=H; + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2], guess[2], c, d, i; + float (*pix)[4]; + + float (*image)[4]; + int colors = 3; + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + image = (float (*)[4]) calloc (H*W, sizeof *image); + for (int ii=0; ii 0; i++) { + guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 + - pix[-2*d][c] - pix[2*d][c]; + diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + + ABS(pix[ 2*d][c] - pix[ 0][c]) + + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + + ( ABS(pix[ 3*d][1] - pix[ d][1]) + + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; + } + d = dir[i = diff[0] > diff[1]]; + pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); + } + if(plistener) plistener->setProgress(0.33*row/(height-3)); + } +/* Calculate red and blue for each green pixel: */ + for (row=1; row < height-1; row++) { + for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; c=2-c, i++) + pix[0][c] = CLIP(0.5*(pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]) ); + } + if(plistener) plistener->setProgress(0.33 + 0.33*row/(height-1)); + } +/* Calculate blue for red pixels and vice versa: */ + for (row=1; row < height-1; row++) { + for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { + diff[i] = ABS(pix[-d][c] - pix[d][c]) + + ABS(pix[-d][1] - pix[0][1]) + + ABS(pix[ d][1] - pix[0][1]); + guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]; + } + if (diff[0] != diff[1]) + pix[0][c] = CLIP(guess[diff[0] > diff[1]] /2); + else + pix[0][c] = CLIP((guess[0]+guess[1]) /4); + } + if(plistener) plistener->setProgress(0.67 + 0.33*row/(height-1)); + } + + red = new float*[H]; + for (int i=0; i= border && row < height-border) + col = width-border; + memset (sum, 0, sizeof sum); + for (y=row-1; y != row+2; y++) + for (x=col-1; x != col+2; x++) + if (y < height && x < width) { + f = fc(y,x); + sum[f] += image[y*width+x][f]; + sum[f+4]++; + } + f = fc(row,col); + FORCC if (c != f && sum[c+4]) + image[row*width+col][c] = sum[c] / sum[c+4]; + } +} + + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +#define TS 256 /* Tile Size */ +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define SQR(x) ((x)*(x)) + +void RawImageSource::ahd_demosaic(int winx, int winy, int winw, int winh) +{ + int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; + float (*pix)[4], (*rix)[3]; + static const int dir[4] = { -1, 1, -TS, TS }; + float ldiff[2][4], abdiff[2][4], leps, abeps; + float r, xyz[3], xyz_cam[3][4]; + float (*cbrt); + float (*rgb)[TS][TS][3]; + float (*lab)[TS][TS][3]; + float (*lix)[3]; + char (*homo)[TS][TS], *buffer; + + int width=W, height=H; + float (*image)[4]; + int colors = 3; + + const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } + }; + + const float d65_white[3] = { 0.950456, 1, 1.088754 }; + const float d50_white[3] = { 0.96422, 1, 0.82521 }; + + if (plistener) { + plistener->setProgressStr ("AHD Demosaicing..."); + plistener->setProgress (0.0); + } + + image = (float (*)[4]) calloc (H*W, sizeof *image); + for (int ii=0; ii 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; + } + + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + + border_interpolate(5, image); + buffer = (char *) malloc (13*TS*TS*sizeof(float)); /* 1664 kB */ + //merror (buffer, "ahd_interpolate()"); + rgb = (float(*)[TS][TS][3]) buffer; + lab = (float(*)[TS][TS][3])(buffer + 6*TS*TS*sizeof(float)); + homo = (char (*)[TS][TS]) (buffer + 12*TS*TS*sizeof(float)); + + // helper variables for progress indication + int n_tiles = ((height-7 + (TS-7))/(TS-6)) * ((width-7 + (TS-7))/(TS-6)); + int tile = 0; + + for (top=2; top < height-5; top += TS-6) + for (left=2; left < width-5; left += TS-6) { + + /* Interpolate green horizontally and vertically: */ + for (row = top; row < top+TS && row < height-2; row++) { + col = left + (FC(row,left) & 1); + for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { + pix = image + (row*width+col); + val = 0.25*((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 + - pix[-2][c] - pix[2][c]) ; + rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); + val = 0.25*((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 + - pix[-2*width][c] - pix[2*width][c]) ; + rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); + } + } + + /* Interpolate red and blue, and convert to CIELab: */ + for (d=0; d < 2; d++) + for (row=top+1; row < top+TS-1 && row < height-3; row++) + for (col=left+1; col < left+TS-1 && col < width-3; col++) { + pix = image + (row*width+col); + rix = &rgb[d][row-top][col-left]; + lix = &lab[d][row-top][col-left]; + if ((c = 2 - FC(row,col)) == 1) { + c = FC(row+1,col); + val = pix[0][1] + (0.5*( pix[-1][2-c] + pix[1][2-c] + - rix[-1][1] - rix[1][1] ) ); + rix[0][2-c] = CLIP(val); + val = pix[0][1] + (0.5*( pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1] ) ); + } else + val = rix[0][1] + (0.25*( pix[-width-1][c] + pix[-width+1][c] + + pix[+width-1][c] + pix[+width+1][c] + - rix[-TS-1][1] - rix[-TS+1][1] + - rix[+TS-1][1] - rix[+TS+1][1] + 1) ); + rix[0][c] = CLIP(val); + c = FC(row,col); + rix[0][c] = pix[0][c]; + xyz[0] = xyz[1] = xyz[2] = 0.0; + FORCC { + xyz[0] += xyz_cam[0][c] * rix[0][c]; + xyz[1] += xyz_cam[1][c] * rix[0][c]; + xyz[2] += xyz_cam[2][c] * rix[0][c]; + } + + xyz[0] = CurveFactory::flinterp(cbrt,xyz[0]); + xyz[1] = CurveFactory::flinterp(cbrt,xyz[1]); + xyz[2] = CurveFactory::flinterp(cbrt,xyz[2]); + + //xyz[0] = xyz[0] > 0.008856 ? pow(xyz[0]/65535,1/3.0) : 7.787*xyz[0] + 16/116.0; + //xyz[1] = xyz[1] > 0.008856 ? pow(xyz[1]/65535,1/3.0) : 7.787*xyz[1] + 16/116.0; + //xyz[2] = xyz[2] > 0.008856 ? pow(xyz[2]/65535,1/3.0) : 7.787*xyz[2] + 16/116.0; + + lix[0][0] = (116 * xyz[1] - 16); + lix[0][1] = 500 * (xyz[0] - xyz[1]); + lix[0][2] = 200 * (xyz[1] - xyz[2]); + } + + /* Build homogeneity maps from the CIELab images: */ + memset (homo, 0, 2*TS*TS); + for (row=top+2; row < top+TS-2 && row < height-4; row++) { + tr = row-top; + for (col=left+2; col < left+TS-2 && col < width-4; col++) { + tc = col-left; + for (d=0; d < 2; d++) { + lix = &lab[d][tr][tc]; + for (i=0; i < 4; i++) { + ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); + abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + + SQR(lix[0][2]-lix[dir[i]][2]); + } + } + leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), + MAX(ldiff[1][2],ldiff[1][3])); + abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), + MAX(abdiff[1][2],abdiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } + + /* Combine the most homogenous pixels for the final result: */ + for (row=top+3; row < top+TS-3 && row < height-5; row++) { + tr = row-top; + for (col=left+3; col < left+TS-3 && col < width-5; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (hm[d]=0, i=tr-1; i <= tr+1; i++) + for (j=tc-1; j <= tc+1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row*width+col][c] = + 0.5*(rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) ; + } + } + + tile++; + if(plistener) { + plistener->setProgress((double)tile / n_tiles); + } + } + + if(plistener) plistener->setProgress (1.0); + free (buffer); + for (int i=0; i= H-border) rowMax = TILEBORDER+H-border-y0; + if( x0+TILESIZE+TILEBORDER >= W-border) colMax = TILEBORDER+W-border-x0; +} + +void RawImageSource::fill_raw( float (*cache )[4], int x0, int y0, float** rawData) +{ + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,0); + + for (int row=rowMin,y=y0-TILEBORDER+rowMin; row= border && col < W - border && row >= border && row < H - border){ + col = W - border; + if(col >= x0+TILESIZE+TILEBORDER ) + break; + } + memset(sum, 0, sizeof sum); + for (y = row - 1; y != row + 2; y++) + for (x = col - 1; x != col + 2; x++) + if (y < H && y< y0+TILESIZE+TILEBORDER && x < W && x ( pix[-4] + pix[+4] + pix[-u] + pix[+u])/4 ) + image[indx][3] = ((MIN( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) < (MIN( pix[-u], pix[+u]) + pix[-u] + pix[+u])); + else + image[indx][3] = ((MAX( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) > (MAX( pix[-u], pix[+u]) + pix[-u] + pix[+u])); + } + } +} + + +// interpolated green pixels are corrected using the map +void RawImageSource::dcb_correction(float (*image)[4], int x0, int y0) +{ + const int u=CACHESIZE, v=2*CACHESIZE; + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); + + for (int row=rowMin; row < rowMax; row++) { + for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { + int current = 4*image[indx][3] + + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + + image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; + image[indx][1] = ((16-current)*(image[indx-1][1] + image[indx+1][1])/2 + current*(image[indx-u][1] + image[indx+u][1])/2)/16; + } + } +} + +// R and B smoothing using green contrast, all pixels except 2 pixel wide border +void RawImageSource::dcb_pp(float (*image)[4], int x0, int y0) +{ + const int u=CACHESIZE; + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); + + for (int row=rowMin; row < rowMax; row++) + for (int col=colMin, indx=row*CACHESIZE+col; col < colMax; col++, indx++) { + //int r1 = ( image[indx-1][0] + image[indx+1][0] + image[indx-u][0] + image[indx+u][0] + image[indx-u-1][0] + image[indx+u+1][0] + image[indx-u+1][0] + image[indx+u-1][0])/8; + //int g1 = ( image[indx-1][1] + image[indx+1][1] + image[indx-u][1] + image[indx+u][1] + image[indx-u-1][1] + image[indx+u+1][1] + image[indx-u+1][1] + image[indx+u-1][1])/8; + //int b1 = ( image[indx-1][2] + image[indx+1][2] + image[indx-u][2] + image[indx+u][2] + image[indx-u-1][2] + image[indx+u+1][2] + image[indx-u+1][2] + image[indx+u-1][2])/8; + float (*pix)[4] = image+(indx-u-1); + int r1 = (*pix)[0]; + int g1 = (*pix)[1]; + int b1 = (*pix)[2]; + pix++; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix++; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix+=CACHESIZE-2; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix+=2; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix+=CACHESIZE-2; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix++; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + pix++; + r1 += (*pix)[0]; + g1 += (*pix)[1]; + b1 += (*pix)[2]; + r1 /=8; + g1 /=8; + b1 /=8; + r1 = r1 + ( image[indx][1] - g1 ); + b1 = b1 + ( image[indx][1] - g1 ); + image[indx][0] = CLIP(r1); + image[indx][2] = CLIP(b1); + } +} + +// interpolated green pixels are corrected using the map +// with correction +void RawImageSource::dcb_correction2(float (*image)[4], int x0, int y0) +{ + const int u=CACHESIZE, v=2*CACHESIZE; + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4); + + for (int row=rowMin; row < rowMax; row++) { + for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { + int current = 4*image[indx][3] + + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + + image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; + current = ((16-current)*((image[indx-1][1] + image[indx+1][1])/2 + image[indx][c] - (image[indx+2][c] + image[indx-2][c])/2) + current*((image[indx-u][1] + image[indx+u][1])/2 + image[indx][c] - (image[indx+v][c] + image[indx-v][c])/2))/16; + image[indx][1] = CLIP(current); + } + } +} + +// image refinement +void RawImageSource::dcb_refinement(float (*image)[4], int x0, int y0) +{ + const int u=CACHESIZE, v=2*CACHESIZE, w=3*CACHESIZE; + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4); + + float f[5],g1,g2; + + for (int row=rowMin; row < rowMax; row++) + for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2,indx+=2){ + int current = 4*image[indx][3] + + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + +image[indx+v][3] + image[indx-v][3] + image[indx-2][3] + image[indx+2][3]; + + f[0] = (float)(image[indx-u][1] + image[indx+u][1])/(2 + 2*image[indx][c]); + f[1] = 2*(float)image[indx-u][1]/(2 + image[indx-v][c] + image[indx][c]); + f[2] = (float)(image[indx-u][1] + image[indx-w][1])/(2 + 2*image[indx-v][c]); + f[3] = 2*(float)image[indx+u][1]/(2 + image[indx+v][c] + image[indx][c]); + f[4] = (float)(image[indx+u][1] + image[indx+w][1])/(2 + 2*image[indx+v][c]); + + g1 = (f[0] + f[1] + f[2] + f[3] + f[4] - MAX(f[1], MAX(f[2], MAX(f[3], f[4]))) - MIN(f[1], MIN(f[2], MIN(f[3], f[4]))))/3.0; + + f[0] = (float)(image[indx-1][1] + image[indx+1][1])/(2 + 2*image[indx][c]); + f[1] = 2*(float)image[indx-1][1]/(2 + image[indx-2][c] + image[indx][c]); + f[2] = (float)(image[indx-1][1] + image[indx-3][1])/(2 + 2*image[indx-2][c]); + f[3] = 2*(float)image[indx+1][1]/(2 + image[indx+2][c] + image[indx][c]); + f[4] = (float)(image[indx+1][1] + image[indx+3][1])/(2 + 2*image[indx+2][c]); + + g2 = (f[0] + f[1] + f[2] + f[3] + f[4] - MAX(f[1], MAX(f[2], MAX(f[3], f[4]))) - MIN(f[1], MIN(f[2], MIN(f[3], f[4]))))/3.0; + + image[indx][1] = CLIP((2+image[indx][c])*(current*g1 + (16-current)*g2)/16.0); + +// get rid of the overshooted pixels + int min = MIN(image[indx+1+u][1], MIN(image[indx+1-u][1], MIN(image[indx-1+u][1], MIN(image[indx-1-u][1], MIN(image[indx-1][1], MIN(image[indx+1][1], MIN(image[indx-u][1], image[indx+u][1]))))))); + int max = MAX(image[indx+1+u][1], MAX(image[indx+1-u][1], MAX(image[indx-1+u][1], MAX(image[indx-1-u][1], MAX(image[indx-1][1], MAX(image[indx+1][1], MAX(image[indx-u][1], image[indx+u][1]))))))); + + image[indx][1] = LIM(image[indx][1], min, max); + + + } +} + +// missing colors are interpolated using high quality algorithm by Luis Sanz Rodr‚àö‚â†guez +void RawImageSource::dcb_color_full(float (*image)[4], int x0, int y0, float (*chroma)[2]) +{ + const int u=CACHESIZE, v=2*CACHESIZE, w=3*CACHESIZE; + int rowMin,colMin,rowMax,colMax; + dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,3); + + int i,j; + float f[4],g[4]; + + for (int row=1; row < CACHESIZE-1; row++) + for (int col=1+(FC(y0-TILEBORDER+row,x0-TILEBORDER+1)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col),d=c/2; col < CACHESIZE-1; col+=2,indx+=2) + chroma[indx][d]=image[indx][c]-image[indx][1]; + + for (int row=rowMin; rowsetProgressStr ("DCB Demosaicing..."); + plistener->setProgress (currentProgress); + } + + int wTiles = W/TILESIZE + (W%TILESIZE?1:0); + int hTiles = H/TILESIZE + (H%TILESIZE?1:0); + int numTiles = wTiles * hTiles; + int tilesDone=0; +#ifdef _OPENMP + int nthreads = omp_get_max_threads(); + float (**image)[4] = (float(**)[4]) calloc( nthreads,sizeof( void*) ); + float (**image2)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) ); + float (**image3)[3] = (float(**)[3]) calloc( nthreads,sizeof( void*) ); + float (**chroma)[2] = (float (**)[2]) calloc( nthreads,sizeof( void*) ); + for(int i=0; i0;i--) { + dcb_hid2(tile,x0,y0); + dcb_hid2(tile,x0,y0); + dcb_hid2(tile,x0,y0); + dcb_map(tile,x0,y0); + dcb_correction(tile,x0,y0); + } + dcb_color(tile,x0,y0); + dcb_pp(tile,x0,y0); + dcb_map(tile,x0,y0); + dcb_correction2(tile,x0,y0); + dcb_map(tile,x0,y0); + dcb_correction(tile,x0,y0); + dcb_color(tile,x0,y0); + dcb_map(tile,x0,y0); + dcb_correction(tile,x0,y0); + dcb_map(tile,x0,y0); + dcb_correction(tile,x0,y0); + dcb_map(tile,x0,y0); + restore_from_buffer(tile, buffer); + dcb_color(tile,x0,y0); + if (dcb_enhance) { + dcb_refinement(tile,x0,y0); + dcb_color_full(tile,x0,y0,chrm); + } + + for(int y=0;y currentProgress){ + currentProgress+=0.1; // Show progress each 10% + plistener->setProgress (currentProgress); + } + } +#pragma omp atomic + tilesDone++; + } + +#ifdef _OPENMP + for(int i=0; isetProgress (1.0); +} +#undef TILEBORDER +#undef TILESIZE +#undef CACHESIZE + + + +} /* namespace */ + + diff --git a/rtengine/dirpyrLab_denoise.cc b/rtengine/dirpyrLab_denoise.cc index 1dcb7d327..30a8b0f3b 100644 --- a/rtengine/dirpyrLab_denoise.cc +++ b/rtengine/dirpyrLab_denoise.cc @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef _OPENMP #include @@ -35,22 +36,39 @@ #define CLIP(a) (CLIPTO(a,0,65535)) +#define DIRWT_L(i1,j1,i,j) ( rangefn_L[(data_fine->L[i1][j1]-data_fine->L[i][j]+32768)] ) -#define DIRWT_L(i1,j1,i,j) (/*domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin] */ rangefn_L[(int)(data_fine->L[i1][j1]-data_fine->L[i][j]+0x10000)] ) +#define DIRWT_AB(i1,j1,i,j) ( rangefn_ab[(data_fine->a[i1][j1]-data_fine->a[i][j]+32768)] * \ +rangefn_ab[(data_fine->L[i1][j1]-data_fine->L[i][j]+32768)] * \ +rangefn_ab[(data_fine->b[i1][j1]-data_fine->b[i][j]+32768)] ) -#define DIRWT_AB(i1,j1,i,j) ( /*domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin]*/ rangefn_ab[(int)(data_fine->a[i1][j1]-data_fine->a[i][j]+0x10000)] * \ -rangefn_ab[(int)(data_fine->L[i1][j1]-data_fine->L[i][j]+0x10000)] * \ -rangefn_ab[(int)(data_fine->b[i1][j1]-data_fine->b[i][j]+0x10000)] ) +//#define NRWT_L(a) (nrwt_l[a] ) -#define NRWT_L(a) (nrwt_l[a] ) +#define NRWT_AB (nrwt_ab[(hipass[1]+32768)] * nrwt_ab[(hipass[2]+32768)]) -#define NRWT_AB (nrwt_ab[(int)((hipass[1]+0x10000))] * nrwt_ab[(int)((hipass[2]+0x10000))]) +#define med3(a,b,c) (a(b)) {temp=(a);(a)=(b);(b)=temp;} } + +#define med3x3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \ +p[0]=a0; p[1]=a1; p[2]=a2; p[3]=a3; p[4]=a4; p[5]=a5; p[6]=a6; p[7]=a7; p[8]=a8; \ +PIX_SORT(p[1],p[2]); PIX_SORT(p[4],p[5]); PIX_SORT(p[7],p[8]); \ +PIX_SORT(p[0],p[1]); PIX_SORT(p[3],p[4]); PIX_SORT(p[6],p[7]); \ +PIX_SORT(p[1],p[2]); PIX_SORT(p[4],p[5]); PIX_SORT(p[7],p[8]); \ +PIX_SORT(p[0],p[3]); PIX_SORT(p[5],p[8]); PIX_SORT(p[4],p[7]); \ +PIX_SORT(p[3],p[6]); PIX_SORT(p[1],p[4]); PIX_SORT(p[2],p[5]); \ +PIX_SORT(p[4],p[7]); PIX_SORT(p[4],p[2]); PIX_SORT(p[6],p[4]); \ +PIX_SORT(p[4],p[2]); median=p[4];} //a4 is the median namespace rtengine { - static const int maxlevel = 4; + static const int maxlevel = 3; //sequence of scales //static const int scales[8] = {1,2,4,8,16,32,64,128}; @@ -82,23 +100,40 @@ namespace rtengine { - void ImProcFunctions :: dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma, float gam ) + void ImProcFunctions :: dirpyrLab_denoise(LabImage * src, LabImage * dst, const procparams::DirPyrDenoiseParams & dnparams ) { + float gam = dnparams.gamma/3.0; //float gam = 2.0;//MIN(3.0, 0.1*fabs(c[4])/3.0+0.001); float gamthresh = 0.03; float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - unsigned short * gamcurve = new unsigned short [65536]; + + LUTf gamcurve(65536,0); + + //DiagonalCurve* lumacurve = new DiagonalCurve (dnparams.lumcurve, CURVES_MIN_POLY_POINTS); + //DiagonalCurve* chromacurve = new DiagonalCurve (dnparams.chromcurve, CURVES_MIN_POLY_POINTS); + //LUTf Lcurve(65536); + //LUTf abcurve(65536); for (int i=0; i<65536; i++) { int g = (int)(CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) * 65535.0); - //if (i<500) printf("%d %d \n",i,g); gamcurve[i] = CLIP(g); + /*float val = (float)i/65535.0; + float Lval = (2*(lumacurve->getVal(val))); + float abval = (2*(chromacurve->getVal(val))); + + Lcurve[i] = SQR(Lval); + abcurve[i] = SQR(abval); + if (i % 1000 ==0) printf("%d Lmult=%f abmult=%f \n",i,Lcurve[i],abcurve[i]);*/ } + //delete lumacurve; + //delete chromacurve; + //#pragma omp parallel for if (multiThread) for (int i=0; iH; i++) { for (int j=0; jW; j++) { - src->L[i][j] = gamcurve[src->L[i][j] ]; + //src->L[i][j] = CurveFactory::flinterp(gamcurve,src->L[i][j]); + src->L[i][j] = gamcurve[src->L[i][j]]; } } @@ -106,22 +141,18 @@ namespace rtengine { - int * rangefn_L = new int [0x20000]; - float * nrwt_l = new float [0x10000]; - - - int * rangefn_ab = new int [0x20000]; - float * nrwt_ab = new float [0x20000]; - - int intfactor = 1024;//16384; + LUTf rangefn_L(65536); + LUTf nrwt_l(65536); + LUTf rangefn_ab(65536); + LUTf nrwt_ab(65536); //set up NR weight functions //gamma correction for chroma in shadows float nrwtl_norm = ((CurveFactory::gamma((double)65535.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) - \ (CurveFactory::gamma((double)75535.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0))); - for (int i=0; i<0x10000; i++) { + for (int i=0; i<65536; i++) { nrwt_l[i] = ((CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) - \ CurveFactory::gamma((double)(i+10000)/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) )/nrwtl_norm; //if (i % 100 ==0) printf("%d %f \n",i,nrwt_l[i]); @@ -129,22 +160,22 @@ namespace rtengine { float tonefactor = nrwt_l[32768]; - float noise_L = 25.0*luma; - float noisevar_L = 4*SQR(noise_L); + float noise_L = 10.0*dnparams.luma; + float noisevar_L = SQR(noise_L); - float noise_ab = 25*chroma; + float noise_ab = 25.0*dnparams.chroma; float noisevar_ab = SQR(noise_ab); //set up range functions - for (int i=0; i<0x20000; i++) - rangefn_L[i] = (int)(( exp(-(double)fabs(i-0x10000) * tonefactor / (1+3*noise_L)) * noisevar_L/((double)(i-0x10000)*(double)(i-0x10000) + noisevar_L))*intfactor); - for (int i=0; i<0x20000; i++) - rangefn_ab[i] = (int)(( exp(-(double)fabs(i-0x10000) * tonefactor / (1+3*noise_ab)) * noisevar_ab/((double)(i-0x10000)*(double)(i-0x10000) + noisevar_ab))*intfactor); + for (int i=0; i<65536; i++) + rangefn_L[i] = (( exp(-(double)fabs(i-32768) * tonefactor / (1.0+noise_L)) * (1.0+noisevar_L)/((double)(i-32768)*(double)(i-32768) + noisevar_L+1.0))); + for (int i=0; i<65536; i++) + rangefn_ab[i] = (( exp(-(double)fabs(i-32768) * tonefactor / (1.0+3*noise_ab)) * (1.0+noisevar_ab)/((double)(i-32768)*(double)(i-32768) + noisevar_ab+1.0))); - for (int i=0; i<0x20000; i++) - nrwt_ab[i] = ((1+abs(i-0x10000)/(1+8*noise_ab)) * exp(-(double)fabs(i-0x10000)/ (1+8*noise_ab) ) ); + for (int i=0; i<65536; i++) + nrwt_ab[i] = ((1.0+abs(i-32768)/(1.0+8*noise_ab)) * exp(-(double)fabs(i-32768)/ (1.0+8*noise_ab) ) ); //for (int i=0; i<65536; i+=100) printf("%d %d \n",i,gamcurve[i]); @@ -184,7 +215,7 @@ namespace rtengine { //int thresh = 10 * c[8]; //impulse_nr (src, src, m_w1, m_h1, thresh, noisevar); - dirpyr(src, dirpyrLablo[0], 0, rangefn_L, rangefn_ab, pitch, scale, luma, chroma ); + dirpyr(src, dirpyrLablo[0], 0, rangefn_L, rangefn_ab, pitch, scale, dnparams.luma, dnparams.chroma ); level = 1; @@ -193,7 +224,7 @@ namespace rtengine { scale = scales[level]; pitch = pitches[level]; - dirpyr(dirpyrLablo[level-1], dirpyrLablo[level], level, rangefn_L, rangefn_ab, pitch, scale, luma, chroma ); + dirpyr(dirpyrLablo[level-1], dirpyrLablo[level], level, rangefn_L, rangefn_ab, pitch, scale, dnparams.luma, dnparams.chroma ); level ++; } @@ -208,13 +239,13 @@ namespace rtengine { int scale = scales[level]; int pitch = pitches[level]; - idirpyr(dirpyrLablo[level], dirpyrLablo[level-1], level, nrwt_l, nrwt_ab, pitch, scale, luma, chroma ); + idirpyr(dirpyrLablo[level], dirpyrLablo[level-1], level, rangefn_L, nrwt_l, nrwt_ab, pitch, scale, dnparams.luma, dnparams.chroma/*, Lcurve, abcurve*/ ); } scale = scales[0]; pitch = pitches[0]; - idirpyr(dirpyrLablo[0], dst, 0, nrwt_l, nrwt_ab, pitch, scale, luma, chroma ); + idirpyr(dirpyrLablo[0], dst, 0, rangefn_L, nrwt_l, nrwt_ab, pitch, scale, dnparams.luma, dnparams.chroma/*, Lcurve, abcurve*/ ); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -224,17 +255,21 @@ namespace rtengine { float igamthresh = gamthresh*gamslope; float igamslope = 1/gamslope; for (int i=0; i<65536; i++) { - int g = (int)(CurveFactory::gamma((float)i/65535.0, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0); - gamcurve[i] = CLIP(g); + gamcurve[i] = (CurveFactory::gamma((float)i/65535.0, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0); } - for (int i=0; iH; i++) - for (int j=0; jW; j++) { - - dst->L[i][j] = gamcurve[CLIP(dst->L[i][j]) ]; - - } + if (dnparams.luma>0) { + for (int i=0; iH; i++) + for (int j=0; jW; j++) { + dst->L[i][j] = gamcurve[dst->L[i][j]]; + } + } else { + for (int i=0; iH; i++) + for (int j=0; jW; j++) { + dst->L[i][j] = gamcurve[src->L[i][j]]; + } + } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -244,16 +279,13 @@ namespace rtengine { delete dirpyrLablo[i]; } - delete [] rangefn_L; - delete [] rangefn_ab; - delete [] nrwt_l; - delete [] nrwt_ab; - delete [] gamcurve; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% }; - void ImProcFunctions::dirpyr(LabImage* data_fine, LabImage* data_coarse, int level, int * rangefn_L, int * rangefn_ab, int pitch, int scale, const int luma, const int chroma ) + void ImProcFunctions::dirpyr(LabImage* data_fine, LabImage* data_coarse, int level, \ + LUTf & rangefn_L, LUTf & rangefn_ab, int pitch, int scale, \ + const int luma, const int chroma ) { //pitch is spacing of subsampling @@ -270,20 +302,9 @@ namespace rtengine { int width = data_fine->W; int height = data_fine->H; - - - //generate domain kernel int halfwin = 3;//MIN(ceil(2*sig),3); int scalewin = halfwin*scale; - //int intfactor = 16384; - - /*float domker[7][7]; - for (int i=-halfwin; i<=halfwin; i++) - for (int j=-halfwin; j<=halfwin; j++) { - domker[i+halfwin][j+halfwin] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma??? - }*/ - //float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}}; #ifdef _OPENMP #pragma omp parallel for @@ -291,23 +312,20 @@ namespace rtengine { for(int i = 0; i < height; i+=pitch ) { int i1=i/pitch; for(int j = 0, j1=0; j < width; j+=pitch, j1++) - { - //norm = DIRWT(i, j, i, j); - //Lout = -norm*data_fine->L[i][j];//if we don't want to include the input pixel in the sum - //aout = -norm*data_fine->a[i][j]; - //bout = -norm*data_fine->b[i][j]; - //or + { float dirwt_l, dirwt_ab, norm_l, norm_ab; + float Lmed,Lhmf; //float lops,aops,bops; float Lout, aout, bout; norm_l = norm_ab = 0;//if we do want to include the input pixel in the sum Lout = 0; aout = 0; bout = 0; - //normab = 0; - for(int inbr=MAX(0,i-scalewin); inbr<=MIN(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=MAX(0,j-scalewin); jnbr<=MIN(width-1,j+scalewin); jnbr+=scale) { + for(int inbr=(i-scalewin); inbr<=(i+scalewin); inbr+=scale) { + if (inbr<0 || inbr>height-1) continue; + for (int jnbr=(j-scalewin); jnbr<=(j+scalewin); jnbr+=scale) { + if (jnbr<0 || jnbr>width-1) continue; dirwt_l = DIRWT_L(inbr, jnbr, i, j); dirwt_ab = DIRWT_AB(inbr, jnbr, i, j); Lout += dirwt_l*data_fine->L[inbr][jnbr]; @@ -321,13 +339,21 @@ namespace rtengine { //aops = aout/normab;//diagnostic //bops = bout/normab;//diagnostic - //data_coarse->L[i1][j1]=0.5*(data_fine->L[i][j]+Lout/norm_l);//low pass filter - //data_coarse->a[i1][j1]=0.5*(data_fine->a[i][j]+aout/norm_ab); - //data_coarse->b[i1][j1]=0.5*(data_fine->b[i][j]+bout/norm_ab); - //or data_coarse->L[i1][j1]=Lout/norm_l;//low pass filter data_coarse->a[i1][j1]=aout/norm_ab; data_coarse->b[i1][j1]=bout/norm_ab; + + + /*if (level<2 && i>0 && i0 && jL[i-1][j-1], data_fine->L[i-1][j], data_fine->L[i-1][j+1], \ + data_fine->L[i][j-1], data_fine->L[i][j], data_fine->L[i][j+1], \ + data_fine->L[i+1][j-1], data_fine->L[i+1][j], data_fine->L[i+1][j+1]); + //med3x3(data_fine->L[i-1][j-1], data_fine->L[i-1][j], data_fine->L[i-1][j+1], \ + data_fine->L[i][j-1], data_fine->L[i][j], data_fine->L[i][j+1], \ + data_fine->L[i+1][j-1], data_fine->L[i+1][j], data_fine->L[i+1][j+1],Lmed); + + data_coarse->L[i1][j1] = Lhmf; + }*/ } } @@ -338,12 +364,15 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - void ImProcFunctions::idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, const int chroma ) + void ImProcFunctions::idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, LUTf &rangefn_L, LUTf & nrwt_l, LUTf & nrwt_ab, \ + int pitch, int scale, const int luma, const int chroma/*, LUTf & Lcurve, LUTf & abcurve*/ ) { int width = data_fine->W; int height = data_fine->H; + array2D nrfactorL (width,height); + //float eps = 0.0; // c[0] noise_L @@ -355,22 +384,9 @@ namespace rtengine { float noisevar_L = 4*SQR(25.0 * luma); float noisevar_ab = 2*SQR(100.0 * chroma); float scalefactor = 1.0/pow(2.0,(level+1)*2);//change the last 2 to 1 for longer tail of higher scale NR - //float recontrast = (1+((float)(c[6])/100.0)); - //float resaturate = 10*(1+((float)(c[7])/100.0)); + noisevar_L *= scalefactor; - - //int halfwin = 3;//MIN(ceil(2*sig),3); - //int intfactor= 16384; - //int winwidth=1+2*halfwin;//this belongs in calling function - /*float domker[7][7]; - for (int i=-halfwin; i<=halfwin; i++) - for (int j=-halfwin; j<=halfwin; j++) { - domker[i][j] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma??? - }*/ - //float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}}; - - - + // for coarsest level, take non-subsampled lopass image and subtract from lopass_fine to generate hipass image // denoise hipass image, add back into lopass_fine to generate denoised image at fine scale @@ -390,32 +406,42 @@ namespace rtengine { if (pitch==1) { // step (1-2-3-4) + #ifdef _OPENMP -#pragma omp parallel for +#pragma omp parallel +#endif +{ + +#ifdef _OPENMP +#pragma omp for #endif for(int i = 0; i < height; i++) for(int j = 0; j < width; j++) { double wtdsum[3], norm; float hipass[3], hpffluct[3], tonefactor, nrfactor; - - tonefactor = ((NRWT_L(data_coarse->L[i][j]))); + + tonefactor = (nrwt_l[data_coarse->L[i][j]]); + + hipass[1] = data_fine->a[i][j]-data_coarse->a[i][j]; + hipass[2] = data_fine->b[i][j]-data_coarse->b[i][j]; //Wiener filter //luma if (level<2) { hipass[0] = data_fine->L[i][j]-data_coarse->L[i][j]; - hpffluct[0]=SQR(hipass[0])+0.001; - hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L); - data_fine->L[i][j] = CLIP(hipass[0]+data_coarse->L[i][j]); + hpffluct[0]=SQR(hipass[0])+SQR(hipass[1])+SQR(hipass[2])+0.001; + nrfactorL[i][j] = (1.0+hpffluct[0])/(1.0+hpffluct[0]+noisevar_L /* * Lcurve[data_coarse->L[i][j]]*/); + //hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L); + //data_fine->L[i][j] = CLIP(hipass[0]+data_coarse->L[i][j]); } //chroma - hipass[1] = data_fine->a[i][j]-data_coarse->a[i][j]; - hipass[2] = data_fine->b[i][j]-data_coarse->b[i][j]; + //hipass[1] = data_fine->a[i][j]-data_coarse->a[i][j]; + //hipass[2] = data_fine->b[i][j]-data_coarse->b[i][j]; hpffluct[1]=SQR(hipass[1]*tonefactor)+0.001; hpffluct[2]=SQR(hipass[2]*tonefactor)+0.001; nrfactor = (hpffluct[1]+hpffluct[2]) /((hpffluct[1]+hpffluct[2]) + noisevar_ab * NRWT_AB); - + hipass[1] *= nrfactor; hipass[2] *= nrfactor; @@ -423,7 +449,63 @@ namespace rtengine { data_fine->b[i][j] = hipass[2]+data_coarse->b[i][j]; } - } else { + if (level<2) { +#ifdef _OPENMP +#pragma omp for +#endif + for(int i = 0; i < height; i++) + for(int j = 0; j < width; j++) { + + float dirwt_l, norm_l; + float nrfctrave=0; + norm_l = 0;//if we do want to include the input pixel in the sum + + for(int inbr=MAX(0,i-1); inbr<=MIN(height-1,i+1); inbr++) { + for (int jnbr=MAX(0,j-1); jnbr<=MIN(width-1,j+1); jnbr++) { + dirwt_l = DIRWT_L(inbr, jnbr, i, j); + nrfctrave += dirwt_l*nrfactorL[inbr][jnbr]; + norm_l += dirwt_l; + } + } + + nrfctrave /= norm_l; + //nrfctrave = nrfactorL[i][j]; + //nrfctrave=1; + + float hipass[3],p[9],temp,median; + + //luma + + /*if (i>0 && i0 && jL[i][j]-data_coarse->L[i][j]); + //hipass[0] = median*(data_fine->L[i][j]-data_coarse->L[i][j]); + //hipass[0] = nrfactorL[i][j]*(data_fine->L[i][j]-data_coarse->L[i][j]); + data_fine->L[i][j] = CLIP(hipass[0]+data_coarse->L[i][j]); + + //chroma + //hipass[1] = nrfactorab[i][j]*(data_fine->a[i][j]-data_coarse->a[i][j]); + //hipass[2] = nrfactorab[i][j]*(data_fine->b[i][j]-data_coarse->b[i][j]); + + //data_fine->a[i][j] = hipass[1]+data_coarse->a[i][j]; + //data_fine->b[i][j] = hipass[2]+data_coarse->b[i][j]; + } + }//end of luminance correction + + + +}//end of pitch=1 + + } else {//pitch>1 LabImage* smooth; @@ -526,24 +608,29 @@ namespace rtengine { for( int i = 0; i < height; i++) for(int j = 0; j < width; j++) { - double tonefactor = ((NRWT_L(smooth->L[i][j]))); + float tonefactor = (nrwt_l[smooth->L[i][j]]); //double wtdsum[3], norm; - float hipass[3], hpffluct[3], nrfactor; + float hipass[3], hpffluct[3], nrfactor; + + hipass[1] = data_fine->a[i][j]-smooth->a[i][j]; + hipass[2] = data_fine->b[i][j]-smooth->b[i][j]; + //Wiener filter //luma if (level<2) { hipass[0] = data_fine->L[i][j]-smooth->L[i][j]; - hpffluct[0]=SQR(hipass[0])+0.001; - hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L); - data_fine->L[i][j] = CLIP(hipass[0]+smooth->L[i][j]); + hpffluct[0]=SQR(hipass[0])+SQR(hipass[1])+SQR(hipass[2])+0.001; + nrfactorL[i][j] = (1.0+hpffluct[0])/(1.0+hpffluct[0]+noisevar_L /* * Lcurve[smooth->L[i][j]]*/); + //hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L); + //data_fine->L[i][j] = CLIP(hipass[0]+smooth->L[i][j]); } //chroma - hipass[1] = data_fine->a[i][j]-smooth->a[i][j]; - hipass[2] = data_fine->b[i][j]-smooth->b[i][j]; + //hipass[1] = data_fine->a[i][j]-smooth->a[i][j]; + //hipass[2] = data_fine->b[i][j]-smooth->b[i][j]; hpffluct[1]=SQR(hipass[1]*tonefactor)+0.001; hpffluct[2]=SQR(hipass[2]*tonefactor)+0.001; - nrfactor = (hpffluct[1]+hpffluct[2]) /((hpffluct[1]+hpffluct[2]) + noisevar_ab * NRWT_AB); + nrfactor = (hpffluct[1]+hpffluct[2]) /((hpffluct[1]+hpffluct[2]) + noisevar_ab * NRWT_AB /* * abcurve[smooth->L[i][j]]*/); hipass[1] *= nrfactor; hipass[2] *= nrfactor; @@ -551,6 +638,64 @@ namespace rtengine { data_fine->a[i][j] = hipass[1]+smooth->a[i][j]; data_fine->b[i][j] = hipass[2]+smooth->b[i][j]; } + + + if (level<2) { +#ifdef _OPENMP +#pragma omp for +#endif + for(int i = 0; i < height; i++) + for(int j = 0; j < width; j++) { + + float dirwt_l, norm_l; + float nrfctrave=0; + norm_l = 0;//if we do want to include the input pixel in the sum + + for(int inbr=(i-pitch); inbr<=(i+pitch); inbr+=pitch) { + if (inbr<0 || inbr>height-1) continue; + for (int jnbr=(j-pitch); jnbr<=(j+pitch); jnbr+=pitch) { + if (jnbr<0 || jnbr>width-1) continue; + dirwt_l = DIRWT_L(inbr, jnbr, i, j); + nrfctrave += dirwt_l*nrfactorL[inbr][jnbr]; + norm_l += dirwt_l; + } + } + + nrfctrave /= norm_l; + //nrfctrave = nrfactorL[i][j]; + //nrfctrave=1; + + + float hipass[3],p[9],temp,median; + + //luma + + /*if (i>0 && i0 && jL[i][j]-smooth->L[i][j]); + //hipass[0] = median*(data_fine->L[i][j]-smooth->L[i][j]); + //hipass[0] = nrfactorL[i][j]*(data_fine->L[i][j]-data_coarse->L[i][j]); + data_fine->L[i][j] = CLIP(hipass[0]+smooth->L[i][j]); + + + //chroma + //hipass[1] = nrfactorab[i][j]*(data_fine->a[i][j]-data_coarse->a[i][j]); + //hipass[2] = nrfactorab[i][j]*(data_fine->b[i][j]-data_coarse->b[i][j]); + + //data_fine->a[i][j] = hipass[1]+data_coarse->a[i][j]; + //data_fine->b[i][j] = hipass[2]+data_coarse->b[i][j]; + } + }//end of luminance correction + + } // end parallel delete smooth; }//end of pitch>1 @@ -561,7 +706,7 @@ namespace rtengine { #undef DIRWT_L #undef DIRWT_AB -#undef NRWT_L +//#undef NRWT_L #undef NRWT_AB } diff --git a/rtengine/dirpyrLab_equalizer.cc b/rtengine/dirpyrLab_equalizer.cc index 5a4a60dfe..b6e68854b 100644 --- a/rtengine/dirpyrLab_equalizer.cc +++ b/rtengine/dirpyrLab_equalizer.cc @@ -38,10 +38,7 @@ -//#define IDIRWT(i1,j1,i,j) ( irangefn[abs((int)data_fine->L[i1][j1]-data_fine->L[i][j]) + \ -abs((int)data_fine->a[i1][j1]-data_fine->a[i][j])+abs((int)data_fine->b[i1][j1]-data_fine->b[i][j])] ) - -#define DIRWT(i1,j1,i,j) ( /*domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin] */ rangefn[abs((int)data_fine->L[i1][j1]-data_fine->L[i][j])+abs((int)data_fine->a[i1][j1]-data_fine->a[i][j])+abs((int)data_fine->b[i1][j1]-data_fine->b[i][j])] ) +#define DIRWT(i1,j1,i,j) (rangefn[abs((int)data_fine->L[i1][j1]-data_fine->L[i][j])+abs((int)data_fine->a[i1][j1]-data_fine->a[i][j])+abs((int)data_fine->b[i1][j1]-data_fine->b[i][j])] ) namespace rtengine { @@ -79,32 +76,11 @@ namespace rtengine { void ImProcFunctions :: dirpyrLab_equalizer(LabImage * src, LabImage * dst, /*float luma, float chroma, float gamma*/ const double * mult ) { - /*float gam = 2.0;//MIN(3.0, 0.1*fabs(c[4])/3.0+0.001); - float gamthresh = 0.03; - float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - unsigned short * gamcurve = new unsigned short [65536]; - for (int i=0; i<65536; i++) { - int g = (int)(CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) * 65535.0); - //if (i<500) printf("%d %d \n",i,g); - gamcurve[i] = CLIP(g); - } - - - //#pragma omp parallel for if (multiThread) - for (int i=0; iH; i++) { - for (int j=0; jW; j++) { - src->L[i][j] = gamcurve[src->L[i][j] ]; - } - }*/ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - int * rangefn = new int [0x20000]; - - //int * irangefn = new int [0x20000]; - - int intfactor = 1024;//16384; - + LUTf rangefn(0x20000); + //set up weights float noise = 1500; @@ -113,11 +89,7 @@ namespace rtengine { //set up range functions for (int i=0; i<0x20000; i++) - rangefn[i] = (int)((noise/((double)i + noise))*intfactor); - - /*for (int i=0; i<0x20000; i++) - //irangefn[i] = 1+(int)( exp(-(double)fabs(i-0x10000) / (1+16*noise) )*intfactor); - irangefn[i] = intfactor*(int)(SQR(noise)/((float)SQR(noise)+SQR(i)));*/ + rangefn[i] = (int)((noise/((double)i + noise))); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -216,7 +188,7 @@ namespace rtengine { totalpitch /= pitch; - idirpyr_eq(dirpyrLablo[level], dirpyrLablo[level-1], buffer, /*i*/ rangefn, level, pitch, totalpitch, mult ); + idirpyr_eq(dirpyrLablo[level], dirpyrLablo[level-1], buffer, level, pitch, totalpitch, mult ); } @@ -225,21 +197,12 @@ namespace rtengine { pitch = pitches[0]; totalpitch /= pitch; - idirpyr_eq(dirpyrLablo[0], dst, buffer, /*i*/ rangefn, 0, pitch, totalpitch, mult ); + idirpyr_eq(dirpyrLablo[0], dst, buffer, 0, pitch, totalpitch, mult ); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - /*float igam = 1/gam; - float igamthresh = gamthresh*gamslope; - float igamslope = 1/gamslope; - for (int i=0; i<65536; i++) { - int g = (int)(CurveFactory::gamma((float)i/65535.0, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0); - gamcurve[i] = CLIP(g); - }*/ - - for (int i=0; iH; i++) for (int j=0; jW; j++) { @@ -247,9 +210,6 @@ namespace rtengine { dst->a[i][j] = CLIPC((int)( buffer[1][i][j] )); dst->b[i][j] = CLIPC((int)( buffer[2][i][j] )); - - //dst->L[i][j] = gamcurve[ dst->L[i][j] ]; - } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -263,16 +223,11 @@ namespace rtengine { for (int c=0;c<3;c++) freeArray(buffer[c], h+128); - //delete [] rangefn_L; - //delete [] rangefn_ab; - delete [] rangefn; - //delete [] gamcurve; - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% }; - void ImProcFunctions::dirpyr_eq(LabImage* data_fine, LabImage* data_coarse, int * rangefn, int level, int pitch, int scale, const double * mult ) + void ImProcFunctions::dirpyr_eq(LabImage* data_fine, LabImage* data_coarse, LUTf & rangefn, int level, int pitch, int scale, const double * mult ) { //pitch is spacing of subsampling @@ -294,16 +249,8 @@ namespace rtengine { //generate domain kernel int halfwin = 1;//MIN(ceil(2*sig),3); int scalewin = halfwin*scale; - //int intfactor = 16384; - /*float domker[7][7]; - for (int i=-halfwin; i<=halfwin; i++) - for (int j=-halfwin; j<=halfwin; j++) { - domker[i+halfwin][j+halfwin] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma??? - }*/ - //float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}}; - - //float domker[3][3] = {{1,1,1},{1,2,1},{1,1,1}}; + #ifdef _OPENMP #pragma omp parallel for #endif @@ -339,7 +286,7 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - void ImProcFunctions::idirpyr_eq(LabImage* data_coarse, LabImage* data_fine, int *** buffer, int * irangefn, int level, int pitch, int scale, const double * mult ) + void ImProcFunctions::idirpyr_eq(LabImage* data_coarse, LabImage* data_fine, int *** buffer, int level, int pitch, int scale, const double * mult ) { int width = data_fine->W; @@ -356,17 +303,6 @@ namespace rtengine { int i1, j1; - //int halfwin = 3;//MIN(ceil(2*sig),3); - //int intfactor= 16384; - //int winwidth=1+2*halfwin;//this belongs in calling function - /*float domker[7][7]; - for (int i=-halfwin; i<=halfwin; i++) - for (int j=-halfwin; j<=halfwin; j++) { - domker[i][j] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma??? - }*/ - //float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}}; - - // for coarsest level, take non-subsampled lopass image and subtract from lopass_fine to generate hipass image // denoise hipass image, add back into lopass_fine to generate denoised image at fine scale diff --git a/rtengine/dirpyr_equalizer.cc b/rtengine/dirpyr_equalizer.cc index 5be00ffb0..576f4141b 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef _OPENMP #include @@ -53,7 +54,7 @@ namespace rtengine { //scale is spacing of directional averaging weights - void ImProcFunctions :: dirpyr_equalizer(unsigned short ** src, unsigned short ** dst, int srcwidth, int srcheight, const double * mult ) + void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, const double * mult ) { int lastlevel=maxlevel; @@ -63,27 +64,11 @@ namespace rtengine { } if (lastlevel==0) return; - /*float gam = 2.0;//MIN(3.0, 0.1*fabs(c[4])/3.0+0.001); - float gamthresh = 0.03; - float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - unsigned short *gamcurve = new unsigned short[65536]; - for (int i=0; i<65536; i++) { - int g = (int)(CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) * 65535.0); - //if (i<500) printf("%d %d \n",i,g); - gamcurve[i] = CLIP(g); - } - - - //#pragma omp parallel for if (multiThread) - for (int i=0; iH; i++) { - for (int j=0; jW; j++) { - src[i][j] = gamcurve[src[i][j] ]; - } - }*/ + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - int * rangefn = new int [0x20000]; + LUTf rangefn(0x10000); int intfactor = 1024;//16384; @@ -92,21 +77,17 @@ namespace rtengine { for (int i=0; i<0x10000; i++) { rangefn[i] = (int)((thresh/((double)(i) + thresh))*intfactor); - //rangefn[i] = (int)(exp(-(double)abs(i)/(5*thresh))*(thresh/((double)(i) + thresh))*intfactor); - //rangefn[i] = (int)((thresh*thresh/((double)(i)*(double)(i) + thresh*thresh))*intfactor); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int level; - int ** buffer; + array2D buffer (srcwidth, srcheight); - unsigned short ** dirpyrlo[maxlevel]; + multi_array2D dirpyrlo (srcwidth, srcheight); - - buffer = allocArray (srcwidth, srcheight); - + for (int i=0; i (srcwidth, srcheight); - + dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, rangefn, 0, scale, mult ); level = 1; @@ -126,9 +105,7 @@ namespace rtengine { while(level < lastlevel) { scale = scales[level]; - - dirpyrlo[level] = allocArray(srcwidth, srcheight); - + dirpyr_channel(dirpyrlo[level-1], dirpyrlo[level], srcwidth, srcheight, rangefn, level, scale, mult ); level ++; @@ -162,42 +139,22 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - /*float igam = 1/gam; - float igamthresh = gamthresh*gamslope; - float igamslope = 1/gamslope; - for (int i=0; i<65536; i++) { - int g = (int)(CurveFactory::gamma((float)i/65535.0, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0); - gamcurve[i] = CLIP(g); - }*/ - - for (int i=0; iL[i][j] ]; - + } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - for(int i = 0; i < lastlevel; i++) - { - freeArray(dirpyrlo[i], srcheight); - } - - freeArray(buffer, srcheight); - - delete [] rangefn; - //delete [] gamcurve; - + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } - void ImProcFunctions::dirpyr_channel(unsigned short ** data_fine, unsigned short ** data_coarse, int width, int height, int * rangefn, int level, int scale, const double * mult ) + void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale, const double * mult ) { //scale is spacing of directional averaging weights @@ -243,7 +200,7 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - void ImProcFunctions::idirpyr_eq_channel(unsigned short ** data_coarse, unsigned short ** data_fine, int ** buffer, int width, int height, int level, const double * mult ) + void ImProcFunctions::idirpyr_eq_channel(float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, const double * mult ) { float noisehi = 1.33*noise*mult[4]/pow(3,level), noiselo = 0.66*noise*mult[4]/pow(3,level); float * irangefn = new float [0x20000]; diff --git a/rtengine/fast_demo.cc b/rtengine/fast_demo.cc index ccccb2e95..a24c171b8 100644 --- a/rtengine/fast_demo.cc +++ b/rtengine/fast_demo.cc @@ -44,6 +44,10 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { //int winx=0, winy=0; //int winw=W, winh=H; + if (plistener) { + plistener->setProgressStr ("Fast demosaicing..."); + plistener->setProgress (0.0); + } float progress = 0.0; @@ -174,7 +178,7 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { }//i }//j - if(plistener) plistener->setProgress(0.25); + if(plistener) plistener->setProgress(0.05); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -193,10 +197,10 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { } else { //compute directional weights using image gradients - wtu=dirwt[(abs(rawData[i+1][j]-rawData[i-1][j])+abs(rawData[i][j]-rawData[i-2][j])+abs(rawData[i-1][j]-rawData[i-3][j])) >>4]; - wtd=dirwt[(abs(rawData[i-1][j]-rawData[i+1][j])+abs(rawData[i][j]-rawData[i+2][j])+abs(rawData[i+1][j]-rawData[i+3][j])) >>4]; - wtl=dirwt[(abs(rawData[i][j+1]-rawData[i][j-1])+abs(rawData[i][j]-rawData[i][j-2])+abs(rawData[i][j-1]-rawData[i][j-3])) >>4]; - wtr=dirwt[(abs(rawData[i][j-1]-rawData[i][j+1])+abs(rawData[i][j]-rawData[i][j+2])+abs(rawData[i][j+1]-rawData[i][j+3])) >>4]; + wtu=dirwt[(abs(rawData[i+1][j]-rawData[i-1][j])+abs(rawData[i][j]-rawData[i-2][j])+abs(rawData[i-1][j]-rawData[i-3][j])) >>2]; + wtd=dirwt[(abs(rawData[i-1][j]-rawData[i+1][j])+abs(rawData[i][j]-rawData[i+2][j])+abs(rawData[i+1][j]-rawData[i+3][j])) >>2]; + wtl=dirwt[(abs(rawData[i][j+1]-rawData[i][j-1])+abs(rawData[i][j]-rawData[i][j-2])+abs(rawData[i][j-1]-rawData[i][j-3])) >>2]; + wtr=dirwt[(abs(rawData[i][j-1]-rawData[i][j+1])+abs(rawData[i][j]-rawData[i][j+2])+abs(rawData[i][j+1]-rawData[i][j+3])) >>2]; //store in rgb array the interpolated G value at R/B grid points using directional weighted average green[i][j]=(int)((wtu*rawData[i-1][j]+wtd*rawData[i+1][j]+wtl*rawData[i][j-1]+wtr*rawData[i][j+1])/(wtu+wtd+wtl+wtr)); @@ -208,7 +212,7 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { //progress+=(double)0.33/(H); //if(plistener) plistener->setProgress(progress); } - if(plistener) plistener->setProgress(0.3); + if(plistener) plistener->setProgress(0.4); #pragma omp for @@ -231,7 +235,7 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { //progress+=(double)0.33/(H); //if(plistener) plistener->setProgress(progress); } - if(plistener) plistener->setProgress(0.35); + if(plistener) plistener->setProgress(0.7); #pragma omp barrier @@ -247,9 +251,10 @@ void RawImageSource::fast_demo(int winx, int winy, int winw, int winh) { blue[i][j] = CLIP((int)(green[i][j] - 0.25*((green[i-1][j]-blue[i-1][j])+(green[i+1][j]-blue[i+1][j])+ \ (green[i][j-1]-blue[i][j-1])+(green[i][j+1]-blue[i][j+1])))); } - + progress+=(double)0.33/(H); + //if(plistener) plistener->setProgress(progress); } - if(plistener) plistener->setProgress(0.4 ); + if(plistener) plistener->setProgress(0.99); } #undef bord diff --git a/rtengine/gamutbdy.cc b/rtengine/gamutbdy.cc new file mode 100644 index 000000000..715bebcd9 --- /dev/null +++ b/rtengine/gamutbdy.cc @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////// +// +// Gamut mapping algorithm +// +// copyright (c) 2010-2011 Emil Martinec +// +// +// code dated: February 2, 2011 +// +// sRGBgamutbdy.cc is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +//////////////////////////////////////////////////////////////// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +#define SQR(x) ((x)*(x)) + +#define D50x 0.96422 +#define D50z 0.82521 +#define u0 4.0*D50x/(D50x+15+3*D50z) +#define v0 9.0/(D50x+15+3*D50z) + +#define sgn(x) (x<0 ? -1 : 1) +#define sqrt2 (sqrt(2)) +#define sqrt3 (sqrt(3)) +#define sqrt6 (sqrt(6)) +#define K 20 +#define rmax (3*K + 1) +#define rctr (2*K) +#define cctr (2*K + 1) +#define maxindx (2*(3*K+1) + SQR(3*K+1)) + + + +// solutions to scaling u and v to XYZ paralleliped boundaries +/* some equations: + fu(X,Y,Z) = 4 X/(X + 15 Y + 3 Z); + fv(X,Y,Z) = 9 Y/(X + 15 Y + 3 Z); + + take the plane spanned by X=a*Xr+b*Xg+c*Xb etc with one of a,b,c equal to 0 or 1, + and itersect with the line u0+lam*u, or in other words solve + + u0+lam*u=fu(X,Y,Z) + v0+lam*v=fv(X,Y,Z) + + the value of lam is the scale factor that takes the color to the gamut boundary +*/ +// columns of the matrix p=xyz_rgb are RGB tristimulus primaries in XYZ +// c is the color fixed on the boundary; and m=0 for c=0, m=1 for c=255 + +void ImProcFunctions::gamutmap(float &X, float &Y, float &Z, const double p[3][3]) +{ + float u = 4*X/(X+15*Y+3*Z)-u0; + float v = 9*Y/(X+15*Y+3*Z)-v0; + + float lam[3][2]; + float lam_min = 1.0; + + for (int c=0; c<3; c++) + for (int m=0; m<2; m++) { + + int c1=(c+1)%3; + int c2=(c+2)%3; + + lam[c][m] = (-(p[0][c1]*p[1][c]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2])) + \ + p[0][c]*p[1][c1]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2]) - \ + 4*v0*p[0][c1]*(Y - m*65535*p[1][c2])*p[2][c] + 4*v0*p[0][c]*(Y - m*65535*p[1][c2])*p[2][c1] - \ + (4*m*65535*v0*p[0][c2] - 9*u0*Y)*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1])); + + lam[c][m] /= (3*u*Y*(p[0][c1]*p[1][c] - p[1][c1]*(p[0][c] + 3*p[2][c]) + 3*p[1][c]*p[2][c1]) + \ + 4*v*(p[0][c1]*(5*Y*p[1][c] + m*65535*p[1][c]*p[2][c2] + Y*p[2][c] - m*65535*p[1][c2]*p[2][c]) - \ + p[0][c]*(5*Y*p[1][c1] + m*65535*p[1][c1]*p[2][c2] + Y*p[2][c1] - m*65535*p[1][c2]*p[2][c1]) + \ + m*65535*p[0][c2]*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1]))); + + if (lam[c][m]0) lam_min=lam[c][m]; + + } + + u = u*lam_min + u0; + v = v*lam_min + v0; + + X = (9*u*Y)/(4*v); + Z = (12 - 3*u - 20*v)*Y/(4*v); + + +} + + +//};//namespace diff --git a/rtengine/green_equil_RT.cc b/rtengine/green_equil_RT.cc index d946762a4..a2a4ee072 100644 --- a/rtengine/green_equil_RT.cc +++ b/rtengine/green_equil_RT.cc @@ -21,7 +21,6 @@ // along with this program. If not, see . // //////////////////////////////////////////////////////////////// - #define TS 256 // Tile size #include @@ -41,6 +40,7 @@ void RawImageSource::green_equilibrate(float thresh) 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; int height=H, width=W; //for RT only + int top, left; int verbose=1; @@ -90,11 +90,16 @@ void RawImageSource::green_equilibrate(float thresh) int row, col; int rr, cc, indx; int vote1, vote2; - + int counter, vtest; + float gin, gse, gsw, gne, gnw, wtse, wtsw, wtne, wtnw; float mcorr, pcorr; float ginterp; + float d1,d2,c1,c2; + float o1_1,o1_2,o1_3,o1_4; + float o2_1,o2_2,o2_3,o2_4; + // rgb from input CFA data /* rgb values should be floating point number between 0 and 1 after white balance multipliers are applied */ @@ -108,19 +113,6 @@ void RawImageSource::green_equilibrate(float thresh) //The green equilibration algorithm starts here - //%%%%%%%%%%%%%%%%%%%%%%%%% - // To the extent possible under law, Manuel Llorens - // has waived all copyright and related or neighboring rights to this work. - // This code is licensed under CC0 v1.0, see license information at - // http://creativecommons.org/publicdomain/zero/1.0/ - - double d1,d2,c1,c2; - int o1_1,o1_2,o1_3,o1_4; - int o2_1,o2_2,o2_3,o2_4; - - - //%%%%%%%%%%%%%%%%%%%%%% - for (rr=2; rr < numrows-2; rr++) for (cc=3-(FC(rr,2)&1), indx=rr*TS+cc; cc < numcols-2; cc+=2, indx+=2) { @@ -132,7 +124,7 @@ void RawImageSource::green_equilibrate(float thresh) //checker[indx]=1;//test what happens if we always interpolate } - + counter=vtest=0; //now smooth the cfa data for (rr=6; rr < numrows-6; rr+=2) @@ -158,6 +150,7 @@ void RawImageSource::green_equilibrate(float thresh) vote1=(checker[indx-v2]+checker[indx-2]+checker[indx+2]+checker[indx+v2]); vote2=(checker[indx-m1]+checker[indx+p1]+checker[indx-p1]+checker[indx+m1]); + //if ((vote1==0 || vote2==0) && (c1+c2)<2*thresh*fabs(d1-d2)) vtest++; if (vote1>0 && vote2>0 && (c1+c2)<4*thresh*fabs(d1-d2)) { //pixel interpolation gin=cfa[indx]; @@ -176,11 +169,15 @@ void RawImageSource::green_equilibrate(float thresh) ginterp=(gse*wtse+gnw*wtnw+gne*wtne+gsw*wtsw)/(wtse+wtnw+wtne+wtsw); - cfa[indx]=ginterp;//0.5*(ginterp+gin); + //if ( ((ginterp-gin) < thresh*(ginterp+gin)) ) { + cfa[indx]=0.5*(ginterp+gin); + counter++; + //} + } } } - + //printf("pixfix count= %d; vtest= %d \n",counter,vtest); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // copy smoothed results back to image matrix @@ -189,9 +186,9 @@ void 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 - rawData[row][col] = CLIP((int)(cfa[indx] + 0.5)); + rawData[row][col] = CLIP(cfa[indx]); } - + // clean up } free(buffer); diff --git a/rtengine/hlmultipliers.cc b/rtengine/hlmultipliers.cc index 57a455d6c..99b329798 100644 --- a/rtengine/hlmultipliers.cc +++ b/rtengine/hlmultipliers.cc @@ -196,7 +196,7 @@ void hlmultipliers (int** rec[3], int max[3], int dh, int dw) { if (!change && phase<4) { phase++; if( options.rtSettings.verbose ) - printf ("phc %d: %d\n", phase, k); + printf ("phc %d: %d\n", phase, k); } else if (!change) break; @@ -205,7 +205,7 @@ void hlmultipliers (int** rec[3], int max[3], int dh, int dw) { printf ("changed %d\n", changed); } if( options.rtSettings.verbose ) - printf ("Highlight recovery ends in %d iterations\n", k); + printf ("Highlight recovery ends in %d iterations\n", k); int maxval = MAX(MAX(max[0], max[1]), max[2]); for (int i=0; i=H/HR_SCALE-2) @@ -235,18 +235,22 @@ void RawImageSource::HLRecovery_ColorPropagation (unsigned short* red, unsigned double mulr = mr1*mc1 * hrmap[0][blr][blc] + mr1*(1.0-mc1) * hrmap[0][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[0][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[0][blr+1][blc+1]; double mulg = mr1*mc1 * hrmap[1][blr][blc] + mr1*(1.0-mc1) * hrmap[1][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[1][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[1][blr+1][blc+1]; double mulb = mr1*mc1 * hrmap[2][blr][blc] + mr1*(1.0-mc1) * hrmap[2][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[2][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[2][blr+1][blc+1]; - red[jx] = CLIP(red[jx] * mulr); - green[jx] = CLIP(green[jx] * mulg); - blue[jx] = CLIP(blue[jx] * mulb); - } + red[jx] = (red[jx] * mulr); + green[jx] = (green[jx] * mulg); + blue[jx] = (blue[jx] * mulb); + } else { + red[jx] = (red[jx]); + green[jx] = (green[jx]); + blue[jx] = (blue[jx]); + } } } void RawImageSource::updateHLRecoveryMap_ColorPropagation () { // detect maximal pixel values - unsigned short* red = new unsigned short[W]; - unsigned short* blue = new unsigned short[W]; + float* red = new float[W]; + float* blue = new float[W]; int maxr = 0, maxg = 0, maxb = 0; for (int i=32; i (dw, dh); - unsigned short* reds[HR_SCALE]; - unsigned short* blues[HR_SCALE]; + float* reds[HR_SCALE]; + float* blues[HR_SCALE]; for (int i=0; i #include +#include + namespace rtengine { -const double (*wprofiles[])[3] = {sRGB_d50, adobe_d50, prophoto_d50, widegamut_d50, bruce_d50, beta_d50, best_d50}; -const double (*iwprofiles[])[3] = {d50_sRGB, d50_adobe, d50_prophoto, d50_widegamut, d50_bruce, d50_beta, d50_best}; +const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best}; +const double (*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz}; const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"}; +const char* wpgamma[] = {"default","BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "linear_g1.0", "standard_g2.2", "standard_g1.8", "High_g1.3_s3.35","Low_g2.6_s6.9"}; //gamma free +//default = gamma inside profile +//BT709 g=2.22 s=4.5 sRGB g=2.4 s=12.92 +//linear g=1.0 +//std22 g=2.2 std18 g=1.8 +// high g=1.3 s=3.35 for high dynamic images +//low g=2.6 s=6.9 for low contrast images + + +std::vector getGamma () {//return gamma + + std::vector res; + for (unsigned int i=0; i getWorkingProfiles () { @@ -81,7 +100,7 @@ ICCStore::getInstance(void) ICCStore::ICCStore () { - // cmsErrorAction (LCMS_ERROR_SHOW); + //cmsErrorAction (LCMS_ERROR_SHOW); int N = sizeof(wpnames)/sizeof(wpnames[0]); for (int i=0; i ICCStore::parseDir (Glib::ustring pdir) { if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { int lastdot = sname.find_last_of ('.'); if (lastdot!=Glib::ustring::npos && lastdot<=(int)sname.size()-4 && (!sname.casefold().compare (lastdot, 4, ".icm") || !sname.casefold().compare (lastdot, 4, ".icc"))) { - if( options.rtSettings.verbose ) - printf ("Processing ICC file: %s...\n", fname.c_str()); +// printf ("processing file %s...\n", fname.c_str()); Glib::ustring name = sname.substr(0,lastdot); ProfileContent pc (fname); if (pc.data) { @@ -221,17 +239,17 @@ void ICCStore::findDefaultMonitorProfile() { #ifdef WIN32 // Get current main monitor. Could be fine tuned to get the current windows monitor (multi monitor setup), // but problem is that we live in RTEngine with no GUI window to query around - HDC hDC=GetDC(NULL); - - if (hDC!=NULL) { - if (SetICMMode(hDC, ICM_ON)) { - char profileName[MAX_PATH+1]; DWORD profileLength=MAX_PATH; - if (GetICMProfileA(hDC,&profileLength,profileName)) defaultMonitorProfile=Glib::ustring(profileName); - // might fail if e.g. the monitor has no profile - } - - ReleaseDC(NULL,hDC); - } + HDC hDC=GetDC(NULL); + + if (hDC!=NULL) { + if (SetICMMode(hDC, ICM_ON)) { + char profileName[MAX_PATH+1]; DWORD profileLength=MAX_PATH; + if (GetICMProfileA(hDC,&profileLength,profileName)) defaultMonitorProfile=Glib::ustring(profileName); + // might fail if e.g. the monitor has no profile + } + + ReleaseDC(NULL,hDC); + } #else // TODO: Add other OS specific code here printf("Automatic Monitor Profile Detection not supported on your OS\n"); @@ -310,14 +328,19 @@ cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, G 0x7258595a, 0, 20, /* rXYZ */ 0x6758595a, 0, 20, /* gXYZ */ 0x6258595a, 0, 20 }; /* bXYZ */ - static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc };//D65 + //static const unsigned pwhite[] = { 0xf6d6, 0x10000, 0xd340 };//D50 + // 0x63757276 : curveType, 0 : reserved, 1 : entries (1=gamma, 0=identity), 0x1000000=1.0 unsigned pcurve[] = { 0x63757276, 0, 0, 0x1000000 }; // unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; if (gamma) { pcurve[2] = 1; - pcurve[3] = 0x1f00000; + // pcurve[3] = 0x1f00000;// pcurve for gamma BT709 : g=2.22 s=4.5 + // normalize gamma in RT, default (Emil's choice = sRGB) + pcurve[3] = 0x2390000;//pcurve for gamma sRGB : g:2.4 s=12.92 + } // constructing profile header @@ -348,7 +371,7 @@ cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, G // pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); for (int i=0; i < 3; i++) for (int j=0; j < 3; j++) { - oprof[pbody[j*3+23]/4+i+2] = matrix[j][i] * 0x10000 + 0.5; + oprof[pbody[j*3+23]/4+i+2] = matrix[i][j] * 0x10000 + 0.5; // for (num = k=0; k < 3; k++) // num += xyzd50_srgb[i][k] * inverse[j][k]; } diff --git a/rtengine/iimage.h b/rtengine/iimage.h index f783d715d..148dcc8e8 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -18,6 +18,7 @@ */ #ifndef _IIMAGE_ #define _IIMAGE_ + #include #include @@ -90,6 +91,21 @@ namespace rtengine { * @return the two dimensional array of the blue plane */ virtual unsigned short** getBPlane ()=0; }; + + /** This class represents an image having a float pixel planar representation. + The planes are stored as two dimensional arrays. All the rows have a 8-byte alignment. */ + class IImagefloat : public IImage { + public: + /** Returns the "red" plane data. + * @return the two dimensional array of the red plane */ + virtual float** getRPlane ()=0; + /** Returns the "green" plane data. + * @return the two dimensional array of the green plane */ + virtual float** getGPlane ()=0; + /** Returns the "blue" plane data. + * @return the two dimensional array of the blue plane */ + virtual float** getBPlane ()=0; + }; } #endif diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 1f6227f98..3b3fadc44 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -17,8 +17,10 @@ * along with RawTherapee. If not, see . */ #include +#include #include #include +#include #include using namespace rtengine; @@ -36,47 +38,44 @@ Image16::Image16 (int w, int h) Image16::~Image16 () { if (data!=NULL) { - delete [] unaligned; + delete [] data; delete [] r; delete [] g; delete [] b; } } -void Image16::allocate (int width, int height) { +void Image16::allocate (int W, int H) { + width=W; + height=H; if (data!=NULL) { - delete [] unaligned; + delete [] data; delete [] r; delete [] g; delete [] b; } - int lsize = width + 8 - width % 8; - unaligned = new unsigned char[16 + 3 * lsize * sizeof(short) * height]; - memset(unaligned, 0, (16 + 3 * lsize * sizeof(short) * height) * sizeof(unsigned char)); - - uintptr_t poin = (uintptr_t)unaligned + 16 - (uintptr_t)unaligned % 16; - data = (unsigned short*) (poin); - - rowstride = lsize * sizeof(unsigned short); - planestride = rowstride * height; - - uintptr_t redstart = poin + 0*planestride; - uintptr_t greenstart = poin + 1*planestride; - uintptr_t bluestart = poin + 2*planestride; - r = new unsigned short*[height]; g = new unsigned short*[height]; b = new unsigned short*[height]; + data = new unsigned short[W*H*3]; + + rowstride = W; + planestride = rowstride * height; + + unsigned short* redstart = data + 0*planestride; + unsigned short* greenstart = data + 1*planestride; + unsigned short* bluestart = data + 2*planestride; + + for (int i=0; iwidth = width; - this->height = height; + } void Image16::getScanline (int row, unsigned char* buffer, int bps) { @@ -256,3 +255,30 @@ Image16::to8() const } return img8; } + +Imagefloat* +Image16::tofloat() const +{ + Imagefloat* imgfloat = new Imagefloat(width,height); + for ( int h = 0; h < height; ++h ) + { + for ( int w = 0; w < width; ++w ) + { + imgfloat->r[h][w] = ((float)r[h][w]) ; + imgfloat->g[h][w] = ((float)g[h][w]) ; + imgfloat->b[h][w] = ((float)b[h][w]) ; + } + } + return imgfloat; +} + +// Parallized transformation; create transform with cmsFLAGS_NOCACHE! +void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, bool safe) { + if (safe) { + cmsDoTransform(hTransform, data, data, planestride); + } else { + #pragma omp parallel for + for (int i=0; i #include +#include namespace rtengine { @@ -57,6 +58,7 @@ class Image16 : public ImageIO, public IImage16 { Image16* copy (); Image8* to8() const; + Imagefloat* tofloat() const; Image16* rotate (int deg); Image16* hflip (); @@ -85,6 +87,8 @@ class Image16 : public ImageIO, public IImage16 { virtual unsigned short** getRPlane () { return r; } virtual unsigned short** getGPlane () { return g; } virtual unsigned short** getBPlane () { return b; } -}; + + void ExecCMSTransform(cmsHTRANSFORM hTransform, bool safe); + }; }; #endif diff --git a/rtengine/image8.cc b/rtengine/image8.cc index 793ce536b..1600c0b1c 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -16,9 +16,11 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include +#include #include #include -#include + using namespace rtengine; diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc new file mode 100644 index 000000000..d4f92c91f --- /dev/null +++ b/rtengine/imagefloat.cc @@ -0,0 +1,275 @@ +/* + * 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 + +using namespace rtengine; + +Imagefloat::Imagefloat () + : unaligned (NULL), data (NULL), r (NULL), g (NULL), b (NULL){ +} + +Imagefloat::Imagefloat (int w, int h) + : unaligned (NULL), width(w), height (h), data (NULL), r (NULL), g (NULL), b (NULL) { + + allocate (w, h); +} + +Imagefloat::~Imagefloat () { + + if (data!=NULL) { + delete [] data; + delete [] r; + delete [] g; + delete [] b; + } +} + +void Imagefloat::allocate (int W, int H) { + + width=W; + height=H; + + if (data!=NULL) { + delete [] data; + delete [] r; + delete [] g; + delete [] b; + } + + /* + int lsize = width + 8 - width % 8; + unaligned = new unsigned char[16 + 3 * lsize * sizeof(float) * height]; + memset(unaligned, 0, (16 + 3 * lsize * sizeof(float) * height) * sizeof(unsigned char)); + + uintptr_t poin = (uintptr_t)unaligned + 16 - (uintptr_t)unaligned % 16; + data = (float*) (poin); + */ + r = new float*[height]; + g = new float*[height]; + b = new float*[height]; + + data = new float[W*H*3]; + rowstride = W; + planestride = rowstride * H; + + float * redstart = data + 0*planestride; + float * greenstart = data + 1*planestride; + float * bluestart = data + 2*planestride; + + + for (int i=0; ir[i], r[i], width*sizeof(float)); + memcpy (cp->g[i], g[i], width*sizeof(float)); + memcpy (cp->b[i], b[i], width*sizeof(float)); + } + + return cp; +} + +Imagefloat* Imagefloat::rotate (int deg) { + + if (deg==90) { + Imagefloat* result = new Imagefloat (height, width); + for (int i=0; ir[i][j] = r[height-1-j][i]; + result->g[i][j] = g[height-1-j][i]; + result->b[i][j] = b[height-1-j][i]; + } + return result; + } + else if (deg==270) { + Imagefloat* result = new Imagefloat (height, width); + for (int i=0; ir[i][j] = r[j][width-1-i]; + result->g[i][j] = g[j][width-1-i]; + result->b[i][j] = b[j][width-1-i]; + } + return result; + } + else if (deg==180) { + Imagefloat* result = new Imagefloat (width, height); + for (int i=0; ir[i][j] = r[height-1-i][width-1-j]; + result->g[i][j] = g[height-1-i][width-1-j]; + result->b[i][j] = b[height-1-i][width-1-j]; + } + return result; + } + else + return NULL; +} + +Imagefloat* Imagefloat::hflip () { + + Imagefloat* result = new Imagefloat (width, height); + for (int i=0; ir[i][j] = r[i][width-1-j]; + result->g[i][j] = g[i][width-1-j]; + result->b[i][j] = b[i][width-1-j]; + } + return result; + +} + +Imagefloat* Imagefloat::vflip () { + + Imagefloat* result = new Imagefloat (width, height); + for (int i=0; ir[i][j] = r[height-1-i][j]; + result->g[i][j] = g[height-1-i][j]; + result->b[i][j] = b[height-1-i][j]; + } + return result; + +} + +/*Imagefloat* Imagefloat::resize (int nw, int nh, TypeInterpolation interp) { + + if (interp == TI_Nearest) { + Imagefloat* res = new Imagefloat (nw, nh); + for (int i=0; ir[i][j] = r[ri][ci]; + res->g[i][j] = g[ri][ci]; + res->b[i][j] = b[ri][ci]; + } + } + return res; + } + else if (interp == TI_Bilinear) { + Imagefloat* res = new Imagefloat (nw, nh); + for (int i=0; i=height) sy = height-1; + double dy = (double)i*height/nh - sy; + int ny = sy+1; + if (ny>=height) ny = sy; + for (int j=0; j=width) sx = width; + double dx = (double)j*width/nw - sx; + int nx = sx+1; + if (nx>=width) nx = sx; + res->r[i][j] = r[sy][sx]*(1-dx)*(1-dy) + r[sy][nx]*dx*(1-dy) + r[ny][sx]*(1-dx)*dy + r[ny][nx]*dx*dy; + res->g[i][j] = g[sy][sx]*(1-dx)*(1-dy) + g[sy][nx]*dx*(1-dy) + g[ny][sx]*(1-dx)*dy + g[ny][nx]*dx*dy; + res->b[i][j] = b[sy][sx]*(1-dx)*(1-dy) + b[sy][nx]*dx*(1-dy) + b[ny][sx]*(1-dx)*dy + b[ny][nx]*dx*dy; + } + } + return res; + } + return NULL; +}*/ + +Image8* +Imagefloat::to8() const +{ + Image8* img8 = new Image8(width,height); + for ( int h = 0; h < height; ++h ) + { + for ( int w = 0; w < width; ++w ) + { + img8->r(h,w,((int)r[h][w]) >> 8); + img8->g(h,w,((int)g[h][w]) >> 8); + img8->b(h,w,((int)b[h][w]) >> 8); + } + } + return img8; +} + +Image16* +Imagefloat::to16() const +{ + Image16* img16 = new Image16(width,height); + for ( int h = 0; h < height; ++h ) + { + for ( int w = 0; w < width; ++w ) + { + img16->r[h][w] = ((int)r[h][w]) ; + img16->g[h][w] = ((int)g[h][w]) ; + img16->b[h][w] = ((int)b[h][w]) ; + } + } + return img16; +} + + +void Imagefloat::calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist) { + hist.clear(); + + // Set up factors to calc the lightness + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + + float facRed = wprof[1][0]; + float facGreen = wprof[1][1]; + float facBlue = wprof[1][2]; + + + // calc pixel size + int x1, x2, y1, y2; + params.crop.mapToResized(width, height, scale, x1, x2, y1, y2); + + #pragma omp parallel for + for (int y=y1; y65535) i=65535; + hist[i]++; + } + } +} + +// Parallized transformation; create transform with cmsFLAGS_NOCACHE! +void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform, bool safe) { + if (safe) { + cmsDoTransform(hTransform, data, data, planestride); + } else { + #pragma omp parallel for + for (int i=0; i + * + * 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 . + */ +// +// A class representing a 16 bit rgb image with separate planes and 16 byte aligned data +// +#ifndef _IMAGEFLOAT_ +#define _IMAGEFLOAT_ + +#include +#include + +namespace rtengine { + using namespace procparams; +//enum TypeInterpolation { TI_Nearest, TI_Bilinear }; + +class Image8; +class Image16; + +class Imagefloat : public ImageIO, public IImagefloat { + + private: + unsigned char* unaligned; + + public: + int rowstride; + int planestride; + + int width; + int height; + + float* data; + + float** r; + float** g; + float** b; + + + Imagefloat (); + Imagefloat (int width, int height); + ~Imagefloat (); + + Imagefloat* copy (); + + Image8* to8() const; + Image16* to16() const; + + + Imagefloat* rotate (int deg); + Imagefloat* hflip (); + Imagefloat* vflip (); + //Imagefloat* resize (int nw, int nh, TypeInterpolation interp); + + virtual int getW () { return width; } + virtual int getH () { return height; } + virtual void allocate (int width, int height); + virtual int getBPS () { return 8*sizeof(float); } + //virtual void getScanline (int row, unsigned char* buffer, int bps); + //virtual void setScanline (int row, unsigned char* buffer, int bps); + + // functions inherited from IImagefloat: + virtual int getWidth () { return width; } + virtual int getHeight () { return height; } + virtual Glib::Mutex& getMutex () { return mutex (); } + virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } + virtual int getBitsPerPixel () { return 16; } + virtual int saveToFile (Glib::ustring fname) { return save (fname); } + virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); } + virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); } + virtual int saveAsTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false) { return saveTIFF (fname, bps, uncompressed); } + virtual void setSaveProgressListener (ProgressListener* pl) { return setProgressListener (pl); } + virtual void free () { delete this; } + virtual float** getRPlane () { return r; } + virtual float** getGPlane () { return g; } + virtual float** getBPlane () { return b; } + + void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist); + + void ExecCMSTransform(cmsHTRANSFORM hTransform, bool safe); + }; +}; +#endif diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index e09dee3c2..89e182769 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -691,7 +691,6 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality) { delete [] row; delete [] buffer; - fclose (file); if (pl) { @@ -788,7 +787,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { exif->write (8, buffer); write (TIFFFileno (out), buffer+8, exif_size); - delete buffer; + delete[] buffer; // let libtiff know that scanlines or any other following stuff should go // at a different offset: TIFFSetWriteOffset (out, exif_size+8); diff --git a/rtengine/imageio.h b/rtengine/imageio.h index ee4241bf2..09490c3f5 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -82,7 +82,7 @@ class ImageIO { cmsHPROFILE getEmbeddedProfile () { return embProfile; } void getEmbeddedProfileData (int& length, unsigned char*& pdata) { length = loadedProfileLength; pdata = (unsigned char*)loadedProfileData; } - void setMetadata (const rtexif::TagDirectory* eroot); + void setMetadata (const rtexif::TagDirectory* eroot); void setMetadata (const rtexif::TagDirectory* eroot, const std::vector& exif, const std::vector& iptcc); void setOutputProfile (char* pdata, int plen); Glib::Mutex& mutex () { return imutex; } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index ceecf37b2..05a65bdcb 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include #include +#include "LUT.h" namespace rtengine { @@ -68,7 +70,7 @@ class ImageSource : public InitialImage { virtual int load (Glib::ustring fname, bool batch = false) =0; 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 void getImage (ColorTemp ctemp, int tran, Imagefloat* 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; @@ -85,7 +87,11 @@ class ImageSource : public InitialImage { void increaseRef () { references++; } void decreaseRef () { references--; if (!references) delete this; } - virtual int getAEHistogram (unsigned int* histogram, int& histcompr) {return 0;} + + virtual void getAutoExpHistogram (LUTu & histogram, int& histcompr)=0; + virtual void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) { + histRedRaw.clear(); histGreenRaw.clear(); histBlueRaw.clear(); // only some sources will supply this + } // functions inherited from the InitialImage interface virtual Glib::ustring getFileName () { return fileName; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index b33c8dc4b..79eeb5999 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -22,7 +22,7 @@ #include #include #define CLIPTO(a,b,c) ((a)>b?((a)0?((a)<65535?(a):65535):0) namespace rtengine { @@ -32,28 +32,28 @@ ImProcCoordinator::ImProcCoordinator () : awbComputed(false), ipf(¶ms, true), scale(10), allocated(false), pW(-1), pH(-1), plistener(NULL),fineDetailsProcessed(false), imageListener(NULL), aeListener(NULL), hListener(NULL), resultValid(false), - changeSinceLast(0), updaterRunning(false), destroying(false) { + changeSinceLast(0), updaterRunning(false), destroying(false), workimg(NULL) { - dummy1 = new float[65536]; - dummy2 = new float[65536]; - hltonecurve = new float[65536]; - shtonecurve = new float[65536]; - tonecurve = new int[65536]; + hltonecurve(65536,0); + shtonecurve(65536,0);//,1); + tonecurve(65536,0);//,1); - lumacurve = new int[65536]; - chroma_acurve = new float[65536]; - chroma_bcurve = new float[65536]; + lumacurve(65536,0); + chroma_acurve(65536,0); + chroma_bcurve(65536,0); + satcurve(65536,0); - vhist16 = new unsigned int[65536]; - lhist16 = new unsigned int[65536]; + vhist16(65536); + lhist16(65536); lhist16Cropped(65536); + histCropped(65536); - rhist = new unsigned int[256]; - ghist = new unsigned int[256]; - bhist = new unsigned int[256]; - Lhist = new unsigned int[256]; - bcrgbhist = new unsigned int[256]; - bcLhist = new unsigned int[256]; - //bcabhist = new unsigned int[256]; + histRed(256); histRedRaw(256); + histGreen(256); histGreenRaw(256); + histBlue(256); histBlueRaw(256); + histLuma(256); + histToneCurve(256); + histLCurve(256); + bcabhist(256); } @@ -75,27 +75,6 @@ ImProcCoordinator::~ImProcCoordinator () { for (int i=0; idecreaseRef (); updaterThreadStart.unlock (); } @@ -111,6 +90,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { mProcessing.lock (); + int numofphases = 10; + int readyphase = 0; + ipf.setScale (scale); // Check if any detail crops need high detail. If not, take a fast path short cut @@ -124,16 +106,21 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if( !highDetailNeeded ){ rp.dmethod = RAWParams::methodstring[RAWParams::fast]; rp.ca_autocorrect = false; - rp.hotdeadpix_filt = false; + //rp.hotdeadpix_filt = false; rp.ccSteps = 0; } - if ( todo & M_PREPROC) + progress ("Applying white balance, color correction & sRBG conversion...",100*readyphase/numofphases); + if ( todo & M_PREPROC) { imgsrc->preprocess( rp ); + imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw ); + } + if( todo & M_RAW){ fineDetailsProcessed = highDetailNeeded; imgsrc->demosaic( rp ); } + if (todo & M_INIT) { Glib::Mutex::Lock lock(minit); @@ -161,105 +148,131 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, scale); setScale (scale); - progress ("Sample ...",45); imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); + } + readyphase++; - progress ("Rotate / Distortion...",50); + progress ("Rotate / Distortion...",100*readyphase/numofphases); bool needstransform = ipf.needsTransform(); // Remove transformation if unneeded if (!needstransform && orig_prev!=oprevi) { delete oprevi; oprevi = orig_prev; } - - if ((todo & M_TRANSFORM) && needstransform) { - if (oprevi==orig_prev) oprevi = new Image16 (pW, pH); + if (needstransform && orig_prev==oprevi) + oprevi = new Imagefloat (pW, pH); + if ((todo & M_TRANSFORM) && needstransform) ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH); - } - progress ("Shadow/highlight...",55); + readyphase++; + + progress ("Preparing shadow/highlight map...",100*readyphase/numofphases); if ((todo & M_BLURMAP) && params.sh.enabled) { double radius = sqrt (double(pW*pW+pH*pH)) / 2.0; - double shradius = radius / 1800.0 * params.sh.radius; - shmap->update (oprevi, (unsigned short**)buffer, shradius, ipf.lumimul, params.sh.hq); + double shradius = params.sh.radius; + if (!params.sh.hq) shradius *= radius / 1800.0; + shmap->update (oprevi, shradius, ipf.lumimul, params.sh.hq, scale); + } + readyphase++; if (todo & M_AUTOEXP) { if (params.toneCurve.autoexp) { - unsigned int *aehist = new unsigned int[65536]; int aehistcompr; - imgsrc->getAEHistogram (aehist, aehistcompr); + LUTu aehist; int aehistcompr; + imgsrc->getAutoExpHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black); if (aeListener) aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.black); - delete [] aehist; } } - progress ("Lab/curves ...",60); - if (todo & M_RGBCURVE) { + progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); + if ((todo & M_RGBCURVE) || todo==CROP) { + if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); + + // complexCurve also calculated pre-curves histogram dependend on crop CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, \ params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, \ params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, \ - imgsrc->getDefGain(), imgsrc->getGamma(), true, params.toneCurve.curve, vhist16, \ - hltonecurve, shtonecurve, tonecurve, bcrgbhist, scale==1 ? 1 : 1); - ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation); + imgsrc->getGamma(), true, params.toneCurve.curve, \ + vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, scale==1 ? 1 : 1); + + // if it's just crop we just need the histogram, no image updates + if ( todo!=CROP ) { + ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation); + } - // recompute luminance histogram - memset (lhist16, 0, 65536*sizeof(int)); - for (int i=0; iL[i][j]]++; + // compute L channel histogram + int x1, y1, x2, y2, pos; + params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + lhist16.clear(); lhist16Cropped.clear(); + for (int x=0; xL[x][y])); + lhist16[pos]++; + + if (y>=y1 && y=x1 && xhasListener () && cropCall != crops[i] ) crops[i]->update (todo); // may call outselves - progress ("Conversion to RGB...",95); + progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP) { previmg->getMutex().lock(); try { ipf.lab2rgb (nprevl, previmg); + delete workimg; + workimg = ipf.lab2rgb (nprevl, 0,0,pW,pH, params.icm.working); } catch(char * str) { - progress ("Error converting file...",0); - previmg->getMutex().unlock(); + progress ("Error converting file...",0); + previmg->getMutex().unlock(); mProcessing.unlock (); return; } @@ -291,20 +306,14 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (imageListener) imageListener->imageReady (params.crop); + readyphase++; if (hListener) { - int hx1 = 0, hx2 = pW, hy1 = 0, hy2 = pH; - if (params.crop.enabled) { - hx1 = MIN(pW-1,MAX(0,params.crop.x / scale)); - hy1 = MIN(pH-1,MAX(0,params.crop.y / scale)); - hx2 = MIN(pW,MAX(0,(params.crop.x+params.crop.w) / scale)); - hy2 = MIN(pH,MAX(0,(params.crop.y+params.crop.h) / scale)); - } - updateHistograms (hx1, hy1, hx2, hy2); - hListener->histogramChanged (rhist, ghist, bhist, Lhist, bcrgbhist, bcLhist); + updateLRGBHistograms (); + hListener->histogramChanged (histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histRedRaw, histGreenRaw, histBlueRaw); } - progress ("PROGRESSBAR_READY",100); + progress ("Ready",100*readyphase/numofphases); mProcessing.unlock (); } @@ -319,15 +328,16 @@ void ImProcCoordinator::freeAll () { delete orig_prev; delete oprevl; delete nprevl; + if (imageListener) { imageListener->delImage (previmg); } else delete previmg; + + delete workimg; delete shmap; - for (int i=0; iverbose) printf ("setscale before lock\n"); pW = nW; pH = nH; - orig_prev = new Image16 (pW, pH); + orig_prev = new Imagefloat (pW, pH); oprevi = orig_prev; oprevl = new LabImage (pW, pH); nprevl = new LabImage (pW, pH); previmg = new Image8 (pW, pH); + workimg = new Image8 (pW, pH); shmap = new SHMap (pW, pH, true); - - buffer = new int*[pH]; - for (int i=0; iverbose) printf ("setscale before lock\n"); } -void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { +void ImProcCoordinator::updateLRGBHistograms () { - memset (rhist, 0, 256*sizeof(int)); - memset (ghist, 0, 256*sizeof(int)); - memset (bhist, 0, 256*sizeof(int)); - //memset (bcrgbhist, 0, 256*sizeof(int)); + int x1, y1, x2, y2; + params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + histRed.clear(); + histGreen.clear(); + histBlue.clear(); + for (int i=y1; idata[ofs++]; - int g=previmg->data[ofs++]; - int b=previmg->data[ofs++]; - - //bcrgbhist[(int)(0.299*r + 0.587*g + 0.114*b)]++; - rhist[r]++; - ghist[g]++; - bhist[b]++; + int r=workimg->data[ofs++]; + int g=workimg->data[ofs++]; + int b=workimg->data[ofs++]; + + histRed[r]++; + histGreen[g]++; + histBlue[b]++; } } - memset (Lhist, 0, 256*sizeof(int)); + histLuma.clear(); for (int i=y1; iL[i][j]/256]++; + histLuma[(int)(nprevl->L[i][j]/128)]++; } /*for (int i=0; i<256; i++) { @@ -423,10 +432,10 @@ void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { void ImProcCoordinator::progress (Glib::ustring str, int pr) { - if (plistener) { +/* if (plistener) { plistener->setProgressStr (str); plistener->setProgress ((double)pr / 100.0); - } + }*/ } void ImProcCoordinator::getAutoWB (double& temp, double& green) { @@ -504,35 +513,37 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { - - mProcessing.lock (); - - int fW, fH; - imgsrc->getFullSize (fW, fH, 0); - PreviewProps pp (0, 0, fW, fH, 1); - ProcParams ppar = params; - ppar.hlrecovery.enabled = false; - ppar.icm.input = "(none)"; - Image16* im = new Image16 (fW, fH); - imgsrc->preprocess( ppar.raw ); - imgsrc->demosaic(ppar.raw ); - //imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); - ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green); - if (params.wb.method=="Camera") - currWB = imgsrc->getWB (); - else if (params.wb.method=="Auto") { - if (!awbComputed) { - autoWB = imgsrc->getAutoWB (); - awbComputed = true; - } - currWB = autoWB; - } - params.wb.temperature = currWB.getTemp (); - params.wb.green = currWB.getGreen (); - imgsrc->getImage (currWB, 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); - im->saveTIFF (fname,16,true); - mProcessing.unlock (); + mProcessing.lock (); + + int fW, fH; + imgsrc->getFullSize (fW, fH, 0); + PreviewProps pp (0, 0, fW, fH, 1); + ProcParams ppar = params; + ppar.hlrecovery.enabled = false; + ppar.icm.input = "(none)"; + Imagefloat* im = new Imagefloat (fW, fH); + Image16* im16 = new Image16 (fW, fH); + imgsrc->preprocess( ppar.raw ); + imgsrc->demosaic(ppar.raw ); + //imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); + ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green); + if (params.wb.method=="Camera") + currWB = imgsrc->getWB (); + else if (params.wb.method=="Auto") { + if (!awbComputed) { + autoWB = imgsrc->getAutoWB (); + awbComputed = true; + } + currWB = autoWB; + } + params.wb.temperature = currWB.getTemp (); + params.wb.green = currWB.getGreen (); + imgsrc->getImage (currWB, 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); + im16 = im->to16(); + im16->saveTIFF (fname,16,true); + //im->saveJPEG (fname, 85); + mProcessing.unlock (); } void ImProcCoordinator::stopProcessing () { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 5395955f5..660107778 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -26,6 +26,7 @@ #include #include #include +#include "LUT.h" namespace rtengine { @@ -40,15 +41,15 @@ class ImProcCoordinator : public StagedImageProcessor { friend class Crop; protected: - Image16 *orig_prev; - Image16 *oprevi; + Imagefloat *orig_prev; + Imagefloat *oprevi; LabImage *oprevl; LabImage *nprevl; Image8 *previmg; + Image8 *workimg; + ImageSource* imgsrc; - int** buffer; - SHMap* shmap; ColorTemp currWB; @@ -64,20 +65,21 @@ class ImProcCoordinator : public StagedImageProcessor { void freeAll (); - float *dummy1; - float *dummy2; - float *hltonecurve; - float *shtonecurve; - int *tonecurve; - - int *lumacurve; - float *chroma_acurve; - float *chroma_bcurve; + LUTf hltonecurve; + LUTf shtonecurve; + LUTf tonecurve; + + LUTf lumacurve; + LUTf chroma_acurve; + LUTf chroma_bcurve; + LUTf satcurve; - unsigned int *vhist16; - unsigned int *lhist16; - - unsigned int *rhist, *ghist, *bhist, *Lhist, *bcrgbhist, *bcLhist, *bcabhist; + LUTu vhist16; + LUTu lhist16,lhist16Cropped; + LUTu histCropped; + + LUTu histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, bcabhist; + LUTu histRedRaw, histGreenRaw, histBlueRaw; int fw, fh, tr, fullw, fullh; int pW, pH; @@ -96,7 +98,7 @@ class ImProcCoordinator : public StagedImageProcessor { void progress (Glib::ustring str, int pr); void reallocAll (); - void updateHistograms (int x1, int y1, int x2, int y2); + void updateLRGBHistograms (); void setScale (int prevscale); void updatePreviewImage (int todo, Crop* cropCall= NULL); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index ec8a878b9..b51f2489e 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -19,13 +19,14 @@ #ifndef _IMPROCFUN_H_ #define _IMPROCFUN_H_ +#include #include #include #include #include #include #include -#include +#include "LUT.h" namespace rtengine { @@ -33,40 +34,33 @@ using namespace procparams; class ImProcFunctions { - static int* cacheL; - static int* cachea; - static int* cacheb; - static int* xcache; - static int* ycache; - static int* zcache; - static unsigned short* gamma2curve; + static LUTf gamma2curve; cmsHTRANSFORM monitorTransform; - int chroma_scale; - int chroma_radius; - const ProcParams* params; double scale; bool multiThread; + float g; - void simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH); - void vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH); - void transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH); - void transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH); - void sharpenHaloCtrl (LabImage* lab, unsigned short** blurmap, unsigned short** base, int W, int H); - void firstAnalysis_ (Image16* original, const TMatrix &wprof, unsigned int* histogram, int* chroma_radius, int row_from, int row_to); - void dcdamping (float** aI, unsigned short** aO, float damping, int W, int H); + void simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); + void vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH); + void transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); + void transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); + void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H); + void firstAnalysisThread(Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to); + void dcdamping (float** aI, float** aO, float damping, int W, int H); bool needsCA (); bool needsDistortion (); bool needsRotation (); bool needsPerspective (); bool needsVignetting (); + // static cmsUInt8Number* Mempro = NULL; public: - + static LUTf cachef; double lumimul[3]; static void initCache (); @@ -80,48 +74,72 @@ class ImProcFunctions { bool needsTransform (); - void firstAnalysis (Image16* working, const ProcParams* params, unsigned int* vhist16, double gamma); - void rgbProc (Image16* working, LabImage* lab, float* hltonecurve, float* shtonecurve, int* tonecurve, SHMap* shmap, int sat); - void luminanceCurve (LabImage* lold, LabImage* lnew, int* curve); - void chrominanceCurve (LabImage* lold, LabImage* lnew, float* acurve, float* bcurve); + void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16, double gamma); + void rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat); + void luminanceCurve (LabImage* lold, LabImage* lnew, LUTf &curve); + void chrominanceCurve (LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve); void colorCurve (LabImage* lold, LabImage* lnew); - void sharpening (LabImage* lab, unsigned short** buffer); + void sharpening (LabImage* lab, float** buffer); void lumadenoise (LabImage* lab, int** buffer); void colordenoise (LabImage* lab, int** buffer); - void transform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH); + void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void lab2rgb (LabImage* lab, Image8* image); void resize (Image16* src, Image16* dst, double dScale); - void deconvsharpening (LabImage* lab, unsigned short** buffer); - void waveletEqualizer (Image16 * image); + void deconvsharpening (LabImage* lab, float** buffer); + void waveletEqualizer (Imagefloat * image); void waveletEqualizer (LabImage * image, bool luminance, bool chromaticity); void impulsedenoise (LabImage* lab);//Emil's impulse denoise - void dirpyrdenoise (LabImage* lab);//Emil's impulse denoise + void impulse_nr (LabImage* lab, double thresh); + void dirpyrdenoise (LabImage* lab);//Emil's pyramid denoise void dirpyrequalizer (LabImage* lab);//Emil's equalizer - void dirpyrLab_denoise(LabImage * src, LabImage * dst, int luma, int chroma, float gamma );//Emil's directional pyramid denoise - void dirpyr (LabImage* data_fine, LabImage* data_coarse, int level, int * rangefn_L, int * rangefn_ab, int pitch, int scale, const int luma, int chroma ); - void idirpyr (LabImage* data_coarse, LabImage* data_fine, int level, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, int chroma ); + procparams::DirPyrDenoiseParams dnparams; + void dirpyrLab_denoise(LabImage * src, LabImage * dst, const procparams::DirPyrDenoiseParams & dnparams );//Emil's directional pyramid denoise + void dirpyr (LabImage* data_fine, LabImage* data_coarse, int level, LUTf &rangefn_L, LUTf &rangefn_ab, \ + int pitch, int scale, const int luma, int chroma ); + void idirpyr (LabImage* data_coarse, LabImage* data_fine, int level, LUTf &rangefn_L, LUTf & nrwt_l, LUTf & nrwt_ab, \ + int pitch, int scale, const int luma, const int chroma/*, LUTf & Lcurve, LUTf & abcurve*/ ); void dirpyrLab_equalizer (LabImage * src, LabImage * dst, const double * mult );//Emil's directional pyramid equalizer - void dirpyr_eq (LabImage* data_coarse, LabImage* data_fine, int * rangefn, int level, int pitch, int scale, const double * mult ); - void idirpyr_eq (LabImage* data_coarse, LabImage* data_fine, int *** buffer, int * irangefn, int level, int pitch, int scale, const double * mult ); + void dirpyr_eq (LabImage* data_coarse, LabImage* data_fine, LUTf & rangefn, int level, int pitch, int scale, const double * mult ); + void idirpyr_eq (LabImage* data_coarse, LabImage* data_fine, int *** buffer, int level, int pitch, int scale, const double * mult ); - void dirpyr_equalizer (unsigned short ** src, unsigned short ** dst, int srcwidth, int srcheight, const double * mult );//Emil's directional pyramid equalizer - void dirpyr_channel (unsigned short ** data_fine, unsigned short ** data_coarse, int width, int height, int * rangefn, int level, int scale, const double * mult ); - void idirpyr_eq_channel (unsigned short ** data_coarse, unsigned short ** data_fine, int ** buffer, int width, int height, int level, const double * mult ); + void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, const double * mult );//Emil's directional pyramid equalizer + void dirpyr_channel (float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale, const double * mult ); + void idirpyr_eq_channel (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, const double * mult ); void defringe (LabImage* lab); void PF_correct_RT (LabImage * src, LabImage * dst, double radius, int thresh, bool edges); Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); - Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); + Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam);// for gamma output + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile);//without gamma ==>default bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1); bool transCoord (int W, int H, std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1); - void getAutoExp (unsigned int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl); - static double getAutoDistor (const Glib::ustring& fname, int thumb_size); + void getAutoExp (LUTu & histogram, int histcompr, double expcomp, double clip, double& br, int& bl); + static double getAutoDistor (const Glib::ustring& fname, int thumb_size); double getTransformAutoFill (int oW, int oH); + + void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); + void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); + void xyz2srgb (float x, float y, float z, float &r, float &g, float &b); + void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, float rgb_xyz[3][3]); + void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); + void XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b); + void Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v); + void Yuv2Lab(float Y, float u, float v, float &L, float &a, float &b, double wp[3][3]); + + //void gamutmap(LabImage* ); + void gamutmap(float &X, float &Y, float &Z, const double p[3][3]); + + static inline float f2xyz(register float f) { + const float epsilonExpInv3 = 6.0/29.0; + const float kappaInv = 27.0/24389.0; // inverse of kappa + + return (f > epsilonExpInv3) ? f*f*f : (116 * f - 16) * kappaInv; + } }; } #endif diff --git a/rtengine/impulse_denoise.h b/rtengine/impulse_denoise.h index f1bb9bf3c..1efd45334 100644 --- a/rtengine/impulse_denoise.h +++ b/rtengine/impulse_denoise.h @@ -22,79 +22,35 @@ #include #include - -// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// modified version of Gabor's implementation of bilateral filtering, without input pixel - -#define NBRWT(a,b) (src[i - a][j - b] * ec[src[i - a][j - b]-src[i][j]+0x10000]) -#define NORM(a,b) (ec[src[i - a][j - b]-src[i][j]+0x10000]) - -//ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*rangewidth*rangewidth))*scale); \ - -#define RB_BEGIN(a,b) double scale = (a); \ - int* ec = new int [0x20000]; \ - for (int i=0; i<0x20000; i++) \ - ec[i] = (int)(1 + 1024/(abs(i-0x10000) + 1)); \ - int rstart = b; \ - int rend = H-b; \ - int cstart = b; \ - int cend = W-b; - -#define RB_END(b) buffer[i][j] = v; }} delete [] ec; \ - for (int i=0; i=rend || j>=cend) \ - dst[i][j] = src[i][j]; \ - else \ - dst[i][j] = buffer[i][j]; - -#define RB_OPER5 for (int i=rstart; i +#include -template void rangeblur (T** src, T** dst, T** buffer, int W, int H, double rangewidth, bool multiThread) { - - RB_BEGIN(753,2) -#pragma omp parallel for if (multiThread) - RB_OPER5 - RB_END(2) - -} +namespace rtengine { - - -template void impulse_nr (T** src, T** dst, int width, int height, double thresh) { +void ImProcFunctions::impulse_nr (LabImage* lab, double thresh) { // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // impulse noise removal // local variables + int width = lab->W; + int height = lab->H; + float hpfabs, hfnbrave; // buffer for the lowpass image - unsigned short ** lpf = new unsigned short *[height]; - for (int i=0; i void impulse_nr (T** src, T** dst, int width, int height, doub // modified bilateral filter for lowpass image, omitting input pixel; or Gaussian blur static float eps = 1.0; - float wtdsum, dirwt, norm; + float wtdsum[3], dirwt, norm; int i1, j1; - //rangeblur (src, lpf, impish /*used as buffer here*/, width, height, thresh, false); + //rangeblur (lab->L, lpf, impish /*used as buffer here*/, width, height, thresh, false); AlignedBuffer* buffer = new AlignedBuffer (MAX(width,height)); - gaussHorizontal (src, lpf, buffer, width, height, 2.0, false /*multiThread*/); - gaussVertical (lpf, lpf, buffer, width, height, 2.0, false); + gaussHorizontal (lab->L, lpf, buffer, width, height, 2.0, false /*multiThread*/); + gaussVertical (lpf, lpf, buffer, width, height, 2.0, false); delete buffer; @@ -120,11 +76,11 @@ template void impulse_nr (T** src, T** dst, int width, int height, doub for (int i=0; i < height; i++) for (int j=0; j < width; j++) { - hpfabs = fabs(src[i][j]-lpf[i][j]); + hpfabs = fabs(lab->L[i][j]-lpf[i][j]); //block average of high pass data for (i1=MAX(0,i-2), hfnbrave=0; i1<=MIN(i+2,height-1); i1++ ) for (j1=MAX(0,j-2); j1<=MIN(j+2,width-1); j1++ ) { - hfnbrave += fabs(src[i1][j1]-lpf[i1][j1]); + hfnbrave += fabs(lab->L[i1][j1]-lpf[i1][j1]); } hfnbrave = (hfnbrave-hpfabs)/24; hpfabs>(hfnbrave*(5.5-thresh)) ? impish[i][j]=1 : impish[i][j]=0; @@ -135,32 +91,36 @@ template void impulse_nr (T** src, T** dst, int width, int height, doub for (int j=0; j < width; j++) { if (!impish[i][j]) continue; norm=0.0; - wtdsum=0.0; + wtdsum[0]=wtdsum[1]=wtdsum[2]=0.0; for (i1=MAX(0,i-2), hfnbrave=0; i1<=MIN(i+2,height-1); i1++ ) for (j1=MAX(0,j-2); j1<=MIN(j+2,width-1); j1++ ) { if (i1==i && j1==j) continue; if (impish[i1][j1]) continue; - dirwt = 1/(SQR(src[i1][j1]-src[i][j])+eps);//use more sophisticated rangefn??? - wtdsum += dirwt*src[i1][j1]; + dirwt = 1/(SQR(lab->L[i1][j1]-lab->L[i][j])+eps);//use more sophisticated rangefn??? + wtdsum[0] += dirwt*lab->L[i1][j1]; + wtdsum[1] += dirwt*lab->a[i1][j1]; + wtdsum[2] += dirwt*lab->b[i1][j1]; norm += dirwt; } //wtdsum /= norm; if (norm) { - src[i][j]=wtdsum/norm;//low pass filter + lab->L[i][j]=wtdsum[0]/norm;//low pass filter + lab->a[i][j]=wtdsum[1]/norm;//low pass filter + lab->b[i][j]=wtdsum[2]/norm;//low pass filter } }//now impulsive values have been corrected - for (int i=0; iequalizer.enabled) { return; diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 95900da69..47aee24d6 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -20,6 +20,13 @@ #include #include #include +#include +#include +#include +#include +#include +//#include + #ifdef _OPENMP #include #endif @@ -33,80 +40,104 @@ namespace rtengine { #define CMAXVAL 0xffff #define CLIP(a) ((a)>0?((a)(b)?((a)<(c)?(a):(c)):(b)) +#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) + + +#define D50x 0.96422 +#define D50z 0.82521 extern const Settings* settings; + +const double (*wprof[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best}; +const double (*iwprof[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz}; +const char* wprofnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"}; +const int numprof = 7; void ImProcFunctions::lab2rgb (LabImage* lab, Image8* image) { - - if (chroma_scale == 0) - return; + //MyTime tBeg,tEnd; + // tBeg.set(); + //gamutmap(lab); if (monitorTransform) { - int ix = 0; - short* buffer = new short [3*lab->W]; + + // cmsDoTransform is relatively expensive + #pragma omp parallel for if (multiThread) for (int i=0; iH; i++) { - unsigned short* rL = lab->L[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; - int iy = 0; + float buffer[3*lab->W]; + float g; + + const int ix = i * 3 * lab->W; + int iy = 0; + + float* rL = lab->L[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; + + float fy,fx,fz,x_,y_,z_; + for (int j=0; jW; j++) { + + fy = (0.00862069 * rL[j]) / 327.68 + 0.137932; // (L+16)/116 + fx = (0.002 * ra[j]) / 327.68 + fy; + fz = fy - (0.005 * rb[j]) / 327.68; + + x_ = f2xyz(fx)*D50x;//should this be 32767??? buffer is short int !!! + y_ = f2xyz(fy); + z_ = f2xyz(fz)*D50z; - int y_ = rL[j]; - int x_ = rL[j]+10486+ra[j]*152/chroma_scale+141556; - int z_ = rL[j]+10486-rb[j]*380/chroma_scale+369619; - - x_ = CLIPTO(x_,0,369820); - y_ = CLIPTO(y_,0,825745); - - y_ = ycache[y_]; - x_ = xcache[x_]; - z_ = zcache[z_]; - - buffer[iy++] = CLIP(x_); - buffer[iy++] = CLIP(y_); - buffer[iy++] = CLIP(z_); + buffer[iy++] = CLIP01(x_); + buffer[iy++] = CLIP01(y_); + buffer[iy++] = CLIP01(z_); } + + if (settings->LCMSSafeMode) lcmsMutex->lock (); cmsDoTransform (monitorTransform, buffer, image->data + ix, lab->W); - ix += 3*lab->W; + if (settings->LCMSSafeMode) lcmsMutex->unlock (); } - delete [] buffer; - } - else { + + } else { + #pragma omp parallel for if (multiThread) for (int i=0; iH; i++) { - unsigned short* rL = lab->L[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; - int ix = 3*i*lab->W; + float* rL = lab->L[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; + int ix = i * 3 * lab->W; + float g; + + float R,G,B; + float fy,fx,fz,x_,y_,z_; + for (int j=0; jW; j++) { + + //float L1=rL[j],a1=ra[j],b1=rb[j];//for testing + + fy = (0.00862069 * rL[j]) / 327.68 + 0.137932; // (L+16)/116 + fx = (0.002 * ra[j]) / 327.68 + fy; + fz = fy - (0.005 * rb[j]) / 327.68; + + x_ = 65535.0 * f2xyz(fx)*D50x; + y_ = 65535.0 * f2xyz(fy); + z_ = 65535.0 * f2xyz(fz)*D50z; - int y_ = rL[j]; - int x_ = rL[j]+10486+ra[j]*152/chroma_scale+141556; - int z_ = rL[j]+10486-rb[j]*380/chroma_scale+369619; - - x_ = CLIPTO(x_,0,369820); - y_ = CLIPTO(y_,0,825745); - - y_ = ycache[y_]; - x_ = xcache[x_]; - z_ = zcache[z_]; - - /* XYZ-D50 to RGB */ - int R = (25689*x_-13261*y_-4022*z_) >> 13; - int G = (-8017*x_+15697*y_+274*z_) >> 13; - int B = (590*x_-1877*y_+11517*z_) >> 13; + xyz2srgb(x_,y_,z_,R,G,B); /* copy RGB */ - image->data[ix++] = gamma2curve[CLIP(R)] >> 8; - image->data[ix++] = gamma2curve[CLIP(G)] >> 8; - image->data[ix++] = gamma2curve[CLIP(B)] >> 8; + image->data[ix++] = (int)gamma2curve[(R)] >> 8; + image->data[ix++] = (int)gamma2curve[(G)] >> 8; + image->data[ix++] = (int)gamma2curve[(B)] >> 8; } } } + + //tEnd.set(); + //printf("lab2rgb %i %d\n", lab->W, tEnd.etime(tBeg)); } Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile) { + //gamutmap(lab); + if (cx<0) cx = 0; if (cy<0) cy = 0; if (cx+cw>lab->W) cw = lab->W-cx; @@ -119,72 +150,90 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, if (oprof) { cmsHPROFILE iprof = iccStore->getXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_8, settings->colorimetricIntent, 0); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_8, settings->colorimetricIntent, + settings->LCMSSafeMode ? cmsFLAGS_NOOPTIMIZE : cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety lcmsMutex->unlock (); - int ix = 0; - short* buffer = new short [3*cw]; - for (int i=cy; iL[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; - int iy = 0; - for (int j=cx; jdata + ix, cw); - ix += 3*cw; - } - delete [] buffer; - cmsDeleteTransform(hTransform); - } - else { + // cmsDoTransform is relatively expensive #pragma omp parallel for if (multiThread) for (int i=cy; iL[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; + short buffer [3*cw]; + float g; + + const int ix = i * 3 * cw; + int iy = 0; + + float* rL = lab->L[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; + + for (int j=cx; jLCMSSafeMode) lcmsMutex->lock (); + cmsDoTransform (hTransform, buffer, image->data + ix, cw); + if (settings->LCMSSafeMode) lcmsMutex->unlock (); + } + + cmsDeleteTransform(hTransform); + } else { + + float rgb_xyz[3][3]; + + for (int i=0; iL[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; int ix = 3*i*cw; for (int j=cx; j> 13; - int G = (-8017*x_+15697*y_+274*z_) >> 13; - int B = (590*x_-1877*y_+11517*z_) >> 13; - - image->data[ix++] = gamma2curve[CLIP(R)] >> 8; - image->data[ix++] = gamma2curve[CLIP(G)] >> 8; - image->data[ix++] = gamma2curve[CLIP(B)] >> 8; + image->data[ix++] = (int)gamma2curve[(R)] >> 8; + image->data[ix++] = (int)gamma2curve[(G)] >> 8; + image->data[ix++] = (int)gamma2curve[(B)] >> 8; } } } return image; } - +// for default (not gamma) Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile) { + + //gamutmap(lab); if (cx<0) cx = 0; if (cy<0) cy = 0; @@ -192,73 +241,197 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int if (cy+ch>lab->H) ch = lab->H-cy; Image16* image = new Image16 (cw, ch); - - cmsHPROFILE oprof = iccStore->getProfile (profile); + cmsHPROFILE oprof = iccStore->getProfile (profile); + + if (oprof) { #pragma omp parallel for if (multiThread) for (int i=cy; iL[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; + float g; + float* rL = lab->L[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; short* xa = (short*)image->r[i-cy]; short* ya = (short*)image->g[i-cy]; short* za = (short*)image->b[i-cy]; for (int j=cx; jgetXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16_PLANAR, oprof, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16_PLANAR, oprof, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_NOOPTIMIZE); lcmsMutex->unlock (); - cmsDoTransform (hTransform, image->data, image->data, image->planestride/2); + + cmsDoTransform (hTransform, image->data, image->data, image->planestride); cmsDeleteTransform(hTransform); - } - else { + } else { #pragma omp parallel for if (multiThread) for (int i=cy; iL[i]; - short* ra = lab->a[i]; - short* rb = lab->b[i]; + float g; + float R,G,B; + float* rL = lab->L[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; for (int j=cx; j> 13; - int G = (-8017*x_+15697*y_+274*z_) >> 13; - int B = (590*x_-1877*y_+11517*z_) >> 13; - - image->r[i-cy][j-cx] = gamma2curve[CLIP(R)]; - image->g[i-cy][j-cx] = gamma2curve[CLIP(G)]; - image->b[i-cy][j-cx] = gamma2curve[CLIP(B)]; + image->r[i-cy][j-cx] = (int)gamma2curve[(R)]; + image->g[i-cy][j-cx] = (int)gamma2curve[(G)]; + image->b[i-cy][j-cx] = (int)gamma2curve[(B)]; } } } return image; } + +// for gamma options (BT709...sRGB linear...) +Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam) { + + //gamutmap(lab); + + if (cx<0) cx = 0; + if (cy<0) cy = 0; + if (cx+cw>lab->W) cw = lab->W-cx; + if (cy+ch>lab->H) ch = lab->H-cy; + + Image16* image = new Image16 (cw, ch); + cmsBool rc = TRUE; + float p1,p2,p3,p4,p5,p6;//primaries + float ga0,ga1,ga2,ga3,ga4,ga5=0;//gamma parameters + int t50; + int select_temp =1;//5003K + double eps=0.000000001;// not divide by zero + //primaries + if(profi=="ProPhoto") {p1=0.7347; p2=0.2653; p3=0.1596; p4=0.8404; p5=0.0366; p6=0.0001;select_temp=1;}//Prophoto primaries + else if (profi=="WideGamut") {p1=0.7350; p2=0.2650; p3=0.1150; p4=0.8260; p5=0.1570; p6=0.0180;select_temp=1;}//Widegamut primaries + else if (profi=="Adobe RGB") {p1=0.6400; p2=0.3300; p3=0.2100; p4=0.7100; p5=0.1500; p6=0.0600;select_temp=2;}//Adobe primaries + else if (profi=="sRGB") {p1=0.6400; p2=0.3300; p3=0.3000; p4=0.6000; p5=0.1500; p6=0.0600;select_temp=2;} // sRGB primaries + else if (profi=="BruceRGB") {p1=0.6400; p2=0.3300; p3=0.2800; p4=0.6500; p5=0.1500; p6=0.0600;select_temp=2;} // Bruce primaries + else if (profi=="Beta RGB") {p1=0.6888; p2=0.3112; p3=0.1986; p4=0.7551; p5=0.1265; p6=0.0352;select_temp=1;} // Beta primaries + else if (profi=="BestRGB") {p1=0.7347; p2=0.2653; p3=0.2150; p4=0.7750; p5=0.1300; p6=0.0350;select_temp=1;} // Best primaries + + // gamma : ga0,ga1,ga2,ga3,ga4,ga5 by calcul + if(gam=="BT709_g2.2_s4.5") {ga0=2.222;ga1=1./1.099258;ga2=0.099258/1.099258;ga3=1./4.5; ga4=0.01805;ga5=0;}//BT709 2.2 4.5 - my prefered as D.Coffin ga4=0.01805 + else if (gam=="sRGB_g2.4_s12.92") {ga0=2.3999 ; ga1=1./1.0550; ga2=0.0550/1.0550;ga3=1./12.92;ga4=0.039289;}//sRGB 2.4 12.92 - RT default as Lightroom + else if (gam=="High_g1.3_s3.35") {ga0=1.3 ; ga1=1./1.001724; ga2=0.001724/1.001724;ga3=1./3.35;ga4=0.001715;}//for high dynamic images + else if (gam== "Low_g2.6_s6.9") {ga0=2.6 ; ga1=1./1.12213; ga2=0.12213/1.12213;ga3=1./6.90;ga4=0.01;} //gamma 2.6 variable : for low contrast images + else if (gam=="linear_g1.0") {ga0=1.0; ga1=1.;ga2=0.;ga3=1./eps;ga4=0.;}//gamma=1 linear : for high dynamic images (cf : D.Coffin...) + else if (gam=="standard_g2.2") {ga0=2.2; ga1=1.;ga2=0.;ga3=1./eps;ga4=0.;}//gamma=2.2 (as gamma of Adobe, Widegamut...) + else if (gam=="standard_g1.8") {ga0=1.8; ga1=1.;ga2=0.;ga3=1./eps;ga4=0.;}//gamma=1.8 (as gamma of Prophoto) + + + if(select_temp==1) t50=5003;// for Widegamut, Prophoto Best, Beta D50 + else if (select_temp==2) t50=6504;// for sRGB, AdobeRGB, Bruce D65 + + cmsCIExyY xyD; + cmsCIExyYTRIPLE Primaries = {{p1, p2, 1.0},//red primaries + {p3, p4, 1.0}, // green + {p5, p6, 1.0} //blue + }; + cmsToneCurve* GammaTRC[3]; + cmsFloat64Number Parameters[7]; + Parameters[0] = ga0; + Parameters[1] = ga1; + Parameters[2] = ga2; + Parameters[3] = ga3; + Parameters[4] = ga4; + Parameters[5] = ga5; + Parameters[6] = 0; +// 6 parameters for smoother curves + cmsWhitePointFromTemp(&xyD, t50); + GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters);//5 = more smoother than 4 + cmsHPROFILE oprofdef = cmsCreateRGBProfileTHR(NULL, &xyD, &Primaries, GammaTRC); + + cmsFreeToneCurve(GammaTRC[0]); + + + if (oprofdef) { + #pragma omp parallel for if (multiThread) + for (int i=cy; iL[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; + short* xa = (short*)image->r[i-cy]; + short* ya = (short*)image->g[i-cy]; + short* za = (short*)image->b[i-cy]; + for (int j=cx; jgetXYZProfile (); + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16_PLANAR, oprofdef, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_NOOPTIMIZE); + lcmsMutex->unlock (); + + cmsDoTransform (hTransform, image->data, image->data, image->planestride); + cmsDeleteTransform(hTransform); + } else { + // + #pragma omp parallel for if (multiThread) + for (int i=cy; iL[i]; + float* ra = lab->a[i]; + float* rb = lab->b[i]; + for (int j=cx; jr[i-cy][j-cx] = (int)gamma2curve[(R)]; + image->g[i-cy][j-cx] = (int)gamma2curve[(G)]; + image->b[i-cy][j-cx] = (int)gamma2curve[(B)]; + } + } + } + return image; +} + +//#include "sRGBgamutbdy.cc" + } diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 278a96c1c..e7a3c121c 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -35,7 +35,7 @@ namespace rtengine { #define CLIP(a) ((a)>0?((a)sharpening.enabled==false || params->sharpening.deconvamount<1) return; @@ -107,13 +107,15 @@ void ImProcFunctions::deconvsharpening (LabImage* lab, unsigned short** b2) { } // end for delete buffer; + float p2 = params->sharpening.deconvamount /100.0; + float p1 = 1.0 - p2; #ifdef _OPENMP #pragma omp for #endif for (int i=0; iL[i][j] = lab->L[i][j]*(100-params->sharpening.deconvamount) / 100 + (int)CLIP(tmpI[i][j])*params->sharpening.deconvamount / 100; + lab->L[i][j] = lab->L[i][j]*p1 + CLIP(tmpI[i][j])*p2; } // end parallel @@ -122,7 +124,7 @@ void ImProcFunctions::deconvsharpening (LabImage* lab, unsigned short** b2) { delete [] tmpI; } -void ImProcFunctions::sharpening (LabImage* lab, unsigned short** b2) { +void ImProcFunctions::sharpening (LabImage* lab, float** b2) { if (params->sharpening.method=="rld") { deconvsharpening (lab, b2); @@ -133,32 +135,33 @@ void ImProcFunctions::sharpening (LabImage* lab, unsigned short** b2) { return; int W = lab->W, H = lab->H; - unsigned short** b3; + float** b3; if (params->sharpening.edgesonly) { - b3 = new unsigned short*[H]; + b3 = new float*[H]; for (int i=0; i* buffer = new AlignedBuffer (MAX(W,H)); if (params->sharpening.edgesonly==false) { - gaussHorizontal (lab->L, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); - gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); + + gaussHorizontal (lab->L, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); + gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); } else { - bilateral (lab->L, (unsigned short**)b3, b2, W, H, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance, multiThread); - gaussHorizontal (b3, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); - gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); + bilateral (lab->L, (float**)b3, b2, W, H, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance, multiThread); + gaussHorizontal (b3, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); + gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale, multiThread); } delete buffer; - unsigned short** base = lab->L; + float** base = lab->L; if (params->sharpening.edgesonly) base = b3; @@ -184,10 +187,10 @@ void ImProcFunctions::sharpening (LabImage* lab, unsigned short** b2) { } } -void ImProcFunctions::sharpenHaloCtrl (LabImage* lab, unsigned short** blurmap, unsigned short** base, int W, int H) { +void ImProcFunctions::sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H) { int scale = 100 * (100-params->sharpening.halocontrol_amount); - unsigned short** nL = base; + float** nL = base; #pragma omp parallel for if (multiThread) for (int i=2; i(b)?((a)<(c)?(a):(c)):(b)) #define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):(d=true,(c))):(d=true,(b))) #define RT_PI 3.141592653589 +#define SQR(x) ((x)*(x)) bool ImProcFunctions::transCoord (int W, int H, std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef) { @@ -183,7 +185,7 @@ bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& return result; } -void ImProcFunctions::transform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { +void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective()) && needsVignetting()) vignetting (original, transformed, cx, cy, oW, oH); @@ -216,7 +218,7 @@ void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, do mul = (1.0-v) / tanh(b); } -void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH) { +void ImProcFunctions::vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) { double vig_w2; double vig_h2; @@ -245,7 +247,7 @@ void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int c } #include "cubint.cc" -void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { +void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; @@ -353,7 +355,7 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, } #include "cubintch.cc" -void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { +void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; @@ -371,11 +373,11 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cdist[0] = params->cacorrection.red; cdist[1] = 0.0; cdist[2] = params->cacorrection.blue; - unsigned short** chorig[3]; + float** chorig[3]; chorig[0] = original->r; chorig[1] = original->g; chorig[2] = original->b; - unsigned short** chtrans[3]; + float** chtrans[3]; chtrans[0] = transformed->r; chtrans[1] = transformed->g; chtrans[2] = transformed->b; @@ -392,13 +394,15 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int // auxiliary variables for vertical perspective correction double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90.0 - vpdeg) / 180.0 * RT_PI; - double vpteta = fabs(vpalpha-RT_PI/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-oW*oW*tan(vpalpha)*tan(vpalpha) + (vpdeg>0 ? 1.0 : -1.0) * oW*tan(vpalpha)*sqrt(16*maxRadius*maxRadius+oW*oW*tan(vpalpha)*tan(vpalpha)))/(maxRadius*maxRadius*8))); + double vpteta = fabs(vpalpha-RT_PI/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-SQR(oW*tan(vpalpha)) + (vpdeg>0 ? 1.0 : -1.0) * \ + oW*tan(vpalpha)*sqrt(SQR(4*maxRadius)+SQR(oW*tan(vpalpha))))/(SQR(maxRadius)*8))); double vpcospt = (vpdeg>=0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); // auxiliary variables for horizontal perspective correction double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90.0 - hpdeg) / 180.0 * RT_PI; - double hpteta = fabs(hpalpha-RT_PI/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-oH*oH*tan(hpalpha)*tan(hpalpha) + (hpdeg>0 ? 1.0 : -1.0) * oH*tan(hpalpha)*sqrt(16*maxRadius*maxRadius+oH*oH*tan(hpalpha)*tan(hpalpha)))/(maxRadius*maxRadius*8))); + double hpteta = fabs(hpalpha-RT_PI/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-SQR(oH*tan(hpalpha)) + (hpdeg>0 ? 1.0 : -1.0) * \ + oH*tan(hpalpha)*sqrt(SQR(4*maxRadius)+SQR(oH*tan(hpalpha))))/(SQR(maxRadius)*8))); double hpcospt = (hpdeg>=0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH) : 1.0; @@ -472,7 +476,7 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int } } -void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { +void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; diff --git a/rtengine/jdatasrc.c b/rtengine/jdatasrc.c index d33452fb8..c30c4c37a 100644 --- a/rtengine/jdatasrc.c +++ b/rtengine/jdatasrc.c @@ -1,13 +1,13 @@ -#include -#include -#include -#include "jpeg.h" - +#include +#include +#include +#include "jpeg.h" + /* * jdatasrc.c * * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2009-2010 by Guido Vollbeding. + * Modified 2009-2010 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -22,20 +22,20 @@ /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ //#include "jinclude.h" - -#define JFREAD(file,buf,sizeofbuf) \ - ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) -#define JFWRITE(file,buf,sizeofbuf) \ - ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) - - + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) + + /* Expanded data source object for stdio input */ typedef struct { struct jpeg_source_mgr pub; /* public fields */ - jmp_buf error_jmp_buf; /* error handler for this instance */ + jmp_buf error_jmp_buf; /* error handler for this instance */ FILE * infile; /* source stream */ JOCTET * buffer; /* start of buffer */ @@ -228,7 +228,7 @@ my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) METHODDEF(void) my_error_exit (j_common_ptr cinfo) -{ +{ /* Always display the message */ (*cinfo->err->output_message) (cinfo); diff --git a/rtengine/klt/trackFeatures.c b/rtengine/klt/trackFeatures.c index 91ee5ce39..5bfb801b1 100644 --- a/rtengine/klt/trackFeatures.c +++ b/rtengine/klt/trackFeatures.c @@ -567,7 +567,9 @@ static int _am_gauss_jordan_elimination(float **a, int n, float **b, int m) row=j; col=k; } - } else if (ipiv[k] > 1) return KLT_SMALL_DET; + } else if (ipiv[k] > 1) { + free(ipiv); free(indxr); free(indxc); return KLT_SMALL_DET; + } } ++(ipiv[col]); if (row != col) { diff --git a/rtengine/labimage.cc b/rtengine/labimage.cc index d6f351c8e..dbdb96d34 100644 --- a/rtengine/labimage.cc +++ b/rtengine/labimage.cc @@ -3,40 +3,30 @@ namespace rtengine { LabImage::LabImage (int w, int h) : fromImage(false), W(w), H(h) { - L = new unsigned short*[H]; + L = new float*[H]; + a = new float*[H]; + b = new float*[H]; + + data = new float [W*H*3]; + float * index = data; for (int i=0; iwidth; - H = im->height; - L = im->r; - a = (short**) im->g; - b = (short**) im->b; - fromImage = true; + b[i] = index + i*W; } LabImage::~LabImage () { if (!fromImage) { - for (int i=0; i #endif +#ifdef BZIP_SUPPORT +#include +#endif // get mmap() sorted out #ifdef MYFILE_MMAP @@ -94,6 +97,76 @@ IMFILE* fopen (const char* fname) mf->data = (char*)data; mf->eof = false; +#ifdef BZIP_SUPPORT + { + bool bzip = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + bzip = bname.substr (lastdot).casefold() == Glib::ustring(".bz2").casefold(); + + if (bzip) { + int ret; + + // initialize bzip stream structure + bz_stream stream; + stream.bzalloc = 0; + stream.bzfree = 0; + stream.opaque = 0; + ret = BZ2_bzDecompressInit(&stream, 0, 0); + + if (ret != BZ_OK) { + printf("bzip initialization failed with error %d\n", ret); + } + else { + // allocate initial buffer for decompressed data + unsigned int buffer_out_count = 0; // bytes of decompressed data + unsigned int buffer_size = 10*1024*1024; // 10 MB, extended dynamically if needed + char* buffer = 0; + + stream.next_in = mf->data; // input data address + stream.avail_in = mf->size; + + while (ret == BZ_OK) { + buffer = static_cast( realloc(buffer, buffer_size)); // allocate/resize buffer + + stream.next_out = buffer + buffer_out_count; // output data adress + stream.avail_out = buffer_size - buffer_out_count; + + ret = BZ2_bzDecompress(&stream); + + buffer_size *= 2; // increase buffer size for next iteration + buffer_out_count = stream.total_out_lo32; + if (stream.total_out_hi32 > 0) + printf("bzip decompressed data byte count high byte is nonzero: %d\n", stream.total_out_hi32); + } + + if (ret == BZ_STREAM_END) { + //delete [] mf->data; + // close memory mapping, setting fd -1 will ensure deletion of mf->data upon fclose() + mf->fd = -1; + munmap((void*)mf->data,mf->size); + close(mf->fd); + + char* realData = new char [buffer_out_count]; + memcpy(realData, buffer, buffer_out_count); + + mf->data = realData; + mf->size = buffer_out_count; + } + else + printf("bzip decompression failed with error %d\n", ret); + + // cleanup + free(buffer); + ret = BZ2_bzDecompressEnd(&stream); + if (ret != BZ_OK) + printf("bzip cleanup failed with error %d\n", ret); + } + } + } +#endif // BZIP_SUPPORT + return mf; } @@ -137,8 +210,7 @@ IMFILE* fopen (const char* fname) { } // RAWZOR support end #endif - - return mf; + return mf; } IMFILE* gfopen (const char* fname) { @@ -176,7 +248,71 @@ IMFILE* gfopen (const char* fname) { } // RAWZOR support end #endif - return mf; +#ifdef BZIP_SUPPORT + { + bool bzip = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + bzip = bname.substr (lastdot).casefold() == Glib::ustring(".bz2").casefold(); + + if (bzip) { + int ret; + + // initialize bzip stream structure + bz_stream stream; + stream.bzalloc = 0; + stream.bzfree = 0; + stream.opaque = 0; + ret = BZ2_bzDecompressInit(&stream, 0, 0); + + if (ret != BZ_OK) { + printf("bzip initialization failed with error %d\n", ret); + } + else { + // allocate initial buffer for decompressed data + unsigned int buffer_out_count = 0; // bytes of decompressed data + unsigned int buffer_size = 10*1024*1024; // 10 MB, extended dynamically if needed + char* buffer = 0; + + stream.next_in = mf->data; // input data address + stream.avail_in = mf->size; + + while (ret == BZ_OK) { + buffer = static_cast( realloc(buffer, buffer_size)); // allocate/resize buffer + + stream.next_out = buffer + buffer_out_count; // output data adress + stream.avail_out = buffer_size - buffer_out_count; + + ret = BZ2_bzDecompress(&stream); + + buffer_size *= 2; // increase buffer size for next iteration + buffer_out_count = stream.total_out_lo32; + if (stream.total_out_hi32 > 0) + printf("bzip decompressed data byte count high byte is nonzero: %d\n", stream.total_out_hi32); + } + + if (ret == BZ_STREAM_END) { + delete [] mf->data; + char* realData = new char [buffer_out_count]; + memcpy(realData, buffer, buffer_out_count); + + mf->data = realData; + mf->size = buffer_out_count; + } + else + printf("bzip decompression failed with error %d\n", ret); + + // cleanup + free(buffer); + ret = BZ2_bzDecompressEnd(&stream); + if (ret != BZ_OK) + printf("bzip cleanup failed with error %d\n", ret); + } + } + } +#endif // BZIP_SUPPORT + return mf; } #endif //MYFILE_MMAP diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 1b5b5d889..a46ecd8e9 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -151,8 +151,12 @@ enum ProcEvent { EvFlatFieldAutoSelect=126, EvFlatFieldBlurRadius=127, EvFlatFieldBlurType=128, - EvAutoDIST=129, - NUMOFEVENTS=130 - }; -} -#endif + EvAutoDIST=129, + EvDPDNLumCurve=130, + EvDPDNChromCurve=131, + EvGAMMA=132, + NUMOFEVENTS=133 + + }; +} +#endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f57fdfc9f..59d35e411 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -24,8 +24,8 @@ #include #include #include -#include #include +#include #include @@ -37,6 +37,17 @@ namespace procparams { const char *RAWParams::methodstring[RAWParams::numMethods]={"eahd", "hphd", "vng4", "dcb", "amaze", "ahd", "fast" }; const char *RAWParams::ff_BlurTypestring[RAWParams::numFlatFileBlurTypes]={/*"Parametric",*/ "Area Flatfield", "Vertical Flatfield", "Horizontal Flatfield", "V+H Flatfield"}; +// Maps crop to resized width (e.g. smaller previews) +void CropParams::mapToResized(int resizedWidth, int resizedHeight, int scale, int &x1, int &x2, int &y1, int &y2) const { + x1 = 0, x2 = resizedWidth, y1 = 0, y2 = resizedHeight; + if (enabled) { + x1 = MIN(resizedWidth-1, MAX(0, x / scale)); + y1 = MIN(resizedHeight-1, MAX(0, y / scale)); + x2 = MIN(resizedWidth, MAX(0, (x+w) / scale)); + y2 = MIN(resizedHeight, MAX(0, (y+h) / scale)); + } +} + ProcParams::ProcParams () { setDefaults (); @@ -59,7 +70,7 @@ void ProcParams::setDefaults () { toneCurve.expcomp = 0; toneCurve.brightness = 0; toneCurve.contrast = 0; - toneCurve.saturation = 0; + toneCurve.saturation = 0; toneCurve.black = 0; toneCurve.hlcompr = 70; toneCurve.hlcomprthresh = 0; @@ -69,13 +80,13 @@ void ProcParams::setDefaults () { labCurve.brightness = 0; labCurve.contrast = 0; - labCurve.saturation = 0; - labCurve.avoidclip = false; + labCurve.saturation = 0; + labCurve.avoidclip = false; labCurve.enable_saturationlimiter = false; - labCurve.saturationlimit = 40; + labCurve.saturationlimit = 50; labCurve.lcurve.clear (); labCurve.lcurve.push_back(DCT_Linear); - labCurve.acurve.clear (); + labCurve.acurve.clear (); labCurve.acurve.push_back(DCT_Linear); labCurve.bcurve.clear (); labCurve.bcurve.push_back(DCT_Linear); @@ -116,17 +127,21 @@ void ProcParams::setDefaults () { colorDenoise.radius = 1.9; colorDenoise.edgetolerance = 2000; - impulseDenoise.enabled = false; - impulseDenoise.thresh = 50; + impulseDenoise.enabled = false; + impulseDenoise.thresh = 50; - defringe.enabled = false; - defringe.radius = 2.0; - defringe.threshold = 25; + defringe.enabled = false; + defringe.radius = 2.0; + defringe.threshold = 25; - dirpyrDenoise.enabled = false; + dirpyrDenoise.enabled = false; dirpyrDenoise.luma = 10; - dirpyrDenoise.chroma = 10; - dirpyrDenoise.gamma = 2.0; + dirpyrDenoise.chroma = 10; + dirpyrDenoise.gamma = 2.0; + dirpyrDenoise.lumcurve.clear (); + dirpyrDenoise.lumcurve.push_back (DCT_Linear); + dirpyrDenoise.chromcurve.clear (); + dirpyrDenoise.chromcurve.push_back (DCT_Linear); sh.enabled = false; sh.hq = false; @@ -195,7 +210,8 @@ void ProcParams::setDefaults () { icm.gammaOnInput = false; icm.working = "sRGB"; icm.output = "sRGB"; - + icm.gamma = "default"; + equalizer.enabled = false; for(int i = 0; i < 8; i ++) { @@ -206,32 +222,33 @@ void ProcParams::setDefaults () { { dirpyrequalizer.mult[i] = 1.0; } - dirpyrequalizer.mult[4] = 0.0; - hsvequalizer.hcurve.clear (); - hsvequalizer.hcurve.push_back (FCT_Linear); - hsvequalizer.scurve.clear (); - hsvequalizer.scurve.push_back (FCT_Linear); - hsvequalizer.vcurve.clear (); - hsvequalizer.vcurve.push_back (FCT_Linear); + dirpyrequalizer.mult[4] = 0.0; + hsvequalizer.hcurve.clear (); + hsvequalizer.hcurve.push_back (FCT_Linear); + hsvequalizer.scurve.clear (); + hsvequalizer.scurve.push_back (FCT_Linear); + hsvequalizer.vcurve.clear (); + hsvequalizer.vcurve.push_back (FCT_Linear); raw.df_autoselect = false; raw.ff_AutoSelect = false; raw.ff_BlurRadius = 32; raw.ff_BlurType = RAWParams::ff_BlurTypestring[RAWParams::area_ff]; raw.cared = 0; - raw.cablue = 0; + raw.cablue = 0; raw.ca_autocorrect = false; raw.hotdeadpix_filt = false; + raw.hotdeadpix_thresh = 40; raw.linenoise = 0; raw.greenthresh = 0; raw.ccSteps = 1; raw.dmethod = RAWParams::methodstring[RAWParams::hphd];; raw.dcb_iterations=2; raw.dcb_enhance=false; - //exposition + // exposure before interpolation raw.expos=1.0; raw.preser=0.0; - //raw.expos_correc=false; - // expos + + exif.clear (); iptc.clear (); @@ -329,6 +346,10 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_integer ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma); keyFile.set_integer ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma); keyFile.set_double ("Directional Pyramid Denoising", "Gamma", dirpyrDenoise.gamma); + Glib::ArrayHandle lumcurve = dirpyrDenoise.lumcurve; + Glib::ArrayHandle chromcurve = dirpyrDenoise.chromcurve; + keyFile.set_double_list("Directional Pyramid Denoising", "LumCurve", lumcurve); + keyFile.set_double_list("Directional Pyramid Denoising", "ChromCurve", chromcurve); // save lumaDenoise keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled); @@ -407,6 +428,7 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_boolean ("Color Management", "ApplyGammaBeforeInputProfile", icm.gammaOnInput); keyFile.set_string ("Color Management", "WorkingProfile", icm.working); keyFile.set_string ("Color Management", "OutputProfile", icm.output); + keyFile.set_string ("Color Management", "Gammafree", icm.gamma); // save wavelet equalizer parameters keyFile.set_boolean ("Equalizer", "Enabled", equalizer.enabled); @@ -444,16 +466,16 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_integer ("RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius ); keyFile.set_string ("RAW", "FlatFieldBlurType", raw.ff_BlurType ); keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); - keyFile.set_double ("RAW", "CARed", raw.cared ); + keyFile.set_double ("RAW", "CARed", raw.cared ); keyFile.set_double ("RAW", "CABlue", raw.cablue ); keyFile.set_boolean ("RAW", "HotDeadPixels", raw.hotdeadpix_filt ); + keyFile.set_integer ("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh ); 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 ); - //exposure keyFile.set_double ("RAW", "PreExposure", raw.expos ); keyFile.set_double ("RAW", "PrePreserv", raw.preser ); @@ -544,7 +566,6 @@ if (keyFile.has_group ("Luminance Curve")) { if (keyFile.has_key ("Luminance Curve", "AvoidColorClipping")) labCurve.avoidclip = keyFile.get_boolean ("Luminance Curve", "AvoidColorClipping"); if (keyFile.has_key ("Luminance Curve", "SaturationLimiter")) labCurve.enable_saturationlimiter= keyFile.get_boolean ("Luminance Curve", "SaturationLimiter"); if (keyFile.has_key ("Luminance Curve", "SaturationLimit")) labCurve.saturationlimit = keyFile.get_double ("Luminance Curve", "SaturationLimit"); - if (ppVersion>200) if (keyFile.has_key ("Luminance Curve", "LCurve")) labCurve.lcurve = keyFile.get_double_list ("Luminance Curve", "LCurve"); if (keyFile.has_key ("Luminance Curve", "aCurve")) labCurve.acurve = keyFile.get_double_list ("Luminance Curve", "aCurve"); if (keyFile.has_key ("Luminance Curve", "bCurve")) labCurve.bcurve = keyFile.get_double_list ("Luminance Curve", "bCurve"); @@ -614,6 +635,8 @@ if (keyFile.has_group ("Directional Pyramid Denoising")) { if (keyFile.has_key ("Directional Pyramid Denoising", "Luma")) dirpyrDenoise.luma = keyFile.get_integer ("Directional Pyramid Denoising", "Luma"); if (keyFile.has_key ("Directional Pyramid Denoising", "Chroma")) dirpyrDenoise.chroma = keyFile.get_integer ("Directional Pyramid Denoising", "Chroma"); if (keyFile.has_key ("Directional Pyramid Denoising", "Gamma")) dirpyrDenoise.gamma = keyFile.get_double ("Directional Pyramid Denoising", "Gamma"); + if (keyFile.has_key ("Directional Pyramid Denoising", "LumCurve")) dirpyrDenoise.lumcurve = keyFile.get_double_list ("Directional Pyramid Denoising", "LumCurve"); + if (keyFile.has_key ("Directional Pyramid Denoising", "ChromCurve")) dirpyrDenoise.chromcurve = keyFile.get_double_list ("Directional Pyramid Denoising", "ChromCurve"); } // load lumaDenoise @@ -720,6 +743,8 @@ if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "ApplyGammaBeforeInputProfile")) icm.gammaOnInput = keyFile.get_boolean ("Color Management", "ApplyGammaBeforeInputProfile"); if (keyFile.has_key ("Color Management", "WorkingProfile")) icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (keyFile.has_key ("Color Management", "OutputProfile")) icm.output = keyFile.get_string ("Color Management", "OutputProfile"); + if (keyFile.has_key ("Color Management", "Gammafree")) icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); + } // load wavelet equalizer parameters @@ -762,9 +787,10 @@ if (keyFile.has_group ("RAW")) { if (keyFile.has_key ("RAW", "FlatFieldBlurRadius")) raw.ff_BlurRadius = keyFile.get_integer ("RAW", "FlatFieldBlurRadius" ); if (keyFile.has_key ("RAW", "FlatFieldBlurType")) raw.ff_BlurType = keyFile.get_string ("RAW", "FlatFieldBlurType" ); if (keyFile.has_key ("RAW", "CA")) raw.ca_autocorrect = keyFile.get_boolean ("RAW", "CA" ); - if (keyFile.has_key ("RAW", "CARed")) raw.cared = keyFile.get_double ("RAW", "CARed" ); - if (keyFile.has_key ("RAW", "CABlue")) raw.cablue = keyFile.get_double ("RAW", "CABlue" ); + if (keyFile.has_key ("RAW", "CARed")) raw.cared = keyFile.get_double ("RAW", "CARed" ); + if (keyFile.has_key ("RAW", "CABlue")) raw.cablue = keyFile.get_double ("RAW", "CABlue" ); if (keyFile.has_key ("RAW", "HotDeadPixels")) raw.hotdeadpix_filt = keyFile.get_boolean ("RAW", "HotDeadPixels" ); + if (keyFile.has_key ("RAW", "HotDeadPixelThresh")) raw.hotdeadpix_thresh = keyFile.get_integer ("RAW", "HotDeadPixelThresh" ); if (keyFile.has_key ("RAW", "LineDenoise")) raw.linenoise = keyFile.get_integer ("RAW", "LineDenoise" ); if (keyFile.has_key ("RAW", "GreenEqThreshold")) raw.greenthresh= keyFile.get_integer ("RAW", "GreenEqThreshold"); if (keyFile.has_key ("RAW", "CcSteps")) raw.ccSteps = keyFile.get_integer ("RAW", "CcSteps"); @@ -773,8 +799,6 @@ if (keyFile.has_group ("RAW")) { if (keyFile.has_key ("RAW", "DCBEnhance")) raw.dcb_enhance =keyFile.get_boolean("RAW", "DCBEnhance"); if (keyFile.has_key ("RAW", "PreExposure")) raw.expos =keyFile.get_double("RAW", "PreExposure"); if (keyFile.has_key ("RAW", "PrePreserv")) raw.preser =keyFile.get_double("RAW", "PrePreserv"); - - } // load exif change settings @@ -843,140 +867,143 @@ bool operator==(const IPTCPair& a, const IPTCPair& b) { } bool ProcParams::operator== (const ProcParams& other) { - return - toneCurve.curve == other.toneCurve.curve - && toneCurve.brightness == other.toneCurve.brightness - && toneCurve.black == other.toneCurve.black - && toneCurve.contrast == other.toneCurve.contrast + return + toneCurve.curve == other.toneCurve.curve + && toneCurve.brightness == other.toneCurve.brightness + && toneCurve.black == other.toneCurve.black + && toneCurve.contrast == other.toneCurve.contrast && toneCurve.saturation == other.toneCurve.saturation - && toneCurve.shcompr == other.toneCurve.shcompr - && toneCurve.hlcompr == other.toneCurve.hlcompr - && toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh - && toneCurve.autoexp == other.toneCurve.autoexp - && toneCurve.clip == other.toneCurve.clip - && toneCurve.expcomp == other.toneCurve.expcomp - && labCurve.lcurve == other.labCurve.lcurve - && labCurve.acurve == other.labCurve.acurve - && labCurve.bcurve == other.labCurve.bcurve - && labCurve.brightness == other.labCurve.brightness - && labCurve.contrast == other.labCurve.contrast + && toneCurve.shcompr == other.toneCurve.shcompr + && toneCurve.hlcompr == other.toneCurve.hlcompr + && toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh + && toneCurve.autoexp == other.toneCurve.autoexp + && toneCurve.clip == other.toneCurve.clip + && toneCurve.expcomp == other.toneCurve.expcomp + && labCurve.lcurve == other.labCurve.lcurve + && labCurve.acurve == other.labCurve.acurve + && labCurve.bcurve == other.labCurve.bcurve + && labCurve.brightness == other.labCurve.brightness + && labCurve.contrast == other.labCurve.contrast && labCurve.saturation == other.labCurve.saturation && labCurve.avoidclip == other.labCurve.avoidclip && labCurve.enable_saturationlimiter == other.labCurve.enable_saturationlimiter - && labCurve.saturationlimit == other.labCurve.saturationlimit - && sharpening.enabled == other.sharpening.enabled - && sharpening.radius == other.sharpening.radius - && sharpening.amount == other.sharpening.amount - && sharpening.threshold == other.sharpening.threshold - && sharpening.edgesonly == other.sharpening.edgesonly - && sharpening.edges_radius == other.sharpening.edges_radius - && sharpening.edges_tolerance == other.sharpening.edges_tolerance - && sharpening.halocontrol == other.sharpening.halocontrol - && sharpening.halocontrol_amount== other.sharpening.halocontrol_amount - && sharpening.method == other.sharpening.method - && sharpening.deconvamount == other.sharpening.deconvamount - && sharpening.deconvradius == other.sharpening.deconvradius - && sharpening.deconviter == other.sharpening.deconviter - && sharpening.deconvdamping == other.sharpening.deconvdamping - && colorBoost.amount == other.colorBoost.amount - && colorBoost.avoidclip == other.colorBoost.avoidclip - && colorBoost.enable_saturationlimiter == other.colorBoost.enable_saturationlimiter - && colorBoost.saturationlimit == other.colorBoost.saturationlimit - && wb.method == other.wb.method - && wb.green == other.wb.green - && wb.temperature == other.wb.temperature - && colorShift.a == other.colorShift.a - && colorShift.b == other.colorShift.b - && impulseDenoise.enabled == other.impulseDenoise.enabled - && impulseDenoise.thresh == other.impulseDenoise.thresh - && dirpyrDenoise.enabled == other.dirpyrDenoise.enabled - && dirpyrDenoise.luma == other.dirpyrDenoise.luma - && dirpyrDenoise.chroma == other.dirpyrDenoise.chroma - && dirpyrDenoise.gamma == other.dirpyrDenoise.gamma - && defringe.enabled == other.defringe.enabled - && defringe.radius == other.defringe.radius - && defringe.threshold == other.defringe.threshold - && lumaDenoise.enabled == other.lumaDenoise.enabled - && lumaDenoise.radius == other.lumaDenoise.radius - && lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance - && colorDenoise.enabled == other.colorDenoise.enabled - && colorDenoise.radius == other.colorDenoise.radius - && colorDenoise.edgetolerance == other.colorDenoise.edgetolerance - && colorDenoise.edgesensitive == other.colorDenoise.edgesensitive - && sh.enabled == other.sh.enabled - && sh.hq == other.sh.hq - && sh.highlights == other.sh.highlights - && sh.htonalwidth == other.sh.htonalwidth - && sh.shadows == other.sh.shadows - && sh.stonalwidth == other.sh.stonalwidth - && sh.localcontrast == other.sh.localcontrast - && sh.radius == other.sh.radius - && crop.enabled == other.crop.enabled - && crop.x == other.crop.x - && crop.y == other.crop.y - && crop.w == other.crop.w - && crop.h == other.crop.h - && crop.fixratio == other.crop.fixratio - && crop.ratio == other.crop.ratio - && crop.orientation == other.crop.orientation - && crop.guide == other.crop.guide - && coarse.rotate == other.coarse.rotate - && coarse.hflip == other.coarse.hflip - && coarse.vflip == other.coarse.vflip - && rotate.degree == other.rotate.degree - && commonTrans.autofill == other.commonTrans.autofill - && distortion.uselensfun == other.distortion.uselensfun - && distortion.amount == other.distortion.amount - && perspective.horizontal == other.perspective.horizontal - && perspective.vertical == other.perspective.vertical - && cacorrection.red == other.cacorrection.red - && cacorrection.blue == other.cacorrection.blue - && vignetting.amount == other.vignetting.amount - && vignetting.radius == other.vignetting.radius - && vignetting.strength == other.vignetting.strength - && vignetting.centerX == other.vignetting.centerX - && vignetting.centerY == other.vignetting.centerY - && !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int)) - && !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int)) - && !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int)) - && hlrecovery.enabled == other.hlrecovery.enabled - && hlrecovery.method == other.hlrecovery.method - && resize.scale == other.resize.scale - && resize.appliesTo == other.resize.appliesTo - && resize.method == other.resize.method - && 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.ff_file == other.raw.ff_file - && raw.ff_AutoSelect == other.raw.ff_AutoSelect - && raw.ff_BlurRadius == other.raw.ff_BlurRadius - && raw.ff_BlurType == other.raw.ff_BlurType - && 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.cared == other.raw.cared - && raw.cablue == other.raw.cablue - && 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 - && icm.output == other.icm.output - && equalizer == other.equalizer - && dirpyrequalizer == other.dirpyrequalizer - && hsvequalizer.hcurve == other.hsvequalizer.hcurve - && hsvequalizer.scurve == other.hsvequalizer.scurve - && hsvequalizer.vcurve == other.hsvequalizer.vcurve - && exif==other.exif - && iptc==other.iptc - && raw.expos==other.raw.expos // exposi - && raw.preser==other.raw.preser; -} + && labCurve.saturationlimit == other.labCurve.saturationlimit + && sharpening.enabled == other.sharpening.enabled + && sharpening.radius == other.sharpening.radius + && sharpening.amount == other.sharpening.amount + && sharpening.threshold == other.sharpening.threshold + && sharpening.edgesonly == other.sharpening.edgesonly + && sharpening.edges_radius == other.sharpening.edges_radius + && sharpening.edges_tolerance == other.sharpening.edges_tolerance + && sharpening.halocontrol == other.sharpening.halocontrol + && sharpening.halocontrol_amount== other.sharpening.halocontrol_amount + && sharpening.method == other.sharpening.method + && sharpening.deconvamount == other.sharpening.deconvamount + && sharpening.deconvradius == other.sharpening.deconvradius + && sharpening.deconviter == other.sharpening.deconviter + && sharpening.deconvdamping == other.sharpening.deconvdamping + && colorBoost.amount == other.colorBoost.amount + && colorBoost.avoidclip == other.colorBoost.avoidclip + && colorBoost.enable_saturationlimiter == other.colorBoost.enable_saturationlimiter + && colorBoost.saturationlimit == other.colorBoost.saturationlimit + && wb.method == other.wb.method + && wb.green == other.wb.green + && wb.temperature == other.wb.temperature + && colorShift.a == other.colorShift.a + && colorShift.b == other.colorShift.b + && impulseDenoise.enabled == other.impulseDenoise.enabled + && impulseDenoise.thresh == other.impulseDenoise.thresh + && dirpyrDenoise.enabled == other.dirpyrDenoise.enabled + && dirpyrDenoise.luma == other.dirpyrDenoise.luma + && dirpyrDenoise.chroma == other.dirpyrDenoise.chroma + && dirpyrDenoise.gamma == other.dirpyrDenoise.gamma + && dirpyrDenoise.lumcurve == other.dirpyrDenoise.lumcurve + && dirpyrDenoise.chromcurve == other.dirpyrDenoise.chromcurve + && defringe.enabled == other.defringe.enabled + && defringe.radius == other.defringe.radius + && defringe.threshold == other.defringe.threshold + && lumaDenoise.enabled == other.lumaDenoise.enabled + && lumaDenoise.radius == other.lumaDenoise.radius + && lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance + && colorDenoise.enabled == other.colorDenoise.enabled + && colorDenoise.radius == other.colorDenoise.radius + && colorDenoise.edgetolerance == other.colorDenoise.edgetolerance + && colorDenoise.edgesensitive == other.colorDenoise.edgesensitive + && sh.enabled == other.sh.enabled + && sh.hq == other.sh.hq + && sh.highlights == other.sh.highlights + && sh.htonalwidth == other.sh.htonalwidth + && sh.shadows == other.sh.shadows + && sh.stonalwidth == other.sh.stonalwidth + && sh.localcontrast == other.sh.localcontrast + && sh.radius == other.sh.radius + && crop.enabled == other.crop.enabled + && crop.x == other.crop.x + && crop.y == other.crop.y + && crop.w == other.crop.w + && crop.h == other.crop.h + && crop.fixratio == other.crop.fixratio + && crop.ratio == other.crop.ratio + && crop.orientation == other.crop.orientation + && crop.guide == other.crop.guide + && coarse.rotate == other.coarse.rotate + && coarse.hflip == other.coarse.hflip + && coarse.vflip == other.coarse.vflip + && rotate.degree == other.rotate.degree + && commonTrans.autofill == other.commonTrans.autofill + && distortion.uselensfun == other.distortion.uselensfun + && distortion.amount == other.distortion.amount + && perspective.horizontal == other.perspective.horizontal + && perspective.vertical == other.perspective.vertical + && cacorrection.red == other.cacorrection.red + && cacorrection.blue == other.cacorrection.blue + && vignetting.amount == other.vignetting.amount + && vignetting.radius == other.vignetting.radius + && vignetting.strength == other.vignetting.strength + && vignetting.centerX == other.vignetting.centerX + && vignetting.centerY == other.vignetting.centerY + && !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int)) + && !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int)) + && !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int)) + && hlrecovery.enabled == other.hlrecovery.enabled + && hlrecovery.method == other.hlrecovery.method + && resize.scale == other.resize.scale + && resize.appliesTo == other.resize.appliesTo + && resize.method == other.resize.method + && 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.ff_file == other.raw.ff_file + && raw.ff_AutoSelect == other.raw.ff_AutoSelect + && raw.ff_BlurRadius == other.raw.ff_BlurRadius + && raw.ff_BlurType == other.raw.ff_BlurType + && 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.cared == other.raw.cared + && raw.cablue == other.raw.cablue + && 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 + && icm.output == other.icm.output + && icm.gamma == other.icm.gamma + && equalizer == other.equalizer + && dirpyrequalizer == other.dirpyrequalizer + && hsvequalizer.hcurve == other.hsvequalizer.hcurve + && hsvequalizer.scurve == other.hsvequalizer.scurve + && hsvequalizer.vcurve == other.hsvequalizer.vcurve + && exif==other.exif + && iptc==other.iptc + && raw.expos==other.raw.expos + && raw.preser==other.raw.preser; + } bool ProcParams::operator!= (const ProcParams& other) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index c9081be2a..24d9133ca 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -174,6 +174,8 @@ class ColorDenoiseParams { int luma; int chroma; float gamma; + std::vector lumcurve; + std::vector chromcurve; }; /** @@ -207,6 +209,8 @@ class CropParams { Glib::ustring ratio; Glib::ustring orientation; Glib::ustring guide; + + void mapToResized(int resizedWidth, int resizedHeight, int scale, int &x1, int &x2, int &y1, int &y2) const; }; /** @@ -327,6 +331,8 @@ class ColorManagementParams { bool gammaOnInput; Glib::ustring working; Glib::ustring output; + Glib::ustring gamma; + }; /** @@ -406,9 +412,13 @@ class RAWParams { bool ca_autocorrect; double cared; double cablue; + + // exposure before interpolation double expos; - double preser; // expos + double preser; + bool hotdeadpix_filt; + int hotdeadpix_thresh; int linenoise; int greenthresh; int ccSteps; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 0a74f3dc6..8bcf548a0 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -133,9 +133,8 @@ int RawImage::loadRaw (bool loadData, bool closeFile) verbose = settings->verbose; oprof = NULL; - ifp = gfopen (ifname); - if (!ifp) - return 3; + ifp = gfopen (ifname); // Maps to either file map or direct fopen + if (!ifp) return 3; thumb_length = 0; thumb_offset = 0; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index c0ba5dba0..7b6c52084 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -30,6 +30,9 @@ #include #include #include +#include + +#include #ifdef _OPENMP #include @@ -43,11 +46,14 @@ extern const Settings* settings; #undef MAX #undef MIN #undef DIST +#undef CLIP #define ABS(a) ((a)<0?-(a):(a)) #define MAX(a,b) ((a)<(b)?(b):(a)) #define MIN(a,b) ((a)>(b)?(b):(a)) #define DIST(a,b) (ABS(a-b)) +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)(b)) {temp=(a);(a)=(b);(b)=temp;} } @@ -60,6 +66,8 @@ PIX_SORT(p[0],p[3]); PIX_SORT(p[5],p[8]); PIX_SORT(p[4],p[7]); \ PIX_SORT(p[3],p[6]); PIX_SORT(p[1],p[4]); PIX_SORT(p[2],p[5]); \ PIX_SORT(p[4],p[7]); PIX_SORT(p[4],p[2]); PIX_SORT(p[6],p[4]); \ PIX_SORT(p[4],p[2]); median=p[4];} //a4 is the median + + RawImageSource::RawImageSource () :ImageSource() @@ -76,10 +84,12 @@ RawImageSource::RawImageSource () hrmap[1] = NULL; hrmap[2] = NULL; needhr = NULL; - hpmap = NULL; + //hpmap = NULL; camProfile = NULL; embProfile = NULL; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% RawImageSource::~RawImageSource () { @@ -89,13 +99,13 @@ RawImageSource::~RawImageSource () { } if (green) - freeArray(green, H); + freeArray(green, H); if (red) - freeArray(red, H); + freeArray(red, H); if (blue) - freeArray(blue, H); + freeArray(blue, H); if(rawData) - freeArray(rawData, H); + freeArray(rawData, H); if( cache ) delete [] cache; if (hrmap[0]!=NULL) { @@ -106,13 +116,15 @@ RawImageSource::~RawImageSource () { } if (needhr) freeArray(needhr, H); - if (hpmap) - freeArray(hpmap, H); + //if (hpmap) + // freeArray(hpmap, H); if (camProfile) cmsCloseProfile (camProfile); if (embProfile) cmsCloseProfile (embProfile); } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &ssy1, int &width, int &height, int &fw) { @@ -176,6 +188,7 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s if (fuji) { // atszamoljuk a koordinatakat fuji-ra: + // recalculate the coordinates fuji-ra: ssx1 = (sx1+sy1) / 2; ssy1 = (sy1 - sx2 ) / 2 + ri->get_FujiWidth(); int ssx2 = (sx2+sy2) / 2 + 1; @@ -191,8 +204,10 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s height = (sy2 - sy1) / pp.skip + ((sy2 - sy1) % pp.skip > 0); } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw ) +void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw ) { isrcMutex.lock (); @@ -200,27 +215,45 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe tran = defTransform (tran); // compute channel multipliers - double r, g, b, rm, gm, bm; + double r, g, b; + float rm, gm, bm; ctemp.getMultipliers (r, g, b); - 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 = cam_rgb[0][0]*r + cam_rgb[0][1]*g + cam_rgb[0][2]*b; + gm = cam_rgb[1][0]*r + cam_rgb[1][1]*g + cam_rgb[1][2]*b; + bm = cam_rgb[2][0]*r + cam_rgb[2][1]*g + cam_rgb[2][2]*b; rm = camwb_red / rm; gm = camwb_green / gm; bm = camwb_blue / bm; - double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; + + /*float mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; rm /= mul_lum; gm /= mul_lum; - bm /= mul_lum; + bm /= mul_lum;*/ + + /*//initialGain=1.0; + // in floating point, should keep white point fixed and recover higher values with exposure slider + //if (hrp.enabled) */ + float min = rm; + if (min>gm) min = gm; + if (min>bm) min = bm; + defGain=0.0;// = log(initialGain) / log(2.0); + //printf(" Initial gain=%f defgain=%f min=%f\n",initialGain,defGain,min); + //printf(" rm=%f gm=%f bm=%f\n",rm,gm,bm); + min/=initialGain; + //min=(float)1.0/min; + //else { + //defGain = 0.0; + rm /= min; + gm /= min; + bm /= min; + //} + //defGain = 0.0;//no need now for making headroom for highlights??? + //printf("initial gain= %e\n",initialGain); + //TODO: normalize the gain control + + + - if (hrp.enabled) - defGain = log(initialGain) / log(2.0); - else { - defGain = 0.0; - rm *= initialGain; - gm *= initialGain; - bm *= initialGain; - } if (hrp.enabled==true && hrp.method=="Color" && hrmap[0]==NULL) updateHLRecoveryMap_ColorPropagation (); @@ -249,8 +282,8 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe imheight = maximheight; int maxx=this->W,maxy=this->H,skip=pp.skip; - if (sx1+skip*imwidth>maxx) imwidth --; // very hard to fix this situation without an 'if' in the loop. - double area=skip*skip; + //if (sx1+skip*imwidth>maxx) imwidth --; // very hard to fix this situation without an 'if' in the loop. + float area=skip*skip; rm/=area; gm/=area; bm/=area; @@ -260,18 +293,18 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe { #endif // render the requested image part - unsigned short* line_red = new unsigned short [imwidth]; - unsigned short* line_grn = new unsigned short [imwidth]; - unsigned short* line_blue = new unsigned short [imwidth]; + float* line_red = new float[imwidth]; + float* line_grn = new float[imwidth]; + float* line_blue = new float[imwidth]; #ifdef _OPENMP #pragma omp for #endif - for (int ix=0; ixmaxy-skip) i=maxy-skip; // avoid trouble + for (int ix=0; ix=maxy-skip) i=maxy-skip-1; // avoid trouble if (ri->isBayer()) { - for (int j=0,jx=sx1; j=maxx-skip) jx=maxx-skip-1; // avoid trouble float rtot,gtot,btot; rtot=gtot=btot=0; for (int m=0; mmaxx-skip) jx=maxx-skip-1; float rtot,gtot,btot; rtot=gtot=btot=0; for (int m=0; misBayer() && pp.skip==1) - correction_YIQ_LQ (image, raw.ccSteps); - - // Applying postmul - colorSpaceConversion (image, cmp, embProfile, camProfile, cam, defGain); + correction_YIQ_LQ (image, pp.skip==1?1:raw.ccSteps); + // Applying postmul + colorSpaceConversion (image, cmp, embProfile, camProfile, xyz_cam, defGain); + isrcMutex.unlock (); } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* cfaCleanFromMap: correct raw pixels looking at the bitmap * takes into consideration if there are multiple bad pixels in the neighborhood @@ -408,12 +462,14 @@ int RawImageSource::cfaCleanFromMap( PixelsMap &bitmapBads ) rawData[row][col]= wtdsum / norm;//gradient weighted average counter++; } else { - if (tot > 0) rawData[row][col] = sum/tot;//backup plan -- simple average + if (tot > 0.1) rawData[row][col] = sum/tot;//backup plan -- simple average } } } return counter; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* Search for hot or dead pixels in the image and update the map * For each pixel compare its value to the average of similar color surrounding @@ -422,66 +478,68 @@ int RawImageSource::cfaCleanFromMap( PixelsMap &bitmapBads ) int RawImageSource::findHotDeadPixel( PixelsMap &bpMap, float thresh) { volatile int counter=0; - unsigned short (*cfablur); - cfablur = (unsigned short (*)) calloc (H*W, sizeof *cfablur); + + float (*cfablur); + cfablur = (float (*)) calloc (H*W, sizeof *cfablur); #pragma omp parallel { #pragma omp for - for (int i=0; iH-3) {inext=i-2;} else {inext=i+2;} - for (int j=0; jW-3) {jnext=j-2;} else {jnext=j+2;} - med3x3(rawData[iprev][jprev],rawData[iprev][j],rawData[iprev][jnext], \ - rawData[i][jprev],rawData[i][j],rawData[i][jnext], \ - rawData[inext][jprev],rawData[inext][j],rawData[inext][jnext],cfablur[i*W+j]); - } + for (int i=0; iH-3) {inext=i-2;} else {inext=i+2;} + for (int j=0; jW-3) {jnext=j-2;} else {jnext=j+2;} + med3x3(rawData[iprev][jprev],rawData[iprev][j],rawData[iprev][jnext], \ + rawData[i][jprev],rawData[i][j],rawData[i][jnext], \ + rawData[inext][jprev],rawData[inext][j],rawData[inext][jnext],cfablur[i*W+j]); } - - //TODO: counter needs a openmp fix. - + } + #pragma omp for - //cfa pixel heat/death evaluation - for (int rr=0; rr < H; rr++) { - for (int cc=0; cc < W; cc++) { - //rawData[rr][cc] = cfablur[rr*W+cc];//diagnostic - - //evaluate pixel for heat/death - float pixdev = (float)abs(rawData[rr][cc]-cfablur[rr*W+cc]); - float hfnbrave=0; - int top, bottom, left, right; - top=MAX(0,rr-2); - bottom=MIN(H-1,rr+2); - left=MAX(0,cc-2); - right=MIN(W-1,cc+2); - for (int mm=top; mm<=bottom; mm++) - for (int nn=left; nn<=right; nn++) { - hfnbrave += (float)abs(rawData[mm][nn]-cfablur[mm*W+nn]); - } - hfnbrave = (hfnbrave-pixdev)/((bottom-top+1)*(right-left+1)-1); - - if (pixdev > thresh*hfnbrave) { - // mark the pixel as "bad" - bpMap.set(cc,rr ); - counter++; + //cfa pixel heat/death evaluation + for (int rr=0; rr < H; rr++) { + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int cc=0; cc < W; cc++) { + //rawData[rr][cc] = cfablur[rr*W+cc];//diagnostic + + //evaluate pixel for heat/death + float pixdev = fabs(rawData[rr][cc]-cfablur[rr*W+cc]); + float hfnbrave=0; + int top=MAX(0,rr-2); + int bottom=MIN(H-1,rr+2); + int left=MAX(0,cc-2); + int right=MIN(W-1,cc+2); + for (int mm=top; mm<=bottom; mm++) + for (int nn=left; nn<=right; nn++) { + hfnbrave += fabs(rawData[mm][nn]-cfablur[mm*W+nn]); } - }//end of pixel evaluation + hfnbrave = (hfnbrave-pixdev)/((bottom-top+1)*(right-left+1)-1); - - } + if (pixdev > thresh*hfnbrave) { + // mark the pixel as "bad" + bpMap.set(cc,rr ); + counter++; + } + }//end of pixel evaluation + + + } }//end pragma free (cfablur); //printf ("counter %d \n",counter); return counter; } - -void RawImageSource::rotateLine (unsigned short* line, unsigned short** channel, int tran, int i, int w, int h) { + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void RawImageSource::rotateLine (float* line, float** channel, int tran, int i, int w, int h) { if ((tran & TR_ROT) == TR_R180) for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; - image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; - image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + image->r[row][col] = (red[j] + image->r[row+1][col]) /2; + image->g[row][col] = (green[j] + image->g[row+1][col]) /2; + image->b[row][col] = (blue[j] + image->b[row+1][col]) /2; } } else if (i==imheight-1) { int row = 2*imheight-1-2*i; for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; - image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; - image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + image->r[row][col] = (red[j] + image->r[row+1][col]) /2; + image->g[row][col] = (green[j] + image->g[row+1][col]) /2; + image->b[row][col] = (blue[j] + image->b[row+1][col]) /2; } row = 2*imheight-1-2*i+2; for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; - image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; - image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + image->r[row][col] = (red[j] + image->r[row+1][col]) /2; + image->g[row][col] = (green[j] + image->g[row+1][col]) /2; + image->b[row][col] = (blue[j] + image->b[row+1][col]) /2; } } else if (i>2 && ir[j][col] = (red[j] + image->r[j][col+1]) >> 1; - image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; - image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + image->r[j][col] = (red[j] + image->r[j][col+1]) /2; + image->g[j][col] = (green[j] + image->g[j][col+1]) /2; + image->b[j][col] = (blue[j] + image->b[j][col+1]) /2; } } else if (i==imheight-1) { int col = 2*imheight-1-2*i; for (int j=0; jr[j][col] = (red[j] + image->r[j][col+1]) >> 1; - image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; - image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + image->r[j][col] = (red[j] + image->r[j][col+1]) /2; + image->g[j][col] = (green[j] + image->g[j][col+1]) /2; + image->b[j][col] = (blue[j] + image->b[j][col+1]) /2; } col = 2*imheight-1-2*i+2; for (int j=0; jr[j][col] = (red[j] + image->r[j][col+1]) >> 1; - image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; - image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + image->r[j][col] = (red[j] + image->r[j][col+1]) /2; + image->g[j][col] = (green[j] + image->g[j][col+1]) /2; + image->b[j][col] = (blue[j] + image->b[j][col+1]) /2; } } - else if (i>2 && i2 && ir[j][col] = CLIP((int)(-0.0625*red[j] + 0.5625*image->r[j][col-1] + 0.5625*image->r[j][col+1] - 0.0625*image->r[j][col+3])); @@ -646,20 +707,20 @@ void RawImageSource::transLine (unsigned short* red, unsigned short* green, unsi if (i==1 || i==2) { // linear interpolation for (int j=0; jr[row][2*i-1] = (red[j] + image->r[row][2*i-2]) >> 1; - image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) >> 1; - image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) >> 1; + image->r[row][2*i-1] = (red[j] + image->r[row][2*i-2]) /2; + image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) /2; + image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) /2; } } else if (i==imheight-1) { for (int j=0; jr[row][2*i-1] = (red[j] + image->r[row][2*i-2]) >> 1; - image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) >> 1; - image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) >> 1; - image->r[row][2*i-3] = (image->r[row][2*i-2] + image->r[row][2*i-4]) >> 1; - image->g[row][2*i-3] = (image->g[row][2*i-2] + image->g[row][2*i-4]) >> 1; - image->b[row][2*i-3] = (image->b[row][2*i-2] + image->b[row][2*i-4]) >> 1; + image->r[row][2*i-1] = (red[j] + image->r[row][2*i-2]) /2; + image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) /2; + image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) /2; + image->r[row][2*i-3] = (image->r[row][2*i-2] + image->r[row][2*i-4]) /2; + image->g[row][2*i-3] = (image->g[row][2*i-2] + image->g[row][2*i-4]) /2; + image->b[row][2*i-3] = (image->b[row][2*i-2] + image->b[row][2*i-4]) /2; } } else if (i>0 && ir[2*i-1][j] = (red[j] + image->r[2*i-2][j]) >> 1; - image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) >> 1; - image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) >> 1; + image->r[2*i-1][j] = (red[j] + image->r[2*i-2][j]) /2; + image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) /2; + image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) /2; } } else if (i==imheight-1) { for (int j=0; jr[2*i-3][j] = (image->r[2*i-4][j] + image->r[2*i-2][j]) >> 1; - image->g[2*i-3][j] = (image->g[2*i-4][j] + image->g[2*i-2][j]) >> 1; - image->b[2*i-3][j] = (image->b[2*i-4][j] + image->b[2*i-2][j]) >> 1; - image->r[2*i-1][j] = (red[j] + image->r[2*i-2][j]) >> 1; - image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) >> 1; - image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) >> 1; + image->r[2*i-3][j] = (image->r[2*i-4][j] + image->r[2*i-2][j]) /2; + image->g[2*i-3][j] = (image->g[2*i-4][j] + image->g[2*i-2][j]) /2; + image->b[2*i-3][j] = (image->b[2*i-4][j] + image->b[2*i-2][j]) /2; + image->r[2*i-1][j] = (red[j] + image->r[2*i-2][j]) /2; + image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) /2; + image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) /2; } } else if (i>2 && ib, tran, i, imwidth, imheight); } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::getFullSize (int& w, int& h, int tr) { @@ -735,6 +798,8 @@ void RawImageSource::getFullSize (int& w, int& h, int tr) { w -= 2 * border; h -= 2 * border; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) { @@ -751,34 +816,38 @@ void RawImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) { h = pp.h / pp.skip + (pp.h % pp.skip > 0); // } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::hflip (Image16* image) { +void RawImageSource::hflip (Imagefloat* image) { int width = image->width; int height = image->height; - unsigned short* rowr = new unsigned short[width]; - unsigned short* rowg = new unsigned short[width]; - unsigned short* rowb = new unsigned short[width]; + float* rowr = new float[width]; + float* rowg = new float[width]; + float* rowb = new float[width]; for (int i=0; ir[i][width-1-j]; rowg[j] = image->g[i][width-1-j]; rowb[j] = image->b[i][width-1-j]; } - memcpy (image->r[i], rowr, width*sizeof(unsigned short)); - memcpy (image->g[i], rowg, width*sizeof(unsigned short)); - memcpy (image->b[i], rowb, width*sizeof(unsigned short)); + memcpy (image->r[i], rowr, width*sizeof(float)); + memcpy (image->g[i], rowg, width*sizeof(float)); + memcpy (image->b[i], rowb, width*sizeof(float)); } delete [] rowr; delete [] rowg; delete [] rowb; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::vflip (Image16* image) { +void RawImageSource::vflip (Imagefloat* image) { int width = image->width; int height = image->height; - register unsigned short tmp; + register float tmp; for (int i=0; ir[i][j]; @@ -792,19 +861,9 @@ void RawImageSource::vflip (Image16* image) { image->b[height-1-i][j] = tmp; } } - -void RawImageSource::inverse33 (double (*coeff)[3], double (*icoeff)[3]) { - double nom = coeff[0][2]*coeff[1][1]*coeff[2][0] - coeff[0][1]*coeff[1][2]*coeff[2][0] - coeff[0][2]*coeff[1][0]*coeff[2][1] + coeff[0][0]*coeff[1][2]*coeff[2][1] + coeff[0][1]*coeff[1][0]*coeff[2][2] - coeff[0][0]*coeff[1][1]*coeff[2][2]; - icoeff[0][0] = (coeff[1][2]*coeff[2][1]-coeff[1][1]*coeff[2][2]) / nom; - icoeff[0][1] = -(coeff[0][2]*coeff[2][1]-coeff[0][1]*coeff[2][2]) / nom; - icoeff[0][2] = (coeff[0][2]*coeff[1][1]-coeff[0][1]*coeff[1][2]) / nom; - icoeff[1][0] = -(coeff[1][2]*coeff[2][0]-coeff[1][0]*coeff[2][2]) / nom; - icoeff[1][1] = (coeff[0][2]*coeff[2][0]-coeff[0][0]*coeff[2][2]) / nom; - icoeff[1][2] = -(coeff[0][2]*coeff[1][0]-coeff[0][0]*coeff[1][2]) / nom; - icoeff[2][0] = (coeff[1][1]*coeff[2][0]-coeff[1][0]*coeff[2][1]) / nom; - icoeff[2][1] = -(coeff[0][1]*coeff[2][0]-coeff[0][0]*coeff[2][1]) / nom; - icoeff[2][2] = (coeff[0][1]*coeff[1][0]-coeff[0][0]*coeff[1][1]) / nom; -} + + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int RawImageSource::load (Glib::ustring fname, bool batch) { @@ -813,14 +872,14 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { fileName = fname; if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_DECODING"); + plistener->setProgressStr ("Decoding..."); plistener->setProgress (0.0); } ri = new RawImage(fname); - int res = ri->loadRaw (); - if (res) - return res; + int errCode = ri->loadRaw (); + if (errCode) return errCode; + ri->compress_image(); if (plistener) { plistener->setProgress (0.8); @@ -831,9 +890,10 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { fuji = ri->get_FujiWidth()!=0; for (int i=0; i<3; i++) for (int j=0; j<3; j++) - coeff[i][j] = ri->get_rgb_cam(i,j); + rgb_cam[i][j] = ri->get_rgb_cam(i,j); // compute inverse of the color transformation matrix - inverse33 (coeff, icoeff); + // first arg is matrix, second arg is inverse + inverse33 (rgb_cam, cam_rgb); d1x = ! ri->get_model().compare("D1X"); if (d1x) @@ -842,13 +902,13 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { embProfile = cmsOpenProfileFromMem (ri->get_profile(), ri->get_profileLen()); // create profile - memset (cam, 0, sizeof(cam)); + memset (xyz_cam, 0, sizeof(xyz_cam)); for (int i=0; i<3; i++) for (int j=0; j<3; j++) for (int k=0; k<3; k++) - cam[i][j] += coeff[k][i] * sRGB_d50[k][j]; - camProfile = iccStore->createFromMatrix (cam, false, "Camera"); - inverse33 (cam, icam); + xyz_cam[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + camProfile = iccStore->createFromMatrix (xyz_cam, false, "Camera"); + inverse33 (xyz_cam, cam_xyz); float pre_mul[4]; ri->get_colorsCoeff( pre_mul, scale_mul, cblack ); @@ -858,9 +918,9 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { camwb_blue = ri->get_pre_mul(2) / pre_mul[2]; initialGain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); - 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; + double cam_r = rgb_cam[0][0]*camwb_red + rgb_cam[0][1]*camwb_green + rgb_cam[0][2]*camwb_blue; + double cam_g = rgb_cam[1][0]*camwb_red + rgb_cam[1][1]*camwb_green + rgb_cam[1][2]*camwb_blue; + double cam_b = rgb_cam[2][0]*camwb_red + rgb_cam[2][1]*camwb_green + rgb_cam[2][2]*camwb_blue; wb = ColorTemp (cam_r, cam_g, cam_b); @@ -873,10 +933,10 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { rml.ciffLength = ri->get_ciffLen(); idata = new ImageData (fname, &rml); - green = allocArray(W,H); - red = allocArray(W,H); - blue = allocArray(W,H); - hpmap = allocArray(W, H); + green = allocArray(W,H); + red = allocArray(W,H); + blue = allocArray(W,H); + //hpmap = allocArray(W, H); if (plistener) { plistener->setProgress (1.0); @@ -884,10 +944,12 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { plistener=NULL; // This must be reset, because only load() is called through progressConnector t2.set(); if( settings->verbose ) - printf("Load %s: %d usec\n",fname.c_str(), t2.etime(t1)); + printf("Load %s: %d µsec\n",fname.c_str(), t2.etime(t1)); return 0; // OK! } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::preprocess (const RAWParams &raw) { @@ -899,11 +961,12 @@ void RawImageSource::preprocess (const RAWParams &raw) if( raw.dark_frame.size()>0) rid = dfm.searchDarkFrame( raw.dark_frame ); } else { - rid = dfm.searchDarkFrame( idata->getMake(), idata->getModel(),idata->getISOSpeed(),idata->getShutterSpeed(),idata->getDateTimeAsTS()); + rid = dfm.searchDarkFrame( ri->get_maker(), ri->get_model(), ri->get_ISOspeed(), ri->get_shutter(), ri->get_timestamp()); } if( rid && settings->verbose){ printf( "Subtracting Darkframe:%s\n",rid->get_filename().c_str()); } + //copyOriginalPixels(ri, rid); //FLATFIELD start Glib::ustring newFF = raw.ff_file; @@ -917,22 +980,16 @@ void RawImageSource::preprocess (const RAWParams &raw) if( rif && settings->verbose) { printf( "Flat Field Correction:%s\n",rif->get_filename().c_str()); } - if (plistener) { - plistener->setProgress (0.0); - if( rid || rif) - plistener->setProgressStr ("PROGRESSBAR_DARKFRAME"); - } copyOriginalPixels(raw, ri, rid, rif); //FLATFIELD end + PixelsMap bitmapBads(W,H); int totBP=0; // Hold count of bad pixels to correct // Always correct camera badpixels - std::list *bp = dfm.getBadPixels( idata->getMake(), idata->getModel(), idata->getSerialNumber() ); - if( !bp && !idata->getSerialNumber().empty() ) - bp = dfm.getBadPixels( idata->getMake(), idata->getModel(), "" ); // 2nd try without serial number + std::list *bp = dfm.getBadPixels( ri->get_maker(), ri->get_model(), std::string("") ); if( bp ){ totBP+=bitmapBads.set( *bp ); if( settings->verbose ){ @@ -943,7 +1000,7 @@ void RawImageSource::preprocess (const RAWParams &raw) // If darkframe selected, correct hotpixels found on darkframe bp = 0; if( raw.df_autoselect ){ - bp = dfm.getHotPixels( idata->getMake(), idata->getModel(),idata->getISOSpeed(),idata->getShutterSpeed(), idata->getDateTimeAsTS() ); + bp = dfm.getHotPixels( ri->get_maker(), ri->get_model(), ri->get_ISOspeed(), ri->get_shutter(), ri->get_timestamp()); }else if( raw.dark_frame.size()>0 ) bp = dfm.getHotPixels( raw.dark_frame ); if(bp){ @@ -955,20 +1012,20 @@ void RawImageSource::preprocess (const RAWParams &raw) scaleColors( 0,0, W, H); - defGain = log(initialGain) / log(2.0); + defGain = 0.0;//log(initialGain) / log(2.0); - if ( raw.hotdeadpix_filt ) { - - int nFound =findHotDeadPixel( bitmapBads, 10.0 ); + if ( raw.hotdeadpix_filt>0 ) { + if (plistener) { + plistener->setProgressStr ("Hot/Dead Pixel Filter..."); + plistener->setProgress (0.0); + } + float varthresh = (20.0*((float)raw.hotdeadpix_thresh/100.0) + 1.0 ); + int nFound =findHotDeadPixel( bitmapBads, varthresh ); totBP += nFound; if( settings->verbose && nFound>0){ printf( "Correcting %d hot/dead pixels found inside image\n",nFound ); } } - if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_BADPIXELS"); - plistener->setProgress (0.1); - } if( totBP ) cfaCleanFromMap( bitmapBads ); @@ -982,13 +1039,13 @@ void RawImageSource::preprocess (const RAWParams &raw) for (i=border; iISGREEN(i,j)) { - if (i%2==0) { - avgg1 += rawData[i][j]; - ng1++; + if (i&1) { + avgg2 += rawData[i][j]; + ng2++; } else { - avgg2 += rawData[i][j]; - ng2++; + avgg1 += rawData[i][j]; + ng1++; } } double corrg1 = ((double)avgg1/ng1 + (double)avgg2/ng2) / 2.0 / ((double)avgg1/ng1); @@ -998,16 +1055,16 @@ void RawImageSource::preprocess (const RAWParams &raw) for (int i=border; iISGREEN(i,j)) { - unsigned short currData; - currData = (unsigned short)(rawData[i][j] * (i%2 ? corrg2 : corrg1)); + float currData; + currData = (float)(rawData[i][j] * ((i&1) ? corrg2 : corrg1)); rawData[i][j] = CLIP(currData); } } if ( raw.greenthresh >0) { if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_GREENEQUIL"); - plistener->setProgress (0.12); + plistener->setProgressStr ("Green equilibrate..."); + plistener->setProgress (0.0); } green_equilibrate(0.01*(raw.greenthresh)); } @@ -1015,20 +1072,20 @@ void RawImageSource::preprocess (const RAWParams &raw) if ( raw.linenoise >0 ) { if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_LINEDENOISE"); - plistener->setProgress (0.14); + plistener->setProgressStr ("Line Denoise..."); + plistener->setProgress (0.0); } cfa_linedn(0.00002*(raw.linenoise)); } - if ( raw.ca_autocorrect || raw.cared || raw.cablue ) { + if ( raw.ca_autocorrect || fabs(raw.cared)>0.001 || fabs(raw.cablue)>0.001 ) { if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_CACORRECTION"); - plistener->setProgress (0.16); + plistener->setProgressStr ("CA Auto Correction..."); + plistener->setProgress (0.0); } - CA_correct_RT(raw.cared, raw.cablue); + CA_correct_RT(raw.cared, raw.cablue); } if ( raw.expos !=1 ) { // exposure @@ -1040,16 +1097,14 @@ void RawImageSource::preprocess (const RAWParams &raw) printf("Preprocessing: %d usec\n", t2.etime(t1)); return; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + void RawImageSource::demosaic(const RAWParams &raw) { if (ri->isBayer()) { MyTime t1,t2; t1.set(); - - if (plistener) { - plistener->setProgressStr ("PROGRESSBAR_DEMOSAICING"); - plistener->setProgress (0.20); - } if ( raw.dmethod == RAWParams::methodstring[RAWParams::hphd] ) hphd_demosaic (); else if (raw.dmethod == RAWParams::methodstring[RAWParams::vng4] ) @@ -1071,9 +1126,15 @@ void RawImageSource::demosaic(const RAWParams &raw) if( settings->verbose ) printf("Demosaicing: %s - %d usec\n",raw.dmethod.c_str(), t2.etime(t1)); } -} + if (plistener) { + plistener->setProgressStr ("Ready."); + plistener->setProgress (1.0); + } +} +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + /* Copy original pixel data and * subtract dark frame (if present) from current image and apply flat field correction (if present) */ @@ -1081,7 +1142,7 @@ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, Raw { if (ri->isBayer()) { if (!rawData) - rawData = allocArray< unsigned short >(W,H); + rawData = allocArray(W,H); if (riDark && W == riDark->get_width() && H == riDark->get_height()) { for (int row = 0; row < H; row++) { for (int col = 0; col < W; col++) { @@ -1095,98 +1156,76 @@ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, Raw } } } - }else{ - if (!rawData) - rawData = allocArray< unsigned short >(3*W,H); - if (riDark && W == riDark->get_width() && H == riDark->get_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->get_black() - riDark->data[row][3*col+0], 0); - rawData[row][3*col+1] = MAX (src->data[row][3*col+1]+ri->get_black() - riDark->data[row][3*col+1], 0); - rawData[row][3*col+2] = MAX (src->data[row][3*col+2]+ri->get_black() - 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]; - } - } - } - } - - if (ri->isBayer() && riFlatFile && W == riFlatFile->get_width() && H == riFlatFile->get_height()) { - //TODO: flat field correction for non-Bayer raw data - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - float (*cfablur); - cfablur = (float (*)) calloc (H*W, sizeof *cfablur); - //#define BS 32 - int BS = raw.ff_BlurRadius; - if (BS&1) BS++; - //function call to cfabloxblur - if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::v_ff]) - cfaboxblur(riFlatFile, cfablur, 2*BS, 0); - else if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::h_ff]) - cfaboxblur(riFlatFile, cfablur, 0, 2*BS); - else if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::vh_ff]) - //slightly more complicated blur if trying to correct both vertical and horizontal anomalies - cfaboxblur(riFlatFile, cfablur, BS, BS);//first do area blur to correct vignette - else //(raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::area_ff]) - cfaboxblur(riFlatFile, cfablur, BS, BS); - float refctrval,reflocval,refcolor[2][2],vignettecorr,colorcastcorr; - //find center ave values by channel - for (int m=0; m<2; m++) - for (int n=0; n<2; n++) { - refcolor[m][n] = MAX(0,cfablur[(2*(H>>2)+m)*W+2*(W>>2)+n] - ri->get_black()); - } - - for (int m=0; m<2; m++) - for (int n=0; n<2; n++) { - for (int row = 0; row+m < H; row+=2) - for (int col = 0; col+n < W; col+=2) { - - vignettecorr = ( refcolor[m][n]/MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black()) ); - rawData[row+m][col+n] = CLIP(round(rawData[row+m][col+n] * vignettecorr)); - //would rather not clip, but this is the restriction of ushort - } - } - - if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::vh_ff]) { - float (*cfablur1); - cfablur1 = (float (*)) calloc (H*W, sizeof *cfablur1); - float (*cfablur2); - cfablur2 = (float (*)) calloc (H*W, sizeof *cfablur2); - //slightly more complicated blur if trying to correct both vertical and horizontal anomalies - cfaboxblur(riFlatFile, cfablur1, 0, 2*BS);//now do horizontal blur - cfaboxblur(riFlatFile, cfablur2, 2*BS, 0);//now do vertical blur + if (riFlatFile && W == riFlatFile->get_width() && H == riFlatFile->get_height()) { - float vlinecorr, hlinecorr; + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + float (*cfablur); + cfablur = (float (*)) calloc (H*W, sizeof *cfablur); +//#define BS 32 + int BS = raw.ff_BlurRadius; + if (BS&1) BS++; + + //function call to cfabloxblur + if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::v_ff]) + cfaboxblur(riFlatFile, cfablur, 2*BS, 0); + else if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::h_ff]) + cfaboxblur(riFlatFile, cfablur, 0, 2*BS); + else if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::vh_ff]) + //slightly more complicated blur if trying to correct both vertical and horizontal anomalies + cfaboxblur(riFlatFile, cfablur, BS, BS);//first do area blur to correct vignette + else //(raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::area_ff]) + cfaboxblur(riFlatFile, cfablur, BS, BS); + + float refctrval,reflocval,refcolor[2][2],vignettecorr,colorcastcorr; + //find center ave values by channel + for (int m=0; m<2; m++) + for (int n=0; n<2; n++) { + refcolor[m][n] = MAX(0,cfablur[(2*(H>>2)+m)*W+2*(W>>2)+n] - ri->get_black()); + } for (int m=0; m<2; m++) for (int n=0; n<2; n++) { for (int row = 0; row+m < H; row+=2) for (int col = 0; col+n < W; col+=2) { - hlinecorr = ( MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black())/MAX(1e-5,cfablur1[(row+m)*W+col+n]-ri->get_black()) ); - vlinecorr = ( MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black())/MAX(1e-5,cfablur2[(row+m)*W+col+n]-ri->get_black()) ); - rawData[row+m][col+n] = CLIP(round(rawData[row+m][col+n] * hlinecorr * vlinecorr)); - //would rather not clip, but this is the restriction of ushort + + vignettecorr = ( refcolor[m][n]/MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black()) ); + rawData[row+m][col+n] = (rawData[row+m][col+n] * vignettecorr); } } - free (cfablur1); - free (cfablur2); + + if (raw.ff_BlurType == RAWParams::ff_BlurTypestring[RAWParams::vh_ff]) { + float (*cfablur1); + cfablur1 = (float (*)) calloc (H*W, sizeof *cfablur1); + float (*cfablur2); + cfablur2 = (float (*)) calloc (H*W, sizeof *cfablur2); + //slightly more complicated blur if trying to correct both vertical and horizontal anomalies + cfaboxblur(riFlatFile, cfablur1, 0, 2*BS);//now do horizontal blur + cfaboxblur(riFlatFile, cfablur2, 2*BS, 0);//now do vertical blur + + float vlinecorr, hlinecorr; + + for (int m=0; m<2; m++) + for (int n=0; n<2; n++) { + for (int row = 0; row+m < H; row+=2) + for (int col = 0; col+n < W; col+=2) { + hlinecorr = ( MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black())/MAX(1e-5,cfablur1[(row+m)*W+col+n]-ri->get_black()) ); + vlinecorr = ( MAX(1e-5,cfablur[(row+m)*W+col+n]-ri->get_black())/MAX(1e-5,cfablur2[(row+m)*W+col+n]-ri->get_black()) ); + rawData[row+m][col+n] = (rawData[row+m][col+n] * hlinecorr * vlinecorr); + } + } + free (cfablur1); + free (cfablur2); + } + + free (cfablur); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//#undef BS + + } - - free (cfablur); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //#undef BS - - } - } void RawImageSource::cfaboxblur(RawImage *riFlatFile, float* cfablur, int boxH, int boxW ) { @@ -1262,7 +1301,7 @@ void RawImageSource::scaleColors(int winx,int winy,int winw,int winh) int c = FC(row, col); val -= cblack[c]; val *= scale_mul[c]; - rawData[row][col] = CLIP(val); + rawData[row][col] = (val); } } }else{ @@ -1272,25 +1311,27 @@ void RawImageSource::scaleColors(int winx,int winy,int winw,int winh) if (val){ val -= cblack[0]; val *= scale_mul[0]; - rawData[row][3*col+0] = CLIP(val); + rawData[row][3*col+0] = (val); } val = rawData[row][3*col+1]; if (val){ val -= cblack[1]; val *= scale_mul[1]; - rawData[row][3*col+1] = CLIP(val); + rawData[row][3*col+1] = (val); } val = rawData[row][3*col+2]; if (val){ val -= cblack[2]; val *= scale_mul[2]; - rawData[row][3*col+2] = CLIP(val); + rawData[row][3*col+2] = (val); } } } } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int RawImageSource::defTransform (int tran) { @@ -1316,38 +1357,40 @@ int RawImageSource::defTransform (int tran) { ret |= TR_VFLIP; return ret; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::correction_YIQ_LQ_ (Image16* im, int row_from, int row_to) { +void RawImageSource::correction_YIQ_LQ_ (Imagefloat* im, int row_from, int row_to) { int W = im->width; - int** rbconv_Y = new int*[3]; - int** rbconv_I = new int*[3]; - int** rbconv_Q = new int*[3]; - int** rbout_I = new int*[3]; - int** rbout_Q = new int*[3]; + float** rbconv_Y = new float*[3]; + float** rbconv_I = new float*[3]; + float** rbconv_Q = new float*[3]; + float** rbout_I = new float*[3]; + float** rbout_Q = new float*[3]; for (int i=0; i<3; i++) { - rbconv_Y[i] = new int[W]; - rbconv_I[i] = new int[W]; - rbconv_Q[i] = new int[W]; - rbout_I[i] = new int[W]; - rbout_Q[i] = new int[W]; + rbconv_Y[i] = new float[W]; + rbconv_I[i] = new float[W]; + rbconv_Q[i] = new float[W]; + rbout_I[i] = new float[W]; + rbout_Q[i] = new float[W]; } - int* row_I = new int[W]; - int* row_Q = new int[W]; + float* row_I = new float[W]; + float* row_Q = new float[W]; - int* pre1_I = new int[3]; - int* pre2_I = new int[3]; - int* post1_I = new int[3]; - int* post2_I = new int[3]; - int middle_I[6]; - int* pre1_Q = new int[3]; - int* pre2_Q = new int[3]; - int* post1_Q = new int[3]; - int* post2_Q = new int[3]; - int middle_Q[6]; - int* tmp; + float* pre1_I = new float[3]; + float* pre2_I = new float[3]; + float* post1_I = new float[3]; + float* post2_I = new float[3]; + float middle_I[6]; + float* pre1_Q = new float[3]; + float* pre2_Q = new float[3]; + float* post1_Q = new float[3]; + float* post2_Q = new float[3]; + float middle_Q[6]; + float* tmp; int ppx=0, px=(row_from-1)%3, cx=row_from%3, nx=0; @@ -1434,11 +1477,11 @@ void RawImageSource::correction_YIQ_LQ_ (Image16* im, int row_from, int row_to) row_Q[W-1] = rbout_Q[cx][W-1]; convert_row_to_RGB (im->r[row_to-1], im->g[row_to-1], im->b[row_to-1], rbconv_Y[cx], row_I, row_Q, W); - freeArray(rbconv_Y, 3); - freeArray(rbconv_I, 3); - freeArray(rbconv_Q, 3); - freeArray(rbout_I, 3); - freeArray(rbout_Q, 3); + freeArray(rbconv_Y, 3); + freeArray(rbconv_I, 3); + freeArray(rbconv_Q, 3); + freeArray(rbout_I, 3); + freeArray(rbout_Q, 3); delete [] row_I; delete [] row_Q; delete [] pre1_I; @@ -1450,9 +1493,11 @@ void RawImageSource::correction_YIQ_LQ_ (Image16* im, int row_from, int row_to) delete [] post1_Q; delete [] post2_Q; } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::correction_YIQ_LQ (Image16* im, int times) { +void RawImageSource::correction_YIQ_LQ (Imagefloat* im, int times) { if (im->height<4) return; @@ -1475,12 +1520,17 @@ void RawImageSource::correction_YIQ_LQ (Image16* im, int times) { #endif } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], double& defgain) { +void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], double& defgain) { + //camMatrix is cam2xyz = xyz_cam + if (cmp.input == "(none)") return; + MyTime t1, t2, t3; @@ -1507,570 +1557,207 @@ void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cm if (inProfile=="(camera)" || inProfile=="" || (inProfile=="(embedded)" && !embedded)) { + // use default profiles supplied by dcraw // in this case we avoid using the slllllooooooowwww lcms // out = iccStore->workingSpace (wProfile); -// hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);//cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT); +// hTransform = cmsCreateTransform (in, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), out, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), settings->colorimetricIntent, cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);//cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT); // cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); // cmsDeleteTransform(hTransform); TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); - double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + float mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (int i=0; i<3; i++) for (int j=0; j<3; j++) for (int k=0; k<3; k++) - mat[i][j] += camMatrix[i][k] * work[k][j]; + mat[i][j] += work[i][k] * camMatrix[k][j]; // rgb_xyz * xyz_cam -#pragma omp parallel for + #pragma omp parallel for for (int i=0; iheight; i++) for (int j=0; jwidth; j++) { - int newr = mat[0][0]*im->r[i][j] + mat[1][0]*im->g[i][j] + mat[2][0]*im->b[i][j]; - int newg = mat[0][1]*im->r[i][j] + mat[1][1]*im->g[i][j] + mat[2][1]*im->b[i][j]; - int newb = mat[0][2]*im->r[i][j] + mat[1][2]*im->g[i][j] + mat[2][2]*im->b[i][j]; + float newr = mat[0][0]*im->r[i][j] + mat[0][1]*im->g[i][j] + mat[0][2]*im->b[i][j]; + float newg = mat[1][0]*im->r[i][j] + mat[1][1]*im->g[i][j] + mat[1][2]*im->b[i][j]; + float newb = mat[2][0]*im->r[i][j] + mat[2][1]*im->g[i][j] + mat[2][2]*im->b[i][j]; + + im->r[i][j] = (newr); + im->g[i][j] = (newg); + im->b[i][j] = (newb); - im->r[i][j] = CLIP(newr); - im->g[i][j] = CLIP(newg); - im->b[i][j] = CLIP(newb); } - } - else { + } else { + // use supplied input profile + // color space transform is expecting data in the range (0,1) + for ( int h = 0; h < im->height; ++h ) + for ( int w = 0; w < im->width; ++w ) { + im->r[h][w] /= 65535.0f ; + im->g[h][w] /= 65535.0f ; + im->b[h][w] /= 65535.0f ; + } out = iccStore->workingSpace (cmp.working); // out = iccStore->workingSpaceGamma (wProfile); + lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), out, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), settings->colorimetricIntent, + settings->LCMSSafeMode ? 0 : cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety lcmsMutex->unlock (); + if (hTransform) { + // there is an input profile if (cmp.gammaOnInput) { - double gd = pow (2.0, defgain); - defgain = 0.0; -#pragma omp parallel for + float gd = pow (2.0, defgain); + defgain = 0.0; // Writeback defgain to be 0.0 + + #pragma omp parallel for for (int i=0; iheight; i++) for (int j=0; jwidth; j++) { - im->r[i][j] = CurveFactory::gamma (CLIP(defgain*im->r[i][j])); - im->g[i][j] = CurveFactory::gamma (CLIP(defgain*im->g[i][j])); - im->b[i][j] = CurveFactory::gamma (CLIP(defgain*im->b[i][j])); + //TODO: extend beyond 65535 + im->r[i][j] = CurveFactory::gamma (CLIP(gd*im->r[i][j])); + im->g[i][j] = CurveFactory::gamma (CLIP(gd*im->g[i][j])); + im->b[i][j] = CurveFactory::gamma (CLIP(gd*im->b[i][j])); } } - cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); - } - else { + + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + } else { + // create the profile from camera lcmsMutex->lock (); - hTransform = cmsCreateTransform (camprofile, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + hTransform = cmsCreateTransform (camprofile, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), out, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), settings->colorimetricIntent, + settings->LCMSSafeMode ? cmsFLAGS_NOOPTIMIZE : cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety lcmsMutex->unlock (); - cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); + + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); } + cmsDeleteTransform(hTransform); + + // restore normalization to the range (0,65535) + #pragma omp parallel for + for ( int h = 0; h < im->height; ++h ) + for ( int w = 0; w < im->width; ++w ) { + im->r[h][w] *= 65535.0 ; + im->g[h][w] *= 65535.0 ; + im->b[h][w] *= 65535.0 ; + } } t3.set (); // printf ("ICM TIME: %d\n", t3.etime(t1)); } - -void RawImageSource::eahd_demosaic () { - - // prepare chache and constants for cielab conversion - lc00 = (0.412453 * coeff[0][0] + 0.357580 * coeff[1][0] + 0.180423 * coeff[2][0]) / 0.950456; - lc01 = (0.412453 * coeff[0][1] + 0.357580 * coeff[1][1] + 0.180423 * coeff[2][1]) / 0.950456; - lc02 = (0.412453 * coeff[0][2] + 0.357580 * coeff[1][2] + 0.180423 * coeff[2][2]) / 0.950456; - - lc10 = 0.212671 * coeff[0][0] + 0.715160 * coeff[1][0] + 0.072169 * coeff[2][0]; - lc11 = 0.212671 * coeff[0][1] + 0.715160 * coeff[1][1] + 0.072169 * coeff[2][1]; - lc12 = 0.212671 * coeff[0][2] + 0.715160 * coeff[1][2] + 0.072169 * coeff[2][2]; - - lc20 = (0.019334 * coeff[0][0] + 0.119193 * coeff[1][0] + 0.950227 * coeff[2][0]) / 1.088754; - lc21 = (0.019334 * coeff[0][1] + 0.119193 * coeff[1][1] + 0.950227 * coeff[2][1]) / 1.088754; - lc22 = (0.019334 * coeff[0][2] + 0.119193 * coeff[1][2] + 0.950227 * coeff[2][2]) / 1.088754; - - int maxindex = 2*65536; - cache = new double[maxindex]; - threshold = (int)(0.008856*MAXVAL); - for (int i=0; isv) { // fixate horizontal pixel - dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]); - dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]); - dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]); - dLmapv[dmi] = DIST(lLv[ix][j], lLh[idx][j+y]); - dCamapv[dmi] = DIST(lav[ix][j], lah[idx][j+y]); - dCbmapv[dmi] = DIST(lbv[ix][j], lbh[idx][j+y]); - } - else if (shISGREEN(i-1,j)) - green[i-1][j] = rawData[i-1][j]; - else { - hc = homh[imx][j]; - vc = homv[imx][j]; - if (hc > vc) - green[i-1][j] = gh[(i-1)%4][j]; - else if (hc < vc) - green[i-1][j] = gv[(i-1)%4][j]; - else - green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; - } - } - - if (!(i%20) && plistener) - plistener->setProgress (0.2 + 0.2*(double)i / (H-2) ); - } - // finish H-2th and H-1th row, homogenity value is still valailable - int hc, vc; - for (int i=H-1; i vc) - green[i-1][j] = gh[(i-1)%4][j]; - else if (hc < vc) - green[i-1][j] = gv[(i-1)%4][j]; - else - green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; - } - - freeArray2(rh, 3); - freeArray2(gh, 4); - freeArray2(bh, 3); - freeArray2(rv, 3); - freeArray2(gv, 4); - freeArray2(bv, 3); - freeArray2(lLh, 3); - freeArray2(lah, 3); - freeArray2(lbh, 3); - freeArray2(homh, 3); - freeArray2(lLv, 3); - freeArray2(lav, 3); - freeArray2(lbv, 3); - freeArray2(homv, 3); - - // Interpolate R and B - for (int i=0; ihpmap[i][j] = 2; - else if (hpv < 0.8*hpmap[i][j]) - this->hpmap[i][j] = 1; - else - this->hpmap[i][j] = 0; - } - } - delete [] temp; - delete [] avg; - delete [] dev; -} - -void RawImageSource::hphd_green () { - - #pragma omp parallel for - for (int i=3; iISGREEN(i,j)) - green[i][j] = rawData[i][j]; - else { - if (this->hpmap[i][j]==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 = 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 = 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 = 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 = 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 = 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 = 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 = rawData[i][j+1] - rawData[i][j-1]; - int dy = rawData[i+1][j] - rawData[i-1][j]; - - int d1 = rawData[i-1][j] - rawData[i-3][j]; - int d2 = rawData[i][j] - rawData[i-2][j]; - int d3 = (rawData[i][j-1] - rawData[i-2][j-1]) >> 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 = 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 = 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 = 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((e1*g1 + e2*g2 + e3*g3 + e4*g4) / (e1 + e2 + e3 + e4)); - } - } - } - } -} - -void RawImageSource::hphd_demosaic () { - - - float** hpmap = new float*[H]; - for (int i=0; isetProgress (0.25); + in = camprofile; + } + else if (inProfile=="(camera)" || inProfile=="") + in = camprofile; + else { + in = iccStore->getProfile (inProfile); + if (in==NULL) + inProfile = "(camera)"; + } + + + if (inProfile=="(camera)" || inProfile=="" || (inProfile=="(embedded)" && !embedded)) { - for (int i=0; ihpmap[i], 0, W*sizeof(char)); +/* out = iccStore->workingSpace (cmp.working); -#ifdef _OPENMP - #pragma omp parallel - { - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - int blk = H/nthreads; + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_NOCACHE); //cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);//cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT); + lcmsMutex->unlock (); - if (tid(hpmap, H); + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + cmsDeleteTransform(hTransform); +*/ + // in this case we avoid using the slllllooooooowwww lcms +TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); + double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + mat[i][j] += work[i][k] * camMatrix[k][j]; // rgb_xyz * xyz_cam + +#pragma omp parallel for + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + + float newr = mat[0][0]*im->r[i][j] + mat[0][1]*im->g[i][j] + mat[0][2]*im->b[i][j]; + float newg = mat[1][0]*im->r[i][j] + mat[1][1]*im->g[i][j] + mat[1][2]*im->b[i][j]; + float newb = mat[2][0]*im->r[i][j] + mat[2][1]*im->g[i][j] + mat[2][2]*im->b[i][j]; + + im->r[i][j] = CLIP((int)newr); + im->g[i][j] = CLIP((int)newg); + im->b[i][j] = CLIP((int)newb); + } + } + else { + out = iccStore->workingSpace (cmp.working); + // out = iccStore->workingSpaceGamma (wProfile); + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, + settings->LCMSSafeMode ? 0 : cmsFLAGS_NOCACHE); // NOCACHE is important for thread safety + lcmsMutex->unlock (); - if (plistener) - plistener->setProgress (0.30); + if (hTransform) { + if (cmp.gammaOnInput) { + float gd = pow (2.0, defgain); + defgain = 0.0; - - hphd_green (); - for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + im->r[i][j] = CurveFactory::gamma ((gd*im->r[i][j])); + im->g[i][j] = CurveFactory::gamma ((gd*im->g[i][j])); + im->b[i][j] = CurveFactory::gamma ((gd*im->b[i][j])); + } + } - } - if (plistener) - plistener->setProgress (0.35); + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + } + else { + lcmsMutex->lock (); + hTransform = cmsCreateTransform (camprofile, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, + settings->LCMSSafeMode ? 0 : cmsFLAGS_NOCACHE); + lcmsMutex->unlock (); + + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + } + + cmsDeleteTransform(hTransform); + } + + //t3.set (); + // printf ("ICM TIME: %d\n", t3.etime(t1)); } -void RawImageSource::HLRecovery_Luminance (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval) { +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +void RawImageSource::HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval) { for (int i=0; imaxval || g>maxval || b>maxval) { - int ro = MIN (r, maxval); - int go = MIN (g, maxval); - int bo = MIN (b, maxval); + float ro = MIN (r, maxval); + float go = MIN (g, maxval); + float bo = MIN (b, maxval); double L = r + g + b; double C = 1.732050808 * (r - g); double H = 2 * b - r - g; @@ -2081,12 +1768,12 @@ void RawImageSource::HLRecovery_Luminance (unsigned short* rin, unsigned short* C *= ratio; H *= ratio; } - int rr = L / 3.0 - H / 6.0 + C / 3.464101615; - int gr = L / 3.0 - H / 6.0 - C / 3.464101615; - int br = L / 3.0 + H / 3.0; - rout[i] = CLIP(rr); - gout[i] = CLIP(gr); - bout[i] = CLIP(br); + float rr = L / 3.0 - H / 6.0 + C / 3.464101615; + float gr = L / 3.0 - H / 6.0 - C / 3.464101615; + float br = L / 3.0 + H / 3.0; + rout[i] = rr; + gout[i] = gr; + bout[i] = br; } else { rout[i] = rin[i]; @@ -2095,85 +1782,90 @@ void RawImageSource::HLRecovery_Luminance (unsigned short* rin, unsigned short* } } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::HLRecovery_CIELab (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval, double cam[3][3], double icam[3][3]) { +void RawImageSource::HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, \ + int width, float maxval, double xyz_cam[3][3], double cam_xyz[3][3]) { - static bool crTableReady = false; - static double fv[0x10000]; - if (!crTableReady) { - for (int ix=0; ix < 0x10000; ix++) { - double rx = ix / 65535.0; + //static bool crTableReady = false; + + // lookup table for Lab conversion + // perhaps should be centralized, universally defined so we don't keep remaking it??? + ImProcFunctions::cachef; + /*for (int ix=0; ix < 0x10000; ix++) { + float rx = ix / 65535.0; fv[ix] = rx > 0.008856 ? exp(1.0/3 * log(rx)) : 7.787*rx + 16/116.0; - } - crTableReady = true; - } + }*/ + //crTableReady = true; + for (int i=0; imaxval || g>maxval || b>maxval) { - int ro = MIN (r, maxval); - int go = MIN (g, maxval); - int bo = MIN (b, maxval); - double yy = cam[0][1]*r + cam[1][1]*g + cam[2][1]*b; - double fy = fv[CLIP((int)yy)]; + float ro = MIN (r, maxval); + float go = MIN (g, maxval); + float bo = MIN (b, maxval); + float yy = xyz_cam[1][0]*r + xyz_cam[1][1]*g + xyz_cam[1][2]*b; + float fy = (yy<65535.0 ? ImProcFunctions::cachef[yy]/327.68 : (exp(log(yy/MAXVAL)/3.0 ))); // compute LCH decompostion of the clipped pixel (only color information, thus C and H will be used) - double x = cam[0][0]*ro + cam[1][0]*go + cam[2][0]*bo; - double y = cam[0][1]*ro + cam[1][1]*go + cam[2][1]*bo; - double z = cam[0][2]*ro + cam[1][2]*go + cam[2][2]*bo; - x = fv[CLIP((int)x)]; - y = fv[CLIP((int)y)]; - z = fv[CLIP((int)z)]; + float x = xyz_cam[0][0]*ro + xyz_cam[0][1]*go + xyz_cam[0][2]*bo; + float y = xyz_cam[1][0]*ro + xyz_cam[1][1]*go + xyz_cam[1][2]*bo; + float z = xyz_cam[2][0]*ro + xyz_cam[2][1]*go + xyz_cam[2][2]*bo; + x = (x<65535.0 ? ImProcFunctions::cachef[x]/327.68 : (exp(log(x/MAXVAL)/3.0 ))); + y = (y<65535.0 ? ImProcFunctions::cachef[y]/327.68 : (exp(log(y/MAXVAL)/3.0 ))); + z = (z<65535.0 ? ImProcFunctions::cachef[z]/327.68 : (exp(log(z/MAXVAL)/3.0 ))); // convert back to rgb double fz = fy - y + z; double fx = fy + x - y; - double zr = (fz<=0.206893) ? ((116.0*fz-16.0)/903.3) : (fz * fz * fz); - double xr = (fx<=0.206893) ? ((116.0*fx-16.0)/903.3) : (fx * fx * fx); - x = xr*65535.0 - 0.5; + + double zr = ImProcFunctions::f2xyz(fz); + double xr = ImProcFunctions::f2xyz(fx); + + x = xr*65535.0 ; y = yy; - z = zr*65535.0 - 0.5; - int rr = icam[0][0]*x + icam[1][0]*y + icam[2][0]*z; - int gr = icam[0][1]*x + icam[1][1]*y + icam[2][1]*z; - int br = icam[0][2]*x + icam[1][2]*y + icam[2][2]*z; - rout[i] = CLIP(rr); - gout[i] = CLIP(gr); - bout[i] = CLIP(br); + z = zr*65535.0 ; + float rr = cam_xyz[0][0]*x + cam_xyz[0][1]*y + cam_xyz[0][2]*z; + float gr = cam_xyz[1][0]*x + cam_xyz[1][1]*y + cam_xyz[1][2]*z; + float br = cam_xyz[2][0]*x + cam_xyz[2][1]*y + cam_xyz[2][2]*z; + rout[i] = (rr); + gout[i] = (gr); + bout[i] = (br); } else { - rout[i] = rin[i]; - gout[i] = gin[i]; - bout[i] = bin[i]; + rout[i] = (rin[i]); + gout[i] = (gin[i]); + bout[i] = (bin[i]); } } } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::hlRecovery (std::string method, unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int width, int skip) { +void RawImageSource::hlRecovery (std::string method, float* red, float* green, float* blue, int i, int sx1, int width, int skip) { if (method=="Luminance") - HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535 / initialGain); + HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535.0); else if (method=="CIELab blending") - HLRecovery_CIELab (red, green, blue, red, green, blue, width, 65535 / initialGain, cam, icam); + HLRecovery_CIELab (red, green, blue, red, green, blue, width, 65535.0, xyz_cam, cam_xyz); else if (method=="Color") HLRecovery_ColorPropagation (red, green, blue, i, sx1, width, skip); } + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { +void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) { histcompr = 3; - memset (histogram, 0, (65536>>histcompr)*sizeof(int)); + histogram(65536>>histcompr); + histogram.clear(); for (int i=border; iget_FujiWidth(); - start = ABS(fw-i) + border; - end = MIN( H+ W-fw-i, fw+i) - border; - } - else { - start = border; - end = W-border; - } - if (ri->isBayer()) + getRowStartEnd (i, start, end); + + if (ri->isBayer()) { for (int j=start; jISGREEN(i,j)) histogram[CLIP((int)(camwb_green*rawData[i][j]))>>histcompr]+=4; @@ -2181,6 +1873,7 @@ int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { histogram[CLIP((int)(camwb_red*rawData[i][j]))>>histcompr]+=4; else if (ri->ISBLUE(i,j)) histogram[CLIP((int)(camwb_blue*rawData[i][j]))>>histcompr]+=4; + } } else { for (int j=start; j<3*end; j++) { histogram[CLIP((int)(camwb_red*rawData[i][j+0]))>>histcompr]++; @@ -2188,115 +1881,171 @@ int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { histogram[CLIP((int)(camwb_blue*rawData[i][j+2]))>>histcompr]++; } } - } - return 1; -} +} + +// Histogram MUST be 256 in size; gamma is applied, blackpoint and gain also +void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) { + + histRedRaw.clear(); histGreenRaw.clear(); histBlueRaw.clear(); - ColorTemp RawImageSource::getAutoWB () { - - double avg_r = 0; - double avg_g = 0; - double avg_b = 0; - int rn = 0, gn = 0, bn = 0; - - if (fuji) { - for (int i=32; iget_FujiWidth(); - int start = ABS(fw-i) + 32; - int end = MIN(H+W-fw-i, fw+i) - 32; - for (int j=start; jisBayer()) { - double d = CLIP(initialGain*(rawData[i][3*j])); - if (d>64000) - continue; - avg_r += d; rn++; - d = CLIP(initialGain*(rawData[i][3*j+1])); - if (d>64000) - continue; - avg_g += d; gn++; - d = CLIP(initialGain*(rawData[i][3*j+2])); - if (d>64000) - continue; - avg_b += d; bn++; - } - else { - int c = FC( i, j); - double d = CLIP(initialGain*(rawData[i][j])); - if (d>64000) - continue; - double dp = d; - if (c==0) { - avg_r += dp; - rn++; - } - else if (c==1) { - avg_g += dp; - gn++; - } - else if (c==2) { - avg_b += dp; - bn++; - } - } - } + float mult = 65535.0 / ri->get_white(); + + #pragma omp parallel for + for (int i=border; iisBayer()) { + for (int j=start; jISGREEN(i,j)) { + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j]-cblack[0]))); + histGreenRaw[idx>>8]++; + } else if (ri->ISRED(i,j)) { + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j]-cblack[1]))); + histRedRaw[idx>>8]++; + } else if (ri->ISBLUE(i,j)) { + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j]-cblack[2]))); + histBlueRaw[idx>>8]++; + } + } + } else { + for (int j=start; j<3*end; j++) { + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j]-cblack[0]))); + histRedRaw[idx>>8]++; + + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j+1]-cblack[1]))); + histGreenRaw[idx>>8]++; + + idx = CLIP((int)CurveFactory::gamma(mult*(ri->data[i][j+2]-cblack[2]))); + histBlueRaw[idx>>8]++; } } - else { - if (!ri->isBayer()) { - for (int i=32; i64000 || dg>64000 || db>64000) continue; - avg_r += dr; rn++; - avg_g += dg; - avg_b += db; - } - gn = rn; bn=rn; - } else { - //determine GRBG coset; (ey,ex) is the offset of the R subarray - int ey, ex; - if (ri->ISGREEN(0,0)) {//first pixel is G - if (ri->ISRED(0,1)) {ey=0; ex=1;} else {ey=1; ex=0;} - } else {//first pixel is R or B - if (ri->ISRED(0,0)) {ey=0; ex=0;} else {ey=1; ex=1;} + } + + // since there are twice as many greens, correct for it + if (ri->isBayer()) for (int i=0;i<256;i++) histGreenRaw[i]>>=1; +} + +void RawImageSource::getRowStartEnd (int x, int &start, int &end) { + if (fuji) { + int fw = ri->get_FujiWidth(); + start = ABS(fw-x) + border; + end = MIN( H+ W-fw-x, fw+x) - border; + } + else { + start = border; + end = W-border; + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ColorTemp RawImageSource::getAutoWB () { + + double avg_r = 0; + double avg_g = 0; + double avg_b = 0; + int rn = 0, gn = 0, bn = 0; + + if (fuji) { + for (int i=32; iget_FujiWidth(); + int start = ABS(fw-i) + 32; + int end = MIN(H+W-fw-i, fw+i) - 32; + for (int j=start; jisBayer()) { + double d = CLIP(initialGain*(ri->data[i][3*j]-cblack[0])*scale_mul[0]); + if (d>64000) + continue; + avg_r += d; rn++; + d = CLIP(initialGain*(ri->data[i][3*j+1]-cblack[1])*scale_mul[1]); + if (d>64000) + continue; + avg_g += d; gn++; + d = CLIP(initialGain*(ri->data[i][3*j+2]-cblack[2])*scale_mul[2]); + if (d>64000) + continue; + avg_b += d; bn++; } - double d[2][2]; - for (int i=32; i64000 || d[0][1]>64000 || d[1][0]>64000 || d[1][1]>64000 ) continue; - avg_r += d[ey][ex]; - avg_g += d[1-ey][ex] + d[ey][1-ex]; - avg_b += d[1-ey][1-ex]; + else { + int c = FC( i, j); + double d = CLIP(initialGain*(ri->data[i][j]-cblack[c])*scale_mul[c]); + if (d>64000) + continue; + double dp = d; + if (c==0) { + avg_r += dp; rn++; } - gn = 2*rn; - bn = rn; + else if (c==1) { + avg_g += dp; + gn++; + } + else if (c==2) { + avg_b += dp; + bn++; + } + } } } - if( settings->verbose ) - printf ("AVG: %g %g %g\n", avg_r/rn, avg_g/gn, avg_b/bn); - - // 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 = avg_r/rn * camwb_red; - double greens = avg_g/gn * camwb_green; - double blues = avg_b/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; - double bm = coeff[2][0]*reds + coeff[2][1]*greens + coeff[2][2]*blues; - - return ColorTemp (rm, gm, bm); + } + else { + if (!ri->isBayer()) { + for (int i=32; idata[i][3*j] -cblack[0])*scale_mul[0]); + double dg = CLIP(initialGain*(ri->data[i][3*j+1]-cblack[1])*scale_mul[1]); + double db = CLIP(initialGain*(ri->data[i][3*j+2]-cblack[2])*scale_mul[2]); + if (dr>64000 || dg>64000 || db>64000) continue; + avg_r += dr; rn++; + avg_g += dg; + avg_b += db; + } + gn = rn; bn=rn; + } else { + //determine GRBG coset; (ey,ex) is the offset of the R subarray + int ey, ex; + if (ri->ISGREEN(0,0)) {//first pixel is G + if (ri->ISRED(0,1)) {ey=0; ex=1;} else {ey=1; ex=0;} + } else {//first pixel is R or B + if (ri->ISRED(0,0)) {ey=0; ex=0;} else {ey=1; ex=1;} + } + double d[2][2]; + for (int i=32; idata[i][j] -cblack[FC(i,j)])*scale_mul[FC(i,j)]); + d[0][1] = CLIP(initialGain*(ri->data[i][j+1] -cblack[FC(i,j+1)])*scale_mul[FC(i,j+1)]); + d[1][0] = CLIP(initialGain*(ri->data[i+1][j] -cblack[FC(i+1,j)])*scale_mul[FC(i+1,j)]); + d[1][1] = CLIP(initialGain*(ri->data[i+1][j+1]-cblack[FC(i+1,j+1)])*scale_mul[FC(i+1,j+1)]); + if ( d[0][0]>64000 || d[0][1]>64000 || d[1][0]>64000 || d[1][1]>64000 ) continue; + avg_r += d[ey][ex]; + avg_g += d[1-ey][ex] + d[ey][1-ex]; + avg_b += d[1-ey][1-ex]; + rn++; + } + gn = 2*rn; + bn = rn; + } } + //printf ("AVG: %g %g %g\n", avg_r/rn, avg_g/gn, avg_b/bn); + + // 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 = avg_r/rn * camwb_red; + double greens = avg_g/gn * camwb_green; + double blues = avg_b/bn * camwb_blue; + + double rm = rgb_cam[0][0]*reds + rgb_cam[0][1]*greens + rgb_cam[0][2]*blues; + double gm = rgb_cam[1][0]*reds + rgb_cam[1][1]*greens + rgb_cam[1][2]*blues; + double bm = rgb_cam[2][0]*reds + rgb_cam[2][1]*greens + rgb_cam[2][2]*blues; + + return ColorTemp (rm, gm, bm); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::transformPosition (int x, int y, int tran, int& ttx, int& tty) { @@ -2355,6 +2104,7 @@ void RawImageSource::transformPosition (int x, int y, int tran, int& ttx, int& t } } +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) { @@ -2369,17 +2119,17 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector52500 || - initialGain*(rawData[yg][3*xg+1])>52500 || - initialGain*(rawData[yb][3*xb+2])>52500) continue; + if (initialGain*(ri->data[yr][3*xr] -cblack[0])*scale_mul[0]>52500 || + initialGain*(ri->data[yg][3*xg+1]-cblack[1])*scale_mul[1]>52500 || + initialGain*(ri->data[yb][3*xb+2]-cblack[2])*scale_mul[2]>52500) continue; xmin = MIN(xr,MIN(xg,xb)); xmax = MAX(xr,MAX(xg,xb)); ymin = MIN(yr,MIN(yg,yb)); ymax = MAX(yr,MAX(yg,yb)); if (xmin>=0 && ymin>=0 && xmaxdata[yr][3*xr] -cblack[0])*scale_mul[0]; + greens += (ri->data[yg][3*xg+1]-cblack[1])*scale_mul[1]; + blues += (ri->data[yb][3*xb+2]-cblack[2])*scale_mul[2]; rn++; } } @@ -2396,15 +2146,15 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector=0 && yv>=0 && xvdata[yv][xv]-cblack[c])*scale_mul[c]; rnbrs++; continue; }else if (c==2 && xv>=0 && yv>=0 && xvdata[yv][xv]-cblack[c])*scale_mul[c]; bnbrs++; continue; } else { // GREEN - gloc += (rawData[yv][xv]); + gloc += (ri->data[yv][xv]-cblack[c])*scale_mul[c]; gnbrs++; continue; } @@ -2427,981 +2177,51 @@ ColorTemp RawImageSource::getSpotWB (std::vector red, std::vectorprefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) -typedef unsigned short ushort; -void RawImageSource::vng4_demosaic () { - - static const signed char *cp, terms[] = { - -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, - -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, - -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, - -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, - -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, - -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, - -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, - -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, - -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, - -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, - -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, - -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, - -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, - +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, - +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, - +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, - +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, - +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, - +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, - +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, - +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, - +1,+0,+2,+1,0,0x10 - }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; - - - ushort (*brow[5])[4], *pix; - int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; - int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; - int g, diff, thold, num, c, width=W, height=H, colors=4; - ushort (*image)[4]; - int lcode[16][16][32], shift, i, j; - - image = (ushort (*)[4]) calloc (H*W, sizeof *image); - for (int ii=0; ii> 8; - } - -// lin_interpolate(); - - - ip = (int *) calloc ((prow+1)*(pcol+1), 1280); - for (row=0; row <= prow; row++) /* Precalculate for VNG */ - for (col=0; col <= pcol; col++) { - code[row][col] = ip; - for (cp=terms, t=0; t < 64; t++) { - y1 = *cp++; x1 = *cp++; - y2 = *cp++; x2 = *cp++; - weight = *cp++; - grads = *cp++; - color = fc(row+y1,col+x1); - if (fc(row+y2,col+x2) != color) continue; - diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1; - if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; - *ip++ = (y1*width + x1)*4 + color; - *ip++ = (y2*width + x2)*4 + color; - *ip++ = weight; - for (g=0; g < 8; g++) - if (grads & 1< gval[g]) gmin = gval[g]; - if (gmax < gval[g]) gmax = gval[g]; - } - if (gmax == 0) { - memcpy (brow[2][col], pix, sizeof *image); - continue; - } - thold = gmin + (gmax >> 1); - memset (sum, 0, sizeof sum); - for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ - if (gval[g] <= thold) { - FORCC - if (c == color && ip[1]) - sum[c] += (pix[c] + pix[ip[1]]) >> 1; - else - sum[c] += pix[ip[0] + c]; - num++; - } - } - FORCC { /* Save to buffer */ - t = pix[color]; - if (c != color) - t += (sum[c] - sum[color]) / num; - brow[2][col][c] = CLIP(t); - } - } - if (row > 3) /* Write buffer to image */ - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - for (g=0; g < 4; g++) - brow[(g-1) & 3] = brow[g]; - if (!(row%20) && plistener) - plistener->setProgress (0.2 + 0.2*(double)row / (H-2) ); - } - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); - free (brow[4]); - free (code[0][0]); - - for (int i=0; i> 1; - } - // Interpolate R and B - for (int i=0; iget_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) -#define LIM(x,min,max) MAX(min,MIN(x,max)) -#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) - -void RawImageSource::border_interpolate(int border, ushort (*image)[4], int start, int end) -{ - unsigned row, col, y, x, f, c, sum[8]; - int width=W, height=H; - int colors = 3; - - if (end == 0 )end = H; - for (row=start; row < end; row++) - for (col=0; col < width; col++) { - if (col==border && row >= border && row < height-border) - col = width-border; - memset (sum, 0, sizeof sum); - for (y=row-1; y != row+2; y++) - for (x=col-1; x != col+2; x++) - if (y < height && x < width) { - f = fc(y,x); - sum[f] += image[y*width+x][f]; - sum[f+4]++; - } - f = fc(row,col); - FORCC if (c != f && sum[c+4]) - image[row*width+col][c] = sum[c] / sum[c+4]; - } -} - -/* - Adaptive Homogeneity-Directed interpolation is based on - the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. - */ -#define TS 256 /* Tile Size */ -#define FORC(cnt) for (c=0; c < cnt; c++) -#define FORC3 FORC(3) -#define SQR(x) ((x)*(x)) - -void RawImageSource::ahd_demosaic(int winx, int winy, int winw, int winh) -{ - int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; - ushort (*pix)[4], (*rix)[3]; - static const int dir[4] = { -1, 1, -TS, TS }; - unsigned ldiff[2][4], abdiff[2][4], leps, abeps; - float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; - ushort (*rgb)[TS][TS][3]; - short (*lab)[TS][TS][3], (*lix)[3]; - char (*homo)[TS][TS], *buffer; - - int width=W, height=H; - ushort (*image)[4]; - int colors = 3; - - const double xyz_rgb[3][3] = { /* XYZ from RGB */ - { 0.412453, 0.357580, 0.180423 }, - { 0.212671, 0.715160, 0.072169 }, - { 0.019334, 0.119193, 0.950227 } - }; - - const float d65_white[3] = { 0.950456, 1, 1.088754 }; - - image = (ushort (*)[4]) calloc (H*W, sizeof *image); - for (int ii=0; ii 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; - } - - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * coeff[k][j] / d65_white[i]; - - border_interpolate(5, image); - buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ - //merror (buffer, "ahd_interpolate()"); - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); - homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); - - // helper variables for progress indication - int n_tiles = ((height-7 + (TS-7))/(TS-6)) * ((width-7 + (TS-7))/(TS-6)); - int tile = 0; - - for (top=2; top < height-5; top += TS-6) - for (left=2; left < width-5; left += TS-6) { - - /* Interpolate green horizontally and vertically: */ - for (row = top; row < top+TS && row < height-2; row++) { - col = left + (FC(row,left) & 1); - for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { - pix = image + row*width+col; - val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - - pix[-2][c] - pix[2][c]) >> 2; - rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); - val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - - pix[-2*width][c] - pix[2*width][c]) >> 2; - rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); - } - } - - /* Interpolate red and blue, and convert to CIELab: */ - for (d=0; d < 2; d++) - for (row=top+1; row < top+TS-1 && row < height-3; row++) - for (col=left+1; col < left+TS-1 && col < width-3; col++) { - pix = image + row*width+col; - rix = &rgb[d][row-top][col-left]; - lix = &lab[d][row-top][col-left]; - if ((c = 2 - FC(row,col)) == 1) { - c = FC(row+1,col); - val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - - rix[-1][1] - rix[1][1] ) >> 1); - rix[0][2-c] = CLIP(val); - val = pix[0][1] + (( pix[-width][c] + pix[width][c] - - rix[-TS][1] - rix[TS][1] ) >> 1); - } else - val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] - + pix[+width-1][c] + pix[+width+1][c] - - rix[-TS-1][1] - rix[-TS+1][1] - - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); - rix[0][c] = CLIP(val); - c = FC(row,col); - rix[0][c] = pix[0][c]; - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rix[0][c]; - xyz[1] += xyz_cam[1][c] * rix[0][c]; - xyz[2] += xyz_cam[2][c] * rix[0][c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lix[0][0] = 64 * (116 * xyz[1] - 16); - lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); - lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); - } - - /* Build homogeneity maps from the CIELab images: */ - memset (homo, 0, 2*TS*TS); - for (row=top+2; row < top+TS-2 && row < height-4; row++) { - tr = row-top; - for (col=left+2; col < left+TS-2 && col < width-4; col++) { - tc = col-left; - for (d=0; d < 2; d++) { - lix = &lab[d][tr][tc]; - for (i=0; i < 4; i++) { - ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); - abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) - + SQR(lix[0][2]-lix[dir[i]][2]); - } - } - leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), - MAX(ldiff[1][2],ldiff[1][3])); - abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), - MAX(abdiff[1][2],abdiff[1][3])); - for (d=0; d < 2; d++) - for (i=0; i < 4; i++) - if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) - homo[d][tr][tc]++; - } - } - - /* Combine the most homogenous pixels for the final result: */ - for (row=top+3; row < top+TS-3 && row < height-5; row++) { - tr = row-top; - for (col=left+3; col < left+TS-3 && col < width-5; col++) { - tc = col-left; - for (d=0; d < 2; d++) - for (hm[d]=0, i=tr-1; i <= tr+1; i++) - for (j=tc-1; j <= tc+1; j++) - hm[d] += homo[d][i][j]; - if (hm[0] != hm[1]) - FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; - else - FORC3 image[row*width+col][c] = - (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; - } - } - - tile++; - if(plistener) { - plistener->setProgress(0.20 + 0.20*(double)tile / n_tiles); - } - } - - free (buffer); - for (int i=0; i= H-border) rowMax = TILEBORDER+H-border-y0; - if( x0+TILESIZE+TILEBORDER >= W-border) colMax = TILEBORDER+W-border-x0; -} - -void RawImageSource::fill_raw( ushort (*cache )[4], int x0, int y0, ushort** rawData) -{ - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,0); - - for (int row=rowMin,y=y0-TILEBORDER+rowMin; row= border && col < W - border && row >= border && row < H - border){ - col = W - border; - if(col >= x0+TILESIZE+TILEBORDER ) - break; - } - memset(sum, 0, sizeof sum); - for (y = row - 1; y != row + 2; y++) - for (x = col - 1; x != col + 2; x++) - if (y < H && y< y0+TILESIZE+TILEBORDER && x < W && x ( pix[-4] + pix[+4] + pix[-u] + pix[+u])/4 ) - image[indx][3] = ((MIN( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) < (MIN( pix[-u], pix[+u]) + pix[-u] + pix[+u])); - else - image[indx][3] = ((MAX( pix[-4], pix[+4]) + pix[-4] + pix[+4] ) > (MAX( pix[-u], pix[+u]) + pix[-u] + pix[+u])); - } - } -} - - -// interpolated green pixels are corrected using the map -void RawImageSource::dcb_correction(ushort (*image)[4], int x0, int y0) -{ - const int u=CACHESIZE, v=2*CACHESIZE; - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); - for (int row=rowMin; row < rowMax; row++) { - for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { - int current = 4*image[indx][3] + - 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + - image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; - image[indx][1] = ((16-current)*(image[indx-1][1] + image[indx+1][1])/2 + current*(image[indx-u][1] + image[indx+u][1])/2)/16; - } - } -} - -// R and B smoothing using green contrast, all pixels except 2 pixel wide border -void RawImageSource::dcb_pp(ushort (*image)[4], int x0, int y0) -{ - const int u=CACHESIZE; - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,2); +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - for (int row=rowMin; row < rowMax; row++) - for (int col=colMin, indx=row*CACHESIZE+col; col < colMax; col++, indx++) { - //int r1 = ( image[indx-1][0] + image[indx+1][0] + image[indx-u][0] + image[indx+u][0] + image[indx-u-1][0] + image[indx+u+1][0] + image[indx-u+1][0] + image[indx+u-1][0])/8; - //int g1 = ( image[indx-1][1] + image[indx+1][1] + image[indx-u][1] + image[indx+u][1] + image[indx-u-1][1] + image[indx+u+1][1] + image[indx-u+1][1] + image[indx+u-1][1])/8; - //int b1 = ( image[indx-1][2] + image[indx+1][2] + image[indx-u][2] + image[indx+u][2] + image[indx-u-1][2] + image[indx+u+1][2] + image[indx-u+1][2] + image[indx+u-1][2])/8; - ushort (*pix)[4] = image+(indx-u-1); - int r1 = (*pix)[0]; - int g1 = (*pix)[1]; - int b1 = (*pix)[2]; - pix++; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix++; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix+=CACHESIZE-2; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix+=2; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix+=CACHESIZE-2; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix++; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - pix++; - r1 += (*pix)[0]; - g1 += (*pix)[1]; - b1 += (*pix)[2]; - r1 /=8; - g1 /=8; - b1 /=8; - r1 = r1 + ( image[indx][1] - g1 ); - b1 = b1 + ( image[indx][1] - g1 ); - image[indx][0] = CLIP(r1); - image[indx][2] = CLIP(b1); - } -} - -// interpolated green pixels are corrected using the map -// with correction -void RawImageSource::dcb_correction2(ushort (*image)[4], int x0, int y0) -{ - const int u=CACHESIZE, v=2*CACHESIZE; - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4); - - for (int row=rowMin; row < rowMax; row++) { - for (int col = colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2, indx+=2) { - int current = 4*image[indx][3] + - 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + - image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; - current = ((16-current)*((image[indx-1][1] + image[indx+1][1])/2 + image[indx][c] - (image[indx+2][c] + image[indx-2][c])/2) + current*((image[indx-u][1] + image[indx+u][1])/2 + image[indx][c] - (image[indx+v][c] + image[indx-v][c])/2))/16; - image[indx][1] = CLIP(current); - } - } -} - -// image refinement -void RawImageSource::dcb_refinement(ushort (*image)[4], int x0, int y0) -{ - const int u=CACHESIZE, v=2*CACHESIZE, w=3*CACHESIZE; - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,4); - - float f[5],g1,g2; - - for (int row=rowMin; row < rowMax; row++) - for (int col=colMin+(FC(y0-TILEBORDER+row,x0-TILEBORDER+colMin)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col); col < colMax; col+=2,indx+=2){ - int current = 4*image[indx][3] + - 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) - +image[indx+v][3] + image[indx-v][3] + image[indx-2][3] + image[indx+2][3]; - - f[0] = (float)(image[indx-u][1] + image[indx+u][1])/(2 + 2*image[indx][c]); - f[1] = 2*(float)image[indx-u][1]/(2 + image[indx-v][c] + image[indx][c]); - f[2] = (float)(image[indx-u][1] + image[indx-w][1])/(2 + 2*image[indx-v][c]); - f[3] = 2*(float)image[indx+u][1]/(2 + image[indx+v][c] + image[indx][c]); - f[4] = (float)(image[indx+u][1] + image[indx+w][1])/(2 + 2*image[indx+v][c]); - - g1 = (f[0] + f[1] + f[2] + f[3] + f[4] - MAX(f[1], MAX(f[2], MAX(f[3], f[4]))) - MIN(f[1], MIN(f[2], MIN(f[3], f[4]))))/3.0; - - f[0] = (float)(image[indx-1][1] + image[indx+1][1])/(2 + 2*image[indx][c]); - f[1] = 2*(float)image[indx-1][1]/(2 + image[indx-2][c] + image[indx][c]); - f[2] = (float)(image[indx-1][1] + image[indx-3][1])/(2 + 2*image[indx-2][c]); - f[3] = 2*(float)image[indx+1][1]/(2 + image[indx+2][c] + image[indx][c]); - f[4] = (float)(image[indx+1][1] + image[indx+3][1])/(2 + 2*image[indx+2][c]); - - g2 = (f[0] + f[1] + f[2] + f[3] + f[4] - MAX(f[1], MAX(f[2], MAX(f[3], f[4]))) - MIN(f[1], MIN(f[2], MIN(f[3], f[4]))))/3.0; - - image[indx][1] = CLIP((2+image[indx][c])*(current*g1 + (16-current)*g2)/16.0); - -// get rid of the overshooted pixels - int min = MIN(image[indx+1+u][1], MIN(image[indx+1-u][1], MIN(image[indx-1+u][1], MIN(image[indx-1-u][1], MIN(image[indx-1][1], MIN(image[indx+1][1], MIN(image[indx-u][1], image[indx+u][1]))))))); - int max = MAX(image[indx+1+u][1], MAX(image[indx+1-u][1], MAX(image[indx-1+u][1], MAX(image[indx-1-u][1], MAX(image[indx-1][1], MAX(image[indx+1][1], MAX(image[indx-u][1], image[indx+u][1]))))))); - - image[indx][1] = LIM(image[indx][1], min, max); - - - } -} - -// missing colors are interpolated using high quality algorithm by Luis Sanz Rodr‚àö‚â†guez -void RawImageSource::dcb_color_full(ushort (*image)[4], int x0, int y0, float (*chroma)[2]) -{ - const int u=CACHESIZE, v=2*CACHESIZE, w=3*CACHESIZE; - int rowMin,colMin,rowMax,colMax; - dcb_initTileLimits(colMin,rowMin,colMax,rowMax,x0,y0,3); - - int i,j; - float f[4],g[4]; - - for (int row=1; row < CACHESIZE-1; row++) - for (int col=1+(FC(y0-TILEBORDER+row,x0-TILEBORDER+1)&1),indx=row*CACHESIZE+col,c=FC(y0-TILEBORDER+row,x0-TILEBORDER+col),d=c/2; col < CACHESIZE-1; col+=2,indx+=2) - chroma[indx][d]=image[indx][c]-image[indx][1]; - - for (int row=rowMin; row0;i--) { - dcb_hid2(tile,x0,y0); - dcb_hid2(tile,x0,y0); - dcb_hid2(tile,x0,y0); - dcb_map(tile,x0,y0); - dcb_correction(tile,x0,y0); - } - dcb_color(tile,x0,y0); - dcb_pp(tile,x0,y0); - dcb_map(tile,x0,y0); - dcb_correction2(tile,x0,y0); - dcb_map(tile,x0,y0); - dcb_correction(tile,x0,y0); - dcb_color(tile,x0,y0); - dcb_map(tile,x0,y0); - dcb_correction(tile,x0,y0); - dcb_map(tile,x0,y0); - dcb_correction(tile,x0,y0); - dcb_map(tile,x0,y0); - restore_from_buffer(tile, buffer); - dcb_color(tile,x0,y0); - if (dcb_enhance) { - dcb_refinement(tile,x0,y0); - dcb_color_full(tile,x0,y0,chrm); - } - - for(int y=0;y currentProgress){ - currentProgress+=0.1; // Show progress each 10% - plistener->setProgress (0.2 + 0.2*currentProgress); - } - } -#pragma omp atomic - tilesDone++; - } - -#ifdef _OPENMP - for(int i=0; i #include + #define HR_SCALE 2 namespace rtengine { template void freeArray (T** a, int H) { - for (int i=0; i T** allocArray (int W, int H) { T** t = new T*[H]; - for (int i=0; i void freeArray2 (T** a, int H) { - for (int i=0; iFC(row,col); } + inline void getRowStartEnd (int x, int &start, int &end); + public: RawImageSource (); ~RawImageSource (); - + int load (Glib::ustring fname, bool batch = false); void preprocess (const RAWParams &raw); void demosaic (const RAWParams &raw); void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile ); - void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW ); - void scaleColors (int winx,int winy,int winw,int winh ); - void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw); + void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW ); + void scaleColors (int winx,int winy,int winw,int winh ); + void getImage (ColorTemp ctemp, int tran, Imagefloat* 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); double getDefGain () { return defGain; } - double getGamma () { return 2.2; } - + // double getGamma () { return 2.2; } + double getGamma () { return 2.4; }//normalize gamma to sRGB + void getFullSize (int& w, int& h, int tr = TR_NONE); void getSize (int tran, PreviewProps pp, int& w, int& h); ImageData* getImageData () { return idata; } void setProgressListener (ProgressListener* pl) { plistener = pl; } - int getAEHistogram (unsigned int* histogram, int& histcompr); + void getAutoExpHistogram (LUTu & histogram, int& histcompr); + void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); - static void colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], double& defgain); + static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], double& defgain); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], double& defgain); static void inverse33 (double (*coeff)[3], double (*icoeff)[3]); - static void HLRecovery_Luminance (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval); - static void HLRecovery_CIELab (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval, double cam[3][3], double icam[3][3]); + static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); + static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]); protected: typedef unsigned short ushort; - void correction_YIQ_LQ (Image16* i, int times); - inline void convert_row_to_YIQ (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W); - inline void convert_row_to_RGB (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W); + void correction_YIQ_LQ (Imagefloat* i, int times); + inline void convert_row_to_YIQ (float* r, float* g, float* b, float* Y, float* I, float* Q, int W); + inline void convert_row_to_RGB (float* r, float* g, float* b, float* Y, float* I, float* Q, int W); - inline void convert_to_cielab_row (unsigned short* ar, unsigned short* ag, unsigned short* ab, short* oL, short* oa, short* ob); - inline void interpolate_row_g (unsigned short* agh, unsigned short* agv, int i); - 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); + inline void convert_to_cielab_row (float* ar, float* ag, float* ab, float* oL, float* oa, float* ob); + inline void interpolate_row_g (float* agh, float* agv, int i); + inline void interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i); + inline void interpolate_row_rb_mul_pp (float* ar, float* ab, float* pg, float* cg, float* 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 void CA_correct_RT (double cared, double cablue); - void exp_bef (float expos, float preser);//exposi - + void ddct8x8s(int isgn, float **a); + void exp_bef (float expos, float preser); // exposure before interpolation + int cfaCleanFromMap( PixelsMap &bitmapBads ); int findHotDeadPixel( PixelsMap &bpMap, float thresh); - void ddct8x8s(int isgn, float **a); void cfa_linedn (float linenoiselevel);//Emil's line denoise - void green_equilibrate (float greenthresh);//Emil's green equilibration + void green_equilibrate (float greenthresh);//Emil's green equilibration - void nodemosaic(); + void nodemosaic(); void eahd_demosaic(); void hphd_demosaic(); void vng4_demosaic(); + void ppg_demosaic(); void amaze_demosaic_RT(int winx, int winy, int winw, int winh);//Emil's code for AMaZE void fast_demo(int winx, int winy, int winw, int winh);//Emil's code for fast demosaicing void dcb_demosaic(int iterations, int dcb_enhance); void ahd_demosaic(int winx, int winy, int winw, int winh); - void border_interpolate(int border, ushort (*image)[4], int start = 0, int end = 0); + void border_interpolate(int border, float (*image)[4], int start = 0, int end = 0); void dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border); - void fill_raw( ushort (*cache )[4], int x0, int y0, ushort** rawData); - void fill_border( ushort (*cache )[4], int border, int x0, int y0); - void copy_to_buffer(ushort (*image2)[3], ushort (*image)[4]); - void dcb_hid(ushort (*image)[4], ushort (*bufferH)[3], ushort (*bufferV)[3], int x0, int y0); - void dcb_color(ushort (*image)[4], int x0, int y0); - void dcb_hid2(ushort (*image)[4], int x0, int y0); - void dcb_map(ushort (*image)[4], int x0, int y0); - void dcb_correction(ushort (*image)[4], int x0, int y0); - void dcb_pp(ushort (*image)[4], int x0, int y0); - void dcb_correction2(ushort (*image)[4], int x0, int y0); - void restore_from_buffer(ushort (*image)[4], ushort (*image2)[3]); - void dcb_refinement(ushort (*image)[4], int x0, int y0); - void dcb_color_full(ushort (*image)[4], int x0, int y0, float (*chroma)[2]); + void fill_raw( float (*cache )[4], int x0, int y0, float** rawData); + void fill_border( float (*cache )[4], int border, int x0, int y0); + void copy_to_buffer(float (*image2)[3], float (*image)[4]); + void dcb_hid(float (*image)[4], float (*bufferH)[3], float (*bufferV)[3], int x0, int y0); + void dcb_color(float (*image)[4], int x0, int y0); + void dcb_hid2(float (*image)[4], int x0, int y0); + void dcb_map(float (*image)[4], int x0, int y0); + void dcb_correction(float (*image)[4], int x0, int y0); + void dcb_pp(float (*image)[4], int x0, int y0); + void dcb_correction2(float (*image)[4], int x0, int y0); + void restore_from_buffer(float (*image)[4], float (*image2)[3]); + void dcb_refinement(float (*image)[4], int x0, int y0); + void dcb_color_full(float (*image)[4], int x0, int y0, float (*chroma)[2]); + + void transLine (float* red, float* green, float* blue, int i, Imagefloat* image, int tran, int imw, int imh, int fw); + void hflip (Imagefloat* im); + void vflip (Imagefloat* im); - void transLine (unsigned short* red, unsigned short* green, unsigned short* blue, int i, Image16* image, int tran, int imw, int imh, int fw); - void hflip (Image16* im); - void vflip (Image16* im); - }; }; #endif diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h index 771e649d7..c3a210d56 100644 --- a/rtengine/rawimagesource_i.h +++ b/rtengine/rawimagesource_i.h @@ -32,26 +32,26 @@ namespace rtengine { -inline void RawImageSource::convert_row_to_YIQ (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W) { +inline void RawImageSource::convert_row_to_YIQ (float* r, float* g, float* b, float* Y, float* I, float* Q, int W) { for (int j=0; jthreshold) - oL[j] = 300.0*cache[(int)y]; + oL[j] = cache[(int)y]; else - oL[j] = 300.0 * 903.3 * y / MAXVAL; + oL[j] = 903.3 * y / MAXVAL; - oa[j] = 32.0 * 500.0 * ((x>threshold ? cache[(int)x] : 7.787*x/MAXVAL+16.0/116.0) - (y>threshold ? cache[(int)y] : 7.787*y/MAXVAL+16.0/116.0)); - ob[j] = 32.0 * 200.0 * ((y>threshold ? cache[(int)y] : 7.787*y/MAXVAL+16.0/116.0) - (z>threshold ? cache[(int)z] : 7.787*z/MAXVAL+16.0/116.0)); + oa[j] = 500.0 * ((x>threshold ? cache[(int)x] : 7.787*x/MAXVAL+16.0/116.0) - (y>threshold ? cache[(int)y] : 7.787*y/MAXVAL+16.0/116.0)); + ob[j] = 200.0 * ((y>threshold ? cache[(int)y] : 7.787*y/MAXVAL+16.0/116.0) - (z>threshold ? cache[(int)z] : 7.787*z/MAXVAL+16.0/116.0)); } } -inline void RawImageSource::interpolate_row_g (unsigned short* agh, unsigned short* agv, int i) { +inline void RawImageSource::interpolate_row_g (float* agh, float* agv, int i) { for (int j=0; jISGREEN(i,j)) { @@ -124,7 +124,7 @@ inline void RawImageSource::interpolate_row_g (unsigned short* agh, unsigned sho } } -inline void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i) { +inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i) { if (ri->ISRED(i,0) || ri->ISRED(i,1)) { // RGRGR or GRGRGR line for (int j=0; jISRED(i,0) || ri->ISRED(i,1)) { // RGRGR or GRGRGR line diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 73d284dae..f1322fd9d 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -19,8 +19,6 @@ #include #include -// Mapping of which event causes what change in the image -// given to Improccordinator::updatePreviewImage(todo) int refreshmap[rtengine::NUMOFEVENTS] = { ALL, // EvPhotoLoaded, ALL, // EvProfileLoaded, @@ -152,6 +150,9 @@ FLATFIELD, // EvFlatFieldAutoSelect, FLATFIELD, // EvFlatFieldBlurRadius, FLATFIELD, // EvFlatFieldBlurType, TRANSFORM, // EvAutoDIST, +DIRPYRDENOISE, // EvDPDNLumCurve, +DIRPYRDENOISE, // EvDPDNChromCurve, +ALL, // EvGAMMA }; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index d18d34fdd..233c9ec7e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -30,6 +30,7 @@ #include #include #include +#include "LUT.h" /** * @file * This file contains the main functionality of the raw therapee engine. @@ -179,7 +180,8 @@ namespace rtengine { public: /** With this member function the staged processor notifies the listener that the detailed crop image has been updated. * @param img is a pointer to the detailed crop image */ - virtual void setDetailedCrop (IImage8* img, procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip) {} + virtual void setDetailedCrop (IImage8* img, IImage8* imgtrue, procparams::ColorManagementParams cmp, \ + procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip) {} virtual bool getWindow (int& cx, int& cy, int& cw, int& ch, int& skip) { return false; } }; @@ -198,11 +200,13 @@ namespace rtengine { class HistogramListener { public: /** This member function is called when the histogram of the final image has changed. - * @param redh is the array of size 256 containing the histogram of the red channel - * @param greenh is the array of size 256 containing the histogram of the green channel - * @param blueh is the array of size 256 containing the histogram of the blue channel - * @param lumah is the array of size 256 containing the histogram of the luminance channel */ - virtual void histogramChanged (unsigned int* redh, unsigned int* greenh, unsigned int* blueh, unsigned int* lumah, unsigned int* bcrgbhist, unsigned int* bcLhist) {} + * @param histRed is the array of size 256 containing the histogram of the red channel + * @param histGreen is the array of size 256 containing the histogram of the green channel + * @param histBlue is the array of size 256 containing the histogram of the blue channel + * @param histLuma is the array of size 256 containing the histogram of the luminance channel + * other for curves backgrounds, histRAW is RAW without colors */ + virtual void histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, + LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) {} }; /** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */ @@ -315,6 +319,8 @@ namespace rtengine { /** Returns the available working profile names * @return a vector of the available working profile names */ std::vector getWorkingProfiles (); +/** return gamma */ + std::vector getGamma (); /** This class holds all the necessary informations to accomplish the full processing of the image */ class ProcessingJob { diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 4424ad976..75d0b6502 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -92,18 +92,19 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, } // bilinear interpolation + if (tpp->thumbImg) delete tpp->thumbImg; tpp->thumbImg = img->resize (w, h, TI_Bilinear); // histogram computation tpp->aeHistCompression = 3; - tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression]; + tpp->aeHistogram(65536>>tpp->aeHistCompression); double avg_r = 0; double avg_g = 0; double avg_b = 0; int n = 0; - memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); + tpp->aeHistogram.clear(); int ix = 0; for (int i=0; iheight*img->width; i++) { int rtmp=CurveFactory::igamma_srgb (img->data[ix++]); @@ -204,6 +205,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL tpp->scale = (double)img->width / w; } + if (tpp->thumbImg) delete tpp->thumbImg; tpp->thumbImg = img->resize (w, h, TI_Nearest); delete img; @@ -232,7 +234,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate) { RawImage *ri= new RawImage (fname); - int r = ri->loadRaw(); + int r = ri->loadRaw(1,0); if( r ){ delete ri; return NULL; @@ -282,10 +284,10 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati else skip = (ri->get_FujiWidth()/sqrt(0.5) - firstgreen - 1) / w; }else{ - if (fixwh == 1) // fix height, scale width - skip = (ri->get_height() - firstgreen - 1) / h; - else - skip = (ri->get_width() - firstgreen - 1) / w; + if (fixwh == 1) // fix height, scale width + skip = (ri->get_height() - firstgreen - 1) / h; + else + skip = (ri->get_width() - firstgreen - 1) / w; } if (skip % 2) skip--; @@ -303,7 +305,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati DCraw::dcrawImage_t image = ri->get_image(); - Image16* tmpImg = new Image16(tmpw, tmph); + Imagefloat* tmpImg = new Imagefloat(tmpw, tmph); if (ri->isBayer()) { for (int row = 1, y = 0; row < height - 1 && y < tmph; row += vskip, y++) { rofs = row * width; @@ -341,7 +343,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati double step = sqrt(0.5); int wide = fw / step; int high = (tmph - fw) / step; - Image16* fImg = new Image16(wide, high); + Imagefloat* fImg = new Imagefloat(wide, high); float r, c; for (int row = 0; row < high; row++) @@ -377,10 +379,16 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati w = tmpw * h / tmph; else h = tmph * w / tmpw; - - tpp->thumbImg = tmpImg->resize(w, h, TI_Bilinear); + + Image16* resImg;// = new Image16(tmpw, tmph);<< memory leak!! + resImg = tmpImg->to16(); delete tmpImg; + if (tpp->thumbImg) delete tpp->thumbImg; + tpp->thumbImg = resImg->resize(w, h, TI_Bilinear); + delete resImg; + + if (ri->get_FujiWidth() != 0) tpp->scale = (double) (height - ri->get_FujiWidth()) / sqrt(0.5) / h; else @@ -388,8 +396,8 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati // generate histogram for auto exposure tpp->aeHistCompression = 3; - tpp->aeHistogram = new unsigned int[65536 >> tpp->aeHistCompression]; - memset(tpp->aeHistogram, 0, (65536 >> tpp->aeHistCompression) * sizeof(int)); + tpp->aeHistogram(65536 >> tpp->aeHistCompression); + tpp->aeHistogram.clear(); int radd = 4; int gadd = 4; int badd = 4; @@ -407,18 +415,18 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati } for (int j = start; j < end; j++) if (FISGREEN(filter,i,j)) - tpp->aeHistogram[CLIP((int)(tpp->camwbGreen*image[i* width+j][1]))>>tpp->aeHistCompression]+=gadd; + tpp->aeHistogram[((int)(tpp->camwbGreen*image[i* width+j][1]))>>tpp->aeHistCompression]+=gadd; else if (FISRED(filter,i,j)) - tpp->aeHistogram[CLIP((int)(tpp->camwbRed * image[i* width+j][0]))>>tpp->aeHistCompression]+=radd; + tpp->aeHistogram[((int)(tpp->camwbRed * image[i* width+j][0]))>>tpp->aeHistCompression]+=radd; else if (FISBLUE(filter,i,j)) - tpp->aeHistogram[CLIP((int)(tpp->camwbBlue *image[i* width+j][2]))>>tpp->aeHistCompression]+=badd; + tpp->aeHistogram[((int)(tpp->camwbBlue *image[i* width+j][2]))>>tpp->aeHistCompression]+=badd; } // generate autoWB double avg_r = 0; double avg_g = 0; double avg_b = 0; - int rn = 0, gn = 0, bn = 0; + float rn = 0.0, gn = 0.0, bn = 0.0; for (int i = 32; i < height - 32; i++) { int start, end; @@ -504,22 +512,23 @@ void Thumbnail::cleanupGamma () { void Thumbnail::init () { RawImageSource::inverse33 (colorMatrix, iColorMatrix); - memset (camToD50, 0, sizeof(camToD50)); + //colorMatrix is rgb_cam + memset (cam2xyz, 0, sizeof(cam2xyz)); for (int i=0; i<3; i++) for (int j=0; j<3; j++) for (int k=0; k<3; k++) - camToD50[i][j] += colorMatrix[k][i] * sRGB_d50[k][j]; - camProfile = iccStore->createFromMatrix (camToD50, false, "Camera"); + cam2xyz[i][j] += xyz_sRGB[i][k] * colorMatrix[k][j]; + camProfile = iccStore->createFromMatrix (cam2xyz, false, "Camera"); } Thumbnail::Thumbnail () : - camProfile(NULL), thumbImg(NULL), aeHistogram(NULL), embProfileData(NULL), embProfile(NULL) { + camProfile(NULL), thumbImg(NULL), embProfileData(NULL), embProfile(NULL) { } Thumbnail::~Thumbnail () { - delete thumbImg; thumbImg=NULL; - delete [] aeHistogram; + delete thumbImg; + //delete [] aeHistogram; delete [] embProfileData; if (embProfile) cmsCloseProfile(embProfile); @@ -537,27 +546,29 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int } else rwidth = thumbImg->width * rheight / thumbImg->height; - Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); + Image16* tmp = thumbImg->resize (rwidth, rheight, interp); + Imagefloat* baseImg = tmp->tofloat(); if (params.coarse.rotate) { - Image16* tmp = baseImg->rotate (params.coarse.rotate); + Imagefloat* tmp = baseImg->rotate (params.coarse.rotate); rwidth = tmp->width; rheight = tmp->height; delete baseImg; baseImg = tmp; } if (params.coarse.hflip) { - Image16* tmp = baseImg->hflip (); + Imagefloat* tmp = baseImg->hflip (); delete baseImg; baseImg = tmp; } if (params.coarse.vflip) { - Image16* tmp = baseImg->vflip (); + Imagefloat* tmp = baseImg->vflip (); delete baseImg; baseImg = tmp; } Image8* img8 = baseImg->to8(); delete baseImg; + //delete tmp; return img8; } @@ -567,6 +578,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // compute WB multipliers ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green); if (params.wb.method=="Camera") { + //recall colorMatrix is rgb_cam double cam_r = colorMatrix[0][0]*camwbRed + colorMatrix[0][1]*camwbGreen + colorMatrix[0][2]*camwbBlue; double cam_g = colorMatrix[1][0]*camwbRed + colorMatrix[1][1]*camwbGreen + colorMatrix[1][2]*camwbBlue; double cam_b = colorMatrix[2][0]*camwbRed + colorMatrix[2][1]*camwbGreen + colorMatrix[2][2]*camwbBlue; @@ -576,6 +588,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei currWB = ColorTemp (autowbTemp, autowbGreen); double r, g, b; currWB.getMultipliers (r, g, b); + //iColorMatrix is cam_rgb double rm = iColorMatrix[0][0]*r + iColorMatrix[0][1]*g + iColorMatrix[0][2]*b; double gm = iColorMatrix[1][0]*r + iColorMatrix[1][1]*g + iColorMatrix[1][2]*b; double bm = iColorMatrix[2][0]*r + iColorMatrix[2][1]*g + iColorMatrix[2][2]*b; @@ -605,38 +618,45 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei else rwidth = thumbImg->width * rheight / thumbImg->height; - Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); - + Image16* resImg = thumbImg->resize (rwidth, rheight, interp); + //Imagefloat* baseImg = resImg->tofloat(); + //Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); + + if (params.coarse.rotate) { - Image16* tmp = baseImg->rotate (params.coarse.rotate); + Image16* tmp = resImg->rotate (params.coarse.rotate); rwidth = tmp->width; rheight = tmp->height; - delete baseImg; - baseImg = tmp; + delete resImg; + resImg = tmp; + //delete tmp; } if (params.coarse.hflip) { - Image16* tmp = baseImg->hflip (); - delete baseImg; - baseImg = tmp; + Image16* tmp = resImg->hflip (); + delete resImg; + resImg = tmp; + //delete tmp; } if (params.coarse.vflip) { - Image16* tmp = baseImg->vflip (); - delete baseImg; - baseImg = tmp; + Image16* tmp = resImg->vflip (); + delete resImg; + resImg = tmp; + //delete tmp; } // apply white balance int val; for (int i=0; ir[i][j]*rmi>>10; - baseImg->r[i][j] = CLIP(val); - val = baseImg->g[i][j]*gmi>>10; - baseImg->g[i][j] = CLIP(val); - val = baseImg->b[i][j]*bmi>>10; - baseImg->b[i][j] = CLIP(val); + val = ((int)resImg->r[i][j]*rmi)>>10; + resImg->r[i][j] = CLIP(val); + val = ((int)resImg->g[i][j]*gmi)>>10; + resImg->g[i][j] = CLIP(val); + val = ((int)resImg->b[i][j]*bmi)>>10; + resImg->b[i][j] = CLIP(val); } - - // apply highlight recovery, if needed + +/* + // apply highlight recovery, if needed -- CURRENTLY BROKEN DUE TO INCOMPATIBLE DATA TYPES; DO WE CARE??? if (isRaw && params.hlrecovery.enabled) { int maxval = 65535 / defGain; if (params.hlrecovery.method=="Luminance" || params.hlrecovery.method=="Color") @@ -644,30 +664,32 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei RawImageSource::HLRecovery_Luminance (baseImg->r[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval); else if (params.hlrecovery.method=="CIELab blending") { double icamToD50[3][3]; - RawImageSource::inverse33 (camToD50, icamToD50); + RawImageSource::inverse33 (cam2xyz, icamToD50); for (int i=0; ir[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval, camToD50, icamToD50); + RawImageSource::HLRecovery_CIELab (baseImg->r[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval, cam2xyz, icamToD50); } } - +*/ // perform color space transformation if (isRaw) - RawImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, camProfile, camToD50, logDefGain); + RawImageSource::colorSpaceConversion16 (resImg, params.icm, embProfile, camProfile, cam2xyz, logDefGain); else - StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile); - + StdImageSource::colorSpaceConversion16 (resImg, params.icm, embProfile); + + Imagefloat* baseImg = resImg->tofloat(); + delete resImg;// << avoid mem leak! int fw = baseImg->width; int fh = baseImg->height; ImProcFunctions ipf (¶ms, false); ipf.setScale (sqrt(double(fw*fw+fh*fh))/sqrt(double(thumbImg->width*thumbImg->width+thumbImg->height*thumbImg->height))*scale); - unsigned int* hist16 = new unsigned int [65536]; + LUTu hist16 (65536); ipf.firstAnalysis (baseImg, ¶ms, hist16, isRaw ? 2.2 : 0.0); // perform transform if (ipf.needsTransform()) { - Image16* trImg = new Image16 (fw, fh); + Imagefloat* trImg = new Imagefloat (fw, fh); ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh); delete baseImg; baseImg = trImg; @@ -676,21 +698,11 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // update blurmap SHMap* shmap = NULL; if (params.sh.enabled) { - unsigned short** buffer = NULL; - if (params.sh.hq) { - buffer = new unsigned short*[fh]; - for (int i=0; iupdate (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq); - if (buffer) { - for (int i=0; iupdate (baseImg, shradius, ipf.lumimul, params.sh.hq, 16); } // RGB processing @@ -704,37 +716,38 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // that is already preprocessed. So we simulate the effect here roughly my modifying the exposure accordingly if (params.raw.expos!=1) br += (params.raw.expos-1.0); - float* curve1 = new float [65536]; - float* curve2 = new float [65536]; - int* curve = new int [65536]; - CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, logDefGain, isRaw ? 2.2 : 0, true, params.toneCurve.curve, hist16, curve1, curve2, curve, NULL, 16); + LUTf curve1 (65536); + LUTf curve2 (65536); + LUTf curve (65536); + LUTf satcurve (65536); + + LUTu dummy; + CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, isRaw ? 2.2 : 0, true, params.toneCurve.curve, + hist16, dummy, curve1, curve2, curve, dummy, 16); + + LabImage* labView = new LabImage (fw,fh); - LabImage* labView = new LabImage (baseImg); ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation); if (shmap) delete shmap; // luminance histogram update - memset (hist16, 0, 65536*sizeof(int)); + hist16.clear(); for (int i=0; iL[i][j]]++; + hist16[(int)(2*(labView->L[i][j]))]++; // luminance processing - CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, 0.0, params.labCurve.brightness, params.labCurve.contrast, 0.0, 0.0, false, params.labCurve.lcurve, hist16, curve1, curve2, curve, NULL, 16); + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, + hist16, hist16, curve, dummy, 16); ipf.luminanceCurve (labView, labView, curve); - CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, params.labCurve.acurve, curve1, 16); - CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, params.labCurve.bcurve, curve2, 16); - ipf.chrominanceCurve (labView, labView, curve1, curve2); - - delete [] curve1; - delete [] curve2; - delete [] curve; - delete [] hist16; + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, \ + params.labCurve.acurve, params.labCurve.bcurve, curve1, curve2, satcurve, 16); + ipf.chrominanceCurve (labView, labView, curve1, curve2, satcurve); // color processing - ipf.colorCurve (labView, labView); + //ipf.colorCurve (labView, labView); // obtain final image Image8* readyImg = new Image8 (fw, fh); @@ -879,7 +892,6 @@ void Thumbnail::getSpotWB (const procparams::ProcParams& params, int xp, int yp, rtemp = ct.getTemp (); rgreen = ct.getGreen (); } - void Thumbnail::transformPixel (int x, int y, int tran, int& tx, int& ty) { int W = thumbImg->width; @@ -1385,10 +1397,10 @@ bool Thumbnail::readAEHistogram (const Glib::ustring& fname) { FILE* f = safe_g_fopen (fname, "rb"); if (!f) - aeHistogram = NULL; + aeHistogram(0); else { - aeHistogram = new unsigned int[65536>>aeHistCompression]; - fread (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f); + aeHistogram(65536>>aeHistCompression); + fread (&aeHistogram[0], 1, (65536>>aeHistCompression)*sizeof(aeHistogram[0]), f); fclose (f); return true; } @@ -1400,7 +1412,7 @@ bool Thumbnail::writeAEHistogram (const Glib::ustring& fname) { if (aeHistogram) { FILE* f = safe_g_fopen (fname, "wb"); if (f) { - fwrite (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f); + fwrite (&aeHistogram[0], 1, (65536>>aeHistCompression)*sizeof(aeHistogram[0]), f); fclose (f); return true; } diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index d2dea16ec..6e9e49d0d 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -31,7 +31,7 @@ namespace rtengine { cmsHPROFILE camProfile; double iColorMatrix[3][3]; - double camToD50[3][3]; + double cam2xyz[3][3]; void transformPixel (int x, int y, int tran, int& tx, int& ty); @@ -45,7 +45,7 @@ namespace rtengine { double camwbBlue; double autowbTemp; double autowbGreen; - unsigned int* aeHistogram; + LUTu aeHistogram; int aeHistCompression; int embProfileLength; unsigned char* embProfileData; diff --git a/rtengine/settings.h b/rtengine/settings.h index bd3c1f32a..51e766118 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -1,47 +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 _RTSETTINGS_ -#define _RTSETTINGS_ - -namespace rtengine { - - /** This structure holds the global parameters used by the RT engine. */ - class Settings { - public: - bool dualThreadEnabled; ///< If true, the image processing operations with utilize two processor cores (if possible) - 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) +/* + * 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 _RTSETTINGS_ +#define _RTSETTINGS_ + +namespace rtengine { + + /** This structure holds the global parameters used by the RT engine. */ + class Settings { + public: + bool dualThreadEnabled; ///< If true, the image processing operations with utilize two processor cores (if possible) + 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 autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile - - bool verbose; - Glib::ustring darkFramesPath; ///< The default directory for dark frames - Glib::ustring flatFieldsPath; ///< The default directory for flat fields - - /** Creates a new instance of Settings. - * @return a pointer to the new Settings instance. */ - static Settings* create (); - /** Destroys an instance of Settings. - * @param s a pointer to the Settings instance to destroy. */ - static void destroy (Settings* s); - }; -} - -#endif - + + bool verbose; + Glib::ustring darkFramesPath; ///< The default directory for dark frames + Glib::ustring flatFieldsPath; ///< The default directory for flat fields + bool LCMSSafeMode; // If true, not OMP + Glib::ustring adobe; + Glib::ustring prophoto; + Glib::ustring widegamut; + Glib::ustring beta; + Glib::ustring best; + Glib::ustring bruce; + Glib::ustring srgb; + + /** Creates a new instance of Settings. + * @return a pointer to the new Settings instance. */ + static Settings* create (); + /** Destroys an instance of Settings. + * @param s a pointer to the Settings instance to destroy. */ + static void destroy (Settings* s); + }; +} + +#endif + diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index 836f60e06..c81b79147 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -21,9 +21,22 @@ #include #include +#include //for dirpyr + + +#undef MAXVAL +#undef CLIP +#undef MAX +#undef MIN +#undef SQR + #undef THREAD_PRIORITY_NORMAL #define MAXVAL 0xffff #define CLIP(a) ((a)>0?((a)(b)?(b):(a)) namespace rtengine { @@ -31,9 +44,9 @@ extern const Settings* settings; SHMap::SHMap (int w, int h, bool multiThread) : W(w), H(h), multiThread(multiThread) { - map = new unsigned short*[H]; + map = new float*[H]; for (int i=0; i* buffer = new AlignedBuffer (MAX(W,H)); - gaussHorizontal (map, map, buffer, W, H, radius, multiThread); - gaussVertical (map, map, buffer, W, H, radius, multiThread); + gaussHorizontal (map, map, buffer, W, H, radius, multiThread); + gaussVertical (map, map, buffer, W, H, radius, multiThread); delete buffer; } else { +/* #if 0 // the new OpenMP method does not need thread number specific code. // #ifdef _OPENMP @@ -73,13 +87,57 @@ void SHMap::update (Image16* img, unsigned short** buffer, double radius, double int blk = H/nthreads; if (tid (map, buffer, W, H, 8000, radius, tid*blk, (tid+1)*blk); + bilateral (map, buffer, W, H, 8000, radius, tid*blk, (tid+1)*blk); else - bilateral (map, buffer, W, H, 8000, radius, tid*blk, H); + bilateral (map, buffer, W, H, 8000, radius, tid*blk, H); } #else - bilateral (map, buffer, W, H, 8000, radius, 0, H); + bilateral (map, buffer, W, H, 8000, radius, 0, H); #endif +*/ + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //experimental dirpyr shmap + + float thresh = 100*radius;//1000; + LUTf rangefn(0x10000); + float ** dirpyrlo[2]; + + int intfactor = 1024;//16384; + + //set up range functions + + for (int i=0; i<0x10000; i++) { + //rangefn[i] = (int)(((thresh)/((double)(i) + (thresh)))*intfactor); + rangefn[i] = (int)(exp(-(MIN(10,((float)i*i) / (thresh*thresh))))*intfactor); + //if (rangefn[i]<0 || rangefn[i]>intfactor) + //printf("i=%d rangefn=%d arg=%f \n",i,rangefn[i], float(i*i) / (thresh*thresh)); + } + dirpyrlo[0] = allocArray (W, H); + dirpyrlo[1] = allocArray (W, H); + + int scale=1; + int level=0; + int indx=0; + dirpyr_shmap(map, dirpyrlo[indx], W, H, rangefn, 0, scale ); + scale *= 2; + level += 1; + indx = 1-indx; + while (skip*scale<16) { + dirpyr_shmap(dirpyrlo[1-indx], dirpyrlo[indx], W, H, rangefn, level, scale ); + scale *= 2; + level += 1; + indx = 1-indx; + } + + dirpyr_shmap(dirpyrlo[1-indx], map, W, H, rangefn, level, scale ); + + + freeArray(dirpyrlo[0], H); + freeArray(dirpyrlo[1], H); + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +/* // anti-alias filtering the result #ifdef _OPENMP #pragma omp for @@ -90,6 +148,8 @@ void SHMap::update (Image16* img, unsigned short** buffer, double radius, double map[i][j] = (buffer[i-1][j-1]+buffer[i-1][j]+buffer[i-1][j+1]+buffer[i][j-1]+buffer[i][j]+buffer[i][j+1]+buffer[i+1][j-1]+buffer[i+1][j]+buffer[i+1][j+1])/9; else map[i][j] = buffer[i][j]; +*/ + } } // end parallel enclosure // update average, minimum, maximum @@ -110,10 +170,65 @@ void SHMap::update (Image16* img, unsigned short** buffer, double radius, double avg = (int) _avg; } -void SHMap::forceStat (unsigned short max_, unsigned short min_, unsigned short avg_) { +void SHMap::forceStat (float max_, float min_, float avg_) { max = max_; min = min_; avg = avg_; -}} +} + +void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale) +{ + //scale is spacing of directional averaging weights + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // calculate weights, compute directionally weighted average + + int halfwin=2; + int domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,2,2,1},{1,2,2,2,1},{1,1,1,1,1}}; + + //generate domain kernel + if (level<2) { + halfwin = 1; + domker[1][1]=domker[1][2]=domker[2][1]=domker[2][2]=1; + } + + + int scalewin = halfwin*scale; + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) + { + float val=0; + float norm=0; + + for(int inbr=(i-scalewin); inbr<=(i+scalewin); inbr+=scale) { + if (inbr<0 || inbr>height-1) continue; + for (int jnbr=(j-scalewin); jnbr<=(j+scalewin); jnbr+=scale) { + if (jnbr<0 || jnbr>width-1) continue; + float dirwt = ( domker[(inbr-i)/scale+halfwin][(jnbr-j)/scale+halfwin] * rangefn[abs(data_fine[inbr][jnbr]-data_fine[i][j])] ); + val += dirwt*data_fine[inbr][jnbr]; + norm += dirwt; + /*if (val<0 || norm<0) { + printf("val=%f norm=%f \n",val,norm); + printf("i=%d j=%d inbr=%d jnbr=%d domker=%d val=%d nbrval=%d rangefn=%d \n",i,j,inbr,jnbr, \ + domker[(inbr-i)/scale+halfwin][(jnbr-j)/scale+halfwin], \ + data_fine[i][j], data_fine[inbr][jnbr], \ + rangefn[abs(data_fine[inbr][jnbr]-data_fine[i][j])]); + }*/ + } + } + data_coarse[i][j]=CLIP((int)(val/norm));//low pass filter + if (val<=0 || norm<=0) + printf("val=%f norm=%f \n",val,norm); + } + } + +} + + +}//end of SHMap diff --git a/rtengine/shmap.h b/rtengine/shmap.h index 042d10d7f..7ddf23b04 100644 --- a/rtengine/shmap.h +++ b/rtengine/shmap.h @@ -19,6 +19,7 @@ #ifndef __SHMAP__ #define __SHMAP__ +#include #include namespace rtengine { @@ -27,15 +28,17 @@ class SHMap { public: int W, H; - unsigned short** map; - unsigned short max, min, avg; + float** map; + float max, min, avg; bool multiThread; SHMap (int w, int h, bool multiThread); ~SHMap (); - void update (Image16* img, unsigned short** buffer, double radius, double lumi[3], bool hq); - void forceStat (unsigned short max_, unsigned short min_, unsigned short avg_); + void update (Imagefloat* img, double radius, double lumi[3], bool hq, int skip); + void forceStat (float max_, float min_, float avg_); + void dirpyr_shmap (float ** data_fine, float ** data_coarse, + int width, int height, LUTf & rangefn, int level, int scale); }; }; #endif diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 037e7b2f9..1bfba277a 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -2,7 +2,6 @@ * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2010 Oliver Duis * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +24,15 @@ #include #include #include - +#include #include - +#include #undef THREAD_PRIORITY_NORMAL -namespace rtengine { +#define CLIP(a) ((a)>0?((a)<65535?(a):65535):0) -// tunnelMetaData copies IPTC and XMP untouched to output + +namespace rtengine { IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData) { errorCode = 0; @@ -43,7 +43,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p pl->setProgressStr ("PROGRESSBAR_PROCESSING"); pl->setProgress (0.0); } - + InitialImage* ii = job->initialImage; if (!ii) { ii = InitialImage::load (job->fname, job->isRaw, &errorCode); @@ -56,7 +56,6 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // aquire image from imagesource ImageSource* imgsrc = ii->getImageSource (); - imgsrc->setProgressListener(NULL); int tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; @@ -98,39 +97,38 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p else if (params.wb.method=="Auto") currWB = imgsrc->getAutoWB (); - Image16* baseImg; PreviewProps pp (0, 0, fw, fh, 1); imgsrc->preprocess( params.raw ); - if (pl) pl->setProgress (0.20); + if (pl) pl->setProgress (0.20); imgsrc->demosaic( params.raw ); - if (pl) pl->setProgress (0.40); - baseImg = new Image16 (fw, fh); + if (pl) pl->setProgress (0.40); + Imagefloat* baseImg = new Imagefloat (fw, fh); imgsrc->getImage (currWB, tr, baseImg, pp, params.hlrecovery, params.icm, params.raw); if (pl) pl->setProgress (0.45); + // perform first analysis - unsigned int* hist16 = new unsigned int[65536]; + LUTu hist16 (65536); ipf.firstAnalysis (baseImg, ¶ms, hist16, imgsrc->getGamma()); // perform transform (excepted resizing) if (ipf.needsTransform()) { - Image16* trImg = new Image16 (fw, fh); + Imagefloat* trImg = new Imagefloat (fw, fh); ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh); delete baseImg; baseImg = trImg; } // update blurmap - int** buffer = new int*[fh]; - for (int i=0; iupdate (baseImg, (unsigned short**)buffer, shradius, ipf.lumimul, params.sh.hq); + double shradius = params.sh.radius; + if (!params.sh.hq) shradius *= radius / 1800.0; + shmap->update (baseImg, shradius, ipf.lumimul, params.sh.hq, 1); } // RGB processing //!!!// auto exposure!!! @@ -138,71 +136,71 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p int bl = params.toneCurve.black; if (params.toneCurve.autoexp) { - unsigned int* aehist = new unsigned int [65536]; int aehistcompr; - imgsrc->getAEHistogram (aehist, aehistcompr); + LUTu aehist; int aehistcompr; + imgsrc->getAutoExpHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, br, bl); - delete [] aehist; } - float* curve1 = new float [65536]; - float* curve2 = new float [65536]; - int* curve = new int [65536]; - - CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getDefGain(), imgsrc->getGamma(), true, params.toneCurve.curve, hist16, curve1, curve2, curve, NULL); + LUTf curve1 (65536,0); + LUTf curve2 (65536,0); + LUTf curve (65536,0); + LUTf satcurve (65536,0); + LUTu dummy; - LabImage* labView = new LabImage (baseImg); - ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation); + CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getGamma(), true, params.toneCurve.curve, + hist16, dummy, curve1, curve2, curve, dummy); + + LabImage* labView = new LabImage (fw,fh); + + ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation); if (shmap) - delete shmap; + delete shmap; if (pl) pl->setProgress (0.5); // luminance histogram update - memset (hist16, 0, 65536*sizeof(int)); + hist16.clear(); for (int i=0; iL[i][j]]++; + hist16[CLIP((int)((labView->L[i][j])))]++; // luminance processing - CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, 0.0, params.labCurve.brightness, params.labCurve.contrast, 0.0, 0.0, false, params.labCurve.lcurve, hist16, curve1, curve2, curve, NULL); - ipf.luminanceCurve (labView, labView, curve); - CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, params.labCurve.acurve, curve1, 1); - CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, params.labCurve.bcurve, curve2, 1); - ipf.chrominanceCurve (labView, labView, curve1, curve2); - + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, hist16, curve, dummy, 1); + ipf.luminanceCurve (labView, labView, curve); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.enable_saturationlimiter, params.labCurve.saturationlimit, \ + params.labCurve.acurve, params.labCurve.bcurve, curve1, curve2, satcurve, 1); + ipf.chrominanceCurve (labView, labView, curve1, curve2, satcurve); + ipf.impulsedenoise (labView); ipf.defringe (labView); - ipf.lumadenoise (labView, buffer); - ipf.sharpening (labView, (unsigned short**)buffer); + //ipf.lumadenoise (labView, buffer); + ipf.dirpyrdenoise (labView); - delete [] curve1; - delete [] curve2; - delete [] curve; - delete [] hist16; + if (params.sharpening.enabled) { + float** buffer = new float*[fh]; + for (int i=0; isetProgress (0.60); + if (pl) pl->setProgress (0.60); // crop and convert to rgb16 - Image16* readyImg; int cx = 0, cy = 0, cw = labView->W, ch = labView->H; if (params.crop.enabled) { cx = params.crop.x; @@ -210,13 +208,12 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p cw = params.crop.w; ch = params.crop.h; } - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output); - - // we can now safely delete labView + + if(params.icm.gamma != "default") + { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + Image16* readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.working, params.icm.gamma); delete labView; - - if (pl) - pl->setProgress (0.70); + if (pl) pl->setProgress (0.70); // get the resize parameters int refw, refh; @@ -281,28 +278,151 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } } + if (tunnelMetaData) readyImg->setMetadata (ii->getMetaData()->getExifData ()); else readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); - + ProfileContent pc; + Glib::ustring chpro; + int present_space[7]={0,0,0,0,0,0,0}; + std::vector opnames = rtengine::getOutputProfiles (); + //test if files are in system + for (int j=0; j<7;j++) { + //one can modify "option" [Color Management] to adapt name of profile ih there are different for windows, MacOS, Linux ?? + if(j==0) chpro=options.rtSettings.prophoto; + else if(j==1) chpro=options.rtSettings.adobe; + else if(j==2) chpro=options.rtSettings.widegamut; + else if(j==3) chpro=options.rtSettings.beta; + else if(j==4) chpro=options.rtSettings.best; + else if(j==5) chpro=options.rtSettings.bruce; + else if(j==6) chpro=options.rtSettings.srgb; + for (int i=0; isetProgressStr ("Missing file..");pl->setProgress (0.0);}// display file not present: not very good display information...!! + } + //choose output profile + if(params.icm.working=="ProPhoto" && present_space[0]==1) params.icm.output=options.rtSettings.prophoto; + else if(params.icm.working=="Adobe RGB" && present_space[1]==1) params.icm.output=options.rtSettings.adobe; + else if(params.icm.working=="WideGamut" && present_space[2]==1) params.icm.output=options.rtSettings.widegamut; + else if(params.icm.working=="Beta RGB" && present_space[3]==1) params.icm.output=options.rtSettings.beta; + else if(params.icm.working=="BestRGB" && present_space[4]==1) params.icm.output=options.rtSettings.best; + else if(params.icm.working=="BruceRGB" && present_space[5]==1) params.icm.output=options.rtSettings.bruce; + else params.icm.output=options.rtSettings.srgb; //if not found or choice=srgb + + if (params.icm.output.compare (0, 6, "No ICM") && params.icm.output!="") pc = iccStore->getContent (params.icm.output); - + readyImg->setOutputProfile (pc.data, pc.length); - + delete baseImg; if (!job->initialImage) ii->decreaseRef (); - + delete job; if (pl) pl->setProgress (0.75); - + return readyImg; + } + else + {//if default mode : profil = selection by choice in list (Prophoto.icm, sRGB.icm, etc., etc.) , gamma = gamma of profile + Image16* readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output); + delete labView; + if (pl) pl->setProgress (0.70); + + // get the resize parameters + int refw, refh; + double tmpScale; + + if (params.resize.enabled) { + + if (params.crop.enabled && params.resize.appliesTo == "Cropped area") { + // the resize values applies to the crop dimensions + refw = cw; + refh = ch; + } + else { + // the resize values applies to the image dimensions + // if a crop exists, it will be resized to the calculated scale + refw = fw; + refh = fh; + } + + switch(params.resize.dataspec) { + case (1): + // Width + tmpScale = (double)params.resize.width/(double)refw; + break; + case (2): + // Height + tmpScale = (double)params.resize.height/(double)refh; + break; + case (3): + // FitBox + if ((double)refw/(double)refh > (double)params.resize.width/(double)params.resize.height) { + tmpScale = (double)params.resize.width/(double)refw; + } + else { + tmpScale = (double)params.resize.height/(double)refh; + } + break; + default: + // Scale + tmpScale = params.resize.scale; + break; + } + + // resize image + if (fabs(tmpScale-1.0)>1e-5) + { + int imw, imh; + if (params.crop.enabled && params.resize.appliesTo == "Full image") { + imw = cw; + imh = ch; + } + else { + imw = refw; + imh = refh; + } + imw = (int)( (double)imw * tmpScale + 0.5 ); + imh = (int)( (double)imh * tmpScale + 0.5 ); + Image16* tempImage = new Image16 (imw, imh); + ipf.resize (readyImg, tempImage, tmpScale); + delete readyImg; + readyImg = tempImage; + } + } + + + if (tunnelMetaData) + readyImg->setMetadata (ii->getMetaData()->getExifData ()); + else + readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); + + + ProfileContent pc; + if (params.icm.output.compare (0, 6, "No ICM") && params.icm.output!="") + pc = iccStore->getContent (params.icm.output); + + readyImg->setOutputProfile (pc.data, pc.length); + + delete baseImg; + + if (!job->initialImage) + ii->decreaseRef (); + + delete job; + if (pl) + pl->setProgress (0.75); + + return readyImg; + + } } void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) { diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index dedd8b619..5d7c5bc92 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -96,7 +96,8 @@ int StdImageSource::load (Glib::ustring fname, bool batch) { plistener->setProgress (1.0); } - wb = ColorTemp (1.0, 1.0, 1.0); + wb = ColorTemp (1.0,1.0,1.0); + //this is probably a mistake if embedded profile is not D65 return 0; } @@ -139,20 +140,22 @@ void StdImageSource::transform (PreviewProps pp, int tran, int &sx1, int &sy1, i sx2 = sx1 + pp.h; sy2 = sy1 + pp.w; } - printf ("ppx %d ppy %d ppw %d pph %d s: %d %d %d %d\n",pp.x, pp.y,pp.w,pp.h,sx1,sy1,sx2,sy2); + //printf ("ppx %d ppy %d ppw %d pph %d s: %d %d %d %d\n",pp.x, pp.y,pp.w,pp.h,sx1,sy1,sx2,sy2); if (sx1<0)sx1=0; if (sy1<0)sy1=0; } -void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, bool first, HRecParams hrp) { +void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, HRecParams hrp) { // compute channel multipliers - double rm, gm, bm; - ctemp.getMultipliers (rm, gm, bm); + double drm, dgm, dbm; + ctemp.getMultipliers (drm, dgm, dbm); + float rm=drm,gm=dgm,bm=dbm; + rm = 1.0 / rm; gm = 1.0 / gm; bm = 1.0 / bm; - double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; + float mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; rm /= mul_lum; gm /= mul_lum; bm /= mul_lum; @@ -179,12 +182,12 @@ void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, Previ int mtran = tran; int skip = pp.skip; - if ((sx1 + skip*imwidth)>maxx) imwidth -- ; // we have a boundary condition that can cause errors + //if ((sx1 + skip*imwidth)>maxx) imwidth -- ; // we have a boundary condition that can cause errors // improve speed by integrating the area division into the multipliers // switched to using ints for the red/green/blue channel buffer. // Incidentally this improves accuracy too. - double area=skip*skip; + float area=skip*skip; rm/=area; gm/=area; bm/=area; @@ -193,63 +196,66 @@ void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, Previ #pragma omp parallel { #endif - int *line_red = new int[imwidth]; - int *line_green = new int[imwidth]; - int *line_blue = new int[imwidth]; + float *line_red = new float[imwidth]; + float *line_green = new float[imwidth]; + float *line_blue = new float[imwidth]; #ifdef _OPENMP #pragma omp for #endif - for (int ix=0;ixmaxy-skip) i=maxy-skip; // avoid trouble - for (int j=0,jx=sx1; j=maxy-skip) i=maxy-skip-1; // avoid trouble + for (int j=0,jx=sx1; j=maxx-skip) jx=maxx-skip-1; // avoid trouble + + float rtot,gtot,btot; + rtot=gtot=btot=0; + + for (int m=0; mr[i+m][jx+n]); - gtot += CurveFactory::igamma_srgb(img->g[i+m][jx+n]); - btot += CurveFactory::igamma_srgb(img->b[i+m][jx+n]); + rtot += CurveFactory::igamma_srgb(img->r[i+m][jx+n]); + gtot += CurveFactory::igamma_srgb(img->g[i+m][jx+n]); + btot += CurveFactory::igamma_srgb(img->b[i+m][jx+n]); } - line_red[j] = rtot; - line_green[j] = gtot; - line_blue[j] = btot; - } - -// covert back to gamma and clip + line_red[j] = rtot; + line_green[j] = gtot; + line_blue[j] = btot; + } + + // covert back to gamma and clip #define GCLIP( x ) CurveFactory::gamma_srgb(CLIP(x)) - -// if (hrp.enabled) -// hlRecovery (red, grn, blue, i, sx1, sx2, pp.skip); - - if ((mtran & TR_ROT) == TR_R180) - for (int j=0; jr[imheight-1-ix][imwidth-1-j] = (int)GCLIP(rm*line_red[j]); - image->g[imheight-1-ix][imwidth-1-j] = (int)GCLIP(gm*line_green[j]); - image->b[imheight-1-ix][imwidth-1-j] = (int)GCLIP(bm*line_blue[j]); - } - else if ((mtran & TR_ROT) == TR_R90) - for (int j=0,jx=sx1; jr[j][imheight-1-ix] = (int)GCLIP(rm*line_red[j]); - image->g[j][imheight-1-ix] = (int)GCLIP(gm*line_green[j]); - image->b[j][imheight-1-ix] = (int)GCLIP(bm*line_blue[j]); - } - else if ((mtran & TR_ROT) == TR_R270) - for (int j=0,jx=sx1; jr[imwidth-1-j][ix] = (int)GCLIP(rm*line_red[j]); - image->g[imwidth-1-j][ix] = (int)GCLIP(gm*line_green[j]); - image->b[imwidth-1-j][ix] = (int)GCLIP(bm*line_blue[j]); - } - else { - for (int j=0,jx=sx1; jr[ix][j] = (int)GCLIP(rm*line_red[j]); - image->g[ix][j] = (int)GCLIP(gm*line_green[j]); - image->b[ix][j] = (int)GCLIP(bm*line_blue[j]); - } - } - } + + // if (hrp.enabled) + // hlRecovery (red, grn, blue, i, sx1, sx2, pp.skip); + + if ((mtran & TR_ROT) == TR_R180) + for (int j=0; jr[imheight-1-ix][imwidth-1-j] = GCLIP(rm*line_red[j])/65535.0; + image->g[imheight-1-ix][imwidth-1-j] = GCLIP(gm*line_green[j])/65535.0; + image->b[imheight-1-ix][imwidth-1-j] = GCLIP(bm*line_blue[j])/65535.0; + } + else if ((mtran & TR_ROT) == TR_R90) + for (int j=0,jx=sx1; jr[j][imheight-1-ix] = GCLIP(rm*line_red[j])/65535.0; + image->g[j][imheight-1-ix] = GCLIP(gm*line_green[j])/65535.0; + image->b[j][imheight-1-ix] = GCLIP(bm*line_blue[j])/65535.0; + } + else if ((mtran & TR_ROT) == TR_R270) + for (int j=0,jx=sx1; jr[imwidth-1-j][ix] = GCLIP(rm*line_red[j])/65535.0; + image->g[imwidth-1-j][ix] = GCLIP(gm*line_green[j])/65535.0; + image->b[imwidth-1-j][ix] = GCLIP(bm*line_blue[j])/65535.0; + } + else { + for (int j=0,jx=sx1; jr[ix][j] = GCLIP(rm*line_red[j])/65535.0; + image->g[ix][j] = GCLIP(gm*line_green[j])/65535.0; + image->b[ix][j] = GCLIP(bm*line_blue[j])/65535.0; + //if (ix==100 && j==100) printf("stdimsrc before R= %f G= %f B= %f \n",65535*image->r[ix][j],65535*image->g[ix][j],65535*image->b[ix][j]); + + } + } + } #undef GCLIP delete [] line_red; delete [] line_green; @@ -260,7 +266,7 @@ void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, Previ } -void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw) { +void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw) { MyTime t1,t2; @@ -269,20 +275,70 @@ void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe // if (hrp.enabled==true && hrmap[0]==NULL) // updateHLRecoveryMap (); // the code will use OpenMP as of now. + + //Image16* tmpim = new Image16 (image->width,image->height); getImage_ (ctemp, tran, image, pp, true, hrp); - colorSpaceConversion (image, cmp, embProfile); - + colorSpaceConversion (image, cmp, embProfile); + + for ( int h = 0; h < image->height; ++h ) + for ( int w = 0; w < image->width; ++w ) { + image->r[h][w] *= 65535.0 ; + image->g[h][w] *= 65535.0 ; + image->b[h][w] *= 65535.0 ; + //if (h==100 && w==100) printf("stdimsrc after R= %f G= %f B= %f \n",image->r[h][w],image->g[h][w],image->b[h][w]); + } + // Flip if needed if (tran & TR_HFLIP) - hflip (image); - if (tran & TR_VFLIP) - vflip (image); - + hflip (image); + if (tran & TR_VFLIP) + vflip (image); + + t2.set (); } + +void StdImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded) { + + cmsHPROFILE in; + cmsHPROFILE out = iccStore->workingSpace (cmp.working); + if (cmp.input=="(embedded)" || cmp.input=="" || cmp.input=="(camera)") { + if (embedded) + in = embedded; + else + in = iccStore->getsRGBProfile (); + } else { + if (cmp.input!="(none)") { + in = iccStore->getProfile (cmp.input); + if (in==NULL && embedded) + in = embedded; + else if (in==NULL) + in = iccStore->getsRGBProfile (); + else if (cmp.gammaOnInput) + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + im->r[i][j] = CurveFactory::gamma (im->r[i][j]); + im->g[i][j] = CurveFactory::gamma (im->g[i][j]); + im->b[i][j] = CurveFactory::gamma (im->b[i][j]); + } + } + } + + if (cmp.input!="(none)") { + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), out, (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)), settings->colorimetricIntent, + settings->LCMSSafeMode ? cmsFLAGS_NOOPTIMIZE : cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + lcmsMutex->unlock (); + + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + + cmsDeleteTransform(hTransform); + } +} + -void StdImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded) { +void StdImageSource::colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded) { cmsHPROFILE in; cmsHPROFILE out = iccStore->workingSpace (cmp.working); @@ -309,9 +365,12 @@ void StdImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cm if (cmp.input!="(none)") { lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, + settings->LCMSSafeMode ? 0 : cmsFLAGS_NOCACHE); lcmsMutex->unlock (); - cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); + + im->ExecCMSTransform(hTransform, settings->LCMSSafeMode); + cmsDeleteTransform(hTransform); } } @@ -332,7 +391,7 @@ void StdImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) { h = pp.h / pp.skip + (pp.h % pp.skip > 0); } -void StdImageSource::hflip (Image16* image) { +void StdImageSource::hflip (Imagefloat* image) { int width = image->width; int height = image->height; @@ -354,7 +413,7 @@ void StdImageSource::hflip (Image16* image) { delete [] rowb; } -void StdImageSource::vflip (Image16* image) { +void StdImageSource::vflip (Imagefloat* image) { int width = image->width; int height = image->height; @@ -472,19 +531,19 @@ void StdImageSource::hlRecovery (unsigned short* red, unsigned short* green, uns rtengine::hlRecovery (red, green, blue, img->height, img->width, i, sx1, sx2, skip, needhr, hrmap); } */ -int StdImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { +void StdImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) { histcompr = 3; - memset (histogram, 0, (65536>>histcompr)*sizeof(int)); + histogram(65536>>histcompr); + histogram.clear(); for (int i=0; iheight; i++) for (int j=0; jwidth; j++) { - histogram[CurveFactory::igamma_srgb (img->r[i][j])>>histcompr]++; - histogram[CurveFactory::igamma_srgb (img->g[i][j])>>histcompr]++; - histogram[CurveFactory::igamma_srgb (img->b[i][j])>>histcompr]++; + histogram[(int)CurveFactory::igamma_srgb (img->r[i][j])>>histcompr]++; + histogram[(int)CurveFactory::igamma_srgb (img->g[i][j])>>histcompr]++; + histogram[(int)CurveFactory::igamma_srgb (img->b[i][j])>>histcompr]++; } - return 1; } ColorTemp StdImageSource::getAutoWB () { diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index b06f53916..ae2d50f16 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -44,12 +44,12 @@ class StdImageSource : public ImageSource { ~StdImageSource (); int load (Glib::ustring fname, bool batch = false); - void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw); + void getImage (ColorTemp ctemp, int tran, Imagefloat* 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); - int getAEHistogram (unsigned int* histogram, int& histcompr); + void getAutoExpHistogram (LUTu &histogram, int& histcompr); double getDefGain () { return 0.0; } double getGamma () { return 0.0; } @@ -59,15 +59,16 @@ class StdImageSource : public ImageSource { ImageData* getImageData () { return idata; } void setProgressListener (ProgressListener* pl) { plistener = pl; } - static void colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded); + static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded); static inline double intpow (double a, int b) { double r = 1.0; for (int i=0; i + * + * 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 + +Updater::Updater () : + change (0), + ipc (NULL), + pl (NULL), + running (false) +{ +} + +ProcParams* Updater::changing (int what) { + + mutex.lock (); + change |= what; + return ¶ms; +} + +void Updater::changed () { + + mutex.unlock (); + startProcessing (); +} + +void Updater::clearState () { + + mutex.lock (); + change = 0; + mutex.unlock (); +} + +ProcParams* Updater::getParams () { + + return ¶ms; +} + +void Updater::startProcessing () { + + #undef THREAD_PRIORITY_LOW + + tstart.lock (); + if (ipc && !running) { + running = true; + tstart.unlock (); + Glib::Thread::create(sigc::mem_fun(*this, &Updater::process), 0, false, true, Glib::THREAD_PRIORITY_LOW); + } + else + tstart.unlock (); +} + +void Updater::process () { + + processing.lock (); + if (pl) + pl->setProcessingState (true); + + int ch; + + mutex.lock (); + while (change && ipc) { + ipc->params.copy (¶ms); + ch = change; + change = 0; + mutex.unlock (); + if (ch<=16384) + ipc->update (ch); + mutex.lock (); + } + mutex.unlock (); + tstart.lock (); + running = false; + tstart.unlock (); + + if (pl) + pl->setProcessingState (false); + processing.unlock (); +} + +void Updater::stop () { + + if (running) { + change = 0; + processing.lock (); + processing.unlock (); + + } +} + diff --git a/rtengine/updater.h b/rtengine/updater.h new file mode 100644 index 000000000..54dbf1cd7 --- /dev/null +++ b/rtengine/updater.h @@ -0,0 +1,57 @@ +/* + * 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 _UPDATER_ +#define _UPDATER_ + +#include +#include +#include +#include + +class Updater { + + protected: + int change; + ProcParams params; + Glib::Mutex mutex; + Glib::Mutex tstart; + Glib::Mutex processing; + ImProcCoordinator* ipc; + ProgressListener* pl; + bool running; + + public: + + Updater (); + void setProgressListener (ProgressListener* l) { pl = l; } + void setIPC (ImProcCoordinator* ipc) { this->ipc = ipc; } + + ProcParams* changing (int what); + void changed (); + void clearState (); + int getClear (); + ProcParams* getParams (); + int getChange (); + void startProcessing (); + void process (); + + void stop (); +}; + +#endif diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index cede66dad..e9c7942b8 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -25,6 +25,8 @@ #include #include +#include + using namespace rtengine; BatchQueue::BatchQueue () : processing(NULL), listener(NULL) { diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index a8acadebc..9594aa021 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -19,6 +19,8 @@ #include #include +#include + BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, guint8* previmg, int prevw, int prevh, Thumbnail* thumbnail) : ThumbBrowserEntryBase(fname), opreview(previmg), origpw(prevw), origph(prevh), thumbnail(thumbnail), diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index d61d51532..48054e0a0 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -120,7 +120,7 @@ void BatchToolPanelCoordinator::initSession () { pparams = selected[0]->getProcParams (); coarse->initBatchBehavior (); - curve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]); + toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]); lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST], options.baBehav[ADDSET_LC_SATURATION]); whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN]); vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT]); diff --git a/rtgui/clipboard.h b/rtgui/clipboard.h index e9a43bd54..704bd03f2 100644 --- a/rtgui/clipboard.h +++ b/rtgui/clipboard.h @@ -21,6 +21,7 @@ #include #include +#include class Clipboard { @@ -28,6 +29,9 @@ class Clipboard { std::vector iptc; bool _hasProcParams; rtengine::procparams::ProcParams procParams; + DiagonalCurveType hasCurveDataType; + std::vector curve; + public: void setIPTC (const std::vector& iptcc) { iptc = iptcc; _hasIPTC = true;} @@ -37,6 +41,12 @@ class Clipboard { void setProcParams (const rtengine::procparams::ProcParams& pparams) { procParams = pparams; _hasProcParams = true; } const rtengine::procparams::ProcParams& getProcParams () { return procParams; } bool hasProcParams () { return _hasProcParams; } + + void setCurveData (std::vector& p, DiagonalCurveType type ) { curve = p; hasCurveDataType = type; return; } + const std::vector & getCurveData () { return curve; } + DiagonalCurveType hasCurveData () { return hasCurveDataType; } + + }; extern Clipboard clipboard; diff --git a/rtgui/crop.cc b/rtgui/crop.cc index 43592be86..abf2564b0 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -103,26 +103,32 @@ Crop::Crop (): Gtk::VBox(), FoldableToolPanel(this) { pack_start (*hb31, Gtk::PACK_SHRINK, 4); - dpibox = Gtk::manage (new Gtk::VBox()); - dpibox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_SHRINK, 2); + // ppibox START + ppibox = Gtk::manage (new Gtk::VBox()); + ppibox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_SHRINK, 2); Gtk::HBox* hb4 = Gtk::manage (new Gtk::HBox ()); - hb4->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_DPI")))); - dpi = Gtk::manage (new Gtk::SpinButton ()); - dpi->set_size_request (60, -1); - hb4->pack_start (*dpi); + hb4->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_PPI")))); + ppi = Gtk::manage (new Gtk::SpinButton ()); + ppi->set_size_request (60, -1); + hb4->pack_start (*ppi); - dpibox->pack_start (*hb4, Gtk::PACK_SHRINK, 2); + sizebox = Gtk::manage (new Gtk::HBox()); sizecm = Gtk::manage (new Gtk::Label (M("GENERAL_NA") + " cm x " + M("GENERAL_NA") + " cm")); sizein = Gtk::manage (new Gtk::Label (M("GENERAL_NA") + " in x " + M("GENERAL_NA") + " in")); - dpibox->pack_start (*sizecm, Gtk::PACK_SHRINK, 1); - dpibox->pack_start (*sizein, Gtk::PACK_SHRINK, 1); + sizebox->pack_start (*sizecm, Gtk::PACK_SHRINK, 4); + sizebox->pack_start (*Gtk::manage (new Gtk::VSeparator()), Gtk::PACK_SHRINK, 6); + sizebox->pack_start (*sizein, Gtk::PACK_SHRINK, 4); + sizebox->pack_start (*Gtk::manage (new Gtk::VSeparator()), Gtk::PACK_SHRINK, 6); + sizebox->pack_start (*hb4, Gtk::PACK_SHRINK, 2); - pack_start (*dpibox, Gtk::PACK_SHRINK, 0); + ppibox->pack_start (*sizebox, Gtk::PACK_SHRINK, 1); + pack_start (*ppibox, Gtk::PACK_SHRINK, 0); - dpi->set_value (300); + ppi->set_value (300); + // ppibox END ratio->append_text ("3:2"); ratio->append_text ("4:3"); @@ -169,10 +175,10 @@ Crop::Crop (): Gtk::VBox(), FoldableToolPanel(this) { h->set_increments (1,100); h->set_value (200); - dpi->set_digits (0); - dpi->set_increments (1,100); - dpi->set_range (50, 12000); - dpi->set_value (300); + ppi->set_digits (0); + ppi->set_increments (1,100); + ppi->set_range (50, 12000); + ppi->set_value (300); xconn = x->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::positionChanged), true); yconn = y->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::positionChanged), true); @@ -184,7 +190,7 @@ Crop::Crop (): Gtk::VBox(), FoldableToolPanel(this) { oconn = orientation->signal_changed().connect( sigc::mem_fun(*this, &Crop::ratioChanged) ); gconn = guide->signal_changed().connect( sigc::mem_fun(*this, &Crop::notifyListener) ); selectCrop->signal_pressed().connect( sigc::mem_fun(*this, &Crop::selectPressed) ); - dpi->signal_value_changed().connect( sigc::mem_fun(*this, &Crop::refreshSize) ); + ppi->signal_value_changed().connect( sigc::mem_fun(*this, &Crop::refreshSize) ); nx = ny = nw = nh = 0; lastRotationDeg = 0; @@ -193,14 +199,14 @@ Crop::Crop (): Gtk::VBox(), FoldableToolPanel(this) { void Crop::writeOptions () { - options.cropDPI = (int)dpi->get_value (); + options.cropPPI = (int)ppi->get_value (); } void Crop::readOptions () { disableListener (); - dpi->set_value (options.cropDPI); + ppi->set_value (options.cropPPI); enableListener (); } @@ -554,15 +560,15 @@ void Crop::refreshSize () { std::ostringstream ostrin; ostrin.precision (3); - // ostrin << h->get_value()/dpi->get_value() << " in x " << w->get_value()/dpi->get_value() << " in";; - ostrin << nh/dpi->get_value() << " in x " << nw/dpi->get_value() << " in";; + // ostrin << h->get_value()/ppi->get_value() << " in x " << w->get_value()/ppi->get_value() << " in";; + ostrin << nh/ppi->get_value() << " in x " << nw/ppi->get_value() << " in";; sizein->set_text (ostrin.str ()); std::ostringstream ostrcm; ostrcm.precision (3); - // ostrcm << h->get_value()/dpi->get_value()*2.54 << " cm x " << w->get_value()/dpi->get_value()*2.54 << " cm";; - ostrcm << nh/dpi->get_value()*2.54 << " cm x " << nw/dpi->get_value()*2.54 << " cm";; + // ostrcm << h->get_value()/ppi->get_value()*2.54 << " cm x " << w->get_value()/ppi->get_value()*2.54 << " cm";; + ostrcm << nh/ppi->get_value()*2.54 << " cm x " << nw/ppi->get_value()*2.54 << " cm";; sizecm->set_text (ostrcm.str ()); } @@ -946,5 +952,5 @@ void Crop::setBatchMode (bool batchMode) { ratio->append_text ("(Unchanged)"); orientation->append_text ("(Unchanged)"); guide->append_text ("(Unchanged)"); - removeIfThere (this, dpibox); + removeIfThere (this, ppibox); } diff --git a/rtgui/crop.h b/rtgui/crop.h index 62a36095d..ce3f5727d 100644 --- a/rtgui/crop.h +++ b/rtgui/crop.h @@ -45,10 +45,11 @@ class Crop : public Gtk::VBox, public CropGUIListener, public FoldableToolPanel, Gtk::SpinButton* y; Gtk::SpinButton* w; Gtk::SpinButton* h; - Gtk::SpinButton* dpi; + Gtk::SpinButton* ppi; Gtk::Label* sizecm; Gtk::Label* sizein; - Gtk::VBox* dpibox; + Gtk::VBox* ppibox; + Gtk::HBox* sizebox; int maxw, maxh; int nx, ny, nw, nh; int lastRotationDeg; diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index b6220b796..51f998763 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -19,12 +19,19 @@ #include #undef THREAD_PRIORITY_NORMAL +#include + using namespace rtengine; CropHandler::CropHandler () : zoom(10), cx(0), cy(0), cw(0), ch(0), cropX(0), cropY(0), cropW(0), cropH(0), enabled(false), - cropimg(NULL), ipc(NULL), crop(NULL), listener(NULL) { + cropimg(NULL), cropimgtrue(NULL), ipc(NULL), crop(NULL), listener(NULL) { + + chi = new CropHandlerIdleHelper; + chi->destroyed = false; + chi->pending = 0; + chi->cropHandler = this; } CropHandler::~CropHandler () { @@ -35,6 +42,12 @@ CropHandler::~CropHandler () { setEnabled (false); if (crop) crop->destroy (); + cimg.lock (); + if (chi->pending) + chi->destroyed = true; + else + delete chi; + cimg.unlock (); } void CropHandler::newImage (StagedImageProcessor* ipc_) { @@ -53,7 +66,13 @@ void CropHandler::newImage (StagedImageProcessor* ipc_) { } void CropHandler::sizeChanged (int x, int y, int ow, int oh) { // the ipc notifies it to keep track size changes like rotation + compDim (); + +// this should be put into an idle source!!! +/* if (listener) + listener->cropWindowChanged (); + */ } double CropHandler::getFitZoom () { @@ -63,12 +82,12 @@ double CropHandler::getFitZoom () { double z2 = (double) ww / ipc->getFullWidth (); return z1=1000) { cw = ww * 1000 / zoom; ch = wh * 1000 / zoom; @@ -136,66 +154,112 @@ void CropHandler::getPosition (int& x, int& y) { y = cropY; } -void CropHandler::setDetailedCrop (IImage8* im, rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) { - cimg.lock (); +int createpixbufs (void* data) { - cropPixbuf.clear (); - if (cropimg) delete [] cropimg; - cropimg = NULL; + gdk_threads_enter (); - if (!enabled) { - cimg.unlock (); - return; - } + CropHandlerIdleHelper* chi = (CropHandlerIdleHelper*) data; + if (chi->destroyed) { + if (chi->pending == 1) + delete chi; + else + chi->pending--; + gdk_threads_leave (); + return 0; + } + + CropHandler* ch = chi->cropHandler; + + ch->cimg.lock (); + ch->cropPixbuf.clear (); + + if (!ch->enabled) { + delete [] ch->cropimg; + ch->cropimg = NULL; + delete [] ch->cropimgtrue; + ch->cropimgtrue = NULL; + ch->cimg.unlock (); + gdk_threads_leave (); + return 0; + } + + if (ch->cropimg) { + if (ch->cix==ch->cropX && ch->ciy==ch->cropY && ch->ciw==ch->cropW && ch->cih==ch->cropH && ch->cis==(ch->zoom>=1000?1:ch->zoom)) { + // calculate final image size + int czoom = ch->zoom<1000 ? 1000 : ch->zoom; + int imw = ch->cropimg_width * czoom / 1000; + int imh = ch->cropimg_height * czoom / 1000; + if (imw>ch->ww) + imw = ch->ww; + if (imh>ch->wh) + imh = ch->wh; + + Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width); + ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST); + tmpPixbuf.clear (); + + Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width); + ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST); + tmpPixbuftrue.clear (); + } + delete [] ch->cropimg; + ch->cropimg = NULL; + delete [] ch->cropimgtrue; + ch->cropimgtrue = NULL; + } + ch->cimg.unlock (); + if (ch->listener) { + ch->listener->cropImageUpdated (); + if (ch->initial) { + ch->listener->initialImageArrived (); + ch->initial = false; + } + } + + chi->pending--; + + gdk_threads_leave (); + return 0; +} + +void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procparams::ColorManagementParams cmp, \ + rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) { + + if (!enabled) + return; + + cimg.lock (); cropParams = cp; - + colorParams = cmp; + + cropPixbuf.clear (); + if (cropimg) + delete [] cropimg; + cropimg = NULL; + if (cropimgtrue) + delete [] cropimgtrue; + cropimgtrue = NULL; + if (ax==cropX && ay==cropY && aw==cropW && ah==cropH && askip==(zoom>=1000?1:zoom)) { cropimg_width = im->getWidth (); cropimg_height = im->getHeight (); cropimg = new unsigned char [3*cropimg_width*cropimg_height]; + cropimgtrue = new unsigned char [3*cropimg_width*cropimg_height]; memcpy (cropimg, im->getData(), 3*cropimg_width*cropimg_height); + memcpy (cropimgtrue, imtrue->getData(), 3*cropimg_width*cropimg_height); cix = ax; ciy = ay; ciw = aw; cih = ah; cis = askip; - - // Create the piece of preview image that will be integrally copied in the preview area - if (cix==cropX && ciy==cropY && ciw==cropW && cih==cropH && cis==(zoom>=1000?1:zoom)) { - // calculate final image size - int czoom = zoom<1000 ? 1000 : zoom; - int imw = cropimg_width * czoom / 1000; - int imh = cropimg_height * czoom / 1000; - if (imw>ww) - imw = ww; - if (imh>wh) - imh = wh; - - // Create a temporary pixbuf to copy the piece of the full size image - Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (cropimg, Gdk::COLORSPACE_RGB, false, 8, cropimg_width, cropimg_height, 3*cropimg_width); - // Create the real preview image - cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); - // Rescale the piece of the full size image and put it in the preview image - tmpPixbuf->scale (cropPixbuf, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST); - // Delete the temporary pixbuf - tmpPixbuf.clear (); - } - delete [] cropimg; - cropimg = NULL; - - cimg.unlock (); - - if (listener) { - listener->cropImageUpdated (); - if (initial) { - listener->initialImageArrived (); // sets zoomToFit, so it should be the right size image! - initial = false; - } - } - } else cimg.unlock (); - + chi->pending++; + g_idle_add (createpixbufs, chi); + } + cimg.unlock (); } bool CropHandler::getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip) { @@ -205,13 +269,12 @@ bool CropHandler::getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip) cww = cropW; cwh = cropH; - /* // hack: if called before first size allocation the size will be 0 if (cww<10) cww = 10; if (cwh<32) cwh = 32; - */ + cskip = zoom>=1000 ? 1 : zoom; return true; @@ -243,6 +306,8 @@ void CropHandler::setEnabled (bool e) { cimg.lock (); delete [] cropimg; cropimg = NULL; + delete [] cropimgtrue; + cropimgtrue = NULL; cropPixbuf.clear (); cimg.unlock (); } diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index d95a15d37..bd97dc14f 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -30,6 +30,12 @@ class CropHandlerListener { virtual void initialImageArrived () {} }; +class CropHandler; +struct CropHandlerIdleHelper { + CropHandler* cropHandler; + bool destroyed; + int pending; +}; class CropHandler : public rtengine::DetailedCropListener, public rtengine::SizeListener { @@ -42,21 +48,28 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size int cropX, cropY, cropW, cropH; // position and size of the crop corresponding to cropPixbuf bool enabled; unsigned char* cropimg; + unsigned char* cropimgtrue; int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; bool initial; - bool isLowUpdatePriority; + bool isLowUpdatePriority; rtengine::StagedImageProcessor* ipc; rtengine::DetailedCrop* crop; CropHandlerListener* listener; + CropHandlerIdleHelper* chi; void compDim (); + public: - void update (); + + void update (); rtengine::procparams::CropParams cropParams; + rtengine::procparams::ColorManagementParams colorParams; Glib::RefPtr cropPixbuf; + Glib::RefPtr cropPixbuftrue; + Glib::Mutex cimg; CropHandler (); @@ -76,10 +89,9 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size void setEnabled (bool e); bool getEnabled (); - void setIsLowUpdatePriority(bool p) { isLowUpdatePriority=p; } - // DetailedCropListener interface - void setDetailedCrop (rtengine::IImage8* im, rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip); + void setDetailedCrop (rtengine::IImage8* im, rtengine::IImage8* imworking,rtengine::procparams::ColorManagementParams cmp, \ + rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip); bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip); // SizeListener interface void sizeChanged (int w, int h, int ow, int oh); diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index f50fd3d65..c0b9bb51c 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -464,15 +464,33 @@ void CropWindow::pointerMoved (int x, int y) { int mx, my; translateCoord (x, y, mx, my); if (!onArea (CropImage, x, y) || !cropHandler.cropPixbuf) - pmlistener->pointerMoved (false, mx, my, -1, -1, -1); + // pmlistener->pointerMoved (false, mx, my, -1, -1, -1); + pmlistener->pointerMoved (false, cropHandler.colorParams.working, mx, my, -1, -1, -1); + else { - Glib::Mutex::Lock lock(cropHandler.cimg); + /*Glib::Mutex::Lock lock(cropHandler.cimg); int vx = x - xpos - imgX; int vy = y - ypos - imgY; guint8* pix = cropHandler.cropPixbuf->get_pixels() + vy*cropHandler.cropPixbuf->get_rowstride() + vx*3; if (vx < cropHandler.cropPixbuf->get_width() && vy < cropHandler.cropPixbuf->get_height()) pmlistener->pointerMoved (true, mx, my, pix[0], pix[1], pix[2]); + + */ + cropHandler.cimg.lock (); + int vx = x - xpos - imgX; + int vy = y - ypos - imgY; +// guint8* pix = cropHandler.cropPixbuf->get_pixels() + vy*cropHandler.cropPixbuf->get_rowstride() + vx*3; +// if (vx < cropHandler.cropPixbuf->get_width() && vy < cropHandler.cropPixbuf->get_height()) +// pmlistener->pointerMoved (true, mx, my, pix[0], pix[1], pix[2]); + int imwidth = cropHandler.cropPixbuf->get_width(); + int imheight = cropHandler.cropPixbuf->get_height(); + guint8* pix = cropHandler.cropPixbuftrue->get_pixels() + vy*cropHandler.cropPixbuf->get_rowstride() + vx*3; + if (vx < imwidth && vy < imheight) + pmlistener->pointerMoved (true, cropHandler.colorParams.working, mx, my, pix[0], pix[1], pix[2]); + + cropHandler.cimg.unlock (); + } } } @@ -655,22 +673,67 @@ void CropWindow::expose (Cairo::RefPtr cr) { if (showcs || showch) { Glib::RefPtr tmp = cropHandler.cropPixbuf->copy (); guint8* pix = tmp->get_pixels(); + guint8* pixWrkSpace = cropHandler.cropPixbuftrue->get_pixels(); + + int pixRowStride = tmp->get_rowstride (); + int pixWSRowStride = cropHandler.cropPixbuftrue->get_rowstride (); + + const float ShawdowFac = 64 / (options.shadowThreshold+1); + const float HighlightFac = 64 / (256-options.highlightThreshold); #ifdef _OPENMP #pragma omp for #endif - for (int i=0; iget_height(); i++) - for (int j=0; jget_width(); j++) { - guint8* curr = pix + i*tmp->get_rowstride () + j*3; - /*if (showch && (curr[0]>=options.highlightThreshold || curr[1]>=options.highlightThreshold || curr[2]>=options.highlightThreshold)) - curr[0] = curr[1] = curr[2] = 0; - else if (showcs && (curr[0]<=options.shadowThreshold || curr[1]<=options.shadowThreshold || curr[2]<=options.shadowThreshold)) - curr[0] = curr[1] = curr[2] = 255;*/ - if (showch && ((0.299*curr[0]+0.587*curr[1]+0.114*curr[2])>=options.highlightThreshold)) - curr[0] = curr[1] = curr[2] = 0; - else if (showcs && ((0.299*curr[0]+0.587*curr[1]+0.114*curr[2])<=options.shadowThreshold)) - curr[0] = curr[1] = curr[2] = 255; + for (int i=0; iget_height(); i++) { + guint8* curr = pix + i*pixRowStride; + guint8* currWS = pixWrkSpace + i*pixWSRowStride; + + int delta; bool changed; + + for (int j=0; jget_width(); j++) { + // we must compare clippings in working space, since the cropPixbuf is in sRGB, with mon profile + + if (showch) { + delta=0; changed=false; + + if (currWS[0]>=options.highlightThreshold) { delta += 255-currWS[0]; changed=true; } + if (currWS[1]>=options.highlightThreshold) { delta += 255-currWS[1]; changed=true; } + if (currWS[2]>=options.highlightThreshold) { delta += 255-currWS[2]; changed=true; } + + if (changed) { + delta *= HighlightFac; + curr[0]=delta; curr[1]=delta; curr[2]=delta; + } + } + if (showcs) { + delta=0; changed=false; + + if (currWS[0]<=options.shadowThreshold) { delta += currWS[0]; changed=true; } + if (currWS[1]<=options.shadowThreshold) { delta += currWS[1]; changed=true; } + if (currWS[2]<=options.shadowThreshold) { delta += currWS[2]; changed=true; } + + + if (changed) { + delta = 255 - (delta * ShawdowFac); + curr[0]=delta; curr[1]=delta; curr[2]=delta; + } + } + + /* + if (showch && (currWS[0]>=options.highlightThreshold || currWS[1]>=options.highlightThreshold || currWS[2]>=options.highlightThreshold)) + curr[0] = curr[1] = curr[2] = 0; + else if (showcs && (currWS[0]<=options.shadowThreshold || currWS[1]<=options.shadowThreshold || currWS[2]<=options.shadowThreshold)) + curr[0] = curr[1] = curr[2] = 255; + //if (showch && ((0.299*curr[0]+0.587*curr[1]+0.114*curr[2])>=options.highlightThreshold)) + // curr[0] = curr[1] = curr[2] = 0; + //else if (showcs && ((0.299*curr[0]+0.587*curr[1]+0.114*curr[2])<=options.shadowThreshold)) + // curr[0] = curr[1] = curr[2] = 255; + */ + + curr+=3; currWS+=3; } + } + iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), tmp, 0, 0, x+imgX, y+imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); } else diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 20097acc0..7f7fc92e9 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -22,6 +22,9 @@ #include #include #include +#include + +#include extern Glib::ustring argv0; @@ -91,7 +94,7 @@ CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEd bgHistValid = false; selected = DCT_Linear; - histogram = new unsigned int[256]; // histogram values + histogram(256); // histogram values group = ceGroup; subGroup = ceSubGroup; @@ -107,11 +110,6 @@ CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEd typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) ); } -CurveEditor::~CurveEditor () { - - delete [] histogram; -} - void CurveEditor::setCurve (const std::vector& p) { tempCurve = p; group->setCurveExternal(this, p); @@ -136,15 +134,15 @@ void CurveEditor::setUnChanged (bool uc) { /* * Update the backgrounds histograms */ -void CurveEditor::updateBackgroundHistogram (unsigned int* hist) { +void CurveEditor::updateBackgroundHistogram (LUTu & hist) { // Copy the histogram in the curve editor cache - if (hist!=NULL) { - memcpy (histogram, hist, 256*sizeof(unsigned int)); + if (hist) { + histogram=hist; bgHistValid = true; } else bgHistValid = false; - + // Then call the curve editor group to eventually update the histogram subGroup->updateBackgroundHistogram (this); } diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index 854ea2171..01f38b609 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -20,6 +20,7 @@ #define _CURVEEDITOR_ #include +#include class CurveEditorGroup; class CurveEditorSubGroup; @@ -32,7 +33,7 @@ class CurveEditorSubGroup; /* * This class is an interface between RT and the curve editor group ; it handles the methods - * related to a specific curve. It is created by CurveEditorGroup::addCurve + * related to a specific curve. It is created by CurveEditorGroup::addCurve */ class CurveEditor { @@ -51,7 +52,7 @@ class CurveEditor { */ PopUpToggleButton* curveType; - unsigned int* histogram; // histogram values + LUTu histogram; // histogram values bool bgHistValid; int selected; @@ -65,12 +66,12 @@ class CurveEditor { public: CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); - ~CurveEditor (); + void typeSelectionChanged (int n); void curveTypeToggled(); bool isUnChanged (); void setUnChanged (bool uc); - void updateBackgroundHistogram (unsigned int* hist); + void updateBackgroundHistogram (LUTu & hist); void setCurve (const std::vector& p); virtual std::vector getCurve () = 0; }; @@ -98,7 +99,7 @@ class DiagonalCurveEditor : public CurveEditor { /* - ********************** Flat Curve Editor ********************** + ********************** Flat Curve Editor ********************** */ diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index 497243bf8..fba51ff25 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ +#include #include #include #include @@ -53,17 +54,32 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt) saveCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); loadCustom = Gtk::manage (new Gtk::Button ()); loadCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + pasteCustom = Gtk::manage (new Gtk::Button ()); + pasteCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-paste"), Gtk::ICON_SIZE_BUTTON))); + copyCustom = Gtk::manage (new Gtk::Button ()); + copyCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-copy"), Gtk::ICON_SIZE_BUTTON))); + custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0); custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_end (*pasteCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_end (*copyCustom, Gtk::PACK_SHRINK, 0); + customCurveBox->pack_end (*custombbox, Gtk::PACK_SHRINK, 0); customCurveBox->show_all (); saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + pasteCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + copyCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + pasteCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + // Custom curve end + // NURBS curve NURBSCurveBox = new Gtk::HBox (); @@ -71,6 +87,7 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt) NURBSCurve = Gtk::manage (new MyDiagonalCurve ()); NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); NURBSCurve->setType (DCT_NURBS); + //customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED")); NURBSCurveBox->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0); @@ -80,32 +97,79 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt) saveNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); loadNURBS = Gtk::manage (new Gtk::Button ()); loadNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + pasteNURBS = Gtk::manage (new Gtk::Button ()); + pasteNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-paste"), Gtk::ICON_SIZE_BUTTON))); + copyNURBS = Gtk::manage (new Gtk::Button ()); + copyNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-copy"), Gtk::ICON_SIZE_BUTTON))); NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0); NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_end (*pasteNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_end (*copyNURBS, Gtk::PACK_SHRINK, 0); NURBSCurveBox->pack_end (*NURBSbbox, Gtk::PACK_SHRINK, 0); NURBSCurveBox->show_all (); saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + copyNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + pasteNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + copyNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + // NURBS curve end + // parametric curve paramCurveBox = new Gtk::VBox (); paramCurveBox->set_spacing(4); + paramInnerBox = new Gtk::HBox (); + paramInnerBox->set_spacing(4); + paramCurve = Gtk::manage (new MyDiagonalCurve ()); Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1)); paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); paramCurve->setType (DCT_Parametric); + shcSelector = Gtk::manage (new SHCSelector ()); shcSelector->set_size_request (GRAPH_SIZE, 20); paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 0, 0); paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS, 0); - paramCurveBox->pack_start (*paramctab, Gtk::PACK_EXPAND_WIDGET, 0); + paramInnerBox->pack_start (*paramctab, Gtk::PACK_EXPAND_WIDGET, 0); + + Gtk::VBox* Parambbox = Gtk::manage (new Gtk::VBox ()); + Parambbox->set_spacing(4); + saveParam = Gtk::manage (new Gtk::Button ()); + saveParam->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + loadParam = Gtk::manage (new Gtk::Button ()); + loadParam->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + pasteParam = Gtk::manage (new Gtk::Button ()); + pasteParam->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-paste"), Gtk::ICON_SIZE_BUTTON))); + copyParam = Gtk::manage (new Gtk::Button ()); + copyParam->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-copy"), Gtk::ICON_SIZE_BUTTON))); + + Parambbox->pack_end (*saveParam, Gtk::PACK_SHRINK, 0); + Parambbox->pack_end (*loadParam, Gtk::PACK_SHRINK, 0); + Parambbox->pack_end (*pasteParam, Gtk::PACK_SHRINK, 0); + Parambbox->pack_end (*copyParam, Gtk::PACK_SHRINK, 0); + + saveParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); + loadParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + pasteParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + copyParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + + saveParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + pasteParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + copyParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + + paramInnerBox->pack_start (*Parambbox, Gtk::PACK_EXPAND_WIDGET, 0); + + paramCurveBox->pack_start (*paramInnerBox, Gtk::PACK_SHRINK, 0); highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0)); lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0)); @@ -127,7 +191,11 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt) paramCurveBox->pack_start (*evlights); paramCurveBox->pack_start (*evdarks); paramCurveBox->pack_start (*evshadows); + paramCurveBox->show_all (); + // parametric curve end + + customCurveBox->reference (); paramCurveBox->reference (); @@ -160,6 +228,7 @@ DiagonalCurveEditorSubGroup::~DiagonalCurveEditorSubGroup() { delete customCurveBox; delete paramCurveBox; delete NURBSCurveBox; + delete paramInnerBox; } /* @@ -238,12 +307,15 @@ void DiagonalCurveEditorSubGroup::savePressed () { //std::vector p = customCurve->getPoints (); switch (parent->displayedCurve->selected) { - case DCT_Spline: // custom + case DCT_Spline: // custom p = customCurve->getPoints (); break; case DCT_NURBS: // NURBS p = NURBSCurve->getPoints (); break; + case DCT_Parametric: + p = paramCurve->getPoints (); + break; default: break; } @@ -255,9 +327,19 @@ void DiagonalCurveEditorSubGroup::savePressed () { f << "Spline\n"; else if (p[ix]==(double)(DCT_NURBS)) f << "NURBS\n"; - ix++; - for (unsigned int i=0; i> x; @@ -294,10 +379,94 @@ void DiagonalCurveEditorSubGroup::loadPressed () { NURBSCurve->queue_draw (); NURBSCurve->notifyListener (); } + else if (p[0] == (double)(DCT_Parametric)) { + shcSelector->setPositions ( + p[1], + p[2], + p[3] ); + highlights->setValue (p[4]); + lights->setValue (p[5]); + darks->setValue (p[6]); + shadows->setValue (p[7]); + paramCurve->setPoints (p); + paramCurve->queue_draw (); + paramCurve->notifyListener (); + } } } } +void DiagonalCurveEditorSubGroup::copyPressed () { +// For compatibility use enum DiagonalCurveType here + + std::vector curve; + + switch (parent->displayedCurve->selected) { + case DCT_Spline: // custom + curve = customCurve->getPoints (); + clipboard.setCurveData (curve,DCT_Spline); + break; + case DCT_Parametric: // parametric + // ... do something, first add save/load functions + curve = paramCurve->getPoints (); + clipboard.setCurveData (curve,DCT_Parametric); + break; + case DCT_NURBS: // NURBS + curve = NURBSCurve->getPoints (); + clipboard.setCurveData (curve,DCT_NURBS); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::pastePressed () { +// For compatibility use enum DiagonalCurveType here + + std::vector curve; + DiagonalCurveType type; + + type = clipboard.hasCurveData(); + + if (type == (DiagonalCurveType)parent->displayedCurve->selected) { + curve = clipboard.getCurveData (); + switch (type) { + case DCT_Linear: // linear + break; + case DCT_Spline: // custom + customCurve->setPoints (curve); + customCurve->queue_draw (); + customCurve->notifyListener (); + break; + case DCT_Parametric: // parametric + // ... do something, first add save/load functions + shcSelector->setPositions ( + curve[1], + curve[2], + curve[3] ); + highlights->setValue (curve[4]); + lights->setValue (curve[5]); + darks->setValue (curve[6]); + shadows->setValue (curve[7]); + paramCurve->setPoints (curve); + paramCurve->queue_draw (); + paramCurve->notifyListener (); + break; + case DCT_NURBS: // NURBS + NURBSCurve->setPoints (curve); + NURBSCurve->queue_draw (); + NURBSCurve->notifyListener (); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + } + return; +} + + /* * Store the curves of the currently displayed type from the widgets to the CurveEditor object */ @@ -323,12 +492,12 @@ void DiagonalCurveEditorSubGroup::storeDisplayedCurve() { * Restore the histogram to all types from the CurveEditor object to the widgets */ void DiagonalCurveEditorSubGroup::restoreDisplayedHistogram() { - if (parent->displayedCurve) { - paramCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL); - customCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL); - NURBSCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL); + if (parent->displayedCurve /*&& initslope==1*/) { + paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + customCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + NURBSCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); } - + } void DiagonalCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { @@ -465,9 +634,9 @@ bool DiagonalCurveEditorSubGroup::adjusterLeft (GdkEventCrossing* ev, int ac) { } void DiagonalCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { - if (ce==parent->displayedCurve) { - paramCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); - customCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); - NURBSCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); + if (ce==parent->displayedCurve /*&& initslope==1*/) { + paramCurve->updateBackgroundHistogram (ce->histogram); + customCurve->updateBackgroundHistogram (ce->histogram); + NURBSCurve->updateBackgroundHistogram (ce->histogram); } } diff --git a/rtgui/diagonalcurveeditorsubgroup.h b/rtgui/diagonalcurveeditorsubgroup.h index 4edfce825..49d8d8fc0 100644 --- a/rtgui/diagonalcurveeditorsubgroup.h +++ b/rtgui/diagonalcurveeditorsubgroup.h @@ -31,6 +31,7 @@ class DiagonalCurveEditorSubGroup : public CurveEditorSubGroup, public SHCListen protected: Gtk::HBox* customCurveBox; Gtk::VBox* paramCurveBox; + Gtk::HBox* paramInnerBox; Gtk::HBox* NURBSCurveBox; MyDiagonalCurve* customCurve; @@ -45,8 +46,16 @@ protected: Gtk::Button* saveCustom; Gtk::Button* loadCustom; + Gtk::Button* copyCustom; + Gtk::Button* pasteCustom; Gtk::Button* saveNURBS; Gtk::Button* loadNURBS; + Gtk::Button* copyNURBS; + Gtk::Button* pasteNURBS; + Gtk::Button* saveParam; + Gtk::Button* loadParam; + Gtk::Button* copyParam; + Gtk::Button* pasteParam; int activeParamControl; @@ -64,6 +73,8 @@ protected: void restoreDisplayedHistogram (); void savePressed (); void loadPressed (); + void copyPressed (); + void pastePressed (); void switchGUI(); bool curveReset (int cType); void removeEditor (); diff --git a/rtgui/dirbrowser.cc b/rtgui/dirbrowser.cc index 6b24dbdbf..464c358de 100644 --- a/rtgui/dirbrowser.cc +++ b/rtgui/dirbrowser.cc @@ -24,6 +24,8 @@ #include #include +#include + #define CHECKTIME 5000 extern Glib::ustring argv0; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index e01dbfafe..e5494ee76 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -289,6 +289,7 @@ EditorPanel::~EditorPanel () { iarea->setBeforeAfterViews (NULL, iarea); delete iarea; iarea = NULL; + if (beforeIpc) beforeIpc->stopProcessing (); @@ -297,11 +298,15 @@ EditorPanel::~EditorPanel () { if (beforeIpc) beforeIpc->setPreviewImageListener (NULL); + if (beforeIpc) + beforeIpc->setPreviewImageListener (NULL); + delete beforePreviewHandler; beforePreviewHandler = NULL; if (beforeIpc) rtengine::StagedImageProcessor::destroy (beforeIpc); beforeIpc = NULL; + close (); if (epih->pending) @@ -1288,10 +1293,11 @@ void EditorPanel::beforeAfterToggled () { } } -void EditorPanel::histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh, unsigned int* bcrgb, unsigned int* bcl) { +void EditorPanel::histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, + LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) { - histogramPanel->histogramChanged (rh, gh, bh, lh); - tpc->updateCurveBackgroundHistogram (bcrgb, bcl); + histogramPanel->histogramChanged (histRed, histGreen, histBlue, histLuma, histRedRaw, histGreenRaw, histBlueRaw); + tpc->updateCurveBackgroundHistogram (histToneCurve, histLCurve); } bool EditorPanel::CheckSidePanelsVisibility(){ diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 8eeeba0eb..ada625ca0 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -149,7 +149,8 @@ class EditorPanel : public Gtk::VBox, void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params); // HistogramListener - void histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh, unsigned int* bcrgb, unsigned int* bcl); + void histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, + LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); // event handlers void info_toggled (); diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 27ba33f72..8ff6a2801 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -23,6 +23,8 @@ #include #include +#include + #define CROPRESIZEBORDER 4 bool FileBrowserEntry::iconsLoaded = false; @@ -210,8 +212,16 @@ void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine: redrawRequests--; scale = s; this->cropParams = cropParams; + + bool newLandscape = img->getWidth() > img->getHeight(); + bool rotated=false; + if (preh == img->getHeight ()) { prew = img->getWidth (); + + // Check if image has been rotated since last time + rotated = preview!=NULL && newLandscape!=landscape; + guint8* temp = preview; preview = NULL; delete [] temp; @@ -220,9 +230,17 @@ void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine: preview = temp; updateBackBuffer (); } - if (redrawRequests==0 && parent) - parent->redrawNeeded (this); + + landscape = newLandscape; + img->free (); + + if (parent!=NULL) { + if (rotated) + parent->thumbRearrangementNeeded(); + else if (redrawRequests==0) + parent->redrawNeeded (this); + } } bool FileBrowserEntry::motionNotify (int x, int y) { diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index 490e0d100..349e98bf2 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -48,6 +48,7 @@ class FileBrowserEntry : public ThumbBrowserEntryBase, ImageAreaToolListener* iatlistener; int press_x, press_y, action_x, action_y; double rot_deg; + bool landscape; rtengine::procparams::CropParams cropParams; CropGUIListener* cropgl; FileBrowserEntryIdleHelper* feih; diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index ea4c4209d..c491f584a 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -194,8 +194,8 @@ void FlatCurveEditorSubGroup::storeDisplayedCurve() { */ void FlatCurveEditorSubGroup::restoreDisplayedHistogram() { if (parent->displayedCurve) { - //paramCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL); - CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL); + //paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); } } diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 3c240d5bc..a1fddcafd 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -19,6 +19,8 @@ #include #include #include +#include + HistogramPanel::HistogramPanel () { @@ -27,16 +29,19 @@ HistogramPanel::HistogramPanel () { showGreen = Gtk::manage (new Gtk::ToggleButton (M("HISTOGRAM_BUTTON_G"))); showBlue = Gtk::manage (new Gtk::ToggleButton (M("HISTOGRAM_BUTTON_B"))); showValue = Gtk::manage (new Gtk::ToggleButton (M("HISTOGRAM_BUTTON_L"))); + showRAW = Gtk::manage (new Gtk::ToggleButton (M("HISTOGRAM_BUTTON_RAW"))); Gtk::VBox* vbox = Gtk::manage (new Gtk::VBox (false, 0)); showRed->set_active (true); showGreen->set_active (true); showBlue->set_active (true); showValue->set_active (true); + showRAW->set_active (false); vbox->pack_start (*showRed, Gtk::PACK_SHRINK, 2); vbox->pack_start (*showGreen, Gtk::PACK_SHRINK, 2); vbox->pack_start (*showBlue, Gtk::PACK_SHRINK, 2); vbox->pack_start (*showValue, Gtk::PACK_SHRINK, 2); + vbox->pack_end (*showRAW, Gtk::PACK_SHRINK, 2); pack_start (*histogramArea); pack_end (*vbox, Gtk::PACK_SHRINK, 2); @@ -44,6 +49,7 @@ HistogramPanel::HistogramPanel () { showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); + showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); show_all (); @@ -51,6 +57,7 @@ HistogramPanel::HistogramPanel () { showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); + showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); } @@ -70,17 +77,12 @@ void HistogramPanel::resized (Gtk::Allocation& req) { void HistogramPanel::rgbv_toggled () { - histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active()); + histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showRAW->get_active()); histogramArea->queue_draw (); } HistogramArea::HistogramArea () : - valid(false), showFull(true), oldwidth(-1), needVal(true), needRed(true), needGreen(true), needBlue(true) { - - lhist = new unsigned int[256]; - rhist = new unsigned int[256]; - ghist = new unsigned int[256]; - bhist = new unsigned int[256]; + valid(false), showFull(true), oldwidth(-1), needLuma(true), needRed(true), needGreen(true), needBlue(true), rawMode(false) { haih = new HistogramAreaIdleHelper; haih->harea = this; @@ -97,18 +99,15 @@ HistogramArea::~HistogramArea () { else delete haih; - delete [] lhist; - delete [] rhist; - delete [] ghist; - delete [] bhist; } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool v) { +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool raw) { needRed = r; needGreen = g; needBlue = b; - needVal = v; + needLuma = l; + rawMode = raw; renderHistogram (); } @@ -136,18 +135,18 @@ int histupdate (void* data) { return 0; } -void HistogramArea::update (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh) { +void HistogramArea::update (LUTu &histRed, LUTu &histGreen, LUTu &histBlue, LUTu &histLuma, LUTu &histRedRaw, LUTu &histGreenRaw, LUTu &histBlueRaw) { + + if (histRed) { + lhist=histLuma; + rhist=histRed; ghist=histGreen; bhist=histBlue; + rhistRaw=histRedRaw; ghistRaw=histGreenRaw; bhistRaw=histBlueRaw; - if (rh!=NULL) { - memcpy (lhist, lh, 256*sizeof(unsigned int)); - memcpy (rhist, rh, 256*sizeof(unsigned int)); - memcpy (ghist, gh, 256*sizeof(unsigned int)); - memcpy (bhist, bh, 256*sizeof(unsigned int)); valid = true; } else valid = false; - + haih->pending++; g_idle_add (histupdate, haih); } @@ -169,6 +168,10 @@ void HistogramArea::renderHistogram () { backBuffer->draw_rectangle (bgc, true, 0, 0, winw, winh); if (valid) { + // For RAW mode use the other hists + LUTu& rh = rawMode ? rhistRaw : rhist; + LUTu& gh = rawMode ? ghistRaw : ghist; + LUTu& bh = rawMode ? bhistRaw : bhist; // compute height of the full histogram (realheight) and // does not take into account 0 and 255 values @@ -176,14 +179,14 @@ void HistogramArea::renderHistogram () { int fullhistheight = 0; for (int i=1; i<255; i++) { - if (needVal && lhist[i]>fullhistheight) + if (needLuma && lhist[i]>fullhistheight) fullhistheight = lhist[i]; - if (needRed && rhist[i]>fullhistheight) - fullhistheight = rhist[i]; - if (needGreen && ghist[i]>fullhistheight) - fullhistheight = ghist[i]; - if (needBlue && bhist[i]>fullhistheight) - fullhistheight = bhist[i]; + if (needRed && (rawMode?rhistRaw:rhist)[i]>fullhistheight) + fullhistheight = rh[i]; + if (needGreen && (rawMode?ghistRaw:ghist)[i]>fullhistheight) + fullhistheight = gh[i]; + if (needBlue && (rawMode?bhistRaw:bhist)[i]>fullhistheight) + fullhistheight = bh[i]; } int realhistheight = fullhistheight; @@ -194,7 +197,7 @@ void HistogramArea::renderHistogram () { int area = 0; for (int i=0; ii) || (needRed && rhist[j]>i) || (needGreen && ghist[j]>i) || (needBlue && bhist[j]>i)) + if ((needLuma && !rawMode && lhist[j]>i) || (needRed && rh[j]>i) || (needGreen && gh[j]>i) || (needBlue && bh[j]>i)) area++; if (area1thres==0 && (double)area / (256*(i+1)) < 0.3) area1thres = i; @@ -216,7 +219,7 @@ void HistogramArea::renderHistogram () { int ui = 0, oi = 0; - if (needVal) { + if (needLuma && !rawMode) { drawCurve(cr, lhist, realhistheight, winw, winh); cr->set_source_rgb (0.75, 0.75, 0.75); cr->fill_preserve (); @@ -226,162 +229,28 @@ void HistogramArea::renderHistogram () { drawMarks(cr, lhist, realhistheight, winw, ui, oi); } if (needRed) { - drawCurve(cr, rhist, realhistheight, winw, winh); + drawCurve(cr, rh, realhistheight, winw, winh); cr->set_source_rgb (1.0, 0.0, 0.0); cr->stroke (); - drawMarks(cr, rhist, realhistheight, winw, ui, oi); + drawMarks(cr, rh, realhistheight, winw, ui, oi); } if (needGreen) { - drawCurve(cr, ghist, realhistheight, winw, winh); + drawCurve(cr, gh, realhistheight, winw, winh); cr->set_source_rgb (0.0, 1.0, 0.0); cr->stroke (); - drawMarks(cr, ghist, realhistheight, winw, ui, oi); + drawMarks(cr, gh, realhistheight, winw, ui, oi); } if (needBlue) { - drawCurve(cr, bhist, realhistheight, winw, winh); + drawCurve(cr, bh, realhistheight, winw, winh); cr->set_source_rgb (0.0, 0.0, 1.0); cr->stroke (); - drawMarks(cr, bhist, realhistheight, winw, ui, oi); + drawMarks(cr, bh, realhistheight, winw, ui, oi); } } -/* - - // scale histogram to width winw-1 - - int* vval = new int[winw-1]; - int* vred = new int[winw-1]; - int* vgreen = new int[winw-1]; - int* vblue = new int[winw-1]; - - memset (vval, 0, sizeof(int)*(winw-1)); - memset (vred, 0, sizeof(int)*(winw-1)); - memset (vgreen, 0, sizeof(int)*(winw-1)); - memset (vblue, 0, sizeof(int)*(winw-1)); - - int index = 0; - double scale = 256.0 / (winw-2); - for (int i=0; i<=winw-2; i++) { - int samples = 0; - while (index < 256 && (int)(index/scale) == i) { - vval[i] += lhist[index]; - vred[i] += rhist[index]; - vgreen[i] += ghist[index]; - vblue[i] += bhist[index]; - index++; - samples++; - } - if (samples>0) { - vval[i] /= samples; - vred[i] /= samples; - vgreen[i] /= samples; - vblue[i] /= samples; - } - } - - // compute height of the full histogram (realheight) and - - int fullhistheight = 0; - for (int i=0; i<=winw-2; i++) { - if (needVal && vval[i]>fullhistheight) - fullhistheight = vval[i]; - if (needRed && vred[i]>fullhistheight) - fullhistheight = vred[i]; - if (needGreen && vgreen[i]>fullhistheight) - fullhistheight = vgreen[i]; - if (needBlue && vblue[i]>fullhistheight) - fullhistheight = vblue[i]; - } - - // compute two hights, one for the magnified view and one for the threshold - - int realhistheight = fullhistheight; - - if (!showFull) { - int area1thres = 0; - int area2thres = 0; - int area = 0; - for (int i=0; ii) || (needRed && vred[j]>i) || (needGreen && vgreen[j]>i) || (needBlue && vblue[j]>i)) - area++; - if (area1thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3) - area1thres = i; - if (area2thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3) - area2thres = i; - if (area1thres && area2thres) - break; - } - if (area1thres>0 && area2thres>0 && area1thres cr = backBuffer->create_cairo_context(); - cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - cr->set_line_width (1.0); - if (needVal) { - cr->move_to (0, winh-1); - cr->set_source_rgb (0.75, 0.75, 0.75); - for (int i=0; i<=winw-2; i++) { - int val = (int)(vval[i] * (double)(winh-2) / realhistheight); - if (val>winh-1) - val = winh-1; - if (i>0) - cr->line_to (i+1, winh-1-val); - } - cr->fill_preserve (); - cr->set_source_rgb (0.5, 0.5, 0.5); - cr->stroke (); - } - if (needRed) { - cr->move_to (0, winh-1); - cr->set_source_rgb (1.0, 0.0, 0.0); - for (int i=0; i<=winw-2; i++) { - int val = (int)(vred[i] * (double)(winh-2) / realhistheight); - if (val>winh-1) - val = winh-1; - if (i>0) - cr->line_to (i+1, winh-1-val); - } - cr->stroke (); - } - if (needGreen) { - cr->move_to (0, winh-1); - cr->set_source_rgb (0.0, 1.0, 0.0); - for (int i=0; i<=winw-2; i++) { - int val = (int)(vgreen[i] * (double)(winh-2) / realhistheight); - if (val>winh-1) - val = winh-1; - if (i>0) - cr->line_to (i+1, winh-1-val); - } - cr->stroke (); - } - if (needBlue) { - cr->move_to (0, winh-1); - cr->set_source_rgb (0.0, 0.0, 1.0); - for (int i=0; i<=winw-2; i++) { - int val = (int)(vblue[i] * (double)(winh-2) / realhistheight); - if (val>winh-1) - val = winh-1; - if (i>0) - cr->line_to (i+1, winh-1-val); - } - cr->stroke (); - } - - delete [] vval; - delete [] vred; - delete [] vgreen; - delete [] vblue; - } -*/ bgc->set_foreground (mgray); backBuffer->draw_rectangle (bgc, false, 0, 0, winw-1, winh-1); @@ -427,7 +296,7 @@ void HistogramArea::on_realize () { } void HistogramArea::drawCurve(Cairo::RefPtr &cr, - unsigned int * data, double scale, int hsize, int vsize) + LUTu & data, double scale, int hsize, int vsize) { cr->move_to (0, vsize-1); for (int i = 0; i < 256; i++) { @@ -440,7 +309,7 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, } void HistogramArea::drawMarks(Cairo::RefPtr &cr, - unsigned int * data, double scale, int hsize, int & ui, int & oi) + LUTu & data, double scale, int hsize, int & ui, int & oi) { int s = 8; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 43d96928f..523b20175 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -21,6 +21,7 @@ #include #include +#include class HistogramArea; struct HistogramAreaIdleHelper { @@ -44,18 +45,14 @@ class HistogramArea : public Gtk::DrawingArea { Gdk::Color lgray; Gdk::Color mgray; Gdk::Color dgray; - unsigned int* lhist; - unsigned int* rhist; - unsigned int* ghist; - unsigned int* bhist; + LUTu lhist, rhist, ghist, bhist; + LUTu lhistRaw, rhistRaw, ghistRaw, bhistRaw; + bool valid; bool showFull; int oldwidth, oldheight; - bool needVal; - bool needRed; - bool needGreen; - bool needBlue; + bool needLuma, needRed, needGreen, needBlue, rawMode; HistogramAreaIdleHelper* haih; @@ -65,17 +62,17 @@ class HistogramArea : public Gtk::DrawingArea { ~HistogramArea(); void renderHistogram (); - void update (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh); - void updateOptions (bool r, bool g, bool b, bool v); + void update (LUTu &histRed, LUTu &histGreen, LUTu &histBlue, LUTu &histLuma, LUTu &histRedRaw, LUTu &histGreenRaw, LUTu &histBlueRaw); + void updateOptions (bool r, bool g, bool b, bool l, bool raw); void on_realize(); bool on_expose_event(GdkEventExpose* event); bool on_button_press_event (GdkEventButton* event); void styleChanged (const Glib::RefPtr& style); private: void drawCurve(Cairo::RefPtr &cr, - unsigned int * data, double scale, int hsize, int vsize); + LUTu & data, double scale, int hsize, int vsize); void drawMarks(Cairo::RefPtr &cr, - unsigned int * data, double scale, int hsize, int & ui, int & oi); + LUTu & data, double scale, int hsize, int & ui, int & oi); }; class HistogramPanel : public Gtk::HBox { @@ -87,6 +84,7 @@ class HistogramPanel : public Gtk::HBox { Gtk::ToggleButton* showGreen; Gtk::ToggleButton* showBlue; Gtk::ToggleButton* showValue; + Gtk::ToggleButton* showRAW; sigc::connection rconn; @@ -94,7 +92,9 @@ class HistogramPanel : public Gtk::HBox { HistogramPanel (); - void histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh) { histogramArea->update (rh, gh, bh, lh); } + void histogramChanged (LUTu &histRed, LUTu &histGreen, LUTu &histBlue, LUTu &histLuma, LUTu &histRedRaw, LUTu &histGreenRaw, LUTu &histBlueRaw) { + histogramArea->update (histRed, histGreen, histBlue, histLuma, histRedRaw, histGreenRaw, histBlueRaw); + } void rgbv_toggled (); void resized (Gtk::Allocation& req); }; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 88492be57..dbeea3b4c 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -31,7 +31,6 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), // set_border_width (4); ipDialog = Gtk::manage (new Gtk::FileChooserButton (M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - opDialog = Gtk::manage (new Gtk::FileChooserButton (M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); Gtk::Label* ilab = Gtk::manage (new Gtk::Label ()); ilab->set_alignment (0.0, 0.5); @@ -93,6 +92,22 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), std::vector wpnames = rtengine::getWorkingProfiles (); for (int i=0; iappend_text (wpnames[i]); + + Gtk::HSeparator* hsep22 = Gtk::manage (new Gtk::HSeparator ()); + pack_start (*hsep22, Gtk::PACK_SHRINK, 2); + + Gtk::Label* galab = Gtk::manage (new Gtk::Label ()); + galab->set_alignment (0.0, 0.5); + //galab->set_markup (Glib::ustring("") + M("TP_GAMMA_OUTPUT") + "" +M("TP_GAMMA_COMMENT")); + galab->set_markup (Glib::ustring("") + M("TP_GAMMA_OUTPUT") + ""); + + pack_start (*galab, Gtk::PACK_SHRINK, 4); + wgamma = Gtk::manage (new Gtk::ComboBoxText ()); + pack_start (*wgamma, Gtk::PACK_SHRINK, 4); + + std::vector wpgamma = rtengine::getGamma (); + for (int i=0; iappend_text (wpgamma[i]); onames->append_text (M("TP_ICM_NOICM")); onames->set_active (0); @@ -103,6 +118,7 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), wnames->set_active (0); onames->set_active (0); + wgamma->set_active (0); Gtk::FileFilter filter_icc; filter_icc.set_name(M("TP_ICM_FILEDLGFILTERICM")); @@ -116,18 +132,17 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), ipDialog->add_filter (filter_icc); ipDialog->add_filter (filter_any); - opDialog->add_filter (filter_icc); - opDialog->add_filter (filter_any); if (safe_file_test (options.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) { ipDialog->set_current_folder (options.rtSettings.iccDirectory); - opDialog->set_current_folder (options.rtSettings.iccDirectory); } oldip = ""; wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) ); onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) ); + wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); + icamera->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); iembedded->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); ifromfile->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); @@ -161,7 +176,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { igamma->set_sensitive (true); } - wnames->set_active_text (pp->icm.working); + wnames->set_active_text (pp->icm.working); + wgamma->set_active_text (pp->icm.gamma); + if (pp->icm.output=="No ICM: sRGB output") onames->set_active_text (M("TP_ICM_NOICM")); else @@ -171,7 +188,8 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { onames->set_active_text (M("TP_ICM_NOICM")); igamma->set_active (pp->icm.gammaOnInput); - + onames->set_sensitive(wgamma->get_active_row_number()==0); //"default" + //thanks to Michael if (pedited) { iunchanged->set_active (!pedited->icm.input); igamma->set_sensitive (false); @@ -179,6 +197,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { wnames->set_active_text(M("GENERAL_UNCHANGED")); if (!pedited->icm.output) onames->set_active_text(M("GENERAL_UNCHANGED")); + if (!pedited->icm.gamma) + wgamma->set_active_text(M("GENERAL_UNCHANGED")); + } ipc.block (false); @@ -198,18 +219,21 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { pp->icm.input = "file:"+ipDialog->get_filename (); pp->icm.working = wnames->get_active_text (); - + pp->icm.gamma = wgamma->get_active_text (); + if (onames->get_active_text()==M("TP_ICM_NOICM")) pp->icm.output = "No ICM: sRGB output"; else pp->icm.output = onames->get_active_text(); pp->icm.gammaOnInput = igamma->get_active (); - + if (pedited) { pedited->icm.input = !iunchanged->get_active (); pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.gammaOnInput = !ifromfile->get_active (); + pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED"); + } } @@ -218,6 +242,14 @@ void ICMPanel::wpChanged () { if (listener) listener->panelChanged (EvWProfile, wnames->get_active_text ()); } +void ICMPanel::gpChanged () { + + if (listener) + {listener->panelChanged (EvGAMMA, wgamma->get_active_text ()); + onames->set_sensitive(wgamma->get_active_row_number()==0); //"default"//thanks to Michael + } + +} void ICMPanel::ipChanged () { @@ -301,5 +333,7 @@ void ICMPanel::setBatchMode (bool batchMode) { removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); wnames->append_text (M("GENERAL_UNCHANGED")); + wgamma->append_text (M("GENERAL_UNCHANGED")); + } diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index c83c55cf6..30c500aa9 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -37,12 +37,13 @@ class ICMPanel : public Gtk::VBox, public FoldableToolPanel { Gtk::RadioButton* ifromfile; Gtk::CheckButton* igamma; Gtk::ComboBoxText* wnames; + Gtk::ComboBoxText* wgamma; + Gtk::ComboBoxText* onames; Gtk::RadioButton* ofromdir; Gtk::RadioButton* ofromfile; Gtk::RadioButton* iunchanged; Gtk::FileChooserButton* ipDialog; - Gtk::FileChooserButton* opDialog; Gtk::RadioButton::Group opts; Gtk::Button* saveRef; sigc::connection ipc; @@ -59,6 +60,7 @@ class ICMPanel : public Gtk::VBox, public FoldableToolPanel { void wpChanged (); void opChanged (); void ipChanged (); + void gpChanged (); void ipSelectionChanged (); diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index cc847decc..8c01999c3 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -359,7 +359,7 @@ void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) { } -void LCurve::updateCurveBackgroundHistogram (unsigned* hist) { +void LCurve::updateCurveBackgroundHistogram (LUTu & hist) { lshape->updateBackgroundHistogram (hist); } diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index 68efe3c7a..a223eb38d 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -65,7 +65,7 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPan void adjusterChanged (Adjuster* a, double newval); void avoidclip_toggled (); void enablelimiter_toggled (); - void updateCurveBackgroundHistogram (unsigned* hist); + void updateCurveBackgroundHistogram (LUTu & hist); virtual void colorForValue (double valX, double valY); }; diff --git a/rtgui/mycurve.h b/rtgui/mycurve.h index be70f59c7..5649b46a9 100644 --- a/rtgui/mycurve.h +++ b/rtgui/mycurve.h @@ -24,6 +24,7 @@ #include #include #include +#include #define RADIUS 3 /* radius of the control points */ #define SQUARE 2 /* half length of the square shape of the tangent handles */ @@ -96,7 +97,7 @@ class MyCurve : public Gtk::DrawingArea { void setCurveListener (CurveListener* cl) { listener = cl; } void setColorProvider (ColorProvider* cp) { colorProvider = cp; } void notifyListener (); - void updateBackgroundHistogram (unsigned int* hist) {return;} ; + void updateBackgroundHistogram (LUTu & hist) {return;} ; void forceResize() { sized = RS_Force; } virtual std::vector getPoints () = 0; virtual void setPoints (const std::vector& p) = 0; diff --git a/rtgui/mydiagonalcurve.cc b/rtgui/mydiagonalcurve.cc index 1b4042e6c..8843958b5 100644 --- a/rtgui/mydiagonalcurve.cc +++ b/rtgui/mydiagonalcurve.cc @@ -719,10 +719,12 @@ int diagonalmchistupdate (void* data) { return 0; } -void MyDiagonalCurve::updateBackgroundHistogram (unsigned int* hist) { - +void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) { + if (hist!=NULL) { - memcpy (bghist, hist, 256*sizeof(unsigned int)); + //memcpy (bghist, hist, 256*sizeof(unsigned int)); + for (int i=0; i<256; i++) bghist[i]=hist[i]; + //hist = bghist; bghistvalid = true; } else diff --git a/rtgui/mydiagonalcurve.h b/rtgui/mydiagonalcurve.h index 9aee97358..c130d37c5 100644 --- a/rtgui/mydiagonalcurve.h +++ b/rtgui/mydiagonalcurve.h @@ -24,6 +24,8 @@ #include #include #include +#include + // For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget enum DiagonalCurveType { @@ -76,7 +78,7 @@ class MyDiagonalCurve : public MyCurve { bool handleEvents (GdkEvent* event); void setActiveParam (int ac); void reset (); - void updateBackgroundHistogram (unsigned int* hist); + void updateBackgroundHistogram (LUTu & hist); }; #endif diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc index 8de4a3e5a..bf86eb2df 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -18,6 +18,11 @@ */ #include #include +#include // from rtengine +#include + +#define D50x 0.96422 +#define D50z 0.82521 Navigator::Navigator () { @@ -71,7 +76,8 @@ void Navigator::setInvalid () { LAB_L->set_text (M("NAVIGATOR_LAB_L_NA")); } -void Navigator::pointerMoved (bool validPos, int x, int y, int r, int g, int b) { + +void Navigator::pointerMoved (bool validPos, Glib::ustring profile, int x, int y, int r, int g, int b) { if (!validPos) setInvalid (); @@ -86,7 +92,9 @@ void Navigator::pointerMoved (bool validPos, int x, int y, int r, int g, int b) S->set_text (Glib::ustring::compose (M("NAVIGATOR_S_VALUE"), s)); V->set_text (Glib::ustring::compose (M("NAVIGATOR_V_VALUE"), v)); int LAB_a, LAB_b, LAB_l; - rgb2lab (r, g, b, LAB_l, LAB_a, LAB_b); + //rgb2lab (r, g, b, LAB_l, LAB_a, LAB_b); + rgb2lab (profile, r, g, b, LAB_l, LAB_a, LAB_b); + LAB_A->set_text (Glib::ustring::compose (M("NAVIGATOR_LAB_A_VALUE"), LAB_a)); LAB_B->set_text (Glib::ustring::compose (M("NAVIGATOR_LAB_B_VALUE"), LAB_b)); LAB_L->set_text (Glib::ustring::compose (M("NAVIGATOR_LAB_L_VALUE"), LAB_l)); @@ -150,12 +158,22 @@ void Navigator::rgb2hsv (int r, int g, int b, int &h, int &s, int &v) { v = (int)(V*255.0); } -void Navigator::rgb2lab (int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b) { +void Navigator::rgb2lab (Glib::ustring profile, int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b) { + + double xyz_rgb[3][3]; + double ep=216.0/24389.0; + double ka=24389.0/27.0; volatile double var_R = r / 255.0; volatile double var_G = g / 255.0; volatile double var_B = b / 255.0; + if (profile=="sRGB") {//apply sRGB inverse gamma + + // +// if you want display = working space +// today as the gamma output can not be configured +// it is better that the user has the gamma of the output space if ( var_R > 0.04045 ) var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), 2.4); else @@ -168,30 +186,47 @@ void Navigator::rgb2lab (int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), 2.4); else var_B = var_B / 12.92; - - var_R = var_R * 100; - var_G = var_G * 100; - var_B = var_B * 100; - - double var_X = ( var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805 ) / 95.047; - double var_Y = ( var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 ) / 100.000; - double var_Z = ( var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505 ) / 108.883; - - if ( var_X > 0.008856 ) - var_X = pow (var_X, ( 1.0/3.0 )); - else - var_X = ( 7.787 * var_X ) + ( 16.0 / 116.0 ); - if ( var_Y > 0.008856 ) - var_Y = pow (var_Y, ( 1.0/3.0 )); + } +// if you want display = output space else - var_Y = ( 7.787 * var_Y ) + ( 16.0 / 116.0 ); - if ( var_Z > 0.008856 ) - var_Z = pow (var_Z, ( 1.0/3.0 )); - else - var_Z = ( 7.787 * var_Z ) + ( 16.0 / 116.0 ); + if (profile=="ProPhoto") {// apply inverse gamma 1.8 + var_R = pow ( var_R, 1.8); + var_G = pow ( var_G, 1.8); + var_B = pow ( var_B, 1.8); + } + else {// apply inverse gamma 2.2 + var_R = pow ( var_R, 2.2); + var_G = pow ( var_G, 2.2); + var_B = pow ( var_B, 2.2); + } - LAB_l = ( 116 * var_Y ) - 16; - LAB_a = 500 * ( var_X - var_Y ); - LAB_b = 200 * ( var_Y - var_Z ); + /*for (int i=0; iworkingSpaceMatrix (profile); + + for (int m=0; m<3; m++) + for (int n=0; n<3; n++) { + xyz_rgb[m][n] = wprof[m][n]; + } + + double varxx,varyy,varzz; + double var_X = ( xyz_rgb[0][0]*var_R + xyz_rgb[0][1]*var_G + xyz_rgb[0][2]*var_B ) / D50x; + double var_Y = ( xyz_rgb[1][0]*var_R + xyz_rgb[1][1]*var_G + xyz_rgb[1][2]*var_B ) ; + double var_Z = ( xyz_rgb[2][0]*var_R + xyz_rgb[2][1]*var_G + xyz_rgb[2][2]*var_B ) / D50z; + + varxx = var_X>ep?pow (var_X, 1.0/3.0):( ka * var_X + 16.0) / 116.0 ; + varyy = var_Y>ep?pow (var_Y, 1.0/3.0):( ka * var_Y + 16.0) / 116.0 ; + varzz = var_Z>ep?pow (var_Z, 1.0/3.0):( ka * var_Z + 16.0) / 116.0 ; + LAB_l = ( 116 * varyy ) - 16; + LAB_a = 500 * ( varxx - varyy ); + LAB_b = 200 * ( varyy - varzz ); } diff --git a/rtgui/navigator.h b/rtgui/navigator.h index 0c94c31db..cfe7321b4 100644 --- a/rtgui/navigator.h +++ b/rtgui/navigator.h @@ -22,9 +22,12 @@ #include #include #include +#include class Navigator : public Gtk::Frame, public PointerMotionListener { + typedef const double (*TMatrix)[3]; + protected: Gtk::Label* position; Gtk::Label *R, *G, *B; @@ -32,7 +35,9 @@ class Navigator : public Gtk::Frame, public PointerMotionListener { Gtk::Label *LAB_A, *LAB_B, *LAB_L; void rgb2hsv (int r, int g, int b, int &h, int &s, int &v); - void rgb2lab (int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b); + //void rgb2lab (int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b); + void rgb2lab (Glib::ustring profile, int r, int g, int b, int &LAB_l, int &LAB_a, int &LAB_b); + void setInvalid (); public: PreviewWindow* previewWindow; @@ -40,7 +45,8 @@ class Navigator : public Gtk::Frame, public PointerMotionListener { Navigator (); // pointermotionlistener interface - void pointerMoved (bool validPos, int x, int y, int r, int g, int b); + // void pointerMoved (bool validPos, int x, int y, int r, int g, int b); + void pointerMoved (bool validPos, Glib::ustring profile, int x, int y, int r, int g, int b); }; diff --git a/rtgui/options.cc b/rtgui/options.cc index 1a6675f4f..12a9cad46 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -84,7 +84,7 @@ void Options::setDefaults () { showHistory = true; showFilePanelState = 0; showInfo = false; - cropDPI = 300; + cropPPI = 300; showClippedHighlights = false; showClippedShadows = false; highlightThreshold = 254; @@ -151,6 +151,14 @@ void Options::setDefaults () { rtSettings.colorimetricIntent = 1; rtSettings.monitorProfile = ""; rtSettings.autoMonitorProfile = false; + rtSettings.LCMSSafeMode = true; + rtSettings.adobe = "AdobeRGB1998"; + rtSettings.prophoto = "ProPhoto"; + rtSettings.widegamut = "WideGamutRGB"; + rtSettings.srgb = "sRGB Color Space Profile"; + rtSettings.bruce = "Bruce"; + rtSettings.beta = "BetaRGB"; + rtSettings.best = "BestRGB"; rtSettings.verbose = false; } @@ -303,7 +311,7 @@ if (keyFile.has_group ("GUI")) { if (keyFile.has_group ("Crop Settings")) { - if (keyFile.has_key ("Crop Settings", "DPI")) cropDPI = keyFile.get_integer ("Crop Settings", "DPI"); + if (keyFile.has_key ("Crop Settings", "PPI")) cropPPI = keyFile.get_integer ("Crop Settings", "PPI"); } if (keyFile.has_group ("Color Management")) { @@ -312,6 +320,9 @@ if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "AutoMonitorProfile")) rtSettings.autoMonitorProfile = keyFile.get_boolean ("Color Management", "AutoMonitorProfile"); if (keyFile.has_key ("Color Management", "Intent")) rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); + + // Disabled (default is true) till issues are sorted out + //if (keyFile.has_key ("Color Management", "LCMSSafeMode")) rtSettings.LCMSSafeMode = keyFile.get_boolean ("Color Management", "LCMSSafeMode"); } if (keyFile.has_group ("Batch Processing")) { @@ -447,12 +458,20 @@ int Options::saveToFile (Glib::ustring fname) { //Glib::ArrayHandle crvopen = crvOpen; //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); - keyFile.set_integer ("Crop Settings", "DPI", cropDPI); + keyFile.set_integer ("Crop Settings", "PPI", cropPPI); keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); keyFile.set_string ("Color Management", "MonitorProfile", rtSettings.monitorProfile); keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + keyFile.set_boolean ("Color Management", "LCMSSafeMode", rtSettings.LCMSSafeMode); + keyFile.set_string ("Color Management", "Adobe_RGB", rtSettings.adobe); + keyFile.set_string ("Color Management", "Pro_Photo", rtSettings.prophoto); + keyFile.set_string ("Color Management", "Wide_Gamut", rtSettings.widegamut); + keyFile.set_string ("Color Management", "S_rgb", rtSettings.srgb); + keyFile.set_string ("Color Management", "B_eta", rtSettings.beta); + keyFile.set_string ("Color Management", "B_est", rtSettings.best); + keyFile.set_string ("Color Management", "B_ruce", rtSettings.bruce); Glib::ArrayHandle bab = baBehav; keyFile.set_integer_list ("Batch Processing", "AdjusterBehavior", bab); diff --git a/rtgui/options.h b/rtgui/options.h index 4c384312e..976c82d0f 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -92,7 +92,7 @@ class Options { int showFilePanelState; // 0: normal, 1: maximized, 2: normal, 3: hidden bool showInfo; bool mainNBVertical; // main notebook vertical tabs? - int cropDPI; + int cropPPI; bool showClippedHighlights; bool showClippedShadows; int highlightThreshold; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 18e6c0d8d..7fc9701db 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -250,6 +250,7 @@ class ColorManagementParamsEdited { bool gammaOnInput; bool working; bool output; + bool gamma; }; class EqualizerParamsEdited { diff --git a/rtgui/pointermotionlistener.h b/rtgui/pointermotionlistener.h index ff2ed0b19..321b73723 100644 --- a/rtgui/pointermotionlistener.h +++ b/rtgui/pointermotionlistener.h @@ -22,7 +22,8 @@ class PointerMotionListener { public: - virtual void pointerMoved (bool validPos, int x, int y, int r, int g, int b) {} +// virtual void pointerMoved (bool validPos, int x, int y, int r, int g, int b) {} + virtual void pointerMoved (bool validPos, Glib::ustring profile, int x, int y, int r, int g, int b) {} }; #endif diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index fbbb3322f..6a4d827f0 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -69,12 +69,10 @@ void RAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* ped void RAWExposure::adjusterChanged (Adjuster* a, double newval) { if (listener) { - Glib::ustring value = a->getTextValue(); - - if (a == PexPos) + if (a == PexPos) listener->panelChanged (EvPreProcessExpCorrLinear, value ); - else if (a == PexPreser) + else if (a == PexPreser && ABS(PexPos->getValue()-1.0)>0.0001) // update takes long, only do it if it would have an effect listener->panelChanged (EvPreProcessExpCorrPH, value ); } } diff --git a/rtgui/thumbbrowserentry.cc b/rtgui/thumbbrowserentry.cc index 988d588f8..7703e9775 100644 --- a/rtgui/thumbbrowserentry.cc +++ b/rtgui/thumbbrowserentry.cc @@ -27,11 +27,6 @@ FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) exifline = thumbnail->getExifString (); } -void ThumbBrowserEntry::obtainThumbnailImage () { - - preview = thumbnail ? (guint8*) thumbnail->getThumbnailImage (prew, preh) : NULL; -} - void ThumbBrowserEntry::obtainThumbnailSize () { if (thumbnail) diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index 06552a774..4e8b94e79 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -40,7 +40,7 @@ protected: int sideMargin; int lowerMargin; - guint8* preview; + guint8* preview; // holds the preview image. used in updateBackBuffer. TODO Olli: Make a cache to reduce mem significantly Glib::ustring dispname; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 86f5d922c..0df11aad6 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -75,7 +75,6 @@ void Thumbnail::_generateThumbnailImage () { th = options.maxThumbnailHeight; // generate thumbnail image - Glib::ustring ext = getExtension (fname); if (ext=="") return; @@ -83,8 +82,6 @@ void Thumbnail::_generateThumbnailImage () { cfs.exifValid = false; cfs.timeValid = false; - delete tpp; - tpp = NULL; if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff") { tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1); if (tpp) { @@ -112,7 +109,7 @@ void Thumbnail::_generateThumbnailImage () { quick = true; tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1, TRUE); } - if ( tpp == 0 ) + if ( tpp == NULL ) { quick = false; tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, TRUE); @@ -123,16 +120,17 @@ void Thumbnail::_generateThumbnailImage () { infoFromImage (fname, &ri); } } - if (tpp ) + + if (tpp) { - _saveThumbnail (); - cfs.supported = true; - } - needsReProcessing = true; + _saveThumbnail (); + cfs.supported = true; + needsReProcessing = true; - cfs.save (getCacheFileName ("data")+".txt"); + cfs.save (getCacheFileName ("data")+".txt"); - generateExifDateTimeStrings (); + generateExifDateTimeStrings (); + } } bool Thumbnail::isSupported () { @@ -463,6 +461,8 @@ void Thumbnail::_loadThumbnail(bool firstTrial) { _generateThumbnailImage (); if (cfs.supported && firstTrial) _loadThumbnail (false); + + if (tpp==NULL) return; } else if (!succ) { delete tpp; diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 8bebb3a9b..8cd9db8da 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -127,6 +127,7 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { hlcompr->setValue (pp->toneCurve.hlcompr); hlcomprthresh->setValue (pp->toneCurve.hlcomprthresh); shcompr->setValue (pp->toneCurve.shcompr); + if (!blackAdd) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect brightness->setValue (pp->toneCurve.brightness); contrast->setValue (pp->toneCurve.contrast); saturation->setValue (pp->toneCurve.saturation); @@ -224,8 +225,10 @@ void ToneCurve::adjusterChanged (Adjuster* a, double newval) { listener->panelChanged (EvExpComp, costr); else if (a==brightness) listener->panelChanged (EvBrightness, costr); - else if (a==black) + else if (a==black){ listener->panelChanged (EvBlack, costr); + if (!blackAdd) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + } else if (a==contrast) listener->panelChanged (EvContrast, costr); else if (a==saturation) @@ -256,6 +259,7 @@ void ToneCurve::autolevels_toggled () { if (!batchMode && autolevels->get_active() && listener) { listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); waitForAutoExp (); + if (!blackAdd) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect } if (batchMode) { @@ -337,6 +341,7 @@ bool ToneCurve::autoExpComputed_ () { enableAll (); expcomp->setValue (nextBr); black->setValue (nextBl); + if (!blackAdd) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect enableListener (); return false; @@ -393,7 +398,7 @@ void ToneCurve::setAdjusterBehavior (bool expadd, bool hlcompadd, bool hlcompthr satAdd = satadd; } -void ToneCurve::updateCurveBackgroundHistogram (unsigned* hist) { +void ToneCurve::updateCurveBackgroundHistogram (LUTu & hist) { shape->updateBackgroundHistogram (hist); } diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 5c79b295c..2b5303f81 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -69,7 +69,7 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public FoldableTool void curveChanged (); void expandCurve (bool isExpanded); bool isCurveExpanded (); - void updateCurveBackgroundHistogram (unsigned* hist); + void updateCurveBackgroundHistogram (LUTu & hist); }; #endif diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index b017bb4aa..eb425083b 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -36,7 +36,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { rawPanel = Gtk::manage (new Gtk::VBox ()); coarse = Gtk::manage (new CoarsePanel ()); - curve = Gtk::manage (new ToneCurve ()); + toneCurve = Gtk::manage (new ToneCurve ()); shadowshighlights = Gtk::manage (new ShadowsHighlights ()); lumadenoise = Gtk::manage (new LumaDenoise ()); colordenoise = Gtk::manage (new ColorDenoise ()); @@ -72,7 +72,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { rawexposure = Gtk::manage (new RAWExposure ()); addPanel (colorPanel, whitebalance, M("TP_WBALANCE_LABEL")); toolPanels.push_back (whitebalance); - addPanel (exposurePanel, curve, M("TP_EXPOSURE_LABEL")); toolPanels.push_back (curve); + addPanel (exposurePanel, toneCurve, M("TP_EXPOSURE_LABEL")); toolPanels.push_back (toneCurve); addPanel (exposurePanel, hlrecovery, M("TP_HLREC_LABEL")); toolPanels.push_back (hlrecovery); addPanel (colorPanel, chmixer, M("TP_CHMIXER_LABEL")); toolPanels.push_back (chmixer); addPanel (exposurePanel, shadowshighlights, M("TP_SHADOWSHLIGHTS_LABEL")); toolPanels.push_back (shadowshighlights); @@ -295,16 +295,15 @@ CropGUIListener* ToolPanelCoordinator::getCropGUIListener () { void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool raw) { ipc = ipc_; - curve->disableListener (); - curve->enableAll (); - curve->enableListener (); - + toneCurve->disableListener (); + toneCurve->enableAll (); + toneCurve->enableListener (); exifpanel->setImageData (ipc->getInitialImage()->getMetaData()); iptcpanel->setImageData (ipc->getInitialImage()->getMetaData()); if (ipc) { - ipc->setAutoExpListener (curve); + ipc->setAutoExpListener (toneCurve); ipc->setSizeListener (crop); ipc->setSizeListener (resize); } @@ -329,9 +328,6 @@ void ToolPanelCoordinator::readOptions () { for (int i=0; iset_expanded (options.tpOpen[i]); - - //if (options.crvOpen.size()>1) - // curve->expandCurve (options.crvOpen[0]); } void ToolPanelCoordinator::writeOptions () { @@ -340,9 +336,6 @@ void ToolPanelCoordinator::writeOptions () { options.tpOpen.clear (); for (int i=0; iget_expanded ()); - - //options.crvOpen.clear (); - //options.crvOpen.push_back (curve->isCurveExpanded()); } @@ -470,10 +463,10 @@ int ToolPanelCoordinator::getSpotWBRectSize () { return whitebalance->getSize (); } -void ToolPanelCoordinator::updateCurveBackgroundHistogram (unsigned* histrgb, unsigned* histl) { +void ToolPanelCoordinator::updateCurveBackgroundHistogram (LUTu &histToneCurve, LUTu &histLCurve) { - curve->updateCurveBackgroundHistogram (histrgb); - lcurve->updateCurveBackgroundHistogram (histl); + toneCurve->updateCurveBackgroundHistogram (histToneCurve); + lcurve->updateCurveBackgroundHistogram (histLCurve); } void ToolPanelCoordinator::foldAllButOne (Gtk::Box* parent, FoldableToolPanel* openedSection) { diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 694f3ea7b..2dadd358b 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -93,7 +93,7 @@ class ToolPanelCoordinator : public ToolPanelListener, Resize* resize; ICMPanel* icm; Crop* crop; - ToneCurve* curve; + ToneCurve* toneCurve; ShadowsHighlights* shadowshighlights; LumaDenoise* lumadenoise; ColorDenoise* colordenoise; @@ -149,7 +149,7 @@ class ToolPanelCoordinator : public ToolPanelListener, ~ToolPanelCoordinator (); bool getChangedState () { return hasChanged; } - void updateCurveBackgroundHistogram (unsigned* histrgb, unsigned* histl); + void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurves); void foldAllButOne (Gtk::Box* parent, FoldableToolPanel* openedSection); // multiple listeners can be added that are notified on changes (typical: profile panel and the history)