diff --git a/rtdata/languages/default b/rtdata/languages/default index 215761415..60b68bbd7 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1729,6 +1729,7 @@ TP_PREPROCESS_LINEDENOISE;Line noise filter TP_PREPROCESS_LINEDENOISE_DIRECTION;Direction TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH;Both TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;Horizontal +TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;Horizontal only on PDAF rows TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Vertical TP_PREPROCESS_NO_FOUND;None found TP_PREPROCESS_PDAFLINESFILTER;PDAF lines filter diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index ad8775ad1..929a49d38 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -39,7 +39,7 @@ using namespace rtengine; // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertical) +void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertical, const CFALineDenoiseRowBlender &rowblender) { // local variables int height = H, width = W; @@ -254,10 +254,15 @@ void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertica // copy temporary buffer back to image matrix #pragma omp for - for(int i = 0; i < height; i++) - for(int j = 0; j < width; j++) { - rawData[i][j] = RawDataTmp[i * width + j]; + for(int i = 0; i < height; i++) { + float f = rowblender(i); + if (f > 0.f) { + float f2 = 1.f - f; + for(int j = 0; j < width; j++) { + rawData[i][j] = f * RawDataTmp[i * width + j] + f2 * rawData[i][j]; + } } + } } // end of parallel processing diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 5cbc6246b..f648ad891 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -128,6 +128,39 @@ private: std::vector> tiles_; }; + +class PDAFLineDenoiseRowFilter: public RawImageSource::CFALineDenoiseRowBlender { + static constexpr int BORDER1 = 1; + static constexpr int BORDER2 = 2; +public: + PDAFLineDenoiseRowFilter(const std::vector &pattern, int offset): + pattern_(pattern), + offset_(offset) + {} + + float operator()(int row) const + { + if (!pattern_.empty()) { + int key = (row - offset_) % pattern_.back(); + auto it = std::lower_bound(pattern_.begin(), pattern_.end(), key); + int d = *it - key; + if (d <= BORDER2) { + return d <= BORDER1 ? 1.f : 0.5f; + } else if (it > pattern_.begin()) { + d = key - *(it-1); + if (d <= BORDER2) { + return d <= BORDER1 ? 1.f : 0.5f; + } + } + } + return 0.f; + } + +private: + std::vector pattern_; + int offset_; +}; + } // namespace @@ -163,6 +196,12 @@ RawImageSource::GreenEqulibrateThreshold &PDAFLinesFilter::greenEqThreshold() } +std::unique_ptr PDAFLinesFilter::lineDenoiseRowBlender() +{ + return std::unique_ptr(new PDAFLineDenoiseRowFilter(pattern_, offset_)); +} + + int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) { rowmap_.clear(); diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h index 312367be7..9837db5b6 100644 --- a/rtengine/pdaflinesfilter.h +++ b/rtengine/pdaflinesfilter.h @@ -32,6 +32,7 @@ public: int mark(array2D &rawData, PixelsMap &bpMap); RawImageSource::GreenEqulibrateThreshold &greenEqThreshold(); + std::unique_ptr lineDenoiseRowBlender(); private: int markLine(array2D &rawData, PixelsMap &bpMap, int y); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 2f04179e7..70216a1d1 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1263,7 +1263,8 @@ struct RAWParams { enum class LineNoiseDirection { HORIZONTAL = 1, VERTICAL, - BOTH + BOTH, + PDAF_LINES = 5 }; LineNoiseDirection linenoiseDirection; int greenthresh; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d4c7b59d7..719d69106 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1998,7 +1998,15 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgress (0.0); } - cfa_linedn(0.00002 * (raw.bayersensor.linenoise), int(raw.bayersensor.linenoiseDirection) & int(RAWParams::BayerSensor::LineNoiseDirection::VERTICAL), int(raw.bayersensor.linenoiseDirection) & int(RAWParams::BayerSensor::LineNoiseDirection::HORIZONTAL)); + std::unique_ptr line_denoise_rowblender; + if (raw.bayersensor.linenoiseDirection == RAWParams::BayerSensor::LineNoiseDirection::PDAF_LINES) { + PDAFLinesFilter f(ri); + line_denoise_rowblender = f.lineDenoiseRowBlender(); + } else { + line_denoise_rowblender.reset(new CFALineDenoiseRowBlender()); + } + + cfa_linedn(0.00002 * (raw.bayersensor.linenoise), int(raw.bayersensor.linenoiseDirection) & int(RAWParams::BayerSensor::LineNoiseDirection::VERTICAL), int(raw.bayersensor.linenoiseDirection) & int(RAWParams::BayerSensor::LineNoiseDirection::HORIZONTAL), *line_denoise_rowblender); } if ( (raw.ca_autocorrect || fabs(raw.cared) > 0.001 || fabs(raw.cablue) > 0.001) && ri->getSensorType() == ST_BAYER ) { // Auto CA correction disabled for X-Trans, for now... diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index ae0d38dc1..15a15e03d 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -221,6 +221,12 @@ public: protected: const float thresh_; }; + + class CFALineDenoiseRowBlender { + public: + virtual ~CFALineDenoiseRowBlender() {} + virtual float operator()(int row) const { return 1.f; } + }; protected: typedef unsigned short ushort; @@ -243,7 +249,7 @@ protected: int interpolateBadPixelsXtrans( PixelsMap &bitmapBads ); int findHotDeadPixels( PixelsMap &bpMap, float thresh, bool findHotPixels, bool findDeadPixels ); - void cfa_linedn (float linenoiselevel, bool horizontal, bool vertical);//Emil's line denoise + void cfa_linedn (float linenoiselevel, bool horizontal, bool vertical, const CFALineDenoiseRowBlender &rowblender);//Emil's line denoise void green_equilibrate_global (array2D &rawData); void green_equilibrate (const GreenEqulibrateThreshold &greenthresh, array2D &rawData);//Emil's green equilibration diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index e7780de47..c43bdb4d8 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -54,6 +54,7 @@ BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", lineDenoiseDirection->append(M("TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL")); lineDenoiseDirection->append(M("TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL")); lineDenoiseDirection->append(M("TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH")); + lineDenoiseDirection->append(M("TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES")); lineDenoiseDirection->show(); lineDenoiseDirection->signal_changed().connect(sigc::mem_fun(*this, &BayerPreProcess::lineDenoiseDirectionChanged)); @@ -89,7 +90,11 @@ void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const Par } lineDenoise->setValue (pp->raw.bayersensor.linenoise); - lineDenoiseDirection->set_active(int(pp->raw.bayersensor.linenoiseDirection)-1); + int d = int(pp->raw.bayersensor.linenoiseDirection)-1; + if (d == 4) { + --d; + } + lineDenoiseDirection->set_active(d); greenEqThreshold->setValue (pp->raw.bayersensor.greenthresh); pdafLinesFilter->set_active(pp->raw.bayersensor.pdafLinesFilter); @@ -99,7 +104,11 @@ void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const Par void BayerPreProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { pp->raw.bayersensor.linenoise = lineDenoise->getIntValue(); - pp->raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(lineDenoiseDirection->get_active_row_number() + 1); + int d = lineDenoiseDirection->get_active_row_number() + 1; + if (d == 4) { + ++d; + } + pp->raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(d); pp->raw.bayersensor.greenthresh = greenEqThreshold->getIntValue(); pp->raw.bayersensor.pdafLinesFilter = pdafLinesFilter->get_active();