From 6410f0579935b1a4075f617871c6d7da5d9c3a77 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 18 Nov 2017 23:45:30 +0100 Subject: [PATCH 01/18] Integrated the RCD demosaic method by Luis Sanz Rodriguez Original code at https://github.com/LuisSR/RCD-Demosaicing --- rtdata/languages/default | 1 + rtengine/demosaic_algos.cc | 280 +++++++++++++++++++++++++++++++++++++ rtengine/procparams.cc | 2 +- rtengine/procparams.h | 2 +- rtengine/rawimagesource.cc | 2 + rtengine/rawimagesource.h | 1 + 6 files changed, 286 insertions(+), 2 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 8320a351b..ba9a11466 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1788,6 +1788,7 @@ TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions between areas with motion and TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE;StdDev factor Blue TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN;StdDev factor Green TP_RAW_PIXELSHIFTSTDDEVFACTORRED;StdDev factor Red +TP_RAW_RCD;RCD TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster. TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index 88d369969..61258fca2 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -3927,6 +3927,286 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b } } + +/** +* RATIO CORRECTED DEMOSAICING +* Luis Sanz Rodriguez (luis.sanz.rodriguez(at)gmail(dot)com) +* +* Release 2.2 @ 171117 +*/ +void RawImageSource::rcd_demosaic() +{ + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgressStr(Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), "rcd")); + plistener->setProgress(0); + } + + int width = W, height = H; + + std::vector cfa(width * height); + std::vector> rgb(width * height); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int row = 0; row < height; row++) { + for (int col = 0, indx = row * width + col; col < width; col++, indx++) { + int c = FC(row, col); + cfa[indx] = rgb[indx][c] = CLIP(rawData[row][col]) / 65535.f; + } + } + + if (plistener) { + plistener->setProgress(0.05); + } + // ------------------------------------------------------------------------ +/* RT + int row, col, indx, c; +*/ + int w1 = width, w2 = 2 * width, w3 = 3 * width, w4 = 4 * width; + + //Tolerance to avoid dividing by zero + static const float eps = 1e-5, epssq = 1e-10; + +/* RT + //Gradients + float N_Grad, E_Grad, W_Grad, S_Grad, NW_Grad, NE_Grad, SW_Grad, SE_Grad; + + //Pixel estimation + float N_Est, E_Est, W_Est, S_Est, NW_Est, NE_Est, SW_Est, SE_Est, V_Est, H_Est, P_Est, Q_Est; + + //Directional discrimination + //float V_Stat, H_Stat, P_Stat, Q_Stat; + float VH_Central_Value, VH_Neighbour_Value, PQ_Central_Value, PQ_Neighbour_Value; +*/ + float ( *VH_Dir ), ( *VH_Disc ), ( *PQ_Dir ), ( *PQ_Disc ); + + //Low pass filter + float ( *lpf ); + + + /** + * STEP 1: Find cardinal and diagonal interpolation directions + */ + + VH_Dir = ( float ( * ) ) calloc( width * height, sizeof *VH_Dir ); //merror ( VH_Dir, "rcd_demosaicing_171117()" ); + PQ_Dir = ( float ( * ) ) calloc( width * height, sizeof *PQ_Dir ); //merror ( PQ_Dir, "rcd_demosaicing_171117()" ); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int row = 4; row < height - 4; row++ ) { + for (int col = 4, indx = row * width + col; col < width - 4; col++, indx++ ) { + + //Calculate h/v local discrimination + float V_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - w1] - 18.0f * cfa[indx] * cfa[indx + w1] - 36.0f * cfa[indx] * cfa[indx - w2] - 36.0f * cfa[indx] * cfa[indx + w2] + 18.0f * cfa[indx] * cfa[indx - w3] + 18.0f * cfa[indx] * cfa[indx + w3] - 2.0f * cfa[indx] * cfa[indx - w4] - 2.0f * cfa[indx] * cfa[indx + w4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1] * cfa[indx + w1] - 12.0f * cfa[indx - w1] * cfa[indx - w2] + 24.0f * cfa[indx - w1] * cfa[indx + w2] - 38.0f * cfa[indx - w1] * cfa[indx - w3] + 16.0f * cfa[indx - w1] * cfa[indx + w3] + 12.0f * cfa[indx - w1] * cfa[indx - w4] - 6.0f * cfa[indx - w1] * cfa[indx + w4] + 46.0f * cfa[indx - w1] * cfa[indx - w1] + 24.0f * cfa[indx + w1] * cfa[indx - w2] - 12.0f * cfa[indx + w1] * cfa[indx + w2] + 16.0f * cfa[indx + w1] * cfa[indx - w3] - 38.0f * cfa[indx + w1] * cfa[indx + w3] - 6.0f * cfa[indx + w1] * cfa[indx - w4] + 12.0f * cfa[indx + w1] * cfa[indx + w4] + 46.0f * cfa[indx + w1] * cfa[indx + w1] + 14.0f * cfa[indx - w2] * cfa[indx + w2] - 12.0f * cfa[indx - w2] * cfa[indx + w3] - 2.0f * cfa[indx - w2] * cfa[indx - w4] + 2.0f * cfa[indx - w2] * cfa[indx + w4] + 11.0f * cfa[indx - w2] * cfa[indx - w2] - 12.0f * cfa[indx + w2] * cfa[indx - w3] + 2.0f * cfa[indx + w2] * cfa[indx - w4] - 2.0f * cfa[indx + w2] * cfa[indx + w4] + 11.0f * cfa[indx + w2] * cfa[indx + w2] + 2.0f * cfa[indx - w3] * cfa[indx + w3] - 6.0f * cfa[indx - w3] * cfa[indx - w4] + 10.0f * cfa[indx - w3] * cfa[indx - w3] - 6.0f * cfa[indx + w3] * cfa[indx + w4] + 10.0f * cfa[indx + w3] * cfa[indx + w3] + 1.0f * cfa[indx - w4] * cfa[indx - w4] + 1.0f * cfa[indx + w4] * cfa[indx + w4]; + float H_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - 1] - 18.0f * cfa[indx] * cfa[indx + 1] - 36.0f * cfa[indx] * cfa[indx - 2] - 36.0f * cfa[indx] * cfa[indx + 2] + 18.0f * cfa[indx] * cfa[indx - 3] + 18.0f * cfa[indx] * cfa[indx + 3] - 2.0f * cfa[indx] * cfa[indx - 4] - 2.0f * cfa[indx] * cfa[indx + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - 1] * cfa[indx + 1] - 12.0f * cfa[indx - 1] * cfa[indx - 2] + 24.0f * cfa[indx - 1] * cfa[indx + 2] - 38.0f * cfa[indx - 1] * cfa[indx - 3] + 16.0f * cfa[indx - 1] * cfa[indx + 3] + 12.0f * cfa[indx - 1] * cfa[indx - 4] - 6.0f * cfa[indx - 1] * cfa[indx + 4] + 46.0f * cfa[indx - 1] * cfa[indx - 1] + 24.0f * cfa[indx + 1] * cfa[indx - 2] - 12.0f * cfa[indx + 1] * cfa[indx + 2] + 16.0f * cfa[indx + 1] * cfa[indx - 3] - 38.0f * cfa[indx + 1] * cfa[indx + 3] - 6.0f * cfa[indx + 1] * cfa[indx - 4] + 12.0f * cfa[indx + 1] * cfa[indx + 4] + 46.0f * cfa[indx + 1] * cfa[indx + 1] + 14.0f * cfa[indx - 2] * cfa[indx + 2] - 12.0f * cfa[indx - 2] * cfa[indx + 3] - 2.0f * cfa[indx - 2] * cfa[indx - 4] + 2.0f * cfa[indx - 2] * cfa[indx + 4] + 11.0f * cfa[indx - 2] * cfa[indx - 2] - 12.0f * cfa[indx + 2] * cfa[indx - 3] + 2.0f * cfa[indx + 2] * cfa[indx - 4] - 2.0f * cfa[indx + 2] * cfa[indx + 4] + 11.0f * cfa[indx + 2] * cfa[indx + 2] + 2.0f * cfa[indx - 3] * cfa[indx + 3] - 6.0f * cfa[indx - 3] * cfa[indx - 4] + 10.0f * cfa[indx - 3] * cfa[indx - 3] - 6.0f * cfa[indx + 3] * cfa[indx + 4] + 10.0f * cfa[indx + 3] * cfa[indx + 3] + 1.0f * cfa[indx - 4] * cfa[indx - 4] + 1.0f * cfa[indx + 4] * cfa[indx + 4]; + + VH_Dir[indx] = V_Stat / (V_Stat + H_Stat); + + //Calculate m/p local discrimination + float P_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - w1 - 1] - 18.0f * cfa[indx] * cfa[indx + w1 + 1] - 36.0f * cfa[indx] * cfa[indx - w2 - 2] - 36.0f * cfa[indx] * cfa[indx + w2 + 2] + 18.0f * cfa[indx] * cfa[indx - w3 - 3] + 18.0f * cfa[indx] * cfa[indx + w3 + 3] - 2.0f * cfa[indx] * cfa[indx - w4 - 4] - 2.0f * cfa[indx] * cfa[indx + w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1 - 1] * cfa[indx + w1 + 1] - 12.0f * cfa[indx - w1 - 1] * cfa[indx - w2 - 2] + 24.0f * cfa[indx - w1 - 1] * cfa[indx + w2 + 2] - 38.0f * cfa[indx - w1 - 1] * cfa[indx - w3 - 3] + 16.0f * cfa[indx - w1 - 1] * cfa[indx + w3 + 3] + 12.0f * cfa[indx - w1 - 1] * cfa[indx - w4 - 4] - 6.0f * cfa[indx - w1 - 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx - w1 - 1] * cfa[indx - w1 - 1] + 24.0f * cfa[indx + w1 + 1] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w1 + 1] * cfa[indx + w2 + 2] + 16.0f * cfa[indx + w1 + 1] * cfa[indx - w3 - 3] - 38.0f * cfa[indx + w1 + 1] * cfa[indx + w3 + 3] - 6.0f * cfa[indx + w1 + 1] * cfa[indx - w4 - 4] + 12.0f * cfa[indx + w1 + 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx + w1 + 1] * cfa[indx + w1 + 1] + 14.0f * cfa[indx - w2 - 2] * cfa[indx + w2 + 2] - 12.0f * cfa[indx - w2 - 2] * cfa[indx + w3 + 3] - 2.0f * cfa[indx - w2 - 2] * cfa[indx - w4 - 4] + 2.0f * cfa[indx - w2 - 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx - w2 - 2] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w2 + 2] * cfa[indx - w3 - 3] + 2 * cfa[indx + w2 + 2] * cfa[indx - w4 - 4] - 2.0f * cfa[indx + w2 + 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx + w2 + 2] * cfa[indx + w2 + 2] + 2.0f * cfa[indx - w3 - 3] * cfa[indx + w3 + 3] - 6.0f * cfa[indx - w3 - 3] * cfa[indx - w4 - 4] + 10.0f * cfa[indx - w3 - 3] * cfa[indx - w3 - 3] - 6.0f * cfa[indx + w3 + 3] * cfa[indx + w4 + 4] + 10.0f * cfa[indx + w3 + 3] * cfa[indx + w3 + 3] + 1.0f * cfa[indx - w4 - 4] * cfa[indx - w4 - 4] + 1.0f * cfa[indx + w4 + 4] * cfa[indx + w4 + 4]; + float Q_Stat = epssq - 18.0f * cfa[indx] * cfa[indx + w1 - 1] - 18.0f * cfa[indx] * cfa[indx - w1 + 1] - 36.0f * cfa[indx] * cfa[indx + w2 - 2] - 36.0f * cfa[indx] * cfa[indx - w2 + 2] + 18.0f * cfa[indx] * cfa[indx + w3 - 3] + 18.0f * cfa[indx] * cfa[indx - w3 + 3] - 2.0f * cfa[indx] * cfa[indx + w4 - 4] - 2.0f * cfa[indx] * cfa[indx - w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx + w1 - 1] * cfa[indx - w1 + 1] - 12.0f * cfa[indx + w1 - 1] * cfa[indx + w2 - 2] + 24.0f * cfa[indx + w1 - 1] * cfa[indx - w2 + 2] - 38.0f * cfa[indx + w1 - 1] * cfa[indx + w3 - 3] + 16.0f * cfa[indx + w1 - 1] * cfa[indx - w3 + 3] + 12.0f * cfa[indx + w1 - 1] * cfa[indx + w4 - 4] - 6.0f * cfa[indx + w1 - 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx + w1 - 1] * cfa[indx + w1 - 1] + 24.0f * cfa[indx - w1 + 1] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w1 + 1] * cfa[indx - w2 + 2] + 16.0f * cfa[indx - w1 + 1] * cfa[indx + w3 - 3] - 38.0f * cfa[indx - w1 + 1] * cfa[indx - w3 + 3] - 6.0f * cfa[indx - w1 + 1] * cfa[indx + w4 - 4] + 12.0f * cfa[indx - w1 + 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx - w1 + 1] * cfa[indx - w1 + 1] + 14.0f * cfa[indx + w2 - 2] * cfa[indx - w2 + 2] - 12.0f * cfa[indx + w2 - 2] * cfa[indx - w3 + 3] - 2.0f * cfa[indx + w2 - 2] * cfa[indx + w4 - 4] + 2.0f * cfa[indx + w2 - 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx + w2 - 2] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w2 + 2] * cfa[indx + w3 - 3] + 2 * cfa[indx - w2 + 2] * cfa[indx + w4 - 4] - 2.0f * cfa[indx - w2 + 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx - w2 + 2] * cfa[indx - w2 + 2] + 2.0f * cfa[indx + w3 - 3] * cfa[indx - w3 + 3] - 6.0f * cfa[indx + w3 - 3] * cfa[indx + w4 - 4] + 10.0f * cfa[indx + w3 - 3] * cfa[indx + w3 - 3] - 6.0f * cfa[indx - w3 + 3] * cfa[indx - w4 + 4] + 10.0f * cfa[indx - w3 + 3] * cfa[indx - w3 + 3] + 1.0f * cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + 1.0f * cfa[indx - w4 + 4] * cfa[indx - w4 + 4]; + + PQ_Dir[indx] = P_Stat / ( P_Stat + Q_Stat ); + + } + } + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.2); + } + // ------------------------------------------------------------------------- + + + VH_Disc = ( float ( * ) ) calloc( width * height, sizeof *VH_Disc ); //merror ( VH_Disc, "rcd_demosaicing_171117()" ); + PQ_Disc = ( float ( * ) ) calloc( width * height, sizeof *PQ_Disc ); //merror ( PQ_Disc, "rcd_demosaicing_171117()" ); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4, indx = row * width + col; col < width - 4; col++, indx++ ) { + + //Refined h/v local discrimination + float VH_Central_Value = VH_Dir[indx]; + float VH_Neighbour_Value = 0.25f * (VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1] + VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1]); + + VH_Disc[indx] = ( fabs( 0.5f - VH_Central_Value ) < fabs( 0.5f - VH_Neighbour_Value ) ) ? VH_Neighbour_Value : VH_Central_Value; + + //Refined m/p local discrimination + float PQ_Central_Value = PQ_Dir[indx]; + float PQ_Neighbour_Value = 0.25f * (PQ_Dir[indx - w1 - 1] + PQ_Dir[indx - w1 + 1] + PQ_Dir[indx + w1 - 1] + PQ_Dir[indx + w1 + 1]); + + PQ_Disc[indx] = ( fabs( 0.5f - PQ_Central_Value ) < fabs( 0.5f - PQ_Neighbour_Value ) ) ? PQ_Neighbour_Value : PQ_Central_Value; + + } + } + + free( VH_Dir ); + free( PQ_Dir ); + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.4); + } + // ------------------------------------------------------------------------ + + /** + * STEP 2: Calculate the low pass filter + */ + + lpf = ( float ( * ) ) calloc( width * height, sizeof *lpf ); //merror ( lpf, "rcd_demosaicing_171117()" ); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 1; row < height - 1; row++ ) { + for ( int col = 1, indx = row * width + col; col < width - 1; col++, indx++ ) { + + //Low pass filter incorporating red and blue local samples + lpf[indx] = 0.25f * cfa[indx] + 0.125f * ( cfa[indx - w1] + cfa[indx + w1] + cfa[indx - 1] + cfa[indx + 1] ) + 0.0625f * ( cfa[indx - w1 - 1] + cfa[indx - w1 + 1] + cfa[indx + w1 - 1] + cfa[indx + w1 + 1] ); + + } + } + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.5); + } + // ------------------------------------------------------------------------ + + /** + * STEP 3: Populate the green channel + */ +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { + + //Cardinal gradients + float N_Grad = eps + fabs( cfa[indx - w1] - cfa[indx + w1] ) + fabs( cfa[indx] - cfa[indx - w2] ) + fabs( cfa[indx - w1] - cfa[indx - w3] ) + fabs( cfa[indx - w2] - cfa[indx - w4] ); + float S_Grad = eps + fabs( cfa[indx + w1] - cfa[indx - w1] ) + fabs( cfa[indx] - cfa[indx + w2] ) + fabs( cfa[indx + w1] - cfa[indx + w3] ) + fabs( cfa[indx + w2] - cfa[indx + w4] ); + float W_Grad = eps + fabs( cfa[indx - 1] - cfa[indx + 1] ) + fabs( cfa[indx] - cfa[indx - 2] ) + fabs( cfa[indx - 1] - cfa[indx - 3] ) + fabs( cfa[indx - 2] - cfa[indx - 4] ); + float E_Grad = eps + fabs( cfa[indx + 1] - cfa[indx - 1] ) + fabs( cfa[indx] - cfa[indx + 2] ) + fabs( cfa[indx + 1] - cfa[indx + 3] ) + fabs( cfa[indx + 2] - cfa[indx + 4] ); + + //Cardinal pixel estimations + float N_Est = cfa[indx - w1] * ( 1.f + ( lpf[indx] - lpf[indx - w2] ) / ( eps + lpf[indx] + lpf[indx - w2] ) ); + float S_Est = cfa[indx + w1] * ( 1.f + ( lpf[indx] - lpf[indx + w2] ) / ( eps + lpf[indx] + lpf[indx + w2] ) ); + float W_Est = cfa[indx - 1] * ( 1.f + ( lpf[indx] - lpf[indx - 2] ) / ( eps + lpf[indx] + lpf[indx - 2] ) ); + float E_Est = cfa[indx + 1] * ( 1.f + ( lpf[indx] - lpf[indx + 2] ) / ( eps + lpf[indx] + lpf[indx + 2] ) ); + + //Interpolate G@R & G@B + float V_Est = ( S_Grad * N_Est + N_Grad * S_Est ) / ( N_Grad + S_Grad ); + float H_Est = ( W_Grad * E_Est + E_Grad * W_Est ) / ( E_Grad + W_Grad ); + + rgb[indx][1] = LIM( VH_Disc[indx] * H_Est + ( 1.0f - VH_Disc[indx] ) * V_Est, 0.f, 1.f ); + + } + } + + free( lpf ); + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.7); + } + // ------------------------------------------------------------------------- + + /** + * STEP 4: Populate the red and blue channel + */ +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col, c = 2 - FC( row, col ); col < width - 4; col += 2, indx += 2 ) { + + //Diagonal gradients + float NW_Grad = eps + fabs( rgb[indx - w1 - 1][c] - rgb[indx + w1 + 1][c] ) + fabs( rgb[indx - w1 - 1][c] - rgb[indx - w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 - 2][1] ); + float NE_Grad = eps + fabs( rgb[indx - w1 + 1][c] - rgb[indx + w1 - 1][c] ) + fabs( rgb[indx - w1 + 1][c] - rgb[indx - w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 + 2][1] ); + float SW_Grad = eps + fabs( rgb[indx + w1 - 1][c] - rgb[indx - w1 + 1][c] ) + fabs( rgb[indx + w1 - 1][c] - rgb[indx + w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 - 2][1] ); + float SE_Grad = eps + fabs( rgb[indx + w1 + 1][c] - rgb[indx - w1 - 1][c] ) + fabs( rgb[indx + w1 + 1][c] - rgb[indx + w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 + 2][1] ); + + //Diagonal colour differences + float NW_Est = rgb[indx - w1 - 1][c] - rgb[indx - w1 - 1][1]; + float NE_Est = rgb[indx - w1 + 1][c] - rgb[indx - w1 + 1][1]; + float SW_Est = rgb[indx + w1 - 1][c] - rgb[indx + w1 - 1][1]; + float SE_Est = rgb[indx + w1 + 1][c] - rgb[indx + w1 + 1][1]; + + //Interpolate R@B and B@R + float P_Est = ( NW_Grad * SE_Est + SE_Grad * NW_Est ) / ( NW_Grad + SE_Grad ); + float Q_Est = ( NE_Grad * SW_Est + SW_Grad * NE_Est ) / ( NE_Grad + SW_Grad ); + + rgb[indx][c] = LIM( rgb[indx][1] + ( 1.0f - PQ_Disc[indx] ) * P_Est + PQ_Disc[indx] * Q_Est, 0.f, 1.f ); + + } + } + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.825); + } + // ------------------------------------------------------------------------- + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4 + ( FC( row, 1 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { + + for ( int c = 0; c <= 2; c += 2 ) { + + //Cardinal gradients + float N_Grad = eps + fabs( rgb[indx][1] - rgb[indx - w2][1] ) + fabs( rgb[indx - w1][c] - rgb[indx + w1][c] ) + fabs( rgb[indx - w1][c] - rgb[indx - w3][c] ); + float S_Grad = eps + fabs( rgb[indx][1] - rgb[indx + w2][1] ) + fabs( rgb[indx + w1][c] - rgb[indx - w1][c] ) + fabs( rgb[indx + w1][c] - rgb[indx + w3][c] ); + float W_Grad = eps + fabs( rgb[indx][1] - rgb[indx - 2][1] ) + fabs( rgb[indx - 1][c] - rgb[indx + 1][c] ) + fabs( rgb[indx - 1][c] - rgb[indx - 3][c] ); + float E_Grad = eps + fabs( rgb[indx][1] - rgb[indx + 2][1] ) + fabs( rgb[indx + 1][c] - rgb[indx - 1][c] ) + fabs( rgb[indx + 1][c] - rgb[indx + 3][c] ); + + //Cardinal colour differences + float N_Est = rgb[indx - w1][c] - rgb[indx - w1][1]; + float S_Est = rgb[indx + w1][c] - rgb[indx + w1][1]; + float W_Est = rgb[indx - 1][c] - rgb[indx - 1][1]; + float E_Est = rgb[indx + 1][c] - rgb[indx + 1][1]; + + //Interpolate R@G and B@G + float V_Est = ( N_Grad * S_Est + S_Grad * N_Est ) / ( N_Grad + S_Grad ); + float H_Est = ( E_Grad * W_Est + W_Grad * E_Est ) / ( E_Grad + W_Grad ); + + rgb[indx][c] = LIM( rgb[indx][1] + ( 1.0f - VH_Disc[indx] ) * V_Est + VH_Disc[indx] * H_Est, 0.f, 1.f ); + + } + } + } + + free( PQ_Disc ); + free( VH_Disc ); + + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.95); + } + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int row = 0; row < height; ++row) { + for (int col = 0, idx = row * width + col ; col < width; ++col, ++idx) { + red[row][col] = CLIP(rgb[idx][0] * 65535.f); + green[row][col] = CLIP(rgb[idx][1] * 65535.f); + blue[row][col] = CLIP(rgb[idx][2] * 65535.f); + } + } + + if (plistener) { + plistener->setProgress(1); + } + // ------------------------------------------------------------------------- +} + #define fcol(row,col) xtrans[(row)%6][(col)%6] #define isgreen(row,col) (xtrans[(row)%3][(col)%3]&1) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 0ada68a62..0447da364 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -53,7 +53,7 @@ const int tl = (int) options.rtSettings.top_left; const int bl = (int) options.rtSettings.bot_left; const char *LensProfParams::methodstring[static_cast(LensProfParams::LcMode::LCP) + 1u] = {"none", "lfauto", "lfmanual", "lcp"}; -const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "fast", "mono", "none", "pixelshift" }; +const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "rcd", "fast", "mono", "none", "pixelshift" }; const char *RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::numMethods] = {"3-pass (best)", "1-pass (medium)", "fast", "mono", "none" }; const char *RAWParams::ff_BlurTypestring[RAWParams::numFlatFileBlurTypes] = {/*"Parametric",*/ "Area Flatfield", "Vertical Flatfield", "Horizontal Flatfield", "V+H Flatfield"}; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index b3139cdcb..d7ebd1921 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1262,7 +1262,7 @@ public: public: //enum eMethod{ eahd,hphd,vng4,dcb,amaze,ahd,IGV_noise,fast, //numMethods }; // This MUST be the last enum - enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, pixelshift, + enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, rcd, fast, mono, none, pixelshift, numMethods }; // This MUST be the last enum enum ePSMotionCorrection { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5eb7aa7b9..a6b6d4b53 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2049,6 +2049,8 @@ void RawImageSource::demosaic(const RAWParams &raw) fast_demosaic(); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::mono] ) { nodemosaic(true); + } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::rcd] ) { + rcd_demosaic (); } else { nodemosaic(false); } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index d2ce77fed..4924b955a 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -248,6 +248,7 @@ protected: void fast_demosaic();//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(); + void rcd_demosaic(); void border_interpolate(unsigned int border, float (*image)[4], unsigned int start = 0, unsigned int end = 0); void border_interpolate2(int winw, int winh, int lborders); void dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border); From 3673f1392c1b19a232a4decf5b1f5b78aae974fd Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 19 Nov 2017 00:43:12 +0100 Subject: [PATCH 02/18] added reference to the original repo and license for the RCD demosaic code --- rtengine/demosaic_algos.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index 61258fca2..1f89ce31f 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -3933,6 +3933,9 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b * Luis Sanz Rodriguez (luis.sanz.rodriguez(at)gmail(dot)com) * * Release 2.2 @ 171117 +* +* Original code from https://github.com/LuisSR/RCD-Demosaicing +* Licensed under the GNU GPL version 3 */ void RawImageSource::rcd_demosaic() { From 95d303f442ced402068e0670255aeff22dc86ff1 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 19 Nov 2017 18:47:16 +0100 Subject: [PATCH 03/18] turn off parallelization of step 4 of rcd as the arrays are read and written, doing parallel operations properly requires some deeper analysis of the code. For now, let's simply disable them. We can always optimize later --- rtengine/demosaic_algos.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index 1f89ce31f..0eb920a36 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -4122,9 +4122,6 @@ void RawImageSource::rcd_demosaic() /** * STEP 4: Populate the red and blue channel */ -#ifdef _OPENMP - #pragma omp parallel for -#endif for ( int row = 4; row < height - 4; row++ ) { for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col, c = 2 - FC( row, col ); col < width - 4; col += 2, indx += 2 ) { @@ -4155,9 +4152,6 @@ void RawImageSource::rcd_demosaic() } // ------------------------------------------------------------------------- -#ifdef _OPENMP - #pragma omp parallel for -#endif for ( int row = 4; row < height - 4; row++ ) { for ( int col = 4 + ( FC( row, 1 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { From 421fa881c35423958757098be9cc221b5a9945eb Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 23 Nov 2017 16:25:47 +0100 Subject: [PATCH 04/18] RCD demosaic: fixed potential divisons by zero (due to non-associativity and cancellation effects of ops on floats) --- rtengine/demosaic_algos.cc | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index 0eb920a36..e1efcda86 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -4003,17 +4003,22 @@ void RawImageSource::rcd_demosaic() for (int col = 4, indx = row * width + col; col < width - 4; col++, indx++ ) { //Calculate h/v local discrimination - float V_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - w1] - 18.0f * cfa[indx] * cfa[indx + w1] - 36.0f * cfa[indx] * cfa[indx - w2] - 36.0f * cfa[indx] * cfa[indx + w2] + 18.0f * cfa[indx] * cfa[indx - w3] + 18.0f * cfa[indx] * cfa[indx + w3] - 2.0f * cfa[indx] * cfa[indx - w4] - 2.0f * cfa[indx] * cfa[indx + w4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1] * cfa[indx + w1] - 12.0f * cfa[indx - w1] * cfa[indx - w2] + 24.0f * cfa[indx - w1] * cfa[indx + w2] - 38.0f * cfa[indx - w1] * cfa[indx - w3] + 16.0f * cfa[indx - w1] * cfa[indx + w3] + 12.0f * cfa[indx - w1] * cfa[indx - w4] - 6.0f * cfa[indx - w1] * cfa[indx + w4] + 46.0f * cfa[indx - w1] * cfa[indx - w1] + 24.0f * cfa[indx + w1] * cfa[indx - w2] - 12.0f * cfa[indx + w1] * cfa[indx + w2] + 16.0f * cfa[indx + w1] * cfa[indx - w3] - 38.0f * cfa[indx + w1] * cfa[indx + w3] - 6.0f * cfa[indx + w1] * cfa[indx - w4] + 12.0f * cfa[indx + w1] * cfa[indx + w4] + 46.0f * cfa[indx + w1] * cfa[indx + w1] + 14.0f * cfa[indx - w2] * cfa[indx + w2] - 12.0f * cfa[indx - w2] * cfa[indx + w3] - 2.0f * cfa[indx - w2] * cfa[indx - w4] + 2.0f * cfa[indx - w2] * cfa[indx + w4] + 11.0f * cfa[indx - w2] * cfa[indx - w2] - 12.0f * cfa[indx + w2] * cfa[indx - w3] + 2.0f * cfa[indx + w2] * cfa[indx - w4] - 2.0f * cfa[indx + w2] * cfa[indx + w4] + 11.0f * cfa[indx + w2] * cfa[indx + w2] + 2.0f * cfa[indx - w3] * cfa[indx + w3] - 6.0f * cfa[indx - w3] * cfa[indx - w4] + 10.0f * cfa[indx - w3] * cfa[indx - w3] - 6.0f * cfa[indx + w3] * cfa[indx + w4] + 10.0f * cfa[indx + w3] * cfa[indx + w3] + 1.0f * cfa[indx - w4] * cfa[indx - w4] + 1.0f * cfa[indx + w4] * cfa[indx + w4]; - float H_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - 1] - 18.0f * cfa[indx] * cfa[indx + 1] - 36.0f * cfa[indx] * cfa[indx - 2] - 36.0f * cfa[indx] * cfa[indx + 2] + 18.0f * cfa[indx] * cfa[indx - 3] + 18.0f * cfa[indx] * cfa[indx + 3] - 2.0f * cfa[indx] * cfa[indx - 4] - 2.0f * cfa[indx] * cfa[indx + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - 1] * cfa[indx + 1] - 12.0f * cfa[indx - 1] * cfa[indx - 2] + 24.0f * cfa[indx - 1] * cfa[indx + 2] - 38.0f * cfa[indx - 1] * cfa[indx - 3] + 16.0f * cfa[indx - 1] * cfa[indx + 3] + 12.0f * cfa[indx - 1] * cfa[indx - 4] - 6.0f * cfa[indx - 1] * cfa[indx + 4] + 46.0f * cfa[indx - 1] * cfa[indx - 1] + 24.0f * cfa[indx + 1] * cfa[indx - 2] - 12.0f * cfa[indx + 1] * cfa[indx + 2] + 16.0f * cfa[indx + 1] * cfa[indx - 3] - 38.0f * cfa[indx + 1] * cfa[indx + 3] - 6.0f * cfa[indx + 1] * cfa[indx - 4] + 12.0f * cfa[indx + 1] * cfa[indx + 4] + 46.0f * cfa[indx + 1] * cfa[indx + 1] + 14.0f * cfa[indx - 2] * cfa[indx + 2] - 12.0f * cfa[indx - 2] * cfa[indx + 3] - 2.0f * cfa[indx - 2] * cfa[indx - 4] + 2.0f * cfa[indx - 2] * cfa[indx + 4] + 11.0f * cfa[indx - 2] * cfa[indx - 2] - 12.0f * cfa[indx + 2] * cfa[indx - 3] + 2.0f * cfa[indx + 2] * cfa[indx - 4] - 2.0f * cfa[indx + 2] * cfa[indx + 4] + 11.0f * cfa[indx + 2] * cfa[indx + 2] + 2.0f * cfa[indx - 3] * cfa[indx + 3] - 6.0f * cfa[indx - 3] * cfa[indx - 4] + 10.0f * cfa[indx - 3] * cfa[indx - 3] - 6.0f * cfa[indx + 3] * cfa[indx + 4] + 10.0f * cfa[indx + 3] * cfa[indx + 3] + 1.0f * cfa[indx - 4] * cfa[indx - 4] + 1.0f * cfa[indx + 4] * cfa[indx + 4]; + float V_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - w1] - 18.0f * cfa[indx] * cfa[indx + w1] - 36.0f * cfa[indx] * cfa[indx - w2] - 36.0f * cfa[indx] * cfa[indx + w2] + 18.0f * cfa[indx] * cfa[indx - w3] + 18.0f * cfa[indx] * cfa[indx + w3] - 2.0f * cfa[indx] * cfa[indx - w4] - 2.0f * cfa[indx] * cfa[indx + w4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1] * cfa[indx + w1] - 12.0f * cfa[indx - w1] * cfa[indx - w2] + 24.0f * cfa[indx - w1] * cfa[indx + w2] - 38.0f * cfa[indx - w1] * cfa[indx - w3] + 16.0f * cfa[indx - w1] * cfa[indx + w3] + 12.0f * cfa[indx - w1] * cfa[indx - w4] - 6.0f * cfa[indx - w1] * cfa[indx + w4] + 46.0f * cfa[indx - w1] * cfa[indx - w1] + 24.0f * cfa[indx + w1] * cfa[indx - w2] - 12.0f * cfa[indx + w1] * cfa[indx + w2] + 16.0f * cfa[indx + w1] * cfa[indx - w3] - 38.0f * cfa[indx + w1] * cfa[indx + w3] - 6.0f * cfa[indx + w1] * cfa[indx - w4] + 12.0f * cfa[indx + w1] * cfa[indx + w4] + 46.0f * cfa[indx + w1] * cfa[indx + w1] + 14.0f * cfa[indx - w2] * cfa[indx + w2] - 12.0f * cfa[indx - w2] * cfa[indx + w3] - 2.0f * cfa[indx - w2] * cfa[indx - w4] + 2.0f * cfa[indx - w2] * cfa[indx + w4] + 11.0f * cfa[indx - w2] * cfa[indx - w2] - 12.0f * cfa[indx + w2] * cfa[indx - w3] + 2.0f * cfa[indx + w2] * cfa[indx - w4] - 2.0f * cfa[indx + w2] * cfa[indx + w4] + 11.0f * cfa[indx + w2] * cfa[indx + w2] + 2.0f * cfa[indx - w3] * cfa[indx + w3] - 6.0f * cfa[indx - w3] * cfa[indx - w4] + 10.0f * cfa[indx - w3] * cfa[indx - w3] - 6.0f * cfa[indx + w3] * cfa[indx + w4] + 10.0f * cfa[indx + w3] * cfa[indx + w3] + 1.0f * cfa[indx - w4] * cfa[indx - w4] + 1.0f * cfa[indx + w4] * cfa[indx + w4]); + + float H_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - 1] - 18.0f * cfa[indx] * cfa[indx + 1] - 36.0f * cfa[indx] * cfa[indx - 2] - 36.0f * cfa[indx] * cfa[indx + 2] + 18.0f * cfa[indx] * cfa[indx - 3] + 18.0f * cfa[indx] * cfa[indx + 3] - 2.0f * cfa[indx] * cfa[indx - 4] - 2.0f * cfa[indx] * cfa[indx + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - 1] * cfa[indx + 1] - 12.0f * cfa[indx - 1] * cfa[indx - 2] + 24.0f * cfa[indx - 1] * cfa[indx + 2] - 38.0f * cfa[indx - 1] * cfa[indx - 3] + 16.0f * cfa[indx - 1] * cfa[indx + 3] + 12.0f * cfa[indx - 1] * cfa[indx - 4] - 6.0f * cfa[indx - 1] * cfa[indx + 4] + 46.0f * cfa[indx - 1] * cfa[indx - 1] + 24.0f * cfa[indx + 1] * cfa[indx - 2] - 12.0f * cfa[indx + 1] * cfa[indx + 2] + 16.0f * cfa[indx + 1] * cfa[indx - 3] - 38.0f * cfa[indx + 1] * cfa[indx + 3] - 6.0f * cfa[indx + 1] * cfa[indx - 4] + 12.0f * cfa[indx + 1] * cfa[indx + 4] + 46.0f * cfa[indx + 1] * cfa[indx + 1] + 14.0f * cfa[indx - 2] * cfa[indx + 2] - 12.0f * cfa[indx - 2] * cfa[indx + 3] - 2.0f * cfa[indx - 2] * cfa[indx - 4] + 2.0f * cfa[indx - 2] * cfa[indx + 4] + 11.0f * cfa[indx - 2] * cfa[indx - 2] - 12.0f * cfa[indx + 2] * cfa[indx - 3] + 2.0f * cfa[indx + 2] * cfa[indx - 4] - 2.0f * cfa[indx + 2] * cfa[indx + 4] + 11.0f * cfa[indx + 2] * cfa[indx + 2] + 2.0f * cfa[indx - 3] * cfa[indx + 3] - 6.0f * cfa[indx - 3] * cfa[indx - 4] + 10.0f * cfa[indx - 3] * cfa[indx - 3] - 6.0f * cfa[indx + 3] * cfa[indx + 4] + 10.0f * cfa[indx + 3] * cfa[indx + 3] + 1.0f * cfa[indx - 4] * cfa[indx - 4] + 1.0f * cfa[indx + 4] * cfa[indx + 4]); VH_Dir[indx] = V_Stat / (V_Stat + H_Stat); //Calculate m/p local discrimination - float P_Stat = epssq - 18.0f * cfa[indx] * cfa[indx - w1 - 1] - 18.0f * cfa[indx] * cfa[indx + w1 + 1] - 36.0f * cfa[indx] * cfa[indx - w2 - 2] - 36.0f * cfa[indx] * cfa[indx + w2 + 2] + 18.0f * cfa[indx] * cfa[indx - w3 - 3] + 18.0f * cfa[indx] * cfa[indx + w3 + 3] - 2.0f * cfa[indx] * cfa[indx - w4 - 4] - 2.0f * cfa[indx] * cfa[indx + w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1 - 1] * cfa[indx + w1 + 1] - 12.0f * cfa[indx - w1 - 1] * cfa[indx - w2 - 2] + 24.0f * cfa[indx - w1 - 1] * cfa[indx + w2 + 2] - 38.0f * cfa[indx - w1 - 1] * cfa[indx - w3 - 3] + 16.0f * cfa[indx - w1 - 1] * cfa[indx + w3 + 3] + 12.0f * cfa[indx - w1 - 1] * cfa[indx - w4 - 4] - 6.0f * cfa[indx - w1 - 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx - w1 - 1] * cfa[indx - w1 - 1] + 24.0f * cfa[indx + w1 + 1] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w1 + 1] * cfa[indx + w2 + 2] + 16.0f * cfa[indx + w1 + 1] * cfa[indx - w3 - 3] - 38.0f * cfa[indx + w1 + 1] * cfa[indx + w3 + 3] - 6.0f * cfa[indx + w1 + 1] * cfa[indx - w4 - 4] + 12.0f * cfa[indx + w1 + 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx + w1 + 1] * cfa[indx + w1 + 1] + 14.0f * cfa[indx - w2 - 2] * cfa[indx + w2 + 2] - 12.0f * cfa[indx - w2 - 2] * cfa[indx + w3 + 3] - 2.0f * cfa[indx - w2 - 2] * cfa[indx - w4 - 4] + 2.0f * cfa[indx - w2 - 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx - w2 - 2] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w2 + 2] * cfa[indx - w3 - 3] + 2 * cfa[indx + w2 + 2] * cfa[indx - w4 - 4] - 2.0f * cfa[indx + w2 + 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx + w2 + 2] * cfa[indx + w2 + 2] + 2.0f * cfa[indx - w3 - 3] * cfa[indx + w3 + 3] - 6.0f * cfa[indx - w3 - 3] * cfa[indx - w4 - 4] + 10.0f * cfa[indx - w3 - 3] * cfa[indx - w3 - 3] - 6.0f * cfa[indx + w3 + 3] * cfa[indx + w4 + 4] + 10.0f * cfa[indx + w3 + 3] * cfa[indx + w3 + 3] + 1.0f * cfa[indx - w4 - 4] * cfa[indx - w4 - 4] + 1.0f * cfa[indx + w4 + 4] * cfa[indx + w4 + 4]; - float Q_Stat = epssq - 18.0f * cfa[indx] * cfa[indx + w1 - 1] - 18.0f * cfa[indx] * cfa[indx - w1 + 1] - 36.0f * cfa[indx] * cfa[indx + w2 - 2] - 36.0f * cfa[indx] * cfa[indx - w2 + 2] + 18.0f * cfa[indx] * cfa[indx + w3 - 3] + 18.0f * cfa[indx] * cfa[indx - w3 + 3] - 2.0f * cfa[indx] * cfa[indx + w4 - 4] - 2.0f * cfa[indx] * cfa[indx - w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx + w1 - 1] * cfa[indx - w1 + 1] - 12.0f * cfa[indx + w1 - 1] * cfa[indx + w2 - 2] + 24.0f * cfa[indx + w1 - 1] * cfa[indx - w2 + 2] - 38.0f * cfa[indx + w1 - 1] * cfa[indx + w3 - 3] + 16.0f * cfa[indx + w1 - 1] * cfa[indx - w3 + 3] + 12.0f * cfa[indx + w1 - 1] * cfa[indx + w4 - 4] - 6.0f * cfa[indx + w1 - 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx + w1 - 1] * cfa[indx + w1 - 1] + 24.0f * cfa[indx - w1 + 1] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w1 + 1] * cfa[indx - w2 + 2] + 16.0f * cfa[indx - w1 + 1] * cfa[indx + w3 - 3] - 38.0f * cfa[indx - w1 + 1] * cfa[indx - w3 + 3] - 6.0f * cfa[indx - w1 + 1] * cfa[indx + w4 - 4] + 12.0f * cfa[indx - w1 + 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx - w1 + 1] * cfa[indx - w1 + 1] + 14.0f * cfa[indx + w2 - 2] * cfa[indx - w2 + 2] - 12.0f * cfa[indx + w2 - 2] * cfa[indx - w3 + 3] - 2.0f * cfa[indx + w2 - 2] * cfa[indx + w4 - 4] + 2.0f * cfa[indx + w2 - 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx + w2 - 2] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w2 + 2] * cfa[indx + w3 - 3] + 2 * cfa[indx - w2 + 2] * cfa[indx + w4 - 4] - 2.0f * cfa[indx - w2 + 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx - w2 + 2] * cfa[indx - w2 + 2] + 2.0f * cfa[indx + w3 - 3] * cfa[indx - w3 + 3] - 6.0f * cfa[indx + w3 - 3] * cfa[indx + w4 - 4] + 10.0f * cfa[indx + w3 - 3] * cfa[indx + w3 - 3] - 6.0f * cfa[indx - w3 + 3] * cfa[indx - w4 + 4] + 10.0f * cfa[indx - w3 + 3] * cfa[indx - w3 + 3] + 1.0f * cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + 1.0f * cfa[indx - w4 + 4] * cfa[indx - w4 + 4]; + float P_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - w1 - 1] - 18.0f * cfa[indx] * cfa[indx + w1 + 1] - 36.0f * cfa[indx] * cfa[indx - w2 - 2] - 36.0f * cfa[indx] * cfa[indx + w2 + 2] + 18.0f * cfa[indx] * cfa[indx - w3 - 3] + 18.0f * cfa[indx] * cfa[indx + w3 + 3] - 2.0f * cfa[indx] * cfa[indx - w4 - 4] - 2.0f * cfa[indx] * cfa[indx + w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1 - 1] * cfa[indx + w1 + 1] - 12.0f * cfa[indx - w1 - 1] * cfa[indx - w2 - 2] + 24.0f * cfa[indx - w1 - 1] * cfa[indx + w2 + 2] - 38.0f * cfa[indx - w1 - 1] * cfa[indx - w3 - 3] + 16.0f * cfa[indx - w1 - 1] * cfa[indx + w3 + 3] + 12.0f * cfa[indx - w1 - 1] * cfa[indx - w4 - 4] - 6.0f * cfa[indx - w1 - 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx - w1 - 1] * cfa[indx - w1 - 1] + 24.0f * cfa[indx + w1 + 1] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w1 + 1] * cfa[indx + w2 + 2] + 16.0f * cfa[indx + w1 + 1] * cfa[indx - w3 - 3] - 38.0f * cfa[indx + w1 + 1] * cfa[indx + w3 + 3] - 6.0f * cfa[indx + w1 + 1] * cfa[indx - w4 - 4] + 12.0f * cfa[indx + w1 + 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx + w1 + 1] * cfa[indx + w1 + 1] + 14.0f * cfa[indx - w2 - 2] * cfa[indx + w2 + 2] - 12.0f * cfa[indx - w2 - 2] * cfa[indx + w3 + 3] - 2.0f * cfa[indx - w2 - 2] * cfa[indx - w4 - 4] + 2.0f * cfa[indx - w2 - 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx - w2 - 2] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w2 + 2] * cfa[indx - w3 - 3] + 2 * cfa[indx + w2 + 2] * cfa[indx - w4 - 4] - 2.0f * cfa[indx + w2 + 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx + w2 + 2] * cfa[indx + w2 + 2] + 2.0f * cfa[indx - w3 - 3] * cfa[indx + w3 + 3] - 6.0f * cfa[indx - w3 - 3] * cfa[indx - w4 - 4] + 10.0f * cfa[indx - w3 - 3] * cfa[indx - w3 - 3] - 6.0f * cfa[indx + w3 + 3] * cfa[indx + w4 + 4] + 10.0f * cfa[indx + w3 + 3] * cfa[indx + w3 + 3] + 1.0f * cfa[indx - w4 - 4] * cfa[indx - w4 - 4] + 1.0f * cfa[indx + w4 + 4] * cfa[indx + w4 + 4]); + + float Q_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx + w1 - 1] - 18.0f * cfa[indx] * cfa[indx - w1 + 1] - 36.0f * cfa[indx] * cfa[indx + w2 - 2] - 36.0f * cfa[indx] * cfa[indx - w2 + 2] + 18.0f * cfa[indx] * cfa[indx + w3 - 3] + 18.0f * cfa[indx] * cfa[indx - w3 + 3] - 2.0f * cfa[indx] * cfa[indx + w4 - 4] - 2.0f * cfa[indx] * cfa[indx - w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx + w1 - 1] * cfa[indx - w1 + 1] - 12.0f * cfa[indx + w1 - 1] * cfa[indx + w2 - 2] + 24.0f * cfa[indx + w1 - 1] * cfa[indx - w2 + 2] - 38.0f * cfa[indx + w1 - 1] * cfa[indx + w3 - 3] + 16.0f * cfa[indx + w1 - 1] * cfa[indx - w3 + 3] + 12.0f * cfa[indx + w1 - 1] * cfa[indx + w4 - 4] - 6.0f * cfa[indx + w1 - 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx + w1 - 1] * cfa[indx + w1 - 1] + 24.0f * cfa[indx - w1 + 1] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w1 + 1] * cfa[indx - w2 + 2] + 16.0f * cfa[indx - w1 + 1] * cfa[indx + w3 - 3] - 38.0f * cfa[indx - w1 + 1] * cfa[indx - w3 + 3] - 6.0f * cfa[indx - w1 + 1] * cfa[indx + w4 - 4] + 12.0f * cfa[indx - w1 + 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx - w1 + 1] * cfa[indx - w1 + 1] + 14.0f * cfa[indx + w2 - 2] * cfa[indx - w2 + 2] - 12.0f * cfa[indx + w2 - 2] * cfa[indx - w3 + 3] - 2.0f * cfa[indx + w2 - 2] * cfa[indx + w4 - 4] + 2.0f * cfa[indx + w2 - 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx + w2 - 2] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w2 + 2] * cfa[indx + w3 - 3] + 2 * cfa[indx - w2 + 2] * cfa[indx + w4 - 4] - 2.0f * cfa[indx - w2 + 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx - w2 + 2] * cfa[indx - w2 + 2] + 2.0f * cfa[indx + w3 - 3] * cfa[indx - w3 + 3] - 6.0f * cfa[indx + w3 - 3] * cfa[indx + w4 - 4] + 10.0f * cfa[indx + w3 - 3] * cfa[indx + w3 - 3] - 6.0f * cfa[indx - w3 + 3] * cfa[indx - w4 + 4] + 10.0f * cfa[indx - w3 + 3] * cfa[indx - w3 + 3] + 1.0f * cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + 1.0f * cfa[indx - w4 + 4] * cfa[indx - w4 + 4]); PQ_Dir[indx] = P_Stat / ( P_Stat + Q_Stat ); + assert(isfinite(VH_Dir[indx])); + assert(isfinite(PQ_Dir[indx])); + } } @@ -4091,16 +4096,16 @@ void RawImageSource::rcd_demosaic() for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { //Cardinal gradients - float N_Grad = eps + fabs( cfa[indx - w1] - cfa[indx + w1] ) + fabs( cfa[indx] - cfa[indx - w2] ) + fabs( cfa[indx - w1] - cfa[indx - w3] ) + fabs( cfa[indx - w2] - cfa[indx - w4] ); - float S_Grad = eps + fabs( cfa[indx + w1] - cfa[indx - w1] ) + fabs( cfa[indx] - cfa[indx + w2] ) + fabs( cfa[indx + w1] - cfa[indx + w3] ) + fabs( cfa[indx + w2] - cfa[indx + w4] ); - float W_Grad = eps + fabs( cfa[indx - 1] - cfa[indx + 1] ) + fabs( cfa[indx] - cfa[indx - 2] ) + fabs( cfa[indx - 1] - cfa[indx - 3] ) + fabs( cfa[indx - 2] - cfa[indx - 4] ); - float E_Grad = eps + fabs( cfa[indx + 1] - cfa[indx - 1] ) + fabs( cfa[indx] - cfa[indx + 2] ) + fabs( cfa[indx + 1] - cfa[indx + 3] ) + fabs( cfa[indx + 2] - cfa[indx + 4] ); + float N_Grad = eps + (fabs( cfa[indx - w1] - cfa[indx + w1] ) + fabs( cfa[indx] - cfa[indx - w2] ) + fabs( cfa[indx - w1] - cfa[indx - w3] ) + fabs( cfa[indx - w2] - cfa[indx - w4] )); + float S_Grad = eps + (fabs( cfa[indx + w1] - cfa[indx - w1] ) + fabs( cfa[indx] - cfa[indx + w2] ) + fabs( cfa[indx + w1] - cfa[indx + w3] ) + fabs( cfa[indx + w2] - cfa[indx + w4] )); + float W_Grad = eps + (fabs( cfa[indx - 1] - cfa[indx + 1] ) + fabs( cfa[indx] - cfa[indx - 2] ) + fabs( cfa[indx - 1] - cfa[indx - 3] ) + fabs( cfa[indx - 2] - cfa[indx - 4] )); + float E_Grad = eps + (fabs( cfa[indx + 1] - cfa[indx - 1] ) + fabs( cfa[indx] - cfa[indx + 2] ) + fabs( cfa[indx + 1] - cfa[indx + 3] ) + fabs( cfa[indx + 2] - cfa[indx + 4] )); //Cardinal pixel estimations - float N_Est = cfa[indx - w1] * ( 1.f + ( lpf[indx] - lpf[indx - w2] ) / ( eps + lpf[indx] + lpf[indx - w2] ) ); - float S_Est = cfa[indx + w1] * ( 1.f + ( lpf[indx] - lpf[indx + w2] ) / ( eps + lpf[indx] + lpf[indx + w2] ) ); - float W_Est = cfa[indx - 1] * ( 1.f + ( lpf[indx] - lpf[indx - 2] ) / ( eps + lpf[indx] + lpf[indx - 2] ) ); - float E_Est = cfa[indx + 1] * ( 1.f + ( lpf[indx] - lpf[indx + 2] ) / ( eps + lpf[indx] + lpf[indx + 2] ) ); + float N_Est = cfa[indx - w1] * ( 1.f + ( lpf[indx] - lpf[indx - w2] ) / ( eps + (lpf[indx] + lpf[indx - w2])) ); + float S_Est = cfa[indx + w1] * ( 1.f + ( lpf[indx] - lpf[indx + w2] ) / ( eps + (lpf[indx] + lpf[indx + w2])) ); + float W_Est = cfa[indx - 1] * ( 1.f + ( lpf[indx] - lpf[indx - 2] ) / ( eps + (lpf[indx] + lpf[indx - 2])) ); + float E_Est = cfa[indx + 1] * ( 1.f + ( lpf[indx] - lpf[indx + 2] ) / ( eps + (lpf[indx] + lpf[indx + 2])) ); //Interpolate G@R & G@B float V_Est = ( S_Grad * N_Est + N_Grad * S_Est ) / ( N_Grad + S_Grad ); @@ -4126,10 +4131,10 @@ void RawImageSource::rcd_demosaic() for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col, c = 2 - FC( row, col ); col < width - 4; col += 2, indx += 2 ) { //Diagonal gradients - float NW_Grad = eps + fabs( rgb[indx - w1 - 1][c] - rgb[indx + w1 + 1][c] ) + fabs( rgb[indx - w1 - 1][c] - rgb[indx - w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 - 2][1] ); - float NE_Grad = eps + fabs( rgb[indx - w1 + 1][c] - rgb[indx + w1 - 1][c] ) + fabs( rgb[indx - w1 + 1][c] - rgb[indx - w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 + 2][1] ); - float SW_Grad = eps + fabs( rgb[indx + w1 - 1][c] - rgb[indx - w1 + 1][c] ) + fabs( rgb[indx + w1 - 1][c] - rgb[indx + w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 - 2][1] ); - float SE_Grad = eps + fabs( rgb[indx + w1 + 1][c] - rgb[indx - w1 - 1][c] ) + fabs( rgb[indx + w1 + 1][c] - rgb[indx + w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 + 2][1] ); + float NW_Grad = eps + (fabs( rgb[indx - w1 - 1][c] - rgb[indx + w1 + 1][c] ) + fabs( rgb[indx - w1 - 1][c] - rgb[indx - w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 - 2][1] )); + float NE_Grad = eps + (fabs( rgb[indx - w1 + 1][c] - rgb[indx + w1 - 1][c] ) + fabs( rgb[indx - w1 + 1][c] - rgb[indx - w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 + 2][1] )); + float SW_Grad = eps + (fabs( rgb[indx + w1 - 1][c] - rgb[indx - w1 + 1][c] ) + fabs( rgb[indx + w1 - 1][c] - rgb[indx + w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 - 2][1] )); + float SE_Grad = eps + (fabs( rgb[indx + w1 + 1][c] - rgb[indx - w1 - 1][c] ) + fabs( rgb[indx + w1 + 1][c] - rgb[indx + w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 + 2][1] )); //Diagonal colour differences float NW_Est = rgb[indx - w1 - 1][c] - rgb[indx - w1 - 1][1]; @@ -4158,10 +4163,10 @@ void RawImageSource::rcd_demosaic() for ( int c = 0; c <= 2; c += 2 ) { //Cardinal gradients - float N_Grad = eps + fabs( rgb[indx][1] - rgb[indx - w2][1] ) + fabs( rgb[indx - w1][c] - rgb[indx + w1][c] ) + fabs( rgb[indx - w1][c] - rgb[indx - w3][c] ); - float S_Grad = eps + fabs( rgb[indx][1] - rgb[indx + w2][1] ) + fabs( rgb[indx + w1][c] - rgb[indx - w1][c] ) + fabs( rgb[indx + w1][c] - rgb[indx + w3][c] ); - float W_Grad = eps + fabs( rgb[indx][1] - rgb[indx - 2][1] ) + fabs( rgb[indx - 1][c] - rgb[indx + 1][c] ) + fabs( rgb[indx - 1][c] - rgb[indx - 3][c] ); - float E_Grad = eps + fabs( rgb[indx][1] - rgb[indx + 2][1] ) + fabs( rgb[indx + 1][c] - rgb[indx - 1][c] ) + fabs( rgb[indx + 1][c] - rgb[indx + 3][c] ); + float N_Grad = eps + (fabs( rgb[indx][1] - rgb[indx - w2][1] ) + fabs( rgb[indx - w1][c] - rgb[indx + w1][c] ) + fabs( rgb[indx - w1][c] - rgb[indx - w3][c] )); + float S_Grad = eps + (fabs( rgb[indx][1] - rgb[indx + w2][1] ) + fabs( rgb[indx + w1][c] - rgb[indx - w1][c] ) + fabs( rgb[indx + w1][c] - rgb[indx + w3][c] )); + float W_Grad = eps + (fabs( rgb[indx][1] - rgb[indx - 2][1] ) + fabs( rgb[indx - 1][c] - rgb[indx + 1][c] ) + fabs( rgb[indx - 1][c] - rgb[indx - 3][c] )); + float E_Grad = eps + (fabs( rgb[indx][1] - rgb[indx + 2][1] ) + fabs( rgb[indx + 1][c] - rgb[indx - 1][c] ) + fabs( rgb[indx + 1][c] - rgb[indx + 3][c] )); //Cardinal colour differences float N_Est = rgb[indx - w1][c] - rgb[indx - w1][1]; From 4b6b806163a1df157600e741738ef09c60f78d86 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 24 Nov 2017 17:46:07 +0100 Subject: [PATCH 05/18] RCD: some tweaks to better fit in the RT way of dealing with highlight scaling --- rtengine/demosaic_algos.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index e1efcda86..c73f29415 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -3950,13 +3950,27 @@ void RawImageSource::rcd_demosaic() std::vector cfa(width * height); std::vector> rgb(width * height); + const float prescale = max(ref_pre_mul[0], ref_pre_mul[1], ref_pre_mul[2], ref_pre_mul[3]) / min(ref_pre_mul[0], ref_pre_mul[1], ref_pre_mul[2], ref_pre_mul[3]); + + auto clip = + [=](float v) -> float + { + v /= 65535.f; + float f = (1.f - LIM01(v * 0.25f)) * prescale; + if (f > 1e-4f) { + return LIM01(v * f) / f; + } else { + return LIM01(v); + } + }; + #ifdef _OPENMP #pragma omp parallel for #endif for (int row = 0; row < height; row++) { for (int col = 0, indx = row * width + col; col < width; col++, indx++) { int c = FC(row, col); - cfa[indx] = rgb[indx][c] = CLIP(rawData[row][col]) / 65535.f; + cfa[indx] = rgb[indx][c] = clip(rawData[row][col]); } } From 84379ffb7d6c46879fd466ae374c74aa6d051693 Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Mon, 27 Nov 2017 17:00:09 +0200 Subject: [PATCH 06/18] Removed histogram profile settings from preferences window. modified: ../rtgui/preferences.cc modified: ../rtgui/preferences.h --- rtgui/preferences.cc | 8 +------- rtgui/preferences.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 3f414321b..7e6018ff0 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -990,18 +990,14 @@ Gtk::Widget* Preferences::getGeneralPanel () ckbHistogramPositionLeft = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_HISTOGRAMPOSITIONLEFT")) ); setExpandAlignProperties (ckbHistogramPositionLeft, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - ckbHistogramWorking = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_HISTOGRAMWORKING")) ); - setExpandAlignProperties (ckbHistogramWorking, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - ckbHistogramWorking->set_tooltip_markup (M ("PREFERENCES_HISTOGRAM_TOOLTIP")); workflowGrid->attach_next_to (*ckbHistogramPositionLeft, *curveBBoxPosL, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*ckbHistogramWorking, *curveBBoxPosC, Gtk::POS_BOTTOM, 2, 1); ckbFileBrowserToolbarSingleRow = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW")) ); setExpandAlignProperties (ckbFileBrowserToolbarSingleRow, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); ckbShowFilmStripToolBar = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SHOWFILMSTRIPTOOLBAR")) ); setExpandAlignProperties (ckbShowFilmStripToolBar, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); workflowGrid->attach_next_to (*ckbFileBrowserToolbarSingleRow, *ckbHistogramPositionLeft, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*ckbShowFilmStripToolBar, *ckbHistogramWorking, Gtk::POS_BOTTOM, 2, 1); + workflowGrid->attach_next_to (*ckbShowFilmStripToolBar, *curveBBoxPosC, Gtk::POS_BOTTOM, 2, 1); Gtk::Label* hb4label = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_TP_LABEL")) ); setExpandAlignProperties (hb4label, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); @@ -1757,7 +1753,6 @@ void Preferences::storePreferences () // moptions.rtSettings.viewinggreySc = greySc->get_active_row_number (); // moptions.rtSettings.autocielab = cbAutocielab->get_active (); moptions.rtSettings.ciecamfloat = cbciecamfloat->get_active (); - moptions.rtSettings.HistogramWorking = ckbHistogramWorking->get_active (); moptions.rtSettings.leveldnv = dnv->get_active_row_number (); moptions.rtSettings.leveldnti = dnti->get_active_row_number (); moptions.rtSettings.leveldnliss = dnliss->get_active_row_number (); @@ -1928,7 +1923,6 @@ void Preferences::fillPreferences () // cbAutocielab->set_active (moptions.rtSettings.autocielab); cbciecamfloat->set_active (moptions.rtSettings.ciecamfloat); - ckbHistogramWorking->set_active (moptions.rtSettings.HistogramWorking); languages->set_active_text (moptions.language); ckbLangAutoDetect->set_active (moptions.languageAutoDetect); int themeNbr = getThemeRowNumber (moptions.theme); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index b3efd8b6a..70cef4bee 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -195,7 +195,6 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::ComboBoxText* custProfBuilderLabelType; Gtk::CheckButton* ckbHistogramPositionLeft; - Gtk::CheckButton* ckbHistogramWorking; Gtk::CheckButton* ckbFileBrowserToolbarSingleRow; Gtk::CheckButton* ckbShowFilmStripToolBar; Gtk::CheckButton* ckbHideTPVScrollbar; From 4c76c7456f9cc6707450606d52c7c735a50d54da Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Mon, 27 Nov 2017 17:00:51 +0200 Subject: [PATCH 07/18] Added a histogram profile settings toggle button. Now working histogram profile can be changed without entering the preferences window. modified: ../rtgui/editorpanel.cc modified: ../rtgui/editorpanel.h --- rtgui/editorpanel.cc | 17 +++++++++++++++++ rtgui/editorpanel.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index cf5dcba89..21286ca01 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -585,6 +585,13 @@ EditorPanel::EditorPanel (FilePanel* filePanel) Gtk::VSeparator* vsep1 = Gtk::manage (new Gtk::VSeparator ()); Gtk::VSeparator* vsep2 = Gtk::manage (new Gtk::VSeparator ()); + // Histogram profile toggle controls + toggleHistogramProfile = Gtk::manage (new Gtk::ToggleButton ()); + toggleHistogramProfile->set_relief(Gtk::RELIEF_NONE); + toggleHistogramProfile->set_active(options.rtSettings.HistogramWorking); + + Gtk::VSeparator* vsep3 = Gtk::manage (new Gtk::VSeparator ()); + iareapanel = new ImageAreaPanel (); tpc->setEditProvider (iareapanel->imageArea); tpc->getToolBar()->setLockablePickerToolListener (iareapanel->imageArea); @@ -607,6 +614,10 @@ EditorPanel::EditorPanel (FilePanel* filePanel) toolBarPanel->pack_end (*tpc->coarse, Gtk::PACK_SHRINK, 2); toolBarPanel->pack_end (*vsepcl, Gtk::PACK_SHRINK, 2); + // Histogram profile toggle + toolBarPanel->pack_end (*toggleHistogramProfile, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_end (*vsep3, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_end (*iareapanel->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0); toolBarPanel->pack_end (*vsepz, Gtk::PACK_SHRINK, 2); toolBarPanel->pack_end (*iareapanel->imageArea->previewModePanel, Gtk::PACK_SHRINK, 0); @@ -819,6 +830,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) ); queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) ); sendtogimp->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::sendToGimpPressed) ); + toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) ); if (navPrev) { navPrev->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::openPreviousEditorImage) ); @@ -2015,6 +2027,11 @@ void EditorPanel::syncFileBrowser() // synchronize filebrowser with image in E } } +void EditorPanel::histogramProfile_toggled() +{ + options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active(); +} + bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname) { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 5beb9ee7d..9ccbbef2d 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -115,6 +115,7 @@ public: void openNextEditorImage (); void openPreviousEditorImage (); void syncFileBrowser (); + void histogramProfile_toggled (); void tbTopPanel_1_visible (bool visible); bool CheckSidePanelsVisibility(); @@ -196,6 +197,7 @@ private: Gtk::HBox* beforeAfterBox; Gtk::HBox* beforeHeaderBox; Gtk::HBox* afterHeaderBox; + Gtk::ToggleButton* toggleHistogramProfile; Gtk::Frame* ppframe; ProfilePanel* profilep; From f071d321fdf61f1536b958bc8b44a9c087d8d44f Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Mon, 27 Nov 2017 17:38:09 +0200 Subject: [PATCH 08/18] Added tooltip for histogram profile toggle button --- rtgui/editorpanel.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 21286ca01..855458b93 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -587,8 +587,9 @@ EditorPanel::EditorPanel (FilePanel* filePanel) // Histogram profile toggle controls toggleHistogramProfile = Gtk::manage (new Gtk::ToggleButton ()); - toggleHistogramProfile->set_relief(Gtk::RELIEF_NONE); - toggleHistogramProfile->set_active(options.rtSettings.HistogramWorking); + toggleHistogramProfile->set_relief (Gtk::RELIEF_NONE); + toggleHistogramProfile->set_active (options.rtSettings.HistogramWorking); + toggleHistogramProfile->set_tooltip_markup ( (M ("PREFERENCES_HISTOGRAM_TOOLTIP"))); Gtk::VSeparator* vsep3 = Gtk::manage (new Gtk::VSeparator ()); From 6512b9f5fff7aaed9ec7f4ad667309a5631f67f6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 30 Nov 2017 23:15:20 +0100 Subject: [PATCH 09/18] updated RCD to the latest version (plus tweaks to avoid division by zero) --- rtengine/demosaic_algos.cc | 251 ++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 127 deletions(-) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index c73f29415..a21ff216d 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -3932,7 +3932,7 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b * RATIO CORRECTED DEMOSAICING * Luis Sanz Rodriguez (luis.sanz.rodriguez(at)gmail(dot)com) * -* Release 2.2 @ 171117 +* Release 2.3 @ 171125 * * Original code from https://github.com/LuisSR/RCD-Demosaicing * Licensed under the GNU GPL version 3 @@ -3950,27 +3950,13 @@ void RawImageSource::rcd_demosaic() std::vector cfa(width * height); std::vector> rgb(width * height); - const float prescale = max(ref_pre_mul[0], ref_pre_mul[1], ref_pre_mul[2], ref_pre_mul[3]) / min(ref_pre_mul[0], ref_pre_mul[1], ref_pre_mul[2], ref_pre_mul[3]); - - auto clip = - [=](float v) -> float - { - v /= 65535.f; - float f = (1.f - LIM01(v * 0.25f)) * prescale; - if (f > 1e-4f) { - return LIM01(v * f) / f; - } else { - return LIM01(v); - } - }; - #ifdef _OPENMP #pragma omp parallel for #endif for (int row = 0; row < height; row++) { for (int col = 0, indx = row * width + col; col < width; col++, indx++) { int c = FC(row, col); - cfa[indx] = rgb[indx][c] = clip(rawData[row][col]); + cfa[indx] = rgb[indx][c] = LIM01(rawData[row][col] / 65535.f); } } @@ -3997,7 +3983,7 @@ void RawImageSource::rcd_demosaic() //float V_Stat, H_Stat, P_Stat, Q_Stat; float VH_Central_Value, VH_Neighbour_Value, PQ_Central_Value, PQ_Neighbour_Value; */ - float ( *VH_Dir ), ( *VH_Disc ), ( *PQ_Dir ), ( *PQ_Disc ); + float ( *VH_Dir ), ( *PQ_Dir ); //Low pass filter float ( *lpf ); @@ -4008,31 +3994,18 @@ void RawImageSource::rcd_demosaic() */ VH_Dir = ( float ( * ) ) calloc( width * height, sizeof *VH_Dir ); //merror ( VH_Dir, "rcd_demosaicing_171117()" ); - PQ_Dir = ( float ( * ) ) calloc( width * height, sizeof *PQ_Dir ); //merror ( PQ_Dir, "rcd_demosaicing_171117()" ); #ifdef _OPENMP #pragma omp parallel for #endif for (int row = 4; row < height - 4; row++ ) { for (int col = 4, indx = row * width + col; col < width - 4; col++, indx++ ) { - //Calculate h/v local discrimination - float V_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - w1] - 18.0f * cfa[indx] * cfa[indx + w1] - 36.0f * cfa[indx] * cfa[indx - w2] - 36.0f * cfa[indx] * cfa[indx + w2] + 18.0f * cfa[indx] * cfa[indx - w3] + 18.0f * cfa[indx] * cfa[indx + w3] - 2.0f * cfa[indx] * cfa[indx - w4] - 2.0f * cfa[indx] * cfa[indx + w4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1] * cfa[indx + w1] - 12.0f * cfa[indx - w1] * cfa[indx - w2] + 24.0f * cfa[indx - w1] * cfa[indx + w2] - 38.0f * cfa[indx - w1] * cfa[indx - w3] + 16.0f * cfa[indx - w1] * cfa[indx + w3] + 12.0f * cfa[indx - w1] * cfa[indx - w4] - 6.0f * cfa[indx - w1] * cfa[indx + w4] + 46.0f * cfa[indx - w1] * cfa[indx - w1] + 24.0f * cfa[indx + w1] * cfa[indx - w2] - 12.0f * cfa[indx + w1] * cfa[indx + w2] + 16.0f * cfa[indx + w1] * cfa[indx - w3] - 38.0f * cfa[indx + w1] * cfa[indx + w3] - 6.0f * cfa[indx + w1] * cfa[indx - w4] + 12.0f * cfa[indx + w1] * cfa[indx + w4] + 46.0f * cfa[indx + w1] * cfa[indx + w1] + 14.0f * cfa[indx - w2] * cfa[indx + w2] - 12.0f * cfa[indx - w2] * cfa[indx + w3] - 2.0f * cfa[indx - w2] * cfa[indx - w4] + 2.0f * cfa[indx - w2] * cfa[indx + w4] + 11.0f * cfa[indx - w2] * cfa[indx - w2] - 12.0f * cfa[indx + w2] * cfa[indx - w3] + 2.0f * cfa[indx + w2] * cfa[indx - w4] - 2.0f * cfa[indx + w2] * cfa[indx + w4] + 11.0f * cfa[indx + w2] * cfa[indx + w2] + 2.0f * cfa[indx - w3] * cfa[indx + w3] - 6.0f * cfa[indx - w3] * cfa[indx - w4] + 10.0f * cfa[indx - w3] * cfa[indx - w3] - 6.0f * cfa[indx + w3] * cfa[indx + w4] + 10.0f * cfa[indx + w3] * cfa[indx + w3] + 1.0f * cfa[indx - w4] * cfa[indx - w4] + 1.0f * cfa[indx + w4] * cfa[indx + w4]); + float V_Stat = max(epssq, - 18.0f * cfa[indx] * cfa[indx - w1] - 18.0f * cfa[indx] * cfa[indx + w1] - 36.0f * cfa[indx] * cfa[indx - w2] - 36.0f * cfa[indx] * cfa[indx + w2] + 18.0f * cfa[indx] * cfa[indx - w3] + 18.0f * cfa[indx] * cfa[indx + w3] - 2.0f * cfa[indx] * cfa[indx - w4] - 2.0f * cfa[indx] * cfa[indx + w4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1] * cfa[indx + w1] - 12.0f * cfa[indx - w1] * cfa[indx - w2] + 24.0f * cfa[indx - w1] * cfa[indx + w2] - 38.0f * cfa[indx - w1] * cfa[indx - w3] + 16.0f * cfa[indx - w1] * cfa[indx + w3] + 12.0f * cfa[indx - w1] * cfa[indx - w4] - 6.0f * cfa[indx - w1] * cfa[indx + w4] + 46.0f * cfa[indx - w1] * cfa[indx - w1] + 24.0f * cfa[indx + w1] * cfa[indx - w2] - 12.0f * cfa[indx + w1] * cfa[indx + w2] + 16.0f * cfa[indx + w1] * cfa[indx - w3] - 38.0f * cfa[indx + w1] * cfa[indx + w3] - 6.0f * cfa[indx + w1] * cfa[indx - w4] + 12.0f * cfa[indx + w1] * cfa[indx + w4] + 46.0f * cfa[indx + w1] * cfa[indx + w1] + 14.0f * cfa[indx - w2] * cfa[indx + w2] - 12.0f * cfa[indx - w2] * cfa[indx + w3] - 2.0f * cfa[indx - w2] * cfa[indx - w4] + 2.0f * cfa[indx - w2] * cfa[indx + w4] + 11.0f * cfa[indx - w2] * cfa[indx - w2] - 12.0f * cfa[indx + w2] * cfa[indx - w3] + 2.0f * cfa[indx + w2] * cfa[indx - w4] - 2.0f * cfa[indx + w2] * cfa[indx + w4] + 11.0f * cfa[indx + w2] * cfa[indx + w2] + 2.0f * cfa[indx - w3] * cfa[indx + w3] - 6.0f * cfa[indx - w3] * cfa[indx - w4] + 10.0f * cfa[indx - w3] * cfa[indx - w3] - 6.0f * cfa[indx + w3] * cfa[indx + w4] + 10.0f * cfa[indx + w3] * cfa[indx + w3] + 1.0f * cfa[indx - w4] * cfa[indx - w4] + 1.0f * cfa[indx + w4] * cfa[indx + w4]); - float H_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - 1] - 18.0f * cfa[indx] * cfa[indx + 1] - 36.0f * cfa[indx] * cfa[indx - 2] - 36.0f * cfa[indx] * cfa[indx + 2] + 18.0f * cfa[indx] * cfa[indx - 3] + 18.0f * cfa[indx] * cfa[indx + 3] - 2.0f * cfa[indx] * cfa[indx - 4] - 2.0f * cfa[indx] * cfa[indx + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - 1] * cfa[indx + 1] - 12.0f * cfa[indx - 1] * cfa[indx - 2] + 24.0f * cfa[indx - 1] * cfa[indx + 2] - 38.0f * cfa[indx - 1] * cfa[indx - 3] + 16.0f * cfa[indx - 1] * cfa[indx + 3] + 12.0f * cfa[indx - 1] * cfa[indx - 4] - 6.0f * cfa[indx - 1] * cfa[indx + 4] + 46.0f * cfa[indx - 1] * cfa[indx - 1] + 24.0f * cfa[indx + 1] * cfa[indx - 2] - 12.0f * cfa[indx + 1] * cfa[indx + 2] + 16.0f * cfa[indx + 1] * cfa[indx - 3] - 38.0f * cfa[indx + 1] * cfa[indx + 3] - 6.0f * cfa[indx + 1] * cfa[indx - 4] + 12.0f * cfa[indx + 1] * cfa[indx + 4] + 46.0f * cfa[indx + 1] * cfa[indx + 1] + 14.0f * cfa[indx - 2] * cfa[indx + 2] - 12.0f * cfa[indx - 2] * cfa[indx + 3] - 2.0f * cfa[indx - 2] * cfa[indx - 4] + 2.0f * cfa[indx - 2] * cfa[indx + 4] + 11.0f * cfa[indx - 2] * cfa[indx - 2] - 12.0f * cfa[indx + 2] * cfa[indx - 3] + 2.0f * cfa[indx + 2] * cfa[indx - 4] - 2.0f * cfa[indx + 2] * cfa[indx + 4] + 11.0f * cfa[indx + 2] * cfa[indx + 2] + 2.0f * cfa[indx - 3] * cfa[indx + 3] - 6.0f * cfa[indx - 3] * cfa[indx - 4] + 10.0f * cfa[indx - 3] * cfa[indx - 3] - 6.0f * cfa[indx + 3] * cfa[indx + 4] + 10.0f * cfa[indx + 3] * cfa[indx + 3] + 1.0f * cfa[indx - 4] * cfa[indx - 4] + 1.0f * cfa[indx + 4] * cfa[indx + 4]); + float H_Stat = max(epssq, - 18.0f * cfa[indx] * cfa[indx - 1] - 18.0f * cfa[indx] * cfa[indx + 1] - 36.0f * cfa[indx] * cfa[indx - 2] - 36.0f * cfa[indx] * cfa[indx + 2] + 18.0f * cfa[indx] * cfa[indx - 3] + 18.0f * cfa[indx] * cfa[indx + 3] - 2.0f * cfa[indx] * cfa[indx - 4] - 2.0f * cfa[indx] * cfa[indx + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - 1] * cfa[indx + 1] - 12.0f * cfa[indx - 1] * cfa[indx - 2] + 24.0f * cfa[indx - 1] * cfa[indx + 2] - 38.0f * cfa[indx - 1] * cfa[indx - 3] + 16.0f * cfa[indx - 1] * cfa[indx + 3] + 12.0f * cfa[indx - 1] * cfa[indx - 4] - 6.0f * cfa[indx - 1] * cfa[indx + 4] + 46.0f * cfa[indx - 1] * cfa[indx - 1] + 24.0f * cfa[indx + 1] * cfa[indx - 2] - 12.0f * cfa[indx + 1] * cfa[indx + 2] + 16.0f * cfa[indx + 1] * cfa[indx - 3] - 38.0f * cfa[indx + 1] * cfa[indx + 3] - 6.0f * cfa[indx + 1] * cfa[indx - 4] + 12.0f * cfa[indx + 1] * cfa[indx + 4] + 46.0f * cfa[indx + 1] * cfa[indx + 1] + 14.0f * cfa[indx - 2] * cfa[indx + 2] - 12.0f * cfa[indx - 2] * cfa[indx + 3] - 2.0f * cfa[indx - 2] * cfa[indx - 4] + 2.0f * cfa[indx - 2] * cfa[indx + 4] + 11.0f * cfa[indx - 2] * cfa[indx - 2] - 12.0f * cfa[indx + 2] * cfa[indx - 3] + 2.0f * cfa[indx + 2] * cfa[indx - 4] - 2.0f * cfa[indx + 2] * cfa[indx + 4] + 11.0f * cfa[indx + 2] * cfa[indx + 2] + 2.0f * cfa[indx - 3] * cfa[indx + 3] - 6.0f * cfa[indx - 3] * cfa[indx - 4] + 10.0f * cfa[indx - 3] * cfa[indx - 3] - 6.0f * cfa[indx + 3] * cfa[indx + 4] + 10.0f * cfa[indx + 3] * cfa[indx + 3] + 1.0f * cfa[indx - 4] * cfa[indx - 4] + 1.0f * cfa[indx + 4] * cfa[indx + 4]); VH_Dir[indx] = V_Stat / (V_Stat + H_Stat); - - //Calculate m/p local discrimination - float P_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx - w1 - 1] - 18.0f * cfa[indx] * cfa[indx + w1 + 1] - 36.0f * cfa[indx] * cfa[indx - w2 - 2] - 36.0f * cfa[indx] * cfa[indx + w2 + 2] + 18.0f * cfa[indx] * cfa[indx - w3 - 3] + 18.0f * cfa[indx] * cfa[indx + w3 + 3] - 2.0f * cfa[indx] * cfa[indx - w4 - 4] - 2.0f * cfa[indx] * cfa[indx + w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx - w1 - 1] * cfa[indx + w1 + 1] - 12.0f * cfa[indx - w1 - 1] * cfa[indx - w2 - 2] + 24.0f * cfa[indx - w1 - 1] * cfa[indx + w2 + 2] - 38.0f * cfa[indx - w1 - 1] * cfa[indx - w3 - 3] + 16.0f * cfa[indx - w1 - 1] * cfa[indx + w3 + 3] + 12.0f * cfa[indx - w1 - 1] * cfa[indx - w4 - 4] - 6.0f * cfa[indx - w1 - 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx - w1 - 1] * cfa[indx - w1 - 1] + 24.0f * cfa[indx + w1 + 1] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w1 + 1] * cfa[indx + w2 + 2] + 16.0f * cfa[indx + w1 + 1] * cfa[indx - w3 - 3] - 38.0f * cfa[indx + w1 + 1] * cfa[indx + w3 + 3] - 6.0f * cfa[indx + w1 + 1] * cfa[indx - w4 - 4] + 12.0f * cfa[indx + w1 + 1] * cfa[indx + w4 + 4] + 46.0f * cfa[indx + w1 + 1] * cfa[indx + w1 + 1] + 14.0f * cfa[indx - w2 - 2] * cfa[indx + w2 + 2] - 12.0f * cfa[indx - w2 - 2] * cfa[indx + w3 + 3] - 2.0f * cfa[indx - w2 - 2] * cfa[indx - w4 - 4] + 2.0f * cfa[indx - w2 - 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx - w2 - 2] * cfa[indx - w2 - 2] - 12.0f * cfa[indx + w2 + 2] * cfa[indx - w3 - 3] + 2 * cfa[indx + w2 + 2] * cfa[indx - w4 - 4] - 2.0f * cfa[indx + w2 + 2] * cfa[indx + w4 + 4] + 11.0f * cfa[indx + w2 + 2] * cfa[indx + w2 + 2] + 2.0f * cfa[indx - w3 - 3] * cfa[indx + w3 + 3] - 6.0f * cfa[indx - w3 - 3] * cfa[indx - w4 - 4] + 10.0f * cfa[indx - w3 - 3] * cfa[indx - w3 - 3] - 6.0f * cfa[indx + w3 + 3] * cfa[indx + w4 + 4] + 10.0f * cfa[indx + w3 + 3] * cfa[indx + w3 + 3] + 1.0f * cfa[indx - w4 - 4] * cfa[indx - w4 - 4] + 1.0f * cfa[indx + w4 + 4] * cfa[indx + w4 + 4]); - - float Q_Stat = epssq + (- 18.0f * cfa[indx] * cfa[indx + w1 - 1] - 18.0f * cfa[indx] * cfa[indx - w1 + 1] - 36.0f * cfa[indx] * cfa[indx + w2 - 2] - 36.0f * cfa[indx] * cfa[indx - w2 + 2] + 18.0f * cfa[indx] * cfa[indx + w3 - 3] + 18.0f * cfa[indx] * cfa[indx - w3 + 3] - 2.0f * cfa[indx] * cfa[indx + w4 - 4] - 2.0f * cfa[indx] * cfa[indx - w4 + 4] + 38.0f * cfa[indx] * cfa[indx] - 70.0f * cfa[indx + w1 - 1] * cfa[indx - w1 + 1] - 12.0f * cfa[indx + w1 - 1] * cfa[indx + w2 - 2] + 24.0f * cfa[indx + w1 - 1] * cfa[indx - w2 + 2] - 38.0f * cfa[indx + w1 - 1] * cfa[indx + w3 - 3] + 16.0f * cfa[indx + w1 - 1] * cfa[indx - w3 + 3] + 12.0f * cfa[indx + w1 - 1] * cfa[indx + w4 - 4] - 6.0f * cfa[indx + w1 - 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx + w1 - 1] * cfa[indx + w1 - 1] + 24.0f * cfa[indx - w1 + 1] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w1 + 1] * cfa[indx - w2 + 2] + 16.0f * cfa[indx - w1 + 1] * cfa[indx + w3 - 3] - 38.0f * cfa[indx - w1 + 1] * cfa[indx - w3 + 3] - 6.0f * cfa[indx - w1 + 1] * cfa[indx + w4 - 4] + 12.0f * cfa[indx - w1 + 1] * cfa[indx - w4 + 4] + 46.0f * cfa[indx - w1 + 1] * cfa[indx - w1 + 1] + 14.0f * cfa[indx + w2 - 2] * cfa[indx - w2 + 2] - 12.0f * cfa[indx + w2 - 2] * cfa[indx - w3 + 3] - 2.0f * cfa[indx + w2 - 2] * cfa[indx + w4 - 4] + 2.0f * cfa[indx + w2 - 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx + w2 - 2] * cfa[indx + w2 - 2] - 12.0f * cfa[indx - w2 + 2] * cfa[indx + w3 - 3] + 2 * cfa[indx - w2 + 2] * cfa[indx + w4 - 4] - 2.0f * cfa[indx - w2 + 2] * cfa[indx - w4 + 4] + 11.0f * cfa[indx - w2 + 2] * cfa[indx - w2 + 2] + 2.0f * cfa[indx + w3 - 3] * cfa[indx - w3 + 3] - 6.0f * cfa[indx + w3 - 3] * cfa[indx + w4 - 4] + 10.0f * cfa[indx + w3 - 3] * cfa[indx + w3 - 3] - 6.0f * cfa[indx - w3 + 3] * cfa[indx - w4 + 4] + 10.0f * cfa[indx - w3 + 3] * cfa[indx - w3 + 3] + 1.0f * cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + 1.0f * cfa[indx - w4 + 4] * cfa[indx - w4 + 4]); - - PQ_Dir[indx] = P_Stat / ( P_Stat + Q_Stat ); - - assert(isfinite(VH_Dir[indx])); - assert(isfinite(PQ_Dir[indx])); - } } @@ -4041,91 +4014,66 @@ void RawImageSource::rcd_demosaic() plistener->setProgress(0.2); } // ------------------------------------------------------------------------- - - VH_Disc = ( float ( * ) ) calloc( width * height, sizeof *VH_Disc ); //merror ( VH_Disc, "rcd_demosaicing_171117()" ); - PQ_Disc = ( float ( * ) ) calloc( width * height, sizeof *PQ_Disc ); //merror ( PQ_Disc, "rcd_demosaicing_171117()" ); + /** + * STEP 2: Calculate the low pass filter + */ + + // Step 2.1: Low pass filter incorporating green, red and blue local samples from the raw data + lpf = ( float ( * ) ) calloc( width * height, sizeof *lpf ); //merror ( lpf, "rcd_demosaicing_171125()" ); #ifdef _OPENMP #pragma omp parallel for -#endif - for ( int row = 4; row < height - 4; row++ ) { - for ( int col = 4, indx = row * width + col; col < width - 4; col++, indx++ ) { +#endif + for ( int row = 2; row < height - 2; row++ ) { + for ( int col = 2 + (FC( row, 0 ) & 1), indx = row * width + col; col < width - 2; col += 2, indx += 2 ) { - //Refined h/v local discrimination - float VH_Central_Value = VH_Dir[indx]; - float VH_Neighbour_Value = 0.25f * (VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1] + VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1]); - - VH_Disc[indx] = ( fabs( 0.5f - VH_Central_Value ) < fabs( 0.5f - VH_Neighbour_Value ) ) ? VH_Neighbour_Value : VH_Central_Value; - - //Refined m/p local discrimination - float PQ_Central_Value = PQ_Dir[indx]; - float PQ_Neighbour_Value = 0.25f * (PQ_Dir[indx - w1 - 1] + PQ_Dir[indx - w1 + 1] + PQ_Dir[indx + w1 - 1] + PQ_Dir[indx + w1 + 1]); - - PQ_Disc[indx] = ( fabs( 0.5f - PQ_Central_Value ) < fabs( 0.5f - PQ_Neighbour_Value ) ) ? PQ_Neighbour_Value : PQ_Central_Value; + lpf[indx] = 0.25f * cfa[indx] + 0.125f * ( cfa[indx - w1] + cfa[indx + w1] + cfa[indx - 1] + cfa[indx + 1] ) + 0.0625f * ( cfa[indx - w1 - 1] + cfa[indx - w1 + 1] + cfa[indx + w1 - 1] + cfa[indx + w1 + 1] ); } } - free( VH_Dir ); - free( PQ_Dir ); - // RT --------------------------------------------------------------------- if (plistener) { plistener->setProgress(0.4); } // ------------------------------------------------------------------------ - /** - * STEP 2: Calculate the low pass filter - */ - - lpf = ( float ( * ) ) calloc( width * height, sizeof *lpf ); //merror ( lpf, "rcd_demosaicing_171117()" ); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - for ( int row = 1; row < height - 1; row++ ) { - for ( int col = 1, indx = row * width + col; col < width - 1; col++, indx++ ) { - - //Low pass filter incorporating red and blue local samples - lpf[indx] = 0.25f * cfa[indx] + 0.125f * ( cfa[indx - w1] + cfa[indx + w1] + cfa[indx - 1] + cfa[indx + 1] ) + 0.0625f * ( cfa[indx - w1 - 1] + cfa[indx - w1 + 1] + cfa[indx + w1 - 1] + cfa[indx + w1 + 1] ); - - } - } - - // RT --------------------------------------------------------------------- - if (plistener) { - plistener->setProgress(0.5); - } - // ------------------------------------------------------------------------ - /** * STEP 3: Populate the green channel */ + + // Step 3.1: Populate the green channel at blue and red CFA positions #ifdef _OPENMP #pragma omp parallel for #endif - for ( int row = 4; row < height - 4; row++ ) { - for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4 + (FC( row, 0 ) & 1), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { - //Cardinal gradients - float N_Grad = eps + (fabs( cfa[indx - w1] - cfa[indx + w1] ) + fabs( cfa[indx] - cfa[indx - w2] ) + fabs( cfa[indx - w1] - cfa[indx - w3] ) + fabs( cfa[indx - w2] - cfa[indx - w4] )); - float S_Grad = eps + (fabs( cfa[indx + w1] - cfa[indx - w1] ) + fabs( cfa[indx] - cfa[indx + w2] ) + fabs( cfa[indx + w1] - cfa[indx + w3] ) + fabs( cfa[indx + w2] - cfa[indx + w4] )); - float W_Grad = eps + (fabs( cfa[indx - 1] - cfa[indx + 1] ) + fabs( cfa[indx] - cfa[indx - 2] ) + fabs( cfa[indx - 1] - cfa[indx - 3] ) + fabs( cfa[indx - 2] - cfa[indx - 4] )); - float E_Grad = eps + (fabs( cfa[indx + 1] - cfa[indx - 1] ) + fabs( cfa[indx] - cfa[indx + 2] ) + fabs( cfa[indx + 1] - cfa[indx + 3] ) + fabs( cfa[indx + 2] - cfa[indx + 4] )); + // Refined vertical and horizontal local discrimination + float VH_Central_Value = VH_Dir[indx]; + float VH_Neighbourhood_Value = 0.25f * ( VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1] + VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1] ); - //Cardinal pixel estimations - float N_Est = cfa[indx - w1] * ( 1.f + ( lpf[indx] - lpf[indx - w2] ) / ( eps + (lpf[indx] + lpf[indx - w2])) ); - float S_Est = cfa[indx + w1] * ( 1.f + ( lpf[indx] - lpf[indx + w2] ) / ( eps + (lpf[indx] + lpf[indx + w2])) ); - float W_Est = cfa[indx - 1] * ( 1.f + ( lpf[indx] - lpf[indx - 2] ) / ( eps + (lpf[indx] + lpf[indx - 2])) ); - float E_Est = cfa[indx + 1] * ( 1.f + ( lpf[indx] - lpf[indx + 2] ) / ( eps + (lpf[indx] + lpf[indx + 2])) ); + float VH_Disc = ( fabs( 0.5f - VH_Central_Value ) < fabs( 0.5f - VH_Neighbourhood_Value ) ) ? VH_Neighbourhood_Value : VH_Central_Value; - //Interpolate G@R & G@B - float V_Est = ( S_Grad * N_Est + N_Grad * S_Est ) / ( N_Grad + S_Grad ); - float H_Est = ( W_Grad * E_Est + E_Grad * W_Est ) / ( E_Grad + W_Grad ); + // Cardinal gradients + float N_Grad = eps + fabs( cfa[indx - w1] - cfa[indx + w1] ) + fabs( cfa[indx] - cfa[indx - w2] ) + fabs( cfa[indx - w1] - cfa[indx - w3] ) + fabs( cfa[indx - w2] - cfa[indx - w4] ); + float S_Grad = eps + fabs( cfa[indx + w1] - cfa[indx - w1] ) + fabs( cfa[indx] - cfa[indx + w2] ) + fabs( cfa[indx + w1] - cfa[indx + w3] ) + fabs( cfa[indx + w2] - cfa[indx + w4] ); + float W_Grad = eps + fabs( cfa[indx - 1] - cfa[indx + 1] ) + fabs( cfa[indx] - cfa[indx - 2] ) + fabs( cfa[indx - 1] - cfa[indx - 3] ) + fabs( cfa[indx - 2] - cfa[indx - 4] ); + float E_Grad = eps + fabs( cfa[indx + 1] - cfa[indx - 1] ) + fabs( cfa[indx] - cfa[indx + 2] ) + fabs( cfa[indx + 1] - cfa[indx + 3] ) + fabs( cfa[indx + 2] - cfa[indx + 4] ); - rgb[indx][1] = LIM( VH_Disc[indx] * H_Est + ( 1.0f - VH_Disc[indx] ) * V_Est, 0.f, 1.f ); + // Cardinal pixel estimations + float N_Est = cfa[indx - w1] * ( 1.f + ( lpf[indx] - lpf[indx - w2] ) / ( eps + lpf[indx] + lpf[indx - w2] ) ); + float S_Est = cfa[indx + w1] * ( 1.f + ( lpf[indx] - lpf[indx + w2] ) / ( eps + lpf[indx] + lpf[indx + w2] ) ); + float W_Est = cfa[indx - 1] * ( 1.f + ( lpf[indx] - lpf[indx - 2] ) / ( eps + lpf[indx] + lpf[indx - 2] ) ); + float E_Est = cfa[indx + 1] * ( 1.f + ( lpf[indx] - lpf[indx + 2] ) / ( eps + lpf[indx] + lpf[indx + 2] ) ); + + // Vertical and horizontal estimations + float V_Est = ( S_Grad * N_Est + N_Grad * S_Est ) / max(eps, N_Grad + S_Grad ); + float H_Est = ( W_Grad * E_Est + E_Grad * W_Est ) / max(eps, E_Grad + W_Grad ); + + // G@B and G@R interpolation + rgb[indx][1] = LIM( VH_Disc * H_Est + ( 1.f - VH_Disc ) * V_Est, 0.f, 1.f ); } } @@ -4134,72 +4082,119 @@ void RawImageSource::rcd_demosaic() // RT --------------------------------------------------------------------- if (plistener) { - plistener->setProgress(0.7); + plistener->setProgress(0.5); } - // ------------------------------------------------------------------------- - + // ------------------------------------------------------------------------ + /** - * STEP 4: Populate the red and blue channel + * STEP 4: Populate the red and blue channels */ + + // Step 4.1: Calculate P/Q diagonal local discrimination + PQ_Dir = ( float ( * ) ) calloc( width * height, sizeof *PQ_Dir ); //merror ( PQ_Dir, "rcd_demosaicing_171125()" ); + +#ifdef _OPENMP + #pragma omp parallel for +#endif for ( int row = 4; row < height - 4; row++ ) { - for ( int col = 4 + ( FC( row, 0 )&1 ), indx = row * width + col, c = 2 - FC( row, col ); col < width - 4; col += 2, indx += 2 ) { + for ( int col = 4 + (FC( row, 0 ) & 1), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { - //Diagonal gradients - float NW_Grad = eps + (fabs( rgb[indx - w1 - 1][c] - rgb[indx + w1 + 1][c] ) + fabs( rgb[indx - w1 - 1][c] - rgb[indx - w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 - 2][1] )); - float NE_Grad = eps + (fabs( rgb[indx - w1 + 1][c] - rgb[indx + w1 - 1][c] ) + fabs( rgb[indx - w1 + 1][c] - rgb[indx - w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 + 2][1] )); - float SW_Grad = eps + (fabs( rgb[indx + w1 - 1][c] - rgb[indx - w1 + 1][c] ) + fabs( rgb[indx + w1 - 1][c] - rgb[indx + w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 - 2][1] )); - float SE_Grad = eps + (fabs( rgb[indx + w1 + 1][c] - rgb[indx - w1 - 1][c] ) + fabs( rgb[indx + w1 + 1][c] - rgb[indx + w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 + 2][1] )); + float P_Stat = max( - 18.f * cfa[indx] * cfa[indx - w1 - 1] - 18.f * cfa[indx] * cfa[indx + w1 + 1] - 36.f * cfa[indx] * cfa[indx - w2 - 2] - 36.f * cfa[indx] * cfa[indx + w2 + 2] + 18.f * cfa[indx] * cfa[indx - w3 - 3] + 18.f * cfa[indx] * cfa[indx + w3 + 3] - 2.f * cfa[indx] * cfa[indx - w4 - 4] - 2.f * cfa[indx] * cfa[indx + w4 + 4] + 38.f * cfa[indx] * cfa[indx] - 70.f * cfa[indx - w1 - 1] * cfa[indx + w1 + 1] - 12.f * cfa[indx - w1 - 1] * cfa[indx - w2 - 2] + 24.f * cfa[indx - w1 - 1] * cfa[indx + w2 + 2] - 38.f * cfa[indx - w1 - 1] * cfa[indx - w3 - 3] + 16.f * cfa[indx - w1 - 1] * cfa[indx + w3 + 3] + 12.f * cfa[indx - w1 - 1] * cfa[indx - w4 - 4] - 6.f * cfa[indx - w1 - 1] * cfa[indx + w4 + 4] + 46.f * cfa[indx - w1 - 1] * cfa[indx - w1 - 1] + 24.f * cfa[indx + w1 + 1] * cfa[indx - w2 - 2] - 12.f * cfa[indx + w1 + 1] * cfa[indx + w2 + 2] + 16.f * cfa[indx + w1 + 1] * cfa[indx - w3 - 3] - 38.f * cfa[indx + w1 + 1] * cfa[indx + w3 + 3] - 6.f * cfa[indx + w1 + 1] * cfa[indx - w4 - 4] + 12.f * cfa[indx + w1 + 1] * cfa[indx + w4 + 4] + 46.f * cfa[indx + w1 + 1] * cfa[indx + w1 + 1] + 14.f * cfa[indx - w2 - 2] * cfa[indx + w2 + 2] - 12.f * cfa[indx - w2 - 2] * cfa[indx + w3 + 3] - 2.f * cfa[indx - w2 - 2] * cfa[indx - w4 - 4] + 2.f * cfa[indx - w2 - 2] * cfa[indx + w4 + 4] + 11.f * cfa[indx - w2 - 2] * cfa[indx - w2 - 2] - 12.f * cfa[indx + w2 + 2] * cfa[indx - w3 - 3] + 2 * cfa[indx + w2 + 2] * cfa[indx - w4 - 4] - 2.f * cfa[indx + w2 + 2] * cfa[indx + w4 + 4] + 11.f * cfa[indx + w2 + 2] * cfa[indx + w2 + 2] + 2.f * cfa[indx - w3 - 3] * cfa[indx + w3 + 3] - 6.f * cfa[indx - w3 - 3] * cfa[indx - w4 - 4] + 10.f * cfa[indx - w3 - 3] * cfa[indx - w3 - 3] - 6.f * cfa[indx + w3 + 3] * cfa[indx + w4 + 4] + 10.f * cfa[indx + w3 + 3] * cfa[indx + w3 + 3] + 1.f * cfa[indx - w4 - 4] * cfa[indx - w4 - 4] + 1.f * cfa[indx + w4 + 4] * cfa[indx + w4 + 4], epssq ); + float Q_Stat = max( - 18.f * cfa[indx] * cfa[indx + w1 - 1] - 18.f * cfa[indx] * cfa[indx - w1 + 1] - 36.f * cfa[indx] * cfa[indx + w2 - 2] - 36.f * cfa[indx] * cfa[indx - w2 + 2] + 18.f * cfa[indx] * cfa[indx + w3 - 3] + 18.f * cfa[indx] * cfa[indx - w3 + 3] - 2.f * cfa[indx] * cfa[indx + w4 - 4] - 2.f * cfa[indx] * cfa[indx - w4 + 4] + 38.f * cfa[indx] * cfa[indx] - 70.f * cfa[indx + w1 - 1] * cfa[indx - w1 + 1] - 12.f * cfa[indx + w1 - 1] * cfa[indx + w2 - 2] + 24.f * cfa[indx + w1 - 1] * cfa[indx - w2 + 2] - 38.f * cfa[indx + w1 - 1] * cfa[indx + w3 - 3] + 16.f * cfa[indx + w1 - 1] * cfa[indx - w3 + 3] + 12.f * cfa[indx + w1 - 1] * cfa[indx + w4 - 4] - 6.f * cfa[indx + w1 - 1] * cfa[indx - w4 + 4] + 46.f * cfa[indx + w1 - 1] * cfa[indx + w1 - 1] + 24.f * cfa[indx - w1 + 1] * cfa[indx + w2 - 2] - 12.f * cfa[indx - w1 + 1] * cfa[indx - w2 + 2] + 16.f * cfa[indx - w1 + 1] * cfa[indx + w3 - 3] - 38.f * cfa[indx - w1 + 1] * cfa[indx - w3 + 3] - 6.f * cfa[indx - w1 + 1] * cfa[indx + w4 - 4] + 12.f * cfa[indx - w1 + 1] * cfa[indx - w4 + 4] + 46.f * cfa[indx - w1 + 1] * cfa[indx - w1 + 1] + 14.f * cfa[indx + w2 - 2] * cfa[indx - w2 + 2] - 12.f * cfa[indx + w2 - 2] * cfa[indx - w3 + 3] - 2.f * cfa[indx + w2 - 2] * cfa[indx + w4 - 4] + 2.f * cfa[indx + w2 - 2] * cfa[indx - w4 + 4] + 11.f * cfa[indx + w2 - 2] * cfa[indx + w2 - 2] - 12.f * cfa[indx - w2 + 2] * cfa[indx + w3 - 3] + 2 * cfa[indx - w2 + 2] * cfa[indx + w4 - 4] - 2.f * cfa[indx - w2 + 2] * cfa[indx - w4 + 4] + 11.f * cfa[indx - w2 + 2] * cfa[indx - w2 + 2] + 2.f * cfa[indx + w3 - 3] * cfa[indx - w3 + 3] - 6.f * cfa[indx + w3 - 3] * cfa[indx + w4 - 4] + 10.f * cfa[indx + w3 - 3] * cfa[indx + w3 - 3] - 6.f * cfa[indx - w3 + 3] * cfa[indx - w4 + 4] + 10.f * cfa[indx - w3 + 3] * cfa[indx - w3 + 3] + 1.f * cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + 1.f * cfa[indx - w4 + 4] * cfa[indx - w4 + 4], epssq ); - //Diagonal colour differences - float NW_Est = rgb[indx - w1 - 1][c] - rgb[indx - w1 - 1][1]; - float NE_Est = rgb[indx - w1 + 1][c] - rgb[indx - w1 + 1][1]; - float SW_Est = rgb[indx + w1 - 1][c] - rgb[indx + w1 - 1][1]; - float SE_Est = rgb[indx + w1 + 1][c] - rgb[indx + w1 + 1][1]; - - //Interpolate R@B and B@R - float P_Est = ( NW_Grad * SE_Est + SE_Grad * NW_Est ) / ( NW_Grad + SE_Grad ); - float Q_Est = ( NE_Grad * SW_Est + SW_Grad * NE_Est ) / ( NE_Grad + SW_Grad ); - - rgb[indx][c] = LIM( rgb[indx][1] + ( 1.0f - PQ_Disc[indx] ) * P_Est + PQ_Disc[indx] * Q_Est, 0.f, 1.f ); + PQ_Dir[indx] = P_Stat / ( P_Stat + Q_Stat ); } } + // RT --------------------------------------------------------------------- + if (plistener) { + plistener->setProgress(0.7); + } + // ------------------------------------------------------------------------- + + // Step 4.2: Populate the red and blue channels at blue and red CFA positions +#ifdef _OPENMP + #pragma omp parallel for +#endif + for ( int row = 4; row < height - 4; row++ ) { + for ( int col = 4 + (FC( row, 0 ) & 1), indx = row * width + col, c = 2 - FC( row, col ); col < width - 4; col += 2, indx += 2 ) { + + // Refined P/Q diagonal local discrimination + float PQ_Central_Value = PQ_Dir[indx]; + float PQ_Neighbourhood_Value = 0.25f * ( PQ_Dir[indx - w1 - 1] + PQ_Dir[indx - w1 + 1] + PQ_Dir[indx + w1 - 1] + PQ_Dir[indx + w1 + 1] ); + + float PQ_Disc = ( fabs( 0.5f - PQ_Central_Value ) < fabs( 0.5f - PQ_Neighbourhood_Value ) ) ? PQ_Neighbourhood_Value : PQ_Central_Value; + + // Diagonal gradients + float NW_Grad = eps + fabs( rgb[indx - w1 - 1][c] - rgb[indx + w1 + 1][c] ) + fabs( rgb[indx - w1 - 1][c] - rgb[indx - w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 - 2][1] ); + float NE_Grad = eps + fabs( rgb[indx - w1 + 1][c] - rgb[indx + w1 - 1][c] ) + fabs( rgb[indx - w1 + 1][c] - rgb[indx - w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx - w2 + 2][1] ); + float SW_Grad = eps + fabs( rgb[indx + w1 - 1][c] - rgb[indx - w1 + 1][c] ) + fabs( rgb[indx + w1 - 1][c] - rgb[indx + w3 - 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 - 2][1] ); + float SE_Grad = eps + fabs( rgb[indx + w1 + 1][c] - rgb[indx - w1 - 1][c] ) + fabs( rgb[indx + w1 + 1][c] - rgb[indx + w3 + 3][c] ) + fabs( rgb[indx][1] - rgb[indx + w2 + 2][1] ); + + // Diagonal colour differences + float NW_Est = rgb[indx - w1 - 1][c] - rgb[indx - w1 - 1][1]; + float NE_Est = rgb[indx - w1 + 1][c] - rgb[indx - w1 + 1][1]; + float SW_Est = rgb[indx + w1 - 1][c] - rgb[indx + w1 - 1][1]; + float SE_Est = rgb[indx + w1 + 1][c] - rgb[indx + w1 + 1][1]; + + // P/Q estimations + float P_Est = ( NW_Grad * SE_Est + SE_Grad * NW_Est ) / max(eps, NW_Grad + SE_Grad ); + float Q_Est = ( NE_Grad * SW_Est + SW_Grad * NE_Est ) / max(eps, NE_Grad + SW_Grad ); + + // R@B and B@R interpolation + rgb[indx][c] = LIM( rgb[indx][1] + ( 1.f - PQ_Disc ) * P_Est + PQ_Disc * Q_Est, 0.f, 1.f ); + + } + } + + free( PQ_Dir ); + // RT --------------------------------------------------------------------- if (plistener) { plistener->setProgress(0.825); } // ------------------------------------------------------------------------- - + + // Step 4.3: Populate the red and blue channels at green CFA positions +#ifdef _OPENMP + #pragma omp parallel for +#endif for ( int row = 4; row < height - 4; row++ ) { - for ( int col = 4 + ( FC( row, 1 )&1 ), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { + for ( int col = 4 + (FC( row, 1 ) & 1), indx = row * width + col; col < width - 4; col += 2, indx += 2 ) { + + // Refined vertical and horizontal local discrimination + float VH_Central_Value = VH_Dir[indx]; + float VH_Neighbourhood_Value = 0.25f * ( VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1] + VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1] ); + + float VH_Disc = ( fabs( 0.5f - VH_Central_Value ) < fabs( 0.5f - VH_Neighbourhood_Value ) ) ? VH_Neighbourhood_Value : VH_Central_Value; for ( int c = 0; c <= 2; c += 2 ) { - //Cardinal gradients - float N_Grad = eps + (fabs( rgb[indx][1] - rgb[indx - w2][1] ) + fabs( rgb[indx - w1][c] - rgb[indx + w1][c] ) + fabs( rgb[indx - w1][c] - rgb[indx - w3][c] )); - float S_Grad = eps + (fabs( rgb[indx][1] - rgb[indx + w2][1] ) + fabs( rgb[indx + w1][c] - rgb[indx - w1][c] ) + fabs( rgb[indx + w1][c] - rgb[indx + w3][c] )); - float W_Grad = eps + (fabs( rgb[indx][1] - rgb[indx - 2][1] ) + fabs( rgb[indx - 1][c] - rgb[indx + 1][c] ) + fabs( rgb[indx - 1][c] - rgb[indx - 3][c] )); - float E_Grad = eps + (fabs( rgb[indx][1] - rgb[indx + 2][1] ) + fabs( rgb[indx + 1][c] - rgb[indx - 1][c] ) + fabs( rgb[indx + 1][c] - rgb[indx + 3][c] )); + // Cardinal gradients + float N_Grad = eps + fabs( rgb[indx][1] - rgb[indx - w2][1] ) + fabs( rgb[indx - w1][c] - rgb[indx + w1][c] ) + fabs( rgb[indx - w1][c] - rgb[indx - w3][c] ); + float S_Grad = eps + fabs( rgb[indx][1] - rgb[indx + w2][1] ) + fabs( rgb[indx + w1][c] - rgb[indx - w1][c] ) + fabs( rgb[indx + w1][c] - rgb[indx + w3][c] ); + float W_Grad = eps + fabs( rgb[indx][1] - rgb[indx - 2][1] ) + fabs( rgb[indx - 1][c] - rgb[indx + 1][c] ) + fabs( rgb[indx - 1][c] - rgb[indx - 3][c] ); + float E_Grad = eps + fabs( rgb[indx][1] - rgb[indx + 2][1] ) + fabs( rgb[indx + 1][c] - rgb[indx - 1][c] ) + fabs( rgb[indx + 1][c] - rgb[indx + 3][c] ); - //Cardinal colour differences + // Cardinal colour differences float N_Est = rgb[indx - w1][c] - rgb[indx - w1][1]; float S_Est = rgb[indx + w1][c] - rgb[indx + w1][1]; float W_Est = rgb[indx - 1][c] - rgb[indx - 1][1]; float E_Est = rgb[indx + 1][c] - rgb[indx + 1][1]; - //Interpolate R@G and B@G - float V_Est = ( N_Grad * S_Est + S_Grad * N_Est ) / ( N_Grad + S_Grad ); - float H_Est = ( E_Grad * W_Est + W_Grad * E_Est ) / ( E_Grad + W_Grad ); + // Vertical and horizontal estimations + float V_Est = ( N_Grad * S_Est + S_Grad * N_Est ) / max(eps, N_Grad + S_Grad ); + float H_Est = ( E_Grad * W_Est + W_Grad * E_Est ) / max(eps, E_Grad + W_Grad ); - rgb[indx][c] = LIM( rgb[indx][1] + ( 1.0f - VH_Disc[indx] ) * V_Est + VH_Disc[indx] * H_Est, 0.f, 1.f ); + // R@G and B@G interpolation + rgb[indx][c] = LIM( rgb[indx][1] + ( 1.f - VH_Disc ) * V_Est + VH_Disc * H_Est, 0.f, 1.f ); } } } - free( PQ_Disc ); - free( VH_Disc ); + free(VH_Dir); // RT --------------------------------------------------------------------- if (plistener) { @@ -4217,6 +4212,8 @@ void RawImageSource::rcd_demosaic() } } + border_interpolate2(width, height, 4); + if (plistener) { plistener->setProgress(1); } From 4d616e2782b3d80b1d18fbaae098594309b19bd7 Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Tue, 5 Dec 2017 17:34:18 +0200 Subject: [PATCH 10/18] Added updateHistogram method to ColorManagementToolbar class. This method get's called on histogram profile icon toggle and updated histogram. modified: rtgui/editorpanel.cc --- rtgui/editorpanel.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 855458b93..d5cd42dcb 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -464,6 +464,13 @@ public: updateParameters (); } + void updateHistogram() + { + intentBox.setSelected(intentBox.getSelected()); + updateParameters(); + } + + void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile) { ConnectionBlocker profileBlocker (profileConn); @@ -2031,6 +2038,7 @@ void EditorPanel::syncFileBrowser() // synchronize filebrowser with image in E void EditorPanel::histogramProfile_toggled() { options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active(); + colorMgmtToolBar->updateHistogram(); } bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname) From edc1175271e43d6aebca8ece3136f427e98d0d60 Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Tue, 5 Dec 2017 19:04:34 +0200 Subject: [PATCH 11/18] Clean up for updateHistogram() method --- rtgui/editorpanel.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index d5cd42dcb..98854d67b 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -466,7 +466,6 @@ public: void updateHistogram() { - intentBox.setSelected(intentBox.getSelected()); updateParameters(); } From 95af7dd65c4773167ac30f72a8bb00ffb6ad7b2c Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Wed, 6 Dec 2017 11:03:56 +0100 Subject: [PATCH 12/18] Added histogram profile button images, #4066 --- rtdata/images/Dark/actions/gamut-hist.png | Bin 0 -> 761 bytes rtdata/images/Light/actions/gamut-hist.png | Bin 0 -> 763 bytes rtgui/editorpanel.cc | 2 + tools/source_icons/scalable/gamut-hist.file | 1 + tools/source_icons/scalable/gamut-hist.svg | 852 ++++++++++++++++++++ 5 files changed, 855 insertions(+) create mode 100644 rtdata/images/Dark/actions/gamut-hist.png create mode 100644 rtdata/images/Light/actions/gamut-hist.png create mode 100644 tools/source_icons/scalable/gamut-hist.file create mode 100644 tools/source_icons/scalable/gamut-hist.svg diff --git a/rtdata/images/Dark/actions/gamut-hist.png b/rtdata/images/Dark/actions/gamut-hist.png new file mode 100644 index 0000000000000000000000000000000000000000..8a60118ddb5c741891ed9d763a84b0d4a2376592 GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UVK#Cko zOEU6{7<_@kiFpbhiA5>p`S~dc0i`#AD%2pxlolnYG6W@-hh(G{0gXsi02x@6SY86< z>m}#sUXA#e2GkJ*(&3z6P+63jo>9W!?5yBeQc{$eR9cdmpQjs~0d$UIPG)whLPkkR zft9{~a#3nxNoH9p(1hIlykd~+^m8(kQ}c>bi}jN#b&C`AP4o=(4~HbNGB7Y6@pN$v zvFP1;)wWwWP=xKl_d6%W4v8_k3QU>1apPvMsYOP@!CkIz-duCq5}>4Wqo>tgX}^Px z$e&f`?kw>VlinSB!Eqie;$APZdHY%j#6FTozSbxvl~6xcJ}`fn|S-Q zntlu8kDdR78>|_$R_!X!o3TV)>3Y%T-bF8tCm8HtKM;JiWyu-P+MwqCpEKk3Po%>rh}eq4@o zd9%kjP(-%RZE^qAtgjz)J_R{G622i(%$2wOcC@3w9n)hr3YCVwmvb4;pKoDgIi9({ zHL>E;?#UwAZ*>{`J>FS7-`8=%d(!&pUN)_aFG>zZMQ^>fjp5CNEyrf4@EooceE8<+ z&Vv2-_fJT@naUv1f85OX^6Yav#ZKljtUvYi({Hb(pH?eesj)b1B;UX=V~W>OwubpC z^IZeKY~`>PHaixh`17FU_hr{#zg72qG>w(}Vbt1dj29wBf2-g5AET$m_-~)WYnR6s f`!;SoBE8z)^8dk}Ye$4Z37f&w)z4*}Q$iB}A<;&Z literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/gamut-hist.png b/rtdata/images/Light/actions/gamut-hist.png new file mode 100644 index 0000000000000000000000000000000000000000..8c81e0213533842906b9bc72ec9fed769b605e47 GIT binary patch literal 763 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UVK#Cko zOEU6{7<_@kiFpbhiA5>p`S~dc0i`#AD%2pxlolnYG6W@-hh(G{0gXsi02x@6SY86< z>m}#sUXA#e2GkJ*(&3z6P+63jo>9W!?5yBeQc{$eR9cdmpQjs~0d$UIPG)whLPkkR zft9{~a#3nxNoH9p(1hIlykd~+^m8(kQ}c>bi}jN#b&C`AP4o=(4~HbNGB7Y6^K@|x zvFP1;b?@rS2_kGCo_pSM+))z9;<(ZD&1GHKmmXrB{`$dvB|fe? z-%HiUyD#hton^LAL{QMkLsKlu=J-K2r`${Yw~Y5b-*d9ReR>VUZ=LIU;8?-xtGiaLs$@`D zdHLlR76z-i=eFE`zh7XY{;?T{O>9KB|3>pSJ0B-!>Ry{J^9;j@4xJ{^iZIPXy{ax{~afM zC+&B65-HJkf76Dk8#-bXejePk#(dxV`Aic^5BgZ}98P99K0E1T)K|eadd (*histProfImg); toggleHistogramProfile->set_relief (Gtk::RELIEF_NONE); toggleHistogramProfile->set_active (options.rtSettings.HistogramWorking); toggleHistogramProfile->set_tooltip_markup ( (M ("PREFERENCES_HISTOGRAM_TOOLTIP"))); diff --git a/tools/source_icons/scalable/gamut-hist.file b/tools/source_icons/scalable/gamut-hist.file new file mode 100644 index 000000000..5eb359187 --- /dev/null +++ b/tools/source_icons/scalable/gamut-hist.file @@ -0,0 +1 @@ +gamut-hist.png,w22,actions diff --git a/tools/source_icons/scalable/gamut-hist.svg b/tools/source_icons/scalable/gamut-hist.svg new file mode 100644 index 000000000..cf163df83 --- /dev/null +++ b/tools/source_icons/scalable/gamut-hist.svg @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + Morgan Hardwood + + + RawTherapee www.rawtherapee.com + + + + + + + + + + + + + + + + + From d6037a880ee423a67b05a7b6d457c655ca115921 Mon Sep 17 00:00:00 2001 From: Oleg Koncevoy Date: Fri, 8 Dec 2017 09:59:46 +0200 Subject: [PATCH 13/18] Moved histogramProfile_toggled() to EditorPanel private section. modified: rtgui/editorpanel.h --- rtgui/editorpanel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 9ccbbef2d..0249e77ca 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -115,7 +115,6 @@ public: void openNextEditorImage (); void openPreviousEditorImage (); void syncFileBrowser (); - void histogramProfile_toggled (); void tbTopPanel_1_visible (bool visible); bool CheckSidePanelsVisibility(); @@ -151,6 +150,8 @@ private: bool idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams); bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring filename); + void histogramProfile_toggled (); + Glib::ustring lastSaveAsFileName; bool realized; From 729e50ff2e3bd15a1ab9353db30fdf2a3f67f80f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 8 Dec 2017 15:54:05 +0100 Subject: [PATCH 14/18] color toning: properly draw hue and strength gradients for the highlights and shadows sliders Fixes #4209 --- rtgui/colortoning.cc | 22 ++++++++++------------ rtgui/thresholdselector.cc | 3 +++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index c5d9252cd..b53f7e5db 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -954,36 +954,34 @@ void ColorToning::colorForValue (double valX, double valY, enum ColorCaller::Ele if (callerId == 1) { // ch - main curve Color::hsv2rgb01(float(valY), 1.0f, 0.5f, R, G, B); } else if (callerId == 2) { // Slider 1 background - if (valY > 0.5) + if (valY <= 0.5) // the hue range { Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); } else { // the strength applied to the current hue double strength, hue; - float r_, g_, b_; hlColSat->getValue(strength, hue); - Color::hsv2rgb01(valY * 2.f, 1.f, 1.f, r_, g_, b_); Color::hsv2rgb01(hue / 360.f, 1.f, 1.f, R, G, B); - R = r_ + (R - r_) * valX; - G = g_ + (G - g_) * valX; - B = b_ + (B - b_) * valX; + const double gray = 0.46; + R = (gray * (1.0 - valX)) + R * valX; + G = (gray * (1.0 - valX)) + G * valX; + B = (gray * (1.0 - valX)) + B * valX; } } else if (callerId == 3) { // Slider 2 background - if (valY > 0.5) + if (valY <= 0.5) // the hue range { Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); } else { // the strength applied to the current hue double strength, hue; - float r_, g_, b_; shadowsColSat->getValue(strength, hue); - Color::hsv2rgb01(valY * 2.f, 1.f, 1.f, r_, g_, b_); Color::hsv2rgb01(hue / 360.f, 1.f, 1.f, R, G, B); - R = r_ + (R - r_) * valX; - G = g_ + (G - g_) * valX; - B = b_ + (B - b_) * valX; + const double gray = 0.46; + R = (gray * (1.0 - valX)) + R * valX; + G = (gray * (1.0 - valX)) + G * valX; + B = (gray * (1.0 - valX)) + B * valX; } } diff --git a/rtgui/thresholdselector.cc b/rtgui/thresholdselector.cc index 0f9b11cf2..891095e6f 100644 --- a/rtgui/thresholdselector.cc +++ b/rtgui/thresholdselector.cc @@ -284,6 +284,9 @@ void ThresholdSelector::updateBackBuffer() cr->set_line_cap(Cairo::LINE_CAP_BUTT); if (is_sensitive() && coloredBar.canGetColors()) { + if (updatePolicy == RTUP_DYNAMIC) { + coloredBar.setDirty(true); + } // this will eventually create/update the off-screen Surface for the gradient area only ! coloredBar.setDrawRectangle(hb + hwslider, int(float(h) * 1.5f / 7.f + 0.5f), iw + 1, int(float(h) * 4.f / 7.f + 0.5f)); // that we're displaying here From a3d59a864a661ad30cc8193aab2a5515c385cbc6 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 8 Dec 2017 20:40:03 +0100 Subject: [PATCH 15/18] heap-buffer-overflow, fixes #4217 --- rtexif/rtexif.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index bc0e2002f..d44515f6a 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -1671,7 +1671,7 @@ void Tag::toString (char* buffer, int ofs) strcpy (buffer, ""); - for (size_t i = 0; i < maxcount; i++) { + for (size_t i = 0; i < std::min(maxcount, static_cast(valuesize - ofs)); i++) { if (i > 0) { strcat (buffer, ", "); } From d258216d41c9f4bdeb32cac7060efd205c0a6e4e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 9 Dec 2017 00:34:07 +0100 Subject: [PATCH 16/18] fixed warning reported by clang (forward declaration of ColorManagementParams as class, but it is a struct) --- rtengine/iccstore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 48efae087..bdb15d2c0 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -34,7 +34,7 @@ namespace rtengine namespace procparams { - class ColorManagementParams; + struct ColorManagementParams; } From d7fb8c91360188d3c8eefd645d5199fe0f2767aa Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 9 Dec 2017 00:35:09 +0100 Subject: [PATCH 17/18] Avoid division by zero in RGB_denoise Fix for #4214 --- rtengine/FTblockDN.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 4deb2b7c8..334f97f05 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -658,7 +658,8 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef } const float gain = pow(2.0f, float(expcomp)); - float noisevar_Ldetail = SQR(static_cast(SQR(100. - dnparams.Ldetail) + 50.*(100. - dnparams.Ldetail)) * TS * 0.5f); + float params_Ldetail = min(float(dnparams.Ldetail), 99.9f); // max out to avoid div by zero when using noisevar_Ldetail as divisor + float noisevar_Ldetail = SQR(static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f); array2D tilemask_in(TS, TS); array2D tilemask_out(TS, TS); From 4cc7861125feb1ad03966c7ca8678a40feceb8dd Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 9 Dec 2017 11:54:23 +0100 Subject: [PATCH 18/18] Fix wrong cast --- rtexif/rtexif.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index d44515f6a..8b57fd239 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -1671,7 +1671,7 @@ void Tag::toString (char* buffer, int ofs) strcpy (buffer, ""); - for (size_t i = 0; i < std::min(maxcount, static_cast(valuesize - ofs)); i++) { + for (size_t i = 0; i < std::min(maxcount, valuesize - ofs); i++) { if (i > 0) { strcat (buffer, ", "); }