//////////////////////////////////////////////////////////////// // // //exposure correction before interpolation // // code dated: December 27, 2010 // // Expo_before.cc is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // //////////////////////////////////////////////////////////////// // Jacques Desmis // use fast-demo(provisional) from Emil Martinec // inspired from work Guillermo Luijk and Manuel LLorens(Perfectraw) // Ingo Weyrich (2014-07-07) // optimized the highlight protection case // needs 2*width*height*sizeof(float) byte less memory than before // needs about 60% less processing time than before // // This function uses parameters: // exposure (linear): 2^(-8..0..8): currently 0.5 +3 // preserve (log) : 0..8 : currently 0.1 1 #include "rtengine.h" #include "rawimagesource.h" #include "mytime.h" #include "rt_math.h" namespace rtengine { extern const Settings* settings; void RawImageSource::processRawWhitepoint(float expos, float preser) { MyTime t1e, t2e; if (settings->verbose) { t1e.set(); } int width = W, height = H; // exposure correction inspired from G.Luijk for (int c = 0; c < 4; c++) { chmax[c] *= expos; } if (fabs(preser) < 0.001f) { // No highlight protection - simple mutiplication if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) #pragma omp parallel for for (int row = 0; row < height; row++) for (int col = 0; col < width; col++) { rawData[row][col] *= expos; } else #pragma omp parallel for for (int row = 0; row < height; row++) for (int col = 0; col < width; col++) { rawData[row][col * 3] *= expos; rawData[row][col * 3 + 1] *= expos; rawData[row][col * 3 + 2] *= expos; } } else { if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) { // Demosaic to allow calculation of luminosity. if(ri->getSensorType() == ST_BAYER) { fast_demosaic (0, 0, W, H); } else { fast_xtrans_interpolate(); } } // Find maximum to adjust LUTs. New float engines clips only at the very end float maxValFloat = 0.f; #pragma omp parallel { float maxValFloatThr = 0.f; if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) #pragma omp for schedule(dynamic,16) nowait for(int row = 0; row < height; row++) for (int col = 0; col < width; col++) { if (rawData[row][col] > maxValFloatThr) { maxValFloatThr = rawData[row][col]; } } else #pragma omp for schedule(dynamic,16) nowait for(int row = 0; row < height; row++) for (int col = 0; col < width; col++) { for (int c = 0; c < 3; c++) if (rawData[row][col * 3 + c] > maxValFloatThr) { maxValFloatThr = rawData[row][col * 3 + c]; } } #pragma omp critical { if(maxValFloatThr > maxValFloat) { maxValFloat = maxValFloatThr; } } } // Exposure correction with highlight preservation int maxVal = maxValFloat; LUTf lut(maxVal + 1); float K; if(expos > 1) { // Positive exposure K = (float) maxVal / expos * exp(-preser * log(2.0)); for (int j = max(1, (int)K); j <= maxVal; j++) { lut[(int)j] = (((float)maxVal - K * expos) / ((float)maxVal - K) * (j - maxVal) + (float) maxVal) / j; } } else { // Negative exposure float EV = log(expos) / log(2.0); // Convert exp. linear to EV K = (float)maxVal * exp(-preser * log(2.0)); for (int j = 0; j <= maxVal; j++) { lut[(int)j] = exp(EV * ((float)maxVal - j) / ((float)maxVal - K) * log(2.0)); } } if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) #pragma omp parallel for schedule(dynamic,16) for(int row = 0; row < height; row++) for(int col = 0; col < width; col++) { float lumi = 0.299f * red[row][col] + 0.587f * green[row][col] + 0.114f * blue[row][col]; rawData[row][col] *= lumi < K ? expos : lut[lumi]; } else #pragma omp parallel for for(int row = 0; row < height; row++) for(int col = 0; col < width; col++) { float lumi = 0.299f * rawData[row][col * 3] + 0.587f * rawData[row][col * 3 + 1] + 0.114f * rawData[row][col * 3 + 2]; float fac = lumi < K ? expos : lut[lumi]; for (int c = 0; c < 3; c++) { rawData[row][col * 3 + c] *= fac; } } } if (settings->verbose) { t2e.set(); printf("Exposure before %d usec\n", t2e.etime(t1e)); } } } //namespace