diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index ad95776ce..6e90e04d7 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -111,41 +111,34 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams buildBlendMask(L, blend, winw, winh, contrastf, autoContrast); contrast = contrastf * 100.f; - array2D& redTmp = L; // L is not needed anymore => reuse it - array2D greenTmp; - array2D blueTmp; - if (isBayer) { if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR) || raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBBILINEAR)) { bayer_bilinear_demosaic(blend, rawData, red, green, blue); - return; } else { - greenTmp(winw, winh); - blueTmp(winw, winh); + array2D& redTmp = L; // L is not needed anymore => reuse it + array2D greenTmp(winw, winh); + array2D blueTmp(winw, winh); vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for(int i = 0; i < winh; ++i) { + // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache + for(int j = 0; j < winw; ++j) { + red[i][j] = intp(blend[i][j], red[i][j], redTmp[i][j]); + } + for(int j = 0; j < winw; ++j) { + green[i][j] = intp(blend[i][j], green[i][j], greenTmp[i][j]); + } + for(int j = 0; j < winw; ++j) { + blue[i][j] = intp(blend[i][j], blue[i][j], blueTmp[i][j]); + } + } } } else { - greenTmp(winw, winh); - blueTmp(winw, winh); - fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); - } - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - for(int i = 0; i < winh; ++i) { - // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache - for(int j = 0; j < winw; ++j) { - red[i][j] = intp(blend[i][j], red[i][j], redTmp[i][j]); - } - for(int j = 0; j < winw; ++j) { - green[i][j] = intp(blend[i][j], green[i][j], greenTmp[i][j]); - } - for(int j = 0; j < winw; ++j) { - blue[i][j] = intp(blend[i][j], blue[i][j], blueTmp[i][j]); - } + fast_xtrans_interpolate_blend(blend, rawData, red, green, blue); } } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 7b1b4197c..12db6be74 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -299,6 +299,7 @@ protected: void xtransborder_interpolate (int border, array2D &red, array2D &green, array2D &blue); void xtrans_interpolate (const int passes, const bool useCieLab, size_t chunkSize = 1, bool measure = false); void fast_xtrans_interpolate (const array2D &rawData, array2D &red, array2D &green, array2D &blue); + void fast_xtrans_interpolate_blend (const float* const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void pixelshift(int winx, int winy, int winw, int winh, const procparams::RAWParams &rawParams, unsigned int frame, const std::string &make, const std::string &model, float rawWpCorrection); void bayer_bilinear_demosaic(const float *const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void hflip (Imagefloat* im); diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index 5f5afa073..bcad4d7d3 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -1027,6 +1027,67 @@ void RawImageSource::fast_xtrans_interpolate (const array2D &rawData, arr plistener->setProgress (1.0); } } + +void RawImageSource::fast_xtrans_interpolate_blend (const float* const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue) +{ + + if (plistener) { + plistener->setProgressStr(Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_XTRANSFAST"))); + plistener->setProgress(0.0); + } + + int xtrans[6][6]; + ri->getXtransMatrix(xtrans); + + const float weight[3][3] = { + {0.25f, 0.5f, 0.25f}, + {0.5f, 0.f, 0.5f}, + {0.25f, 0.5f, 0.25f} + }; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) +#endif + for (int row = 8; row < H - 8; ++row) { + for (int col = 8; col < W - 8; ++col) { + float sum[3] = {}; + + for (int v = -1; v <= 1; v++) { + for (int h = -1; h <= 1; h++) { + sum[fcol(row + v, col + h)] += rawData[row + v][(col + h)] * weight[v + 1][h + 1]; + } + } + + switch(fcol(row, col)) { + case 0: // red pixel + red[row][col] = intp(blend[row][col], red[row][col], rawData[row][col]); + green[row][col] = intp(blend[row][col], green[row][col], sum[1] * 0.5f); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2]); + break; + + case 1: // green pixel + green[row][col] = intp(blend[row][col], green[row][col], rawData[row][col]); + if (fcol(row, col - 1) == fcol(row, col + 1)) { // Solitary green pixel always has exactly two direct red and blue neighbors in 3x3 grid + red[row][col] = intp(blend[row][col], red[row][col], sum[0]); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2]); + } else { // Non solitary green pixel always has one direct and one diagonal red and blue neighbor in 3x3 grid + red[row][col] = intp(blend[row][col], red[row][col], sum[0] * 1.3333333f); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2] * 1.3333333f); + } + break; + + case 2: // blue pixel + red[row][col] = intp(blend[row][col], red[row][col], sum[0]); + green[row][col] = intp(blend[row][col], green[row][col], sum[1] * 0.5f); + blue[row][col] = intp(blend[row][col], blue[row][col], rawData[row][col]); + break; + } + } + } + + if (plistener) { + plistener->setProgress (1.0); + } +} #undef fcol #undef isgreen