diff --git a/rtdata/languages/default b/rtdata/languages/default index f33608903..8b03dd439 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1954,6 +1954,7 @@ TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;The default radius of 1.0 usually fits well for b TP_RAW_PIXELSHIFTSMOOTH;Smooth transitions TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions between areas with motion and areas without.\nSet to 0 to disable transition smoothing.\nSet to 1 to either get the AMaZE/LMMSE result of the selected frame (depending on whether "Use LMMSE" is selected), or the median of all four frames if "Use median" is selected. TP_RAW_RCD;RCD +TP_RAW_RCDBILINEAR;RCD+Bilinear TP_RAW_RCDVNG4;RCD+VNG4 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.\n+fast gives less artifacts in flat areas diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 3813c5708..0450ee29f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -63,6 +63,7 @@ set(RTENGINESOURCEFILES ahd_demosaic_RT.cc amaze_demosaic_RT.cc badpixels.cc + bayer_bilinear_demosaic.cc boxblur.cc canon_cr3_decoder.cc CA_correct_RT.cc diff --git a/rtengine/bayer_bilinear_demosaic.cc b/rtengine/bayer_bilinear_demosaic.cc new file mode 100644 index 000000000..0125a21e7 --- /dev/null +++ b/rtengine/bayer_bilinear_demosaic.cc @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////// +// +// Bilinear bayer demosaic, optimized for speed, intended use is for flat regions of dual-demosaic +// +// copyright (c) 2020 Ingo Weyrich +// +// +// code dated: May 09, 2020 +// +// bayer_bilinear_demosaic.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 . +// +//////////////////////////////////////////////////////////////// + +#include "rawimagesource.h" +#define BENCHMARK +#include "StopWatch.h" + +using namespace rtengine; + +void RawImageSource::bayer_bilinear_demosaic(const array2D &rawData, array2D &red, array2D &green, array2D &blue) +{ +BENCHFUN +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 1; i < H - 1; ++i) { + float **nonGreen1 = red; + float **nonGreen2 = blue; + if (FC(i, 0) == 2 || FC(i, 1) == 2) { // blue row => swap pointers + std::swap(nonGreen1, nonGreen2); + } +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif + for (int j = 2 - (FC(i, 1) & 1); j < W - 2; j += 2) { // always begin with a green pixel + green[i][j] = rawData[i][j]; + nonGreen1[i][j] = (rawData[i][j - 1] + rawData[i][j + 1]) * 0.5f; + nonGreen2[i][j] = (rawData[i - 1][j] + rawData[i + 1][j]) * 0.5f; + green[i][j + 1] = ((rawData[i - 1][j + 1] + rawData[i][j]) + (rawData[i][j + 2] + rawData[i + 1][j + 1])) * 0.25f; + nonGreen1[i][j + 1] = rawData[i][j + 1]; + nonGreen2[i][j + 1] = ((rawData[i - 1][j] + rawData[i - 1][j + 2]) + (rawData[i + 1][j] + rawData[i + 1][j + 2])) * 0.25f; + } + } + border_interpolate(W, H, 2, rawData, red, green, blue); +} diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 253468a76..bbf4e621a 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -33,7 +33,7 @@ #include "../rtgui/options.h" -//#define BENCHMARK +#define BENCHMARK #include "StopWatch.h" using namespace std; @@ -52,6 +52,8 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) ) { + rcd_demosaic(options.chunkSizeRCD, options.measure); } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4) ) { rcd_demosaic(options.chunkSizeRCD, options.measure); } @@ -73,6 +75,8 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) ) { + rcd_demosaic(options.chunkSizeRCD, options.measure); } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4) ) { rcd_demosaic(options.chunkSizeRCD, options.measure); } @@ -113,7 +117,11 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams array2D blueTmp(winw, winh); if (isBayer) { - vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); + if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) ) { + bayer_bilinear_demosaic(rawData, redTmp, greenTmp, blueTmp); + } else { + vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); + } } else { fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index a198a6813..00a261056 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2717,6 +2717,7 @@ const std::vector& RAWParams::BayerSensor::getMethodStrings() "amaze", "amazevng4", "rcd", + "rcdbilinear", "rcdvng4", "dcb", "dcbvng4", diff --git a/rtengine/procparams.h b/rtengine/procparams.h index f9710b01d..f33214d44 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1395,6 +1395,7 @@ struct RAWParams { AMAZE, AMAZEVNG4, RCD, + RCDBILINEAR, RCDVNG4, DCB, DCBVNG4, diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 75088a07c..a599f9a22 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1575,6 +1575,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) + || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDBILINEAR) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4)) { if (!autoContrast) { double threshold = raw.bayersensor.dualDemosaicContrast; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 770c18ae3..861eb942a 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -300,6 +300,7 @@ protected: 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 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 array2D &rawData, array2D &red, array2D &green, array2D &blue); void hflip (Imagefloat* im); void vflip (Imagefloat* im); void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5b5cfe9c4..9ba011c59 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -365,6 +365,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params lmmseOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::LMMSE)); dualDemosaicOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) + || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4)); if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) { pixelShiftOptions->set_visible(pp->raw.bayersensor.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::PSMotionCorrectionMethod::CUSTOM); @@ -573,7 +574,7 @@ void BayerProcess::methodChanged () lmmseOptions->hide(); } - if (currentMethod == procparams::RAWParams::BayerSensor::Method::AMAZEVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::DCBVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::RCDVNG4) { + if (currentMethod == procparams::RAWParams::BayerSensor::Method::AMAZEVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::DCBVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::RCDVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) { dualDemosaicOptions->show(); } else { dualDemosaicOptions->hide();