From 0bb7375a90492e6e357f5bed72a104fde70389e0 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 28 Feb 2018 23:37:34 +0100 Subject: [PATCH 01/21] added possibility to apply "RAW line noise filter" only in a specific direction (horizontal or vertical) --- rtdata/languages/default | 5 +++++ rtengine/cfa_linedn_RT.cc | 10 +++++----- rtengine/procparams.cc | 9 +++++++++ rtengine/procparams.h | 6 ++++++ rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerpreprocess.cc | 33 +++++++++++++++++++++++++++++++++ rtgui/bayerpreprocess.h | 4 ++++ rtgui/paramsedited.cc | 8 +++++++- rtgui/paramsedited.h | 1 + rtgui/partialpastedlg.cc | 1 + 11 files changed, 73 insertions(+), 8 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index c6c7d08ba..b1ded30f3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -731,6 +731,7 @@ HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius HISTORY_MSG_METADATA_MODE;Metadata copy mode +HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;Line noise filter direction HISTORY_MSG_TM_FATTAL_ANCHOR;HDR TM - Anchor HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -1724,6 +1725,10 @@ TP_PREPROCESS_HOTPIXFILT;Hot pixel filter TP_PREPROCESS_HOTPIXFILT_TOOLTIP;Tries to suppress hot pixels. TP_PREPROCESS_LABEL;Preprocessing 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_VERTICAL;Vertical TP_PREPROCESS_NO_FOUND;None found TP_PRSHARPENING_LABEL;Post-Resize Sharpening TP_PRSHARPENING_TOOLTIP;Sharpens the image after resizing. Only works when the "Lanczos" resizing method is used. It is impossible to preview the effects of this tool. See RawPedia for usage instructions. diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 0f9e27634..67fb4b337 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) +void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertical) { // local variables int height = H, width = W; @@ -183,14 +183,14 @@ void RawImageSource::CLASS cfa_linedn(float noise) } //horizontal lines - if (noisevarm4 > (linehvar[0] + linehvar[1])) { //horizontal lines + if (horizontal && noisevarm4 > (linehvar[0] + linehvar[1])) { //horizontal lines for (int i = 1; i < 8; i++) { dctblock[0][0][i] *= 0.5f * (noisefactor[0][i][1] + noisefactor[1][i][1]); //or should we use MIN??? dctblock[1][0][i] *= 0.5f * (noisefactor[0][i][1] + noisefactor[1][i][1]); //or should we use MIN??? } } - if (noisevarm4 > (linehvar[2] + linehvar[3])) { //horizontal lines + if (horizontal && noisevarm4 > (linehvar[2] + linehvar[3])) { //horizontal lines for (int i = 1; i < 8; i++) { dctblock[2][0][i] *= 0.5f * (noisefactor[2][i][1] + noisefactor[3][i][1]); //or should we use MIN??? dctblock[3][0][i] *= 0.5f * (noisefactor[2][i][1] + noisefactor[3][i][1]); //or should we use MIN??? @@ -198,14 +198,14 @@ void RawImageSource::CLASS cfa_linedn(float noise) } //vertical lines - if (noisevarm4 > (linevvar[0] + linevvar[2])) { //vertical lines + if (vertical && noisevarm4 > (linevvar[0] + linevvar[2])) { //vertical lines for (int i = 1; i < 8; i++) { dctblock[0][i][0] *= 0.5f * (noisefactor[0][i][0] + noisefactor[2][i][0]); //or should we use MIN??? dctblock[2][i][0] *= 0.5f * (noisefactor[0][i][0] + noisefactor[2][i][0]); //or should we use MIN??? } } - if (noisevarm4 > (linevvar[1] + linevvar[3])) { //vertical lines + if (vertical && noisevarm4 > (linevvar[1] + linevvar[3])) { //vertical lines for (int i = 1; i < 8; i++) { dctblock[1][i][0] *= 0.5f * (noisefactor[1][i][0] + noisefactor[3][i][0]); //or should we use MIN??? dctblock[3][i][0] *= 0.5f * (noisefactor[1][i][0] + noisefactor[3][i][0]); //or should we use MIN??? diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 35b176ba1..7d87aa2b8 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2349,6 +2349,7 @@ RAWParams::BayerSensor::BayerSensor() : black3(0.0), twogreen(true), linenoise(0), + linenoiseDirection(LineNoiseDirection::BOTH), greenthresh(0), dcb_iterations(2), lmmse_iterations(2), @@ -2399,6 +2400,7 @@ bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const && black3 == other.black3 && twogreen == other.twogreen && linenoise == other.linenoise + && linenoiseDirection == other.linenoiseDirection && greenthresh == other.greenthresh && dcb_iterations == other.dcb_iterations && lmmse_iterations == other.lmmse_iterations @@ -3366,6 +3368,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.exBlack3, "RAW Bayer", "PreBlack3", raw.bayersensor.black3, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.exTwoGreen, "RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.linenoise, "RAW Bayer", "LineDenoise", raw.bayersensor.linenoise, keyFile); + saveToKeyfile(!pedited || pedited->raw.bayersensor.linenoise, "RAW Bayer", "LineDenoiseDirection", toUnderlying(raw.bayersensor.linenoiseDirection), keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.greenEq, "RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbIterations, "RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbEnhance, "RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance, keyFile); @@ -4684,6 +4687,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack3", pedited, raw.bayersensor.black3, pedited->raw.bayersensor.exBlack3); assignFromKeyfile(keyFile, "RAW Bayer", "PreTwoGreen", pedited, raw.bayersensor.twogreen, pedited->raw.bayersensor.exTwoGreen); assignFromKeyfile(keyFile, "RAW Bayer", "LineDenoise", pedited, raw.bayersensor.linenoise, pedited->raw.bayersensor.linenoise); + if (keyFile.has_key("RAW Bayer", "LineDenoiseDirection")) { + raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(keyFile.get_integer("RAW Bayer", "LineDenoiseDirection")); + if (pedited) { + pedited->raw.bayersensor.linenoiseDirection = true; + } + } assignFromKeyfile(keyFile, "RAW Bayer", "GreenEqThreshold", pedited, raw.bayersensor.greenthresh, pedited->raw.bayersensor.greenEq); assignFromKeyfile(keyFile, "RAW Bayer", "DCBIterations", pedited, raw.bayersensor.dcb_iterations, pedited->raw.bayersensor.dcbIterations); assignFromKeyfile(keyFile, "RAW Bayer", "DCBEnhance", pedited, raw.bayersensor.dcb_enhance, pedited->raw.bayersensor.dcbEnhance); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ee4c1756f..605db56ce 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1260,6 +1260,12 @@ struct RAWParams { double black3; bool twogreen; int linenoise; + enum class LineNoiseDirection { + HORIZONTAL = 1, + VERTICAL, + BOTH + }; + LineNoiseDirection linenoiseDirection; int greenthresh; int dcb_iterations; int lmmse_iterations; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index aef4447ce..cb57591c2 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1969,7 +1969,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgress (0.0); } - cfa_linedn(0.00002 * (raw.bayersensor.linenoise)); + 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)); } 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 ff7d2c1f9..b9ab7a154 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -234,7 +234,7 @@ protected: int interpolateBadPixelsXtrans( PixelsMap &bitmapBads ); int findHotDeadPixels( PixelsMap &bpMap, float thresh, bool findHotPixels, bool findDeadPixels ); - void cfa_linedn (float linenoiselevel);//Emil's line denoise + void cfa_linedn (float linenoiselevel, bool horizontal, bool vertical);//Emil's line denoise void green_equilibrate_global (array2D &rawData); void green_equilibrate (float greenthresh, array2D &rawData);//Emil's green equilibration diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 51a0cb62a..e6402efd0 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -18,6 +18,7 @@ */ #include "bayerpreprocess.h" #include "guiutils.h" +#include "eventmapper.h" #include using namespace rtengine; @@ -25,6 +26,9 @@ using namespace rtengine::procparams; BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", M("TP_PREPROCESS_LABEL"), true) { + auto m = ProcEventMapper::getInstance(); + EvLineDenoiseDirection = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION"); + lineDenoise = Gtk::manage(new Adjuster (M("TP_PREPROCESS_LINEDENOISE"), 0, 1000, 1, 0)); lineDenoise->setAdjusterListener (this); @@ -43,7 +47,19 @@ BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", greenEqThreshold->show(); + Gtk::HBox *hb = Gtk::manage(new Gtk::HBox()); + hb->pack_start(*Gtk::manage(new Gtk::Label(M("TP_PREPROCESS_LINEDENOISE_DIRECTION") + ": ")), Gtk::PACK_SHRINK, 0); + lineDenoiseDirection = Gtk::manage(new MyComboBoxText()); + 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->show(); + lineDenoiseDirection->signal_changed().connect(sigc::mem_fun(*this, &BayerPreProcess::lineDenoiseDirectionChanged)); + + hb->pack_start(*lineDenoiseDirection); + pack_start( *lineDenoise, Gtk::PACK_SHRINK, 4); + pack_start(*hb, Gtk::PACK_SHRINK, 4); pack_start( *Gtk::manage (new Gtk::HSeparator())); @@ -58,9 +74,13 @@ void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const Par if(pedited ) { lineDenoise->setEditedState( pedited->raw.bayersensor.linenoise ? Edited : UnEdited ); greenEqThreshold->setEditedState( pedited->raw.bayersensor.greenEq ? Edited : UnEdited ); + if (!pedited->raw.bayersensor.linenoiseDirection) { + lineDenoiseDirection->set_active(3); + } } lineDenoise->setValue (pp->raw.bayersensor.linenoise); + lineDenoiseDirection->set_active(int(pp->raw.bayersensor.linenoiseDirection)-1); greenEqThreshold->setValue (pp->raw.bayersensor.greenthresh); enableListener (); @@ -69,11 +89,13 @@ 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); pp->raw.bayersensor.greenthresh = greenEqThreshold->getIntValue(); if (pedited) { pedited->raw.bayersensor.linenoise = lineDenoise->getEditedState (); pedited->raw.bayersensor.greenEq = greenEqThreshold->getEditedState (); + pedited->raw.bayersensor.linenoise = lineDenoiseDirection->get_active_row_number() != 3; } } @@ -96,6 +118,9 @@ void BayerPreProcess::setBatchMode(bool batchMode) ToolPanel::setBatchMode (batchMode); lineDenoise->showEditedCB (); greenEqThreshold->showEditedCB (); + if (batchMode) { + lineDenoiseDirection->append(M("GENERAL_UNCHANGED")); + } } void BayerPreProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) @@ -125,3 +150,11 @@ void BayerPreProcess::trimValues (rtengine::procparams::ProcParams* pp) lineDenoise->trimValue(pp->raw.bayersensor.linenoise); greenEqThreshold->trimValue(pp->raw.bayersensor.greenthresh); } + + +void BayerPreProcess::lineDenoiseDirectionChanged() +{ + if (listener) { + listener->panelChanged(EvLineDenoiseDirection, lineDenoiseDirection->get_active_text()); + } +} diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h index 15b2ef7e5..4c28ff64d 100644 --- a/rtgui/bayerpreprocess.h +++ b/rtgui/bayerpreprocess.h @@ -30,8 +30,11 @@ class BayerPreProcess : public ToolParamBlock, public AdjusterListener, public F protected: Adjuster* lineDenoise; + MyComboBoxText *lineDenoiseDirection; Adjuster* greenEqThreshold; + rtengine::ProcEvent EvLineDenoiseDirection; + public: BayerPreProcess (); @@ -45,6 +48,7 @@ public: void hotDeadPixelChanged(); void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); void trimValues (rtengine::procparams::ProcParams* pp); + void lineDenoiseDirectionChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 0833da4e8..8acae08b3 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -433,6 +433,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftNonGreenAmaze = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; + raw.bayersensor.linenoiseDirection = v; raw.xtranssensor.method = v; raw.xtranssensor.ccSteps = v; raw.xtranssensor.exBlackRed = v; @@ -994,6 +995,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftNonGreenAmaze = raw.bayersensor.pixelShiftNonGreenAmaze && p.raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze; raw.bayersensor.greenEq = raw.bayersensor.greenEq && p.raw.bayersensor.greenthresh == other.raw.bayersensor.greenthresh; raw.bayersensor.linenoise = raw.bayersensor.linenoise && p.raw.bayersensor.linenoise == other.raw.bayersensor.linenoise; + raw.bayersensor.linenoiseDirection = raw.bayersensor.linenoiseDirection && p.raw.bayersensor.linenoiseDirection == other.raw.bayersensor.linenoiseDirection; raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; raw.xtranssensor.ccSteps = raw.xtranssensor.ccSteps && p.raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps; raw.xtranssensor.exBlackRed = raw.xtranssensor.exBlackRed && p.raw.xtranssensor.blackred == other.raw.xtranssensor.blackred; @@ -2640,6 +2642,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.linenoise = dontforceSet && options.baBehav[ADDSET_PREPROCESS_LINEDENOISE] ? toEdit.raw.bayersensor.linenoise + mods.raw.bayersensor.linenoise : mods.raw.bayersensor.linenoise; } + if (raw.bayersensor.linenoiseDirection) { + toEdit.raw.bayersensor.linenoiseDirection = mods.raw.bayersensor.linenoiseDirection; + } + if (raw.xtranssensor.method) { toEdit.raw.xtranssensor.method = mods.raw.xtranssensor.method; } @@ -3148,7 +3154,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftMotionCorrectionMethod && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelShiftSigma && pixelShiftSum && pixelShiftRedBlueWeight && pixelShiftShowMotion && pixelShiftShowMotionMaskOnly && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftExp0 && pixelShiftLmmse && pixelShiftOneGreen && pixelShiftEqualBright && pixelShiftEqualBrightChannel - && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; + && linenoise && linenoiseDirection && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } bool RAWParamsEdited::XTransSensor::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ad0b15e8c..d77e06b2d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -763,6 +763,7 @@ public: //bool allEnhance; bool greenEq; bool linenoise; + bool linenoiseDirection; bool isUnchanged() const; }; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 27a56e38e..6ff9f4d3b 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -875,6 +875,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!raw_linenoise->get_active ()) { filterPE.raw.bayersensor.linenoise = falsePE.raw.bayersensor.linenoise; + filterPE.raw.bayersensor.linenoiseDirection = falsePE.raw.bayersensor.linenoiseDirection; } if (!raw_greenthresh->get_active ()) { From 9180392ca703d891616aaa9dfa252b5169c20f64 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 2 Mar 2018 22:10:45 +0100 Subject: [PATCH 02/21] cfa_linedn(): ~30% speedup --- rtengine/cfa_linedn_RT.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 67fb4b337..ad8775ad1 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -318,14 +318,14 @@ void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertica /* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ /* Wn_kR = cos(pi/2*k/n) */ /* Wn_kI = sin(pi/2*k/n) */ -#define C8_1R 0.49039264020161522456 -#define C8_1I 0.09754516100806413392 -#define C8_2R 0.46193976625564337806 -#define C8_2I 0.19134171618254488586 -#define C8_3R 0.41573480615127261854 -#define C8_3I 0.27778511650980111237 -#define C8_4R 0.35355339059327376220 -#define W8_4R 0.70710678118654752440 +#define C8_1R 0.49039264020161522456f +#define C8_1I 0.09754516100806413392f +#define C8_2R 0.46193976625564337806f +#define C8_2I 0.19134171618254488586f +#define C8_3R 0.41573480615127261854f +#define C8_3I 0.27778511650980111237f +#define C8_4R 0.35355339059327376220f +#define W8_4R 0.70710678118654752440f void RawImageSource::ddct8x8s(int isgn, float a[8][8]) From 81a8aa403730fad41f21caa819ed3a543a42eaaa Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 5 Mar 2018 16:25:10 +0100 Subject: [PATCH 03/21] added experimental RAW Bayer preprocessing filter for mititgating the Sony PDAF lines banding problem --- rtdata/languages/default | 3 ++ rtengine/CMakeLists.txt | 1 + rtengine/pdaflinesfilter.cc | 97 +++++++++++++++++++++++++++++++++++++ rtengine/pdaflinesfilter.h | 41 ++++++++++++++++ rtengine/procparams.cc | 8 ++- rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 15 ++++++ rtgui/bayerpreprocess.cc | 19 ++++++++ rtgui/bayerpreprocess.h | 3 ++ rtgui/paramsedited.cc | 8 ++- rtgui/paramsedited.h | 1 + rtgui/partialpastedlg.cc | 9 ++++ rtgui/partialpastedlg.h | 3 +- 13 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 rtengine/pdaflinesfilter.cc create mode 100644 rtengine/pdaflinesfilter.h diff --git a/rtdata/languages/default b/rtdata/languages/default index b1ded30f3..4994365f2 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -732,6 +732,7 @@ HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius HISTORY_MSG_METADATA_MODE;Metadata copy mode HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;Line noise filter direction +HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAF lines filter HISTORY_MSG_TM_FATTAL_ANCHOR;HDR TM - Anchor HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -1730,6 +1731,8 @@ TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH;Both TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;Horizontal TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Vertical TP_PREPROCESS_NO_FOUND;None found +TP_PREPROCESS_PDAFLINESFILTER;PDAF lines filter +TP_PREPROCESS_PDAFLINESFILTER_TOOLTIP;Tries to suppress banding caused by on-sensor PDAF pixels occurring on some Sony mirrorless cameras on some backlit scenes. TP_PRSHARPENING_LABEL;Post-Resize Sharpening TP_PRSHARPENING_TOOLTIP;Sharpens the image after resizing. Only works when the "Lanczos" resizing method is used. It is impossible to preview the effects of this tool. See RawPedia for usage instructions. TP_RAWCACORR_AUTO;Auto-correction diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 080a76410..7101e8b80 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -117,6 +117,7 @@ set(RTENGINESOURCEFILES tmo_fattal02.cc iplocalcontrast.cc histmatching.cc + pdaflinesfilter.cc ) if(LENSFUN_HAS_LOAD_DIRECTORY) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc new file mode 100644 index 000000000..6f11b5e78 --- /dev/null +++ b/rtengine/pdaflinesfilter.cc @@ -0,0 +1,97 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee 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. + * + * RawTherapee 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 RawTherapee. If not, see . + */ + +#include "pdaflinesfilter.h" +#include "settings.h" +#include + +namespace rtengine { + +extern const Settings *settings; + + +PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): + ri_(ri), + W_(ri->get_width()), + H_(ri->get_height()) +{ + if (ri_->get_maker() == "Sony" && ri_->get_model() == "ILCE-7M3") { + // A7III, from https://www.dpreview.com/forums/post/60843139 + // in the original post: + // P 5 P 17 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 + // + // rotated to match the start of the frame + // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 + pattern_ = { + 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 + }; + offset_ = 9; + } else if (ri_->get_maker() == "Sony" && ri_->get_model() == "ILCE-6000") { + // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 + // P 11 P 23 P 17 P 17 P 17 P 23 P 11 P 17 P 17 P 17 P 23 P 11 P 23 P 11 P 17 P 23 P 11 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 23 P 11 P 17 P 11 P 23 + pattern_ = { + 0, 12, 36, 54, 72, 90, 114, 126, 144, 162, 180, 204, 216, 240, 252, 270, 294, 306, 324, 342, 366, 384, 396, 414, 432, 450, 474, 492, 504, 522, 540, 564, 576, 594, 606, 630 + }; + offset_ = 3; + } +} + + +int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) +{ + if (pattern_.empty()) { + if (settings->verbose) { + std::cout << "no PDAF pattern known for " << ri_->get_maker() << " " << ri_->get_model() << std::endl; + } + return 0; + } + + size_t idx = 0; + int off = offset_; + + int found = 0; + for (int y = 1; y < H_-1; ++y) { + int yy = pattern_[idx] + off; + if (y == yy) { + int n = 0; + for (int x = 1; x < W_-1; ++x) { + if (ri_->FC(y, x) == 1 && rawData[y][x] > max(rawData[y-1][x-1], rawData[y-1][x+1], rawData[y+1][x-1], rawData[y+1][x+1])) { + bpMap.set(x, y); + bpMap.set(x-1, y); + bpMap.set(x+1, y); + n += 2; + } + } + found += n; + if (n && settings->verbose) { + std::cout << "marked " << n << "pixels in PDAF line at " << y << std::endl; + } + } else if (y > yy) { + ++idx; + if (idx >= pattern_.size()) { + idx = 0; + off += pattern_.back(); + } + } + } + return found; +} + +} // namespace rtengine diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h new file mode 100644 index 000000000..428281abd --- /dev/null +++ b/rtengine/pdaflinesfilter.h @@ -0,0 +1,41 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee 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. + * + * RawTherapee 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 RawTherapee. If not, see . + */ + +#pragma once + +#include "rawimagesource.h" +#include + +namespace rtengine { + +class PDAFLinesFilter { +public: + PDAFLinesFilter(RawImage *ri); + int mark(array2D &rawData, PixelsMap &bpMap); + +private: + RawImage *ri_; + int W_; + int H_; + std::vector pattern_; + int offset_; +}; + +} // namespace rtengine diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 7d87aa2b8..0a87d9614 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2384,7 +2384,8 @@ RAWParams::BayerSensor::BayerSensor() : pixelShiftNonGreenCross(true), pixelShiftNonGreenCross2(false), pixelShiftNonGreenAmaze(false), - dcb_enhance(true) + dcb_enhance(true), + pdafLinesFilter(false) { } @@ -2435,7 +2436,8 @@ bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const && pixelShiftNonGreenCross == other.pixelShiftNonGreenCross && pixelShiftNonGreenCross2 == other.pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze == other.pixelShiftNonGreenAmaze - && dcb_enhance == other.dcb_enhance; + && dcb_enhance == other.dcb_enhance + && pdafLinesFilter == other.pdafLinesFilter; } bool RAWParams::BayerSensor::operator !=(const BayerSensor& other) const @@ -3404,6 +3406,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross, "RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross2, "RAW Bayer", "pixelShiftNonGreenCross2", raw.bayersensor.pixelShiftNonGreenCross2, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftNonGreenAmaze, "RAW Bayer", "pixelShiftNonGreenAmaze", raw.bayersensor.pixelShiftNonGreenAmaze, keyFile); + saveToKeyfile(!pedited || pedited->raw.bayersensor.pdafLinesFilter, "RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.method, "RAW X-Trans", "Method", raw.xtranssensor.method, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.ccSteps, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackRed, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile); @@ -4743,6 +4746,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftNonGreenCross", pedited, raw.bayersensor.pixelShiftNonGreenCross, pedited->raw.bayersensor.pixelShiftNonGreenCross); assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftNonGreenCross2", pedited, raw.bayersensor.pixelShiftNonGreenCross2, pedited->raw.bayersensor.pixelShiftNonGreenCross2); assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftNonGreenAmaze", pedited, raw.bayersensor.pixelShiftNonGreenAmaze, pedited->raw.bayersensor.pixelShiftNonGreenAmaze); + assignFromKeyfile(keyFile, "RAW Bayer", "PDAFLinesFilter", pedited, raw.bayersensor.pdafLinesFilter, pedited->raw.bayersensor.pdafLinesFilter); } if (keyFile.has_group ("RAW X-Trans")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 605db56ce..2f04179e7 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1301,6 +1301,7 @@ struct RAWParams { bool pixelShiftNonGreenCross2; bool pixelShiftNonGreenAmaze; bool dcb_enhance; + bool pdafLinesFilter; BayerSensor(); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index cb57591c2..da52cf352 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -34,6 +34,7 @@ #include "rt_math.h" #include "improcfun.h" #include "rtlensfun.h" +#include "pdaflinesfilter.h" #ifdef _OPENMP #include #endif @@ -1919,6 +1920,20 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } } + if (ri->getSensorType() == ST_BAYER && raw.bayersensor.pdafLinesFilter) { + PDAFLinesFilter f(ri); + + if (!bitmapBads) { + bitmapBads = new PixelsMap(W, H); + } + + int n = f.mark(rawData, *bitmapBads); + + if (settings->verbose && n > 0) { + printf("Marked %d hot pixels from PDAF lines\n", n); + } + } + // check if it is an olympus E camera or green equilibration is enabled. If yes, compute G channel pre-compensation factors if ( ri->getSensorType() == ST_BAYER && (raw.bayersensor.greenthresh || (((idata->getMake().size() >= 7 && idata->getMake().substr(0, 7) == "OLYMPUS" && idata->getModel()[0] == 'E') || (idata->getMake().size() >= 9 && idata->getMake().substr(0, 9) == "Panasonic")) && raw.bayersensor.method != RAWParams::BayerSensor::getMethodString( RAWParams::BayerSensor::Method::VNG4))) ) { // global correction diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index e6402efd0..e7780de47 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -28,6 +28,7 @@ BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", { auto m = ProcEventMapper::getInstance(); EvLineDenoiseDirection = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION"); + EvPDAFLinesFilter = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_PDAFLINESFILTER"); lineDenoise = Gtk::manage(new Adjuster (M("TP_PREPROCESS_LINEDENOISE"), 0, 1000, 1, 0)); lineDenoise->setAdjusterListener (this); @@ -65,6 +66,13 @@ BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", pack_start( *greenEqThreshold, Gtk::PACK_SHRINK, 4); + pdafLinesFilter = Gtk::manage(new Gtk::CheckButton((M("TP_PREPROCESS_PDAFLINESFILTER")))); + pdafLinesFilter->set_tooltip_markup(M("TP_PREPROCESS_PDAFLINESFILTER_TOOLTIP")); + pdafLinesFilter->show(); + pdafLinesFilter->signal_toggled().connect(sigc::mem_fun(*this, &BayerPreProcess::pdafLinesFilterChanged), true); + + pack_start(*Gtk::manage(new Gtk::HSeparator())); + pack_start(*pdafLinesFilter, Gtk::PACK_SHRINK, 4); } void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) @@ -77,11 +85,13 @@ void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const Par if (!pedited->raw.bayersensor.linenoiseDirection) { lineDenoiseDirection->set_active(3); } + pdafLinesFilter->set_inconsistent(!pedited->raw.bayersensor.pdafLinesFilter); } lineDenoise->setValue (pp->raw.bayersensor.linenoise); lineDenoiseDirection->set_active(int(pp->raw.bayersensor.linenoiseDirection)-1); greenEqThreshold->setValue (pp->raw.bayersensor.greenthresh); + pdafLinesFilter->set_active(pp->raw.bayersensor.pdafLinesFilter); enableListener (); } @@ -91,11 +101,13 @@ void BayerPreProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pp->raw.bayersensor.linenoise = lineDenoise->getIntValue(); pp->raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(lineDenoiseDirection->get_active_row_number() + 1); pp->raw.bayersensor.greenthresh = greenEqThreshold->getIntValue(); + pp->raw.bayersensor.pdafLinesFilter = pdafLinesFilter->get_active(); if (pedited) { pedited->raw.bayersensor.linenoise = lineDenoise->getEditedState (); pedited->raw.bayersensor.greenEq = greenEqThreshold->getEditedState (); pedited->raw.bayersensor.linenoise = lineDenoiseDirection->get_active_row_number() != 3; + pedited->raw.bayersensor.pdafLinesFilter = !pdafLinesFilter->get_inconsistent(); } } @@ -158,3 +170,10 @@ void BayerPreProcess::lineDenoiseDirectionChanged() listener->panelChanged(EvLineDenoiseDirection, lineDenoiseDirection->get_active_text()); } } + +void BayerPreProcess::pdafLinesFilterChanged() +{ + if (listener) { + listener->panelChanged(EvPDAFLinesFilter, pdafLinesFilter->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h index 4c28ff64d..c27e76e00 100644 --- a/rtgui/bayerpreprocess.h +++ b/rtgui/bayerpreprocess.h @@ -32,8 +32,10 @@ protected: Adjuster* lineDenoise; MyComboBoxText *lineDenoiseDirection; Adjuster* greenEqThreshold; + Gtk::CheckButton *pdafLinesFilter; rtengine::ProcEvent EvLineDenoiseDirection; + rtengine::ProcEvent EvPDAFLinesFilter; public: @@ -49,6 +51,7 @@ public: void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); void trimValues (rtengine::procparams::ProcParams* pp); void lineDenoiseDirectionChanged(); + void pdafLinesFilterChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 8acae08b3..868507ad0 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -434,6 +434,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.bayersensor.linenoiseDirection = v; + raw.bayersensor.pdafLinesFilter = v; raw.xtranssensor.method = v; raw.xtranssensor.ccSteps = v; raw.xtranssensor.exBlackRed = v; @@ -996,6 +997,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.greenEq = raw.bayersensor.greenEq && p.raw.bayersensor.greenthresh == other.raw.bayersensor.greenthresh; raw.bayersensor.linenoise = raw.bayersensor.linenoise && p.raw.bayersensor.linenoise == other.raw.bayersensor.linenoise; raw.bayersensor.linenoiseDirection = raw.bayersensor.linenoiseDirection && p.raw.bayersensor.linenoiseDirection == other.raw.bayersensor.linenoiseDirection; + raw.bayersensor.pdafLinesFilter = raw.bayersensor.pdafLinesFilter && p.raw.bayersensor.pdafLinesFilter == other.raw.bayersensor.pdafLinesFilter; raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; raw.xtranssensor.ccSteps = raw.xtranssensor.ccSteps && p.raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps; raw.xtranssensor.exBlackRed = raw.xtranssensor.exBlackRed && p.raw.xtranssensor.blackred == other.raw.xtranssensor.blackred; @@ -2646,6 +2648,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.linenoiseDirection = mods.raw.bayersensor.linenoiseDirection; } + if (raw.bayersensor.pdafLinesFilter) { + toEdit.raw.bayersensor.pdafLinesFilter = mods.raw.bayersensor.pdafLinesFilter; + } + if (raw.xtranssensor.method) { toEdit.raw.xtranssensor.method = mods.raw.xtranssensor.method; } @@ -3154,7 +3160,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftMotionCorrectionMethod && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelShiftSigma && pixelShiftSum && pixelShiftRedBlueWeight && pixelShiftShowMotion && pixelShiftShowMotionMaskOnly && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftExp0 && pixelShiftLmmse && pixelShiftOneGreen && pixelShiftEqualBright && pixelShiftEqualBrightChannel - && linenoise && linenoiseDirection && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; + && linenoise && linenoiseDirection && pdafLinesFilter && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } bool RAWParamsEdited::XTransSensor::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index d77e06b2d..12c8ee86e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -764,6 +764,7 @@ public: bool greenEq; bool linenoise; bool linenoiseDirection; + bool pdafLinesFilter; bool isUnchanged() const; }; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 6ff9f4d3b..4828e90dc 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -114,6 +114,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw_greenthresh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_GREENEQUIL"))); raw_hotpix_filt = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_HOTPIXFILT"))); raw_deadpix_filt = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_DEADPIXFILT"))); + raw_pdaf_lines_filter = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_PDAFLINESFILTER"))); //--- raw_expos = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWEXPOS_LINEAR"))); raw_preser = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWEXPOS_PRESER"))); @@ -225,6 +226,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[7]->pack_start (*raw_greenthresh, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*raw_hotpix_filt, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*raw_deadpix_filt, Gtk::PACK_SHRINK, 2); + vboxes[7]->pack_start (*raw_pdaf_lines_filter, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); vboxes[7]->pack_start (*raw_expos, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*raw_preser, Gtk::PACK_SHRINK, 2); @@ -368,6 +370,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw_greenthreshConn = raw_greenthresh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_hotpix_filtConn = raw_hotpix_filt->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_deadpix_filtConn = raw_deadpix_filt->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + raw_pdaf_lines_filterConn = raw_pdaf_lines_filter->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); //--- raw_exposConn = raw_expos->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_preserConn = raw_preser->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); @@ -441,6 +444,7 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker raw_greenthreshBlocker(raw_greenthreshConn); ConnectionBlocker raw_hotpix_filtBlocker(raw_hotpix_filtConn); ConnectionBlocker raw_deadpix_filtBlocker(raw_deadpix_filtConn); + ConnectionBlocker raw_pdaf_lines_filterBlocker(raw_pdaf_lines_filterConn); ConnectionBlocker raw_exposBlocker(raw_exposConn); ConnectionBlocker raw_preserBlocker(raw_preserConn); ConnectionBlocker raw_blackBlocker(raw_blackConn); @@ -467,6 +471,7 @@ void PartialPasteDlg::rawToggled () raw_greenthresh->set_active (raw->get_active ()); raw_hotpix_filt->set_active (raw->get_active ()); raw_deadpix_filt->set_active (raw->get_active ()); + raw_pdaf_lines_filter->set_active (raw->get_active ()); raw_expos->set_active (raw->get_active ()); raw_preser->set_active (raw->get_active ()); raw_black->set_active (raw->get_active ()); @@ -911,6 +916,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.raw.hotdeadpix_thresh = falsePE.raw.hotdeadpix_thresh; } + if (!raw_pdaf_lines_filter->get_active ()) { + filterPE.raw.bayersensor.pdafLinesFilter = falsePE.raw.bayersensor.pdafLinesFilter; + } + if (!df_file->get_active ()) { filterPE.raw.darkFrame = falsePE.raw.darkFrame; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index e270a1e6e..b404db156 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -106,6 +106,7 @@ public: Gtk::CheckButton* raw_caredblue; Gtk::CheckButton* raw_hotpix_filt; Gtk::CheckButton* raw_deadpix_filt; + Gtk::CheckButton* raw_pdaf_lines_filter; Gtk::CheckButton* raw_linenoise; Gtk::CheckButton* raw_greenthresh; Gtk::CheckButton* raw_method; @@ -133,7 +134,7 @@ public: sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; sigc::connection metadataConn, exifchConn, iptcConn, icmConn; sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; - sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; + sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_pdaf_lines_filterConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; public: PartialPasteDlg (const Glib::ustring &title, Gtk::Window* parent); From 3422dc71739fddfc693dcfbcb3ac9f769fc5a1cd Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 5 Mar 2018 17:46:20 +0100 Subject: [PATCH 04/21] fixed missing update of the total number of bad pixels found --- rtengine/rawimagesource.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index da52cf352..893a4a30d 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1928,6 +1928,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } int n = f.mark(rawData, *bitmapBads); + totBP += n; if (settings->verbose && n > 0) { printf("Marked %d hot pixels from PDAF lines\n", n); From 5ffe11fa8b8a51eca36d07eac5610faa0f3d8f5e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 6 Mar 2018 09:37:37 +0100 Subject: [PATCH 05/21] added PDAF pattern for the Sony A9 --- rtengine/pdaflinesfilter.cc | 48 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 6f11b5e78..c53b22478 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -32,24 +32,34 @@ PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): W_(ri->get_width()), H_(ri->get_height()) { - if (ri_->get_maker() == "Sony" && ri_->get_model() == "ILCE-7M3") { - // A7III, from https://www.dpreview.com/forums/post/60843139 - // in the original post: - // P 5 P 17 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 - // - // rotated to match the start of the frame - // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 - pattern_ = { - 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 - }; - offset_ = 9; - } else if (ri_->get_maker() == "Sony" && ri_->get_model() == "ILCE-6000") { - // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 - // P 11 P 23 P 17 P 17 P 17 P 23 P 11 P 17 P 17 P 17 P 23 P 11 P 23 P 11 P 17 P 23 P 11 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 23 P 11 P 17 P 11 P 23 - pattern_ = { - 0, 12, 36, 54, 72, 90, 114, 126, 144, 162, 180, 204, 216, 240, 252, 270, 294, 306, 324, 342, 366, 384, 396, 414, 432, 450, 474, 492, 504, 522, 540, 564, 576, 594, 606, 630 - }; - offset_ = 3; + if (ri_->get_maker() == "Sony") { + if (ri_->get_model() == "ILCE-7M3") { + // A7III, from https://www.dpreview.com/forums/post/60843139 + // in the original post: + // P 5 P 17 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 + // + // rotated to match the start of the frame + // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 + pattern_ = { + 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 + }; + offset_ = 9; + } else if (ri_->get_model() == "ILCE-6000") { + // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 + // P 11 P 23 P 17 P 17 P 17 P 23 P 11 P 17 P 17 P 17 P 23 P 11 P 23 P 11 P 17 P 23 P 11 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 23 P 11 P 17 P 11 P 23 + pattern_ = { + 0, 12, 36, 54, 72, 90, 114, 126, 144, 162, 180, 204, 216, 240, 252, 270, 294, 306, 324, 342, 366, 384, 396, 414, 432, 450, 474, 492, 504, 522, 540, 564, 576, 594, 606, 630 + }; + offset_ = 3; + } else if (ri_->get_model() == "ILCE-9") { + // the A9 is the same as the A7III, rotated of 1 position + // source: https://www.dpreview.com/forums/post/60857788 + // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 + pattern_ = { + 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 + }; + offset_ = -7; + } } } @@ -81,7 +91,7 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) } found += n; if (n && settings->verbose) { - std::cout << "marked " << n << "pixels in PDAF line at " << y << std::endl; + std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; } } else if (y > yy) { ++idx; From 574114944803baa87a1e73d0b8d9c05575ba2ab8 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 6 Mar 2018 11:50:46 +0100 Subject: [PATCH 06/21] improved PDAF filtering algorithm (check also adjacent lines) --- rtengine/pdaflinesfilter.cc | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index c53b22478..cb7d48e2e 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -82,11 +82,26 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) if (y == yy) { int n = 0; for (int x = 1; x < W_-1; ++x) { - if (ri_->FC(y, x) == 1 && rawData[y][x] > max(rawData[y-1][x-1], rawData[y-1][x+1], rawData[y+1][x-1], rawData[y+1][x+1])) { - bpMap.set(x, y); - bpMap.set(x-1, y); - bpMap.set(x+1, y); - n += 2; + if (ri_->FC(y, x) == 1) { + const float + g0 = rawData[y][x], + g1 = rawData[y-1][x+1], + g2 = rawData[y+1][x+1], + g3 = rawData[y-1][x-1], + g4 = rawData[y+1][x-1]; + const float g = max(g0, g1, g2); + if (g > max(g3, g4)) { + int row = y; + if (g == g1) { + --row; + } else if (g == g2) { + ++row; + } + bpMap.set(x, row); + bpMap.set(x-1, row); + bpMap.set(x+1, row); + n += 2; + } } } found += n; From cabf1160dd653133feaffe7a454f7c9f34380ac7 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 6 Mar 2018 23:23:38 +0100 Subject: [PATCH 07/21] further tweaks to the PDAF lines filter --- rtengine/pdaflinesfilter.cc | 102 ++++++++++++++++++++++++++---------- rtengine/pdaflinesfilter.h | 5 +- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index cb7d48e2e..b9a99565b 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -2,7 +2,7 @@ * * This file is part of RawTherapee. * - * Copyright (c) 2017 Alberto Griggio + * Copyright (c) 2018 Alberto Griggio * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,6 +64,48 @@ PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): } +int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) +{ + rowmap_.clear(); + rowmap_.resize((W_+1)/2, false); + int marked = 0; + + for (int x = 1; x < W_-1; ++x) { + if (ri_->FC(y, x) == 1) { + const float + g0 = rawData[y][x], + g1 = rawData[y-1][x+1], + g2 = rawData[y+1][x+1], + g3 = rawData[y-1][x-1], + g4 = rawData[y+1][x-1]; + if (g0 > max(g1, g2, g3, g4)) { + const float gu = g2 + g4; + const float gd = g1 + g3; + const float gM = max(gu, gd); + const float gm = min(gu, gd); + if ((gM - gm) / gM < 0.2f) { + rowmap_[x/2] = true; + } + } + } + } + + for (int x = 2; x < W_-2; ++x) { + if (ri_->FC(y, x) == 1) { + const int i = x/2; + if (rowmap_[i-1] && rowmap_[i] && rowmap_[i+1]) { + for (int xx = x-2; xx <= x+2; ++xx) { + bpMap.set(xx, y); + ++marked; + } + } + } + } + + return marked; +} + + int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) { if (pattern_.empty()) { @@ -80,34 +122,40 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) for (int y = 1; y < H_-1; ++y) { int yy = pattern_[idx] + off; if (y == yy) { - int n = 0; - for (int x = 1; x < W_-1; ++x) { - if (ri_->FC(y, x) == 1) { - const float - g0 = rawData[y][x], - g1 = rawData[y-1][x+1], - g2 = rawData[y+1][x+1], - g3 = rawData[y-1][x-1], - g4 = rawData[y+1][x-1]; - const float g = max(g0, g1, g2); - if (g > max(g3, g4)) { - int row = y; - if (g == g1) { - --row; - } else if (g == g2) { - ++row; - } - bpMap.set(x, row); - bpMap.set(x-1, row); - bpMap.set(x+1, row); - n += 2; - } + int n = markLine(rawData, bpMap, y) + markLine(rawData, bpMap, y-1) + markLine(rawData, bpMap, y+1); + if (n) { + found += n; + if (settings->verbose) { + std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; } } - found += n; - if (n && settings->verbose) { - std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; - } + // for (int x = 1; x < W_-1; ++x) { + // if (ri_->FC(y, x) == 1) { + // const float + // g0 = rawData[y][x], + // g1 = rawData[y-1][x+1], + // g2 = rawData[y+1][x+1], + // g3 = rawData[y-1][x-1], + // g4 = rawData[y+1][x-1]; + // const float g = max(g0, g1, g2); + // if (g > max(g3, g4)) { + // int row = y; + // if (g == g1) { + // --row; + // } else if (g == g2) { + // ++row; + // } + // bpMap.set(x, row); + // bpMap.set(x-1, row); + // bpMap.set(x+1, row); + // n += 2; + // } + // } + // } + // found += n; + // if (n && settings->verbose) { + // std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; + // } } else if (y > yy) { ++idx; if (idx >= pattern_.size()) { diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h index 428281abd..7980851db 100644 --- a/rtengine/pdaflinesfilter.h +++ b/rtengine/pdaflinesfilter.h @@ -2,7 +2,7 @@ * * This file is part of RawTherapee. * - * Copyright (c) 2017 Alberto Griggio + * Copyright (c) 2018 Alberto Griggio * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,11 +31,14 @@ public: int mark(array2D &rawData, PixelsMap &bpMap); private: + int markLine(array2D &rawData, PixelsMap &bpMap, int y); + RawImage *ri_; int W_; int H_; std::vector pattern_; int offset_; + std::vector rowmap_; }; } // namespace rtengine From 06bd387d52c0afc408637eda20710c666ecddfd1 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 7 Mar 2018 10:42:36 +0100 Subject: [PATCH 08/21] continued working on tuning the PDAF lines filter --- rtengine/pdaflinesfilter.cc | 34 ++++------------------------------ rtengine/pdaflinesfilter.h | 2 +- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index b9a99565b..de1273ba3 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -79,11 +79,12 @@ int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) g3 = rawData[y-1][x-1], g4 = rawData[y+1][x-1]; if (g0 > max(g1, g2, g3, g4)) { - const float gu = g2 + g4; - const float gd = g1 + g3; + const float gu = (g2 + g4) / 2.f; + const float gd = (g1 + g3) / 2.f; const float gM = max(gu, gd); const float gm = min(gu, gd); - if ((gM - gm) / gM < 0.2f) { + const float d = (gM - gm) / gM; + if (d < 0.2f && (g0 - (gm + gM)/2.f) / g0 > std::min(d, 0.1f)) { rowmap_[x/2] = true; } } @@ -129,33 +130,6 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; } } - // for (int x = 1; x < W_-1; ++x) { - // if (ri_->FC(y, x) == 1) { - // const float - // g0 = rawData[y][x], - // g1 = rawData[y-1][x+1], - // g2 = rawData[y+1][x+1], - // g3 = rawData[y-1][x-1], - // g4 = rawData[y+1][x-1]; - // const float g = max(g0, g1, g2); - // if (g > max(g3, g4)) { - // int row = y; - // if (g == g1) { - // --row; - // } else if (g == g2) { - // ++row; - // } - // bpMap.set(x, row); - // bpMap.set(x-1, row); - // bpMap.set(x+1, row); - // n += 2; - // } - // } - // } - // found += n; - // if (n && settings->verbose) { - // std::cout << "marked " << n << " pixels in PDAF line at " << y << std::endl; - // } } else if (y > yy) { ++idx; if (idx >= pattern_.size()) { diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h index 7980851db..13b97812f 100644 --- a/rtengine/pdaflinesfilter.h +++ b/rtengine/pdaflinesfilter.h @@ -38,7 +38,7 @@ private: int H_; std::vector pattern_; int offset_; - std::vector rowmap_; + std::vector rowmap_; }; } // namespace rtengine From 24edd97dcaf2303136becd0b20d28ca1dd1cab48 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 8 Mar 2018 16:12:34 +0100 Subject: [PATCH 09/21] added automatic adaptive green equilibration to the PDAF lines filter --- rtengine/green_equil_RT.cc | 25 ++++++--- rtengine/pdaflinesfilter.cc | 107 +++++++++++++++++++++++++++++++++++- rtengine/pdaflinesfilter.h | 6 +- rtengine/rawimagesource.cc | 15 ++++- rtengine/rawimagesource.h | 11 +++- 5 files changed, 150 insertions(+), 14 deletions(-) diff --git a/rtengine/green_equil_RT.cc b/rtengine/green_equil_RT.cc index 90c412871..5fdf052b7 100644 --- a/rtengine/green_equil_RT.cc +++ b/rtengine/green_equil_RT.cc @@ -89,7 +89,7 @@ void RawImageSource::green_equilibrate_global(array2D &rawData) } //void green_equilibrate()//for dcraw implementation -void RawImageSource::green_equilibrate(float thresh, array2D &rawData) +void RawImageSource::green_equilibrate(const GreenEqulibrateThreshold &thresh, array2D &rawData) { // thresh = threshold for performing green equilibration; max percentage difference of G1 vs G2 // G1-G2 differences larger than this will be assumed to be Nyquist texture, and left untouched @@ -119,7 +119,7 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) } constexpr float eps = 1.f; //tolerance to avoid dividing by zero - const float thresh6 = 6 * thresh; + // const float thresh6 = 6 * thresh; // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Fill G interpolated values with border interpolation and input values @@ -136,8 +136,8 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) #ifdef __SSE2__ vfloat zd5v = F2V(0.5f); vfloat onev = F2V(1.f); - vfloat threshv = F2V(thresh); - vfloat thresh6v = F2V(thresh6); + // vfloat threshv = F2V(thresh); + // vfloat thresh6v = F2V(thresh6); vfloat epsv = F2V(eps); #endif #ifdef _OPENMP @@ -165,7 +165,14 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) vfloat c1 = (vabsf(o1_1 - o1_2) + vabsf(o1_1 - o1_3) + vabsf(o1_1 - o1_4) + vabsf(o1_2 - o1_3) + vabsf(o1_3 - o1_4) + vabsf(o1_2 - o1_4)); vfloat c2 = (vabsf(o2_1 - o2_2) + vabsf(o2_1 - o2_3) + vabsf(o2_1 - o2_4) + vabsf(o2_2 - o2_3) + vabsf(o2_3 - o2_4) + vabsf(o2_2 - o2_4)); - vmask mask1 = vmaskf_lt(c1 + c2, thresh6v * vabsf(d1 - d2)); + vfloat tfv; + vfloat tf6v; + for (int k = 0; k < 4; ++k) { + tfv[k] = thresh(rr, cc+k); + tf6v[k] = 6 * tfv[k]; + } + + vmask mask1 = vmaskf_lt(c1 + c2, tf6v * vabsf(d1 - d2)); if (_mm_movemask_ps((vfloat)mask1)) { // if for any of the 4 pixels the condition is true, do the maths for all 4 pixels and mask the unused out at the end //pixel interpolation @@ -188,7 +195,7 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) vfloat ginterp = (gse * wtse + gnw * wtnw + gne * wtne + gsw * wtsw) / (wtse + wtnw + wtne + wtsw); - vfloat val = vself(vmaskf_lt(ginterp - gin, threshv * (ginterp + gin)), zd5v * (ginterp + gin), gin); + vfloat val = vself(vmaskf_lt(ginterp - gin, tfv * (ginterp + gin)), zd5v * (ginterp + gin), gin); val = vself(mask1, val, gin); STC2VFU(rawData[rr][cc], val); } @@ -213,7 +220,9 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) float c1 = (fabs(o1_1 - o1_2) + fabs(o1_1 - o1_3) + fabs(o1_1 - o1_4) + fabs(o1_2 - o1_3) + fabs(o1_3 - o1_4) + fabs(o1_2 - o1_4)); float c2 = (fabs(o2_1 - o2_2) + fabs(o2_1 - o2_3) + fabs(o2_1 - o2_4) + fabs(o2_2 - o2_3) + fabs(o2_3 - o2_4) + fabs(o2_2 - o2_4)); - if (c1 + c2 < thresh6 * fabs(d1 - d2)) { + float tf = thresh(rr, cc); + + if (c1 + c2 < 6 * tf * fabs(d1 - d2)) { //pixel interpolation float gin = cfa[rr][cc >> 1]; @@ -234,7 +243,7 @@ void RawImageSource::green_equilibrate(float thresh, array2D &rawData) float ginterp = (gse * wtse + gnw * wtnw + gne * wtne + gsw * wtsw) / (wtse + wtnw + wtne + wtsw); - if (ginterp - gin < thresh * (ginterp + gin)) { + if (ginterp - gin < tf * (ginterp + gin)) { rawData[rr][cc] = 0.5f * (ginterp + gin); } } diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index de1273ba3..482dbeb3e 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -27,11 +27,92 @@ namespace rtengine { extern const Settings *settings; +namespace { + +class PDAFGreenEqulibrateThreshold: public RawImageSource::GreenEqulibrateThreshold { + static constexpr float base_threshold = 0.5f; +public: + PDAFGreenEqulibrateThreshold(int w, int h, int ntiles=20): + RawImageSource::GreenEqulibrateThreshold(base_threshold), + w_(w), + h_(h) + { + tw_ = (w_ + 1) / ntiles; + th_ = (h_ + 1) / ntiles; + area_ = tw_ * th_; + tiles_.resize(ntiles+1, std::vector(ntiles+1)); + } + + void increment(int row, int col) + { + auto &r = tiles_[row / th_]; + ++r[col / tw_]; + } + + float operator()(int row, int col) const + { + int y = row / th_; + int x = col / tw_; + + float f = tile_factor(y, x); + int cy = y * th_ + th_/2; + int cx = x * tw_ + tw_/2; + + if (std::abs(y - cy) > std::abs(x - cx)) { + int y1 = y > cy ? y+1 : y-1; + if (y1 >= 0 && size_t(y1) < tiles_.size()) { + float f2 = tile_factor(y1, x); + int d = std::abs(cy - row); + f = f * float(th_ - d)/float(th_) + f2 * float(d)/float(th_); + } + } else { + int x1 = x > cx ? x+1 : x-1; + if (x1 >= 0 && size_t(x1) < tiles_[y].size()) { + float f2 = tile_factor(y, x1); + int d = std::abs(cx - col); + f = f * float(tw_ - d)/float(tw_) + f2 * float(d)/float(tw_); + } + } + return thresh_ * f; + } + + void print() const + { + std::cout << "PDAFGreenEqulibrateThreshold:\n"; + for (size_t row = 0; row < tiles_.size(); ++row) { + for (size_t col = 0; col < tiles_.size(); ++col) { + std::cout << " " << tile_factor(row, col); + } + std::cout << std::endl; + } + } + +private: + float tile_factor(int y, int x) const + { + return float(tiles_[y][x] * 12) / area_; + } + + int w_; + int h_; + int ntiles_; + int tw_; + int th_; + float area_; + std::vector> tiles_; +}; + +} // namespace + + + PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): ri_(ri), W_(ri->get_width()), H_(ri->get_height()) { + gthresh_ = new PDAFGreenEqulibrateThreshold(W_, H_); + if (ri_->get_maker() == "Sony") { if (ri_->get_model() == "ILCE-7M3") { // A7III, from https://www.dpreview.com/forums/post/60843139 @@ -64,6 +145,18 @@ PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): } +PDAFLinesFilter::~PDAFLinesFilter() +{ + delete gthresh_; +} + + +RawImageSource::GreenEqulibrateThreshold &PDAFLinesFilter::greenEqThreshold() +{ + return *gthresh_; +} + + int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) { rowmap_.clear(); @@ -91,13 +184,18 @@ int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) } } + PDAFGreenEqulibrateThreshold *m = static_cast(gthresh_); + for (int x = 2; x < W_-2; ++x) { if (ri_->FC(y, x) == 1) { const int i = x/2; if (rowmap_[i-1] && rowmap_[i] && rowmap_[i+1]) { for (int xx = x-2; xx <= x+2; ++xx) { - bpMap.set(xx, y); - ++marked; + if (!bpMap.get(xx, y)) { + bpMap.set(xx, y); + m->increment(y, xx); + ++marked; + } } } } @@ -138,6 +236,11 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) } } } + + if (settings->verbose) { + static_cast(gthresh_)->print(); + } + return found; } diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h index 13b97812f..312367be7 100644 --- a/rtengine/pdaflinesfilter.h +++ b/rtengine/pdaflinesfilter.h @@ -28,17 +28,21 @@ namespace rtengine { class PDAFLinesFilter { public: PDAFLinesFilter(RawImage *ri); + ~PDAFLinesFilter(); + int mark(array2D &rawData, PixelsMap &bpMap); + RawImageSource::GreenEqulibrateThreshold &greenEqThreshold(); private: int markLine(array2D &rawData, PixelsMap &bpMap, int y); - + RawImage *ri_; int W_; int H_; std::vector pattern_; int offset_; std::vector rowmap_; + RawImageSource::GreenEqulibrateThreshold *gthresh_; }; } // namespace rtengine diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 893a4a30d..bd9af122e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1933,6 +1933,15 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if (settings->verbose && n > 0) { printf("Marked %d hot pixels from PDAF lines\n", n); } + + auto &thresh = f.greenEqThreshold(); + if (numFrames == 4) { + for (int i = 0; i < 4; ++i) { + green_equilibrate(thresh, *rawDataFrames[i]); + } + } else { + green_equilibrate(thresh, rawData); + } } // check if it is an olympus E camera or green equilibration is enabled. If yes, compute G channel pre-compensation factors @@ -1953,12 +1962,14 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgress (0.0); } + GreenEqulibrateThreshold thresh(0.01 * raw.bayersensor.greenthresh); + if(numFrames == 4) { for(int i = 0; i < 4; ++i) { - green_equilibrate(0.01 * raw.bayersensor.greenthresh, *rawDataFrames[i]); + green_equilibrate(thresh, *rawDataFrames[i]); } } else { - green_equilibrate(0.01 * raw.bayersensor.greenthresh, rawData); + green_equilibrate(thresh, rawData); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index b9ab7a154..ae0d38dc1 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -213,6 +213,15 @@ public: } int getFrameCount() {return numFrames;} + class GreenEqulibrateThreshold { + public: + explicit GreenEqulibrateThreshold(float thresh): thresh_(thresh) {} + virtual ~GreenEqulibrateThreshold() {} + virtual float operator()(int row, int column) const { return thresh_; } + protected: + const float thresh_; + }; + protected: typedef unsigned short ushort; void processFalseColorCorrection (Imagefloat* i, const int steps); @@ -237,7 +246,7 @@ protected: void cfa_linedn (float linenoiselevel, bool horizontal, bool vertical);//Emil's line denoise void green_equilibrate_global (array2D &rawData); - void green_equilibrate (float greenthresh, array2D &rawData);//Emil's green equilibration + void green_equilibrate (const GreenEqulibrateThreshold &greenthresh, array2D &rawData);//Emil's green equilibration void nodemosaic(bool bw); void eahd_demosaic(); From 2d914a78bc029c2287a8bdad2a7666a623a5f7bc Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 8 Mar 2018 16:30:36 +0100 Subject: [PATCH 10/21] updated tooltip for the PDAF lines filter --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 4994365f2..215761415 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1732,7 +1732,7 @@ TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;Horizontal TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Vertical TP_PREPROCESS_NO_FOUND;None found TP_PREPROCESS_PDAFLINESFILTER;PDAF lines filter -TP_PREPROCESS_PDAFLINESFILTER_TOOLTIP;Tries to suppress banding caused by on-sensor PDAF pixels occurring on some Sony mirrorless cameras on some backlit scenes. +TP_PREPROCESS_PDAFLINESFILTER_TOOLTIP;Tries to suppress stripe noise caused by on-sensor PDAF pixels, occurring with some Sony mirrorless cameras on some backlit scenes with visible flare. TP_PRSHARPENING_LABEL;Post-Resize Sharpening TP_PRSHARPENING_TOOLTIP;Sharpens the image after resizing. Only works when the "Lanczos" resizing method is used. It is impossible to preview the effects of this tool. See RawPedia for usage instructions. TP_RAWCACORR_AUTO;Auto-correction From a6c86b2bcf2e042837c748ed76a4575f71a7f2d9 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 9 Mar 2018 18:26:29 +0100 Subject: [PATCH 11/21] use bilinear interpolation in PDAFGreenEqulibrateThreshold::operator() --- rtengine/pdaflinesfilter.cc | 74 ++++++++++++++++++++++--------------- rtengine/rawimagesource.cc | 22 ++++++----- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 482dbeb3e..4fd229a99 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -30,49 +30,69 @@ extern const Settings *settings; namespace { class PDAFGreenEqulibrateThreshold: public RawImageSource::GreenEqulibrateThreshold { - static constexpr float base_threshold = 0.5f; + static constexpr float BASE_THRESHOLD = 0.5f; + static constexpr int TILE_SIZE = 200; + static constexpr float AREA = TILE_SIZE * TILE_SIZE; + static constexpr int PIXEL_COUNT_FACTOR = 12; + public: - PDAFGreenEqulibrateThreshold(int w, int h, int ntiles=20): - RawImageSource::GreenEqulibrateThreshold(base_threshold), + PDAFGreenEqulibrateThreshold(int w, int h): + RawImageSource::GreenEqulibrateThreshold(BASE_THRESHOLD), w_(w), h_(h) { - tw_ = (w_ + 1) / ntiles; - th_ = (h_ + 1) / ntiles; - area_ = tw_ * th_; - tiles_.resize(ntiles+1, std::vector(ntiles+1)); + int ctiles = w_ / TILE_SIZE; + int rtiles = h_ / TILE_SIZE; + tiles_.resize(rtiles+1, std::vector(ctiles+1)); } void increment(int row, int col) { - auto &r = tiles_[row / th_]; - ++r[col / tw_]; + auto &r = tiles_[row / TILE_SIZE]; + ++r[col / TILE_SIZE]; } float operator()(int row, int col) const { - int y = row / th_; - int x = col / tw_; + int y = row / TILE_SIZE; + int x = col / TILE_SIZE; - float f = tile_factor(y, x); - int cy = y * th_ + th_/2; - int cx = x * tw_ + tw_/2; + int cy = y * TILE_SIZE + TILE_SIZE/2; + int cx = x * TILE_SIZE + TILE_SIZE/2; - if (std::abs(y - cy) > std::abs(x - cx)) { - int y1 = y > cy ? y+1 : y-1; + int x1 = col > cx ? x+1 : x-1; + int y1 = row > cy ? y+1 : y-1; + + float fxy = tile_factor(y, x); + float f = 0.f; + + if (x1 >= 0 && size_t(x1) < tiles_[y].size()) { if (y1 >= 0 && size_t(y1) < tiles_.size()) { - float f2 = tile_factor(y1, x); - int d = std::abs(cy - row); - f = f * float(th_ - d)/float(th_) + f2 * float(d)/float(th_); - } - } else { - int x1 = x > cx ? x+1 : x-1; - if (x1 >= 0 && size_t(x1) < tiles_[y].size()) { + // bilinear interpolation + float fx1y = tile_factor(y, x1); + float fx1y1 = tile_factor(y1, x1); + float fxy1 = tile_factor(y1, x); + + // x direction + int d = std::abs(cx - col); + float f1 = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + fx1y * float(d)/float(TILE_SIZE); + float f2 = fxy1 * float(TILE_SIZE - d)/float(TILE_SIZE) + fx1y1 * float(d)/float(TILE_SIZE); + // y direction + d = std::abs(cy - row); + f = f1 * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); + } else { float f2 = tile_factor(y, x1); int d = std::abs(cx - col); - f = f * float(tw_ - d)/float(tw_) + f2 * float(d)/float(tw_); + f = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); } + } else if (y1 >= 0 && size_t(y1) < tiles_.size()) { + float f2 = tile_factor(y1, x); + int d = std::abs(cy - row); + f = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); + } else { + f = fxy; } + return thresh_ * f; } @@ -90,15 +110,11 @@ public: private: float tile_factor(int y, int x) const { - return float(tiles_[y][x] * 12) / area_; + return float(tiles_[y][x] * PIXEL_COUNT_FACTOR) / AREA; } int w_; int h_; - int ntiles_; - int tw_; - int th_; - float area_; std::vector> tiles_; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index bd9af122e..d4c7b59d7 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1930,17 +1930,19 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le int n = f.mark(rawData, *bitmapBads); totBP += n; - if (settings->verbose && n > 0) { - printf("Marked %d hot pixels from PDAF lines\n", n); - } - - auto &thresh = f.greenEqThreshold(); - if (numFrames == 4) { - for (int i = 0; i < 4; ++i) { - green_equilibrate(thresh, *rawDataFrames[i]); + if (n > 0) { + if (settings->verbose) { + printf("Marked %d hot pixels from PDAF lines\n", n); + } + + auto &thresh = f.greenEqThreshold(); + if (numFrames == 4) { + for (int i = 0; i < 4; ++i) { + green_equilibrate(thresh, *rawDataFrames[i]); + } + } else { + green_equilibrate(thresh, rawData); } - } else { - green_equilibrate(thresh, rawData); } } From ba22027b2fb5ac13e0384d4916537d93a5a5d434 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 9 Mar 2018 20:18:37 +0100 Subject: [PATCH 12/21] Get pdaf data from camconst.json --- rtengine/camconst.cc | 43 ++++++++++++++++++++++++++++++++++++- rtengine/camconst.h | 6 +++++- rtengine/camconst.json | 25 +++++++++++++++++++-- rtengine/pdaflinesfilter.cc | 37 ++++++++----------------------- 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 469d18571..09a9e55ab 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -19,7 +19,7 @@ namespace rtengine extern const Settings* settings; -CameraConst::CameraConst() +CameraConst::CameraConst() : pdafOffset(0) { memset(dcraw_matrix, 0, sizeof(dcraw_matrix)); memset(raw_crop, 0, sizeof(raw_crop)); @@ -310,6 +310,35 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model) } } + ji = cJSON_GetObjectItem(js, "pdafPattern"); + + if (ji) { + if (ji->type != cJSON_Array) { + fprintf(stderr, "\"pdafPattern\" must be an array\n"); + goto parse_error; + } + + for (ji = ji->child; ji != nullptr; ji = ji->next) { + if (ji->type != cJSON_Number) { + fprintf(stderr, "\"pdafPattern\" array must contain numbers\n"); + goto parse_error; + } + + cc->pdafPattern.push_back(ji->valueint); + } + } + + ji = cJSON_GetObjectItem(js, "pdafOffset"); + + if (ji) { + if (ji->type != cJSON_Number) { + fprintf(stderr, "\"pdafOffset\" must contain a number\n"); + goto parse_error; + } + + cc->pdafOffset = ji->valueint; + } + return cc; parse_error: @@ -345,6 +374,18 @@ CameraConst::get_dcrawMatrix() return dcraw_matrix; } +bool +CameraConst::has_pdafPattern() +{ + return pdafPattern.size() > 0; +} + +void +CameraConst::get_pdafPattern(std::vector &pattern) +{ + pattern = pdafPattern; +} + bool CameraConst::has_rawCrop() { diff --git a/rtengine/camconst.h b/rtengine/camconst.h index 47c8d8bee..0f5d5d2ba 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -24,7 +24,8 @@ private: int white_max; std::map mLevels[2]; std::map mApertureScaling; - + std::vector pdafPattern; + int pdafOffset; CameraConst(); static bool parseLevels(CameraConst *cc, int bw, void *ji); static bool parseApertureScaling(CameraConst *cc, void *ji); @@ -33,8 +34,11 @@ private: public: static CameraConst *parseEntry(void *cJSON, const char *make_model); bool has_dcrawMatrix(void); + bool has_pdafPattern(void); void update_dcrawMatrix(const short *other); const short *get_dcrawMatrix(void); + void get_pdafPattern(std::vector &pattern); + int get_pdafOffset() {return pdafOffset;} bool has_rawCrop(void); void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height); bool has_rawMask(int idx); diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 8709c16c7..7809171cd 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2235,7 +2235,11 @@ Camera constants: "make_model": "Sony ILCE-6000", "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 "raw_crop": [ 0, 0, 6024, 4024 ], - "ranges": { "black": 512, "white": 16300 } + "ranges": { "black": 512, "white": 16300 }, + // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 + // P 11 P 23 P 17 P 17 P 17 P 23 P 11 P 17 P 17 P 17 P 23 P 11 P 23 P 11 P 17 P 23 P 11 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 23 P 11 P 17 P 11 P 23 + "pdafPattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], + "pdafOffset" : 3 }, { // Quality A @@ -2251,6 +2255,18 @@ Camera constants: "ranges": { "black": 512, "white": 16300 } }, + { // Quality C, only pdaf data + "make_model": "Sony ILCE-7M3", + // A7III, from https://www.dpreview.com/forums/post/60843139 + // in the original post: + // P 5 P 17 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 + // + // rotated to match the start of the frame + // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 + "pdafPattern" : [ 0,12,24,36,54,66,72,84,96,114,120,132,150,156,174,180,192,204,216,234,240,252,264,276,282,300,306,324,336,342,360,372,384,402,414,420], + "pdafOffset" : 9 + }, + { // Quality A, correction for frame width "make_model": "Sony ILCE-7R", "dcraw_matrix": [ 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 ], @@ -2269,7 +2285,12 @@ Camera constants: "make_model": "Sony ILCE-9", "dcraw_matrix": [ 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 ], // DNG_v9.12 D65 "raw_crop": [ 8, 8, 6008, 4008 ], // full raw frame 6048x4024 Dcraw auto identify 6024x4024, jpeg 12,12,6000x4000 - "ranges": { "black": 512, "white": 16300 } + "ranges": { "black": 512, "white": 16300 }, + // the A9 is the same as the A7III, rotated of 1 position + // source: https://www.dpreview.com/forums/post/60857788 + // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 + "pdafPattern" : [ 0,12,24,36,54,66,72,84,96,114,120,132,150,156,174,180,192,204,216,234,240,252,264,276,282,300,306,324,336,342,360,372,384,402,414,420 ], + "pdafOffset" : -7 }, { // Quality B, correction for frame width diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 4fd229a99..72dbb1915 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -21,6 +21,7 @@ #include "pdaflinesfilter.h" #include "settings.h" #include +#include "camconst.h" namespace rtengine { @@ -128,34 +129,14 @@ PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): H_(ri->get_height()) { gthresh_ = new PDAFGreenEqulibrateThreshold(W_, H_); - - if (ri_->get_maker() == "Sony") { - if (ri_->get_model() == "ILCE-7M3") { - // A7III, from https://www.dpreview.com/forums/post/60843139 - // in the original post: - // P 5 P 17 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 - // - // rotated to match the start of the frame - // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 - pattern_ = { - 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 - }; - offset_ = 9; - } else if (ri_->get_model() == "ILCE-6000") { - // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 - // P 11 P 23 P 17 P 17 P 17 P 23 P 11 P 17 P 17 P 17 P 23 P 11 P 23 P 11 P 17 P 23 P 11 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 17 P 23 P 17 P 11 P 17 P 17 P 23 P 11 P 17 P 11 P 23 - pattern_ = { - 0, 12, 36, 54, 72, 90, 114, 126, 144, 162, 180, 204, 216, 240, 252, 270, 294, 306, 324, 342, 366, 384, 396, 414, 432, 450, 474, 492, 504, 522, 540, 564, 576, 594, 606, 630 - }; - offset_ = 3; - } else if (ri_->get_model() == "ILCE-9") { - // the A9 is the same as the A7III, rotated of 1 position - // source: https://www.dpreview.com/forums/post/60857788 - // P 11 P 11 P 11 P 17 P 11 P 5 P 11 P 11 P 17 P 5 P 11 P 17 P 5 P 17 P 5 P 11 P 11 P 11 P 17 P 5 P 11 P 11 P 11 P 5 P 17 P 5 P 17 P 11 P 5 P 17 P 11 P 11 P 17 P 11 P 5 - pattern_ = { - 0, 12, 24, 36, 54, 66, 72, 84, 96, 114, 120, 132, 150, 156, 174, 180, 192, 204, 216, 234, 240, 252, 264, 276, 282, 300, 306, 324, 336, 342, 360, 372, 384, 402, 414, 420 - }; - offset_ = -7; + + CameraConstantsStore* ccs = CameraConstantsStore::getInstance(); + CameraConst *cc = ccs->get(ri_->get_maker().c_str(), ri_->get_model().c_str()); + + if (cc) { + cc->get_pdafPattern(pattern_); + if(!pattern_.empty()) { + offset_ = cc->get_pdafOffset(); } } } From 5e2b8caa4996ec91a1a1048efefe4b4e9bd9386d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 9 Mar 2018 23:14:08 +0100 Subject: [PATCH 13/21] added PDAF data for the Sony A6300 to camconst.json (and a comment about the "pdafPattern" and "pdafOffset" fields) --- rtengine/camconst.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 7809171cd..91c2cff2c 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -82,6 +82,11 @@ Examples: // It is useful after detecting the masked areas, to not fully use these areas but leave a border of 2-4 pixels // instead, to take care of possible light leaks from the light sensing area to the optically black (masked) // area or sensor imperfections at the outer borders. + + // list of indices of the rows with on-sensor PDAF pixels, for cameras that have such features. The indices here form a pattern that is repeated for the whole height of the sensor. The values are relative to the "pdafOffset" value (see below) + "pdafPattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], + // index of the first row of the PDAF pattern in the sensor (0 is the topmost row). Allowed to be negative for convenience (this means that the first repetition of the pattern doesn't start from the first row) + "pdafOffset" : 3 }, { @@ -2246,7 +2251,10 @@ Camera constants: "make_model": [ "Sony ILCE-6300","Sony ILCE-6500" ], "dcraw_matrix": [ 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 ], // DNG_v9.8 D65 "raw_crop": [ 0, 0, 6024, 4024 ], - "ranges": { "black": 512, "white": 16300 } + "ranges": { "black": 512, "white": 16300 }, + // contributed by Horshak from https://www.dpreview.com/forums/post/60873077 + "pdafPattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], + "pdafOffset" : 3 }, { // Quality A From 4e9a656658b829894c4b608cbc79c1baf1afbcff Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 9 Mar 2018 23:33:32 +0100 Subject: [PATCH 14/21] Fixed bug in RawImageSource::green_equilibrate() --- rtengine/green_equil_RT.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rtengine/green_equil_RT.cc b/rtengine/green_equil_RT.cc index 5fdf052b7..934b7df4a 100644 --- a/rtengine/green_equil_RT.cc +++ b/rtengine/green_equil_RT.cc @@ -166,11 +166,10 @@ void RawImageSource::green_equilibrate(const GreenEqulibrateThreshold &thresh, a vfloat c2 = (vabsf(o2_1 - o2_2) + vabsf(o2_1 - o2_3) + vabsf(o2_1 - o2_4) + vabsf(o2_2 - o2_3) + vabsf(o2_3 - o2_4) + vabsf(o2_2 - o2_4)); vfloat tfv; - vfloat tf6v; for (int k = 0; k < 4; ++k) { - tfv[k] = thresh(rr, cc+k); - tf6v[k] = 6 * tfv[k]; + tfv[k] = thresh(rr, cc + 2 * k); } + vfloat tf6v = F2V(6.f) * tfv; vmask mask1 = vmaskf_lt(c1 + c2, tf6v * vabsf(d1 - d2)); From 11c942d2b365018c79f189d28097db1b277081c7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 9 Mar 2018 23:34:22 +0100 Subject: [PATCH 15/21] ~ double speed for PDAFLinesFilter::mark() --- rtengine/pdaflinesfilter.cc | 56 ++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 72dbb1915..20355c0dd 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -160,41 +160,45 @@ int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) rowmap_.resize((W_+1)/2, false); int marked = 0; - for (int x = 1; x < W_-1; ++x) { - if (ri_->FC(y, x) == 1) { - const float - g0 = rawData[y][x], - g1 = rawData[y-1][x+1], - g2 = rawData[y+1][x+1], - g3 = rawData[y-1][x-1], - g4 = rawData[y+1][x-1]; - if (g0 > max(g1, g2, g3, g4)) { - const float gu = (g2 + g4) / 2.f; - const float gd = (g1 + g3) / 2.f; - const float gM = max(gu, gd); - const float gm = min(gu, gd); - const float d = (gM - gm) / gM; - if (d < 0.2f && (g0 - (gm + gM)/2.f) / g0 > std::min(d, 0.1f)) { - rowmap_[x/2] = true; - } + for (int x = 1 + (ri_->FC(y, 0) & 1); x < W_-1; x += 2) { + const float + g0 = rawData[y][x], + g1 = rawData[y-1][x+1], + g2 = rawData[y+1][x+1], + g3 = rawData[y-1][x-1], + g4 = rawData[y+1][x-1]; + if (g0 > max(g1, g2, g3, g4)) { + const float gu = g2 + g4; + const float gd = g1 + g3; + const float gM = max(gu, gd); + const float gm = min(gu, gd); + const float d = (gM - gm) / gM; + if (d < 0.2f && (1.f - (gm + gM)/(4.f * g0)) > std::min(d, 0.1f)) { + rowmap_[x/2] = true; } } } PDAFGreenEqulibrateThreshold *m = static_cast(gthresh_); - for (int x = 2; x < W_-2; ++x) { - if (ri_->FC(y, x) == 1) { - const int i = x/2; - if (rowmap_[i-1] && rowmap_[i] && rowmap_[i+1]) { - for (int xx = x-2; xx <= x+2; ++xx) { - if (!bpMap.get(xx, y)) { - bpMap.set(xx, y); - m->increment(y, xx); - ++marked; + for (int x = 2 + (ri_->FC(y, 1) & 1); x < W_-2; x += 2) { + const int i = x/2; + if (rowmap_[i+1]) { + if (rowmap_[i]) { + if (rowmap_[i-1]) { + for (int xx = x-2; xx <= x+2; ++xx) { + if (!bpMap.get(xx, y)) { + bpMap.set(xx, y); + m->increment(y, xx); + ++marked; + } } } + } else { + x += 2; } + } else { + x += 4; } } From 64979b0660dac565ad492a6262bf1272dbe3e011 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 10 Mar 2018 12:18:56 +0100 Subject: [PATCH 16/21] PDAF patterns ignored in user's camconst, #4435 --- rtengine/camconst.cc | 26 +++++++++++++++++++++++--- rtengine/camconst.h | 4 +++- rtengine/pdaflinesfilter.cc | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 09a9e55ab..3d4342ed9 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -380,10 +380,28 @@ CameraConst::has_pdafPattern() return pdafPattern.size() > 0; } -void -CameraConst::get_pdafPattern(std::vector &pattern) +std::vector +CameraConst::get_pdafPattern() { - pattern = pdafPattern; + return pdafPattern; +} + +void +CameraConst::update_pdafPattern(const std::vector &other) +{ + if (other.empty()) { + return; + } + pdafPattern = other; +} + +void +CameraConst::update_pdafOffset(int other) +{ + if (other == 0) { + return; + } + pdafOffset = other; } bool @@ -719,6 +737,8 @@ CameraConstantsStore::parse_camera_constants_file(Glib::ustring filename_) // deleting all the existing levels, replaced by the new ones existingcc->update_Levels(cc); existingcc->update_Crop(cc); + existingcc->update_pdafPattern(cc->get_pdafPattern()); + existingcc->update_pdafOffset(cc->get_pdafOffset()); if (settings->verbose) { printf("Merging camera constants for \"%s\"\n", make_model.c_str()); diff --git a/rtengine/camconst.h b/rtengine/camconst.h index 0f5d5d2ba..60e17201b 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -37,7 +37,7 @@ public: bool has_pdafPattern(void); void update_dcrawMatrix(const short *other); const short *get_dcrawMatrix(void); - void get_pdafPattern(std::vector &pattern); + std::vector get_pdafPattern(); int get_pdafOffset() {return pdafOffset;} bool has_rawCrop(void); void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height); @@ -47,6 +47,8 @@ public: int get_WhiteLevel(int idx, int iso_speed, float fnumber); void update_Levels(const CameraConst *other); void update_Crop(CameraConst *other); + void update_pdafPattern(const std::vector &other); + void update_pdafOffset(int other); }; class CameraConstantsStore diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 20355c0dd..b026324bc 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -134,7 +134,7 @@ PDAFLinesFilter::PDAFLinesFilter(RawImage *ri): CameraConst *cc = ccs->get(ri_->get_maker().c_str(), ri_->get_model().c_str()); if (cc) { - cc->get_pdafPattern(pattern_); + pattern_ = cc->get_pdafPattern(); if(!pattern_.empty()) { offset_ = cc->get_pdafOffset(); } From 478ebb1a49dc5aa8491c602001e7628d01f188b7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 10 Mar 2018 22:52:03 +0100 Subject: [PATCH 17/21] ~ 45% speedup for RawImageSource::green_equilibrate() --- rtengine/pdaflinesfilter.cc | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index b026324bc..5cbc6246b 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -44,7 +44,16 @@ public: { int ctiles = w_ / TILE_SIZE; int rtiles = h_ / TILE_SIZE; - tiles_.resize(rtiles+1, std::vector(ctiles+1)); + tiles_.resize(rtiles+1, std::vector(ctiles+1)); + } + + void processTiles() + { + for(size_t i = 0; i < tiles_.size(); ++i) { + for(size_t j = 0; j < tiles_[i].size(); ++j) { + tiles_[i][j] = tiles_[i][j] * PIXEL_COUNT_FACTOR / (AREA * AREA); + } + } } void increment(int row, int col) @@ -76,22 +85,22 @@ public: // x direction int d = std::abs(cx - col); - float f1 = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + fx1y * float(d)/float(TILE_SIZE); - float f2 = fxy1 * float(TILE_SIZE - d)/float(TILE_SIZE) + fx1y1 * float(d)/float(TILE_SIZE); + float f1 = fxy * (TILE_SIZE - d) + fx1y * float(d); + float f2 = fxy1 * (TILE_SIZE - d) + fx1y1 * float(d); // y direction d = std::abs(cy - row); - f = f1 * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); + f = (f1 * (TILE_SIZE - d) + f2 * float(d)); } else { float f2 = tile_factor(y, x1); int d = std::abs(cx - col); - f = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); + f = (fxy * float(TILE_SIZE - d) + f2 * float(d)) * TILE_SIZE; } } else if (y1 >= 0 && size_t(y1) < tiles_.size()) { float f2 = tile_factor(y1, x); int d = std::abs(cy - row); - f = fxy * float(TILE_SIZE - d)/float(TILE_SIZE) + f2 * float(d)/float(TILE_SIZE); + f = (fxy * float(TILE_SIZE - d) + f2 * float(d)) * TILE_SIZE; } else { - f = fxy; + f = fxy * AREA; } return thresh_ * f; @@ -111,12 +120,12 @@ public: private: float tile_factor(int y, int x) const { - return float(tiles_[y][x] * PIXEL_COUNT_FACTOR) / AREA; + return tiles_[y][x]; } int w_; int h_; - std::vector> tiles_; + std::vector> tiles_; }; } // namespace @@ -208,6 +217,7 @@ int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) { + if (pattern_.empty()) { if (settings->verbose) { std::cout << "no PDAF pattern known for " << ri_->get_maker() << " " << ri_->get_model() << std::endl; @@ -241,7 +251,7 @@ int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) if (settings->verbose) { static_cast(gthresh_)->print(); } - + static_cast(gthresh_)->processTiles(); return found; } From 81210d18b442ee473aced419e20b94117ce2ca66 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 10 Mar 2018 22:56:45 +0100 Subject: [PATCH 18/21] Added new mode "Horizontal on PDAF rows only" for the "line noise filter" --- rtdata/languages/default | 1 + rtengine/cfa_linedn_RT.cc | 13 +++++++++---- rtengine/pdaflinesfilter.cc | 39 +++++++++++++++++++++++++++++++++++++ rtengine/pdaflinesfilter.h | 1 + rtengine/procparams.h | 3 ++- rtengine/rawimagesource.cc | 10 +++++++++- rtengine/rawimagesource.h | 8 +++++++- rtgui/bayerpreprocess.cc | 13 +++++++++++-- 8 files changed, 79 insertions(+), 9 deletions(-) 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(); From f4e530f2acc616053b19c3808b21cd6e00e60ab5 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 11 Mar 2018 11:47:53 +0100 Subject: [PATCH 19/21] added PDAF pattern for A7RII --- rtengine/camconst.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 91c2cff2c..c03c035ca 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2286,7 +2286,10 @@ Camera constants: "make_model": [ "Sony ILCE-7RM2", "Sony DSC-RX1RM2" ], "dcraw_matrix": [ 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 ], // DNG_v9.1.1 D65 "raw_crop": [ 0, 0, -36, 0 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage - "ranges": { "black": 512, "white": 16300 } + "ranges": { "black": 512, "white": 16300 }, + // PDAF info provided by Horshack with the rawshack tool (http://testcams.com/rawshack/) + "pdafPattern" : [ 0,24,36,60,84,120,132,156,192,204,240,252,276,300,324,360,372,396,420 ], + "pdafOffset" : 31 }, { // Quality B, color matrix copied from a7rm2 From 814a235e9f3de14ba1e2af588d109f2d1f2396d7 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 11 Mar 2018 11:48:20 +0100 Subject: [PATCH 20/21] tweaked the behaviour of the line noise filter in PDAF mode --- rtengine/pdaflinesfilter.cc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index f648ad891..92fd68b41 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -130,8 +130,6 @@ private: 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), @@ -140,17 +138,24 @@ public: float operator()(int row) const { + static constexpr float BORDER[] = { 1.f, 1.f, 0.8f, 0.5f, 0.2f }; + static constexpr int BORDER_WIDTH = sizeof(BORDER)/sizeof(float) - 1; + 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; - } + + int b = *it; + int d = b - key; + + if (it > pattern_.begin()) { + int b2 = *(it-1); + int d2 = key - b2; + float f = BORDER[std::min(std::min(d, d2), BORDER_WIDTH)]; + return f; + } else { + float f = BORDER[std::min(d, BORDER_WIDTH)]; + return f; } } return 0.f; From 673ae937ec10d7ed1d83ce7f4015be76a3111272 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 11 Mar 2018 18:13:04 +0100 Subject: [PATCH 21/21] Small speedup and reduced memory usage for cfa_linedn() --- rtengine/cfa_linedn_RT.cc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 929a49d38..2bb3649b6 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -68,11 +68,10 @@ void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertica { // allocate memory and assure the arrays don't have same 64 byte boundary to avoid L1 conflict misses - float *cfain = (float*)malloc(4 * TS * TS * sizeof(float) + 3 * 16 * sizeof(float)); - float *cfablur = (cfain + (TS * TS) + 1 * 16); - float *cfadiff = (cfain + (2 * TS * TS) + 2 * 16); - float *cfadn = (cfain + (3 * TS * TS) + 3 * 16); - + float *cfain = (float*)malloc(3 * TS * TS * sizeof(float) + 2 * 16 * sizeof(float)); + float *cfadiff = (cfain + (1 * TS * TS) + 1 * 16); + float *cfadn = (cfain + (2 * TS * TS) + 2 * 16); + float cfablur[TS]; float linehvar[4], linevvar[4], noisefactor[4][8][2], coeffsq; float dctblock[4][8][8]; @@ -130,19 +129,19 @@ void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertica //gaussian blur of CFA data for (int rr = 8; rr < numrows - 8; rr++) { - for (int indx = rr * TS; indx < rr * TS + numcols; indx++) { - cfablur[indx] = gauss[0] * cfain[indx]; + for (int indx = rr * TS, indxb = 0; indx < rr * TS + numcols; indx++, indxb++) { + cfablur[indxb] = gauss[0] * cfain[indx]; for (int i = 1; i < 5; i++) { - cfablur[indx] += gauss[i] * (cfain[indx - (2 * i) * TS] + cfain[indx + (2 * i) * TS]); + cfablur[indxb] += gauss[i] * (cfain[indx - (2 * i) * TS] + cfain[indx + (2 * i) * TS]); } } - for (int indx = rr * TS + 8; indx < rr * TS + numcols - 8; indx++) { - cfadn[indx] = gauss[0] * cfablur[indx]; + for (int indx = rr * TS + 8, indxb = 8; indx < rr * TS + numcols - 8; indx++, indxb++) { + cfadn[indx] = gauss[0] * cfablur[indxb]; for (int i = 1; i < 5; i++) { - cfadn[indx] += gauss[i] * (cfablur[indx - 2 * i] + cfablur[indx + 2 * i]); + cfadn[indx] += gauss[i] * (cfablur[indxb - 2 * i] + cfablur[indxb + 2 * i]); } cfadiff[indx] = cfain[indx] - cfadn[indx]; // hipass cfa data @@ -252,7 +251,7 @@ void RawImageSource::CLASS cfa_linedn(float noise, bool horizontal, bool vertica free(cfain); // copy temporary buffer back to image matrix - #pragma omp for + #pragma omp for schedule(dynamic,16) for(int i = 0; i < height; i++) { float f = rowblender(i);