From 3f13a98135d7bfe8d03c6603b435cc99e2051355 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 02:20:43 +0100 Subject: [PATCH 01/83] Prepare rtengine to allow extraction of individual frames from multi frame raw files (i.e. Pentax pixel shift) --- rtengine/rawimage.cc | 4 +++- rtengine/rawimage.h | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 382ebe0a7..2d778a3b5 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -398,7 +398,7 @@ skip_block: } } -int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistener, double progressRange) +int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistener, double progressRange, unsigned int frameNum) { ifname = filename.c_str(); image = nullptr; @@ -435,6 +435,8 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene return 2; } + setFrameNumber(frameNum); + if (flip == 5) { this->rotate_deg = 270; } else if (flip == 3) { diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 88ef5d710..c3da24f0d 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -106,7 +106,7 @@ public: explicit RawImage( const Glib::ustring &name ); ~RawImage(); - int loadRaw (bool loadData = true, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); + int loadRaw (bool loadData = true, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0, unsigned int frameNum = 0); void get_colorsCoeff( float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB ); void set_prefilters() { @@ -307,6 +307,13 @@ public: return zero_is_bad == 1 ? true : false; } + void setFrameNumber(unsigned int frameNum) { + // a single raw file can contain more than one frame. + // Variable is_raw holds the number of frames in the raw file + // use setFrameNumber() to set the number of the frame [0; is_raw - 1] to be processed + shot_select = std::min(std::max(is_raw, 1) - 1, frameNum); + } + public: // dcraw functions void scale_colors() From a6876e258ab10d7138f844e11252ae876f940ac2 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 14:25:17 +0100 Subject: [PATCH 02/83] Fixed compilation error --- rtengine/rawimage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index c3da24f0d..474b9b8ee 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -311,7 +311,7 @@ public: // a single raw file can contain more than one frame. // Variable is_raw holds the number of frames in the raw file // use setFrameNumber() to set the number of the frame [0; is_raw - 1] to be processed - shot_select = std::min(std::max(is_raw, 1) - 1, frameNum); + shot_select = std::min(std::max(is_raw, 1u) - 1, frameNum); } public: From 405e9a29a288afacaa6fb65ad190bd68b7fbbea2 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 15:09:36 +0100 Subject: [PATCH 03/83] set frame number before identify --- rtengine/rawimage.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 2d778a3b5..8c09dbc50 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -13,7 +13,7 @@ #else #include #endif - +#include namespace rtengine { @@ -422,6 +422,8 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene raw_image = nullptr; //***************** Read ALL raw file info + setFrameNumber(frameNum); + identify (); if (!is_raw) { @@ -435,8 +437,6 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene return 2; } - setFrameNumber(frameNum); - if (flip == 5) { this->rotate_deg = 270; } else if (flip == 3) { From aca3b5aa825eb450bc9fe26b28b5c15255533857 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 16:33:59 +0100 Subject: [PATCH 04/83] Fix bug when requesting a nonexistant frame from Fuji RAF --- rtengine/dcraw.cc | 2 +- rtengine/dcraw.patch | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index dcfe66ee5..d4a9811d0 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -8572,7 +8572,7 @@ void CLASS identify() parse_fuji (i); } load_raw = &CLASS unpacked_load_raw; - fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); + fseek (ifp, 100+28*(shot_select > 0 && shot_select < is_raw), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); /*RT*/ exif_base = thumb_offset+12; diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch index 22c53d831..43f9e12eb 100644 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2016-10-28 13:45:27 +0000 -+++ dcraw.cc 2016-10-31 13:35:15 +0000 +--- dcraw.c 2016-11-01 01:07:55 +0000 ++++ dcraw.cc 2016-11-01 14:54:02 +0000 @@ -1,3 +1,16 @@ +/*RT*/#include +/*RT*/#include @@ -2892,8 +2892,12 @@ parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); -@@ -8494,6 +8575,7 @@ - fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); +@@ -8491,9 +8572,10 @@ + parse_fuji (i); + } + load_raw = &CLASS unpacked_load_raw; +- fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); ++ fseek (ifp, 100+28*(shot_select > 0 && shot_select < is_raw), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); +/*RT*/ exif_base = thumb_offset+12; From 742d7ee0374c8b001dd4664f562bd467aa79ecef Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 16:46:57 +0100 Subject: [PATCH 05/83] Small corrections to set the number of the frame to be extracted from raw file --- rtengine/rawimage.cc | 6 +++++- rtengine/rawimage.h | 7 ------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 8c09dbc50..b4add328b 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -422,10 +422,14 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene raw_image = nullptr; //***************** Read ALL raw file info - setFrameNumber(frameNum); + // set the number of the frame to extract. If the number is larger then number of existing frames - 1, dcraw will handle that correctly + shot_select = frameNum; identify (); + // in case dcraw didn't handle the above mentioned case... + shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); + if (!is_raw) { fclose(ifp); ifp = nullptr; diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 474b9b8ee..2ba434960 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -307,13 +307,6 @@ public: return zero_is_bad == 1 ? true : false; } - void setFrameNumber(unsigned int frameNum) { - // a single raw file can contain more than one frame. - // Variable is_raw holds the number of frames in the raw file - // use setFrameNumber() to set the number of the frame [0; is_raw - 1] to be processed - shot_select = std::min(std::max(is_raw, 1u) - 1, frameNum); - } - public: // dcraw functions void scale_colors() From d8593469eeccb04c6eb7871df8179acef4b28b04 Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 2 Nov 2016 02:06:40 +0100 Subject: [PATCH 06/83] Adding 'Image Number' to the Bayer Raw tool --- rtdata/languages/default | 4 ++ rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.cc | 2 +- rtengine/procevents.h | 1 + rtengine/procparams.cc | 14 ++++++ rtengine/procparams.h | 1 + rtengine/rawimage.cc | 4 +- rtengine/rawimage.h | 2 +- rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 3 +- rtengine/rtthumbnail.cc | 4 +- rtengine/rtthumbnail.h | 2 +- rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/bayerprocess.cc | 92 ++++++++++++++++++++++++----------- rtgui/bayerprocess.h | 7 ++- rtgui/paramsedited.cc | 8 ++- rtgui/paramsedited.h | 1 + rtgui/partialpastedlg.cc | 12 ++++- rtgui/partialpastedlg.h | 3 +- rtgui/thumbnail.cc | 2 +- 23 files changed, 126 insertions(+), 50 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index df9aaec7c..c66c3a64d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -675,6 +675,7 @@ HISTORY_MSG_440;CbDL - Method HISTORY_MSG_441;Retinex - Gain transmission HISTORY_MSG_442;Retinex - Scale HISTORY_MSG_443;Output Black Point Compensation +HISTORY_MSG_444;Raw Sub-Image HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -864,6 +865,7 @@ PARTIALPASTE_RAW_DCBENHANCE;DCB enhancement PARTIALPASTE_RAW_DCBITERATIONS;DCB iterations PARTIALPASTE_RAW_DMETHOD;Demosaic method PARTIALPASTE_RAW_FALSECOLOR;False color suppression +PARTIALPASTE_RAW_IMAGENUM;Sub-image PARTIALPASTE_RAW_LMMSEITERATIONS;LMMSE enhancement steps PARTIALPASTE_RESIZE;Resize PARTIALPASTE_RETINEX;Retinex @@ -1647,6 +1649,8 @@ TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to a TP_RAW_FALSECOLOR;False color suppression steps TP_RAW_HD;Threshold TP_RAW_HD_TOOLTIP;Lower values make hot/dead pixel detection more aggressive, but false positives may lead to artifacts. If you notice any artifacts appearing when enabling the Hot/Dead Pixel Filters, gradually increase the threshold value until they disappear. +TP_RAW_IMAGENUM;Sub-image +TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift, Dual Sensitivity). Use this button to select the sub-image.\n\nThe last sub-image will be used if you select a value beyond the real sub-image count. TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 59d46035b..4acffef6c 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -66,7 +66,7 @@ public: embProfile(nullptr), idata(nullptr), dirpyrdenoiseExpComp(INFINITY) {} virtual ~ImageSource () {} - virtual int load (const Glib::ustring &fname, bool batch = false) = 0; + virtual int load (const Glib::ustring &fname, int imageNum = 0, bool batch = false) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true) {}; virtual void demosaic (const RAWParams &raw) {}; virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ca1d44cbf..741370813 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -214,7 +214,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if (settings->verbose) { if (imgsrc->getSensorType() == ST_BAYER) { - printf("Demosaic Bayer image using method: %s\n", rp.bayersensor.method.c_str()); + printf("Demosaic Bayer image n.%d using method: %s\n", rp.bayersensor.imageNum + 1, rp.bayersensor.method.c_str()); } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { printf("Demosaic X-Trans image with using method: %s\n", rp.xtranssensor.method.c_str()); } diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 586243391..4860648da 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -6902,7 +6902,7 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, w_raw, h_raw, 1, 1.0, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, w_raw, h_raw, 1, 1.0, FALSE, 0); if (!raw) { delete thumb; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 52517e527..69cda228a 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -470,6 +470,7 @@ enum ProcEvent { EvRetinexgaintransmission = 440, EvLskal = 441, EvOBPCompens = 442, + EvRawImageNum = 443, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5a8ee39a6..fe0d450c9 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -879,6 +879,7 @@ void CoarseTransformParams::setDefaults() void RAWParams::setDefaults() { bayersensor.method = RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze]; + bayersensor.imageNum = 0; bayersensor.ccSteps = 0; bayersensor.dcb_iterations = 2; bayersensor.dcb_enhance = true; @@ -3315,6 +3316,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_string ("RAW Bayer", "Method", raw.bayersensor.method ); } + if (!pedited || pedited->raw.bayersensor.imageNum) { + keyFile.set_integer ("RAW Bayer", "ImageNum", raw.bayersensor.imageNum + 1 ); + } + if (!pedited || pedited->raw.bayersensor.ccSteps) { keyFile.set_integer ("RAW Bayer", "CcSteps", raw.bayersensor.ccSteps); } @@ -7321,6 +7326,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "ImageNum")) { + raw.bayersensor.imageNum = keyFile.get_integer ("RAW Bayer", "ImageNum") - 1; + + if (pedited) { + pedited->raw.bayersensor.imageNum = true; + } + } + if (keyFile.has_key ("RAW Bayer", "CcSteps")) { raw.bayersensor.ccSteps = keyFile.get_integer ("RAW Bayer", "CcSteps"); @@ -7837,6 +7850,7 @@ bool ProcParams::operator== (const ProcParams& other) && resize.width == other.resize.width && resize.height == other.resize.height && raw.bayersensor.method == other.raw.bayersensor.method + && raw.bayersensor.imageNum == other.raw.bayersensor.imageNum && raw.bayersensor.ccSteps == other.raw.bayersensor.ccSteps && raw.bayersensor.black0 == other.raw.bayersensor.black0 && raw.bayersensor.black1 == other.raw.bayersensor.black1 diff --git a/rtengine/procparams.h b/rtengine/procparams.h index c65e89e24..fc539144b 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1171,6 +1171,7 @@ public: static const char *methodstring[numMethods]; Glib::ustring method; + int imageNum; int ccSteps; double black0; double black1; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index b4add328b..0ec9f548c 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -398,7 +398,7 @@ skip_block: } } -int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistener, double progressRange, unsigned int frameNum) +int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, ProgressListener *plistener, double progressRange) { ifname = filename.c_str(); image = nullptr; @@ -423,7 +423,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene //***************** Read ALL raw file info // set the number of the frame to extract. If the number is larger then number of existing frames - 1, dcraw will handle that correctly - shot_select = frameNum; + shot_select = imageNum; identify (); diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 2ba434960..4f39ac855 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -106,7 +106,7 @@ public: explicit RawImage( const Glib::ustring &name ); ~RawImage(); - int loadRaw (bool loadData = true, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0, unsigned int frameNum = 0); + int loadRaw (bool loadData = true, unsigned int imageNum = 0, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); void get_colorsCoeff( float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB ); void set_prefilters() { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index b2e3e5e56..737e733cd 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1494,7 +1494,7 @@ void RawImageSource::vflip (Imagefloat* image) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::load (const Glib::ustring &fname, bool batch) +int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) { MyTime t1, t2; @@ -1507,7 +1507,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool batch) } ri = new RawImage(fname); - int errCode = ri->loadRaw (true, true, plistener, 0.8); + int errCode = ri->loadRaw (true, imageNum, true, plistener, 0.8); if (errCode) { return errCode; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 151edf959..cec3d78b7 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -107,7 +107,7 @@ public: RawImageSource (); ~RawImageSource (); - int load (const Glib::ustring &fname, bool batch = false); + int load (const Glib::ustring &fname, int imageNum = 0, bool batch = false); void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true); void demosaic (const RAWParams &raw); void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 025265e0a..8325ac17d 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -469,7 +469,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvcbdlMethod RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal - OUTPUTPROFILE // EvOBPCompens + OUTPUTPROFILE, // EvOBPCompens + DEMOSAIC // EvRawImageNum }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index c135acc39..afe60d5a0 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -281,10 +281,10 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) return rml; } -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum) { RawImage *ri = new RawImage (fname); - int r = ri->loadRaw(1, 0); + int r = ri->loadRaw(1, imageNum, 0); if( r ) { delete ri; diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 18e72fc19..da1c96f8d 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -78,7 +78,7 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 6017a1ca6..2eda4b512 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -110,7 +110,7 @@ void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleForma * and RT's image data type (Image8, Image16 and Imagefloat), then it will * load the image into it */ -int StdImageSource::load (const Glib::ustring &fname, bool batch) +int StdImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) { fileName = fname; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 0ef487a75..38b6952b0 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -42,7 +42,7 @@ public: StdImageSource (); ~StdImageSource (); - int load (const Glib::ustring &fname, bool batch = false); + int load (const Glib::ustring &fname, int imageNum = 0, bool batch = false); void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); ColorTemp getWB () const { diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 14c542172..3a4f2898a 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -38,6 +38,18 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); pack_start( *hb1, Gtk::PACK_SHRINK, 4); + imageNumberBox = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_IMAGENUM") + ": ")), Gtk::PACK_SHRINK, 4); + imageNumber = Gtk::manage (new MyComboBoxText ()); + imageNumber->append_text("1"); + imageNumber->append_text("2"); + imageNumber->append_text("3"); + imageNumber->append_text("4"); + imageNumber->set_active(0); + imageNumberBox->set_tooltip_text(M("TP_RAW_IMAGENUM_TOOLTIP")); + imageNumberBox->pack_end (*imageNumber, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start( *imageNumberBox, Gtk::PACK_SHRINK, 4); + dcbOptions = Gtk::manage (new Gtk::VBox ()); dcbOptions->set_border_width(4); @@ -88,6 +100,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); + imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -98,27 +111,33 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params disableListener (); methodconn.block (true); dcbEnhconn.block (true); + imagenumberconn.block (true); //allEnhconn.block (true); method->set_active(procparams::RAWParams::BayerSensor::numMethods); + imageNumber->set_active(pp->raw.bayersensor.imageNum); - for( size_t i = 0; i < procparams::RAWParams::BayerSensor::numMethods; i++) + for( size_t i = 0; i < procparams::RAWParams::BayerSensor::numMethods; i++) { if( pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[i]) { method->set_active(i); - oldSelection = i; + oldMethod = i; break; } + } - if(pedited ) { + if(pedited) { ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - if( !pedited->raw.bayersensor.method ) { + if(!pedited->raw.bayersensor.method) { method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name } + if(!pedited->raw.bayersensor.imageNum) { + imageNumber->set_active(4); + } } //allEnhance->set_active(pp->raw.bayersensor.all_enhance); @@ -126,35 +145,36 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); ccSteps->setValue (pp->raw.bayersensor.ccSteps); - - if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || - method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::lmmse] || - method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } + if (!batchMode) { + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || + method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { + dcbOptions->show(); + } else { + dcbOptions->hide(); + } + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::lmmse] || + method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { + lmmseOptions->show(); + } else { + lmmseOptions->hide(); + } - // Flase color suppression is applied to all demozaicing method, so don't hide anything - /*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] || - pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::hphd] || - pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::vng4]) - ccSteps->show(); - else - ccSteps->hide();*/ + // Flase color suppression is applied to all demozaicing method, so don't hide anything + /*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] || + pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::hphd] || + pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::vng4]) + ccSteps->show(); + else + ccSteps->hide();*/ + } lastDCBen = pp->raw.bayersensor.dcb_enhance; //lastALLen = pp->raw.bayersensor.all_enhance; methodconn.block (false); + imagenumberconn.block (false); dcbEnhconn.block (false); //allEnhconn.block (false); @@ -170,19 +190,24 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); int currentRow = method->get_active_row_number(); - if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { pp->raw.bayersensor.method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; } + currentRow = imageNumber->get_active_row_number(); + if (currentRow < 4) { + pp->raw.bayersensor.imageNum = currentRow; + } + + if (pedited) { pedited->raw.bayersensor.ccSteps = ccSteps->getEditedState (); pedited->raw.bayersensor.method = method->get_active_row_number() != procparams::RAWParams::BayerSensor::numMethods; + pedited->raw.bayersensor.imageNum = imageNumber->get_active_row_number() < 4; pedited->raw.bayersensor.dcbIterations = dcbIterations->getEditedState (); pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); - } } @@ -190,6 +215,8 @@ void BayerProcess::setBatchMode(bool batchMode) { method->append_text (M("GENERAL_UNCHANGED")); method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name + imageNumber->append_text (M("GENERAL_UNCHANGED")); + imageNumber->set_active(4); dcbOptions->hide(); lmmseOptions->hide(); ToolPanel::setBatchMode (batchMode); @@ -250,18 +277,25 @@ void BayerProcess::methodChanged () if( curSelection >= 0 && curSelection < procparams::RAWParams::BayerSensor::numMethods) { methodName = procparams::RAWParams::BayerSensor::methodstring[curSelection]; - if (curSelection == procparams::RAWParams::BayerSensor::mono || oldSelection == procparams::RAWParams::BayerSensor::mono) { + if (curSelection == procparams::RAWParams::BayerSensor::mono || oldMethod == procparams::RAWParams::BayerSensor::mono) { ppreq = true; } } - oldSelection = curSelection; + oldMethod = curSelection; if (listener) { listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); } } +void BayerProcess::imageNumberChanged () +{ + if (listener) { + listener->panelChanged (EvRawImageNum, imageNumber->get_active_text()); + } +} + void BayerProcess::dcbEnhanceChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index b78002ea3..bba4bd51d 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -31,6 +31,8 @@ class BayerProcess : public ToolParamBlock, public AdjusterListener, public Fold protected: MyComboBoxText* method; + Gtk::HBox *imageNumberBox; + MyComboBoxText* imageNumber; Adjuster* ccSteps; Gtk::VBox *dcbOptions; Adjuster* dcbIterations; @@ -41,9 +43,9 @@ protected: Adjuster* lmmseIterations; bool lastDCBen; - int oldSelection; + int oldMethod; //bool lastALLen; - sigc::connection methodconn, dcbEnhconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn; //,allEnhconn; public: BayerProcess (); @@ -54,6 +56,7 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); void methodChanged (); + void imageNumberChanged (); void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); //void allEnhanceChanged(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ff3e4c0b1..ebb31ef1d 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -359,6 +359,7 @@ void ParamsEdited::set (bool v) icm.gampos = v; icm.slpos = v; raw.bayersensor.method = v; + raw.bayersensor.imageNum = v; raw.bayersensor.ccSteps = v; raw.bayersensor.exBlack0 = v; raw.bayersensor.exBlack1 = v; @@ -854,6 +855,7 @@ void ParamsEdited::initFrom (const std::vector icm.gampos = icm.gampos && p.icm.gampos == other.icm.gampos; icm.slpos = icm.slpos && p.icm.slpos == other.icm.slpos; raw.bayersensor.method = raw.bayersensor.method && p.raw.bayersensor.method == other.raw.bayersensor.method; + raw.bayersensor.imageNum = raw.bayersensor.imageNum && p.raw.bayersensor.imageNum == other.raw.bayersensor.imageNum; raw.bayersensor.ccSteps = raw.bayersensor.ccSteps && p.raw.bayersensor.ccSteps == other.raw.bayersensor.ccSteps; raw.bayersensor.exBlack0 = raw.bayersensor.exBlack0 && p.raw.bayersensor.black0 == other.raw.bayersensor.black0; raw.bayersensor.exBlack1 = raw.bayersensor.exBlack1 && p.raw.bayersensor.black1 == other.raw.bayersensor.black1; @@ -2236,6 +2238,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.method = mods.raw.bayersensor.method; } + if (raw.bayersensor.imageNum) { + toEdit.raw.bayersensor.imageNum = mods.raw.bayersensor.imageNum; + } + if (raw.bayersensor.ccSteps) { toEdit.raw.bayersensor.ccSteps = mods.raw.bayersensor.ccSteps; } @@ -2782,7 +2788,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten bool RAWParamsEdited::BayerSensor::isUnchanged() const { - return method && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq + return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 19d143398..4e9fa4eb4 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -682,6 +682,7 @@ public: public: bool method; + bool imageNum; bool ccSteps; bool exBlack0; bool exBlack1; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 78631b725..19a83381e 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -112,6 +112,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title) raw_linenoise = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_LINEDENOISE"))); raw_greenthresh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_GREENEQUIL"))); raw_method = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_DMETHOD"))); + raw_imagenum = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_IMAGENUM"))); raw_ccSteps = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_FALSECOLOR"))); raw_dcb_iterations = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_DCBITERATIONS"))); raw_dcb_enhance = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_DCBENHANCE"))); @@ -201,6 +202,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title) vboxes[6]->pack_start (*raw, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*hseps[6], Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_method, Gtk::PACK_SHRINK, 2); + vboxes[6]->pack_start (*raw_imagenum, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_ccSteps, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_dcb_iterations, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_dcb_enhance, Gtk::PACK_SHRINK, 2); @@ -340,7 +342,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title) exifchConn = exifch->signal_toggled().connect (sigc::bind (sigc::mem_fun(*meta, &Gtk::CheckButton::set_inconsistent), true)); iptcConn = iptc->signal_toggled().connect (sigc::bind (sigc::mem_fun(*meta, &Gtk::CheckButton::set_inconsistent), true)); - raw_methodConn = raw_method->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + raw_methodConn = raw_method->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + raw_imagenumConn = raw_imagenum->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_ccStepsConn = raw_ccSteps->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_dcb_iterationsConn = raw_dcb_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_dcb_enhanceConn = raw_dcb_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); @@ -420,6 +423,7 @@ void PartialPasteDlg::rawToggled () { raw_methodConn.block (true); + raw_imagenumConn.block (true); raw_ccStepsConn.block (true); raw_dcb_iterationsConn.block (true); raw_dcb_enhanceConn.block (true); @@ -446,6 +450,7 @@ void PartialPasteDlg::rawToggled () raw->set_inconsistent (false); raw_method->set_active (raw->get_active ()); + raw_imagenum->set_active (raw->get_active ()); raw_ccSteps->set_active (raw->get_active ()); raw_dcb_iterations->set_active (raw->get_active ()); raw_dcb_enhance->set_active (raw->get_active ()); @@ -470,6 +475,7 @@ void PartialPasteDlg::rawToggled () ff_ClipControl->set_active (raw->get_active ()); raw_methodConn.block (false); + raw_imagenumConn.block (false); raw_ccStepsConn.block (false); raw_dcb_iterationsConn.block (false); raw_dcb_enhanceConn.block (false); @@ -849,6 +855,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.raw.xtranssensor.method = falsePE.raw.xtranssensor.method; } + if (!raw_imagenum->get_active ()) { + filterPE.raw.bayersensor.imageNum = falsePE.raw.bayersensor.imageNum; + } + if (!raw_ccSteps->get_active ()) { filterPE.raw.bayersensor.ccSteps = falsePE.raw.bayersensor.ccSteps; filterPE.raw.xtranssensor.ccSteps = falsePE.raw.xtranssensor.ccSteps; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index d22f50fad..8c9118755 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -107,6 +107,7 @@ public: Gtk::CheckButton* raw_linenoise; Gtk::CheckButton* raw_greenthresh; Gtk::CheckButton* raw_method; + Gtk::CheckButton* raw_imagenum; Gtk::CheckButton* raw_ccSteps; Gtk::CheckButton* raw_dcb_iterations; Gtk::CheckButton* raw_dcb_enhance; @@ -129,7 +130,7 @@ public: sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; sigc::connection exifchConn, iptcConn, icmConn; sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; - sigc::connection raw_caredConn, raw_cablueConn, raw_ca_autocorrectConn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; + sigc::connection raw_caredConn, raw_cablueConn, 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_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; public: explicit PartialPasteDlg (const Glib::ustring &title); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 71aeab0ab..300f61e09 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -137,7 +137,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, pparams.wb.equal, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, pparams.wb.equal, TRUE, pparams.raw.bayersensor.imageNum); } if (tpp) { From 6276b17be29f1e21c41f9e6d270c3d0b35898c88 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 2 Nov 2016 02:47:54 +0100 Subject: [PATCH 07/83] Fix segfault --- rtengine/rtthumbnail.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index afe60d5a0..6321f0dcf 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -156,7 +156,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate, bool inspectorMode) { RawImage *ri = new RawImage(fname); - int r = ri->loadRaw(false, false); + int r = ri->loadRaw(false, 0, false); if( r ) { delete ri; From 89901f4b367f205087cc88857cfe66d04cca38b3 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 3 Nov 2016 00:01:47 +0100 Subject: [PATCH 08/83] reworked pixelshift code and temporary removed Fuji S5 dual frame support --- rtengine/dfmanager.cc | 11 +++++++---- rtengine/ffmanager.cc | 12 +++++++----- rtengine/imagesource.h | 3 +++ rtengine/improccoordinator.cc | 1 + rtengine/rawimage.cc | 4 +++- rtengine/rawimage.h | 2 +- rtengine/rawimagesource.cc | 30 ++++++++++++++++++++++-------- rtengine/rawimagesource.h | 11 +++++++++-- rtengine/refreshmap.cc | 2 +- rtengine/rtthumbnail.cc | 11 ++++++++--- rtengine/simpleprocess.cc | 1 + rtengine/stdimagesource.h | 2 ++ 12 files changed, 65 insertions(+), 25 deletions(-) diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index ab76ff854..1dedf661f 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -138,7 +138,8 @@ void dfInfo::updateRawImage() std::list::iterator iName = pathNames.begin(); ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) - if( ri->loadRaw(true)) { + unsigned int imageNum = 0; + if( ri->loadRaw(true, imageNum)) { delete ri; ri = nullptr; } else { @@ -163,7 +164,7 @@ void dfInfo::updateRawImage() for( ++iName; iName != pathNames.end(); ++iName) { RawImage* temp = new RawImage(*iName); - if( !temp->loadRaw(true)) { + if( !temp->loadRaw(true,imageNum)) { temp->compress_image(); //\ TODO would be better working on original, because is temporary nFiles++; @@ -199,8 +200,9 @@ void dfInfo::updateRawImage() } } else { ri = new RawImage(pathname); + unsigned int imageNum = 0; - if( ri->loadRaw(true)) { + if( ri->loadRaw(true,imageNum)) { delete ri; ri = nullptr; } else { @@ -365,7 +367,8 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) } RawImage ri (filename); - int res = ri.loadRaw (false); // Read informations about shot + unsigned int imageNum = 0; + int res = ri.loadRaw (false, imageNum); // Read informations about shot if (res != 0) { return nullptr; diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 069bbf563..42a46802b 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -130,8 +130,8 @@ void ffInfo::updateRawImage() if( !pathNames.empty() ) { std::list::iterator iName = pathNames.begin(); ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) - - if( ri->loadRaw(true)) { + unsigned int imageNum = 0; + if( ri->loadRaw(true, imageNum)) { delete ri; ri = nullptr; } else { @@ -156,7 +156,7 @@ void ffInfo::updateRawImage() for( ++iName; iName != pathNames.end(); ++iName) { RawImage* temp = new RawImage(*iName); - if( !temp->loadRaw(true)) { + if( !temp->loadRaw(true,imageNum)) { temp->compress_image(); //\ TODO would be better working on original, because is temporary nFiles++; @@ -192,8 +192,9 @@ void ffInfo::updateRawImage() } } else { ri = new RawImage(pathname); + unsigned int imageNum = 0; - if( ri->loadRaw(true)) { + if( ri->loadRaw(true, imageNum)) { delete ri; ri = nullptr; } else { @@ -326,7 +327,8 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) RawImage ri (filename); - int res = ri.loadRaw (false); // Read informations about shot + unsigned int imageNum = 0; + int res = ri.loadRaw (false, imageNum); // Read informations about shot if (res != 0) { return nullptr; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 4acffef6c..98e5446a1 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -80,6 +80,9 @@ public: virtual bool IsrgbSourceModified() const = 0; // tracks whether cached rgb output of demosaic has been modified + virtual void setCurrentFrame(unsigned int frameNum) = 0; + + // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hlp, const ColorManagementParams &cmp, const RAWParams &raw) = 0; virtual eSensorType getSensorType () diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 741370813..afa791b4f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -185,6 +185,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed if ( (todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) { + imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); imgsrc->preprocess( rp, params.lensProf, params.coarse ); imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw ); diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 0ec9f548c..85d6a00b5 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -398,7 +398,7 @@ skip_block: } } -int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, ProgressListener *plistener, double progressRange) +int RawImage::loadRaw (bool loadData, unsigned int &imageNum, bool closeFile, ProgressListener *plistener, double progressRange) { ifname = filename.c_str(); image = nullptr; @@ -427,8 +427,10 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro identify (); + std::cout << "israw : " << is_raw << std::endl; // in case dcraw didn't handle the above mentioned case... shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); + imageNum = shot_select; if (!is_raw) { fclose(ifp); diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 4f39ac855..4080702a6 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -106,7 +106,7 @@ public: explicit RawImage( const Glib::ustring &name ); ~RawImage(); - int loadRaw (bool loadData = true, unsigned int imageNum = 0, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); + int loadRaw (bool loadData, unsigned int &imageNum, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); void get_colorsCoeff( float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB ); void set_prefilters() { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 737e733cd..1d30706aa 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -475,8 +475,8 @@ RawImageSource::~RawImageSource () delete idata; - if (ri) { - delete ri; + for(size_t i = 0; i < numFrames; ++i) { + delete riFrames[i]; } flushRGB(); @@ -1506,14 +1506,29 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgress (0.0); } - ri = new RawImage(fname); - int errCode = ri->loadRaw (true, imageNum, true, plistener, 0.8); + unsigned int tempImageNum = 4; + do { + tempImageNum --; + numFrames ++; + ri = new RawImage(fname); + int errCode = ri->loadRaw (true, tempImageNum, true, plistener, 0.8); + std::cout << "imagenum : " << tempImageNum << " width : " << ri->get_width() << " height : " << ri->get_height() << std::endl; - if (errCode) { - return errCode; + if (errCode) { + return errCode; + } + riFrames[tempImageNum] = ri; + ri->compress_image(); + ri->set_prefilters(); + } while (tempImageNum); + + if(numFrames > 1 ) { + if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) { + numFrames = 1; + } } - ri->compress_image(); +std::cout << "numframes : " << numFrames << std::endl; if (plistener) { plistener->setProgress (0.9); @@ -1627,7 +1642,6 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) }*/ - ri->set_prefilters(); //Load complete Exif informations RawMetaDataLocation rml; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index cec3d78b7..79d89be88 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -25,7 +25,7 @@ #include "curves.h" #include "color.h" #include "iimage.h" - +#include #define HR_SCALE 2 namespace rtengine @@ -71,6 +71,9 @@ protected: bool rgbSourceModified; RawImage* ri; // Copy of raw pixels, NOT corrected for initial gain, blackpoint etc. + RawImage* riFrames[16] = {nullptr}; + unsigned int currFrame = 0; + unsigned int numFrames = 0; // to accelerate CIELAB conversion: double lc00, lc01, lc02, lc10, lc11, lc12, lc20, lc21, lc22; @@ -195,7 +198,11 @@ public: static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax); static void init (); static void cleanup (); - + void setCurrentFrame(unsigned int frameNum) { + currFrame = std::min(numFrames - 1, frameNum); + ri = riFrames[currFrame]; + std::cout << "currFrame : " << currFrame << std::endl; + } protected: typedef unsigned short ushort; void processFalseColorCorrection (Imagefloat* i, const int steps); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 8325ac17d..33e988674 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -470,7 +470,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens - DEMOSAIC // EvRawImageNum + DARKFRAME // EvRawImageNum }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 6321f0dcf..9b71d2156 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -156,7 +156,8 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate, bool inspectorMode) { RawImage *ri = new RawImage(fname); - int r = ri->loadRaw(false, 0, false); + unsigned int imageNum = 0; + int r = ri->loadRaw(false, imageNum, false); if( r ) { delete ri; @@ -270,7 +271,9 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) rml.ciffLength = -1; RawImage ri(fname); - int r = ri.loadRaw(false); + unsigned int imageNum = 0; + + int r = ri.loadRaw(false, imageNum); if( !r ) { rml.exifBase = ri.get_exifBase(); @@ -284,7 +287,9 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum) { RawImage *ri = new RawImage (fname); - int r = ri->loadRaw(1, imageNum, 0); + unsigned int tempImageNum = 0; + + int r = ri->loadRaw(1, tempImageNum, 0); if( r ) { delete ri; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 9e7d5f58f..250875b6a 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -102,6 +102,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p ImProcFunctions ipf (¶ms, true); PreviewProps pp (0, 0, fw, fh, 1); + imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); imgsrc->preprocess( params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled); if (params.toneCurve.autoexp) {// this enabled HLRecovery diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 38b6952b0..733a44c42 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -95,6 +95,8 @@ public: { return rgbSourceModified; } + void setCurrentFrame(unsigned int frameNum) {} + }; } #endif From 81fa149570649031f53f1d56341696c29bb35c03 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 3 Nov 2016 00:41:33 +0100 Subject: [PATCH 09/83] small change for Hombre --- rtengine/rawimage.cc | 7 +++++-- rtengine/rawimagesource.cc | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 85d6a00b5..395a8bc55 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -423,13 +423,16 @@ int RawImage::loadRaw (bool loadData, unsigned int &imageNum, bool closeFile, Pr //***************** Read ALL raw file info // set the number of the frame to extract. If the number is larger then number of existing frames - 1, dcraw will handle that correctly - shot_select = imageNum; identify (); + fclose(ifp); + ifp = gfopen (ifname); // Maps to either file map or direct fopen + shot_select = imageNum; + shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); + identify(); std::cout << "israw : " << is_raw << std::endl; // in case dcraw didn't handle the above mentioned case... - shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); imageNum = shot_select; if (!is_raw) { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1d30706aa..9cef132ae 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1506,7 +1506,7 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgress (0.0); } - unsigned int tempImageNum = 4; + unsigned int tempImageNum = 16; do { tempImageNum --; numFrames ++; From 2d730572f58ec1c51f74b24496698c8c9d2c108a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 3 Nov 2016 01:27:56 +0100 Subject: [PATCH 10/83] Fixed gui (thanks to Hombre) and cleaned code a bit --- rtengine/rawimage.cc | 6 +----- rtengine/rawimagesource.cc | 25 ++++++++++++++++++++----- rtgui/bayerprocess.cc | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 395a8bc55..43b829148 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -424,15 +424,11 @@ int RawImage::loadRaw (bool loadData, unsigned int &imageNum, bool closeFile, Pr //***************** Read ALL raw file info // set the number of the frame to extract. If the number is larger then number of existing frames - 1, dcraw will handle that correctly - identify (); - fclose(ifp); - ifp = gfopen (ifname); // Maps to either file map or direct fopen - shot_select = imageNum; - shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); identify(); std::cout << "israw : " << is_raw << std::endl; // in case dcraw didn't handle the above mentioned case... + shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); imageNum = shot_select; if (!is_raw) { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 9cef132ae..6e71e771f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1506,9 +1506,21 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgress (0.0); } - unsigned int tempImageNum = 16; - do { - tempImageNum --; + unsigned int tempImageNum = 256; + // requesting a subimage which is not available gives subimage 0. We use 256 to access a non existent frame resulting in frame 0 + ri = new RawImage(fname); + int errCode = ri->loadRaw (true, tempImageNum, true, plistener, 0.8); + // now tempImageNum is adjusted to the number of last frame + + if (errCode) { + return errCode; + } + ri->compress_image(); + ri->set_prefilters(); + riFrames[0] = ri; + numFrames ++; + + while (tempImageNum) { numFrames ++; ri = new RawImage(fname); int errCode = ri->loadRaw (true, tempImageNum, true, plistener, 0.8); @@ -1520,9 +1532,10 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) riFrames[tempImageNum] = ri; ri->compress_image(); ri->set_prefilters(); - } while (tempImageNum); + tempImageNum --; + } - if(numFrames > 1 ) { + if(numFrames > 1 ) { // this disables multi frame support for Fuji S5 until I found a solution to handle different dimensions if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) { numFrames = 1; } @@ -1530,6 +1543,8 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) std::cout << "numframes : " << numFrames << std::endl; + ri = riFrames[0]; + if (plistener) { plistener->setProgress (0.9); } diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 3a4f2898a..639eabc02 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -39,7 +39,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pack_start( *hb1, Gtk::PACK_SHRINK, 4); imageNumberBox = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_IMAGENUM") + ": ")), Gtk::PACK_SHRINK, 4); + imageNumberBox->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_IMAGENUM") + ": ")), Gtk::PACK_SHRINK, 4); imageNumber = Gtk::manage (new MyComboBoxText ()); imageNumber->append_text("1"); imageNumber->append_text("2"); From f27241a745eda1c510ac6a818e0c6db660c50735 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 4 Nov 2016 18:27:21 +0100 Subject: [PATCH 11/83] Pentax pixelshift v0.0 --- rtengine/CMakeLists.txt | 1 + rtengine/procparams.cc | 2 +- rtengine/procparams.h | 2 +- rtengine/rawimagesource.cc | 76 +++++++++++++++++++++++++++++++++++++- rtengine/rawimagesource.h | 3 ++ rtexif/pentaxattribs.cc | 1 + 6 files changed, 82 insertions(+), 3 deletions(-) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 1f4f3375f..49db10faa 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -24,6 +24,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc klt/storeFeatures.cc klt/trackFeatures.cc klt/writeFeatures.cc clutstore.cc ciecam02.cc + pixelshift.cc ) include_directories (BEFORE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index fe0d450c9..2a7b41847 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -40,7 +40,7 @@ const int br = (int) options.rtSettings.bot_right; const int tl = (int) options.rtSettings.top_left; const int bl = (int) options.rtSettings.bot_left; -const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "fast", "mono", "none" }; +const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "fast", "mono", "none", "pixelshift simple" }; const char *RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::numMethods] = {"3-pass (best)", "1-pass (medium)", "fast", "mono", "none" }; const char *RAWParams::ff_BlurTypestring[RAWParams::numFlatFileBlurTypes] = {/*"Parametric",*/ "Area Flatfield", "Vertical Flatfield", "Horizontal Flatfield", "V+H Flatfield"}; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index fc539144b..35a4f1932 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1165,7 +1165,7 @@ public: public: //enum eMethod{ eahd,hphd,vng4,dcb,amaze,ahd,IGV_noise,fast, //numMethods }; // This MUST be the last enum - enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, + enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, pixelshift_simple, numMethods }; // This MUST be the last enum static const char *methodstring[numMethods]; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 6e71e771f..4ebbd5dc6 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1506,6 +1506,7 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgress (0.0); } +StopWatch Stop1("loadraw"); unsigned int tempImageNum = 256; // requesting a subimage which is not available gives subimage 0. We use 256 to access a non existent frame resulting in frame 0 ri = new RawImage(fname); @@ -1544,7 +1545,7 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) std::cout << "numframes : " << numFrames << std::endl; ri = riFrames[0]; - +Stop1.stop(); if (plistener) { plistener->setProgress (0.9); } @@ -1948,6 +1949,13 @@ void RawImageSource::demosaic(const RAWParams &raw) ahd_demosaic (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); + } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { + if(numFrames == 4) { + pixelshift_simple(0, 0, W, H); + scaleColors_pixelshift( 0, 0, W, H, raw); + } else { + amaze_demosaic_RT (0, 0, W, H); + } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::eahd]) { @@ -3498,6 +3506,72 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R } +void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw) +{ + chmax[0] = chmax[1] = chmax[2] = chmax[3] = 0; //channel maxima + float black_lev[4] = {0.f};//black level + + //adjust black level (eg Canon) + bool isMono = false; + + black_lev[0] = raw.bayersensor.black1; //R + black_lev[1] = raw.bayersensor.black0; //G1 + black_lev[2] = raw.bayersensor.black2; //B + black_lev[3] = raw.bayersensor.black3; //G2 + + for(int i = 0; i < 4 ; i++) { + cblacksom[i] = max( c_black[i] + black_lev[i], 0.0f ); // adjust black level + } + + initialGain = calculate_scale_mul(scale_mul, ref_pre_mul, c_white, cblacksom, isMono, ri->get_colors()); // recalculate scale colors with adjusted levels + + //fprintf(stderr, "recalc: %f [%f %f %f %f]\n", initialGain, scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]); + for(int i = 0; i < 4 ; i++) { + clmax[i] = (c_white[i] - cblacksom[i]) * scale_mul[i]; // raw clip level + } + + // this seems strange, but it works + + // scale image colors + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + float tmpchmax[3]; + tmpchmax[0] = tmpchmax[1] = tmpchmax[2] = 0.0f; +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int row = winy; row < winy + winh; row ++) + { + for (int col = winx; col < winx + winw; col++) { + float redval = (red[row][col] - cblacksom[0]) * scale_mul[0]; + tmpchmax[0] = max(tmpchmax[0], redval); + red[row][col] = redval; + + float greenval = (green[row][col] - cblacksom[1]) * scale_mul[1]; + tmpchmax[1] = max(tmpchmax[1], greenval); + green[row][col] = greenval; + + float blueval = (blue[row][col] - cblacksom[2]) * scale_mul[2]; + tmpchmax[2] = max(tmpchmax[2], blueval); + blue[row][col] = blueval; + } + } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + chmax[0] = max(tmpchmax[0], chmax[0]); + chmax[1] = max(tmpchmax[1], chmax[1]); + chmax[2] = max(tmpchmax[2], chmax[2]); + } + } +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int RawImageSource::defTransform (int tran) diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 79d89be88..abf1f6b97 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -131,6 +131,8 @@ public: void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile ); void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW); void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw); // raw for cblack + void scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw); + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); eSensorType getSensorType () const @@ -260,6 +262,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); + void pixelshift_simple(int winx, int winy, int winw, int winh); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc index 9fc6b6fb6..13dca86b1 100644 --- a/rtexif/pentaxattribs.cc +++ b/rtexif/pentaxattribs.cc @@ -42,6 +42,7 @@ public: choices[3] = "TIFF"; choices[4] = "RAW"; choices[5] = "Premium"; + choices[6] = "RAW (HDR enabled)"; choices[7] = "RAW (pixel shift enabled)"; choices[65535] = "n/a"; } From eaaf841f27e7b00dbf639e3ce31cd69890c2a743 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 4 Nov 2016 18:52:06 +0100 Subject: [PATCH 12/83] Forgot to add one file --- rtengine/pixelshift.cc | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 rtengine/pixelshift.cc diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc new file mode 100644 index 000000000..944fc9790 --- /dev/null +++ b/rtengine/pixelshift.cc @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////// +// +// pixelshift +// +// +// pixelshift.cc is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +//////////////////////////////////////////////////////////////// + +#include +#include "rawimagesource.h" +#include "../rtgui/multilangmgr.h" +#include "procparams.h" +#include "opthelper.h" +#define BENCHMARK +#include "StopWatch.h" +using namespace std; +using namespace rtengine; + +void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh) +{ + +BENCHFUN + double progress = 0.0; + const bool plistenerActive = plistener; + + //int winx=0, winy=0; + //int winw=W, winh=H; + + if (plistener) { + plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); + plistener->setProgress (progress); + } + + + const int bord = 2; + + #pragma omp parallel for + for(int i = bord; i < winh - bord; ++i) { + for(int j = bord; j< winw - bord; ++j) { + int c = FC(i,j); + if(c == 0) { + red[i][j] = riFrames[0]->data[i][j]; + green[i][j] = riFrames[3]->data[i][j+1]; + blue[i][j] = riFrames[2]->data[i+1][j+1]; + } else if(c & 1) { + green[i][j] = riFrames[0]->data[i][j]; + if(FC(i,j+1) == 0) { + red[i][j] = riFrames[3]->data[i][j+1]; + blue[i][j] = riFrames[1]->data[i+1][j]; + } else { + blue[i][j] = riFrames[3]->data[i][j+1]; + red[i][j] = riFrames[1]->data[i+1][j]; + } + } else { + blue[i][j] = riFrames[0]->data[i][j]; + red[i][j] = riFrames[2]->data[i+1][j+1]; + green[i][j] = riFrames[3]->data[i][j+1]; + } + } + } + +// if(plistenerActive && ((++progressCounter) % 16 == 0)) { +//#ifdef _OPENMP +// #pragma omp critical (updateprogress) +//#endif +// { +// progress += progressInc; +// progress = min(1.0, progress); +// plistener->setProgress (progress); +// } +// } + + if(plistenerActive) { + plistener->setProgress(1.00); + } + + + +} +#undef TS +#undef CLF From 5b455702a2ca597e83a87dcd2b0ba4e4f0751b25 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 6 Nov 2016 16:42:20 +0100 Subject: [PATCH 13/83] pixelshift: Fixed a bug, cleaned code, parallel decode of frames --- rtengine/dfmanager.cc | 11 +++---- rtengine/ffmanager.cc | 12 +++----- rtengine/pixelshift.cc | 24 +++------------ rtengine/rawimage.cc | 4 +-- rtengine/rawimage.h | 3 +- rtengine/rawimagesource.cc | 62 +++++++++++++++++++++----------------- rtengine/rawimagesource.h | 1 - 7 files changed, 51 insertions(+), 66 deletions(-) diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 1dedf661f..ab76ff854 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -138,8 +138,7 @@ void dfInfo::updateRawImage() std::list::iterator iName = pathNames.begin(); ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) - unsigned int imageNum = 0; - if( ri->loadRaw(true, imageNum)) { + if( ri->loadRaw(true)) { delete ri; ri = nullptr; } else { @@ -164,7 +163,7 @@ void dfInfo::updateRawImage() for( ++iName; iName != pathNames.end(); ++iName) { RawImage* temp = new RawImage(*iName); - if( !temp->loadRaw(true,imageNum)) { + if( !temp->loadRaw(true)) { temp->compress_image(); //\ TODO would be better working on original, because is temporary nFiles++; @@ -200,9 +199,8 @@ void dfInfo::updateRawImage() } } else { ri = new RawImage(pathname); - unsigned int imageNum = 0; - if( ri->loadRaw(true,imageNum)) { + if( ri->loadRaw(true)) { delete ri; ri = nullptr; } else { @@ -367,8 +365,7 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) } RawImage ri (filename); - unsigned int imageNum = 0; - int res = ri.loadRaw (false, imageNum); // Read informations about shot + int res = ri.loadRaw (false); // Read informations about shot if (res != 0) { return nullptr; diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 42a46802b..7dd9140a1 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -130,8 +130,7 @@ void ffInfo::updateRawImage() if( !pathNames.empty() ) { std::list::iterator iName = pathNames.begin(); ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) - unsigned int imageNum = 0; - if( ri->loadRaw(true, imageNum)) { + if( ri->loadRaw(true)) { delete ri; ri = nullptr; } else { @@ -156,7 +155,7 @@ void ffInfo::updateRawImage() for( ++iName; iName != pathNames.end(); ++iName) { RawImage* temp = new RawImage(*iName); - if( !temp->loadRaw(true,imageNum)) { + if( !temp->loadRaw(true)) { temp->compress_image(); //\ TODO would be better working on original, because is temporary nFiles++; @@ -192,9 +191,7 @@ void ffInfo::updateRawImage() } } else { ri = new RawImage(pathname); - unsigned int imageNum = 0; - - if( ri->loadRaw(true, imageNum)) { + if( ri->loadRaw(true)) { delete ri; ri = nullptr; } else { @@ -327,8 +324,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) RawImage ri (filename); - unsigned int imageNum = 0; - int res = ri.loadRaw (false, imageNum); // Read informations about shot + int res = ri.loadRaw (false); // Read informations about shot if (res != 0) { return nullptr; diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 944fc9790..20f27294a 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -1,6 +1,7 @@ //////////////////////////////////////////////////////////////// // -// pixelshift +// simple pentax pixelshift algorithm +// copyright (c) Ingo Weyrich 2016 // // // pixelshift.cc is free software: you can redistribute it and/or modify @@ -23,7 +24,7 @@ #include "../rtgui/multilangmgr.h" #include "procparams.h" #include "opthelper.h" -#define BENCHMARK +//#define BENCHMARK #include "StopWatch.h" using namespace std; using namespace rtengine; @@ -35,18 +36,16 @@ BENCHFUN double progress = 0.0; const bool plistenerActive = plistener; - //int winx=0, winy=0; - //int winw=W, winh=H; - if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); plistener->setProgress (progress); } - const int bord = 2; +#ifdef _OPENMP #pragma omp parallel for +#endif for(int i = bord; i < winh - bord; ++i) { for(int j = bord; j< winw - bord; ++j) { int c = FC(i,j); @@ -71,23 +70,10 @@ BENCHFUN } } -// if(plistenerActive && ((++progressCounter) % 16 == 0)) { -//#ifdef _OPENMP -// #pragma omp critical (updateprogress) -//#endif -// { -// progress += progressInc; -// progress = min(1.0, progress); -// plistener->setProgress (progress); -// } -// } - if(plistenerActive) { plistener->setProgress(1.00); } - - } #undef TS #undef CLF diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 43b829148..f4a412ca5 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -398,7 +398,7 @@ skip_block: } } -int RawImage::loadRaw (bool loadData, unsigned int &imageNum, bool closeFile, ProgressListener *plistener, double progressRange) +int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, ProgressListener *plistener, double progressRange) { ifname = filename.c_str(); image = nullptr; @@ -426,10 +426,8 @@ int RawImage::loadRaw (bool loadData, unsigned int &imageNum, bool closeFile, Pr shot_select = imageNum; identify(); - std::cout << "israw : " << is_raw << std::endl; // in case dcraw didn't handle the above mentioned case... shot_select = std::min(shot_select, std::max(is_raw, 1u) - 1); - imageNum = shot_select; if (!is_raw) { fclose(ifp); diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 4080702a6..cb9e9100e 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -106,7 +106,7 @@ public: explicit RawImage( const Glib::ustring &name ); ~RawImage(); - int loadRaw (bool loadData, unsigned int &imageNum, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); + int loadRaw (bool loadData, unsigned int imageNum = 0, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); void get_colorsCoeff( float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB ); void set_prefilters() { @@ -122,6 +122,7 @@ public: float** compress_image(); // revert to compressed pixels format and release image data float** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column unsigned prefilters; // original filters saved ( used for 4 color processing ) + unsigned int getFrameCount() const { return is_raw; } protected: Glib::ustring filename; // complete filename int rotate_deg; // 0,90,180,270 degree of rotation: info taken by dcraw from exif diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 4ebbd5dc6..37cf2618e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1505,47 +1505,52 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgressStr ("Decoding..."); plistener->setProgress (0.0); } - -StopWatch Stop1("loadraw"); - unsigned int tempImageNum = 256; - // requesting a subimage which is not available gives subimage 0. We use 256 to access a non existent frame resulting in frame 0 +StopWatch Stop1("decode"); ri = new RawImage(fname); - int errCode = ri->loadRaw (true, tempImageNum, true, plistener, 0.8); - // now tempImageNum is adjusted to the number of last frame + int errCode = ri->loadRaw (false, 0, false); if (errCode) { return errCode; } - ri->compress_image(); - ri->set_prefilters(); - riFrames[0] = ri; - numFrames ++; + numFrames = ri->getFrameCount(); - while (tempImageNum) { - numFrames ++; - ri = new RawImage(fname); - int errCode = ri->loadRaw (true, tempImageNum, true, plistener, 0.8); - std::cout << "imagenum : " << tempImageNum << " width : " << ri->get_width() << " height : " << ri->get_height() << std::endl; - - if (errCode) { - return errCode; + errCode = 0; +#ifdef _OPENMP +#pragma omp parallel if(numFrames > 1) +#endif +{ + int errCodeThr = 0; +#ifdef _OPENMP +#pragma omp for +#endif + for(unsigned int i = 0; i < numFrames; ++i) { + if(i == 0) { + riFrames[i] = ri; + errCodeThr = riFrames[i]->loadRaw (true, i, true, plistener, 0.8); + } else { + riFrames[i] = new RawImage(fname); + errCodeThr = riFrames[i]->loadRaw (true, i); } - riFrames[tempImageNum] = ri; - ri->compress_image(); - ri->set_prefilters(); - tempImageNum --; + riFrames[i]->compress_image(); } +#ifdef _OPENMP +#pragma omp critical +#endif +{ + errCode = errCodeThr ? errCodeThr : errCode; +} +} + if(errCode) { + return errCode; + } +Stop1.stop(); if(numFrames > 1 ) { // this disables multi frame support for Fuji S5 until I found a solution to handle different dimensions if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) { numFrames = 1; } } -std::cout << "numframes : " << numFrames << std::endl; - - ri = riFrames[0]; -Stop1.stop(); if (plistener) { plistener->setProgress (0.9); } @@ -1657,6 +1662,9 @@ Stop1.stop(); initialGain = 1.0 / min(pre_mul[0], pre_mul[1], pre_mul[2]); }*/ + for(unsigned int i=0;i < numFrames; ++i) { + riFrames[i]->set_prefilters(); + } //Load complete Exif informations @@ -1953,7 +1961,7 @@ void RawImageSource::demosaic(const RAWParams &raw) if(numFrames == 4) { pixelshift_simple(0, 0, W, H); scaleColors_pixelshift( 0, 0, W, H, raw); - } else { + } else { // for non pixelshift files use amaze if pixelshift is selected amaze_demosaic_RT (0, 0, W, H); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index abf1f6b97..560314802 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -203,7 +203,6 @@ public: void setCurrentFrame(unsigned int frameNum) { currFrame = std::min(numFrames - 1, frameNum); ri = riFrames[currFrame]; - std::cout << "currFrame : " << currFrame << std::endl; } protected: typedef unsigned short ushort; From 1c2f94a1b667d44443408e397b9f606eabc9c480 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 6 Nov 2016 22:43:08 +0100 Subject: [PATCH 14/83] pixelshift: simplified combination of frames --- rtengine/pixelshift.cc | 45 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 20f27294a..a68157b65 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -24,7 +24,7 @@ #include "../rtgui/multilangmgr.h" #include "procparams.h" #include "opthelper.h" -//#define BENCHMARK +#define BENCHMARK #include "StopWatch.h" using namespace std; using namespace rtengine; @@ -41,32 +41,33 @@ BENCHFUN plistener->setProgress (progress); } - const int bord = 2; + const int bord = 4; #ifdef _OPENMP #pragma omp parallel for #endif for(int i = bord; i < winh - bord; ++i) { - for(int j = bord; j< winw - bord; ++j) { - int c = FC(i,j); - if(c == 0) { - red[i][j] = riFrames[0]->data[i][j]; - green[i][j] = riFrames[3]->data[i][j+1]; - blue[i][j] = riFrames[2]->data[i+1][j+1]; - } else if(c & 1) { - green[i][j] = riFrames[0]->data[i][j]; - if(FC(i,j+1) == 0) { - red[i][j] = riFrames[3]->data[i][j+1]; - blue[i][j] = riFrames[1]->data[i+1][j]; - } else { - blue[i][j] = riFrames[3]->data[i][j+1]; - red[i][j] = riFrames[1]->data[i+1][j]; - } - } else { - blue[i][j] = riFrames[0]->data[i][j]; - red[i][j] = riFrames[2]->data[i+1][j+1]; - green[i][j] = riFrames[3]->data[i][j+1]; - } + float *greenDest = green[i]; + float *nonGreenDest0 = red[i]; + float *nonGreenDest1 = blue[i]; + int j = bord; + int c = FC(i,j); + if (c == 2 || ((c&1) && FC(i,j+1) == 2)) { + std::swap(nonGreenDest0, nonGreenDest1); + } + if(c&1) { + greenDest[j] = (riFrames[0]->data[i][j] + riFrames[2]->data[i+1][j+1]) / 2.f; + nonGreenDest0[j] = riFrames[3]->data[i][j+1]; + nonGreenDest1[j] = riFrames[1]->data[i+1][j]; + j++; + } + for(; j< winw - bord; j+=2) { + nonGreenDest0[j] = riFrames[0]->data[i][j]; + greenDest[j] = (riFrames[3]->data[i][j+1] + riFrames[1]->data[i+1][j] ) / 2.f; + nonGreenDest1[j] = riFrames[2]->data[i+1][j+1]; + greenDest[j+1] = (riFrames[0]->data[i][j+1] + riFrames[2]->data[i+1][j+2]) / 2.f; + nonGreenDest0[j+1] = riFrames[3]->data[i][j+2]; + nonGreenDest1[j+1] = riFrames[1]->data[i+1][j+1]; } } From e92303705387a0bc8728236cba3ed27ea8105ff3 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 16 Nov 2016 09:31:35 +0100 Subject: [PATCH 15/83] Commited current state to allow tests. Expect colour casts when changin demosaic method or pixelshift frame. In this case, just reload the image --- rtdata/languages/default | 5 + rtdata/rt_splash_5.png | Bin 0 -> 78671 bytes rtdata/rt_splash_5.svg | 1772 ++++++++++++++++++++++++++++++++++++ rtengine/pixelshift.cc | 199 +++- rtengine/procevents.h | 1 + rtengine/procparams.cc | 39 + rtengine/procparams.h | 3 + rtengine/rawimagesource.cc | 38 +- rtengine/rawimagesource.h | 8 +- rtengine/refreshmap.cc | 3 +- rtengine/rt_math.h | 7 + rtgui/bayerprocess.cc | 86 ++ rtgui/bayerprocess.h | 8 +- rtgui/paramsedited.cc | 18 + rtgui/paramsedited.h | 3 + 15 files changed, 2132 insertions(+), 58 deletions(-) create mode 100644 rtdata/rt_splash_5.png create mode 100644 rtdata/rt_splash_5.svg diff --git a/rtdata/languages/default b/rtdata/languages/default index c66c3a64d..9399982d8 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1654,6 +1654,11 @@ TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift, TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. +TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection +TP_RAW_PIXELSHIFTMOTION_TOOLTIP;No tooltip available atm +TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction +TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid +TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster. TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix diff --git a/rtdata/rt_splash_5.png b/rtdata/rt_splash_5.png new file mode 100644 index 0000000000000000000000000000000000000000..be996e1197805b83afb2b264a826671de829a341 GIT binary patch literal 78671 zcmZ_$cRW}B|38i^Lb5Wl_om1Q*()o1W@m=%k*yFSd+(8uy^_e@Ga;euk(n)9-`jb< zU!Tk6_s{Qnx%8|&9_Mi$=bYR9cDt^7VQMOJI9TLZC@3g63i2`m+al!frn|_Sv~1k$EKxK}J+!PXUEp;~T06&Qj|*NS_P>wj zG*PO)Kf<=3-;!?q=iYa8Je2LE6#Y-qOX~#?|@GNZhg?+a%% zN;1CtOFQWbMR$rb+3xX+`el;DOO9k3nIicc8hi{E1WL4+sI>C*cPm?eQ$9O*o$2-x zZ(vNYu5c%_vgQlEdrSLMt7qGP#Ac2U*DF-Bw|{(coGb4L!J*){o2)cl!VNUfyHRQS zzaPYy5)%F23mx5580k6ij{jcS7Mw)u`rk3mJ#Eaa{~g>B5-E(!FIn}!qoP~XUAwzW?dh*G zd*nOb*i=#bd@X-C3_mIIRe??W(=p*bONxDQl_$5?BS-ZTRSJr;8?iq{{i-xIXQ(Pi zd&JCG?Ob=}S4K-=sv`dx;}J6lzxwHtw1`X7tOdN-_nRzw(kZhJE-vz@yWutw?|!Zg zIVG-~VPG|R5Y2FJzcIm?5?2kM-MjrBR9>E;e>&^C`qDqtQ=hP0AFrJ@x8D2&_lf`d zrj(jiXOMA5#_sT@>6$i!oWru^5>2G+y|8fm-j{DqG){G1b3yaouw{Q{`4is#3@fo$Q6es$3n?m%lZ#-FC7M%pK8N2v@ zn;3p5@c6tMy;+iqaevk=x<5TPaGZ~E;;~|UJkiua$4cDTf<0Z95>jx510(O?p?sT~3NyLf&=vIgd-uY>r7dXj#g~!M(LgT0^~WE|%lW4T#KfX*k#Ode zl-vrCkXWmr(zS#_jBF3t3X-BGN*)Lv92`t}xEFa{pu4`lezMt57`|QzOP1&LWKN^@ z^|8W{si~V46BL9d67L^n{i@sR3fQ_$NA;rK&`Bth;vO{$=HgvK?9h&Y!9gWHe*VR) z^PQgGL+Loj?k`@LSzBZJ`S}ID>XWQ~RW=3>N$yjtT|zO-XBw@rolxgRuV3Nj!Rel|S68W>Md`Exvtk z!n3`6ttVtVs9kqwdOasJJ3co+L2r|Ss=Bv8b%@iH?rLlTJ^%HL{>hrREaTN&P~{P|UhnyzF&sZai0p0##^ zRc1ANi&me`JFl*Rp20jR_ir;Zku;ZUa=n9td`7l|g?#m^l^;G}V&GACULMaykB(|c zpLKL}c&_IsJ01L1MhlXB-La6;_4)EenGi_{pJuH3R|dUyBCcUKY)Y-5JhvB>9)bQd zH+g2+WGrWf7Z+Z}w_Qlnv$lqBJ$(3Z@{>JA0v9ZxUF^#p)D+CN?PH0 zJgoaJTD+%TvwN~w?1AkjdlBzN$OQ(TJ@6{puj=PW^<8tE(!7HeTv=I(FRg+?`X;>b zwyCTvIu8#IK2~so%Om>RgI~XzSy`bkI6Y~!rlD3*LLqI|O$_MYa1xZk4$ojYz8ZNO zPiTzc;#Vw$lU1%aGjOaYnV+XK$0Vh=)Ytt_r!Q7QlGu^rs4=>wOermX3t~LKAAEnJGCEYz(h71*OR+s>+)0Fl zg%|cb%^F!>)d%o0+}!I8WLMV47^vW7kk_GVU{{@uz4nH!*y|0=X)P8u`bJsDeBGX z;@%fy?C11$_TT+uag(`aI6|fPNmUd`);PlPnufDOH=n{kFt^08sG8_&l%5s>+ zg-0|}*DG1^FzZJ@4|Zo^<+)M|w9x*>hjV&*I$3RbOYCA-T1iQXRJM zT&m2KU<+nn#SC=SbtZ3SiLhItG2vrkMu%O*MVsfGFAJ%Y5!J9|S@W?s3i%exjqzzx zRnyn7`z;G|yVe&ulnK2sZn4s|Ijk$jDeC1)OpLcL;f?V0-sk;2SM;-N>REk|nxD?N zDvt#%89nX9?c`8Gotg&qDMD?kK1;Pemd#I!%)G-as?y{2Y3>(Lw|)KAD`mCb+b*KT z=ui57Ea{sYnX6eajk{ms{S3NZ8X-S0FraQ|7y(10Lyx)9kX_^Hc+5KWm5N&A=hEw} zmTHB4eLX0R0c)Q1Zm_4r7^VS^*evY+W&lDRv} zn@eO8#x3uK_r6xf?X0dB|HNcz4U1r0`Abj8k}6RoB5KH~ZJ;wAX^2bg87graUwY^x z@(|_dP1*qC0Ii3F3zeRG<%M2RR-~Qg@>#5S`gk;%&El~9U*7^Le*yg#g2a(hJnk_` zJ=yWcV*SAu>b1j1%xn}Jk|TWg?7uiM8`xO&$K2(!XL|anyj-QUA%^CzF70gU=rN3m z;NW0ZPEJ{8XKt8}YFb*aGcqVGo;_n=U_jN=(|fmsjUEJJAtgP%n{rKKq>Bx_q+0-NFlJ#k1jZXqDr!3nXV=eWHKFw-J9cF{9bA zt~yqS%*p}9D@{j6;;X8EU!nX!<~uC*>s;~L#xLq|z0Sg@3HmmB6`ASFwL&va28O4K z^LQ9o!(y(TTK;J3KjR#D2aO1KY5cKB{fUM*@wJ$-d9}Wp+h<+&&v78M^KzqYZ_ z-b3>;Vj!8z+|;z~J`)NGfWz9_+LPY`En$m`iwXM&-c6pzGalUB+_@27=u~AD6mB;E zt*tPfYxZMv>?H}4`8GZt91w5~;OD{=ts2A7@Nmyap4{G~c{Cjt7gtfE{PyXo*Tvtu zmM)fTU$ZqeHkxwH#@J$^Ck;{9Rd!FMb7R&y`$w#a0N1St&v!=+aL!fGtH#QsIn)Uk zG&!3qwDeKMj;+f8;Cb=qXYlXeR(yPXIiEj2iD`R!|4n{AlajJ>Ze1OTfa7du?emHG z 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

k?dC+o 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 b0`LC`dr8$8Cv7*pK>ifv)F8Do=Ar)s@QPk} literal 0 HcmV?d00001 diff --git a/rtdata/rt_splash_5.svg b/rtdata/rt_splash_5.svg new file mode 100644 index 000000000..d5f7ac4f3 --- /dev/null +++ b/rtdata/rt_splash_5.svg @@ -0,0 +1,1772 @@ + + + + + RawTherapee logo white font white glow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + RawTherapee logo white font white glow + + + RawTherapee + + + + + rawtherapee + logo + white + + + www.rawtherapee.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Select the desired element and apply one of the effects in the Filter Editor. You might need to ungroup the element before applying. For example to set the RT ring to have a colorful glow, select it and enable the "ring glow". You can change the flood color of the "ring shadow" effect to make it white if you want to make the logo usable on a dark background.For logo specifics, refer to rt_logo.svg Raw + Therapee + "Raw" font Eras-UltraBlk, 69px, -3px spacing between characters, skewed 2° to the right."Therapee" font Eras-Medium, 68px, 4px spacing between characters, skewed 2° to the right.Both have a dropshadow with an opacity of 0.40 and Gaussian blur standard deviation of 3.5.Version number Eras bold 64 or less.Eras font from "freefonts-0.10":ftp://ftp.gimp.org/pub/gimp/fonts/ RawTherapee splash screen design version 1.0 from 2014-05-03 | www.rawtherapee.com + GNU GPLv3 + 5 + + + diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index a68157b65..7e25f907f 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -1,6 +1,13 @@ //////////////////////////////////////////////////////////////// // -// simple pentax pixelshift algorithm +// pentax pixelshift algorithm with motion detection +// +// derived from dcrawps (https://github.com/tomtor/dcrawps), but with additional motion correction methods and adapted for RawTherapee data structures +// +// If motion correction is enabled only the pixels which are not detected as motion are set +// That means for a complete image you have to demosaic one of the frames with a bayer demosaicer to fill red, green and blue +// before calling pixelshift in case motion correction is enabled. +// // copyright (c) Ingo Weyrich 2016 // // @@ -23,58 +30,184 @@ #include "rawimagesource.h" #include "../rtgui/multilangmgr.h" #include "procparams.h" -#include "opthelper.h" #define BENCHMARK #include "StopWatch.h" + +namespace +{ + +float greenDiff(float a, float b) +{ + // calculate the difference between to green samples + // add a small epsilon to avoid division by zero + return std::fabs(a - b) / (std::max(a, b) + 0.0001f); + +} + +} + using namespace std; using namespace rtengine; -void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh) +void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize) { -BENCHFUN - double progress = 0.0; - const bool plistenerActive = plistener; + BENCHFUN if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); - plistener->setProgress (progress); + plistener->setProgress(0.0); } - const int bord = 4; + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel + const float motionThreshold = 1.f - (motion / 100.f); + + unsigned int offsX = 0, offsY = 0; + if(detectMotion && !showMotion) { + // if motion correction is enabled we have to adjust the offsets for the selected subframe we use for areas with motion + switch (frame) { + case 0: + offsX = offsY = 0; + break; + + case 1: + offsX = 0; + offsY = 1; + break; + + case 2: + offsX = offsY = 1; + break; + + case 3: + offsX = 1; + offsY = 0; + } + } #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for schedule(dynamic,16) #endif - for(int i = bord; i < winh - bord; ++i) { - float *greenDest = green[i]; - float *nonGreenDest0 = red[i]; - float *nonGreenDest1 = blue[i]; - int j = bord; - int c = FC(i,j); - if (c == 2 || ((c&1) && FC(i,j+1) == 2)) { + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *nonGreenDest0 = red[i + offsY]; + float *nonGreenDest1 = blue[i + offsY]; + int j = winx + border - offsX; + int c = FC(i, j); + + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels std::swap(nonGreenDest0, nonGreenDest1); } - if(c&1) { - greenDest[j] = (riFrames[0]->data[i][j] + riFrames[2]->data[i+1][j+1]) / 2.f; - nonGreenDest0[j] = riFrames[3]->data[i][j+1]; - nonGreenDest1[j] = riFrames[1]->data[i+1][j]; - j++; + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); + + + float greenDifMax[gridSize]; + // motion detection checks the grid around the pixel for differences in green channels + if(detectMotion) { + if(gridSize == 3) { + // compute maximum of differences for first two columns of 3x3 grid + greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j]) + ); + greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1]) + ); + } else if(gridSize == 5) { + // compute maximum of differences for first four columns of 5x5 grid + greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1]), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1]), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1]), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1]), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1]) + ); + greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j]), + greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j]), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j]) + ); + greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1]), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1]), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1]) + ); + greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2]), + greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2]), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2]), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2]), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2]) + ); + } } - for(; j< winw - bord; j+=2) { - nonGreenDest0[j] = riFrames[0]->data[i][j]; - greenDest[j] = (riFrames[3]->data[i][j+1] + riFrames[1]->data[i+1][j] ) / 2.f; - nonGreenDest1[j] = riFrames[2]->data[i+1][j+1]; - greenDest[j+1] = (riFrames[0]->data[i][j+1] + riFrames[2]->data[i+1][j+2]) / 2.f; - nonGreenDest0[j+1] = riFrames[3]->data[i][j+2]; - nonGreenDest1[j+1] = riFrames[1]->data[i+1][j+1]; + + offset ^= 1; // 0 => 1 or 1 => 0 + + // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 + int lastIndex = gridSize - 1; + + for(; j < winw - (border + offsX); ++j) { + offset ^= 1; // 0 => 1 or 1 => 0 + + if(detectMotion) { + bool skipNext = false; + float gridMax; + if(gridSize == 1) { + // compute difference for current pixel and skip next pixel, that's the method from dcrawps + gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]); + skipNext = !showMotion; + } else if(gridSize == 3) { + // compute maximum of differences for third column of 3x3 grid and save at position lastIndex + greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2]), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2]), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2]) + ); + gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); + } else if(gridSize == 5) { + // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex + greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3]), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3]), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3]), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3]), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3]) + ); + gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); + } + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; + + if (gridMax > motionThreshold) { + // at least one of the tested pixels of the grid is detected as motion + if(showMotion) { + // if showMotion is enabled make the pixel green + greenDest[j] = 10000.f; + nonGreenDest0[j] = nonGreenDest1[j] = 0.f; + } + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + offset ^= 1; + } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; + } + } + + // motion correction disabled or no motion detected => combine the values from the four pixelshift frames + greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; + nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; + nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; } } - if(plistenerActive) { - plistener->setProgress(1.00); + if(plistener) { + plistener->setProgress(1.0); } - } -#undef TS -#undef CLF diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 69cda228a..24469cead 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -471,6 +471,7 @@ enum ProcEvent { EvLskal = 441, EvOBPCompens = 442, EvRawImageNum = 443, + EvDemosaicPixelshiftMotion = 444, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 2a7b41847..466b25d82 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -885,6 +885,9 @@ void RAWParams::setDefaults() bayersensor.dcb_enhance = true; //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; + bayersensor.pixelshiftMotion = 70; + bayersensor.pixelshiftMotionCorrection = 3; + bayersensor.pixelshiftShowMotion = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3364,6 +3367,18 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations ); } + if (!pedited || pedited->raw.bayersensor.pixelshiftMotion) { + keyFile.set_integer ("RAW Bayer", "PixelShiftMotion", raw.bayersensor.pixelshiftMotion ); + } + + if (!pedited || pedited->raw.bayersensor.pixelshiftMotionCorrection) { + keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelshiftMotionCorrection ); + } + + if (!pedited || pedited->raw.bayersensor.pixelshiftShowMotion) { + keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion ); + } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { @@ -7422,6 +7437,30 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftMotion")) { + raw.bayersensor.pixelshiftMotion = keyFile.get_integer("RAW Bayer", "PixelShiftMotion"); + + if (pedited) { + pedited->raw.bayersensor.pixelshiftMotion = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftMotionCorrection")) { + raw.bayersensor.pixelshiftMotionCorrection = keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrection"); + + if (pedited) { + pedited->raw.bayersensor.pixelshiftMotionCorrection = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftShowMotion")) { + raw.bayersensor.pixelshiftShowMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftShowMotion"); + + if (pedited) { + pedited->raw.bayersensor.pixelshiftShowMotion = true; + } + } + //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 35a4f1932..3f5951cf8 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1182,6 +1182,9 @@ public: int greenthresh; int dcb_iterations; int lmmse_iterations; + int pixelshiftMotion; + int pixelshiftMotionCorrection; + bool pixelshiftShowMotion; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 37cf2618e..f4760d44e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1549,6 +1549,7 @@ Stop1.stop(); if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) { numFrames = 1; } + pixelShiftColoursScaled = false; } if (plistener) { @@ -1757,7 +1758,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le printf( "Flat Field Correction:%s\n", rif->get_filename().c_str()); } - copyOriginalPixels(raw, ri, rid, rif); + copyOriginalPixels(raw, ri, rid, rif, rawData); //FLATFIELD end @@ -1798,7 +1799,10 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } - scaleColors( 0, 0, W, H, raw); //+ + raw parameters for black level(raw.blackxx) + scaleColors( 0, 0, W, H, raw, rawData); //+ + raw parameters for black level(raw.blackxx) + if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] && !pixelShiftColoursScaled) { + scaleColors_pixelshift( 0, 0, W, H, raw); + } // Correct vignetting of lens profile if (!hasFlatField && lensProf.useVign) { @@ -1958,11 +1962,11 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { + if(raw.bayersensor.pixelshiftMotion > 0) { + amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction + } if(numFrames == 4) { - pixelshift_simple(0, 0, W, H); - scaleColors_pixelshift( 0, 0, W, H, raw); - } else { // for non pixelshift files use amaze if pixelshift is selected - amaze_demosaic_RT (0, 0, W, H); + pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); @@ -3010,7 +3014,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile /* Copy original pixel data and * subtract dark frame (if present) from current image and apply flat field correction (if present) */ -void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile ) +void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ) { // TODO: Change type of black[] to float to avoid conversions unsigned short black[4] = { @@ -3341,7 +3345,7 @@ SSEFUNCTION void RawImageSource::cfaboxblur(RawImage *riFlatFile, float* cfablur // Scale original pixels into the range 0 65535 using black offsets and multipliers -void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const RAWParams &raw) +void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData) { chmax[0] = chmax[1] = chmax[2] = chmax[3] = 0; //channel maxima float black_lev[4] = {0.f};//black level @@ -3555,17 +3559,12 @@ void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int wi for (int row = winy; row < winy + winh; row ++) { for (int col = winx; col < winx + winw; col++) { - float redval = (red[row][col] - cblacksom[0]) * scale_mul[0]; - tmpchmax[0] = max(tmpchmax[0], redval); - red[row][col] = redval; - - float greenval = (green[row][col] - cblacksom[1]) * scale_mul[1]; - tmpchmax[1] = max(tmpchmax[1], greenval); - green[row][col] = greenval; - - float blueval = (blue[row][col] - cblacksom[2]) * scale_mul[2]; - tmpchmax[2] = max(tmpchmax[2], blueval); - blue[row][col] = blueval; + int c = FC(row,col); + for(int frame = 0; frame < 4; ++frame) { + float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; + tmpchmax[c] = max(tmpchmax[c], val); + riFrames[frame]->data[row][col] = val; + } } } @@ -3578,6 +3577,7 @@ void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int wi chmax[2] = max(tmpchmax[2], chmax[2]); } } + pixelShiftColoursScaled = true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 560314802..648e5ec77 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -81,6 +81,7 @@ protected: int threshold; array2D rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column + array2D *rawDataFrames[16] = {nullptr}; // the interpolated green plane: array2D green; @@ -128,9 +129,9 @@ public: } void processFlatField(const RAWParams &raw, RawImage *riFlatFile, unsigned short black[4]); - void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile ); + void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW); - void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw); // raw for cblack + void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData); // raw for cblack void scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw); @@ -205,6 +206,7 @@ public: ri = riFrames[currFrame]; } protected: + bool pixelShiftColoursScaled = false; typedef unsigned short ushort; void processFalseColorCorrection (Imagefloat* i, const int steps); inline void convert_row_to_YIQ (const float* const r, const float* const g, const float* const b, float* Y, float* I, float* Q, const int W); @@ -261,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift_simple(int winx, int winy, int winw, int winh); + void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int method); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 33e988674..643c9e075 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -470,7 +470,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens - DARKFRAME // EvRawImageNum + DARKFRAME, // EvRawImageNum + DEMOSAIC // EvDemosaicPixelshiftMotion }; diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 67d883080..5e2f04d05 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -74,6 +74,13 @@ inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d) return std::max(d, std::max(c, std::max(a, b))); } +template +inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, const _Tp& e) +{ + return max(max(a,b,c),std::max(d,e)); +} + + template inline _Tp intp(_Tp a, _Tp b, _Tp c) { diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 639eabc02..92351be2b 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -81,6 +81,34 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA lmmseOptions->pack_start(*lmmseIterations); pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); + pixelShiftOptions = Gtk::manage (new Gtk::VBox ()); + pixelShiftOptions->set_border_width(4); + pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); + pixelShiftOptions->pack_start(*pixelShiftShowMotion); + + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); + pixelShiftMotion->setAdjusterListener (this); + pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); + + if (pixelShiftMotion->delay < options.adjusterMaxDelay) { + pixelShiftMotion->delay = options.adjusterMaxDelay; + } + pixelShiftMotion->show(); + pixelShiftOptions->pack_start(*pixelShiftMotion); + + pixelShiftMotionCorrection = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION"), 1, 5, 2, 3)); + pixelShiftMotionCorrection->setAdjusterListener (this); + pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); + + if (pixelShiftMotionCorrection->delay < options.adjusterMaxDelay) { + pixelShiftMotionCorrection->delay = options.adjusterMaxDelay; + } + + pixelShiftMotionCorrection->show(); + pixelShiftOptions->pack_start(*pixelShiftMotionCorrection); + pack_start( *pixelShiftOptions, Gtk::PACK_SHRINK, 4); + + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); ccSteps->setAdjusterListener (this); @@ -102,6 +130,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); + pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -129,8 +158,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); + pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); + pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); + pixelShiftMotionCorrection->setEditedState ( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); if(!pedited->raw.bayersensor.method) { method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name @@ -144,8 +176,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); + pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); + pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); + pixelShiftMotionCorrection->setValue (pp->raw.bayersensor.pixelshiftMotionCorrection); if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || @@ -160,6 +195,12 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } else { lmmseOptions->hide(); } + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::pixelshift_simple] || + method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { + pixelShiftOptions->show(); + } else { + pixelShiftOptions->hide(); + } // Flase color suppression is applied to all demozaicing method, so don't hide anything /*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] || @@ -188,6 +229,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); + pp->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getIntValue(); + pp->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getIntValue(); + pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -208,6 +252,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); + pedited->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getEditedState (); + pedited->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getEditedState (); + pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); } } @@ -219,25 +266,34 @@ void BayerProcess::setBatchMode(bool batchMode) imageNumber->set_active(4); dcbOptions->hide(); lmmseOptions->hide(); + pixelShiftOptions->hide(); ToolPanel::setBatchMode (batchMode); ccSteps->showEditedCB (); dcbIterations->showEditedCB (); lmmseIterations->showEditedCB (); + pixelShiftMotion->showEditedCB (); + pixelShiftMotionCorrection->showEditedCB (); } void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) { dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); + pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelshiftMotion); + pixelShiftMotionCorrection->setDefault( defParams->raw.bayersensor.pixelshiftMotionCorrection); ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); if (pedited) { dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); + pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); + pixelShiftMotionCorrection->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); } else { dcbIterations->setDefaultEditedState( Irrelevant ); lmmseIterations->setDefaultEditedState( Irrelevant ); + pixelShiftMotion->setDefaultEditedState( Irrelevant ); + pixelShiftMotionCorrection->setDefaultEditedState( Irrelevant ); ccSteps->setDefaultEditedState(Irrelevant ); } } @@ -251,6 +307,10 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); } else if (a == lmmseIterations) { listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); + } else if (a == pixelShiftMotion) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + } else if (a == pixelShiftMotionCorrection) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); } } } @@ -271,6 +331,12 @@ void BayerProcess::methodChanged () lmmseOptions->hide(); } + if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift_simple) { + pixelShiftOptions->show(); + } else { + pixelShiftOptions->hide(); + } + Glib::ustring methodName = ""; bool ppreq = false; @@ -316,6 +382,26 @@ void BayerProcess::dcbEnhanceChanged () } } +void BayerProcess::pixelShiftShowMotionChanged () +{ + if (batchMode) { + if (pixelShiftShowMotion->get_inconsistent()) { + pixelShiftShowMotion->set_inconsistent (false); + pixelShiftShowMotionconn.block (true); + pixelShiftShowMotion->set_active (false); + pixelShiftShowMotionconn.block (false); + } else if (lastDCBen) { + pixelShiftShowMotion->set_inconsistent (true); + } + + lastDCBen = pixelShiftShowMotion->get_active (); + } + + if (listener) { + listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + /*void BayerProcess::allEnhanceChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index bba4bd51d..404324ed6 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -41,11 +41,14 @@ protected: //Gtk::CheckButton* allEnhance; Gtk::VBox *lmmseOptions; Adjuster* lmmseIterations; - + Gtk::VBox *pixelShiftOptions; + Adjuster* pixelShiftMotion; + Adjuster* pixelShiftMotionCorrection; + Gtk::CheckButton* pixelShiftShowMotion; bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn; //,allEnhconn; public: BayerProcess (); @@ -59,6 +62,7 @@ public: void imageNumberChanged (); void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); + void pixelShiftShowMotionChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ebb31ef1d..6a020cd8b 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -370,6 +370,9 @@ void ParamsEdited::set (bool v) raw.bayersensor.dcbEnhance = v; //raw.bayersensor.allEnhance = v; raw.bayersensor.lmmseIterations = v; + raw.bayersensor.pixelshiftMotion = v; + raw.bayersensor.pixelshiftMotionCorrection = v; + raw.bayersensor.pixelshiftShowMotion = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -866,6 +869,9 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.dcbEnhance = raw.bayersensor.dcbEnhance && p.raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance; //raw.bayersensor.allEnhance = raw.bayersensor.allEnhance && p.raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance; raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; + raw.bayersensor.pixelshiftMotion = raw.bayersensor.pixelshiftMotion && p.raw.bayersensor.pixelshiftMotion == other.raw.bayersensor.pixelshiftMotion; + raw.bayersensor.pixelshiftMotionCorrection = raw.bayersensor.pixelshiftMotionCorrection && p.raw.bayersensor.pixelshiftMotionCorrection == other.raw.bayersensor.pixelshiftMotionCorrection; + raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2278,6 +2284,18 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.lmmse_iterations = mods.raw.bayersensor.lmmse_iterations; } + if (raw.bayersensor.pixelshiftMotion) { + toEdit.raw.bayersensor.pixelshiftMotion = mods.raw.bayersensor.pixelshiftMotion; + } + + if (raw.bayersensor.pixelshiftMotionCorrection) { + toEdit.raw.bayersensor.pixelshiftMotionCorrection = mods.raw.bayersensor.pixelshiftMotionCorrection; + } + + if (raw.bayersensor.pixelshiftShowMotion) { + toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion; + } + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 4e9fa4eb4..5546c9857 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -692,6 +692,9 @@ public: bool dcbIterations; bool dcbEnhance; bool lmmseIterations; + bool pixelshiftMotion; + bool pixelshiftMotionCorrection; + bool pixelshiftShowMotion; //bool allEnhance; bool greenEq; bool linenoise; From 53bc43459e581d8f206fcc0f52a2d7007695dc8f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 16 Nov 2016 09:34:46 +0100 Subject: [PATCH 16/83] removed splash files --- rtdata/rt_splash_5.png | Bin 78671 -> 0 bytes rtdata/rt_splash_5.svg | 1772 ---------------------------------------- 2 files changed, 1772 deletions(-) delete mode 100644 rtdata/rt_splash_5.png delete mode 100644 rtdata/rt_splash_5.svg diff --git a/rtdata/rt_splash_5.png b/rtdata/rt_splash_5.png deleted file mode 100644 index be996e1197805b83afb2b264a826671de829a341..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78671 zcmZ_$cRW}B|38i^Lb5Wl_om1Q*()o1W@m=%k*yFSd+(8uy^_e@Ga;euk(n)9-`jb< zU!Tk6_s{Qnx%8|&9_Mi$=bYR9cDt^7VQMOJI9TLZC@3g63i2`m+al!frn|_Sv~1k$EKxK}J+!PXUEp;~T06&Qj|*NS_P>wj zG*PO)Kf<=3-;!?q=iYa8Je2LE6#Y-qOX~#?|@GNZhg?+a%% zN;1CtOFQWbMR$rb+3xX+`el;DOO9k3nIicc8hi{E1WL4+sI>C*cPm?eQ$9O*o$2-x zZ(vNYu5c%_vgQlEdrSLMt7qGP#Ac2U*DF-Bw|{(coGb4L!J*){o2)cl!VNUfyHRQS zzaPYy5)%F23mx5580k6ij{jcS7Mw)u`rk3mJ#Eaa{~g>B5-E(!FIn}!qoP~XUAwzW?dh*G zd*nOb*i=#bd@X-C3_mIIRe??W(=p*bONxDQl_$5?BS-ZTRSJr;8?iq{{i-xIXQ(Pi zd&JCG?Ob=}S4K-=sv`dx;}J6lzxwHtw1`X7tOdN-_nRzw(kZhJE-vz@yWutw?|!Zg zIVG-~VPG|R5Y2FJzcIm?5?2kM-MjrBR9>E;e>&^C`qDqtQ=hP0AFrJ@x8D2&_lf`d zrj(jiXOMA5#_sT@>6$i!oWru^5>2G+y|8fm-j{DqG){G1b3yaouw{Q{`4is#3@fo$Q6es$3n?m%lZ#-FC7M%pK8N2v@ zn;3p5@c6tMy;+iqaevk=x<5TPaGZ~E;;~|UJkiua$4cDTf<0Z95>jx510(O?p?sT~3NyLf&=vIgd-uY>r7dXj#g~!M(LgT0^~WE|%lW4T#KfX*k#Ode zl-vrCkXWmr(zS#_jBF3t3X-BGN*)Lv92`t}xEFa{pu4`lezMt57`|QzOP1&LWKN^@ z^|8W{si~V46BL9d67L^n{i@sR3fQ_$NA;rK&`Bth;vO{$=HgvK?9h&Y!9gWHe*VR) z^PQgGL+Loj?k`@LSzBZJ`S}ID>XWQ~RW=3>N$yjtT|zO-XBw@rolxgRuV3Nj!Rel|S68W>Md`Exvtk z!n3`6ttVtVs9kqwdOasJJ3co+L2r|Ss=Bv8b%@iH?rLlTJ^%HL{>hrREaTN&P~{P|UhnyzF&sZai0p0##^ zRc1ANi&me`JFl*Rp20jR_ir;Zku;ZUa=n9td`7l|g?#m^l^;G}V&GACULMaykB(|c zpLKL}c&_IsJ01L1MhlXB-La6;_4)EenGi_{pJuH3R|dUyBCcUKY)Y-5JhvB>9)bQd zH+g2+WGrWf7Z+Z}w_Qlnv$lqBJ$(3Z@{>JA0v9ZxUF^#p)D+CN?PH0 zJgoaJTD+%TvwN~w?1AkjdlBzN$OQ(TJ@6{puj=PW^<8tE(!7HeTv=I(FRg+?`X;>b zwyCTvIu8#IK2~so%Om>RgI~XzSy`bkI6Y~!rlD3*LLqI|O$_MYa1xZk4$ojYz8ZNO zPiTzc;#Vw$lU1%aGjOaYnV+XK$0Vh=)Ytt_r!Q7QlGu^rs4=>wOermX3t~LKAAEnJGCEYz(h71*OR+s>+)0Fl zg%|cb%^F!>)d%o0+}!I8WLMV47^vW7kk_GVU{{@uz4nH!*y|0=X)P8u`bJsDeBGX z;@%fy?C11$_TT+uag(`aI6|fPNmUd`);PlPnufDOH=n{kFt^08sG8_&l%5s>+ zg-0|}*DG1^FzZJ@4|Zo^<+)M|w9x*>hjV&*I$3RbOYCA-T1iQXRJM zT&m2KU<+nn#SC=SbtZ3SiLhItG2vrkMu%O*MVsfGFAJ%Y5!J9|S@W?s3i%exjqzzx zRnyn7`z;G|yVe&ulnK2sZn4s|Ijk$jDeC1)OpLcL;f?V0-sk;2SM;-N>REk|nxD?N zDvt#%89nX9?c`8Gotg&qDMD?kK1;Pemd#I!%)G-as?y{2Y3>(Lw|)KAD`mCb+b*KT z=ui57Ea{sYnX6eajk{ms{S3NZ8X-S0FraQ|7y(10Lyx)9kX_^Hc+5KWm5N&A=hEw} zmTHB4eLX0R0c)Q1Zm_4r7^VS^*evY+W&lDRv} zn@eO8#x3uK_r6xf?X0dB|HNcz4U1r0`Abj8k}6RoB5KH~ZJ;wAX^2bg87graUwY^x z@(|_dP1*qC0Ii3F3zeRG<%M2RR-~Qg@>#5S`gk;%&El~9U*7^Le*yg#g2a(hJnk_` zJ=yWcV*SAu>b1j1%xn}Jk|TWg?7uiM8`xO&$K2(!XL|anyj-QUA%^CzF70gU=rN3m z;NW0ZPEJ{8XKt8}YFb*aGcqVGo;_n=U_jN=(|fmsjUEJJAtgP%n{rKKq>Bx_q+0-NFlJ#k1jZXqDr!3nXV=eWHKFw-J9cF{9bA zt~yqS%*p}9D@{j6;;X8EU!nX!<~uC*>s;~L#xLq|z0Sg@3HmmB6`ASFwL&va28O4K z^LQ9o!(y(TTK;J3KjR#D2aO1KY5cKB{fUM*@wJ$-d9}Wp+h<+&&v78M^KzqYZ_ z-b3>;Vj!8z+|;z~J`)NGfWz9_+LPY`En$m`iwXM&-c6pzGalUB+_@27=u~AD6mB;E zt*tPfYxZMv>?H}4`8GZt91w5~;OD{=ts2A7@Nmyap4{G~c{Cjt7gtfE{PyXo*Tvtu zmM)fTU$ZqeHkxwH#@J$^Ck;{9Rd!FMb7R&y`$w#a0N1St&v!=+aL!fGtH#QsIn)Uk zG&!3qwDeKMj;+f8;Cb=qXYlXeR(yPXIiEj2iD`R!|4n{AlajJ>Ze1OTfa7du?emHG z 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

k?dC+o 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 b0`LC`dr8$8Cv7*pK>ifv)F8Do=Ar)s@QPk} diff --git a/rtdata/rt_splash_5.svg b/rtdata/rt_splash_5.svg deleted file mode 100644 index d5f7ac4f3..000000000 --- a/rtdata/rt_splash_5.svg +++ /dev/null @@ -1,1772 +0,0 @@ - - - - - RawTherapee logo white font white glow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - RawTherapee logo white font white glow - - - RawTherapee - - - - - rawtherapee - logo - white - - - www.rawtherapee.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the desired element and apply one of the effects in the Filter Editor. You might need to ungroup the element before applying. For example to set the RT ring to have a colorful glow, select it and enable the "ring glow". You can change the flood color of the "ring shadow" effect to make it white if you want to make the logo usable on a dark background.For logo specifics, refer to rt_logo.svg Raw - Therapee - "Raw" font Eras-UltraBlk, 69px, -3px spacing between characters, skewed 2° to the right."Therapee" font Eras-Medium, 68px, 4px spacing between characters, skewed 2° to the right.Both have a dropshadow with an opacity of 0.40 and Gaussian blur standard deviation of 3.5.Version number Eras bold 64 or less.Eras font from "freefonts-0.10":ftp://ftp.gimp.org/pub/gimp/fonts/ RawTherapee splash screen design version 1.0 from 2014-05-03 | www.rawtherapee.com - GNU GPLv3 - 5 - - - From d711015ae092ad9d23cac3a87935df811dda2f0a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 17 Nov 2016 15:54:55 +0100 Subject: [PATCH 17/83] Correction for pixelshift 'show motion' when selected frame > 1 --- rtengine/pixelshift.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 7e25f907f..9430315ac 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -40,7 +40,7 @@ float greenDiff(float a, float b) { // calculate the difference between to green samples // add a small epsilon to avoid division by zero - return std::fabs(a - b) / (std::max(a, b) + 0.0001f); + return std::fabs(a - b) / (std::max(a, b) + 0.01f); } @@ -63,7 +63,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b const float motionThreshold = 1.f - (motion / 100.f); unsigned int offsX = 0, offsY = 0; - if(detectMotion && !showMotion) { + if(detectMotion) { // if motion correction is enabled we have to adjust the offsets for the selected subframe we use for areas with motion switch (frame) { case 0: @@ -187,8 +187,8 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b // at least one of the tested pixels of the grid is detected as motion if(showMotion) { // if showMotion is enabled make the pixel green - greenDest[j] = 10000.f; - nonGreenDest0[j] = nonGreenDest1[j] = 0.f; + greenDest[j + offsX] = 10000.f; + nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; } if(skipNext) { // treat the horizontally next pixel also as motion From 5683a1b9b15a6e0995af6a68d4c9eb87198dc2c7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 17 Nov 2016 15:55:37 +0100 Subject: [PATCH 18/83] Pixelshift, added a tooltip --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 9399982d8..997d3ea84 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1655,7 +1655,7 @@ TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection -TP_RAW_PIXELSHIFTMOTION_TOOLTIP;No tooltip available atm +TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion From 8bb958eb190fc91f9188f151ce892cbdd06cebf0 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 21 Nov 2016 01:33:59 +0100 Subject: [PATCH 19/83] pixelshift: committed some experimental changes for testing --- rtdata/languages/default | 1 + rtengine/pixelshift.cc | 147 +++++++++++++++++++++++++++++++++---- rtengine/procparams.cc | 13 ++++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 30 ++++++++ rtgui/bayerprocess.h | 4 +- rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + 10 files changed, 189 insertions(+), 20 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 997d3ea84..44d540315 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1654,6 +1654,7 @@ TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift, TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. +TP_RAW_PIXELSHIFTADAPTIVE;Automatic detection TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 9430315ac..7869daa6d 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -49,19 +49,32 @@ float greenDiff(float a, float b) using namespace std; using namespace rtengine; -void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize) +void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool blendMotion) { BENCHFUN + printf("%f\t%f\t%f\t%f\n",scale_mul[0],scale_mul[1],scale_mul[2],scale_mul[3]); + if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); plistener->setProgress(0.0); } - // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel - const float motionThreshold = 1.f - (motion / 100.f); + LUTf log2Lut(65536); + log2Lut[0] = 0; + const float lutStrength = 2.f; + const float scaleGreen = 1.f / scale_mul[1]; + for(int i=2; i < 65536; i+=2) + log2Lut[i>>1] = 2.f * log2(i) / 100.f; + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel + float motionThreshold = 1.f - (motion / 100.f); + // For 'blend' mode + const float blendFactor = 1.f / (1.f - motionThreshold); + + bool checkRedBlue = (gridSize == 5); +// bool checkRedBlue = false; unsigned int offsX = 0, offsY = 0; if(detectMotion) { // if motion correction is enabled we have to adjust the offsets for the selected subframe we use for areas with motion @@ -155,7 +168,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b for(; j < winw - (border + offsX); ++j) { offset ^= 1; // 0 => 1 or 1 => 0 - if(detectMotion) { + if(detectMotion || blendMotion) { bool skipNext = false; float gridMax; if(gridSize == 1) { @@ -183,23 +196,125 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b lastIndex ++; lastIndex = lastIndex == gridSize ? 0 : lastIndex; - if (gridMax > motionThreshold) { - // at least one of the tested pixels of the grid is detected as motion - if(showMotion) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = 10000.f; - nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + // increase motion detection dependent on brightness +// float korr = 2.f * log2Lut[((int)riFrames[1 - offset]->data[i - offset + 1][j])>>1]; + float centerVal = riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen; + if(true || centerVal > 32) { + float korr; + float thresh; + if(blendMotion) { + korr = 0.f; + float average = scaleGreen * (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; + thresh = (5.f / sqrtf(average)) / 0.75f; + } else { + korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; + thresh = motionThreshold; } - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; - offset ^= 1; +// float korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; +// float korr = 0.f; +// float average = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1])/2.f; +// float motionThreshold = 5.f * sqrtf(3.f*average/(scale_mul[1])) / (average * scaleGreen * 3.f); + if (gridMax > thresh - korr) { + float blend = (gridMax - thresh + korr) * blendFactor; + // at least one of the tested pixels of the grid is detected as motion + if(showMotion) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + } else if(false) { + greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); + nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); + nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); + } + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + offset ^= 1; + } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; } } + if(false && detectMotion && checkRedBlue) { + float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; + float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; + float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; + float diff0 = ng1 - ng0; + float diff2 = ng1 - ng2; + float gridMax; + if(diff0 * diff2 > 0.f) { +// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { + gridMax = greenDiff(ng1, std::max(ng0, ng2)); +// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); + if(gridMax > motionThreshold ) { + float factor = 1.f / (1.f - motionThreshold); + float blend = (gridMax - motionThreshold) * factor; + if(showMotion) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + nonGreenDest0[j + offsX] = 20000.f; + continue; +// greenDest[j + offsX+1] = nonGreenDest1[j + offsX+1] = 0.f; +// nonGreenDest0[j + offsX+1] = 20000.f; + } + greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; + +// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); +// nonGreenDest0[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; + nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); +// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); + nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; + +// nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); + +// if(skipNext) { +// // treat the horizontally next pixel also as motion +// j++; +// offset ^= 1; +// } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; + } + } + ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; + ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; + ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; + diff0 = ng1 - ng0; + diff2 = ng1 - ng2; + if(signbit(diff0) == signbit(diff2)) { +// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { + gridMax = greenDiff(ng1, std::max(ng0, ng2)); +// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); + if(gridMax > motionThreshold ) { + float factor = 1.f / (1.f - motionThreshold); + float blend = (gridMax - motionThreshold) * factor; + if(showMotion) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = nonGreenDest0[j + offsX] = 0.f; + nonGreenDest1[j + offsX] = 20000.f; +// greenDest[j + offsX+1] = nonGreenDest0[j + offsX+1] = 0.f; +// nonGreenDest1[j + offsX+1] = 20000.f; +continue; + } + greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; +// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); +// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); + nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; + +// nonGreenDest1[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; + nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); +// if(skipNext) { +// // treat the horizontally next pixel also as motion +// j++; +// offset ^= 1; +// } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; + } + } + } // motion correction disabled or no motion detected => combine the values from the four pixelshift frames greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 466b25d82..eba1e36f4 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -888,6 +888,7 @@ void RAWParams::setDefaults() bayersensor.pixelshiftMotion = 70; bayersensor.pixelshiftMotionCorrection = 3; bayersensor.pixelshiftShowMotion = false; + bayersensor.pixelshiftBlendMotion = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3379,6 +3380,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion ); } + if (!pedited || pedited->raw.bayersensor.pixelshiftBlendMotion) { + keyFile.set_boolean ("RAW Bayer", "PixelShiftBlendMotion", raw.bayersensor.pixelshiftBlendMotion ); + } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { @@ -7461,6 +7466,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftBlendMotion")) { + raw.bayersensor.pixelshiftBlendMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftBlendMotion"); + + if (pedited) { + pedited->raw.bayersensor.pixelshiftBlendMotion = true; + } + } + //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 3f5951cf8..a6308454c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1185,6 +1185,7 @@ public: int pixelshiftMotion; int pixelshiftMotionCorrection; bool pixelshiftShowMotion; + bool pixelshiftBlendMotion; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index f4760d44e..ed6efdae0 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1966,7 +1966,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection); + pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelshiftBlendMotion); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); @@ -3561,7 +3561,7 @@ void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int wi for (int col = winx; col < winx + winw; col++) { int c = FC(row,col); for(int frame = 0; frame < 4; ++frame) { - float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; + float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; tmpchmax[c] = max(tmpchmax[c], val); riFrames[frame]->data[row][col] = val; } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 648e5ec77..08e1643ed 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -263,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int method); + void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool blendMotion); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 92351be2b..5c80b93c1 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -86,6 +86,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); pixelShiftOptions->pack_start(*pixelShiftShowMotion); + pixelShiftBlendMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); + pixelShiftOptions->pack_start(*pixelShiftBlendMotion); + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); @@ -131,6 +134,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); + pixelShiftBlendMotionconn = pixelShiftBlendMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlendMotionChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -159,6 +163,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); + pixelShiftBlendMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftBlendMotion); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); @@ -177,6 +182,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); + pixelShiftBlendMotion->set_active(pp->raw.bayersensor.pixelshiftBlendMotion); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); @@ -232,6 +238,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getIntValue(); pp->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getIntValue(); pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); + pp->raw.bayersensor.pixelshiftBlendMotion = pixelShiftBlendMotion->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -255,6 +262,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getEditedState (); pedited->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getEditedState (); pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); + pedited->raw.bayersensor.pixelshiftBlendMotion = !pixelShiftBlendMotion->get_inconsistent(); } } @@ -402,6 +410,28 @@ void BayerProcess::pixelShiftShowMotionChanged () } } +void BayerProcess::pixelShiftBlendMotionChanged () +{ + if (batchMode) { + if (pixelShiftBlendMotion->get_inconsistent()) { + pixelShiftBlendMotion->set_inconsistent (false); + pixelShiftBlendMotionconn.block (true); + pixelShiftBlendMotion->set_active (false); + pixelShiftBlendMotionconn.block (false); + } else if (lastDCBen) { + pixelShiftBlendMotion->set_inconsistent (true); + } + + lastDCBen = pixelShiftBlendMotion->get_active (); + } + pixelShiftMotion->set_sensitive(!pixelShiftBlendMotion->get_active ()); + + if (listener) { + listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftBlendMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + + /*void BayerProcess::allEnhanceChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 404324ed6..383adeb43 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -45,10 +45,11 @@ protected: Adjuster* pixelShiftMotion; Adjuster* pixelShiftMotionCorrection; Gtk::CheckButton* pixelShiftShowMotion; + Gtk::CheckButton* pixelShiftBlendMotion; bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftBlendMotionconn; //,allEnhconn; public: BayerProcess (); @@ -63,6 +64,7 @@ public: void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); void pixelShiftShowMotionChanged(); + void pixelShiftBlendMotionChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 6a020cd8b..5b045c2ce 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -373,6 +373,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelshiftMotion = v; raw.bayersensor.pixelshiftMotionCorrection = v; raw.bayersensor.pixelshiftShowMotion = v; + raw.bayersensor.pixelshiftBlendMotion = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -872,6 +873,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelshiftMotion = raw.bayersensor.pixelshiftMotion && p.raw.bayersensor.pixelshiftMotion == other.raw.bayersensor.pixelshiftMotion; raw.bayersensor.pixelshiftMotionCorrection = raw.bayersensor.pixelshiftMotionCorrection && p.raw.bayersensor.pixelshiftMotionCorrection == other.raw.bayersensor.pixelshiftMotionCorrection; raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; + raw.bayersensor.pixelshiftBlendMotion = raw.bayersensor.pixelshiftBlendMotion && p.raw.bayersensor.pixelshiftBlendMotion == other.raw.bayersensor.pixelshiftBlendMotion; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2296,6 +2298,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion; } + if (raw.bayersensor.pixelshiftBlendMotion) { + toEdit.raw.bayersensor.pixelshiftBlendMotion = mods.raw.bayersensor.pixelshiftBlendMotion; + } + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 5546c9857..9d9bc3fb9 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -695,6 +695,7 @@ public: bool pixelshiftMotion; bool pixelshiftMotionCorrection; bool pixelshiftShowMotion; + bool pixelshiftBlendMotion; //bool allEnhance; bool greenEq; bool linenoise; From fa1717fddfb1b240819b6132443d7e4756fb4b63 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 21 Nov 2016 12:35:18 +0100 Subject: [PATCH 20/83] pixelshift bugfix --- rtengine/pixelshift.cc | 4 ++-- rtengine/rawimagesource.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 7869daa6d..333f22bd4 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -76,7 +76,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b bool checkRedBlue = (gridSize == 5); // bool checkRedBlue = false; unsigned int offsX = 0, offsY = 0; - if(detectMotion) { + if(detectMotion || blendMotion) { // if motion correction is enabled we have to adjust the offsets for the selected subframe we use for areas with motion switch (frame) { case 0: @@ -120,7 +120,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b float greenDifMax[gridSize]; // motion detection checks the grid around the pixel for differences in green channels - if(detectMotion) { + if(detectMotion || blendMotion) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]), diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index ed6efdae0..2c07aee3a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1962,7 +1962,7 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { - if(raw.bayersensor.pixelshiftMotion > 0) { + if(raw.bayersensor.pixelshiftMotion > 0 || raw.bayersensor.pixelshiftBlendMotion) { amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { From efde91c226c78b1add01e48f08ba19e29e05e0a7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 21 Nov 2016 14:08:18 +0100 Subject: [PATCH 21/83] pixelshift bugfix --- rtengine/pixelshift.cc | 338 ++++++++++++++++++++--------------------- 1 file changed, 164 insertions(+), 174 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 333f22bd4..7394cb237 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -36,12 +36,14 @@ namespace { -float greenDiff(float a, float b) +float greenDiff(float a, float b, bool adaptive, float scale) { // calculate the difference between to green samples // add a small epsilon to avoid division by zero - return std::fabs(a - b) / (std::max(a, b) + 0.01f); - + float diff = std::fabs(a - b) / (std::max(a, b) + 0.01f); + if(adaptive) + diff -= ((5.f / sqrtf(scale * (a+b) / 2.f)) / 0.75f); + return diff; } } @@ -49,53 +51,52 @@ float greenDiff(float a, float b) using namespace std; using namespace rtengine; -void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool blendMotion) +void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive) { BENCHFUN - printf("%f\t%f\t%f\t%f\n",scale_mul[0],scale_mul[1],scale_mul[2],scale_mul[3]); - if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); plistener->setProgress(0.0); } - LUTf log2Lut(65536); + // Lookup table for non adaptive (slider) mode + LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); log2Lut[0] = 0; const float lutStrength = 2.f; const float scaleGreen = 1.f / scale_mul[1]; for(int i=2; i < 65536; i+=2) log2Lut[i>>1] = 2.f * log2(i) / 100.f; + + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); - // For 'blend' mode - const float blendFactor = 1.f / (1.f - motionThreshold); + // For shades of green motion indicators + const float blendFactor = (motion == 0.f ? 1.f : 1.f / (1.f - motionThreshold)); bool checkRedBlue = (gridSize == 5); // bool checkRedBlue = false; unsigned int offsX = 0, offsY = 0; - if(detectMotion || blendMotion) { - // if motion correction is enabled we have to adjust the offsets for the selected subframe we use for areas with motion - switch (frame) { - case 0: - offsX = offsY = 0; - break; + // We have to adjust the offsets for the selected subframe we use for areas with motion + switch (frame) { + case 0: + offsX = offsY = 0; + break; - case 1: - offsX = 0; - offsY = 1; - break; + case 1: + offsX = 0; + offsY = 1; + break; - case 2: - offsX = offsY = 1; - break; + case 2: + offsX = offsY = 1; + break; - case 3: - offsX = 1; - offsY = 0; - } + case 3: + offsX = 1; + offsY = 0; } #ifdef _OPENMP @@ -120,42 +121,42 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b float greenDifMax[gridSize]; // motion detection checks the grid around the pixel for differences in green channels - if(detectMotion || blendMotion) { + if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j]) + greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen) ); - greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1]) + greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1]), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1]), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1]), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1]), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1]) + greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, scaleGreen) ); - greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j]), - greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j]), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j]), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j]), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j]) + greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen) ); - greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1]), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1]), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1]), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1]) + greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen) ); - greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2]), - greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2]), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2]), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2]), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2]) + greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, scaleGreen) ); } } @@ -168,27 +169,27 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b for(; j < winw - (border + offsX); ++j) { offset ^= 1; // 0 => 1 or 1 => 0 - if(detectMotion || blendMotion) { + if(detectMotion || adaptive) { bool skipNext = false; float gridMax; if(gridSize == 1) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1]); + gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen); skipNext = !showMotion; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2]), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2]), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2]) + greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, scaleGreen) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3]), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3]), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3]), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3]), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3]) + greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, scaleGreen), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, scaleGreen), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, scaleGreen) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } @@ -197,124 +198,113 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b lastIndex = lastIndex == gridSize ? 0 : lastIndex; // increase motion detection dependent on brightness -// float korr = 2.f * log2Lut[((int)riFrames[1 - offset]->data[i - offset + 1][j])>>1]; - float centerVal = riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen; - if(true || centerVal > 32) { - float korr; - float thresh; - if(blendMotion) { - korr = 0.f; - float average = scaleGreen * (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; - thresh = (5.f / sqrtf(average)) / 0.75f; - } else { - korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; - thresh = motionThreshold; + float korr; + float thresh; + if(adaptive) { + korr = 0.f; + thresh = 0; + } else { + korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; + thresh = motionThreshold; + } + + if (gridMax > thresh - korr) { + float blend = (gridMax - thresh + korr) * blendFactor; + // at least one of the tested pixels of the grid is detected as motion + if(showMotion) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; } -// float korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; -// float korr = 0.f; -// float average = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1])/2.f; -// float motionThreshold = 5.f * sqrtf(3.f*average/(scale_mul[1])) / (average * scaleGreen * 3.f); - if (gridMax > thresh - korr) { - float blend = (gridMax - thresh + korr) * blendFactor; - // at least one of the tested pixels of the grid is detected as motion - if(showMotion) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; - } else if(false) { - greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); - nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); - nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); - } - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; - offset ^= 1; - } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; + + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + offset ^= 1; } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; } } - if(false && detectMotion && checkRedBlue) { - float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; - float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; - float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; - float diff0 = ng1 - ng0; - float diff2 = ng1 - ng2; - float gridMax; - if(diff0 * diff2 > 0.f) { -// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { - gridMax = greenDiff(ng1, std::max(ng0, ng2)); -// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); - if(gridMax > motionThreshold ) { - float factor = 1.f / (1.f - motionThreshold); - float blend = (gridMax - motionThreshold) * factor; - if(showMotion) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = nonGreenDest1[j + offsX] = 0.f; - nonGreenDest0[j + offsX] = 20000.f; - continue; -// greenDest[j + offsX+1] = nonGreenDest1[j + offsX+1] = 0.f; -// nonGreenDest0[j + offsX+1] = 20000.f; - } - greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; - -// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); -// nonGreenDest0[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; - nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); +// if(false && detectMotion && checkRedBlue) { +// float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; +// float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; +// float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; +// float diff0 = ng1 - ng0; +// float diff2 = ng1 - ng2; +// float gridMax; +// if(diff0 * diff2 > 0.f) { +//// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { +// gridMax = greenDiff(ng1, std::max(ng0, ng2)); +//// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); +// if(gridMax > motionThreshold ) { +// float factor = 1.f / (1.f - motionThreshold); +// float blend = (gridMax - motionThreshold) * factor; +// if(showMotion) { +// // if showMotion is enabled make the pixel green +// greenDest[j + offsX] = nonGreenDest1[j + offsX] = 0.f; +// nonGreenDest0[j + offsX] = 20000.f; +// continue; +//// greenDest[j + offsX+1] = nonGreenDest1[j + offsX+1] = 0.f; +//// nonGreenDest0[j + offsX+1] = 20000.f; +// } +// greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; +// +//// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); +//// nonGreenDest0[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; // nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); - nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; - +//// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); +// nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; +// +//// nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); +// +//// if(skipNext) { +//// // treat the horizontally next pixel also as motion +//// j++; +//// offset ^= 1; +//// } +// // do not set the motion pixel values. They have already been set by demosaicer or showMotion +// continue; +// } +// } +// ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; +// ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; +// ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; +// diff0 = ng1 - ng0; +// diff2 = ng1 - ng2; +// if(signbit(diff0) == signbit(diff2)) { +//// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { +// gridMax = greenDiff(ng1, std::max(ng0, ng2)); +//// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); +// if(gridMax > motionThreshold ) { +// float factor = 1.f / (1.f - motionThreshold); +// float blend = (gridMax - motionThreshold) * factor; +// if(showMotion) { +// // if showMotion is enabled make the pixel green +// greenDest[j + offsX] = nonGreenDest0[j + offsX] = 0.f; +// nonGreenDest1[j + offsX] = 20000.f; +//// greenDest[j + offsX+1] = nonGreenDest0[j + offsX+1] = 0.f; +//// nonGreenDest1[j + offsX+1] = 20000.f; +//continue; +// } +// greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; +//// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); +//// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); +// nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; +// +//// nonGreenDest1[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; // nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); - -// if(skipNext) { -// // treat the horizontally next pixel also as motion -// j++; -// offset ^= 1; -// } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; - } - } - ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; - ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; - ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; - diff0 = ng1 - ng0; - diff2 = ng1 - ng2; - if(signbit(diff0) == signbit(diff2)) { -// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { - gridMax = greenDiff(ng1, std::max(ng0, ng2)); -// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); - if(gridMax > motionThreshold ) { - float factor = 1.f / (1.f - motionThreshold); - float blend = (gridMax - motionThreshold) * factor; - if(showMotion) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = nonGreenDest0[j + offsX] = 0.f; - nonGreenDest1[j + offsX] = 20000.f; -// greenDest[j + offsX+1] = nonGreenDest0[j + offsX+1] = 0.f; -// nonGreenDest1[j + offsX+1] = 20000.f; -continue; - } - greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; -// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); -// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); - nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; - -// nonGreenDest1[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; - nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); -// if(skipNext) { -// // treat the horizontally next pixel also as motion -// j++; -// offset ^= 1; -// } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; - } - } - } +//// if(skipNext) { +//// // treat the horizontally next pixel also as motion +//// j++; +//// offset ^= 1; +//// } +// // do not set the motion pixel values. They have already been set by demosaicer or showMotion +// continue; +// } +// } +// } // motion correction disabled or no motion detected => combine the values from the four pixelshift frames greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; From fb043e9f5d3f890afbce7b497e06058202250c8c Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 21 Nov 2016 21:38:14 +0100 Subject: [PATCH 22/83] pixelshift: experimental changes for Ilias :) --- rtdata/languages/default | 6 +- rtengine/pixelshift.cc | 94 +++++++++++++++------------- rtengine/procparams.cc | 64 +++++++++++++++++-- rtengine/procparams.h | 6 +- rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 124 ++++++++++++++++++++++++++++++++----- rtgui/bayerprocess.h | 10 ++- rtgui/paramsedited.cc | 32 ++++++++-- rtgui/paramsedited.h | 6 +- 10 files changed, 270 insertions(+), 78 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 44d540315..8520b8c36 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1654,12 +1654,16 @@ TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift, TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. -TP_RAW_PIXELSHIFTADAPTIVE;Automatic detection +TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion +TP_RAW_PIXELSHIFTSTDDEVFACTOR;StdDev factor +TP_RAW_PIXELSHIFTEPERISO;e per ISO +TP_RAW_PIXELSHIFTNREADISO;nRead per ISO +TP_RAW_PIXELSHIFTPRNU;PRNU TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster. TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 7394cb237..e88c4bfeb 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -36,13 +36,18 @@ namespace { -float greenDiff(float a, float b, bool adaptive, float scale) +float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor, float eperIso, float nreadIso, float prnu) { // calculate the difference between to green samples // add a small epsilon to avoid division by zero float diff = std::fabs(a - b) / (std::max(a, b) + 0.01f); - if(adaptive) - diff -= ((5.f / sqrtf(scale * (a+b) / 2.f)) / 0.75f); + if(adaptive) { + float avg = (a+b)/2.f; + avg *= scale; + float stddev = sqrtf(avg * eperIso + nreadIso * nreadIso + prnu * prnu); + float korr = stddevFactor * stddev / (a * scale); + diff -= korr; + } return diff; } @@ -51,7 +56,7 @@ float greenDiff(float a, float b, bool adaptive, float scale) using namespace std; using namespace rtengine; -void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive) +void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu) { BENCHFUN @@ -62,6 +67,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b } + gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); log2Lut[0] = 0; @@ -70,13 +76,18 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b for(int i=2; i < 65536; i+=2) log2Lut[i>>1] = 2.f * log2(i) / 100.f; - +// const float eperIso = 0.75f * idata->getISOSpeed() / 100; + eperIso *= (idata->getISOSpeed() / 100); + nreadIso *= (idata->getISOSpeed() / 100); +// const float nreadIso = 5.f * idata->getISOSpeed() / 100; +// const float prnu = 1.f; +// const float stddevFactor = 4.f; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); // For shades of green motion indicators const float blendFactor = (motion == 0.f ? 1.f : 1.f / (1.f - motionThreshold)); - bool checkRedBlue = (gridSize == 5); +// bool checkRedBlue = (gridSize == 5); // bool checkRedBlue = false; unsigned int offsX = 0, offsY = 0; // We have to adjust the offsets for the selected subframe we use for areas with motion @@ -118,45 +129,44 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop unsigned int offset = (c & 1); - float greenDifMax[gridSize]; // motion detection checks the grid around the pixel for differences in green channels if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen) + greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); - greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen) + greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, scaleGreen) + greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); - greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen) + greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); - greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen) + greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); - greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, scaleGreen) + greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); } } @@ -174,22 +184,22 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b float gridMax; if(gridSize == 1) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen); + gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu); skipNext = !showMotion; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, scaleGreen) + greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, scaleGreen), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, scaleGreen), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, scaleGreen) + greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index eba1e36f4..42e31b3ed 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -887,8 +887,12 @@ void RAWParams::setDefaults() bayersensor.lmmse_iterations = 2; bayersensor.pixelshiftMotion = 70; bayersensor.pixelshiftMotionCorrection = 3; + bayersensor.pixelShiftStddevFactor = 5.0; + bayersensor.pixelShiftEperIso = 0.75; + bayersensor.pixelShiftNreadIso = 5.0; + bayersensor.pixelShiftPrnu = 1.0; bayersensor.pixelshiftShowMotion = false; - bayersensor.pixelshiftBlendMotion = false; + bayersensor.pixelShiftAutomatic = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3376,12 +3380,28 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelshiftMotionCorrection ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactor) { + keyFile.set_double ("RAW Bayer", "PixelShiftStddevFactor", raw.bayersensor.pixelShiftStddevFactor ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftEperIso) { + keyFile.set_double ("RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftNreadIso) { + keyFile.set_double ("RAW Bayer", "PixelShiftNreadIso", raw.bayersensor.pixelShiftNreadIso ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftPrnu) { + keyFile.set_double ("RAW Bayer", "PixelShiftPrnu", raw.bayersensor.pixelShiftPrnu ); + } + if (!pedited || pedited->raw.bayersensor.pixelshiftShowMotion) { keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion ); } - if (!pedited || pedited->raw.bayersensor.pixelshiftBlendMotion) { - keyFile.set_boolean ("RAW Bayer", "PixelShiftBlendMotion", raw.bayersensor.pixelshiftBlendMotion ); + if (!pedited || pedited->raw.bayersensor.pixelShiftAutomatic) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftAutomatic", raw.bayersensor.pixelShiftAutomatic ); } //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); @@ -7458,6 +7478,38 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftStddevFactor")) { + raw.bayersensor.pixelShiftStddevFactor = keyFile.get_double("RAW Bayer", "PixelShiftStddevFactor"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftStddevFactor = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftEperIso")) { + raw.bayersensor.pixelShiftEperIso = keyFile.get_double("RAW Bayer", "PixelShiftEperIso"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftEperIso = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftNreadIso")) { + raw.bayersensor.pixelShiftNreadIso = keyFile.get_double("RAW Bayer", "PixelShiftNreadIso"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNreadIso = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftPrnu")) { + raw.bayersensor.pixelShiftPrnu = keyFile.get_double("RAW Bayer", "PixelShiftPrnu"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftPrnu = true; + } + } + if (keyFile.has_key ("RAW Bayer", "PixelShiftShowMotion")) { raw.bayersensor.pixelshiftShowMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftShowMotion"); @@ -7466,11 +7518,11 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - if (keyFile.has_key ("RAW Bayer", "PixelShiftBlendMotion")) { - raw.bayersensor.pixelshiftBlendMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftBlendMotion"); + if (keyFile.has_key ("RAW Bayer", "pixelShiftAutomatic")) { + raw.bayersensor.pixelShiftAutomatic = keyFile.get_boolean("RAW Bayer", "pixelShiftAutomatic"); if (pedited) { - pedited->raw.bayersensor.pixelshiftBlendMotion = true; + pedited->raw.bayersensor.pixelShiftAutomatic = true; } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index a6308454c..5bd3e4646 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1184,8 +1184,12 @@ public: int lmmse_iterations; int pixelshiftMotion; int pixelshiftMotionCorrection; + double pixelShiftStddevFactor; + double pixelShiftEperIso; + double pixelShiftNreadIso; + double pixelShiftPrnu; bool pixelshiftShowMotion; - bool pixelshiftBlendMotion; + bool pixelShiftAutomatic; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 2c07aee3a..d3e6b1881 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1962,11 +1962,11 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { - if(raw.bayersensor.pixelshiftMotion > 0 || raw.bayersensor.pixelshiftBlendMotion) { + if(raw.bayersensor.pixelshiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) { amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelshiftBlendMotion); + pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 08e1643ed..75037710b 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -263,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool blendMotion); + void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5c80b93c1..867d911e5 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -86,8 +86,8 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); pixelShiftOptions->pack_start(*pixelShiftShowMotion); - pixelShiftBlendMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); - pixelShiftOptions->pack_start(*pixelShiftBlendMotion); + pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); + pixelShiftOptions->pack_start(*pixelShiftAutomatic); pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); @@ -109,6 +109,52 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->show(); pixelShiftOptions->pack_start(*pixelShiftMotionCorrection); + + pixelShiftStddevFactor = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR"), 2, 8, 0.1, 5)); + pixelShiftStddevFactor->setAdjusterListener (this); +// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); + + if (pixelShiftStddevFactor->delay < options.adjusterMaxDelay) { + pixelShiftStddevFactor->delay = options.adjusterMaxDelay; + } + + pixelShiftStddevFactor->show(); + pixelShiftOptions->pack_start(*pixelShiftStddevFactor); + + pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), 0.3, 1.0, 0.05, 0.75)); + pixelShiftEperIso->setAdjusterListener (this); +// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); + + if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { + pixelShiftEperIso->delay = options.adjusterMaxDelay; + } + + pixelShiftEperIso->show(); + pixelShiftOptions->pack_start(*pixelShiftEperIso); + + pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), 1.0, 10.0, 0.5, 5.0)); + pixelShiftNreadIso->setAdjusterListener (this); +// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); + + if (pixelShiftNreadIso->delay < options.adjusterMaxDelay) { + pixelShiftNreadIso->delay = options.adjusterMaxDelay; + } + + pixelShiftNreadIso->show(); + pixelShiftOptions->pack_start(*pixelShiftNreadIso); + + + pixelShiftPrnu = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTPRNU"), 0.3, 2.0, 0.1, 1.0)); + pixelShiftPrnu->setAdjusterListener (this); +// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); + + if (pixelShiftPrnu->delay < options.adjusterMaxDelay) { + pixelShiftPrnu->delay = options.adjusterMaxDelay; + } + + pixelShiftPrnu->show(); + pixelShiftOptions->pack_start(*pixelShiftPrnu); + pack_start( *pixelShiftOptions, Gtk::PACK_SHRINK, 4); @@ -134,7 +180,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); - pixelShiftBlendMotionconn = pixelShiftBlendMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlendMotionChanged), true); + pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -163,11 +209,15 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); - pixelShiftBlendMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftBlendMotion); + pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); pixelShiftMotionCorrection->setEditedState ( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); + pixelShiftStddevFactor->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); + pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); + pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); + pixelShiftPrnu->setEditedState ( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); if(!pedited->raw.bayersensor.method) { method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name @@ -182,11 +232,15 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); - pixelShiftBlendMotion->set_active(pp->raw.bayersensor.pixelshiftBlendMotion); + pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); pixelShiftMotionCorrection->setValue (pp->raw.bayersensor.pixelshiftMotionCorrection); + pixelShiftStddevFactor->setValue (pp->raw.bayersensor.pixelShiftStddevFactor); + pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); + pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); + pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || @@ -237,8 +291,12 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); pp->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getIntValue(); pp->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getIntValue(); + pp->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getValue(); + pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); + pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); + pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); - pp->raw.bayersensor.pixelshiftBlendMotion = pixelShiftBlendMotion->get_active(); + pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -261,8 +319,12 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); pedited->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getEditedState (); pedited->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getEditedState (); + pedited->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getEditedState (); + pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); + pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); - pedited->raw.bayersensor.pixelshiftBlendMotion = !pixelShiftBlendMotion->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); } } @@ -281,6 +343,10 @@ void BayerProcess::setBatchMode(bool batchMode) lmmseIterations->showEditedCB (); pixelShiftMotion->showEditedCB (); pixelShiftMotionCorrection->showEditedCB (); + pixelShiftStddevFactor->showEditedCB (); + pixelShiftEperIso->showEditedCB (); + pixelShiftNreadIso->showEditedCB (); + pixelShiftPrnu->showEditedCB (); } void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) @@ -289,6 +355,10 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelshiftMotion); pixelShiftMotionCorrection->setDefault( defParams->raw.bayersensor.pixelshiftMotionCorrection); + pixelShiftStddevFactor->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactor); + pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); + pixelShiftNreadIso->setDefault( defParams->raw.bayersensor.pixelShiftNreadIso); + pixelShiftPrnu->setDefault( defParams->raw.bayersensor.pixelShiftPrnu); ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); if (pedited) { @@ -296,12 +366,20 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); pixelShiftMotionCorrection->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); + pixelShiftStddevFactor->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); + pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); + pixelShiftNreadIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); + pixelShiftPrnu->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); } else { dcbIterations->setDefaultEditedState( Irrelevant ); lmmseIterations->setDefaultEditedState( Irrelevant ); pixelShiftMotion->setDefaultEditedState( Irrelevant ); pixelShiftMotionCorrection->setDefaultEditedState( Irrelevant ); + pixelShiftStddevFactor->setDefaultEditedState( Irrelevant ); + pixelShiftEperIso->setDefaultEditedState( Irrelevant ); + pixelShiftNreadIso->setDefaultEditedState( Irrelevant ); + pixelShiftPrnu->setDefaultEditedState( Irrelevant ); ccSteps->setDefaultEditedState(Irrelevant ); } } @@ -319,6 +397,14 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); } else if (a == pixelShiftMotionCorrection) { listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + } else if (a == pixelShiftStddevFactor) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + } else if (a == pixelShiftEperIso) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + } else if (a == pixelShiftNreadIso) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + } else if (a == pixelShiftPrnu) { + listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); } } } @@ -410,24 +496,28 @@ void BayerProcess::pixelShiftShowMotionChanged () } } -void BayerProcess::pixelShiftBlendMotionChanged () +void BayerProcess::pixelShiftAutomaticChanged () { if (batchMode) { - if (pixelShiftBlendMotion->get_inconsistent()) { - pixelShiftBlendMotion->set_inconsistent (false); - pixelShiftBlendMotionconn.block (true); - pixelShiftBlendMotion->set_active (false); - pixelShiftBlendMotionconn.block (false); + if (pixelShiftAutomatic->get_inconsistent()) { + pixelShiftAutomatic->set_inconsistent (false); + pixelShiftAutomaticconn.block (true); + pixelShiftAutomatic->set_active (false); + pixelShiftAutomaticconn.block (false); } else if (lastDCBen) { - pixelShiftBlendMotion->set_inconsistent (true); + pixelShiftAutomatic->set_inconsistent (true); } - lastDCBen = pixelShiftBlendMotion->get_active (); + lastDCBen = pixelShiftAutomatic->get_active (); } - pixelShiftMotion->set_sensitive(!pixelShiftBlendMotion->get_active ()); + pixelShiftMotion->set_sensitive(!pixelShiftAutomatic->get_active ()); + pixelShiftEperIso->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNreadIso->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftPrnu->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftStddevFactor->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftBlendMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 383adeb43..b490f8c42 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -45,11 +45,15 @@ protected: Adjuster* pixelShiftMotion; Adjuster* pixelShiftMotionCorrection; Gtk::CheckButton* pixelShiftShowMotion; - Gtk::CheckButton* pixelShiftBlendMotion; + Gtk::CheckButton* pixelShiftAutomatic; + Adjuster* pixelShiftStddevFactor; + Adjuster* pixelShiftEperIso; + Adjuster* pixelShiftNreadIso; + Adjuster* pixelShiftPrnu; bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftBlendMotionconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftAutomaticconn; //,allEnhconn; public: BayerProcess (); @@ -64,7 +68,7 @@ public: void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); void pixelShiftShowMotionChanged(); - void pixelShiftBlendMotionChanged(); + void pixelShiftAutomaticChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 5b045c2ce..87dab2311 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -372,8 +372,12 @@ void ParamsEdited::set (bool v) raw.bayersensor.lmmseIterations = v; raw.bayersensor.pixelshiftMotion = v; raw.bayersensor.pixelshiftMotionCorrection = v; + raw.bayersensor.pixelShiftStddevFactor = v; + raw.bayersensor.pixelShiftEperIso = v; + raw.bayersensor.pixelShiftNreadIso = v; + raw.bayersensor.pixelShiftPrnu = v; raw.bayersensor.pixelshiftShowMotion = v; - raw.bayersensor.pixelshiftBlendMotion = v; + raw.bayersensor.pixelShiftAutomatic = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -872,8 +876,12 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; raw.bayersensor.pixelshiftMotion = raw.bayersensor.pixelshiftMotion && p.raw.bayersensor.pixelshiftMotion == other.raw.bayersensor.pixelshiftMotion; raw.bayersensor.pixelshiftMotionCorrection = raw.bayersensor.pixelshiftMotionCorrection && p.raw.bayersensor.pixelshiftMotionCorrection == other.raw.bayersensor.pixelshiftMotionCorrection; + raw.bayersensor.pixelShiftStddevFactor = raw.bayersensor.pixelShiftStddevFactor && p.raw.bayersensor.pixelShiftStddevFactor == other.raw.bayersensor.pixelShiftStddevFactor; + raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; + raw.bayersensor.pixelShiftNreadIso = raw.bayersensor.pixelShiftNreadIso && p.raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso; + raw.bayersensor.pixelShiftPrnu = raw.bayersensor.pixelShiftPrnu && p.raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu; raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; - raw.bayersensor.pixelshiftBlendMotion = raw.bayersensor.pixelshiftBlendMotion && p.raw.bayersensor.pixelshiftBlendMotion == other.raw.bayersensor.pixelshiftBlendMotion; + raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2294,12 +2302,28 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelshiftMotionCorrection = mods.raw.bayersensor.pixelshiftMotionCorrection; } + if (raw.bayersensor.pixelShiftStddevFactor) { + toEdit.raw.bayersensor.pixelShiftStddevFactor = mods.raw.bayersensor.pixelShiftStddevFactor; + } + + if (raw.bayersensor.pixelShiftEperIso) { + toEdit.raw.bayersensor.pixelShiftEperIso = mods.raw.bayersensor.pixelShiftEperIso; + } + + if (raw.bayersensor.pixelShiftNreadIso) { + toEdit.raw.bayersensor.pixelShiftNreadIso = mods.raw.bayersensor.pixelShiftNreadIso; + } + + if (raw.bayersensor.pixelShiftPrnu) { + toEdit.raw.bayersensor.pixelShiftPrnu = mods.raw.bayersensor.pixelShiftPrnu; + } + if (raw.bayersensor.pixelshiftShowMotion) { toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion; } - if (raw.bayersensor.pixelshiftBlendMotion) { - toEdit.raw.bayersensor.pixelshiftBlendMotion = mods.raw.bayersensor.pixelshiftBlendMotion; + if (raw.bayersensor.pixelShiftAutomatic) { + toEdit.raw.bayersensor.pixelShiftAutomatic = mods.raw.bayersensor.pixelShiftAutomatic; } //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 9d9bc3fb9..c116350a8 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -694,8 +694,12 @@ public: bool lmmseIterations; bool pixelshiftMotion; bool pixelshiftMotionCorrection; + bool pixelShiftStddevFactor; + bool pixelShiftEperIso; + bool pixelShiftNreadIso; + bool pixelShiftPrnu; bool pixelshiftShowMotion; - bool pixelshiftBlendMotion; + bool pixelShiftAutomatic; //bool allEnhance; bool greenEq; bool linenoise; From 520557912b8f2358b649058fcfe826cdb8cf37c8 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 22 Nov 2016 16:35:11 +0100 Subject: [PATCH 23/83] pixelshift: changed formula for adaptive motion detection --- rtdata/languages/default | 4 ++-- rtengine/pixelshift.cc | 6 ++++-- rtgui/bayerprocess.cc | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 8520b8c36..01d5270e1 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1662,8 +1662,8 @@ TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 gr TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_PIXELSHIFTSTDDEVFACTOR;StdDev factor TP_RAW_PIXELSHIFTEPERISO;e per ISO -TP_RAW_PIXELSHIFTNREADISO;nRead per ISO -TP_RAW_PIXELSHIFTPRNU;PRNU +TP_RAW_PIXELSHIFTNREADISO;nRead +TP_RAW_PIXELSHIFTPRNU;PRNU (%) TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster. TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index e88c4bfeb..c4c7d2c7d 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -43,7 +43,8 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor float diff = std::fabs(a - b) / (std::max(a, b) + 0.01f); if(adaptive) { float avg = (a+b)/2.f; - avg *= scale; + avg *= scale; // revert the colour scaling + prnu *= (avg * eperIso); float stddev = sqrtf(avg * eperIso + nreadIso * nreadIso + prnu * prnu); float korr = stddevFactor * stddev / (a * scale); diff -= korr; @@ -78,7 +79,8 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b // const float eperIso = 0.75f * idata->getISOSpeed() / 100; eperIso *= (idata->getISOSpeed() / 100); - nreadIso *= (idata->getISOSpeed() / 100); +// nreadIso *= (idata->getISOSpeed() / 100); + prnu /= 100.f; // const float nreadIso = 5.f * idata->getISOSpeed() / 100; // const float prnu = 1.f; // const float stddevFactor = 4.f; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 867d911e5..63705e472 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -132,7 +132,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftEperIso->show(); pixelShiftOptions->pack_start(*pixelShiftEperIso); - pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), 1.0, 10.0, 0.5, 5.0)); + pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), 1.0, 10.0, 0.05, 3.45)); pixelShiftNreadIso->setAdjusterListener (this); // pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); From 622fddb15cbcd3e4713549344fc53037eb8d8381 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 23 Nov 2016 00:28:26 +0100 Subject: [PATCH 24/83] changed name from 'pixelshift simple' to 'pixelshift' --- rtengine/procparams.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 42e31b3ed..5da9f05fd 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -40,7 +40,7 @@ const int br = (int) options.rtSettings.bot_right; const int tl = (int) options.rtSettings.top_left; const int bl = (int) options.rtSettings.bot_left; -const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "fast", "mono", "none", "pixelshift simple" }; +const char *RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::numMethods] = {"amaze", "igv", "lmmse", "eahd", "hphd", "vng4", "dcb", "ahd", "fast", "mono", "none", "pixelshift" }; const char *RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::numMethods] = {"3-pass (best)", "1-pass (medium)", "fast", "mono", "none" }; const char *RAWParams::ff_BlurTypestring[RAWParams::numFlatFileBlurTypes] = {/*"Parametric",*/ "Area Flatfield", "Vertical Flatfield", "Horizontal Flatfield", "V+H Flatfield"}; From fe5f862c092449423a2ff972f5cf11ae0612a7aa Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 23 Nov 2016 17:45:32 +0100 Subject: [PATCH 25/83] use camconst.json from master --- rtengine/camconst.json | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index cbef6d132..ed28618ab 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1003,8 +1003,8 @@ Camera constants: "ranges": { "white": 16300 } }, - { // Quality B - "make_model": [ "Canon PowerShot G7 X", "Canon PowerShot G7 X Mark II" ], + { // Quality B, + "make_model": "Canon PowerShot G7 X", "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 //"raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 @@ -1012,8 +1012,8 @@ Camera constants: "ranges": { "white": 4080 } }, - { // Quality B - "make_model": [ "Canon PowerShot G5 X", "Canon PowerShot G9 X" ], + { // Quality B, + "make_model": [ "Canon PowerShot G5 X", "Canon PowerShot G9 X", "Canon PowerShot G7 X Mark II" ], "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 //"raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 @@ -1332,6 +1332,20 @@ Camera constants: } }, + { // Quality C, 20Mp and 80Mp raw frames, Color matrix copied from EM5MKII which looks to be close. + "make_model": "OLYMPUS E-M1MarkII", + "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // E-M5II dng_v9.5 D65 + "raw_crop": [ 8, 8, -16, -8 ], // full raw 5240X3912, jpeg top12,left12,5184x3888, full hires 10400X7792, jpeg crop 8,8,10368x7776 + "ranges": { + "white": [ + { "iso": [ 64, 100, 125, 160, 200, 250, 320, 400 ], "levels": 4090 }, // normal 4095 + { "iso": [ 500, 640, 800, 1000, 1600 ], "levels": 4080 }, // 4085-4095 + { "iso": [ 2000, 2500, 3200, 4000, 5000, 6400 ], "levels": 4060 }, // 4085-4095 + { "iso": [ 12800, 25600, 51200 ], "levels": 4060 } // guess + ] + } + }, + { // Quality B, missing per ISO samples "make_model": "OLYMPUS E-M1", "dcraw_matrix": [ 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 ], // dng d65 @@ -1702,6 +1716,22 @@ Camera constants: } }, + { // Quality B, Intemediate ISO samples missing, Pentax_DNG WLtags are after BL sutraction and not valid + "make_model": [ "RICOH PENTAX K-1", "PENTAX K-1" ], + "dcraw_matrix": [ 8596,-2981,-639,-4202,12046,2431,-685,1424,6122 ], // adobe DNG v9.7 D65 + //"dcraw_matrix": [ 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 ], // PENTAX DNG + "raw_crop": [ 6, 18, 7376, 4932 ], // full frame 7392x4950, cropped to official DNG raw_crop 6,18,7382,4950, official jpeg crop 8,10,7360x4912 + "ranges": { + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 16300 }, // 16380 + { "iso": [ 1600, 3200 ], "levels": 16250 }, // 16360 + { "iso": [ 6400, 12800 ], "levels": 16200 }, // 16330 + { "iso": [ 25600, 51200 ], "levels": 16100 }, // 16300 + { "iso": 102400, "levels": 16000 } // 16200 + ] + } + }, + { // Quality B, intermediate ISOs info missing "make_model": [ "RICOH PENTAX K-3", "PENTAX K-3" ], "dcraw_matrix": [ 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 ], // adobe dcp d65 From d83834d4e6a5eb9ab2791b61d03f34f56f6595f7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 24 Nov 2016 15:11:07 +0100 Subject: [PATCH 26/83] pixelshift: Correction for adaptive mode --- rtengine/pixelshift.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index c4c7d2c7d..68393da38 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -40,13 +40,14 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor { // calculate the difference between to green samples // add a small epsilon to avoid division by zero - float diff = std::fabs(a - b) / (std::max(a, b) + 0.01f); + float maxVal = std::max(a, b) + 0.01f; + float diff = std::fabs(a - b) / maxVal; if(adaptive) { float avg = (a+b)/2.f; avg *= scale; // revert the colour scaling prnu *= (avg * eperIso); float stddev = sqrtf(avg * eperIso + nreadIso * nreadIso + prnu * prnu); - float korr = stddevFactor * stddev / (a * scale); + float korr = stddevFactor * stddev / (maxVal * scale); diff -= korr; } return diff; @@ -77,13 +78,9 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b for(int i=2; i < 65536; i+=2) log2Lut[i>>1] = 2.f * log2(i) / 100.f; -// const float eperIso = 0.75f * idata->getISOSpeed() / 100; eperIso *= (idata->getISOSpeed() / 100); -// nreadIso *= (idata->getISOSpeed() / 100); prnu /= 100.f; -// const float nreadIso = 5.f * idata->getISOSpeed() / 100; -// const float prnu = 1.f; -// const float stddevFactor = 4.f; + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); // For shades of green motion indicators From 1fcbdd8966a97ee70494df2b3bff7d56540922aa Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 24 Nov 2016 19:01:33 +0100 Subject: [PATCH 27/83] pixelshift: new version of adapaptive motion detection --- rtengine/pixelshift.cc | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 68393da38..4a3d9e7e6 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -41,13 +41,17 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor // calculate the difference between to green samples // add a small epsilon to avoid division by zero float maxVal = std::max(a, b) + 0.01f; - float diff = std::fabs(a - b) / maxVal; + float gDiff = std::fabs(a - b); + float diff = gDiff / maxVal; if(adaptive) { float avg = (a+b)/2.f; avg *= scale; // revert the colour scaling - prnu *= (avg * eperIso); - float stddev = sqrtf(avg * eperIso + nreadIso * nreadIso + prnu * prnu); - float korr = stddevFactor * stddev / (maxVal * scale); + avg *= eperIso; + prnu *= avg; + float stddev = sqrtf(avg + nreadIso * nreadIso + prnu * prnu); +// float korr = stddevFactor * stddev / (a * scale); // V0: use G1 not scaled by eperIso +// float korr = stddevFactor * stddev / (maxVal * scale); // V1: use max(G1,G2) not scaled by eperIso + float korr = stddevFactor * stddev / (gDiff / (eperIso * scale)); // V2: use absolute difference abs(G1-G2) scaled by eperISo diff -= korr; } return diff; @@ -72,12 +76,14 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - log2Lut[0] = 0; - const float lutStrength = 2.f; + + if(detectMotion && !adaptive) { + const float lutStrength = 2.f; + log2Lut[0] = 0; + for(int i=2; i < 65536; i+=2) + log2Lut[i>>1] = lutStrength * log2(i) / 100.f; + } const float scaleGreen = 1.f / scale_mul[1]; - for(int i=2; i < 65536; i+=2) - log2Lut[i>>1] = 2.f * log2(i) / 100.f; - eperIso *= (idata->getISOSpeed() / 100); prnu /= 100.f; From 7eda37a081ae4410faaeead2994c0f37c0509658 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 24 Nov 2016 19:28:11 +0100 Subject: [PATCH 28/83] pixelshift: adaptice method V3 (worse than V2 imho) --- rtengine/pixelshift.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 4a3d9e7e6..4c1c1f122 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -51,7 +51,8 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor float stddev = sqrtf(avg + nreadIso * nreadIso + prnu * prnu); // float korr = stddevFactor * stddev / (a * scale); // V0: use G1 not scaled by eperIso // float korr = stddevFactor * stddev / (maxVal * scale); // V1: use max(G1,G2) not scaled by eperIso - float korr = stddevFactor * stddev / (gDiff / (eperIso * scale)); // V2: use absolute difference abs(G1-G2) scaled by eperISo +// float korr = stddevFactor * stddev / (gDiff / (eperIso * scale)); // V2: use absolute difference abs(G1-G2) scaled by eperISo + float korr = stddevFactor * stddev / (gDiff * eperIso * scale); // V3: corrected version of V2 diff -= korr; } return diff; From 28358d6bf2d3d6826ef4b03ec71537f4ecae3054 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 24 Nov 2016 20:01:16 +0100 Subject: [PATCH 29/83] pixelshift: added V4 for tests --- rtengine/pixelshift.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 4c1c1f122..c3f2cb986 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -50,9 +50,10 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor prnu *= avg; float stddev = sqrtf(avg + nreadIso * nreadIso + prnu * prnu); // float korr = stddevFactor * stddev / (a * scale); // V0: use G1 not scaled by eperIso -// float korr = stddevFactor * stddev / (maxVal * scale); // V1: use max(G1,G2) not scaled by eperIso + float korr = stddevFactor * stddev / (maxVal * scale); // V1: use max(G1,G2) not scaled by eperIso // float korr = stddevFactor * stddev / (gDiff / (eperIso * scale)); // V2: use absolute difference abs(G1-G2) scaled by eperISo - float korr = stddevFactor * stddev / (gDiff * eperIso * scale); // V3: corrected version of V2 +// float korr = stddevFactor * stddev / (gDiff * eperIso * scale); // V3: corrected version of V2 +// float korr = stddevFactor * stddev / (maxVal * scale * eperIso); // V4: use max(G1,G2) scaled by eperIso diff -= korr; } return diff; From d84b54cfe0e65e021500bbe90ccc1aa7dc71510e Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 24 Nov 2016 21:17:40 +0100 Subject: [PATCH 30/83] pixelshift: Fixed wrong ISO dependency --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index c3f2cb986..8e7a38fcd 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -86,7 +86,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b log2Lut[i>>1] = lutStrength * log2(i) / 100.f; } const float scaleGreen = 1.f / scale_mul[1]; - eperIso *= (idata->getISOSpeed() / 100); + eperIso *= (100 / idata->getISOSpeed()); prnu /= 100.f; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel From 39a02ea8278c1ada2f46b1b6a9b751cc1d5725bd Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 25 Nov 2016 01:57:22 +0100 Subject: [PATCH 31/83] pixelshift: added some verbose console output and reverted inverse ISO scaling --- rtengine/pixelshift.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 8e7a38fcd..be0308908 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -75,6 +75,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b } + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %f\tnread %f\tprnu %f\n",gridSize, adaptive, stddevFactor, eperIso, nreadIso, prnu); gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); @@ -86,7 +87,7 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b log2Lut[i>>1] = lutStrength * log2(i) / 100.f; } const float scaleGreen = 1.f / scale_mul[1]; - eperIso *= (100 / idata->getISOSpeed()); + eperIso *= (idata->getISOSpeed() / 100.f); prnu /= 100.f; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel From 802e7986616993fb2d24c107d7072b23e8e1225e Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 25 Nov 2016 13:56:40 +0100 Subject: [PATCH 32/83] pixelshift: simplified calculation of adaptive detection --- rtengine/pixelshift.cc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index be0308908..e2a59c314 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -39,24 +39,21 @@ namespace float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor, float eperIso, float nreadIso, float prnu) { // calculate the difference between to green samples - // add a small epsilon to avoid division by zero - float maxVal = std::max(a, b) + 0.01f; float gDiff = std::fabs(a - b); - float diff = gDiff / maxVal; if(adaptive) { - float avg = (a+b)/2.f; + float avg = (a + b) / 2.f; avg *= scale; // revert the colour scaling avg *= eperIso; prnu *= avg; - float stddev = sqrtf(avg + nreadIso * nreadIso + prnu * prnu); -// float korr = stddevFactor * stddev / (a * scale); // V0: use G1 not scaled by eperIso - float korr = stddevFactor * stddev / (maxVal * scale); // V1: use max(G1,G2) not scaled by eperIso -// float korr = stddevFactor * stddev / (gDiff / (eperIso * scale)); // V2: use absolute difference abs(G1-G2) scaled by eperISo -// float korr = stddevFactor * stddev / (gDiff * eperIso * scale); // V3: corrected version of V2 -// float korr = stddevFactor * stddev / (maxVal * scale * eperIso); // V4: use max(G1,G2) scaled by eperIso - diff -= korr; + float stddev = stddevFactor * sqrtf(avg + nreadIso * nreadIso + prnu * prnu); + gDiff *= scale; + gDiff *= eperIso; + return gDiff - stddev; + } else { + // add a small epsilon to avoid division by zero + float maxVal = std::max(a, b) + 0.01f; + return gDiff / maxVal; } - return diff; } } @@ -87,7 +84,9 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b log2Lut[i>>1] = lutStrength * log2(i) / 100.f; } const float scaleGreen = 1.f / scale_mul[1]; - eperIso *= (idata->getISOSpeed() / 100.f); + + eperIso *= (100.f / idata->getISOSpeed()); + prnu /= 100.f; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel From b4ef423acd943c972d1231d95a9a360e0db8ec38 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 25 Nov 2016 18:22:26 +0100 Subject: [PATCH 33/83] pixelshift: show mask only, Speedup for adaptive motion detection --- rtdata/languages/default | 1 + rtengine/pixelshift.cc | 114 +++++++++++++++++++++---------------- rtengine/procevents.h | 1 + rtengine/procparams.cc | 17 +++++- rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 3 +- rtgui/bayerprocess.cc | 30 +++++++++- rtgui/bayerprocess.h | 4 +- rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + 12 files changed, 127 insertions(+), 55 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 01d5270e1..2137092f2 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1660,6 +1660,7 @@ TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only TP_RAW_PIXELSHIFTSTDDEVFACTOR;StdDev factor TP_RAW_PIXELSHIFTEPERISO;e per ISO TP_RAW_PIXELSHIFTNREADISO;nRead diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index e2a59c314..215506811 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -36,20 +36,27 @@ namespace { -float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor, float eperIso, float nreadIso, float prnu) +float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between to green samples - float gDiff = std::fabs(a - b); if(adaptive) { + float gDiff = a - b; + gDiff *= eperIso; + gDiff *= gDiff; float avg = (a + b) / 2.f; - avg *= scale; // revert the colour scaling avg *= eperIso; prnu *= avg; - float stddev = stddevFactor * sqrtf(avg + nreadIso * nreadIso + prnu * prnu); - gDiff *= scale; - gDiff *= eperIso; - return gDiff - stddev; + float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); + float result = gDiff - stddev; + if(!showMotion) { + return result; + } else if(result > 0.f) { // for the motion mask + return std::fabs(a - b) / std::max(a, b) + 0.01f; + } else { + return 0.f; + } } else { + float gDiff = std::fabs(a - b); // add a small epsilon to avoid division by zero float maxVal = std::max(a, b) + 0.01f; return gDiff / maxVal; @@ -61,7 +68,7 @@ float greenDiff(float a, float b, bool adaptive, float scale, float stddevFactor using namespace std; using namespace rtengine; -void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu) { BENCHFUN @@ -86,14 +93,18 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b const float scaleGreen = 1.f / scale_mul[1]; eperIso *= (100.f / idata->getISOSpeed()); + eperIso *= scaleGreen; prnu /= 100.f; - + stddevFactor *= stddevFactor; + nreadIso *= nreadIso; + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); // For shades of green motion indicators const float blendFactor = (motion == 0.f ? 1.f : 1.f / (1.f - motionThreshold)); +// bool showOnlyMask = showMotion; // bool checkRedBlue = (gridSize == 5); // bool checkRedBlue = false; unsigned int offsX = 0, offsY = 0; @@ -141,39 +152,39 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); - greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); - greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); } } @@ -191,22 +202,22 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b float gridMax; if(gridSize == 1) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu); + gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion); skipNext = !showMotion; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, scaleGreen, stddevFactor, eperIso, nreadIso, prnu) + greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), + greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } @@ -226,12 +237,16 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b } if (gridMax > thresh - korr) { - float blend = (gridMax - thresh + korr) * blendFactor; // at least one of the tested pixels of the grid is detected as motion if(showMotion) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + float blend = (gridMax - thresh + korr) * blendFactor; + if(!showOnlyMask) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } } if(skipNext) { @@ -241,6 +256,9 @@ void RawImageSource::pixelshift_simple(int winx, int winy, int winw, int winh, b } // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; + } else if(showOnlyMask) { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + continue; } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 24469cead..72cbf781f 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -472,6 +472,7 @@ enum ProcEvent { EvOBPCompens = 442, EvRawImageNum = 443, EvDemosaicPixelshiftMotion = 444, + EvDemosaicPixelshiftMotionMaskOnly = 445, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5da9f05fd..01f3f665b 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -889,10 +889,11 @@ void RAWParams::setDefaults() bayersensor.pixelshiftMotionCorrection = 3; bayersensor.pixelShiftStddevFactor = 5.0; bayersensor.pixelShiftEperIso = 0.75; - bayersensor.pixelShiftNreadIso = 5.0; + bayersensor.pixelShiftNreadIso = 3.45; bayersensor.pixelShiftPrnu = 1.0; bayersensor.pixelshiftShowMotion = false; - bayersensor.pixelShiftAutomatic = false; + bayersensor.pixelshiftShowMotionMaskOnly = false; + bayersensor.pixelShiftAutomatic = true; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3400,6 +3401,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion ); } + if (!pedited || pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly) { + keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotionMaskOnly", raw.bayersensor.pixelshiftShowMotionMaskOnly ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftAutomatic) { keyFile.set_boolean ("RAW Bayer", "pixelShiftAutomatic", raw.bayersensor.pixelShiftAutomatic ); } @@ -7518,6 +7523,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftShowMotionMaskOnly")) { + raw.bayersensor.pixelshiftShowMotionMaskOnly = keyFile.get_boolean("RAW Bayer", "PixelShiftShowMotionMaskOnly"); + + if (pedited) { + pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftAutomatic")) { raw.bayersensor.pixelShiftAutomatic = keyFile.get_boolean("RAW Bayer", "pixelShiftAutomatic"); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 5bd3e4646..80c0af080 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1189,6 +1189,7 @@ public: double pixelShiftNreadIso; double pixelShiftPrnu; bool pixelshiftShowMotion; + bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; bool dcb_enhance; //bool all_enhance; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d3e6b1881..a838b5a0a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1966,7 +1966,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift_simple(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu); + pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 75037710b..3529a28ec 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -263,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift_simple(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 643c9e075..4452ae623 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -471,7 +471,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens DARKFRAME, // EvRawImageNum - DEMOSAIC // EvDemosaicPixelshiftMotion + DEMOSAIC, // EvDemosaicPixelshiftMotion + DEMOSAIC // EvDemosaicPixelshiftMotionMaskOnly }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 63705e472..0878403cf 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -86,6 +86,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); pixelShiftOptions->pack_start(*pixelShiftShowMotion); + pixelShiftShowMotionMaskOnly = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); + pixelShiftOptions->pack_start(*pixelShiftShowMotionMaskOnly); + pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); @@ -180,6 +183,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); + pixelShiftShowMotionMaskOnlyconn = pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true); pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -209,6 +213,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); + pixelShiftShowMotionMaskOnly->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); @@ -232,6 +237,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); + pixelShiftShowMotionMaskOnly->set_active(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); @@ -296,6 +302,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); + pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); int currentRow = method->get_active_row_number(); @@ -324,6 +331,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); + pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = !pixelShiftShowMotionMaskOnly->get_inconsistent(); pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); } } @@ -490,12 +498,32 @@ void BayerProcess::pixelShiftShowMotionChanged () lastDCBen = pixelShiftShowMotion->get_active (); } - + pixelShiftShowMotionMaskOnly->set_sensitive(pixelShiftShowMotion->get_active ()); if (listener) { listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } +void BayerProcess::pixelShiftShowMotionMaskOnlyChanged () +{ + if (batchMode) { + if (pixelShiftShowMotionMaskOnly->get_inconsistent()) { + pixelShiftShowMotionMaskOnly->set_inconsistent (false); + pixelShiftShowMotionMaskOnlyconn.block (true); + pixelShiftShowMotionMaskOnly->set_active (false); + pixelShiftShowMotionMaskOnlyconn.block (false); + } else if (lastDCBen) { + pixelShiftShowMotionMaskOnly->set_inconsistent (true); + } + + lastDCBen = pixelShiftShowMotionMaskOnly->get_active (); + } + + if (listener) { + listener->panelChanged (EvDemosaicPixelshiftMotionMaskOnly, pixelShiftShowMotionMaskOnly->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void BayerProcess::pixelShiftAutomaticChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index b490f8c42..f13a0fb66 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -45,6 +45,7 @@ protected: Adjuster* pixelShiftMotion; Adjuster* pixelShiftMotionCorrection; Gtk::CheckButton* pixelShiftShowMotion; + Gtk::CheckButton* pixelShiftShowMotionMaskOnly; Gtk::CheckButton* pixelShiftAutomatic; Adjuster* pixelShiftStddevFactor; Adjuster* pixelShiftEperIso; @@ -53,7 +54,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftAutomaticconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn; //,allEnhconn; public: BayerProcess (); @@ -68,6 +69,7 @@ public: void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); void pixelShiftShowMotionChanged(); + void pixelShiftShowMotionMaskOnlyChanged(); void pixelShiftAutomaticChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 87dab2311..3859ca1e6 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -377,6 +377,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftNreadIso = v; raw.bayersensor.pixelShiftPrnu = v; raw.bayersensor.pixelshiftShowMotion = v; + raw.bayersensor.pixelshiftShowMotionMaskOnly = v; raw.bayersensor.pixelShiftAutomatic = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; @@ -881,6 +882,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftNreadIso = raw.bayersensor.pixelShiftNreadIso && p.raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso; raw.bayersensor.pixelShiftPrnu = raw.bayersensor.pixelShiftPrnu && p.raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu; raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; + raw.bayersensor.pixelshiftShowMotionMaskOnly = raw.bayersensor.pixelshiftShowMotionMaskOnly && p.raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly; raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; 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; @@ -2322,6 +2324,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion; } + if (raw.bayersensor.pixelshiftShowMotionMaskOnly) { + toEdit.raw.bayersensor.pixelshiftShowMotionMaskOnly = mods.raw.bayersensor.pixelshiftShowMotionMaskOnly; + } + if (raw.bayersensor.pixelShiftAutomatic) { toEdit.raw.bayersensor.pixelShiftAutomatic = mods.raw.bayersensor.pixelShiftAutomatic; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index c116350a8..ae1fae218 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -699,6 +699,7 @@ public: bool pixelShiftNreadIso; bool pixelShiftPrnu; bool pixelshiftShowMotion; + bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; //bool allEnhance; bool greenEq; From 9bcb347a3b30517980c7396e4871ba9f65450b05 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 25 Nov 2016 18:55:11 +0100 Subject: [PATCH 34/83] pixelshift: Fixed a bug in gui --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 215506811..5c40d2019 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -256,7 +256,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; - } else if(showOnlyMask) { + } else if(showMotion && showOnlyMask) { greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; continue; } From ac5bad2de1eb7eedc044c288c81da0b1585a49b4 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 27 Nov 2016 18:42:58 +0100 Subject: [PATCH 35/83] pixelshift: optional red/blue check --- rtdata/languages/default | 1 + rtengine/dfmanager.cc | 6 +- rtengine/ffmanager.cc | 6 +- rtengine/pixelshift.cc | 190 ++++++++++++++++++++++++++----------- rtengine/procparams.cc | 14 ++- rtengine/procparams.h | 1 + rtengine/rawimage.cc | 7 +- rtengine/rawimage.h | 2 +- rtengine/rawimagesource.cc | 68 +++---------- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 30 ++++++ rtgui/bayerprocess.h | 4 +- rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 2 + 14 files changed, 218 insertions(+), 121 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 2137092f2..5fe1a7f30 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1655,6 +1655,7 @@ TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection +TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index ab76ff854..4ef2c3358 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -144,7 +144,7 @@ void dfInfo::updateRawImage() } else { int H = ri->get_height(); int W = ri->get_width(); - ri->compress_image(); + ri->compress_image(0); int rSize = W * ((ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) ? 1 : 3); acc_t **acc = new acc_t*[H]; @@ -164,7 +164,7 @@ void dfInfo::updateRawImage() RawImage* temp = new RawImage(*iName); if( !temp->loadRaw(true)) { - temp->compress_image(); //\ TODO would be better working on original, because is temporary + temp->compress_image(0); //\ TODO would be better working on original, because is temporary nFiles++; if( ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS ) { @@ -204,7 +204,7 @@ void dfInfo::updateRawImage() delete ri; ri = nullptr; } else { - ri->compress_image(); + ri->compress_image(0); } } } diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 7dd9140a1..87ae98905 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -136,7 +136,7 @@ void ffInfo::updateRawImage() } else { int H = ri->get_height(); int W = ri->get_width(); - ri->compress_image(); + ri->compress_image(0); int rSize = W * ((ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) ? 1 : 3); acc_t **acc = new acc_t*[H]; @@ -156,7 +156,7 @@ void ffInfo::updateRawImage() RawImage* temp = new RawImage(*iName); if( !temp->loadRaw(true)) { - temp->compress_image(); //\ TODO would be better working on original, because is temporary + temp->compress_image(0); //\ TODO would be better working on original, because is temporary nFiles++; if( ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS ) { @@ -195,7 +195,7 @@ void ffInfo::updateRawImage() delete ri; ri = nullptr; } else { - ri->compress_image(); + ri->compress_image(0); } } diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 5c40d2019..df183a5e3 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -36,7 +36,7 @@ namespace { -float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between to green samples if(adaptive) { @@ -68,7 +68,7 @@ float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperI using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal) { BENCHFUN @@ -93,7 +93,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det const float scaleGreen = 1.f / scale_mul[1]; eperIso *= (100.f / idata->getISOSpeed()); - eperIso *= scaleGreen; + + float eperIsoGreen = eperIso * scaleGreen; prnu /= 100.f; stddevFactor *= stddevFactor; @@ -104,9 +105,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // For shades of green motion indicators const float blendFactor = (motion == 0.f ? 1.f : 1.f / (1.f - motionThreshold)); -// bool showOnlyMask = showMotion; -// bool checkRedBlue = (gridSize == 5); -// bool checkRedBlue = false; + bool checkNonGreen = true; unsigned int offsX = 0, offsY = 0; // We have to adjust the offsets for the selected subframe we use for areas with motion switch (frame) { @@ -128,6 +127,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det offsY = 0; } + const float thresh = adaptive ? 0.f : motionThreshold; + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif @@ -138,10 +139,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float *nonGreenDest1 = blue[i + offsY]; int j = winx + border - offsX; int c = FC(i, j); + float scaleNonGreen0 = 1.f / scale_mul[0]; + float scaleNonGreen2 = 1.f / scale_mul[2]; + float eperIsoNonGreen0 = eperIso / scale_mul[0]; + float eperIsoNonGreen2 = eperIso / scale_mul[2]; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels std::swap(nonGreenDest0, nonGreenDest1); + std::swap(scaleNonGreen0, scaleNonGreen2); + std::swap(eperIsoNonGreen0, eperIsoNonGreen2); } // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop @@ -152,39 +159,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[2] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[2] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[3] = max(greenDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[3] = max(colourDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); } } @@ -193,6 +200,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 int lastIndex = gridSize - 1; + float korr = 0.f; for(; j < winw - (border + offsX); ++j) { offset ^= 1; // 0 => 1 or 1 => 0 @@ -202,22 +210,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax; if(gridSize == 1) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = greenDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion); + gridMax = colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion); skipNext = !showMotion; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion), - greenDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, stddevFactor, eperIso, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } @@ -226,14 +234,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det lastIndex = lastIndex == gridSize ? 0 : lastIndex; // increase motion detection dependent on brightness - float korr; - float thresh; - if(adaptive) { - korr = 0.f; - thresh = 0; - } else { + if(!adaptive) { korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; - thresh = motionThreshold; } if (gridMax > thresh - korr) { @@ -260,6 +262,86 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; continue; } + + if(adaptive && checkNonGreenHorizontal) { + float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; + float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; + float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; + float diff0 = ng0 - ng1; + float diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { +// float val = std::abs(diff0) > std::abs(diff2) ? ng0 : ng2; + float val = (ng0 + ng2) / 2.f; + float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + if(!showOnlyMask) { + // if showMotion is enabled make the pixel green + nonGreenDest0[j + offsX] = 1000.f + 25000.f; + nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; + } + } + continue; + } + } + ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; + ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; + ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; + diff0 = ng0 - ng1; + diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { +// float val = std::abs(diff0) > std::abs(diff2) ? ng0 : ng2; + float val = (ng0 + ng2) / 2.f; + float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + if(!showOnlyMask) { + nonGreenDest1[j + offsX] = 1000.f + 25000.f; + nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; + } + } + continue; + } + } +// float ngDiff = nonGreenDiff(ng0,ng1,ng2); +// float korr = log2Lut[((int)(riFrames[(offset << 1) + offset]->data[i][j + offset] * scaleNonGreen0))>>1]; +// if(ngDiff > 0.5f - korr) { +// if(showMotion) { +// if(!showOnlyMask) { +// // if showMotion is enabled make the pixel green +// nonGreenDest0[j + offsX] = 1000.f + 25000.f; +// nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; +// } else { +// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; +// } +// } +// continue; +// } +// +// ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; +// ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; +// ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; +// ngDiff = nonGreenDiff(ng0,ng1,ng2); +// korr = log2Lut[((int)(riFrames[2 - offset]->data[i + 1][j - offset + 1] * scaleNonGreen2))>>1]; +// if(ngDiff > 0.5f - korr) { +// if(showMotion) { +// if(!showOnlyMask) { +// // if showMotion is enabled make the pixel green +// nonGreenDest0[j + offsX] = 1000.f + 25000.f; +// nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; +// } else { +// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; +// } +// } +// continue; +// } + } } // if(false && detectMotion && checkRedBlue) { @@ -270,9 +352,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // float diff2 = ng1 - ng2; // float gridMax; // if(diff0 * diff2 > 0.f) { -//// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { -// gridMax = greenDiff(ng1, std::max(ng0, ng2)); -//// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); +//// if(colourDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { +// gridMax = colourDiff(ng1, std::max(ng0, ng2)); +//// gridMax = colourDiff(ng1, ((ng0 + ng2) / 2.f)); // if(gridMax > motionThreshold ) { // float factor = 1.f / (1.f - motionThreshold); // float blend = (gridMax - motionThreshold) * factor; @@ -309,9 +391,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // diff0 = ng1 - ng0; // diff2 = ng1 - ng2; // if(signbit(diff0) == signbit(diff2)) { -//// if(greenDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { -// gridMax = greenDiff(ng1, std::max(ng0, ng2)); -//// gridMax = greenDiff(ng1, ((ng0 + ng2) / 2.f)); +//// if(colourDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { +// gridMax = colourDiff(ng1, std::max(ng0, ng2)); +//// gridMax = colourDiff(ng1, ((ng0 + ng2) / 2.f)); // if(gridMax > motionThreshold ) { // float factor = 1.f / (1.f - motionThreshold); // float blend = (gridMax - motionThreshold) * factor; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 01f3f665b..b8c475be4 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -885,7 +885,7 @@ void RAWParams::setDefaults() bayersensor.dcb_enhance = true; //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; - bayersensor.pixelshiftMotion = 70; + bayersensor.pixelshiftMotion = 0; bayersensor.pixelshiftMotionCorrection = 3; bayersensor.pixelShiftStddevFactor = 5.0; bayersensor.pixelShiftEperIso = 0.75; @@ -894,6 +894,7 @@ void RAWParams::setDefaults() bayersensor.pixelshiftShowMotion = false; bayersensor.pixelshiftShowMotionMaskOnly = false; bayersensor.pixelShiftAutomatic = true; + bayersensor.pixelShiftNonGreenHorizontal = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3409,6 +3410,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftAutomatic", raw.bayersensor.pixelShiftAutomatic ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenHorizontal) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenHorizontal", raw.bayersensor.pixelShiftNonGreenHorizontal ); + } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { @@ -7539,6 +7544,13 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenHorizontal")) { + raw.bayersensor.pixelShiftNonGreenHorizontal = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenHorizontal"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = true; + } + } //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 80c0af080..20fda6c88 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1191,6 +1191,7 @@ public: bool pixelshiftShowMotion; bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; + bool pixelShiftNonGreenHorizontal; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index f4a412ca5..a9ff42de5 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -659,7 +659,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro return 0; } -float** RawImage::compress_image() +float** RawImage::compress_image(int frameNum) { if( !image ) { return nullptr; @@ -667,11 +667,12 @@ float** RawImage::compress_image() if (isBayer() || isXtrans()) { if (!allocation) { - allocation = new float[height * width]; + // shift the beginning of all frames but the first by 32 floats to avoid cache miss conflicts on CPUs which have <= 4-way associative L1-Cache + allocation = new float[height * width + frameNum * 32]; data = new float*[height]; for (int i = 0; i < height; i++) { - data[i] = allocation + i * width; + data[i] = allocation + i * width + frameNum * 32; } } } else if (colors == 1) { diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index cb9e9100e..4644f7dca 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -119,7 +119,7 @@ public: { return image; } - float** compress_image(); // revert to compressed pixels format and release image data + float** compress_image(int frameNum); // revert to compressed pixels format and release image data float** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column unsigned prefilters; // original filters saved ( used for 4 color processing ) unsigned int getFrameCount() const { return is_raw; } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a838b5a0a..44b1221fa 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -37,7 +37,7 @@ #include #endif #include "opthelper.h" -//#define BENCHMARK +#define BENCHMARK #include "StopWatch.h" #define clipretinex( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val ) #undef CLIPD @@ -1521,7 +1521,7 @@ StopWatch Stop1("decode"); { int errCodeThr = 0; #ifdef _OPENMP -#pragma omp for +#pragma omp for nowait #endif for(unsigned int i = 0; i < numFrames; ++i) { if(i == 0) { @@ -1531,7 +1531,7 @@ StopWatch Stop1("decode"); riFrames[i] = new RawImage(fname); errCodeThr = riFrames[i]->loadRaw (true, i); } - riFrames[i]->compress_image(); + riFrames[i]->compress_image(i); } #ifdef _OPENMP #pragma omp critical @@ -1966,7 +1966,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu); + pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.bayersensor.pixelShiftNonGreenHorizontal); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); @@ -3520,64 +3520,24 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw) { - chmax[0] = chmax[1] = chmax[2] = chmax[3] = 0; //channel maxima - float black_lev[4] = {0.f};//black level - - //adjust black level (eg Canon) - bool isMono = false; - - black_lev[0] = raw.bayersensor.black1; //R - black_lev[1] = raw.bayersensor.black0; //G1 - black_lev[2] = raw.bayersensor.black2; //B - black_lev[3] = raw.bayersensor.black3; //G2 - - for(int i = 0; i < 4 ; i++) { - cblacksom[i] = max( c_black[i] + black_lev[i], 0.0f ); // adjust black level - } - - initialGain = calculate_scale_mul(scale_mul, ref_pre_mul, c_white, cblacksom, isMono, ri->get_colors()); // recalculate scale colors with adjusted levels - - //fprintf(stderr, "recalc: %f [%f %f %f %f]\n", initialGain, scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]); - for(int i = 0; i < 4 ; i++) { - clmax[i] = (c_white[i] - cblacksom[i]) * scale_mul[i]; // raw clip level - } - - // this seems strange, but it works + BENCHFUN // scale image colors #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel for schedule(dynamic,64) collapse(2) #endif + for(int frame = 0; frame < 4; ++frame) { + for (int row = winy; row < winy + winh; row ++) { - float tmpchmax[3]; - tmpchmax[0] = tmpchmax[1] = tmpchmax[2] = 0.0f; -#ifdef _OPENMP - #pragma omp for nowait -#endif - - for (int row = winy; row < winy + winh; row ++) - { - for (int col = winx; col < winx + winw; col++) { - int c = FC(row,col); - for(int frame = 0; frame < 4; ++frame) { - float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; - tmpchmax[c] = max(tmpchmax[c], val); - riFrames[frame]->data[row][col] = val; - } - } - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - chmax[0] = max(tmpchmax[0], chmax[0]); - chmax[1] = max(tmpchmax[1], chmax[1]); - chmax[2] = max(tmpchmax[2], chmax[2]); + for (int col = winx; col < winx + winw; col++) { + int c = FC(row,col); + float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; + riFrames[frame]->data[row][col] = val; } } - pixelShiftColoursScaled = true; + } + pixelShiftColoursScaled = true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 3529a28ec..3bf44ad8c 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -263,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 0878403cf..6e9f34549 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -92,6 +92,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); + pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); @@ -185,6 +188,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); pixelShiftShowMotionMaskOnlyconn = pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true); pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); + pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -215,6 +219,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); pixelShiftShowMotionMaskOnly->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); @@ -239,6 +244,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); pixelShiftShowMotionMaskOnly->set_active(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); @@ -304,6 +310,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -333,6 +340,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = !pixelShiftShowMotionMaskOnly->get_inconsistent(); pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); } } @@ -543,6 +551,7 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftNreadIso->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftPrnu->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftStddevFactor->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -550,6 +559,27 @@ void BayerProcess::pixelShiftAutomaticChanged () } +void BayerProcess::pixelShiftNonGreenHorizontalChanged () +{ + if (batchMode) { + if (pixelShiftNonGreenHorizontal->get_inconsistent()) { + pixelShiftNonGreenHorizontal->set_inconsistent (false); + pixelShiftNonGreenHorizontalconn.block (true); + pixelShiftNonGreenHorizontal->set_active (false); + pixelShiftNonGreenHorizontalconn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenHorizontal->set_inconsistent (true); + } + + lastDCBen = pixelShiftNonGreenHorizontal->get_active (); + } + + if (listener) { + listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftNonGreenHorizontal->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + + /*void BayerProcess::allEnhanceChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index f13a0fb66..de1c99cdf 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -47,6 +47,7 @@ protected: Gtk::CheckButton* pixelShiftShowMotion; Gtk::CheckButton* pixelShiftShowMotionMaskOnly; Gtk::CheckButton* pixelShiftAutomatic; + Gtk::CheckButton* pixelShiftNonGreenHorizontal; Adjuster* pixelShiftStddevFactor; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; @@ -54,7 +55,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn; //,allEnhconn; public: BayerProcess (); @@ -71,6 +72,7 @@ public: void pixelShiftShowMotionChanged(); void pixelShiftShowMotionMaskOnlyChanged(); void pixelShiftAutomaticChanged(); + void pixelShiftNonGreenHorizontalChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 3859ca1e6..ad3e11d69 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -379,6 +379,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelshiftShowMotion = v; raw.bayersensor.pixelshiftShowMotionMaskOnly = v; raw.bayersensor.pixelShiftAutomatic = v; + raw.bayersensor.pixelShiftNonGreenHorizontal = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -884,6 +885,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; raw.bayersensor.pixelshiftShowMotionMaskOnly = raw.bayersensor.pixelshiftShowMotionMaskOnly && p.raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly; raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; + raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2332,6 +2334,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftAutomatic = mods.raw.bayersensor.pixelShiftAutomatic; } + if (raw.bayersensor.pixelShiftNonGreenHorizontal) { + toEdit.raw.bayersensor.pixelShiftNonGreenHorizontal = mods.raw.bayersensor.pixelShiftNonGreenHorizontal; + } + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ae1fae218..305c99880 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -701,6 +701,8 @@ public: bool pixelshiftShowMotion; bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; + bool pixelShiftNonGreenHorizontal; + //bool allEnhance; bool greenEq; bool linenoise; From b9fb8cf29294b7711db96097a6982c2c19e30f4f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 27 Nov 2016 19:12:03 +0100 Subject: [PATCH 36/83] pixelshift: Correction for mask-only mode when red/blue detection is enabled --- rtengine/pixelshift.cc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index df183a5e3..186dc8827 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -258,10 +258,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; - } else if(showMotion && showOnlyMask) { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; - continue; } +// } else if(showMotion && showOnlyMask) { +// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; +// continue; +// } if(adaptive && checkNonGreenHorizontal) { float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; @@ -278,10 +279,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float blend = gridMax * blendFactor; if(!showOnlyMask) { // if showMotion is enabled make the pixel green - nonGreenDest0[j + offsX] = 1000.f + 25000.f; + nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } continue; @@ -300,15 +301,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(showMotion) { float blend = gridMax * blendFactor; if(!showOnlyMask) { - nonGreenDest1[j + offsX] = 1000.f + 25000.f; + nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } continue; } } + // float ngDiff = nonGreenDiff(ng0,ng1,ng2); // float korr = log2Lut[((int)(riFrames[(offset << 1) + offset]->data[i][j + offset] * scaleNonGreen0))>>1]; // if(ngDiff > 0.5f - korr) { @@ -422,6 +424,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // } // } // } + + if(showMotion && showOnlyMask) { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + continue; + } + // motion correction disabled or no motion detected => combine the values from the four pixelshift frames greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; From 13bd6752f6652f40523f75bc66d7a40092b9ecf5 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 27 Nov 2016 20:07:02 +0100 Subject: [PATCH 37/83] pixelshift: Fixed a crash caused by division by zero when Show motion was enabled --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 186dc8827..5483afdf3 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -51,7 +51,7 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask - return std::fabs(a - b) / std::max(a, b) + 0.01f; + return std::fabs(a - b) / (std::max(a, b) + 0.01f); } else { return 0.f; } From 8afb267fe9e3f566889b456c67395ff3824d21aa Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 27 Nov 2016 21:55:27 +0100 Subject: [PATCH 38/83] pixelshift: changed behaviour of correction amount, now 0 is 1x1 for green, 1 is 1x2 for green, no changes for other values --- rtengine/pixelshift.cc | 7 ++++--- rtgui/bayerprocess.cc | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 5483afdf3..16757057d 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -80,6 +80,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %f\tnread %f\tprnu %f\n",gridSize, adaptive, stddevFactor, eperIso, nreadIso, prnu); + const bool skip = (gridSize != 1 ? false : true); gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); @@ -157,7 +158,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float greenDifMax[gridSize]; // motion detection checks the grid around the pixel for differences in green channels if(detectMotion || adaptive) { - if(gridSize == 3) { + if(gridSize < 2) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), colourDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), @@ -208,10 +209,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { bool skipNext = false; float gridMax; - if(gridSize == 1) { + if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps gridMax = colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion); - skipNext = !showMotion; + skipNext = skip && !showMotion ; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex greenDifMax[lastIndex] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 6e9f34549..db34ba8f9 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -105,7 +105,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotion->show(); pixelShiftOptions->pack_start(*pixelShiftMotion); - pixelShiftMotionCorrection = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION"), 1, 5, 2, 3)); + pixelShiftMotionCorrection = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION"), 0, 5, 1, 3)); pixelShiftMotionCorrection->setAdjusterListener (this); pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); From 313e770cfe19cf189c13b5b465466391633ba863 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 28 Nov 2016 15:21:45 +0100 Subject: [PATCH 39/83] pixelshift: optional vertical red/blue check --- rtdata/languages/default | 1 + rtengine/pixelshift.cc | 171 +++++++++++-------------------------- rtengine/procparams.cc | 14 +++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 28 ++++++ rtgui/bayerprocess.h | 4 +- rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + 10 files changed, 108 insertions(+), 122 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 5fe1a7f30..f15ee1a38 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1656,6 +1656,7 @@ TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal +TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 16757057d..09a1cb8d0 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -68,7 +68,7 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal, bool checkNonGreenVertical) { BENCHFUN @@ -260,10 +260,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; } -// } else if(showMotion && showOnlyMask) { -// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; -// continue; -// } if(adaptive && checkNonGreenHorizontal) { float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; @@ -272,14 +268,13 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diff0 = ng0 - ng1; float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { -// float val = std::abs(diff0) > std::abs(diff2) ? ng0 : ng2; float val = (ng0 + ng2) / 2.f; float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; if(!showOnlyMask) { - // if showMotion is enabled make the pixel green + // if showMotion is enabled colourize the pixel nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; } else { @@ -289,19 +284,20 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det continue; } } + ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; diff0 = ng0 - ng1; diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { -// float val = std::abs(diff0) > std::abs(diff2) ? ng0 : ng2; float val = (ng0 + ng2) / 2.f; float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; } else { @@ -311,121 +307,58 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det continue; } } + } + if(adaptive && checkNonGreenVertical) { + float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; + float ng0 = riFrames[((offset << 1) + offset)^1]->data[i][j + offset]; + float ng2 = riFrames[((offset << 1) + offset)^1]->data[i+2][j + offset]; -// float ngDiff = nonGreenDiff(ng0,ng1,ng2); -// float korr = log2Lut[((int)(riFrames[(offset << 1) + offset]->data[i][j + offset] * scaleNonGreen0))>>1]; -// if(ngDiff > 0.5f - korr) { -// if(showMotion) { -// if(!showOnlyMask) { -// // if showMotion is enabled make the pixel green -// nonGreenDest0[j + offsX] = 1000.f + 25000.f; -// nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; -// } else { -// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; -// } -// } -// continue; -// } -// -// ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; -// ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; -// ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; -// ngDiff = nonGreenDiff(ng0,ng1,ng2); -// korr = log2Lut[((int)(riFrames[2 - offset]->data[i + 1][j - offset + 1] * scaleNonGreen2))>>1]; -// if(ngDiff > 0.5f - korr) { -// if(showMotion) { -// if(!showOnlyMask) { -// // if showMotion is enabled make the pixel green -// nonGreenDest0[j + offsX] = 1000.f + 25000.f; -// nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; -// } else { -// greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f; -// } -// } -// continue; -// } + float diff0 = ng0 - ng1; + float diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { + float val = (ng0 + ng2) / 2.f; + float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } + } + continue; + } + } + + ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; + ng0 = riFrames[3 - ((offset<<1) + offset)]->data[i - 1][j - offset + 1]; + ng2 = riFrames[3 - ((offset<<1) + offset)]->data[i + 1][j - offset + 1]; + + diff0 = ng0 - ng1; + diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { + float val = (ng0 + ng2) / 2.f; + float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } + } + continue; + } + } } } -// if(false && detectMotion && checkRedBlue) { -// float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; -// float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; -// float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; -// float diff0 = ng1 - ng0; -// float diff2 = ng1 - ng2; -// float gridMax; -// if(diff0 * diff2 > 0.f) { -//// if(colourDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { -// gridMax = colourDiff(ng1, std::max(ng0, ng2)); -//// gridMax = colourDiff(ng1, ((ng0 + ng2) / 2.f)); -// if(gridMax > motionThreshold ) { -// float factor = 1.f / (1.f - motionThreshold); -// float blend = (gridMax - motionThreshold) * factor; -// if(showMotion) { -// // if showMotion is enabled make the pixel green -// greenDest[j + offsX] = nonGreenDest1[j + offsX] = 0.f; -// nonGreenDest0[j + offsX] = 20000.f; -// continue; -//// greenDest[j + offsX+1] = nonGreenDest1[j + offsX+1] = 0.f; -//// nonGreenDest0[j + offsX+1] = 20000.f; -// } -// greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; -// -//// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); -//// nonGreenDest0[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; -// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); -//// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); -// nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; -// -//// nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); -// -//// if(skipNext) { -//// // treat the horizontally next pixel also as motion -//// j++; -//// offset ^= 1; -//// } -// // do not set the motion pixel values. They have already been set by demosaicer or showMotion -// continue; -// } -// } -// ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; -// ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; -// ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; -// diff0 = ng1 - ng0; -// diff2 = ng1 - ng2; -// if(signbit(diff0) == signbit(diff2)) { -//// if(colourDiff(ng1, fabsf(diff0) < fabsf(diff2) ? ng0 : ng2) > motionThreshold ) { -// gridMax = colourDiff(ng1, std::max(ng0, ng2)); -//// gridMax = colourDiff(ng1, ((ng0 + ng2) / 2.f)); -// if(gridMax > motionThreshold ) { -// float factor = 1.f / (1.f - motionThreshold); -// float blend = (gridMax - motionThreshold) * factor; -// if(showMotion) { -// // if showMotion is enabled make the pixel green -// greenDest[j + offsX] = nonGreenDest0[j + offsX] = 0.f; -// nonGreenDest1[j + offsX] = 20000.f; -//// greenDest[j + offsX+1] = nonGreenDest0[j + offsX+1] = 0.f; -//// nonGreenDest1[j + offsX+1] = 20000.f; -//continue; -// } -// greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; -//// greenDest[j + offsX] = intp(blend, greenDest[j + offsX],(riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f); -//// nonGreenDest0[j + offsX] = intp(blend, nonGreenDest0[j + offsX], riFrames[(offset << 1) + offset]->data[i][j + offset]); -// nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; -// -//// nonGreenDest1[j + offsX] = (ng1 + (diff0 < diff2 ? ng0 : ng2)) / 2.f; -// nonGreenDest1[j + offsX] = intp(blend, nonGreenDest1[j + offsX], riFrames[2 - offset]->data[i + 1][j - offset + 1]); -//// if(skipNext) { -//// // treat the horizontally next pixel also as motion -//// j++; -//// offset ^= 1; -//// } -// // do not set the motion pixel values. They have already been set by demosaicer or showMotion -// continue; -// } -// } -// } - if(showMotion && showOnlyMask) { greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; continue; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index b8c475be4..3671b2c71 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -895,6 +895,7 @@ void RAWParams::setDefaults() bayersensor.pixelshiftShowMotionMaskOnly = false; bayersensor.pixelShiftAutomatic = true; bayersensor.pixelShiftNonGreenHorizontal = false; + bayersensor.pixelShiftNonGreenVertical = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3414,6 +3415,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenHorizontal", raw.bayersensor.pixelShiftNonGreenHorizontal ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenVertical) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenVertical", raw.bayersensor.pixelShiftNonGreenVertical ); + } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { @@ -7551,6 +7556,15 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = true; } } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenVertical")) { + raw.bayersensor.pixelShiftNonGreenVertical = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenVertical"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenVertical = true; + } + } + //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 20fda6c88..747afc250 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1192,6 +1192,7 @@ public: bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; + bool pixelShiftNonGreenVertical; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 44b1221fa..35a24085e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1966,7 +1966,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 3bf44ad8c..ce0e75f49 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -263,7 +263,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal, bool checkNonGreenVertical); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index db34ba8f9..87900cead 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -95,6 +95,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenVertical); + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); @@ -189,6 +192,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftShowMotionMaskOnlyconn = pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true); pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); + pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -220,6 +224,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftShowMotionMaskOnly->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); @@ -245,6 +250,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftShowMotionMaskOnly->set_active(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); @@ -311,6 +317,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -341,6 +348,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = !pixelShiftShowMotionMaskOnly->get_inconsistent(); pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); } } @@ -552,6 +560,7 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftPrnu->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftStddevFactor->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -579,6 +588,25 @@ void BayerProcess::pixelShiftNonGreenHorizontalChanged () } } +void BayerProcess::pixelShiftNonGreenVerticalChanged () +{ + if (batchMode) { + if (pixelShiftNonGreenVertical->get_inconsistent()) { + pixelShiftNonGreenVertical->set_inconsistent (false); + pixelShiftNonGreenVerticalconn.block (true); + pixelShiftNonGreenVertical->set_active (false); + pixelShiftNonGreenVerticalconn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenVertical->set_inconsistent (true); + } + + lastDCBen = pixelShiftNonGreenVertical->get_active (); + } + + if (listener) { + listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftNonGreenVertical->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} /*void BayerProcess::allEnhanceChanged () { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index de1c99cdf..68dab3f95 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -48,6 +48,7 @@ protected: Gtk::CheckButton* pixelShiftShowMotionMaskOnly; Gtk::CheckButton* pixelShiftAutomatic; Gtk::CheckButton* pixelShiftNonGreenHorizontal; + Gtk::CheckButton* pixelShiftNonGreenVertical; Adjuster* pixelShiftStddevFactor; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; @@ -55,7 +56,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn; //,allEnhconn; public: BayerProcess (); @@ -73,6 +74,7 @@ public: void pixelShiftShowMotionMaskOnlyChanged(); void pixelShiftAutomaticChanged(); void pixelShiftNonGreenHorizontalChanged(); + void pixelShiftNonGreenVerticalChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ad3e11d69..d7d101f0a 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -380,6 +380,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelshiftShowMotionMaskOnly = v; raw.bayersensor.pixelShiftAutomatic = v; raw.bayersensor.pixelShiftNonGreenHorizontal = v; + raw.bayersensor.pixelShiftNonGreenVertical = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -886,6 +887,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelshiftShowMotionMaskOnly = raw.bayersensor.pixelshiftShowMotionMaskOnly && p.raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly; raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; + raw.bayersensor.pixelShiftNonGreenVertical = raw.bayersensor.pixelShiftNonGreenVertical && p.raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2338,6 +2340,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftNonGreenHorizontal = mods.raw.bayersensor.pixelShiftNonGreenHorizontal; } + if (raw.bayersensor.pixelShiftNonGreenVertical) { + toEdit.raw.bayersensor.pixelShiftNonGreenVertical = mods.raw.bayersensor.pixelShiftNonGreenVertical; + } + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 305c99880..9fe0d6b9b 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -702,6 +702,7 @@ public: bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; + bool pixelShiftNonGreenVertical; //bool allEnhance; bool greenEq; From 6496e34e4bcbb30a3f78df95a473f7d7e8bee9a3 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 28 Nov 2016 21:01:26 +0100 Subject: [PATCH 40/83] pixelshift: switch subframe without need to reload the image; enabled CA-correction --- rtengine/CA_correct_RT.cc | 2 +- rtengine/pixelshift.cc | 102 ++++++++++++++++++------------------- rtengine/rawimagesource.cc | 42 ++++++++++++--- rtengine/rawimagesource.h | 7 +-- 4 files changed, 91 insertions(+), 62 deletions(-) diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 7c28801ae..97450a61a 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -112,7 +112,7 @@ bool LinEqSolve(int nDim, double* pfMatr, double* pfVect, double* pfSolution) using namespace std; using namespace rtengine; -void RawImageSource::CA_correct_RT(const double cared, const double cablue, const double caautostrength) +void RawImageSource::CA_correct_RT(const double cared, const double cablue, const double caautostrength, array2D &rawData) { // multithreaded and partly vectorized by Ingo Weyrich constexpr int ts = 128; diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 09a1cb8d0..abc5e2e0b 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -160,39 +160,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize < 2) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j-2], riFrames[3 - offset]->data[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 1][j-2], riFrames[3 - offset]->data[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 3][j-2], riFrames[3 - offset]->data[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset - 1][j-2], riFrames[2 + offset]->data[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset + 1][j-2], riFrames[2 + offset]->data[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j-2], (*rawDataFrames[3 - offset])[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j-2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j-2], (*rawDataFrames[3 - offset])[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j-2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j-2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff(riFrames[0 + offset]->data[i + offset-2][j - 1], riFrames[2 + offset]->data[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset][j - 1], riFrames[2 + offset]->data[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset+2][j - 1], riFrames[2 + offset]->data[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset][j - 1], riFrames[3 - offset]->data[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 2][j - 1], riFrames[3 - offset]->data[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[2] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j], riFrames[3 - offset]->data[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 3][j], riFrames[3 - offset]->data[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset - 1][j], riFrames[2 + offset]->data[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset + 1][j], riFrames[2 + offset]->data[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); - greenDifMax[3] = max(colourDiff(riFrames[0 + offset]->data[i + offset-2][j + 1], riFrames[2 + offset]->data[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset+2][j + 1], riFrames[2 + offset]->data[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 2][j +- 1], riFrames[3 - offset]->data[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j +- 1], (*rawDataFrames[3 - offset])[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); } } @@ -211,22 +211,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax; if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = colourDiff(riFrames[1 - offset]->data[i - offset + 1][j], riFrames[3 - offset]->data[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion); + gridMax = colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion); skipNext = skip && !showMotion ; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff(riFrames[0 + offset]->data[i + offset][j + 1], riFrames[2 + offset]->data[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset][j + 1], riFrames[3 - offset]->data[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 2][j + 1], riFrames[3 - offset]->data[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff(riFrames[1 - offset]->data[i - offset - 1][j+2], riFrames[3 - offset]->data[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 1][j+2], riFrames[3 - offset]->data[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[1 - offset]->data[i - offset + 3][j+2], riFrames[3 - offset]->data[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset - 1][j+2], riFrames[2 + offset]->data[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff(riFrames[0 + offset]->data[i + offset + 1][j+2], riFrames[2 + offset]->data[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j+2], (*rawDataFrames[3 - offset])[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j+2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j+2], (*rawDataFrames[3 - offset])[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j+2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j+2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } @@ -236,7 +236,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // increase motion detection dependent on brightness if(!adaptive) { - korr = log2Lut[((int)(riFrames[1 - offset]->data[i - offset + 1][j] * scaleGreen))>>1]; + korr = log2Lut[((int)((*rawDataFrames)[1 - offset][i - offset + 1][j] * scaleGreen))>>1]; } if (gridMax > thresh - korr) { @@ -262,9 +262,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } if(adaptive && checkNonGreenHorizontal) { - float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; - float ng0 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)+1]; - float ng2 = riFrames[((offset^1) << 1) + (offset^1)]->data[i][j + (offset^1)-1]; + float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ng0 = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1)+1]; + float ng2 = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1)-1]; float diff0 = ng0 - ng1; float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { @@ -285,9 +285,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } - ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; - ng0 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1) + 2]; - ng2 = riFrames[2 - (offset^1)]->data[i + 1][j - (offset^1)]; + ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ng0 = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1) + 2]; + ng2 = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1)]; diff0 = ng0 - ng1; diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { @@ -309,9 +309,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } if(adaptive && checkNonGreenVertical) { - float ng1 = riFrames[(offset << 1) + offset]->data[i][j + offset]; - float ng0 = riFrames[((offset << 1) + offset)^1]->data[i][j + offset]; - float ng2 = riFrames[((offset << 1) + offset)^1]->data[i+2][j + offset]; + float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ng0 = (*rawDataFrames[((offset << 1) + offset)^1])[i][j + offset]; + float ng2 = (*rawDataFrames[((offset << 1) + offset)^1])[i+2][j + offset]; float diff0 = ng0 - ng1; float diff2 = ng2 - ng1; @@ -333,9 +333,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } - ng1 = riFrames[2 - offset]->data[i + 1][j - offset + 1]; - ng0 = riFrames[3 - ((offset<<1) + offset)]->data[i - 1][j - offset + 1]; - ng2 = riFrames[3 - ((offset<<1) + offset)]->data[i + 1][j - offset + 1]; + ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ng0 = (*rawDataFrames[3 - ((offset<<1) + offset)])[i - 1][j - offset + 1]; + ng2 = (*rawDataFrames[3 - ((offset<<1) + offset)])[i + 1][j - offset + 1]; diff0 = ng0 - ng1; diff2 = ng2 - ng1; @@ -365,9 +365,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } // motion correction disabled or no motion detected => combine the values from the four pixelshift frames - greenDest[j + offsX] = (riFrames[1 - offset]->data[i - offset + 1][j] + riFrames[3 - offset]->data[i + offset][j + 1]) / 2.f; - nonGreenDest0[j + offsX] = riFrames[(offset << 1) + offset]->data[i][j + offset]; - nonGreenDest1[j + offsX] = riFrames[2 - offset]->data[i + 1][j - offset + 1]; + greenDest[j + offsX] = ((*rawDataFrames[1 - offset])[i - offset + 1][j] + (*rawDataFrames[3 - offset])[i + offset][j + 1]) / 2.f; + nonGreenDest0[j + offsX] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + nonGreenDest1[j + offsX] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; } } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 35a24085e..7e725f92a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -479,6 +479,10 @@ RawImageSource::~RawImageSource () delete riFrames[i]; } + for(size_t i = 0; i < numFrames - 1; ++i) { + delete rawDataBuffer[i]; + } + flushRGB(); flushRawData(); @@ -1758,7 +1762,24 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le printf( "Flat Field Correction:%s\n", rif->get_filename().c_str()); } - copyOriginalPixels(raw, ri, rid, rif, rawData); + if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + int bufferNumber = 0; + for(int i=0; i<4; ++i) { + if(i==currFrame) { + copyOriginalPixels(raw, ri, rid, rif, rawData); + rawDataFrames[i] = &rawData; + } else { + if(!rawDataBuffer[bufferNumber]) { + rawDataBuffer[bufferNumber] = new array2D; + } + rawDataFrames[i] = rawDataBuffer[bufferNumber]; + ++bufferNumber; + copyOriginalPixels(raw, riFrames[i], rid, rif, *rawDataFrames[i]); + } + } + } else { + copyOriginalPixels(raw, ri, rid, rif, rawData); + } //FLATFIELD end @@ -1798,10 +1819,12 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } } - - scaleColors( 0, 0, W, H, raw, rawData); //+ + raw parameters for black level(raw.blackxx) - if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] && !pixelShiftColoursScaled) { - scaleColors_pixelshift( 0, 0, W, H, raw); + if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + for(int i=0; i<4; ++i) { + scaleColors( 0, 0, W, H, raw, *rawDataFrames[i]); + } + } else { + scaleColors( 0, 0, W, H, raw, rawData); //+ + raw parameters for black level(raw.blackxx) } // Correct vignetting of lens profile @@ -1916,8 +1939,13 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgressStr ("CA Auto Correction..."); plistener->setProgress (0.0); } - - CA_correct_RT(raw.cared, raw.cablue, 10.0 - raw.caautostrength); + if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + for(int i=0; i<4; ++i) { + CA_correct_RT(raw.cared, raw.cablue, 10.0 - raw.caautostrength, *rawDataFrames[i]); + } + } else { + CA_correct_RT(raw.cared, raw.cablue, 10.0 - raw.caautostrength, rawData); + } } if ( raw.expos != 1 ) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index ce0e75f49..445b531d6 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -71,7 +71,7 @@ protected: bool rgbSourceModified; RawImage* ri; // Copy of raw pixels, NOT corrected for initial gain, blackpoint etc. - RawImage* riFrames[16] = {nullptr}; + RawImage* riFrames[4] = {nullptr}; unsigned int currFrame = 0; unsigned int numFrames = 0; @@ -81,7 +81,8 @@ protected: int threshold; array2D rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column - array2D *rawDataFrames[16] = {nullptr}; + array2D *rawDataFrames[4] = {nullptr}; + array2D *rawDataBuffer[3] = {nullptr}; // the interpolated green plane: array2D green; @@ -218,7 +219,7 @@ protected: inline void interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i); inline void interpolate_row_rb_mul_pp (float* ar, float* ab, float* pg, float* cg, float* ng, int i, float r_mul, float g_mul, float b_mul, int x1, int width, int skip); - void CA_correct_RT (const double cared, const double cablue, const double caautostrength); + void CA_correct_RT (const double cared, const double cablue, const double caautostrength, array2D &rawData); void ddct8x8s(int isgn, float a[8][8]); void processRawWhitepoint (float expos, float preser); // exposure before interpolation From 5231b442c70673439e5e4e4dbc3d0f6cc650df62 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 28 Nov 2016 21:51:51 +0100 Subject: [PATCH 41/83] pixelshift: fix a crash in non-adaptive mode --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index abc5e2e0b..0abdd5524 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -236,7 +236,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // increase motion detection dependent on brightness if(!adaptive) { - korr = log2Lut[((int)((*rawDataFrames)[1 - offset][i - offset + 1][j] * scaleGreen))>>1]; + korr = log2Lut[((int)((*rawDataFrames[1 - offset])[i - offset + 1][j] * scaleGreen))>>1]; } if (gridMax > thresh - korr) { From 2b09ad6ecc65f21482a57a215a04befbe4b114c4 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 28 Nov 2016 23:40:04 +0100 Subject: [PATCH 42/83] pixelshift: fixed another crash --- rtengine/rawimagesource.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 7e725f92a..3ad0d2ed2 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1762,7 +1762,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le printf( "Flat Field Correction:%s\n", rif->get_filename().c_str()); } - if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + if(numFrames == 4) { int bufferNumber = 0; for(int i=0; i<4; ++i) { if(i==currFrame) { @@ -1819,7 +1819,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } } - if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + if(numFrames == 4) { for(int i=0; i<4; ++i) { scaleColors( 0, 0, W, H, raw, *rawDataFrames[i]); } From 389d2ebdddec2a03f7277153ada6f0be3dece593 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 29 Nov 2016 15:22:33 +0100 Subject: [PATCH 43/83] pixelshift: Added support for .badpixels file and raw white point correction --- rtengine/expo_before_b.cc | 2 +- rtengine/pixelshift.cc | 4 ++-- rtengine/rawimagesource.cc | 48 ++++++++++++++------------------------ rtengine/rawimagesource.h | 9 +++---- 4 files changed, 24 insertions(+), 39 deletions(-) diff --git a/rtengine/expo_before_b.cc b/rtengine/expo_before_b.cc index 0854647c5..98fed04f7 100644 --- a/rtengine/expo_before_b.cc +++ b/rtengine/expo_before_b.cc @@ -44,7 +44,7 @@ namespace rtengine extern const Settings* settings; -void RawImageSource::processRawWhitepoint(float expos, float preser) +void RawImageSource::processRawWhitepoint(float expos, float preser, array2D &rawData) { MyTime t1e, t2e; diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 0abdd5524..a8fbd7bcb 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -68,7 +68,7 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal, bool checkNonGreenVertical) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) { BENCHFUN @@ -93,7 +93,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } const float scaleGreen = 1.f / scale_mul[1]; - eperIso *= (100.f / idata->getISOSpeed()); + eperIso *= (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 3ad0d2ed2..deda1fbc8 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -916,7 +916,7 @@ void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementP /* interpolateBadPixelsBayer: correct raw pixels looking at the bitmap * takes into consideration if there are multiple bad pixels in the neighbourhood */ -int RawImageSource::interpolateBadPixelsBayer( PixelsMap &bitmapBads ) +int RawImageSource::interpolateBadPixelsBayer( PixelsMap &bitmapBads, array2D &rawData ) { static const float eps = 1.f; int counter = 0; @@ -1509,7 +1509,6 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) plistener->setProgressStr ("Decoding..."); plistener->setProgress (0.0); } -StopWatch Stop1("decode"); ri = new RawImage(fname); int errCode = ri->loadRaw (false, 0, false); @@ -1548,12 +1547,11 @@ StopWatch Stop1("decode"); if(errCode) { return errCode; } -Stop1.stop(); + if(numFrames > 1 ) { // this disables multi frame support for Fuji S5 until I found a solution to handle different dimensions if(riFrames[0]->get_width() != riFrames[1]->get_width() || riFrames[0]->get_height() != riFrames[1]->get_height()) { numFrames = 1; } - pixelShiftColoursScaled = false; } if (plistener) { @@ -1667,7 +1665,7 @@ Stop1.stop(); initialGain = 1.0 / min(pre_mul[0], pre_mul[1], pre_mul[2]); }*/ - for(unsigned int i=0;i < numFrames; ++i) { + for(unsigned int i = 0;i < numFrames; ++i) { riFrames[i]->set_prefilters(); } @@ -1918,7 +1916,13 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if( totBP ) if ( ri->getSensorType() == ST_BAYER ) { - interpolateBadPixelsBayer( *bitmapBads ); + if(numFrames == 4) { + for(int i = 0; i < 4; ++i) { + interpolateBadPixelsBayer( *bitmapBads, *rawDataFrames[i] ); + } + } else { + interpolateBadPixelsBayer( *bitmapBads, rawData ); + } } else if ( ri->getSensorType() == ST_FUJI_XTRANS ) { interpolateBadPixelsXtrans( *bitmapBads ); } else { @@ -1949,7 +1953,13 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } if ( raw.expos != 1 ) { - processRawWhitepoint(raw.expos, raw.preser); + if(numFrames == 4) { + for(int i = 0; i < 4; ++i) { + processRawWhitepoint(raw.expos, raw.preser, *rawDataFrames[i]); + } + } else { + processRawWhitepoint(raw.expos, raw.preser, rawData); + } } if(prepareDenoise && dirpyrdenoiseExpComp == INFINITY) { @@ -1994,7 +2004,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); + pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); @@ -3546,28 +3556,6 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R } -void RawImageSource::scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw) -{ - BENCHFUN - - // scale image colors - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,64) collapse(2) -#endif - for(int frame = 0; frame < 4; ++frame) { - for (int row = winy; row < winy + winh; row ++) - { - for (int col = winx; col < winx + winw; col++) { - int c = FC(row,col); - float val = (riFrames[frame]->data[row][col] - cblacksom[c]) * scale_mul[c]; - riFrames[frame]->data[row][col] = val; - } - } - } - pixelShiftColoursScaled = true; -} - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% int RawImageSource::defTransform (int tran) diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 445b531d6..2c389a6d9 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -133,8 +133,6 @@ public: void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW); void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData); // raw for cblack - void scaleColors_pixelshift(int winx, int winy, int winw, int winh, const RAWParams &raw); - void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); eSensorType getSensorType () const @@ -207,7 +205,6 @@ public: ri = riFrames[currFrame]; } protected: - bool pixelShiftColoursScaled = false; typedef unsigned short ushort; void processFalseColorCorrection (Imagefloat* i, const int steps); inline void convert_row_to_YIQ (const float* const r, const float* const g, const float* const b, float* Y, float* I, float* Q, const int W); @@ -221,9 +218,9 @@ protected: void CA_correct_RT (const double cared, const double cablue, const double caautostrength, array2D &rawData); void ddct8x8s(int isgn, float a[8][8]); - void processRawWhitepoint (float expos, float preser); // exposure before interpolation + void processRawWhitepoint (float expos, float preser, array2D &rawData); // exposure before interpolation - int interpolateBadPixelsBayer( PixelsMap &bitmapBads ); + int interpolateBadPixelsBayer( PixelsMap &bitmapBads, array2D &rawData ); int interpolateBadPixelsNColours( PixelsMap &bitmapBads, const int colours ); int interpolateBadPixelsXtrans( PixelsMap &bitmapBads ); int findHotDeadPixels( PixelsMap &bpMap, float thresh, bool findHotPixels, bool findDeadPixels ); @@ -264,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool checkNonGreenHorizontal, bool checkNonGreenVertical); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); void hflip (Imagefloat* im); void vflip (Imagefloat* im); From 675b2cc7fc6eeddc0d08c2dd12acc97f7f562605 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 29 Nov 2016 17:01:14 +0100 Subject: [PATCH 44/83] pixelshift: Added support for lcp vignetting correction and green equilibration --- rtengine/green_equil_RT.cc | 17 ++++++++--------- rtengine/rawimagesource.cc | 35 +++++++++++++++++++++++++++++------ rtengine/rawimagesource.h | 2 +- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/rtengine/green_equil_RT.cc b/rtengine/green_equil_RT.cc index a9183509d..8b1136359 100644 --- a/rtengine/green_equil_RT.cc +++ b/rtengine/green_equil_RT.cc @@ -30,12 +30,11 @@ #include "rt_math.h" #include "rawimagesource.h" - namespace rtengine { //void green_equilibrate()//for dcraw implementation -void RawImageSource::green_equilibrate(float thresh) +void RawImageSource::green_equilibrate(float 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 @@ -79,7 +78,7 @@ void RawImageSource::green_equilibrate(float thresh) */ //now smooth the cfa data #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for schedule(dynamic,16) #endif for (int rr = 4; rr < height - 4; rr++) @@ -99,8 +98,8 @@ void RawImageSource::green_equilibrate(float thresh) float d1 = (o1_1 + o1_2 + o1_3 + o1_4) * 0.25f; float d2 = (o2_1 + o2_2 + o2_3 + o2_4) * 0.25f; - 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)) / 6.0; - 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)) / 6.0; + 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)) / 6.f; + 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)) / 6.f; //%%%%%%%%%%%%%%%%%%%%%% //vote1=(checker[rr-2][cc]+checker[rr][cc-2]+checker[rr][cc+2]+checker[rr+2][cc]); @@ -111,10 +110,10 @@ void RawImageSource::green_equilibrate(float thresh) //pixel interpolation float gin = cfa[rr][cc]; - float gse = (cfa[rr + 1][cc + 1]) + 0.5 * (cfa[rr][cc] - cfa[rr + 2][cc + 2]); - float gnw = (cfa[rr - 1][cc - 1]) + 0.5 * (cfa[rr][cc] - cfa[rr - 2][cc - 2]); - float gne = (cfa[rr - 1][cc + 1]) + 0.5 * (cfa[rr][cc] - cfa[rr - 2][cc + 2]); - float gsw = (cfa[rr + 1][cc - 1]) + 0.5 * (cfa[rr][cc] - cfa[rr + 2][cc - 2]); + float gse = (cfa[rr + 1][cc + 1]) + 0.5f * (cfa[rr][cc] - cfa[rr + 2][cc + 2]); + float gnw = (cfa[rr - 1][cc - 1]) + 0.5f * (cfa[rr][cc] - cfa[rr - 2][cc - 2]); + float gne = (cfa[rr - 1][cc + 1]) + 0.5f * (cfa[rr][cc] - cfa[rr - 2][cc + 2]); + float gsw = (cfa[rr + 1][cc - 1]) + 0.5f * (cfa[rr][cc] - cfa[rr + 2][cc - 2]); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index deda1fbc8..ca3090b50 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1832,14 +1832,31 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if (pLCPProf) { // don't check focal length to allow distortion correction for lenses without chip, also pass dummy focal length 1 in case of 0 LCPMapper map(pLCPProf, max(idata->getFocalLen(), 1.0), idata->getFocalLen35mm(), idata->getFocusDist(), idata->getFNumber(), true, false, W, H, coarse, -1); + if(numFrames == 4) { #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for #endif - for (int y = 0; y < H; y++) { - for (int x = 0; x < W; x++) { - if (rawData[y][x] > 0) { - rawData[y][x] *= map.calcVignetteFac(x, y); + for (int y = 0; y < H; y++) { + for (int x = 0; x < W; x++) { + float val = map.calcVignetteFac(x, y); + for(int i = 0; i < 4; ++i) { + if ((*rawDataFrames[i])[y][x] > 0) { + (*rawDataFrames[i])[y][x] *= val; + } + } + } + } + } else { +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H; y++) { + for (int x = 0; x < W; x++) { + if (rawData[y][x] > 0) { + rawData[y][x] *= map.calcVignetteFac(x, y); + } } } } @@ -1910,7 +1927,13 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgress (0.0); } - green_equilibrate(0.01 * (raw.bayersensor.greenthresh)); + if(numFrames == 4) { + for(int i = 0; i < 4; ++i) { + green_equilibrate(0.01 * (raw.bayersensor.greenthresh), *rawDataFrames[i]); + } + } else { + green_equilibrate(0.01 * (raw.bayersensor.greenthresh), rawData); + } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 2c389a6d9..9045f0a6c 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -227,7 +227,7 @@ protected: void cfa_linedn (float linenoiselevel);//Emil's line denoise - void green_equilibrate (float greenthresh);//Emil's green equilibration + void green_equilibrate (float greenthresh, array2D &rawData);//Emil's green equilibration void nodemosaic(bool bw); void eahd_demosaic(); From 1f365425588985453f24a4d2556e15d25bd277fa Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 30 Nov 2016 01:17:50 +0100 Subject: [PATCH 45/83] pixelshift Diversified green and non green motion detection --- rtengine/pixelshift.cc | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index a8fbd7bcb..491ae882b 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -63,6 +63,34 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper } } +float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +{ + // calculate the difference between to green samples + if(adaptive) { + float gDiff = a - b; + gDiff *= eperIso; + gDiff *= gDiff; + float avg = (a + b) / 2.f; + avg *= eperIso; + prnu *= avg; + float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); + float result = gDiff - stddev; + if(!showMotion) { + return result; + } else if(result > 0.f) { // for the motion mask + return std::fabs(a - b) / (std::max(a, b) + 0.01f); + } else { + return 0.f; + } + } else { + float gDiff = std::fabs(a - b); + // add a small epsilon to avoid division by zero + float maxVal = std::max(a, b) + 0.01f; + return gDiff / maxVal; + } +} + + } using namespace std; @@ -269,7 +297,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -292,7 +320,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -317,7 +345,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -341,7 +369,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = colourDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; From 4ba6e7d5f7e6e6990ecf34ab2a909a47c3ef8ef5 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 1 Dec 2016 19:41:38 +0100 Subject: [PATCH 46/83] pixelshift: model specific default values. Caution: you need to press reset buttons for pixelshift adjusters of existing profiles once! --- rtdata/languages/default | 4 +- rtengine/pixelshift.cc | 210 +++++++++++++++++++++++++++++-------- rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 4 +- 5 files changed, 170 insertions(+), 52 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index f15ee1a38..a9359b839 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1645,12 +1645,12 @@ TP_RAW_DCBITERATIONS;Number of DCB iterations TP_RAW_DMETHOD;Method TP_RAW_DMETHOD_PROGRESSBAR;%1 demosaicing... TP_RAW_DMETHOD_PROGRESSBAR_REFINE;Demosaicing refinement... -TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to aid in noise reduction without leading to maze patterns, posterization or a washed-out look. +TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to aid in noise reduction without leading to maze patterns, posterization or a washed-out look.\nPixelshift is for Pentax pixelshift files. It falls back to Amaze for non pixelshift files. TP_RAW_FALSECOLOR;False color suppression steps TP_RAW_HD;Threshold TP_RAW_HD_TOOLTIP;Lower values make hot/dead pixel detection more aggressive, but false positives may lead to artifacts. If you notice any artifacts appearing when enabling the Hot/Dead Pixel Filters, gradually increase the threshold value until they disappear. TP_RAW_IMAGENUM;Sub-image -TP_RAW_IMAGENUM;Some raw files might embed several sub-images (HDR, Pixel-Shift, Dual Sensitivity). Use this button to select the sub-image.\n\nThe last sub-image will be used if you select a value beyond the real sub-image count. +TP_RAW_IMAGENUM_TOOLTIP;Some raw files might embed several sub-images (HDR, Pixel-Shift, Dual Sensitivity). Use this button to select the sub-image.\n\nThe last sub-image will be used if you select a value beyond the real sub-image count. TP_RAW_LABEL;Demosaicing TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 491ae882b..c5254a5dc 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -38,7 +38,7 @@ namespace float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { - // calculate the difference between to green samples + // calculate the difference between two green samples if(adaptive) { float gDiff = a - b; gDiff *= eperIso; @@ -65,7 +65,7 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { - // calculate the difference between to green samples + // calculate the difference between two nongreen samples if(adaptive) { float gDiff = a - b; gDiff *= eperIso; @@ -96,18 +96,117 @@ float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float ep using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) { BENCHFUN + + static const float nReadK3II[] = { 3.4f, // ISO 100 + 3.1f, // ISO 125 + 2.5f, // ISO 160 + 2.5f, // ISO 200 + 2.5f, // ISO 250 + 2.5f, // ISO 320 + 2.3f, // ISO 400 + 2.5f, // ISO 500 + 2.3f, // ISO 640 + 2.3f, // ISO 800 + 2.4f, // ISO 1000 + 2.3f, // ISO 1250 + 1.75f, // ISO 1600 + 1.75f, // ISO 2000 + 1.75f, // ISO 2500 + 1.75f, // ISO 3200 + 1.75f, // ISO 4000 + 1.75f, // ISO 5000 + 1.75f, // ISO 6400 + 1.75f, // ISO 8000 + 1.75f, // ISO 10000 + 1.5f, // ISO 12800 + 1.5f, // ISO 16000 + 1.5f, // ISO 20000 + 1.5f, // ISO 25600 + 1.5f, // ISO 32000 + 1.5f, // ISO 40000 + 1.5f, // ISO 51200 + 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK3II = 0.35f; + + static const float nReadK1[] = { 3.45f, // ISO 100 + 3.15f, // ISO 125 + 3.45f, // ISO 160 + 3.0f, // ISO 200 + 3.0f, // ISO 250 + 3.0f, // ISO 320 + 2.7f, // ISO 400 + 2.7f, // ISO 500 + 2.7f, // ISO 640 + 2.5f, // ISO 800 + 2.5f, // ISO 1000 + 2.5f, // ISO 1250 + 2.4f, // ISO 1600 + 2.4f, // ISO 2000 + 2.4f, // ISO 2500 + 2.4f, // ISO 3200 + 2.4f, // ISO 4000 + 2.4f, // ISO 5000 + 2.4f, // ISO 6400 + 2.4f, // ISO 8000 + 2.4f, // ISO 10000 + 2.4f, // ISO 12800 + 2.4f, // ISO 16000 + 2.4f, // ISO 20000 + 2.4f, // ISO 25600 + 2.4f, // ISO 32000 + 2.4f, // ISO 40000 + 2.4f, // ISO 51200 + 2.4f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK1 = 0.75f; + + static const float nReadK70[] = { 3.0f, // ISO 100 + 3.0f, // ISO 125 + 3.0f, // ISO 160 + 3.0f, // ISO 200 + 3.0f, // ISO 250 + 3.0f, // ISO 320 + 3.0f, // ISO 400 + 3.0f, // ISO 500 + 3.0f, // ISO 640 + 3.0f, // ISO 800 + 3.0f, // ISO 1000 + 3.0f, // ISO 1250 + 3.0f, // ISO 1600 + 3.0f, // ISO 2000 + 3.0f, // ISO 2500 + 3.0f, // ISO 3200 + 3.0f, // ISO 4000 + 3.0f, // ISO 5000 + 3.0f, // ISO 6400 + 3.0f, // ISO 8000 + 3.0f, // ISO 10000 + 3.0f, // ISO 12800 + 3.0f, // ISO 16000 + 3.0f, // ISO 20000 + 3.0f, // ISO 25600 + 3.0f, // ISO 32000 + 3.0f, // ISO 40000 + 3.0f, // ISO 51200 + 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK70 = 0.5f; + if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); plistener->setProgress(0.0); } - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %f\tnread %f\tprnu %f\n",gridSize, adaptive, stddevFactor, eperIso, nreadIso, prnu); const bool skip = (gridSize != 1 ? false : true); gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode @@ -121,18 +220,36 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } const float scaleGreen = 1.f / scale_mul[1]; - eperIso *= (100.f / (rawWpCorrection * idata->getISOSpeed())); + float nRead; + float eperIsoModel; + if(model.find("K-3") != string::npos) { + nRead = nReadK3II[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + eperIsoModel = ePerIsoK3II; + } else if(model.find("K-1") != string::npos) { + nRead = nReadK1[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + eperIsoModel = ePerIsoK1; + } else { + nRead = nReadK70[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + eperIsoModel = ePerIsoK70; + } + nRead *= pow(2.f, nreadIso); + eperIsoModel *= pow(2.f, eperIso); + eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n",gridSize, adaptive, stddevFactor, eperIso, nRead, prnu); + prnu /= 100.f; stddevFactor *= stddevFactor; - nreadIso *= nreadIso; + + + nRead *= nRead; // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); // For shades of green motion indicators - const float blendFactor = (motion == 0.f ? 1.f : 1.f / (1.f - motionThreshold)); + const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); bool checkNonGreen = true; unsigned int offsX = 0, offsY = 0; @@ -188,39 +305,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize < 2) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j-2], (*rawDataFrames[3 - offset])[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j-2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j-2], (*rawDataFrames[3 - offset])[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j-2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j-2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j-2], (*rawDataFrames[3 - offset])[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j-2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j-2], (*rawDataFrames[3 - offset])[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j-2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j-2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j +- 1], (*rawDataFrames[3 - offset])[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j +- 1], (*rawDataFrames[3 - offset])[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); } } @@ -239,22 +356,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax; if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion); + gridMax = colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion); skipNext = skip && !showMotion ; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j+2], (*rawDataFrames[3 - offset])[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j+2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j+2], (*rawDataFrames[3 - offset])[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j+2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j+2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nreadIso, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j+2], (*rawDataFrames[3 - offset])[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j+2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j+2], (*rawDataFrames[3 - offset])[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j+2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j+2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); } @@ -297,7 +414,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -320,7 +437,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -336,6 +453,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } } + if(adaptive && checkNonGreenVertical) { float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ng0 = (*rawDataFrames[((offset << 1) + offset)^1])[i][j + offset]; @@ -345,7 +463,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; @@ -369,7 +487,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diff2 = ng2 - ng1; if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nreadIso, prnu, showMotion); + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index ca3090b50..4199a3023 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2027,7 +2027,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); + pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 9045f0a6c..5cb98cd64 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 87900cead..0781b9b4b 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -130,7 +130,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftStddevFactor->show(); pixelShiftOptions->pack_start(*pixelShiftStddevFactor); - pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), 0.3, 1.0, 0.05, 0.75)); + pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -2.0, 2.0, 0.05, 0.0)); pixelShiftEperIso->setAdjusterListener (this); // pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); @@ -141,7 +141,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftEperIso->show(); pixelShiftOptions->pack_start(*pixelShiftEperIso); - pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), 1.0, 10.0, 0.05, 3.45)); + pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), -2.0, 2.0, 0.05, 0.0)); pixelShiftNreadIso->setAdjusterListener (this); // pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); From 98cd7af963d16219f8311d8624ea2f5b02517a75 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 1 Dec 2016 19:57:15 +0100 Subject: [PATCH 47/83] pixelshift: Set new default values for images without existing pp3 file --- rtengine/procparams.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 3671b2c71..8ca050cec 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -888,8 +888,8 @@ void RAWParams::setDefaults() bayersensor.pixelshiftMotion = 0; bayersensor.pixelshiftMotionCorrection = 3; bayersensor.pixelShiftStddevFactor = 5.0; - bayersensor.pixelShiftEperIso = 0.75; - bayersensor.pixelShiftNreadIso = 3.45; + bayersensor.pixelShiftEperIso = 0.0; + bayersensor.pixelShiftNreadIso = 0.0; bayersensor.pixelShiftPrnu = 1.0; bayersensor.pixelshiftShowMotion = false; bayersensor.pixelshiftShowMotionMaskOnly = false; From b1e7dcbf4ad605ee2c857dd1411023d82111ceaf Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 2 Dec 2016 02:58:09 +0100 Subject: [PATCH 48/83] Updated GUI --- rtdata/languages/default | 11 ++++ rtengine/pixelshift.cc | 4 +- rtengine/procevents.h | 13 ++++- rtengine/procparams.cc | 35 +++++++++---- rtengine/procparams.h | 7 ++- rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtgui/bayerprocess.cc | 100 ++++++++++++++++++++++++------------- rtgui/bayerprocess.h | 5 +- rtgui/paramsedited.cc | 19 ++++--- rtgui/paramsedited.h | 4 +- 11 files changed, 137 insertions(+), 67 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index a9359b839..23a7d5d68 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -676,6 +676,17 @@ HISTORY_MSG_441;Retinex - Gain transmission HISTORY_MSG_442;Retinex - Scale HISTORY_MSG_443;Output Black Point Compensation HISTORY_MSG_444;Raw Sub-Image +HISTORY_MSG_445;EvPixelShiftMotion +HISTORY_MSG_446;EvPixelShiftMotionCorrection +HISTORY_MSG_447;EvPixelShiftStddevFactor +HISTORY_MSG_448;EvPixelShiftEperIso +HISTORY_MSG_449;EvPixelShiftNreadIso +HISTORY_MSG_450;EvPixelShiftPrnu +HISTORY_MSG_451;EvPixelshiftShowMotion +HISTORY_MSG_452;EvPixelshiftShowMotionMaskOnly +HISTORY_MSG_453;EvPixelShiftAutomatic +HISTORY_MSG_454;EvPixelShiftNonGreenHorizontal +HISTORY_MSG_455;EvPixelShiftNonGreenVertical HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index c5254a5dc..63b670ebc 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -96,7 +96,7 @@ float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float ep using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) { BENCHFUN @@ -207,6 +207,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } + int gridSize = (int)gridSize_; + const bool skip = (gridSize != 1 ? false : true); gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 72cbf781f..a82a2d028 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -471,8 +471,17 @@ enum ProcEvent { EvLskal = 441, EvOBPCompens = 442, EvRawImageNum = 443, - EvDemosaicPixelshiftMotion = 444, - EvDemosaicPixelshiftMotionMaskOnly = 445, + EvPixelShiftMotion = 444, + EvPixelShiftMotionCorrection = 445, + EvPixelShiftStddevFactor = 446, + EvPixelShiftEperIso = 447, + EvPixelShiftNreadIso = 448, + EvPixelShiftPrnu = 449, + EvPixelshiftShowMotion = 450, + EvPixelshiftShowMotionMaskOnly = 451, + EvPixelShiftAutomatic = 452, + EvPixelShiftNonGreenHorizontal = 453, + EvPixelShiftNonGreenVertical = 454, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 8ca050cec..57958a6f5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -885,8 +885,8 @@ void RAWParams::setDefaults() bayersensor.dcb_enhance = true; //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; - bayersensor.pixelshiftMotion = 0; - bayersensor.pixelshiftMotionCorrection = 3; + bayersensor.pixelShiftMotion = 0; + bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid5x5; bayersensor.pixelShiftStddevFactor = 5.0; bayersensor.pixelShiftEperIso = 0.0; bayersensor.pixelShiftNreadIso = 0.0; @@ -3375,12 +3375,12 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations ); } - if (!pedited || pedited->raw.bayersensor.pixelshiftMotion) { - keyFile.set_integer ("RAW Bayer", "PixelShiftMotion", raw.bayersensor.pixelshiftMotion ); + if (!pedited || pedited->raw.bayersensor.pixelShiftMotion) { + keyFile.set_integer ("RAW Bayer", "PixelShiftMotion", raw.bayersensor.pixelShiftMotion ); } - if (!pedited || pedited->raw.bayersensor.pixelshiftMotionCorrection) { - keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelshiftMotionCorrection ); + if (!pedited || pedited->raw.bayersensor.pixelShiftMotionCorrection) { + keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelShiftMotionCorrection ); } if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactor) { @@ -7478,18 +7478,18 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } if (keyFile.has_key ("RAW Bayer", "PixelShiftMotion")) { - raw.bayersensor.pixelshiftMotion = keyFile.get_integer("RAW Bayer", "PixelShiftMotion"); + raw.bayersensor.pixelShiftMotion = keyFile.get_integer("RAW Bayer", "PixelShiftMotion"); if (pedited) { - pedited->raw.bayersensor.pixelshiftMotion = true; + pedited->raw.bayersensor.pixelShiftMotion = true; } } if (keyFile.has_key ("RAW Bayer", "PixelShiftMotionCorrection")) { - raw.bayersensor.pixelshiftMotionCorrection = keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrection"); + raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrection"); if (pedited) { - pedited->raw.bayersensor.pixelshiftMotionCorrection = true; + pedited->raw.bayersensor.pixelShiftMotionCorrection = true; } } @@ -8002,8 +8002,21 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.twogreen == other.raw.bayersensor.twogreen && raw.bayersensor.greenthresh == other.raw.bayersensor.greenthresh && raw.bayersensor.linenoise == other.raw.bayersensor.linenoise - && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance && raw.bayersensor.dcb_iterations == other.raw.bayersensor.dcb_iterations + && raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations + && raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion + && raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection + && raw.bayersensor.pixelShiftStddevFactor == other.raw.bayersensor.pixelShiftStddevFactor + && raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso + && raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso + && raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu + && raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion + && raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly + && raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic + && raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal + && raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical + && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance + //&& raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance && raw.xtranssensor.method == other.raw.xtranssensor.method && raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps && raw.xtranssensor.blackred == other.raw.xtranssensor.blackred diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 747afc250..8d3dfc541 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1168,6 +1168,9 @@ public: enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, pixelshift_simple, numMethods }; // This MUST be the last enum + enum ePSMotionCorrection { + Grid1x1, Grid1x2, Grid3x3, Grid5x5 + }; static const char *methodstring[numMethods]; Glib::ustring method; @@ -1182,8 +1185,8 @@ public: int greenthresh; int dcb_iterations; int lmmse_iterations; - int pixelshiftMotion; - int pixelshiftMotionCorrection; + int pixelShiftMotion; + ePSMotionCorrection pixelShiftMotionCorrection; double pixelShiftStddevFactor; double pixelShiftEperIso; double pixelShiftNreadIso; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 4199a3023..6b97eb0b6 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2023,11 +2023,11 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { - if(raw.bayersensor.pixelshiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) { + if(raw.bayersensor.pixelShiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) { amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelshiftMotion > 0, raw.bayersensor.pixelshiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelshiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); + pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 5cb98cd64..a6877f6fd 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, unsigned int gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 0781b9b4b..2d2f2902b 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -108,16 +108,18 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotion->show(); pixelShiftOptions->pack_start(*pixelShiftMotion); - pixelShiftMotionCorrection = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION"), 0, 5, 1, 3)); - pixelShiftMotionCorrection->setAdjusterListener (this); + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); + hb2->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONCORRECTION") + ": ")), Gtk::PACK_SHRINK, 4); + pixelShiftMotionCorrection = Gtk::manage (new MyComboBoxText ()); + pixelShiftMotionCorrection->append_text("1x1"); + pixelShiftMotionCorrection->append_text("1x2"); + pixelShiftMotionCorrection->append_text("3x3"); + pixelShiftMotionCorrection->append_text("5x5"); + pixelShiftMotionCorrection->set_active(0); pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); - - if (pixelShiftMotionCorrection->delay < options.adjusterMaxDelay) { - pixelShiftMotionCorrection->delay = options.adjusterMaxDelay; - } - pixelShiftMotionCorrection->show(); - pixelShiftOptions->pack_start(*pixelShiftMotionCorrection); + hb2->pack_start(*pixelShiftMotionCorrection); + pixelShiftOptions->pack_start(*hb2); pixelShiftStddevFactor = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR"), 2, 8, 0.1, 5)); pixelShiftStddevFactor->setAdjusterListener (this); @@ -186,6 +188,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); + psmcconn = pixelShiftMotionCorrection->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::psMotionCorrectionChanged) ); imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); @@ -203,6 +206,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params methodconn.block (true); dcbEnhconn.block (true); imagenumberconn.block (true); + psmcconn.block (true); //allEnhconn.block (true); method->set_active(procparams::RAWParams::BayerSensor::numMethods); @@ -227,8 +231,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); - pixelShiftMotionCorrection->setEditedState ( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); + pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftStddevFactor->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); @@ -238,7 +241,10 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name } if(!pedited->raw.bayersensor.imageNum) { - imageNumber->set_active(4); + imageNumber->set_active_text(M("GENERAL_UNCHANGED")); + } + if(!pedited->raw.bayersensor.pixelShiftMotionCorrection) { + pixelShiftMotionCorrection->set_active_text(M("GENERAL_UNCHANGED")); } } @@ -253,8 +259,8 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - pixelShiftMotion->setValue (pp->raw.bayersensor.pixelshiftMotion); - pixelShiftMotionCorrection->setValue (pp->raw.bayersensor.pixelshiftMotionCorrection); + pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); + pixelShiftMotionCorrection->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); pixelShiftStddevFactor->setValue (pp->raw.bayersensor.pixelShiftStddevFactor); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); @@ -293,6 +299,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params //lastALLen = pp->raw.bayersensor.all_enhance; methodconn.block (false); + psmcconn.block (false); imagenumberconn.block (false); dcbEnhconn.block (false); //allEnhconn.block (false); @@ -307,8 +314,8 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); - pp->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getIntValue(); - pp->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getIntValue(); + pp->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getIntValue(); + pp->raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)pixelShiftMotionCorrection->get_active_row_number(); pp->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getValue(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); @@ -333,13 +340,13 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe if (pedited) { pedited->raw.bayersensor.ccSteps = ccSteps->getEditedState (); pedited->raw.bayersensor.method = method->get_active_row_number() != procparams::RAWParams::BayerSensor::numMethods; - pedited->raw.bayersensor.imageNum = imageNumber->get_active_row_number() < 4; + pedited->raw.bayersensor.imageNum = imageNumber->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.dcbIterations = dcbIterations->getEditedState (); pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); - pedited->raw.bayersensor.pixelshiftMotion = pixelShiftMotion->getEditedState (); - pedited->raw.bayersensor.pixelshiftMotionCorrection = pixelShiftMotionCorrection->getEditedState (); + pedited->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getEditedState (); + pedited->raw.bayersensor.pixelShiftMotionCorrection = pixelShiftMotionCorrection->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getEditedState (); pedited->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getEditedState (); pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); @@ -356,6 +363,8 @@ void BayerProcess::setBatchMode(bool batchMode) { method->append_text (M("GENERAL_UNCHANGED")); method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name + pixelShiftMotionCorrection->append_text (M("GENERAL_UNCHANGED")); + pixelShiftMotionCorrection->set_active (4); imageNumber->append_text (M("GENERAL_UNCHANGED")); imageNumber->set_active(4); dcbOptions->hide(); @@ -366,7 +375,6 @@ void BayerProcess::setBatchMode(bool batchMode) dcbIterations->showEditedCB (); lmmseIterations->showEditedCB (); pixelShiftMotion->showEditedCB (); - pixelShiftMotionCorrection->showEditedCB (); pixelShiftStddevFactor->showEditedCB (); pixelShiftEperIso->showEditedCB (); pixelShiftNreadIso->showEditedCB (); @@ -377,8 +385,7 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams { dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); - pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelshiftMotion); - pixelShiftMotionCorrection->setDefault( defParams->raw.bayersensor.pixelshiftMotionCorrection); + pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelShiftMotion); pixelShiftStddevFactor->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactor); pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setDefault( defParams->raw.bayersensor.pixelShiftNreadIso); @@ -388,8 +395,7 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams if (pedited) { dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotion ? Edited : UnEdited); - pixelShiftMotionCorrection->setDefaultEditedState( pedited->raw.bayersensor.pixelshiftMotionCorrection ? Edited : UnEdited); + pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftStddevFactor->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); @@ -399,7 +405,6 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams dcbIterations->setDefaultEditedState( Irrelevant ); lmmseIterations->setDefaultEditedState( Irrelevant ); pixelShiftMotion->setDefaultEditedState( Irrelevant ); - pixelShiftMotionCorrection->setDefaultEditedState( Irrelevant ); pixelShiftStddevFactor->setDefaultEditedState( Irrelevant ); pixelShiftEperIso->setDefaultEditedState( Irrelevant ); pixelShiftNreadIso->setDefaultEditedState( Irrelevant ); @@ -418,21 +423,44 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) } else if (a == lmmseIterations) { listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); } else if (a == pixelShiftMotion) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); - } else if (a == pixelShiftMotionCorrection) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + listener->panelChanged (EvPixelShiftMotion, a->getTextValue() ); } else if (a == pixelShiftStddevFactor) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + listener->panelChanged (EvPixelShiftStddevFactor, a->getTextValue() ); } else if (a == pixelShiftEperIso) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + listener->panelChanged (EvPixelShiftEperIso, a->getTextValue() ); } else if (a == pixelShiftNreadIso) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + listener->panelChanged (EvPixelShiftNreadIso, a->getTextValue() ); } else if (a == pixelShiftPrnu) { - listener->panelChanged (EvDemosaicPixelshiftMotion, a->getTextValue() ); + listener->panelChanged (EvPixelShiftPrnu, a->getTextValue() ); } } } +void BayerProcess::psMotionCorrectionChanged () +{ + int curSelection = pixelShiftMotionCorrection->get_active_row_number(); + Glib::ustring sGrid; + switch (curSelection) { + case 0: + sGrid = "1x1"; + break; + case 1: + sGrid = "1x2"; + break; + case 2: + sGrid = "3x3"; + break; + case 3: + default: + sGrid = "5x5"; + break; + } + + if (listener) { + listener->panelChanged (EvPixelShiftMotionCorrection, sGrid); + } +} + void BayerProcess::methodChanged () { int curSelection = method->get_active_row_number(); @@ -516,7 +544,7 @@ void BayerProcess::pixelShiftShowMotionChanged () } pixelShiftShowMotionMaskOnly->set_sensitive(pixelShiftShowMotion->get_active ()); if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPixelshiftShowMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } @@ -536,7 +564,7 @@ void BayerProcess::pixelShiftShowMotionMaskOnlyChanged () } if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotionMaskOnly, pixelShiftShowMotionMaskOnly->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPixelshiftShowMotionMaskOnly, pixelShiftShowMotionMaskOnly->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } @@ -563,7 +591,7 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } @@ -584,7 +612,7 @@ void BayerProcess::pixelShiftNonGreenHorizontalChanged () } if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftNonGreenHorizontal->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPixelShiftNonGreenHorizontal, pixelShiftNonGreenHorizontal->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } @@ -604,7 +632,7 @@ void BayerProcess::pixelShiftNonGreenVerticalChanged () } if (listener) { - listener->panelChanged (EvDemosaicPixelshiftMotion, pixelShiftNonGreenVertical->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPixelShiftNonGreenVertical, pixelShiftNonGreenVertical->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 68dab3f95..a54637f13 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -43,7 +43,7 @@ protected: Adjuster* lmmseIterations; Gtk::VBox *pixelShiftOptions; Adjuster* pixelShiftMotion; - Adjuster* pixelShiftMotionCorrection; + MyComboBoxText* pixelShiftMotionCorrection; Gtk::CheckButton* pixelShiftShowMotion; Gtk::CheckButton* pixelShiftShowMotionMaskOnly; Gtk::CheckButton* pixelShiftAutomatic; @@ -56,7 +56,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn; //,allEnhconn; public: BayerProcess (); @@ -67,6 +67,7 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); void methodChanged (); + void psMotionCorrectionChanged (); void imageNumberChanged (); void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index d7d101f0a..ac0257fa1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -370,8 +370,8 @@ void ParamsEdited::set (bool v) raw.bayersensor.dcbEnhance = v; //raw.bayersensor.allEnhance = v; raw.bayersensor.lmmseIterations = v; - raw.bayersensor.pixelshiftMotion = v; - raw.bayersensor.pixelshiftMotionCorrection = v; + raw.bayersensor.pixelShiftMotion = v; + raw.bayersensor.pixelShiftMotionCorrection = v; raw.bayersensor.pixelShiftStddevFactor = v; raw.bayersensor.pixelShiftEperIso = v; raw.bayersensor.pixelShiftNreadIso = v; @@ -877,8 +877,8 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.dcbEnhance = raw.bayersensor.dcbEnhance && p.raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance; //raw.bayersensor.allEnhance = raw.bayersensor.allEnhance && p.raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance; raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; - raw.bayersensor.pixelshiftMotion = raw.bayersensor.pixelshiftMotion && p.raw.bayersensor.pixelshiftMotion == other.raw.bayersensor.pixelshiftMotion; - raw.bayersensor.pixelshiftMotionCorrection = raw.bayersensor.pixelshiftMotionCorrection && p.raw.bayersensor.pixelshiftMotionCorrection == other.raw.bayersensor.pixelshiftMotionCorrection; + raw.bayersensor.pixelShiftMotion = raw.bayersensor.pixelShiftMotion && p.raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion; + raw.bayersensor.pixelShiftMotionCorrection = raw.bayersensor.pixelShiftMotionCorrection && p.raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection; raw.bayersensor.pixelShiftStddevFactor = raw.bayersensor.pixelShiftStddevFactor && p.raw.bayersensor.pixelShiftStddevFactor == other.raw.bayersensor.pixelShiftStddevFactor; raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; raw.bayersensor.pixelShiftNreadIso = raw.bayersensor.pixelShiftNreadIso && p.raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso; @@ -2300,12 +2300,12 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.lmmse_iterations = mods.raw.bayersensor.lmmse_iterations; } - if (raw.bayersensor.pixelshiftMotion) { - toEdit.raw.bayersensor.pixelshiftMotion = mods.raw.bayersensor.pixelshiftMotion; + if (raw.bayersensor.pixelShiftMotion) { + toEdit.raw.bayersensor.pixelShiftMotion = mods.raw.bayersensor.pixelShiftMotion; } - if (raw.bayersensor.pixelshiftMotionCorrection) { - toEdit.raw.bayersensor.pixelshiftMotionCorrection = mods.raw.bayersensor.pixelshiftMotionCorrection; + if (raw.bayersensor.pixelShiftMotionCorrection) { + toEdit.raw.bayersensor.pixelShiftMotionCorrection = mods.raw.bayersensor.pixelShiftMotionCorrection; } if (raw.bayersensor.pixelShiftStddevFactor) { @@ -2855,6 +2855,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten bool RAWParamsEdited::BayerSensor::isUnchanged() const { return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq + && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactor && pixelShiftEperIso + && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 9fe0d6b9b..4f9979d1f 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -692,8 +692,8 @@ public: bool dcbIterations; bool dcbEnhance; bool lmmseIterations; - bool pixelshiftMotion; - bool pixelshiftMotionCorrection; + bool pixelShiftMotion; + bool pixelShiftMotionCorrection; bool pixelShiftStddevFactor; bool pixelShiftEperIso; bool pixelShiftNreadIso; From 2b7d3fb591dcc4af1be276898e7dde571fc08755 Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 2 Dec 2016 03:09:55 +0100 Subject: [PATCH 49/83] Forgot to update one file, see issue #3489 --- rtengine/refreshmap.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 4452ae623..cfea668c1 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -472,7 +472,18 @@ int refreshmap[rtengine::NUMOFEVENTS] = { OUTPUTPROFILE, // EvOBPCompens DARKFRAME, // EvRawImageNum DEMOSAIC, // EvDemosaicPixelshiftMotion - DEMOSAIC // EvDemosaicPixelshiftMotionMaskOnly + DEMOSAIC, // EvDemosaicPixelshiftMotionMaskOnly + DEMOSAIC, // EvPixelShiftMotion + DEMOSAIC, // EvPixelShiftMotionCorrection + DEMOSAIC, // EvPixelShiftStddevFactor + DEMOSAIC, // EvPixelShiftEperIso + DEMOSAIC, // EvPixelShiftNreadIso + DEMOSAIC, // EvPixelShiftPrnu + DEMOSAIC, // EvPixelshiftShowMotion + DEMOSAIC, // EvPixelshiftShowMotionMaskOnly + DEMOSAIC, // EvPixelShiftAutomatic + DEMOSAIC, // EvPixelShiftNonGreenHorizontal + DEMOSAIC // EvPixelShiftNonGreenVertical }; From 6a437c90b3c33f9e2616c920f4a39bc4aafbd055 Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 2 Dec 2016 03:22:37 +0100 Subject: [PATCH 50/83] Bugfix Too much confidence... never commit w/o building first! Sorry --- rtengine/refreshmap.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index cfea668c1..6aa73c67a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -471,8 +471,6 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens DARKFRAME, // EvRawImageNum - DEMOSAIC, // EvDemosaicPixelshiftMotion - DEMOSAIC, // EvDemosaicPixelshiftMotionMaskOnly DEMOSAIC, // EvPixelShiftMotion DEMOSAIC, // EvPixelShiftMotionCorrection DEMOSAIC, // EvPixelShiftStddevFactor From 27a537aba44b245868f2b2ad62c4276bea185443 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 2 Dec 2016 14:57:14 +0100 Subject: [PATCH 51/83] pixelshift: fixed possible crash bug in 1x1 and 1x2 mode --- rtengine/pixelshift.cc | 129 +++++++++++++++++++++++++++-------------- rtengine/procparams.cc | 4 +- rtgui/bayerprocess.cc | 4 +- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 63b670ebc..301e36dae 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -48,6 +48,7 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = gDiff - stddev; + if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask @@ -75,6 +76,7 @@ float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float ep prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); float result = gDiff - stddev; + if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask @@ -131,7 +133,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det 1.5f, // ISO 40000 1.5f, // ISO 51200 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; + }; static const float ePerIsoK3II = 0.35f; @@ -164,7 +166,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det 2.4f, // ISO 40000 2.4f, // ISO 51200 2.4f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; + }; static const float ePerIsoK1 = 0.75f; @@ -197,7 +199,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det 3.0f, // ISO 40000 3.0f, // ISO 51200 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; + }; static const float ePerIsoK70 = 0.5f; @@ -207,23 +209,40 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } - int gridSize = (int)gridSize_; + const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); + int gridSize = 1; + + switch (gridSize_) { + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: + gridSize = 1; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: + gridSize = 3; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: + gridSize = 5; + } - const bool skip = (gridSize != 1 ? false : true); - gridSize += ((gridSize & 1) == 0 ? 1 : 0); // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - + if(detectMotion && !adaptive) { const float lutStrength = 2.f; log2Lut[0] = 0; - for(int i=2; i < 65536; i+=2) - log2Lut[i>>1] = lutStrength * log2(i) / 100.f; + + for(int i = 2; i < 65536; i += 2) { + log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; + } } + const float scaleGreen = 1.f / scale_mul[1]; float nRead; float eperIsoModel; + if(model.find("K-3") != string::npos) { nRead = nReadK3II[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; eperIsoModel = ePerIsoK3II; @@ -234,27 +253,28 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det nRead = nReadK70[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; eperIsoModel = ePerIsoK70; } - + nRead *= pow(2.f, nreadIso); eperIsoModel *= pow(2.f, eperIso); eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n",gridSize, adaptive, stddevFactor, eperIso, nRead, prnu); + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n", gridSize, adaptive, stddevFactor, eperIso, nRead, prnu); prnu /= 100.f; stddevFactor *= stddevFactor; nRead *= nRead; - + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel float motionThreshold = 1.f - (motion / 100.f); - // For shades of green motion indicators + // For shades of green motion indicators const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); bool checkNonGreen = true; unsigned int offsX = 0, offsY = 0; + // We have to adjust the offsets for the selected subframe we use for areas with motion switch (frame) { case 0: @@ -303,9 +323,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det unsigned int offset = (c & 1); float greenDifMax[gridSize]; + // motion detection checks the grid around the pixel for differences in green channels if(detectMotion || adaptive) { - if(gridSize < 2) { + if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), @@ -317,29 +338,29 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j-2], (*rawDataFrames[3 - offset])[i + offset -2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j-2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j-2], (*rawDataFrames[3 - offset])[i + offset +2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j-2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j-2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset -2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset +2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset-2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset+2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j +- 1], (*rawDataFrames[3 - offset])[i + offset + 1][j+2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); } } @@ -356,6 +377,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { bool skipNext = false; float gridMax; + if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps gridMax = colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion); @@ -366,30 +388,32 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2]); + gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j+2], (*rawDataFrames[3 - offset])[i + offset -2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j+2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j+2], (*rawDataFrames[3 - offset])[i + offset +2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j+2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j+2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), + colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); - gridMax = max(greenDifMax[0],greenDifMax[1],greenDifMax[2],greenDifMax[3],greenDifMax[4]); + gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]); } + // adjust index for next column lastIndex ++; lastIndex = lastIndex == gridSize ? 0 : lastIndex; // increase motion detection dependent on brightness if(!adaptive) { - korr = log2Lut[((int)((*rawDataFrames[1 - offset])[i - offset + 1][j] * scaleGreen))>>1]; + korr = log2Lut[((int)((*rawDataFrames[1 - offset])[i - offset + 1][j] * scaleGreen)) >> 1]; } if (gridMax > thresh - korr) { // at least one of the tested pixels of the grid is detected as motion if(showMotion) { float blend = (gridMax - thresh + korr) * blendFactor; + if(!showOnlyMask) { // if showMotion is enabled make the pixel green greenDest[j + offsX] = 1000.f + 25000.f * blend; @@ -404,22 +428,26 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det j++; offset ^= 1; } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; } if(adaptive && checkNonGreenHorizontal) { float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - float ng0 = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1)+1]; - float ng2 = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1)-1]; + float ng0 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; + float ng2 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float diff0 = ng0 - ng1; float diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; + if(!showOnlyMask) { // if showMotion is enabled colourize the pixel nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; @@ -428,21 +456,25 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } + continue; } } ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - ng0 = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1) + 2]; - ng2 = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1)]; + ng0 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; + ng2 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; diff0 = ng0 - ng1; diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; + if(!showOnlyMask) { // if showMotion is enabled colourize the pixel nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; @@ -451,6 +483,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } + continue; } } @@ -458,17 +491,20 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(adaptive && checkNonGreenVertical) { float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - float ng0 = (*rawDataFrames[((offset << 1) + offset)^1])[i][j + offset]; - float ng2 = (*rawDataFrames[((offset << 1) + offset)^1])[i+2][j + offset]; + float ng0 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; + float ng2 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; float diff0 = ng0 - ng1; float diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; + if(!showOnlyMask) { // if showMotion is enabled colourize the pixel nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; @@ -477,22 +513,26 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } + continue; } } ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - ng0 = (*rawDataFrames[3 - ((offset<<1) + offset)])[i - 1][j - offset + 1]; - ng2 = (*rawDataFrames[3 - ((offset<<1) + offset)])[i + 1][j - offset + 1]; + ng0 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; + ng2 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; diff0 = ng0 - ng1; diff2 = ng2 - ng1; + if(diff0 * diff2 >= 0.f) { float val = (ng0 + ng2) / 2.f; float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + if(gridMax > 0.f) { if(showMotion) { float blend = gridMax * blendFactor; + if(!showOnlyMask) { // if showMotion is enabled colourize the pixel nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; @@ -501,6 +541,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } } + continue; } } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 57958a6f5..66c924fc1 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -886,8 +886,8 @@ void RAWParams::setDefaults() //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; bayersensor.pixelShiftMotion = 0; - bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid5x5; - bayersensor.pixelShiftStddevFactor = 5.0; + bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid1x2; + bayersensor.pixelShiftStddevFactor = 3.0; bayersensor.pixelShiftEperIso = 0.0; bayersensor.pixelShiftNreadIso = 0.0; bayersensor.pixelShiftPrnu = 1.0; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 2d2f2902b..f5e81de75 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -116,12 +116,12 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->append_text("3x3"); pixelShiftMotionCorrection->append_text("5x5"); pixelShiftMotionCorrection->set_active(0); - pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); +// pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); pixelShiftMotionCorrection->show(); hb2->pack_start(*pixelShiftMotionCorrection); pixelShiftOptions->pack_start(*hb2); - pixelShiftStddevFactor = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR"), 2, 8, 0.1, 5)); + pixelShiftStddevFactor = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR"), 2, 8, 0.1, 3)); pixelShiftStddevFactor->setAdjusterListener (this); // pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); From 4820437c469dfff03706099d58728f3ca8fdd6f5 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 2 Dec 2016 22:41:09 +0100 Subject: [PATCH 52/83] pixelshift: added checkbox to test red/blue cross check --- rtdata/languages/default | 2 ++ rtengine/pixelshift.cc | 65 ++++++++++++++++++++++++++++++++++++-- rtengine/procevents.h | 1 + rtengine/procparams.cc | 14 ++++++++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 3 +- rtgui/bayerprocess.cc | 30 ++++++++++++++++++ rtgui/bayerprocess.h | 4 ++- rtgui/paramsedited.cc | 8 ++++- rtgui/paramsedited.h | 1 + 12 files changed, 126 insertions(+), 7 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 23a7d5d68..d10756b2b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -687,6 +687,7 @@ HISTORY_MSG_452;EvPixelshiftShowMotionMaskOnly HISTORY_MSG_453;EvPixelShiftAutomatic HISTORY_MSG_454;EvPixelShiftNonGreenHorizontal HISTORY_MSG_455;EvPixelShiftNonGreenVertical +HISTORY_MSG_456;EvPixelShiftNonGreenCross HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1668,6 +1669,7 @@ TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (ste TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical +TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 301e36dae..06dfb3b70 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -98,7 +98,7 @@ float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float ep using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { BENCHFUN @@ -272,7 +272,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det // For shades of green motion indicators const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); - bool checkNonGreen = true; unsigned int offsX = 0, offsY = 0; // We have to adjust the offsets for the selected subframe we use for areas with motion @@ -433,6 +432,68 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det continue; } + if(adaptive && checkNonGreenCross) { + float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ng0 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; + float ng2 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; + float ng3 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; + float ng4 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; + float diff0 = ng0 - ng1; + float diff2 = ng2 - ng1; + float diff3 = ng3 - ng1; + float diff4 = ng4 - ng1; + if(diff0 * diff2 >= 0.f && diff3 * diff4 >= 0.f && diff0 * diff3 >= 0.f) { + float val = (ng0 + ng2 + ng3 + ng4) / 4.f; + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } + } + + continue; + } + } + + ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ng0 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; + ng2 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; + ng3 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; + ng4 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; + diff0 = ng0 - ng1; + diff2 = ng2 - ng1; + diff3 = ng3 - ng1; + diff4 = ng4 - ng1; + if(diff0 * diff2 >= 0.f && diff3 * diff4 >= 0.f && diff0 * diff3 >= 0.f) { + float val = (ng0 + ng2 + ng3 + ng4) / 4.f; + float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; + + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } + } + + continue; + } + } + } + if(adaptive && checkNonGreenHorizontal) { float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ng0 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index a82a2d028..7d9d41436 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -482,6 +482,7 @@ enum ProcEvent { EvPixelShiftAutomatic = 452, EvPixelShiftNonGreenHorizontal = 453, EvPixelShiftNonGreenVertical = 454, + EvPixelShiftNonGreenCross = 455, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 66c924fc1..86f02f26d 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -896,6 +896,7 @@ void RAWParams::setDefaults() bayersensor.pixelShiftAutomatic = true; bayersensor.pixelShiftNonGreenHorizontal = false; bayersensor.pixelShiftNonGreenVertical = false; + bayersensor.pixelShiftNonGreenCross = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3419,6 +3420,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenVertical", raw.bayersensor.pixelShiftNonGreenVertical ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); + } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { @@ -7565,6 +7570,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross")) { + raw.bayersensor.pixelShiftNonGreenCross = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenCross = true; + } + } + //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } @@ -8015,6 +8028,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic && raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal && raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical + && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance //&& raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance && raw.xtranssensor.method == other.raw.xtranssensor.method diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 8d3dfc541..1b866b09d 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1196,6 +1196,7 @@ public: bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; + bool pixelShiftNonGreenCross; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 6b97eb0b6..6d4f744d1 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2027,7 +2027,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical); + pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index a6877f6fd..df284e8c9 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 6aa73c67a..f0fdcb69f 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -481,7 +481,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelshiftShowMotionMaskOnly DEMOSAIC, // EvPixelShiftAutomatic DEMOSAIC, // EvPixelShiftNonGreenHorizontal - DEMOSAIC // EvPixelShiftNonGreenVertical + DEMOSAIC, // EvPixelShiftNonGreenVertical + DEMOSAIC // EvPixelShiftNonGreenCross }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index f5e81de75..611314fc0 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -92,6 +92,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); + pixelShiftNonGreenCross = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); + pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); @@ -196,6 +199,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); + pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -229,6 +233,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); @@ -257,6 +262,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); @@ -325,6 +331,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -356,6 +363,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); } } @@ -589,6 +597,7 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftStddevFactor->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -636,6 +645,27 @@ void BayerProcess::pixelShiftNonGreenVerticalChanged () } } +void BayerProcess::pixelShiftNonGreenCrossChanged () +{ + if (batchMode) { + if (pixelShiftNonGreenCross->get_inconsistent()) { + pixelShiftNonGreenCross->set_inconsistent (false); + pixelShiftNonGreenCrossconn.block (true); + pixelShiftNonGreenCross->set_active (false); + pixelShiftNonGreenCrossconn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenCross->set_inconsistent (true); + } + + lastDCBen = pixelShiftNonGreenCross->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenCross, pixelShiftNonGreenCross->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + + /*void BayerProcess::allEnhanceChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index a54637f13..136298e80 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -49,6 +49,7 @@ protected: Gtk::CheckButton* pixelShiftAutomatic; Gtk::CheckButton* pixelShiftNonGreenHorizontal; Gtk::CheckButton* pixelShiftNonGreenVertical; + Gtk::CheckButton* pixelShiftNonGreenCross; Adjuster* pixelShiftStddevFactor; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; @@ -56,7 +57,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn; //,allEnhconn; public: BayerProcess (); @@ -76,6 +77,7 @@ public: void pixelShiftAutomaticChanged(); void pixelShiftNonGreenHorizontalChanged(); void pixelShiftNonGreenVerticalChanged(); + void pixelShiftNonGreenCrossChanged(); //void allEnhanceChanged(); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ac0257fa1..f4b41b784 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -381,6 +381,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftAutomatic = v; raw.bayersensor.pixelShiftNonGreenHorizontal = v; raw.bayersensor.pixelShiftNonGreenVertical = v; + raw.bayersensor.pixelShiftNonGreenCross = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -888,6 +889,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; raw.bayersensor.pixelShiftNonGreenVertical = raw.bayersensor.pixelShiftNonGreenVertical && p.raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical; + raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2344,6 +2346,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftNonGreenVertical = mods.raw.bayersensor.pixelShiftNonGreenVertical; } + if (raw.bayersensor.pixelShiftNonGreenCross) { + toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; + } + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; @@ -2857,7 +2863,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactor && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly - && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 4f9979d1f..bf66afd5d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -703,6 +703,7 @@ public: bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; + bool pixelShiftNonGreenCross; //bool allEnhance; bool greenEq; From 4384819eeefe56df91d96c119ed15419301421f6 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 4 Dec 2016 22:35:29 +0100 Subject: [PATCH 53/83] pixelshift: changed red/blue cross check --- rtengine/pixelshift.cc | 89 +++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 06dfb3b70..c5ead46c3 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -2,7 +2,7 @@ // // pentax pixelshift algorithm with motion detection // -// derived from dcrawps (https://github.com/tomtor/dcrawps), but with additional motion correction methods and adapted for RawTherapee data structures +// non adaptive mode is derived from dcrawps (https://github.com/tomtor/dcrawps), but with additional motion correction methods and adapted for RawTherapee data structures // // If motion correction is enabled only the pixels which are not detected as motion are set // That means for a complete image you have to demosaic one of the frames with a bayer demosaicer to fill red, green and blue @@ -92,6 +92,29 @@ float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float ep } } +float nonGreenDiffCross(float a, float b, float c, float d, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +{ + // calculate the difference between two nongreen samples + float hDiff = (a + b) / 2.f - centre; + hDiff *= eperIso; + hDiff *= hDiff; + float vDiff = (c + d) / 2.f - centre; + vDiff *= eperIso; + vDiff *= vDiff; + float avg = (a + b + c + d) / 4.f; + avg *= eperIso; + prnu *= avg; + float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); + float result = std::min(hDiff - stddev, vDiff - stddev); + + if(!showMotion) { + return result; + } else if(result > 0.f) { // for the motion mask + return std::fabs(a - b) / (std::max(a, b) + 0.01f); + } else { + return 0.f; + } +} } @@ -359,7 +382,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) ); } } @@ -438,29 +461,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ng2 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float ng3 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; float ng4 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float diff0 = ng0 - ng1; - float diff2 = ng2 - ng1; - float diff3 = ng3 - ng1; - float diff4 = ng4 - ng1; - if(diff0 * diff2 >= 0.f && diff3 * diff4 >= 0.f && diff0 * diff3 >= 0.f) { - float val = (ng0 + ng2 + ng3 + ng4) / 4.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + float gridMax = nonGreenDiffCross(ng0, ng2, ng3, ng4, ng1, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); - if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } - - continue; } + + continue; } ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; @@ -468,29 +484,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det ng2 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; ng3 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; ng4 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - diff0 = ng0 - ng1; - diff2 = ng2 - ng1; - diff3 = ng3 - ng1; - diff4 = ng4 - ng1; - if(diff0 * diff2 >= 0.f && diff3 * diff4 >= 0.f && diff0 * diff3 >= 0.f) { - float val = (ng0 + ng2 + ng3 + ng4) / 4.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + gridMax = nonGreenDiffCross(ng0, ng2, ng3, ng4, ng1, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); - if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; + if(gridMax > 0.f) { + if(showMotion) { + float blend = gridMax * blendFactor; - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; } - - continue; } + + continue; } } From d498e5f5c5a3be8de1ff13b8bb2badba2bb75995 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 4 Dec 2016 23:59:42 +0100 Subject: [PATCH 54/83] pixelshift: partly fixed wrong colouring of red/blue cross check motion mask. Not good, but better than last one --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index c5ead46c3..2d808bb2e 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -110,7 +110,7 @@ float nonGreenDiffCross(float a, float b, float c, float d, float centre, float if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask - return std::fabs(a - b) / (std::max(a, b) + 0.01f); + return std::sqrt((result / (stddev + result + 0.01f))); //1.f; //std::fabs(a - b) / (std::max(a, b) + 0.01f); } else { return 0.f; } From 49aa9f0c4e1edca645fc3fcc9c72118a409a3114 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Dec 2016 15:34:05 +0100 Subject: [PATCH 55/83] pixelshift: Added new red/blue stddev adjusters for test --- rtdata/languages/default | 8 +- rtengine/pixelshift.cc | 218 ++++++++++++++++++------------------- rtengine/procevents.h | 4 +- rtengine/procparams.cc | 42 +++++-- rtengine/procparams.h | 6 +- rtengine/rawimagesource.cc | 6 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 6 +- rtgui/bayerprocess.cc | 84 ++++++++++---- rtgui/bayerprocess.h | 4 +- rtgui/paramsedited.cc | 22 +++- rtgui/paramsedited.h | 4 +- 12 files changed, 248 insertions(+), 158 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index d10756b2b..af0c0525b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -678,7 +678,7 @@ HISTORY_MSG_443;Output Black Point Compensation HISTORY_MSG_444;Raw Sub-Image HISTORY_MSG_445;EvPixelShiftMotion HISTORY_MSG_446;EvPixelShiftMotionCorrection -HISTORY_MSG_447;EvPixelShiftStddevFactor +HISTORY_MSG_447;EvPixelShiftStddevFactorGreen HISTORY_MSG_448;EvPixelShiftEperIso HISTORY_MSG_449;EvPixelShiftNreadIso HISTORY_MSG_450;EvPixelShiftPrnu @@ -688,6 +688,8 @@ HISTORY_MSG_453;EvPixelShiftAutomatic HISTORY_MSG_454;EvPixelShiftNonGreenHorizontal HISTORY_MSG_455;EvPixelShiftNonGreenVertical HISTORY_MSG_456;EvPixelShiftNonGreenCross +HISTORY_MSG_457;EvPixelShiftStddevFactorRed +HISTORY_MSG_458;EvPixelShiftStddevFactorBlue HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1676,7 +1678,9 @@ TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only -TP_RAW_PIXELSHIFTSTDDEVFACTOR;StdDev factor +TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN;StdDev factor Green +TP_RAW_PIXELSHIFTSTDDEVFACTORRED;StdDev factor Red +TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE;StdDev factor Blue TP_RAW_PIXELSHIFTEPERISO;e per ISO TP_RAW_PIXELSHIFTNREADISO;nRead TP_RAW_PIXELSHIFTPRNU;PRNU (%) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 2d808bb2e..62b47e41b 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -36,7 +36,7 @@ namespace { -float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two green samples if(adaptive) { @@ -64,44 +64,37 @@ float colourDiff(float a, float b, bool adaptive, float stddevFactor, float eper } } -float nonGreenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two nongreen samples - if(adaptive) { - float gDiff = a - b; - gDiff *= eperIso; - gDiff *= gDiff; - float avg = (a + b) / 2.f; - avg *= eperIso; - prnu *= avg; - float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - float result = gDiff - stddev; + float gDiff = a - b; + gDiff *= eperIso; + gDiff *= gDiff; + float avg = (a + b) / 2.f; + avg *= eperIso; + prnu *= avg; + float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); + float result = gDiff - stddev; - if(!showMotion) { - return result; - } else if(result > 0.f) { // for the motion mask - return std::fabs(a - b) / (std::max(a, b) + 0.01f); - } else { - return 0.f; - } + if(!showMotion) { + return result; + } else if(result > 0.f) { // for the motion mask + return std::fabs(a - b) / (std::max(a, b) + 0.01f); } else { - float gDiff = std::fabs(a - b); - // add a small epsilon to avoid division by zero - float maxVal = std::max(a, b) + 0.01f; - return gDiff / maxVal; + return 0.f; } } -float nonGreenDiffCross(float a, float b, float c, float d, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two nongreen samples - float hDiff = (a + b) / 2.f - centre; + float hDiff = (right + left) / 2.f - centre; hDiff *= eperIso; hDiff *= hDiff; - float vDiff = (c + d) / 2.f - centre; + float vDiff = (top + bottom) / 2.f - centre; vDiff *= eperIso; vDiff *= vDiff; - float avg = (a + b + c + d) / 4.f; + float avg = (right + left + top + bottom) / 4.f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); @@ -110,7 +103,7 @@ float nonGreenDiffCross(float a, float b, float c, float d, float centre, float if(!showMotion) { return result; } else if(result > 0.f) { // for the motion mask - return std::sqrt((result / (stddev + result + 0.01f))); //1.f; //std::fabs(a - b) / (std::max(a, b) + 0.01f); + return std::sqrt((result / (stddev + result + 0.01f))); } else { return 0.f; } @@ -121,7 +114,7 @@ float nonGreenDiffCross(float a, float b, float c, float d, float centre, float using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { BENCHFUN @@ -227,7 +220,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det static const float ePerIsoK70 = 0.5f; if (plistener) { - plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple])); + plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); plistener->setProgress(0.0); } @@ -282,10 +275,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactor %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n", gridSize, adaptive, stddevFactor, eperIso, nRead, prnu); + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); prnu /= 100.f; - stddevFactor *= stddevFactor; + stddevFactorGreen *= stddevFactorGreen; + stddevFactorRed *= stddevFactorRed; + stddevFactorBlue *= stddevFactorBlue; nRead *= nRead; @@ -333,12 +328,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float scaleNonGreen2 = 1.f / scale_mul[2]; float eperIsoNonGreen0 = eperIso / scale_mul[0]; float eperIsoNonGreen2 = eperIso / scale_mul[2]; + float stddevFactorNonGreen0 = stddevFactorRed; + float stddevFactorNonGreen2 = stddevFactorBlue; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels std::swap(nonGreenDest0, nonGreenDest1); std::swap(scaleNonGreen0, scaleNonGreen2); std::swap(eperIsoNonGreen0, eperIsoNonGreen2); + std::swap(stddevFactorNonGreen0, stddevFactorNonGreen2); } // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop @@ -350,39 +348,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[0] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[1] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[2] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[2] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[3] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[3] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); } } @@ -402,22 +400,22 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion); + gridMax = greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); skipNext = skip && !showMotion ; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(colourDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion), - colourDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactor, eperIsoGreen, nRead, prnu, showMotion) + greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]); } @@ -456,12 +454,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } if(adaptive && checkNonGreenCross) { - float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - float ng0 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; - float ng2 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; - float ng3 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; - float ng4 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float gridMax = nonGreenDiffCross(ng0, ng2, ng3, ng4, ng1, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; + float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; + float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; + float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; + float gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { @@ -479,12 +477,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det continue; } - ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - ng0 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; - ng2 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; - ng3 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; - ng4 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - gridMax = nonGreenDiffCross(ng0, ng2, ng3, ng4, ng1, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; + ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; + ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; + ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; + gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { @@ -504,15 +502,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } if(adaptive && checkNonGreenHorizontal) { - float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - float ng0 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; - float ng2 = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; - float diff0 = ng0 - ng1; - float diff2 = ng2 - ng1; + float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; + float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; + float diffRight = ngRight - ngCentre; + float diff2 = ngLeft - ngCentre; - if(diff0 * diff2 >= 0.f) { - float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + if(diffRight * diff2 >= 0.f) { + float val = (ngRight + ngLeft) / 2.f; + float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { @@ -531,15 +529,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } - ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - ng0 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; - ng2 = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; - diff0 = ng0 - ng1; - diff2 = ng2 - ng1; + ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; + ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; + diffRight = ngRight - ngCentre; + diff2 = ngLeft - ngCentre; - if(diff0 * diff2 >= 0.f) { - float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + if(diffRight * diff2 >= 0.f) { + float val = (ngRight + ngLeft) / 2.f; + float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { @@ -560,16 +558,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } if(adaptive && checkNonGreenVertical) { - float ng1 = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - float ng0 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; - float ng2 = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; + float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; + float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float diff0 = ng0 - ng1; - float diff2 = ng2 - ng1; + float diffTop = ngTop - ngCentre; + float diffBottom = ngBottom - ngCentre; - if(diff0 * diff2 >= 0.f) { - float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen0, nRead, prnu, showMotion); + if(diffTop * diffBottom >= 0.f) { + float val = (ngTop + ngBottom) / 2.f; + float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { @@ -588,16 +586,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } } - ng1 = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - ng0 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; - ng2 = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; + ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; + ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - diff0 = ng0 - ng1; - diff2 = ng2 - ng1; + diffTop = ngTop - ngCentre; + diffBottom = ngBottom - ngCentre; - if(diff0 * diff2 >= 0.f) { - float val = (ng0 + ng2) / 2.f; - float gridMax = nonGreenDiff(ng1, val, true, stddevFactor, eperIsoNonGreen2, nRead, prnu, showMotion); + if(diffTop * diffBottom >= 0.f) { + float val = (ngTop + ngBottom) / 2.f; + float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { if(showMotion) { diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 7d9d41436..747d60cb4 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -473,7 +473,7 @@ enum ProcEvent { EvRawImageNum = 443, EvPixelShiftMotion = 444, EvPixelShiftMotionCorrection = 445, - EvPixelShiftStddevFactor = 446, + EvPixelShiftStddevFactorGreen = 446, EvPixelShiftEperIso = 447, EvPixelShiftNreadIso = 448, EvPixelShiftPrnu = 449, @@ -483,6 +483,8 @@ enum ProcEvent { EvPixelShiftNonGreenHorizontal = 453, EvPixelShiftNonGreenVertical = 454, EvPixelShiftNonGreenCross = 455, + EvPixelShiftStddevFactorRed = 456, + EvPixelShiftStddevFactorBlue = 457, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 86f02f26d..0a09995fe 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -887,7 +887,9 @@ void RAWParams::setDefaults() bayersensor.lmmse_iterations = 2; bayersensor.pixelShiftMotion = 0; bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid1x2; - bayersensor.pixelShiftStddevFactor = 3.0; + bayersensor.pixelShiftStddevFactorGreen = 3.0; + bayersensor.pixelShiftStddevFactorRed = 3.0; + bayersensor.pixelShiftStddevFactorBlue = 3.0; bayersensor.pixelShiftEperIso = 0.0; bayersensor.pixelShiftNreadIso = 0.0; bayersensor.pixelShiftPrnu = 1.0; @@ -3384,8 +3386,16 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelShiftMotionCorrection ); } - if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactor) { - keyFile.set_double ("RAW Bayer", "PixelShiftStddevFactor", raw.bayersensor.pixelShiftStddevFactor ); + if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactorGreen) { + keyFile.set_double ("RAW Bayer", "pixelShiftStddevFactorGreen", raw.bayersensor.pixelShiftStddevFactorGreen ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactorRed) { + keyFile.set_double ("RAW Bayer", "pixelShiftStddevFactorRed", raw.bayersensor.pixelShiftStddevFactorRed ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactorBlue) { + keyFile.set_double ("RAW Bayer", "pixelShiftStddevFactorBlue", raw.bayersensor.pixelShiftStddevFactorBlue ); } if (!pedited || pedited->raw.bayersensor.pixelShiftEperIso) { @@ -7498,11 +7508,27 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - if (keyFile.has_key ("RAW Bayer", "PixelShiftStddevFactor")) { - raw.bayersensor.pixelShiftStddevFactor = keyFile.get_double("RAW Bayer", "PixelShiftStddevFactor"); + if (keyFile.has_key ("RAW Bayer", "pixelShiftStddevFactorGreen")) { + raw.bayersensor.pixelShiftStddevFactorGreen = keyFile.get_double("RAW Bayer", "pixelShiftStddevFactorGreen"); if (pedited) { - pedited->raw.bayersensor.pixelShiftStddevFactor = true; + pedited->raw.bayersensor.pixelShiftStddevFactorGreen = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftStddevFactorRed")) { + raw.bayersensor.pixelShiftStddevFactorRed = keyFile.get_double("RAW Bayer", "pixelShiftStddevFactorRed"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftStddevFactorRed = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftStddevFactorBlue")) { + raw.bayersensor.pixelShiftStddevFactorBlue = keyFile.get_double("RAW Bayer", "pixelShiftStddevFactorBlue"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftStddevFactorBlue = true; } } @@ -8019,7 +8045,9 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations && raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion && raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection - && raw.bayersensor.pixelShiftStddevFactor == other.raw.bayersensor.pixelShiftStddevFactor + && raw.bayersensor.pixelShiftStddevFactorGreen == other.raw.bayersensor.pixelShiftStddevFactorGreen + && raw.bayersensor.pixelShiftStddevFactorRed == other.raw.bayersensor.pixelShiftStddevFactorRed + && raw.bayersensor.pixelShiftStddevFactorBlue == other.raw.bayersensor.pixelShiftStddevFactorBlue && raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso && raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso && raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 1b866b09d..d38824559 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1165,7 +1165,7 @@ public: public: //enum eMethod{ eahd,hphd,vng4,dcb,amaze,ahd,IGV_noise,fast, //numMethods }; // This MUST be the last enum - enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, pixelshift_simple, + enum eMethod { amaze, igv, lmmse, eahd, hphd, vng4, dcb, ahd, fast, mono, none, pixelshift, numMethods }; // This MUST be the last enum enum ePSMotionCorrection { @@ -1187,7 +1187,9 @@ public: int lmmse_iterations; int pixelShiftMotion; ePSMotionCorrection pixelShiftMotionCorrection; - double pixelShiftStddevFactor; + double pixelShiftStddevFactorGreen; + double pixelShiftStddevFactorRed; + double pixelShiftStddevFactorBlue; double pixelShiftEperIso; double pixelShiftNreadIso; double pixelShiftPrnu; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 6d4f744d1..dab8e342c 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1966,7 +1966,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le plistener->setProgressStr ("CA Auto Correction..."); plistener->setProgress (0.0); } - if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple]) { + if(numFrames == 4 && raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift]) { for(int i=0; i<4; ++i) { CA_correct_RT(raw.cared, raw.cablue, 10.0 - raw.caautostrength, *rawDataFrames[i]); } @@ -2022,12 +2022,12 @@ void RawImageSource::demosaic(const RAWParams &raw) ahd_demosaic (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { amaze_demosaic_RT (0, 0, W, H); - } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift_simple] ) { + } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift] ) { if(raw.bayersensor.pixelShiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) { amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactor, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); + pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index df284e8c9..f80efeacf 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index f0fdcb69f..08e3d2520 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -473,7 +473,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DARKFRAME, // EvRawImageNum DEMOSAIC, // EvPixelShiftMotion DEMOSAIC, // EvPixelShiftMotionCorrection - DEMOSAIC, // EvPixelShiftStddevFactor + DEMOSAIC, // EvPixelShiftStddevFactorGreen DEMOSAIC, // EvPixelShiftEperIso DEMOSAIC, // EvPixelShiftNreadIso DEMOSAIC, // EvPixelShiftPrnu @@ -482,7 +482,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftAutomatic DEMOSAIC, // EvPixelShiftNonGreenHorizontal DEMOSAIC, // EvPixelShiftNonGreenVertical - DEMOSAIC // EvPixelShiftNonGreenCross + DEMOSAIC, // EvPixelShiftNonGreenCross + DEMOSAIC, // EvPixelShiftStddevFactorRed + DEMOSAIC // EvPixelShiftStddevFactorBlue }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 611314fc0..87a433e38 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -124,20 +124,38 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA hb2->pack_start(*pixelShiftMotionCorrection); pixelShiftOptions->pack_start(*hb2); - pixelShiftStddevFactor = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR"), 2, 8, 0.1, 3)); - pixelShiftStddevFactor->setAdjusterListener (this); -// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); + pixelShiftStddevFactorGreen = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN"), 2, 8, 0.1, 3)); + pixelShiftStddevFactorGreen->setAdjusterListener (this); - if (pixelShiftStddevFactor->delay < options.adjusterMaxDelay) { - pixelShiftStddevFactor->delay = options.adjusterMaxDelay; + if (pixelShiftStddevFactorGreen->delay < options.adjusterMaxDelay) { + pixelShiftStddevFactorGreen->delay = options.adjusterMaxDelay; } - pixelShiftStddevFactor->show(); - pixelShiftOptions->pack_start(*pixelShiftStddevFactor); + pixelShiftStddevFactorGreen->show(); + pixelShiftOptions->pack_start(*pixelShiftStddevFactorGreen); + + pixelShiftStddevFactorRed = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORRED"), 1, 8, 0.1, 3)); + pixelShiftStddevFactorRed->setAdjusterListener (this); + + if (pixelShiftStddevFactorRed->delay < options.adjusterMaxDelay) { + pixelShiftStddevFactorRed->delay = options.adjusterMaxDelay; + } + + pixelShiftStddevFactorRed->show(); + pixelShiftOptions->pack_start(*pixelShiftStddevFactorRed); + + pixelShiftStddevFactorBlue = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE"), 1, 8, 0.1, 3)); + pixelShiftStddevFactorBlue->setAdjusterListener (this); + + if (pixelShiftStddevFactorBlue->delay < options.adjusterMaxDelay) { + pixelShiftStddevFactorBlue->delay = options.adjusterMaxDelay; + } + + pixelShiftStddevFactorBlue->show(); + pixelShiftOptions->pack_start(*pixelShiftStddevFactorBlue); pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -2.0, 2.0, 0.05, 0.0)); pixelShiftEperIso->setAdjusterListener (this); -// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { pixelShiftEperIso->delay = options.adjusterMaxDelay; @@ -148,7 +166,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), -2.0, 2.0, 0.05, 0.0)); pixelShiftNreadIso->setAdjusterListener (this); -// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); if (pixelShiftNreadIso->delay < options.adjusterMaxDelay) { pixelShiftNreadIso->delay = options.adjusterMaxDelay; @@ -160,7 +177,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftPrnu = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTPRNU"), 0.3, 2.0, 0.1, 1.0)); pixelShiftPrnu->setAdjusterListener (this); -// pixelShiftStddevFactor->set_tooltip_markup (M("TP_RAW_PIXELSHIFTSTDDEVFACTOR_TOOLTIP")); if (pixelShiftPrnu->delay < options.adjusterMaxDelay) { pixelShiftPrnu->delay = options.adjusterMaxDelay; @@ -237,7 +253,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); - pixelShiftStddevFactor->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); + pixelShiftStddevFactorGreen->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); + pixelShiftStddevFactorRed->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorRed ? Edited : UnEdited); + pixelShiftStddevFactorBlue->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorBlue ? Edited : UnEdited); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); pixelShiftPrnu->setEditedState ( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); @@ -267,7 +285,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); pixelShiftMotionCorrection->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); - pixelShiftStddevFactor->setValue (pp->raw.bayersensor.pixelShiftStddevFactor); + pixelShiftStddevFactorGreen->setValue (pp->raw.bayersensor.pixelShiftStddevFactorGreen); + pixelShiftStddevFactorRed->setValue (pp->raw.bayersensor.pixelShiftStddevFactorRed); + pixelShiftStddevFactorBlue->setValue (pp->raw.bayersensor.pixelShiftStddevFactorBlue); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); @@ -285,7 +305,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } else { lmmseOptions->hide(); } - if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::pixelshift_simple] || + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::pixelshift] || method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { pixelShiftOptions->show(); } else { @@ -322,7 +342,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); pp->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getIntValue(); pp->raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)pixelShiftMotionCorrection->get_active_row_number(); - pp->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getValue(); + pp->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getValue(); + pp->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getValue(); + pp->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getValue(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); @@ -354,7 +376,9 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); pedited->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getEditedState (); pedited->raw.bayersensor.pixelShiftMotionCorrection = pixelShiftMotionCorrection->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->raw.bayersensor.pixelShiftStddevFactor = pixelShiftStddevFactor->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getEditedState (); pedited->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getEditedState (); pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); @@ -383,7 +407,9 @@ void BayerProcess::setBatchMode(bool batchMode) dcbIterations->showEditedCB (); lmmseIterations->showEditedCB (); pixelShiftMotion->showEditedCB (); - pixelShiftStddevFactor->showEditedCB (); + pixelShiftStddevFactorGreen->showEditedCB (); + pixelShiftStddevFactorRed->showEditedCB (); + pixelShiftStddevFactorBlue->showEditedCB (); pixelShiftEperIso->showEditedCB (); pixelShiftNreadIso->showEditedCB (); pixelShiftPrnu->showEditedCB (); @@ -394,7 +420,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelShiftMotion); - pixelShiftStddevFactor->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactor); + pixelShiftStddevFactorGreen->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorGreen); + pixelShiftStddevFactorRed->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorRed); + pixelShiftStddevFactorBlue->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorBlue); pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setDefault( defParams->raw.bayersensor.pixelShiftNreadIso); pixelShiftPrnu->setDefault( defParams->raw.bayersensor.pixelShiftPrnu); @@ -404,7 +432,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); - pixelShiftStddevFactor->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactor ? Edited : UnEdited); + pixelShiftStddevFactorGreen->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); + pixelShiftStddevFactorRed->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorRed ? Edited : UnEdited); + pixelShiftStddevFactorBlue->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorBlue ? Edited : UnEdited); pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); pixelShiftPrnu->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); @@ -413,7 +443,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams dcbIterations->setDefaultEditedState( Irrelevant ); lmmseIterations->setDefaultEditedState( Irrelevant ); pixelShiftMotion->setDefaultEditedState( Irrelevant ); - pixelShiftStddevFactor->setDefaultEditedState( Irrelevant ); + pixelShiftStddevFactorGreen->setDefaultEditedState( Irrelevant ); + pixelShiftStddevFactorRed->setDefaultEditedState( Irrelevant ); + pixelShiftStddevFactorBlue->setDefaultEditedState( Irrelevant ); pixelShiftEperIso->setDefaultEditedState( Irrelevant ); pixelShiftNreadIso->setDefaultEditedState( Irrelevant ); pixelShiftPrnu->setDefaultEditedState( Irrelevant ); @@ -432,8 +464,12 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); } else if (a == pixelShiftMotion) { listener->panelChanged (EvPixelShiftMotion, a->getTextValue() ); - } else if (a == pixelShiftStddevFactor) { - listener->panelChanged (EvPixelShiftStddevFactor, a->getTextValue() ); + } else if (a == pixelShiftStddevFactorGreen) { + listener->panelChanged (EvPixelShiftStddevFactorGreen, a->getTextValue() ); + } else if (a == pixelShiftStddevFactorRed) { + listener->panelChanged (EvPixelShiftStddevFactorRed, a->getTextValue() ); + } else if (a == pixelShiftStddevFactorBlue) { + listener->panelChanged (EvPixelShiftStddevFactorBlue, a->getTextValue() ); } else if (a == pixelShiftEperIso) { listener->panelChanged (EvPixelShiftEperIso, a->getTextValue() ); } else if (a == pixelShiftNreadIso) { @@ -485,7 +521,7 @@ void BayerProcess::methodChanged () lmmseOptions->hide(); } - if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift_simple) { + if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift) { pixelShiftOptions->show(); } else { pixelShiftOptions->hide(); @@ -594,7 +630,9 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftEperIso->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNreadIso->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftPrnu->set_sensitive(pixelShiftAutomatic->get_active ()); - pixelShiftStddevFactor->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftStddevFactorGreen->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftStddevFactorRed->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftStddevFactorBlue->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 136298e80..ca560ad89 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -50,7 +50,9 @@ protected: Gtk::CheckButton* pixelShiftNonGreenHorizontal; Gtk::CheckButton* pixelShiftNonGreenVertical; Gtk::CheckButton* pixelShiftNonGreenCross; - Adjuster* pixelShiftStddevFactor; + Adjuster* pixelShiftStddevFactorGreen; + Adjuster* pixelShiftStddevFactorRed; + Adjuster* pixelShiftStddevFactorBlue; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; Adjuster* pixelShiftPrnu; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index f4b41b784..f433ec639 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -372,7 +372,9 @@ void ParamsEdited::set (bool v) raw.bayersensor.lmmseIterations = v; raw.bayersensor.pixelShiftMotion = v; raw.bayersensor.pixelShiftMotionCorrection = v; - raw.bayersensor.pixelShiftStddevFactor = v; + raw.bayersensor.pixelShiftStddevFactorGreen = v; + raw.bayersensor.pixelShiftStddevFactorRed = v; + raw.bayersensor.pixelShiftStddevFactorBlue = v; raw.bayersensor.pixelShiftEperIso = v; raw.bayersensor.pixelShiftNreadIso = v; raw.bayersensor.pixelShiftPrnu = v; @@ -880,7 +882,9 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; raw.bayersensor.pixelShiftMotion = raw.bayersensor.pixelShiftMotion && p.raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion; raw.bayersensor.pixelShiftMotionCorrection = raw.bayersensor.pixelShiftMotionCorrection && p.raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection; - raw.bayersensor.pixelShiftStddevFactor = raw.bayersensor.pixelShiftStddevFactor && p.raw.bayersensor.pixelShiftStddevFactor == other.raw.bayersensor.pixelShiftStddevFactor; + raw.bayersensor.pixelShiftStddevFactorGreen = raw.bayersensor.pixelShiftStddevFactorGreen && p.raw.bayersensor.pixelShiftStddevFactorGreen == other.raw.bayersensor.pixelShiftStddevFactorGreen; + raw.bayersensor.pixelShiftStddevFactorRed = raw.bayersensor.pixelShiftStddevFactorRed && p.raw.bayersensor.pixelShiftStddevFactorRed == other.raw.bayersensor.pixelShiftStddevFactorRed; + raw.bayersensor.pixelShiftStddevFactorBlue = raw.bayersensor.pixelShiftStddevFactorBlue && p.raw.bayersensor.pixelShiftStddevFactorBlue == other.raw.bayersensor.pixelShiftStddevFactorBlue; raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; raw.bayersensor.pixelShiftNreadIso = raw.bayersensor.pixelShiftNreadIso && p.raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso; raw.bayersensor.pixelShiftPrnu = raw.bayersensor.pixelShiftPrnu && p.raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu; @@ -2310,8 +2314,16 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftMotionCorrection = mods.raw.bayersensor.pixelShiftMotionCorrection; } - if (raw.bayersensor.pixelShiftStddevFactor) { - toEdit.raw.bayersensor.pixelShiftStddevFactor = mods.raw.bayersensor.pixelShiftStddevFactor; + if (raw.bayersensor.pixelShiftStddevFactorGreen) { + toEdit.raw.bayersensor.pixelShiftStddevFactorGreen = mods.raw.bayersensor.pixelShiftStddevFactorGreen; + } + + if (raw.bayersensor.pixelShiftStddevFactorRed) { + toEdit.raw.bayersensor.pixelShiftStddevFactorRed = mods.raw.bayersensor.pixelShiftStddevFactorRed; + } + + if (raw.bayersensor.pixelShiftStddevFactorBlue) { + toEdit.raw.bayersensor.pixelShiftStddevFactorBlue = mods.raw.bayersensor.pixelShiftStddevFactorBlue; } if (raw.bayersensor.pixelShiftEperIso) { @@ -2861,7 +2873,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten bool RAWParamsEdited::BayerSensor::isUnchanged() const { return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq - && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactor && pixelShiftEperIso + && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index bf66afd5d..b4af2ad05 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -694,7 +694,9 @@ public: bool lmmseIterations; bool pixelShiftMotion; bool pixelShiftMotionCorrection; - bool pixelShiftStddevFactor; + bool pixelShiftStddevFactorGreen; + bool pixelShiftStddevFactorRed; + bool pixelShiftStddevFactorBlue; bool pixelShiftEperIso; bool pixelShiftNreadIso; bool pixelShiftPrnu; From 755a43f4ac338a4957448dcf2eb8d1f78a015a03 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Dec 2016 19:17:58 +0100 Subject: [PATCH 56/83] pixelshift: reordered code for better readability, corrected behaviour of green 1x2 motion mask --- rtdata/languages/default | 2 +- rtengine/pixelshift.cc | 59 ++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index af0c0525b..db55dde96 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1674,7 +1674,7 @@ TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used -TP_RAW_PIXELSHIFTMOTIONCORRECTION;Pixelshift motion correction +TP_RAW_PIXELSHIFTMOTIONCORRECTION;Green motion correction size TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 62b47e41b..8774e1cd5 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -87,7 +87,7 @@ float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nr float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { - // calculate the difference between two nongreen samples + // check non green cross float hDiff = (right + left) / 2.f - centre; hDiff *= eperIso; hDiff *= hDiff; @@ -275,7 +275,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f\%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); prnu /= 100.f; stddevFactorGreen *= stddevFactorGreen; @@ -348,39 +348,39 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); - greenDifMax[1] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); greenDifMax[2] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); greenDifMax[3] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); } } @@ -401,21 +401,21 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps gridMax = greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); - skipNext = skip && !showMotion ; + skipNext = skip; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2]); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]); } @@ -446,6 +446,17 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(skipNext) { // treat the horizontally next pixel also as motion j++; + if(showMotion) { + float blend = (gridMax - thresh + korr) * blendFactor; + + if(!showOnlyMask) { + // if showMotion is enabled make the pixel green + greenDest[j + offsX] = 1000.f + 25000.f * blend; + nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; + } else { + greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; + } + } offset ^= 1; } From 98b405368f4a2b0bfcc9daf44dba3f639541a0ac Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Dec 2016 20:39:28 +0100 Subject: [PATCH 57/83] pixelshift: Added green 7x7 correction grid --- rtengine/pixelshift.cc | 68 ++++++++++++++++++++++++++++++++++++++++++ rtengine/procparams.h | 2 +- rtengine/rt_math.h | 6 ++++ rtgui/bayerprocess.cc | 1 + 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 8774e1cd5..d8a683bb3 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -240,6 +240,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: gridSize = 5; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: + gridSize = 7; + break; } // Lookup table for non adaptive (slider) mode @@ -382,7 +387,58 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); + } else if(gridSize == 7) { + // compute maximum of differences for first six columns of 7x7 grid + greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + greenDifMax[2] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + greenDifMax[3] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + greenDifMax[4] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + greenDifMax[5] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); } + } offset ^= 1; // 0 => 1 or 1 => 0 @@ -418,8 +474,20 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) ); gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]); + } else if(gridSize == 7) { + // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex + greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + ); + gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]); } + // adjust index for next column lastIndex ++; lastIndex = lastIndex == gridSize ? 0 : lastIndex; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d38824559..f9d6a60fd 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1169,7 +1169,7 @@ public: numMethods }; // This MUST be the last enum enum ePSMotionCorrection { - Grid1x1, Grid1x2, Grid3x3, Grid5x5 + Grid1x1, Grid1x2, Grid3x3, Grid5x5, Grid7x7 }; static const char *methodstring[numMethods]; diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 5e2f04d05..3abeae843 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -80,6 +80,12 @@ inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, co return max(max(a,b,c),std::max(d,e)); } +template +inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, const _Tp& e, const _Tp& f, const _Tp& g) +{ + return max(max(a,b,c,d),max(e,f,g)); +} + template inline _Tp intp(_Tp a, _Tp b, _Tp c) diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 87a433e38..297a9b65b 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -118,6 +118,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->append_text("1x2"); pixelShiftMotionCorrection->append_text("3x3"); pixelShiftMotionCorrection->append_text("5x5"); + pixelShiftMotionCorrection->append_text("7x7"); pixelShiftMotionCorrection->set_active(0); // pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); pixelShiftMotionCorrection->show(); From 49b5dbd595e3bb0403f7c7f23b0987b6555b545a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 6 Dec 2016 01:42:19 +0100 Subject: [PATCH 58/83] pixelshift: deduped code to paint motion mask --- rtengine/pixelshift.cc | 127 +++++++++-------------------------------- 1 file changed, 26 insertions(+), 101 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index d8a683bb3..b30918e37 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -109,6 +109,19 @@ float nonGreenDiffCross(float right, float left, float top, float bottom, float } } +void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMask, float *maskDest, float *nonMaskDest0, float *nonMaskDest1) +{ + if(showMotion) { + if(!showOnlyMask) { + // if showMotion is enabled colourize the pixel + maskDest[index] = 1000.f + 25000.f * gridMax; + nonMaskDest1[index] = nonMaskDest0[index] = 0.f; + } else { + maskDest[index] = nonMaskDest0[index] = nonMaskDest1[index] = 1000.f + 25000.f * gridMax; + } + } +} + } using namespace std; @@ -119,7 +132,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det BENCHFUN - static const float nReadK3II[] = { 3.4f, // ISO 100 3.1f, // ISO 125 2.5f, // ISO 160 @@ -244,7 +256,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: gridSize = 7; - break; } // Lookup table for non adaptive (slider) mode @@ -349,7 +360,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float greenDifMax[gridSize]; - // motion detection checks the grid around the pixel for differences in green channels + // green channel motion detection checks the grid around the pixel for differences in green channels if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid @@ -499,32 +510,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if (gridMax > thresh - korr) { // at least one of the tested pixels of the grid is detected as motion - if(showMotion) { - float blend = (gridMax - thresh + korr) * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); if(skipNext) { // treat the horizontally next pixel also as motion j++; - if(showMotion) { - float blend = (gridMax - thresh + korr) * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled make the pixel green - greenDest[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); offset ^= 1; } @@ -541,18 +532,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } @@ -564,18 +544,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } @@ -585,25 +554,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float diffRight = ngRight - ngCentre; - float diff2 = ngLeft - ngCentre; + float diffLeft = ngLeft - ngCentre; - if(diffRight * diff2 >= 0.f) { + if(diffRight * diffLeft >= 0.f) { float val = (ngRight + ngLeft) / 2.f; float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } @@ -612,25 +570,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; diffRight = ngRight - ngCentre; - diff2 = ngLeft - ngCentre; + diffLeft = ngLeft - ngCentre; - if(diffRight * diff2 >= 0.f) { + if(diffRight * diffLeft >= 0.f) { float val = (ngRight + ngLeft) / 2.f; float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } @@ -649,18 +596,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest0[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest1[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } @@ -677,18 +613,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); if(gridMax > 0.f) { - if(showMotion) { - float blend = gridMax * blendFactor; - - if(!showOnlyMask) { - // if showMotion is enabled colourize the pixel - nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - nonGreenDest0[j + offsX] = greenDest[j + offsX] = 0.f; - } else { - greenDest[j + offsX] = nonGreenDest0[j + offsX] = nonGreenDest1[j + offsX] = 1000.f + 25000.f * blend; - } - } - + paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } From 9bd874eb8c76cce79ebce96d0a60f9fc9c3279a4 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 6 Dec 2016 22:52:36 +0100 Subject: [PATCH 59/83] pixelshift: simplified and increased readability of code --- rtengine/pixelshift.cc | 117 +++++++++++++++++++++-------------------- rtengine/rt_math.h | 13 ----- 2 files changed, 59 insertions(+), 71 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index b30918e37..e3ababc85 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -275,14 +275,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float nRead; float eperIsoModel; + int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); if(model.find("K-3") != string::npos) { - nRead = nReadK3II[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + nRead = nReadK3II[nReadIndex]; eperIsoModel = ePerIsoK3II; } else if(model.find("K-1") != string::npos) { - nRead = nReadK1[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + nRead = nReadK1[nReadIndex]; eperIsoModel = ePerIsoK1; } else { - nRead = nReadK70[static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f))]; + nRead = nReadK70[nReadIndex]; eperIsoModel = ePerIsoK70; } @@ -364,90 +365,90 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); + }); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[2] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[3] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); + }); } else if(gridSize == 7) { // compute maximum of differences for first six columns of 7x7 grid - greenDifMax[0] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[1] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[2] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[3] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[4] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - greenDifMax[5] = max(greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); + }); } } @@ -471,31 +472,31 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det skipNext = skip; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2]); + }); + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]); + }); + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex - greenDifMax[lastIndex] = max(greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - ); - gridMax = max(greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]); + }); + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } @@ -529,10 +530,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } @@ -541,10 +542,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - gridMax = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } @@ -557,11 +558,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diffLeft = ngLeft - ngCentre; if(diffRight * diffLeft >= 0.f) { - float val = (ngRight + ngLeft) / 2.f; - float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + float avg = (ngRight + ngLeft) / 2.f; + float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } @@ -573,11 +574,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diffLeft = ngLeft - ngCentre; if(diffRight * diffLeft >= 0.f) { - float val = (ngRight + ngLeft) / 2.f; - float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + float avg = (ngRight + ngLeft) / 2.f; + float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } @@ -592,11 +593,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float diffBottom = ngBottom - ngCentre; if(diffTop * diffBottom >= 0.f) { - float val = (ngTop + ngBottom) / 2.f; - float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + float avg = (ngTop + ngBottom) / 2.f; + float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); continue; } } @@ -609,11 +610,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det diffBottom = ngBottom - ngCentre; if(diffTop * diffBottom >= 0.f) { - float val = (ngTop + ngBottom) / 2.f; - float gridMax = nonGreenDiff(ngCentre, val, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + float avg = (ngTop + ngBottom) / 2.f; + float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - if(gridMax > 0.f) { - paintMotionMask(j + offsX, showMotion, gridMax, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; } } diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 3abeae843..67d883080 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -74,19 +74,6 @@ inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d) return std::max(d, std::max(c, std::max(a, b))); } -template -inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, const _Tp& e) -{ - return max(max(a,b,c),std::max(d,e)); -} - -template -inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d, const _Tp& e, const _Tp& f, const _Tp& g) -{ - return max(max(a,b,c,d),max(e,f,g)); -} - - template inline _Tp intp(_Tp a, _Tp b, _Tp c) { From 3870f6d35d0d4098d232edae42412354cf9f2144 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 15 Dec 2016 18:45:34 +0100 Subject: [PATCH 60/83] pixelshift: Simplified code and added 2 checkboxes --- rtdata/languages/default | 4 + rtengine/pixelshift.cc | 857 ++++++++++++++++++++++++++++++++----- rtengine/procevents.h | 2 + rtengine/procparams.cc | 29 +- rtengine/procparams.h | 2 + rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 4 +- rtgui/bayerprocess.cc | 67 ++- rtgui/bayerprocess.h | 10 +- rtgui/paramsedited.cc | 15 +- rtgui/paramsedited.h | 2 + 12 files changed, 875 insertions(+), 121 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index db55dde96..a6ec3c098 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -690,6 +690,8 @@ HISTORY_MSG_455;EvPixelShiftNonGreenVertical HISTORY_MSG_456;EvPixelShiftNonGreenCross HISTORY_MSG_457;EvPixelShiftStddevFactorRed HISTORY_MSG_458;EvPixelShiftStddevFactorBlue +HISTORY_MSG_459;EvPixelShiftNonGreenCross2 +HISTORY_MSG_460;EvPixelShiftNonGreenAmaze HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1672,6 +1674,8 @@ TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross +TP_RAW_PIXELSHIFTNONGREENCROSS2;Check red/blue experimental +TP_RAW_PIXELSHIFTNONGREENAMAZE;Check red/blue amaze TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Green motion correction size diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index e3ababc85..ebb9d2c64 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -126,7 +126,7 @@ void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMas using namespace std; using namespace rtengine; - +#ifdef __OLDPS__ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { @@ -276,6 +276,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoModel; int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); + if(model.find("K-3") != string::npos) { nRead = nReadK3II[nReadIndex]; eperIsoModel = ePerIsoK3II; @@ -347,9 +348,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoNonGreen2 = eperIso / scale_mul[2]; float stddevFactorNonGreen0 = stddevFactorRed; float stddevFactorNonGreen2 = stddevFactorBlue; + bool blueRow = false; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels + blueRow = true; std::swap(nonGreenDest0, nonGreenDest1); std::swap(scaleNonGreen0, scaleNonGreen2); std::swap(eperIsoNonGreen0, eperIsoNonGreen2); @@ -366,89 +369,89 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } else if(gridSize == 7) { // compute maximum of differences for first six columns of 7x7 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } } @@ -473,29 +476,29 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } @@ -528,29 +531,102 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; - float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; - float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + float diffRight = ngRight - ngCentre; + float diffLeft = ngLeft - ngCentre; + float diffHorNg0 = -1.f; - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); - continue; + if(diffRight * diffLeft >= 0.f) { + float avg = (ngRight + ngLeft) / 2.f; + diffHorNg0 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + +// if(diff > 0.f) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } } + float diffHorNg1 = -1.f; ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; - ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; - ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + diffRight = ngRight - ngCentre; + diffLeft = ngLeft - ngCentre; - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); - continue; + if(diffRight * diffLeft >= 0.f) { + float avg = (ngRight + ngLeft) / 2.f; + float diffHorNg1 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + +// if(diff > 0.f) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); +// continue; +// } } + + if( diffHorNg0 * diffHorNg1 < 0.f) { + paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + continue; + + } + +// bool motion = false; +// float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; +// float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; +// float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; +// float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; +// float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; +// float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); +// +// if(diff > 0.f) { +// motion = true; +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } +// +// ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; +// ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; +// ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; +// ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; +// ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; +// diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); +// +//// if(diff > 0.f) { +// if((diff > 0.f && !motion) || (diff <= 0.f && motion) ) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); +// continue; +// } } if(adaptive && checkNonGreenHorizontal) { +// float lg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j - 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j]) / 2.f; +// float cg = ((*rawDataFrames[1 - offset])[i - offset + 1][j] + (*rawDataFrames[3 - offset])[i + offset][j + 1]) / 2.f; +// float rg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j + 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j + 2]) / 2.f; +// +// float lr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) - 1]; +// float cr = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; +// float rr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) + 1]; +// +// float lb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1)]; +// float cb = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; +// float rb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1) + 2]; +// +// if(blueRow) { +// std::swap(lr, lb); +// std::swap(cr, cb); +// std::swap(rr, rb); +// } +// +// float lh = Color::rgb2h(lr, lg, lb); +// float ch = Color::rgb2h(cr, cg, cb); +// float rh = Color::rgb2h(rr, rg, rb); +// +// float lHueDiff = lh - ch; +// float rHueDiff = rh - ch; +// if(lHueDiff * rHueDiff > 0.f) { +// if(std::fabs(lHueDiff) > 0.5f && std::fabs(rHueDiff) > 0.5f/* && std::fabs(lHueDiff) < 3.f && std::fabs(rHueDiff) < 3.f*/) { +// paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } +// } float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; @@ -637,3 +713,592 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det plistener->setProgress(1.0); } } +#else +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross, bool checkNonGreenAmaze, bool checkNonGreenCross2) +{ + + BENCHFUN + + static const float nReadK3II[] = { 3.4f, // ISO 100 + 3.1f, // ISO 125 + 2.5f, // ISO 160 + 2.5f, // ISO 200 + 2.5f, // ISO 250 + 2.5f, // ISO 320 + 2.3f, // ISO 400 + 2.5f, // ISO 500 + 2.3f, // ISO 640 + 2.3f, // ISO 800 + 2.4f, // ISO 1000 + 2.3f, // ISO 1250 + 1.75f, // ISO 1600 + 1.75f, // ISO 2000 + 1.75f, // ISO 2500 + 1.75f, // ISO 3200 + 1.75f, // ISO 4000 + 1.75f, // ISO 5000 + 1.75f, // ISO 6400 + 1.75f, // ISO 8000 + 1.75f, // ISO 10000 + 1.5f, // ISO 12800 + 1.5f, // ISO 16000 + 1.5f, // ISO 20000 + 1.5f, // ISO 25600 + 1.5f, // ISO 32000 + 1.5f, // ISO 40000 + 1.5f, // ISO 51200 + 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK3II = 0.35f; + + static const float nReadK1[] = { 3.45f, // ISO 100 + 3.15f, // ISO 125 + 3.45f, // ISO 160 + 3.0f, // ISO 200 + 3.0f, // ISO 250 + 3.0f, // ISO 320 + 2.7f, // ISO 400 + 2.7f, // ISO 500 + 2.7f, // ISO 640 + 2.5f, // ISO 800 + 2.5f, // ISO 1000 + 2.5f, // ISO 1250 + 2.4f, // ISO 1600 + 2.4f, // ISO 2000 + 2.4f, // ISO 2500 + 2.4f, // ISO 3200 + 2.4f, // ISO 4000 + 2.4f, // ISO 5000 + 2.4f, // ISO 6400 + 2.4f, // ISO 8000 + 2.4f, // ISO 10000 + 2.4f, // ISO 12800 + 2.4f, // ISO 16000 + 2.4f, // ISO 20000 + 2.4f, // ISO 25600 + 2.4f, // ISO 32000 + 2.4f, // ISO 40000 + 2.4f, // ISO 51200 + 2.4f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK1 = 0.75f; + + static const float nReadK70[] = { 3.0f, // ISO 100 + 3.0f, // ISO 125 + 3.0f, // ISO 160 + 3.0f, // ISO 200 + 3.0f, // ISO 250 + 3.0f, // ISO 320 + 3.0f, // ISO 400 + 3.0f, // ISO 500 + 3.0f, // ISO 640 + 3.0f, // ISO 800 + 3.0f, // ISO 1000 + 3.0f, // ISO 1250 + 3.0f, // ISO 1600 + 3.0f, // ISO 2000 + 3.0f, // ISO 2500 + 3.0f, // ISO 3200 + 3.0f, // ISO 4000 + 3.0f, // ISO 5000 + 3.0f, // ISO 6400 + 3.0f, // ISO 8000 + 3.0f, // ISO 10000 + 3.0f, // ISO 12800 + 3.0f, // ISO 16000 + 3.0f, // ISO 20000 + 3.0f, // ISO 25600 + 3.0f, // ISO 32000 + 3.0f, // ISO 40000 + 3.0f, // ISO 51200 + 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK70 = 0.5f; + + if (plistener) { + plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); + plistener->setProgress(0.0); + } + + + const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); + int gridSize = 1; + + switch (gridSize_) { + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: + gridSize = 1; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: + gridSize = 3; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: + gridSize = 5; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: + gridSize = 7; + } + + // Lookup table for non adaptive (slider) mode + LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); + + if(detectMotion && !adaptive) { + const float lutStrength = 2.f; + log2Lut[0] = 0; + + for(int i = 2; i < 65536; i += 2) { + log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; + } + } + + const float scaleGreen = 1.f / scale_mul[1]; + + float nRead; + float eperIsoModel; + + int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); + + if(model.find("K-3") != string::npos) { + nRead = nReadK3II[nReadIndex]; + eperIsoModel = ePerIsoK3II; + } else if(model.find("K-1") != string::npos) { + nRead = nReadK1[nReadIndex]; + eperIsoModel = ePerIsoK1; + } else { + nRead = nReadK70[nReadIndex]; + eperIsoModel = ePerIsoK70; + } + + nRead *= pow(2.f, nreadIso); + eperIsoModel *= pow(2.f, eperIso); + eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); + + float eperIsoRed = eperIso / scale_mul[0]; + float eperIsoGreen = eperIso * scaleGreen; + float eperIsoBlue = eperIso / scale_mul[2]; + + printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); + + prnu /= 100.f; + stddevFactorGreen *= stddevFactorGreen; + stddevFactorRed *= stddevFactorRed; + stddevFactorBlue *= stddevFactorBlue; + + + nRead *= nRead; + + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel + float motionThreshold = 1.f - (motion / 100.f); + // For shades of green motion indicators + const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); + + unsigned int offsX = 0, offsY = 0; + + // We have to adjust the offsets for the selected subframe we use for areas with motion + switch (frame) { + case 0: + offsX = offsY = 0; + break; + + case 1: + offsX = 0; + offsY = 1; + break; + + case 2: + offsX = offsY = 1; + break; + + case 3: + offsX = 1; + offsY = 0; + } + + const float thresh = adaptive ? 0.f : motionThreshold; + array2D psRed(winw, winh); + array2D psG1(winw, winh); + array2D psG2(winw, winh); + array2D psBlue(winw, winh); + +// fill channels psRed, psG1, psG2 and psBlue +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + 1; i < winh - 1; ++i) { + float *greenDest1 = psG1[i]; + float *greenDest2 = psG2[i]; + float *nonGreenDest0 = psRed[i]; + float *nonGreenDest1 = psBlue[i]; + int j = winx + 1; + int c = FC(i, j); + + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels + std::swap(nonGreenDest0, nonGreenDest1); + std::swap(greenDest1, greenDest2); + } + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); + offset ^= 1; // 0 => 1 or 1 => 0 + + for(; j < winw - 1; ++j) { + offset ^= 1; // 0 => 1 or 1 => 0 + + // store the values from the 4 frames into 4 different temporary planes + greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j]; + greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1]; + nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + } + } + +// now that the temporary planes are filled for easy access we do the motion detection + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *redDest = red[i + offsY]; + float *blueDest = blue[i + offsY]; + int j = winx + border - offsX; + + float greenDifMax[gridSize]; // Here we store the maximum differences per Column + + // green channel motion detection checks the grid around the pixel for differences in green channels + if(detectMotion || adaptive) { + if(gridSize == 3) { + // compute maximum of differences for first two columns of 3x3 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + } else if(gridSize == 5) { + // compute maximum of differences for first four columns of 5x5 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + } else if(gridSize == 7) { + // compute maximum of differences for first six columns of 7x7 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + } + + } + + + // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 + int lastIndex = gridSize - 1; + float korr = 0.f; + int c = FC(i, j); + bool blueRow = false; + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels + blueRow = true; + } + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); +// offset ^= 1; // 0 => 1 or 1 => 0 + + for(; j < winw - (border + offsX); ++j) { + bool greenFromPs = false; + offset ^= 1; // 0 => 1 or 1 => 0 + + if(detectMotion || adaptive) { + bool skipNext = false; + float gridMax; + + if(gridSize < 2) { + // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps + gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); + skipNext = skip; + } else if(gridSize == 3) { + // compute maximum of differences for third column of 3x3 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); + } else if(gridSize == 5) { + // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); + } else if(gridSize == 7) { + // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); + } + + + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; + + // increase motion detection dependent on brightness + if(!adaptive) { + korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; + } + + if (gridMax > thresh - korr) { + if((offset == (frame&1)) && checkNonGreenVertical) { + if(frame > 1) { + green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; + } else { + green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; + } + continue; + } else { + // at least one of the tested green pixels of the grid is detected as motion + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + } + + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; + } + } + } + + if(adaptive && checkNonGreenCross) { + // check red cross + float redTop = psRed[i - 1][ j ]; + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + float redBottom = psRed[i + 1][ j ]; + float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiff > 0.f) { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + continue; + } + + // check blue cross + float blueTop = psBlue[i - 1][ j ]; + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + float blueBottom = psBlue[i + 1][ j ]; + float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + continue; + } + } + + if(adaptive && checkNonGreenHorizontal) { + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + + float redDiffLeft = redLeft - redCentre; + float redDiffRight = redRight - redCentre; + + if(redDiffLeft * redDiffRight >= 0.f) { + float redAvg = (redRight + redLeft) / 2.f; + float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(redDiffHor > 0.f) { + paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); + continue; + } + } + + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + + float blueDiffLeft = blueLeft - blueCentre; + float blueDiffRight = blueRight - blueCentre; + + if(blueDiffLeft * blueDiffRight >= 0.f) { + float blueAvg = (blueRight + blueLeft) / 2.f; + float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiffHor > 0.f) { + paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, redDest, blueDest, greenDest); + continue; + } + } + } + + if(adaptive && checkNonGreenVertical) { + // check red vertically + float redTop = psRed[i - 1][ j ]; + float redCentre = psRed[ i ][ j ]; + float redBottom = psRed[i + 1][ j ]; + + float redDiffTop = redTop - redCentre; + float redDiffBottom = redBottom - redCentre; + + if(redDiffTop * redDiffBottom >= 0.f) { + float redAvg = (redTop + redBottom) / 2.f; + float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiff > 0.f) { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + continue; + } + } + + // check blue vertically + float blueTop = psBlue[i - 1][ j ]; + float blueCentre = psBlue[ i ][ j ]; + float blueBottom = psBlue[i + 1][ j ]; + + float blueDiffTop = blueTop - blueCentre; + float blueDiffBottom = blueBottom - blueCentre; + + if(blueDiffTop * blueDiffBottom >= 0.f) { + float blueAvg = (blueTop + blueBottom) / 2.f; + float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + continue; + } + } + } + + if(adaptive && checkNonGreenAmaze) { + // check current pixel against amaze + float redCentre = psRed[ i ][ j ]; + float redAmaze = red[i + offsY][j + offsX]; + + float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(redDiffAmaze > 0.f) { + paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); + continue; + } + + float blueCentre = psBlue[ i ][ j ]; + float blueAmaze = blue[i + offsY][j + offsX]; + + float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + if(blueDiffAmaze > 0.f) { + paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); + continue; + } + } + + if(adaptive && checkNonGreenCross2) { // for experiments + + } + + + if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; + } else { + // no motion detected, replace the a priori demosaiced values by the pixelshift combined values + red[i + offsY][j + offsX] = psRed[i][j]; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + blue[i + offsY][j + offsX] = psBlue[i][j]; + } + } + } + + if(plistener) { + plistener->setProgress(1.0); + } +} +#endif \ No newline at end of file diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 747d60cb4..43a9ae020 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -485,6 +485,8 @@ enum ProcEvent { EvPixelShiftNonGreenCross = 455, EvPixelShiftStddevFactorRed = 456, EvPixelShiftStddevFactorBlue = 457, + EvPixelShiftNonGreenCross2 = 458, + EvPixelShiftNonGreenAmaze = 459, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5fd8b17ff..65fffb175 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -899,6 +899,8 @@ void RAWParams::setDefaults() bayersensor.pixelShiftNonGreenHorizontal = false; bayersensor.pixelShiftNonGreenVertical = false; bayersensor.pixelShiftNonGreenCross = false; + bayersensor.pixelShiftNonGreenCross2 = false; + bayersensor.pixelShiftNonGreenAmaze = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3434,7 +3436,13 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); } - //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross2) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross2", raw.bayersensor.pixelShiftNonGreenCross2 ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenAmaze) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenAmaze", raw.bayersensor.pixelShiftNonGreenAmaze ); + } if (!pedited || pedited->raw.xtranssensor.method) { keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); @@ -7604,7 +7612,21 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross2")) { + raw.bayersensor.pixelShiftNonGreenCross2 = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross2"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenCross2 = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenAmaze")) { + raw.bayersensor.pixelShiftNonGreenAmaze = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenAmaze"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenAmaze = true; + } + } } // load X-Trans sensors' raw settings @@ -8057,8 +8079,9 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal && raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross + && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 + && raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance - //&& raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance && raw.xtranssensor.method == other.raw.xtranssensor.method && raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps && raw.xtranssensor.blackred == other.raw.xtranssensor.blackred diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0c06fa315..fa46f3ac8 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1218,6 +1218,8 @@ public: bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; bool pixelShiftNonGreenCross; + bool pixelShiftNonGreenCross2; + bool pixelShiftNonGreenAmaze; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 36b78aa20..c95009a80 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2028,7 +2028,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); + pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross, raw.bayersensor.pixelShiftNonGreenAmaze, raw.bayersensor.pixelShiftNonGreenCross2); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index f80efeacf..0b42a37a1 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross, bool checkNonGreenAmaze, bool checkNonGreenCross2); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 08e3d2520..d61065cb8 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -484,7 +484,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftNonGreenVertical DEMOSAIC, // EvPixelShiftNonGreenCross DEMOSAIC, // EvPixelShiftStddevFactorRed - DEMOSAIC // EvPixelShiftStddevFactorBlue + DEMOSAIC, // EvPixelShiftStddevFactorBlue + DEMOSAIC, // EvPixelShiftNonGreenCross2 + DEMOSAIC // EvPixelShiftNonGreenAmaze }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 297a9b65b..98054f3fa 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -95,6 +95,12 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNonGreenCross = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); + pixelShiftNonGreenCross2 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenCross2); + + pixelShiftNonGreenAmaze = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenAmaze); + pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); @@ -217,7 +223,8 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); + pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); + pixelShiftNonGreenAmazeconn = pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true); } @@ -251,7 +258,8 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); - //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); + pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftStddevFactorGreen->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); @@ -282,6 +290,8 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); + pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); @@ -355,6 +365,8 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -389,6 +401,8 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenAmaze = !pixelShiftNonGreenAmaze->get_inconsistent(); } } @@ -637,6 +651,8 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenCross2->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenAmaze->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -704,21 +720,42 @@ void BayerProcess::pixelShiftNonGreenCrossChanged () } } - -/*void BayerProcess::allEnhanceChanged () +void BayerProcess::pixelShiftNonGreenCross2Changed () { if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); + if (pixelShiftNonGreenCross2->get_inconsistent()) { + pixelShiftNonGreenCross2->set_inconsistent (false); + pixelShiftNonGreenCross2conn.block (true); + pixelShiftNonGreenCross2->set_active (false); + pixelShiftNonGreenCross2conn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenCross2->set_inconsistent (true); } - else if (lastALLen) - allEnhance->set_inconsistent (true); - lastALLen = allEnhance->get_active (); + lastDCBen = pixelShiftNonGreenCross2->get_active (); } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ + + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenCross2, pixelShiftNonGreenCross2->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftNonGreenAmazeChanged () +{ + if (batchMode) { + if (pixelShiftNonGreenAmaze->get_inconsistent()) { + pixelShiftNonGreenAmaze->set_inconsistent (false); + pixelShiftNonGreenAmazeconn.block (true); + pixelShiftNonGreenAmaze->set_active (false); + pixelShiftNonGreenAmazeconn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenAmaze->set_inconsistent (true); + } + + lastDCBen = pixelShiftNonGreenAmaze->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenAmaze, pixelShiftNonGreenAmaze->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index ca560ad89..5911a1267 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -50,6 +50,8 @@ protected: Gtk::CheckButton* pixelShiftNonGreenHorizontal; Gtk::CheckButton* pixelShiftNonGreenVertical; Gtk::CheckButton* pixelShiftNonGreenCross; + Gtk::CheckButton* pixelShiftNonGreenCross2; + Gtk::CheckButton* pixelShiftNonGreenAmaze; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; @@ -59,7 +61,10 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, + pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, + pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn, + pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn; public: BayerProcess (); @@ -80,7 +85,8 @@ public: void pixelShiftNonGreenHorizontalChanged(); void pixelShiftNonGreenVerticalChanged(); void pixelShiftNonGreenCrossChanged(); - //void allEnhanceChanged(); + void pixelShiftNonGreenCross2Changed(); + void pixelShiftNonGreenAmazeChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index f433ec639..e91ea6c26 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -384,6 +384,8 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftNonGreenHorizontal = v; raw.bayersensor.pixelShiftNonGreenVertical = v; raw.bayersensor.pixelShiftNonGreenCross = v; + raw.bayersensor.pixelShiftNonGreenCross2 = v; + raw.bayersensor.pixelShiftNonGreenAmaze = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -894,6 +896,8 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; raw.bayersensor.pixelShiftNonGreenVertical = raw.bayersensor.pixelShiftNonGreenVertical && p.raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; + raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; + 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2362,7 +2366,14 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; } - //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; + if (raw.bayersensor.pixelShiftNonGreenCross2) { + toEdit.raw.bayersensor.pixelShiftNonGreenCross2 = mods.raw.bayersensor.pixelShiftNonGreenCross2; + } + + if (raw.bayersensor.pixelShiftNonGreenAmaze) { + toEdit.raw.bayersensor.pixelShiftNonGreenAmaze = mods.raw.bayersensor.pixelShiftNonGreenAmaze; + } + if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; } @@ -2875,7 +2886,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly - && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index b4af2ad05..b4da65ac1 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -706,6 +706,8 @@ public: bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; bool pixelShiftNonGreenCross; + bool pixelShiftNonGreenCross2; + bool pixelShiftNonGreenAmaze; //bool allEnhance; bool greenEq; From bbabe9bca88fa70a0a1b96e9cb0e84629f6001df Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 15 Dec 2016 18:54:42 +0100 Subject: [PATCH 61/83] Revert "pixelshift: Simplified code and added 2 checkboxes" This reverts commit 3870f6d35d0d4098d232edae42412354cf9f2144. --- rtdata/languages/default | 4 - rtengine/pixelshift.cc | 855 +++++-------------------------------- rtengine/procevents.h | 2 - rtengine/procparams.cc | 29 +- rtengine/procparams.h | 2 - rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 4 +- rtgui/bayerprocess.cc | 67 +-- rtgui/bayerprocess.h | 10 +- rtgui/paramsedited.cc | 15 +- rtgui/paramsedited.h | 2 - 12 files changed, 120 insertions(+), 874 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index a6ec3c098..db55dde96 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -690,8 +690,6 @@ HISTORY_MSG_455;EvPixelShiftNonGreenVertical HISTORY_MSG_456;EvPixelShiftNonGreenCross HISTORY_MSG_457;EvPixelShiftStddevFactorRed HISTORY_MSG_458;EvPixelShiftStddevFactorBlue -HISTORY_MSG_459;EvPixelShiftNonGreenCross2 -HISTORY_MSG_460;EvPixelShiftNonGreenAmaze HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1674,8 +1672,6 @@ TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross -TP_RAW_PIXELSHIFTNONGREENCROSS2;Check red/blue experimental -TP_RAW_PIXELSHIFTNONGREENAMAZE;Check red/blue amaze TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTMOTIONCORRECTION;Green motion correction size diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index ebb9d2c64..e3ababc85 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -126,7 +126,7 @@ void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMas using namespace std; using namespace rtengine; -#ifdef __OLDPS__ + void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { @@ -276,7 +276,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoModel; int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); - if(model.find("K-3") != string::npos) { nRead = nReadK3II[nReadIndex]; eperIsoModel = ePerIsoK3II; @@ -348,11 +347,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoNonGreen2 = eperIso / scale_mul[2]; float stddevFactorNonGreen0 = stddevFactorRed; float stddevFactorNonGreen2 = stddevFactorBlue; - bool blueRow = false; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels - blueRow = true; std::swap(nonGreenDest0, nonGreenDest1); std::swap(scaleNonGreen0, scaleNonGreen2); std::swap(eperIsoNonGreen0, eperIsoNonGreen2); @@ -369,89 +366,89 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } else if(gridSize == 7) { // compute maximum of differences for first six columns of 7x7 grid greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); } } @@ -476,29 +473,29 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } @@ -531,102 +528,29 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; - float diffRight = ngRight - ngCentre; - float diffLeft = ngLeft - ngCentre; - float diffHorNg0 = -1.f; + float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; + float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; + float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - if(diffRight * diffLeft >= 0.f) { - float avg = (ngRight + ngLeft) / 2.f; - diffHorNg0 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - -// if(diff > 0.f) { -// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); -// continue; -// } + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + continue; } - float diffHorNg1 = -1.f; ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; - diffRight = ngRight - ngCentre; - diffLeft = ngLeft - ngCentre; + ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; + ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; + diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - if(diffRight * diffLeft >= 0.f) { - float avg = (ngRight + ngLeft) / 2.f; - float diffHorNg1 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - -// if(diff > 0.f) { -// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); -// continue; -// } - } - - if( diffHorNg0 * diffHorNg1 < 0.f) { - paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + if(diff > 0.f) { + paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); continue; - } - -// bool motion = false; -// float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; -// float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; -// float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; -// float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; -// float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; -// float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); -// -// if(diff > 0.f) { -// motion = true; -// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); -// continue; -// } -// -// ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; -// ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; -// ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; -// ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; -// ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; -// diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); -// -//// if(diff > 0.f) { -// if((diff > 0.f && !motion) || (diff <= 0.f && motion) ) { -// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); -// continue; -// } } if(adaptive && checkNonGreenHorizontal) { -// float lg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j - 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j]) / 2.f; -// float cg = ((*rawDataFrames[1 - offset])[i - offset + 1][j] + (*rawDataFrames[3 - offset])[i + offset][j + 1]) / 2.f; -// float rg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j + 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j + 2]) / 2.f; -// -// float lr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) - 1]; -// float cr = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; -// float rr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) + 1]; -// -// float lb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1)]; -// float cb = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; -// float rb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1) + 2]; -// -// if(blueRow) { -// std::swap(lr, lb); -// std::swap(cr, cb); -// std::swap(rr, rb); -// } -// -// float lh = Color::rgb2h(lr, lg, lb); -// float ch = Color::rgb2h(cr, cg, cb); -// float rh = Color::rgb2h(rr, rg, rb); -// -// float lHueDiff = lh - ch; -// float rHueDiff = rh - ch; -// if(lHueDiff * rHueDiff > 0.f) { -// if(std::fabs(lHueDiff) > 0.5f && std::fabs(rHueDiff) > 0.5f/* && std::fabs(lHueDiff) < 3.f && std::fabs(rHueDiff) < 3.f*/) { -// paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); -// continue; -// } -// } float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; @@ -713,592 +637,3 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det plistener->setProgress(1.0); } } -#else -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross, bool checkNonGreenAmaze, bool checkNonGreenCross2) -{ - - BENCHFUN - - static const float nReadK3II[] = { 3.4f, // ISO 100 - 3.1f, // ISO 125 - 2.5f, // ISO 160 - 2.5f, // ISO 200 - 2.5f, // ISO 250 - 2.5f, // ISO 320 - 2.3f, // ISO 400 - 2.5f, // ISO 500 - 2.3f, // ISO 640 - 2.3f, // ISO 800 - 2.4f, // ISO 1000 - 2.3f, // ISO 1250 - 1.75f, // ISO 1600 - 1.75f, // ISO 2000 - 1.75f, // ISO 2500 - 1.75f, // ISO 3200 - 1.75f, // ISO 4000 - 1.75f, // ISO 5000 - 1.75f, // ISO 6400 - 1.75f, // ISO 8000 - 1.75f, // ISO 10000 - 1.5f, // ISO 12800 - 1.5f, // ISO 16000 - 1.5f, // ISO 20000 - 1.5f, // ISO 25600 - 1.5f, // ISO 32000 - 1.5f, // ISO 40000 - 1.5f, // ISO 51200 - 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; - - static const float ePerIsoK3II = 0.35f; - - static const float nReadK1[] = { 3.45f, // ISO 100 - 3.15f, // ISO 125 - 3.45f, // ISO 160 - 3.0f, // ISO 200 - 3.0f, // ISO 250 - 3.0f, // ISO 320 - 2.7f, // ISO 400 - 2.7f, // ISO 500 - 2.7f, // ISO 640 - 2.5f, // ISO 800 - 2.5f, // ISO 1000 - 2.5f, // ISO 1250 - 2.4f, // ISO 1600 - 2.4f, // ISO 2000 - 2.4f, // ISO 2500 - 2.4f, // ISO 3200 - 2.4f, // ISO 4000 - 2.4f, // ISO 5000 - 2.4f, // ISO 6400 - 2.4f, // ISO 8000 - 2.4f, // ISO 10000 - 2.4f, // ISO 12800 - 2.4f, // ISO 16000 - 2.4f, // ISO 20000 - 2.4f, // ISO 25600 - 2.4f, // ISO 32000 - 2.4f, // ISO 40000 - 2.4f, // ISO 51200 - 2.4f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; - - static const float ePerIsoK1 = 0.75f; - - static const float nReadK70[] = { 3.0f, // ISO 100 - 3.0f, // ISO 125 - 3.0f, // ISO 160 - 3.0f, // ISO 200 - 3.0f, // ISO 250 - 3.0f, // ISO 320 - 3.0f, // ISO 400 - 3.0f, // ISO 500 - 3.0f, // ISO 640 - 3.0f, // ISO 800 - 3.0f, // ISO 1000 - 3.0f, // ISO 1250 - 3.0f, // ISO 1600 - 3.0f, // ISO 2000 - 3.0f, // ISO 2500 - 3.0f, // ISO 3200 - 3.0f, // ISO 4000 - 3.0f, // ISO 5000 - 3.0f, // ISO 6400 - 3.0f, // ISO 8000 - 3.0f, // ISO 10000 - 3.0f, // ISO 12800 - 3.0f, // ISO 16000 - 3.0f, // ISO 20000 - 3.0f, // ISO 25600 - 3.0f, // ISO 32000 - 3.0f, // ISO 40000 - 3.0f, // ISO 51200 - 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) - }; - - static const float ePerIsoK70 = 0.5f; - - if (plistener) { - plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); - plistener->setProgress(0.0); - } - - - const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); - int gridSize = 1; - - switch (gridSize_) { - case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: - case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: - gridSize = 1; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: - gridSize = 3; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: - gridSize = 5; - break; - - case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: - gridSize = 7; - } - - // Lookup table for non adaptive (slider) mode - LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - - if(detectMotion && !adaptive) { - const float lutStrength = 2.f; - log2Lut[0] = 0; - - for(int i = 2; i < 65536; i += 2) { - log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; - } - } - - const float scaleGreen = 1.f / scale_mul[1]; - - float nRead; - float eperIsoModel; - - int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); - - if(model.find("K-3") != string::npos) { - nRead = nReadK3II[nReadIndex]; - eperIsoModel = ePerIsoK3II; - } else if(model.find("K-1") != string::npos) { - nRead = nReadK1[nReadIndex]; - eperIsoModel = ePerIsoK1; - } else { - nRead = nReadK70[nReadIndex]; - eperIsoModel = ePerIsoK70; - } - - nRead *= pow(2.f, nreadIso); - eperIsoModel *= pow(2.f, eperIso); - eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); - - float eperIsoRed = eperIso / scale_mul[0]; - float eperIsoGreen = eperIso * scaleGreen; - float eperIsoBlue = eperIso / scale_mul[2]; - - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); - - prnu /= 100.f; - stddevFactorGreen *= stddevFactorGreen; - stddevFactorRed *= stddevFactorRed; - stddevFactorBlue *= stddevFactorBlue; - - - nRead *= nRead; - - // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel - float motionThreshold = 1.f - (motion / 100.f); - // For shades of green motion indicators - const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); - - unsigned int offsX = 0, offsY = 0; - - // We have to adjust the offsets for the selected subframe we use for areas with motion - switch (frame) { - case 0: - offsX = offsY = 0; - break; - - case 1: - offsX = 0; - offsY = 1; - break; - - case 2: - offsX = offsY = 1; - break; - - case 3: - offsX = 1; - offsY = 0; - } - - const float thresh = adaptive ? 0.f : motionThreshold; - array2D psRed(winw, winh); - array2D psG1(winw, winh); - array2D psG2(winw, winh); - array2D psBlue(winw, winh); - -// fill channels psRed, psG1, psG2 and psBlue -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - - for(int i = winy + 1; i < winh - 1; ++i) { - float *greenDest1 = psG1[i]; - float *greenDest2 = psG2[i]; - float *nonGreenDest0 = psRed[i]; - float *nonGreenDest1 = psBlue[i]; - int j = winx + 1; - int c = FC(i, j); - - if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { - // row with blue pixels => swap destination pointers for non green pixels - std::swap(nonGreenDest0, nonGreenDest1); - std::swap(greenDest1, greenDest2); - } - - // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop - unsigned int offset = (c & 1); - offset ^= 1; // 0 => 1 or 1 => 0 - - for(; j < winw - 1; ++j) { - offset ^= 1; // 0 => 1 or 1 => 0 - - // store the values from the 4 frames into 4 different temporary planes - greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j]; - greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1]; - nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; - } - } - -// now that the temporary planes are filled for easy access we do the motion detection - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - - for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { - float *greenDest = green[i + offsY]; - float *redDest = red[i + offsY]; - float *blueDest = blue[i + offsY]; - int j = winx + border - offsX; - - float greenDifMax[gridSize]; // Here we store the maximum differences per Column - - // green channel motion detection checks the grid around the pixel for differences in green channels - if(detectMotion || adaptive) { - if(gridSize == 3) { - // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } else if(gridSize == 5) { - // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } else if(gridSize == 7) { - // compute maximum of differences for first six columns of 7x7 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - } - - } - - - // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 - int lastIndex = gridSize - 1; - float korr = 0.f; - int c = FC(i, j); - bool blueRow = false; - if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { - // row with blue pixels => swap destination pointers for non green pixels - blueRow = true; - } - - // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop - unsigned int offset = (c & 1); -// offset ^= 1; // 0 => 1 or 1 => 0 - - for(; j < winw - (border + offsX); ++j) { - bool greenFromPs = false; - offset ^= 1; // 0 => 1 or 1 => 0 - - if(detectMotion || adaptive) { - bool skipNext = false; - float gridMax; - - if(gridSize < 2) { - // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps - gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); - skipNext = skip; - } else if(gridSize == 3) { - // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); - } else if(gridSize == 5) { - // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); - } else if(gridSize == 7) { - // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); - } - - - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - - // increase motion detection dependent on brightness - if(!adaptive) { - korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; - } - - if (gridMax > thresh - korr) { - if((offset == (frame&1)) && checkNonGreenVertical) { - if(frame > 1) { - green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; - } else { - green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; - } - continue; - } else { - // at least one of the tested green pixels of the grid is detected as motion - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); - - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); - } - - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; - } - } - } - - if(adaptive && checkNonGreenCross) { - // check red cross - float redTop = psRed[i - 1][ j ]; - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - float redBottom = psRed[i + 1][ j ]; - float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiff > 0.f) { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); - continue; - } - - // check blue cross - float blueTop = psBlue[i - 1][ j ]; - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; - float blueBottom = psBlue[i + 1][ j ]; - float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiff > 0.f) { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); - continue; - } - } - - if(adaptive && checkNonGreenHorizontal) { - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - - float redDiffLeft = redLeft - redCentre; - float redDiffRight = redRight - redCentre; - - if(redDiffLeft * redDiffRight >= 0.f) { - float redAvg = (redRight + redLeft) / 2.f; - float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(redDiffHor > 0.f) { - paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); - continue; - } - } - - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; - - float blueDiffLeft = blueLeft - blueCentre; - float blueDiffRight = blueRight - blueCentre; - - if(blueDiffLeft * blueDiffRight >= 0.f) { - float blueAvg = (blueRight + blueLeft) / 2.f; - float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiffHor > 0.f) { - paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, redDest, blueDest, greenDest); - continue; - } - } - } - - if(adaptive && checkNonGreenVertical) { - // check red vertically - float redTop = psRed[i - 1][ j ]; - float redCentre = psRed[ i ][ j ]; - float redBottom = psRed[i + 1][ j ]; - - float redDiffTop = redTop - redCentre; - float redDiffBottom = redBottom - redCentre; - - if(redDiffTop * redDiffBottom >= 0.f) { - float redAvg = (redTop + redBottom) / 2.f; - float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiff > 0.f) { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); - continue; - } - } - - // check blue vertically - float blueTop = psBlue[i - 1][ j ]; - float blueCentre = psBlue[ i ][ j ]; - float blueBottom = psBlue[i + 1][ j ]; - - float blueDiffTop = blueTop - blueCentre; - float blueDiffBottom = blueBottom - blueCentre; - - if(blueDiffTop * blueDiffBottom >= 0.f) { - float blueAvg = (blueTop + blueBottom) / 2.f; - float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiff > 0.f) { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); - continue; - } - } - } - - if(adaptive && checkNonGreenAmaze) { - // check current pixel against amaze - float redCentre = psRed[ i ][ j ]; - float redAmaze = red[i + offsY][j + offsX]; - - float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(redDiffAmaze > 0.f) { - paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); - continue; - } - - float blueCentre = psBlue[ i ][ j ]; - float blueAmaze = blue[i + offsY][j + offsX]; - - float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - if(blueDiffAmaze > 0.f) { - paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); - continue; - } - } - - if(adaptive && checkNonGreenCross2) { // for experiments - - } - - - if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black - red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; - } else { - // no motion detected, replace the a priori demosaiced values by the pixelshift combined values - red[i + offsY][j + offsX] = psRed[i][j]; - green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; - blue[i + offsY][j + offsX] = psBlue[i][j]; - } - } - } - - if(plistener) { - plistener->setProgress(1.0); - } -} -#endif \ No newline at end of file diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 43a9ae020..747d60cb4 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -485,8 +485,6 @@ enum ProcEvent { EvPixelShiftNonGreenCross = 455, EvPixelShiftStddevFactorRed = 456, EvPixelShiftStddevFactorBlue = 457, - EvPixelShiftNonGreenCross2 = 458, - EvPixelShiftNonGreenAmaze = 459, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 65fffb175..5fd8b17ff 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -899,8 +899,6 @@ void RAWParams::setDefaults() bayersensor.pixelShiftNonGreenHorizontal = false; bayersensor.pixelShiftNonGreenVertical = false; bayersensor.pixelShiftNonGreenCross = false; - bayersensor.pixelShiftNonGreenCross2 = false; - bayersensor.pixelShiftNonGreenAmaze = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3436,13 +3434,7 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); } - if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross2) { - keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross2", raw.bayersensor.pixelShiftNonGreenCross2 ); - } - - if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenAmaze) { - keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenAmaze", raw.bayersensor.pixelShiftNonGreenAmaze ); - } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); if (!pedited || pedited->raw.xtranssensor.method) { keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); @@ -7612,21 +7604,7 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross2")) { - raw.bayersensor.pixelShiftNonGreenCross2 = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross2"); - - if (pedited) { - pedited->raw.bayersensor.pixelShiftNonGreenCross2 = true; - } - } - - if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenAmaze")) { - raw.bayersensor.pixelShiftNonGreenAmaze = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenAmaze"); - - if (pedited) { - pedited->raw.bayersensor.pixelShiftNonGreenAmaze = true; - } - } + //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } } // load X-Trans sensors' raw settings @@ -8079,9 +8057,8 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal && raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross - && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 - && raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance + //&& raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance && raw.xtranssensor.method == other.raw.xtranssensor.method && raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps && raw.xtranssensor.blackred == other.raw.xtranssensor.blackred diff --git a/rtengine/procparams.h b/rtengine/procparams.h index fa46f3ac8..0c06fa315 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1218,8 +1218,6 @@ public: bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; bool pixelShiftNonGreenCross; - bool pixelShiftNonGreenCross2; - bool pixelShiftNonGreenAmaze; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index c95009a80..36b78aa20 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2028,7 +2028,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross, raw.bayersensor.pixelShiftNonGreenAmaze, raw.bayersensor.pixelShiftNonGreenCross2); + pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 0b42a37a1..f80efeacf 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross, bool checkNonGreenAmaze, bool checkNonGreenCross2); + void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index d61065cb8..08e3d2520 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -484,9 +484,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftNonGreenVertical DEMOSAIC, // EvPixelShiftNonGreenCross DEMOSAIC, // EvPixelShiftStddevFactorRed - DEMOSAIC, // EvPixelShiftStddevFactorBlue - DEMOSAIC, // EvPixelShiftNonGreenCross2 - DEMOSAIC // EvPixelShiftNonGreenAmaze + DEMOSAIC // EvPixelShiftStddevFactorBlue }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 98054f3fa..297a9b65b 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -95,12 +95,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNonGreenCross = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); - pixelShiftNonGreenCross2 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); - pixelShiftOptions->pack_start(*pixelShiftNonGreenCross2); - - pixelShiftNonGreenAmaze = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); - pixelShiftOptions->pack_start(*pixelShiftNonGreenAmaze); - pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); @@ -223,8 +217,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); - pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); - pixelShiftNonGreenAmazeconn = pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true); + //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); } @@ -258,8 +251,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); - pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); + //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftStddevFactorGreen->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); @@ -290,8 +282,6 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); - pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); @@ -365,8 +355,6 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); - pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); - pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -401,8 +389,6 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftNonGreenAmaze = !pixelShiftNonGreenAmaze->get_inconsistent(); } } @@ -651,8 +637,6 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); - pixelShiftNonGreenCross2->set_sensitive(pixelShiftAutomatic->get_active ()); - pixelShiftNonGreenAmaze->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -720,42 +704,21 @@ void BayerProcess::pixelShiftNonGreenCrossChanged () } } -void BayerProcess::pixelShiftNonGreenCross2Changed () + +/*void BayerProcess::allEnhanceChanged () { if (batchMode) { - if (pixelShiftNonGreenCross2->get_inconsistent()) { - pixelShiftNonGreenCross2->set_inconsistent (false); - pixelShiftNonGreenCross2conn.block (true); - pixelShiftNonGreenCross2->set_active (false); - pixelShiftNonGreenCross2conn.block (false); - } else if (lastDCBen) { - pixelShiftNonGreenCross2->set_inconsistent (true); + if (allEnhance->get_inconsistent()) { + allEnhance->set_inconsistent (false); + allEnhconn.block (true); + allEnhance->set_active (false); + allEnhconn.block (false); } + else if (lastALLen) + allEnhance->set_inconsistent (true); - lastDCBen = pixelShiftNonGreenCross2->get_active (); + lastALLen = allEnhance->get_active (); } - - if (listener) { - listener->panelChanged (EvPixelShiftNonGreenCross2, pixelShiftNonGreenCross2->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -void BayerProcess::pixelShiftNonGreenAmazeChanged () -{ - if (batchMode) { - if (pixelShiftNonGreenAmaze->get_inconsistent()) { - pixelShiftNonGreenAmaze->set_inconsistent (false); - pixelShiftNonGreenAmazeconn.block (true); - pixelShiftNonGreenAmaze->set_active (false); - pixelShiftNonGreenAmazeconn.block (false); - } else if (lastDCBen) { - pixelShiftNonGreenAmaze->set_inconsistent (true); - } - - lastDCBen = pixelShiftNonGreenAmaze->get_active (); - } - - if (listener) { - listener->panelChanged (EvPixelShiftNonGreenAmaze, pixelShiftNonGreenAmaze->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} + if (listener) + listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +}*/ diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 5911a1267..ca560ad89 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -50,8 +50,6 @@ protected: Gtk::CheckButton* pixelShiftNonGreenHorizontal; Gtk::CheckButton* pixelShiftNonGreenVertical; Gtk::CheckButton* pixelShiftNonGreenCross; - Gtk::CheckButton* pixelShiftNonGreenCross2; - Gtk::CheckButton* pixelShiftNonGreenAmaze; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; @@ -61,10 +59,7 @@ protected: bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, - pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, - pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn, - pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn; + sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn; //,allEnhconn; public: BayerProcess (); @@ -85,8 +80,7 @@ public: void pixelShiftNonGreenHorizontalChanged(); void pixelShiftNonGreenVerticalChanged(); void pixelShiftNonGreenCrossChanged(); - void pixelShiftNonGreenCross2Changed(); - void pixelShiftNonGreenAmazeChanged(); + //void allEnhanceChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index e91ea6c26..f433ec639 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -384,8 +384,6 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftNonGreenHorizontal = v; raw.bayersensor.pixelShiftNonGreenVertical = v; raw.bayersensor.pixelShiftNonGreenCross = v; - raw.bayersensor.pixelShiftNonGreenCross2 = v; - raw.bayersensor.pixelShiftNonGreenAmaze = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -896,8 +894,6 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; raw.bayersensor.pixelShiftNonGreenVertical = raw.bayersensor.pixelShiftNonGreenVertical && p.raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; - raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; - 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2366,14 +2362,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; } - if (raw.bayersensor.pixelShiftNonGreenCross2) { - toEdit.raw.bayersensor.pixelShiftNonGreenCross2 = mods.raw.bayersensor.pixelShiftNonGreenCross2; - } - - if (raw.bayersensor.pixelShiftNonGreenAmaze) { - toEdit.raw.bayersensor.pixelShiftNonGreenAmaze = mods.raw.bayersensor.pixelShiftNonGreenAmaze; - } - + //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; } @@ -2886,7 +2875,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly - && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index b4da65ac1..b4af2ad05 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -706,8 +706,6 @@ public: bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; bool pixelShiftNonGreenCross; - bool pixelShiftNonGreenCross2; - bool pixelShiftNonGreenAmaze; //bool allEnhance; bool greenEq; From 37243d9cd6675dca1592c2c3c4ede7e08f51fdc5 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 13 Jan 2017 21:35:11 +0100 Subject: [PATCH 62/83] Pixelshift: new beta realease --- rtdata/languages/default | 29 +- rtengine/amaze_demosaic_RT.cc | 2 +- rtengine/median.h | 9 + rtengine/pixelshift.cc | 1227 ++++++++++++++++++++++++++++++--- rtengine/procevents.h | 11 + rtengine/procparams.cc | 165 ++++- rtengine/procparams.h | 13 +- rtengine/rawimagesource.cc | 106 ++- rtengine/rawimagesource.h | 4 +- rtengine/refreshmap.cc | 13 +- rtgui/bayerprocess.cc | 322 ++++++++- rtgui/bayerprocess.h | 25 +- rtgui/paramsedited.cc | 71 +- rtgui/paramsedited.h | 11 + 14 files changed, 1850 insertions(+), 158 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index db55dde96..4b1b329e9 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -690,6 +690,16 @@ HISTORY_MSG_455;EvPixelShiftNonGreenVertical HISTORY_MSG_456;EvPixelShiftNonGreenCross HISTORY_MSG_457;EvPixelShiftStddevFactorRed HISTORY_MSG_458;EvPixelShiftStddevFactorBlue +HISTORY_MSG_459;EvPixelShiftGreenAmaze +HISTORY_MSG_460;EvPixelShiftNonGreenAmaze +HISTORY_MSG_461;EvPixelShiftGreen +HISTORY_MSG_462;EvPixelShiftRedBlueWeight +HISTORY_MSG_463;EvPixelShiftBlur +HISTORY_MSG_464;EvPixelShiftSigma +HISTORY_MSG_465;EvPixelShiftSum +HISTORY_MSG_466;EvPixelShiftExp0 +HISTORY_MSG_467;EvPixelShiftHoleFill +HISTORY_MSG_468;EvPixelShiftMedian HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1671,9 +1681,23 @@ TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (ste TP_RAW_PIXELSHIFTADAPTIVE;Adaptive detection TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical +TP_RAW_PIXELSHIFTMEDIAN;Median +TP_RAW_PIXELSHIFTMEDIAN3;Exclude selected frame from median +TP_RAW_PIXELSHIFTHOLEFILL;3x3 new: Fill holes +TP_RAW_PIXELSHIFTBLUR;3x3 new: Blur +TP_RAW_PIXELSHIFTEXP0;Experimental +TP_RAW_PIXELSHIFTGREEN;Check dual green TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross -TP_RAW_PIXELSHIFTMOTION;Pixelshift motion detection +TP_RAW_PIXELSHIFTNONGREENCROSS2;Check green amaze +TP_RAW_PIXELSHIFTNONGREENAMAZE;Check red/blue amaze +TP_RAW_PIXELSHIFTMOTION;Motion detection level (deprecated) TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used +TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;Fill holes in motion mask +TP_RAW_PIXELSHIFTBLUR_TOOLTIP;Blur motion mask +TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;Use median of all frames instead of selected frame for regions with motion.\nRemoves objects which are at different places in all frames.\nGives motion effect on slow moving (overlapping) objects. +TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP;Excludes selected frame from median.\nUseful if moving objects overlap in frame 2 and 3 +TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a mask showing the regions with motion +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;Shows the motion mask without the image TP_RAW_PIXELSHIFTMOTIONCORRECTION;Green motion correction size TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid TP_RAW_PIXELSHIFTSHOWMOTION;Show motion @@ -1684,6 +1708,9 @@ TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE;StdDev factor Blue TP_RAW_PIXELSHIFTEPERISO;e per ISO TP_RAW_PIXELSHIFTNREADISO;nRead TP_RAW_PIXELSHIFTPRNU;PRNU (%) +TP_RAW_PIXELSHIFTSIGMA;Blur sigma +TP_RAW_PIXELSHIFTMASKTHRESHOLD;3x3 new threshold +TP_RAW_PIXELSHIFTREDBLUEWEIGHT;Red&Blue weight TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster. TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index c5535493c..3cb0ee8de 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -38,7 +38,7 @@ namespace rtengine { -SSEFUNCTION void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh) +SSEFUNCTION void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue) { BENCHFUN diff --git a/rtengine/median.h b/rtengine/median.h index 971452bc3..30adbacb3 100644 --- a/rtengine/median.h +++ b/rtengine/median.h @@ -64,6 +64,15 @@ inline vfloat median(std::array array) } #endif + +template +inline T median(std::array array) +{ + float val1 = std::max(std::min(array[0], array[1]), std::min(array[2], array[3])); + float val2 = std::min(std::max(array[0], array[1]), std::max(array[2], array[3])); + return (val1 + val2) / 2.f; +} + template inline T median(std::array array) { diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index e3ababc85..ae2f08fdb 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -30,13 +30,14 @@ #include "rawimagesource.h" #include "../rtgui/multilangmgr.h" #include "procparams.h" +#include "gauss.h" #define BENCHMARK #include "StopWatch.h" namespace { -float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) +float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion, int x, int y) { // calculate the difference between two green samples if(adaptive) { @@ -47,6 +48,12 @@ float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperI avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); + +// if(x >= 4294 && x <= 4303 && y >= 3056 && y <= 3058) { +// #pragma omp critical +// std::cout << "x : " << x << " y : " << y << " stddev : " << stddev << " avg : " << avg << " gDiff : " << gDiff << std::endl; +// } + float result = gDiff - stddev; if(!showMotion) { @@ -122,11 +129,166 @@ void paintMotionMask(int index, bool showMotion, float gridMax, bool showOnlyMas } } +void invertMask(int xStart, int xEnd, int yStart, int yEnd, array2D &maskIn, array2D &maskOut) +{ + #pragma omp parallel for schedule(dynamic,16) + + for(int i = yStart; i < yEnd; ++i) { + #pragma omp simd + + for(int j = xStart; j < xEnd; ++j) { + maskOut[i][j] = ~maskIn[i][j]; + } + } +} + +void xorMasks(int xStart, int xEnd, int yStart, int yEnd, array2D &maskIn, array2D &maskOut) +{ + #pragma omp parallel for schedule(dynamic,16) + + for(int i = yStart; i < yEnd; ++i) { + #pragma omp simd + + for(int j = xStart; j < xEnd; ++j) { + maskOut[i][j] ^= maskIn[i][j]; + } + } +} + +void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, array2D &mask, std::stack, std::vector>> &coordStack) +{ + coordStack.emplace(x, y); + + while(!coordStack.empty()) { + auto coord = coordStack.top(); + coordStack.pop(); + auto x = coord.first, y = coord.second; + + if (mask[y][x] == 255) { + auto yUp = y - 1, yDown = y + 1; + bool lastXUp = false, lastXDown = false, firstXUp = false, firstXDown = false; + mask[y][x] = 0; + if(yUp >= yStart && mask[yUp][x] == 255) { + coordStack.emplace(x, yUp); + firstXUp = lastXUp = true; + } + if(yDown < yEnd && mask[yDown][x] == 255) { + coordStack.emplace(x, yDown); + firstXDown = lastXDown = true; + } + auto xr = x + 1; + + while(xr < xEnd && mask[y][xr] == 255) { + mask[y][xr] = 0; + if(yUp >= yStart && mask[yUp][xr] == 255) { + if(!lastXUp) { + coordStack.emplace(xr, yUp); + lastXUp = true; + } + } else { + lastXUp = false; + } + if(yDown < yEnd && mask[yDown][xr] == 255) { + if(!lastXDown) { + coordStack.emplace(xr, yDown); + lastXDown = true; + } + } else { + lastXDown = false; + } + xr++; + } + + auto xl = x - 1; + lastXUp = firstXUp; + lastXDown = firstXDown; + while(xl >= xStart && mask[y][xl] == 255) { + mask[y][xl] = 0; + if(yUp >= yStart && mask[yUp][xl] == 255) { + if(!lastXUp) { + coordStack.emplace(xl, yUp); + lastXUp = true; + } + } else { + lastXUp = false; + } + if(yDown < yEnd && mask[yDown][xl] == 255) { + if(!lastXDown) { + coordStack.emplace(xl, yDown); + lastXDown = true; + } + } else { + lastXDown = false; + } + xl--; + } + mask[y][x] = 0; + } + } +} + +void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D &mask) +{ + #pragma omp parallel + { + std::stack, std::vector>> coordStack; + + #pragma omp for schedule(dynamic,128) nowait + for(uint16_t i = yStart;i= 0 ;i--) + floodFill4Impl(i, xEnd - 1, xStart, xEnd, yStart, yEnd, mask, coordStack); + + #pragma omp sections nowait + { + #pragma omp section + { + uint16_t i = yStart; + + for(uint16_t j = xStart; j < xEnd; j++) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yStart; + + for(uint16_t j = xEnd - 1; j >= xStart; j--) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yEnd; + + for(uint16_t j = xStart; j < xEnd; j++) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yEnd; + + for(uint16_t j = xEnd - 1; j >= xStart; j--) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + } + } +} + + } using namespace std; using namespace rtengine; - +#ifdef __OLDPS__ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize_, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross) { @@ -276,6 +438,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoModel; int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); + if(model.find("K-3") != string::npos) { nRead = nReadK3II[nReadIndex]; eperIsoModel = ePerIsoK3II; @@ -292,7 +455,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); float eperIsoGreen = eperIso * scaleGreen; - printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); +// printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); prnu /= 100.f; stddevFactorGreen *= stddevFactorGreen; @@ -347,9 +510,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float eperIsoNonGreen2 = eperIso / scale_mul[2]; float stddevFactorNonGreen0 = stddevFactorRed; float stddevFactorNonGreen2 = stddevFactorBlue; + bool blueRow = false; if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels + blueRow = true; std::swap(nonGreenDest0, nonGreenDest1); std::swap(scaleNonGreen0, scaleNonGreen2); std::swap(eperIsoNonGreen0, eperIsoNonGreen2); @@ -365,90 +530,90 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(detectMotion || adaptive) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); } else if(gridSize == 5) { // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); } else if(gridSize == 7) { // compute maximum of differences for first six columns of 7x7 grid - greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); - greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[0] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 3], (*rawDataFrames[3 - offset])[i + offset - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 3], (*rawDataFrames[2 + offset])[i - offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 3], (*rawDataFrames[3 - offset])[i + offset - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 3], (*rawDataFrames[2 + offset])[i - offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 3], (*rawDataFrames[3 - offset])[i + offset + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 3], (*rawDataFrames[2 + offset])[i - offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 3], (*rawDataFrames[3 - offset])[i + offset + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j - 2], (*rawDataFrames[2 + offset])[i - offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j - 2], (*rawDataFrames[3 - offset])[i + offset - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j - 2], (*rawDataFrames[2 + offset])[i - offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j - 2], (*rawDataFrames[3 - offset])[i + offset][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j - 2], (*rawDataFrames[2 + offset])[i - offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j - 2], (*rawDataFrames[3 - offset])[i + offset + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j - 2], (*rawDataFrames[2 + offset])[i - offset + 4][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j - 1], (*rawDataFrames[3 - offset])[i + offset - 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j - 1], (*rawDataFrames[2 + offset])[i - offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j - 1], (*rawDataFrames[3 - offset])[i + offset - 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j - 1], (*rawDataFrames[2 + offset])[i - offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j - 1], (*rawDataFrames[3 - offset])[i + offset + 1][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j - 1], (*rawDataFrames[2 + offset])[i - offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j - 1], (*rawDataFrames[3 - offset])[i + offset + 3][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j], (*rawDataFrames[2 + offset])[i - offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j], (*rawDataFrames[3 - offset])[i + offset - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j], (*rawDataFrames[2 + offset])[i - offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j], (*rawDataFrames[2 + offset])[i - offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j], (*rawDataFrames[3 - offset])[i + offset + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j], (*rawDataFrames[2 + offset])[i - offset + 4][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[4] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 1], (*rawDataFrames[3 - offset])[i + offset - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 1], (*rawDataFrames[2 + offset])[i - offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 1], (*rawDataFrames[2 + offset])[i - offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 1], (*rawDataFrames[3 - offset])[i + offset + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[5] = std::max({greenDiff((*rawDataFrames[0 + offset])[i + offset - 3][j + 2], (*rawDataFrames[2 + offset])[i - offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 3][j + 2], (*rawDataFrames[2 + offset])[i - offset + 4][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); } } @@ -468,34 +633,34 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's the method from dcrawps - gridMax = greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); + gridMax = greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j], (*rawDataFrames[3 - offset])[i + offset][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i); skipNext = skip; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 1], (*rawDataFrames[3 - offset])[i + offset - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 1], (*rawDataFrames[2 + offset])[i - offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 1], (*rawDataFrames[3 - offset])[i + offset + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 1][j + 2], (*rawDataFrames[3 - offset])[i + offset - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 1][j + 2], (*rawDataFrames[2 + offset])[i - offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 1][j + 2], (*rawDataFrames[3 - offset])[i + offset][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 1][j + 2], (*rawDataFrames[2 + offset])[i - offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 3][j + 2], (*rawDataFrames[3 - offset])[i + offset + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion), - greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion) - }); + greenDifMax[lastIndex] = std::max({greenDiff((*rawDataFrames[1 - offset])[i - offset - 2][j + 3], (*rawDataFrames[3 - offset])[i + offset - 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset - 2][j + 3], (*rawDataFrames[2 + offset])[i - offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset][j + 3], (*rawDataFrames[3 - offset])[i + offset - 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset][j + 3], (*rawDataFrames[2 + offset])[i - offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 2][j + 3], (*rawDataFrames[3 - offset])[i + offset + 1][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[0 + offset])[i + offset + 2][j + 3], (*rawDataFrames[2 + offset])[i - offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff((*rawDataFrames[1 - offset])[i - offset + 4][j + 3], (*rawDataFrames[3 - offset])[i + offset + 3][j + 4], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } @@ -528,29 +693,102 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; - float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; - float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; - float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + float diffRight = ngRight - ngCentre; + float diffLeft = ngLeft - ngCentre; + float diffHorNg0 = -1.f; - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); - continue; + if(diffRight * diffLeft >= 0.f) { + float avg = (ngRight + ngLeft) / 2.f; + diffHorNg0 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); + +// if(diff > 0.f) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } } + float diffHorNg1 = -1.f; ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; - ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; - ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; - diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + diffRight = ngRight - ngCentre; + diffLeft = ngLeft - ngCentre; - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); - continue; + if(diffRight * diffLeft >= 0.f) { + float avg = (ngRight + ngLeft) / 2.f; + float diffHorNg1 = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); + +// if(diff > 0.f) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); +// continue; +// } } + + if( diffHorNg0 * diffHorNg1 < 0.f) { + paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); + continue; + + } + +// bool motion = false; +// float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; +// float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; +// float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; +// float ngTop = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i][j + offset]; +// float ngBottom = (*rawDataFrames[((offset << 1) + offset) ^ 1])[i + 2][j + offset]; +// float diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); +// +// if(diff > 0.f) { +// motion = true; +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } +// +// ngCentre = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; +// ngRight = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1) + 2]; +// ngLeft = (*rawDataFrames[2 - (offset ^ 1)])[i + 1][j - (offset ^ 1)]; +// ngTop = (*rawDataFrames[3 - ((offset << 1) + offset)])[i - 1][j - offset + 1]; +// ngBottom = (*rawDataFrames[3 - ((offset << 1) + offset)])[i + 1][j - offset + 1]; +// diff = nonGreenDiffCross(ngRight, ngLeft, ngTop, ngBottom, ngCentre, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); +// +//// if(diff > 0.f) { +// if((diff > 0.f && !motion) || (diff <= 0.f && motion) ) { +// paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); +// continue; +// } } if(adaptive && checkNonGreenHorizontal) { +// float lg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j - 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j]) / 2.f; +// float cg = ((*rawDataFrames[1 - offset])[i - offset + 1][j] + (*rawDataFrames[3 - offset])[i + offset][j + 1]) / 2.f; +// float rg = ((*rawDataFrames[1 - (offset^1)])[i - (offset^1) + 1][j + 1] + (*rawDataFrames[3 - (offset^1)])[i + (offset^1)][j + 2]) / 2.f; +// +// float lr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) - 1]; +// float cr = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; +// float rr = (*rawDataFrames[((offset^1) << 1) + (offset^1)])[i][j + (offset^1) + 1]; +// +// float lb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1)]; +// float cb = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; +// float rb = (*rawDataFrames[2 - (offset^1)])[i + 1][j - (offset^1) + 2]; +// +// if(blueRow) { +// std::swap(lr, lb); +// std::swap(cr, cb); +// std::swap(rr, rb); +// } +// +// float lh = Color::rgb2h(lr, lg, lb); +// float ch = Color::rgb2h(cr, cg, cb); +// float rh = Color::rgb2h(rr, rg, rb); +// +// float lHueDiff = lh - ch; +// float rHueDiff = rh - ch; +// if(lHueDiff * rHueDiff > 0.f) { +// if(std::fabs(lHueDiff) > 0.5f && std::fabs(rHueDiff) > 0.5f/* && std::fabs(lHueDiff) < 3.f && std::fabs(rHueDiff) < 3.f*/) { +// paintMotionMask(j + offsX, showMotion, 1.f, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); +// continue; +// } +// } float ngCentre = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; float ngRight = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) + 1]; float ngLeft = (*rawDataFrames[((offset ^ 1) << 1) + (offset ^ 1)])[i][j + (offset ^ 1) - 1]; @@ -637,3 +875,764 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det plistener->setProgress(1.0); } } +#else +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection) +{ + + BENCHFUN + + const bool detectMotion = bayerParams.pixelShiftMotion > 0; + const int motion = bayerParams.pixelShiftMotion; + const bool showMotion = bayerParams.pixelshiftShowMotion; + const bool showOnlyMask = bayerParams.pixelshiftShowMotionMaskOnly; + const RAWParams::BayerSensor::ePSMotionCorrection gridSize_ = bayerParams.pixelShiftMotionCorrection; + const bool adaptive = bayerParams.pixelShiftAutomatic; + float stddevFactorGreen = bayerParams.pixelShiftStddevFactorGreen; + float stddevFactorRed = bayerParams.pixelShiftStddevFactorRed; + float stddevFactorBlue = bayerParams.pixelShiftStddevFactorBlue; + float eperIso = bayerParams.pixelShiftEperIso; + float nreadIso = bayerParams.pixelShiftNreadIso; + float prnu = bayerParams.pixelShiftPrnu; + const bool checkNonGreenHorizontal = bayerParams.pixelShiftNonGreenHorizontal; + const bool checkNonGreenVertical = bayerParams.pixelShiftNonGreenVertical; + const bool checkNonGreenCross = bayerParams.pixelShiftNonGreenCross; + const bool checkNonGreenAmaze = bayerParams.pixelShiftNonGreenAmaze; + const bool checkNonGreenCross2 = bayerParams.pixelShiftNonGreenCross2; + const bool checkGreen = bayerParams.pixelShiftGreen; + const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight; + const bool blurMap = bayerParams.pixelShiftBlur; + const float sigma = bayerParams.pixelShiftSigma; + const float threshold = bayerParams.pixelShiftSum; + const bool experimental0 = bayerParams.pixelShiftExp0; + const bool holeFill = bayerParams.pixelShiftHoleFill; + + static const float nReadK3II[] = { 3.4f, // ISO 100 + 3.1f, // ISO 125 + 2.5f, // ISO 160 + 2.5f, // ISO 200 + 2.5f, // ISO 250 + 2.5f, // ISO 320 + 2.3f, // ISO 400 + 2.5f, // ISO 500 + 2.3f, // ISO 640 + 2.3f, // ISO 800 + 2.4f, // ISO 1000 + 2.3f, // ISO 1250 + 1.75f, // ISO 1600 + 1.75f, // ISO 2000 + 1.75f, // ISO 2500 + 1.75f, // ISO 3200 + 1.75f, // ISO 4000 + 1.75f, // ISO 5000 + 1.75f, // ISO 6400 + 1.75f, // ISO 8000 + 1.75f, // ISO 10000 + 1.5f, // ISO 12800 + 1.5f, // ISO 16000 + 1.5f, // ISO 20000 + 1.5f, // ISO 25600 + 1.5f, // ISO 32000 + 1.5f, // ISO 40000 + 1.5f, // ISO 51200 + 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK3II = 4 * 0.35f; + + static const float nReadK1[] = { 3.45f, // ISO 100 + 3.15f, // ISO 125 + 3.45f, // ISO 160 + 3.0f, // ISO 200 + 3.0f, // ISO 250 + 3.0f, // ISO 320 + 2.7f, // ISO 400 + 2.7f, // ISO 500 + 2.7f, // ISO 640 + 2.5f, // ISO 800 + 2.5f, // ISO 1000 + 2.5f, // ISO 1250 + 2.4f, // ISO 1600 + 2.4f, // ISO 2000 + 2.4f, // ISO 2500 + 2.4f, // ISO 3200 + 2.4f, // ISO 4000 + 2.4f, // ISO 5000 + 2.4f, // ISO 6400 + 2.4f, // ISO 8000 + 2.4f, // ISO 10000 + 2.4f, // ISO 12800 + 2.4f, // ISO 16000 + 2.4f, // ISO 20000 + 2.4f, // ISO 25600 + 2.4f, // ISO 32000 + 2.4f, // ISO 40000 + 2.4f, // ISO 51200 + 2.4f, // ISO 64000 + 2.4f, // ISO 80000 + 2.4f, // ISO 102400 + 2.4f, // ISO 128000 + 2.4f, // ISO 160000 + 2.4f // ISO 204800 + }; + + static const float ePerIsoK1 = 4 * 0.75f; + + static const float nReadK70[] = { 4.0f, // ISO 100 + 4.0f, // ISO 125 + 4.0f, // ISO 160 + 4.0f, // ISO 200 + 4.0f, // ISO 250 + 4.0f, // ISO 320 + 4.0f, // ISO 400 + 4.0f, // ISO 500 + 4.0f, // ISO 640 + 3.0f, // ISO 800 + 3.0f, // ISO 1000 + 3.0f, // ISO 1250 + 3.0f, // ISO 1600 + 3.0f, // ISO 2000 + 3.0f, // ISO 2500 + 3.0f, // ISO 3200 + 3.0f, // ISO 4000 + 3.0f, // ISO 5000 + 3.0f, // ISO 6400 + 3.0f, // ISO 8000 + 3.0f, // ISO 10000 + 3.0f, // ISO 12800 + 3.0f, // ISO 16000 + 3.0f, // ISO 20000 + 3.0f, // ISO 25600 + 3.0f, // ISO 32000 + 3.0f, // ISO 40000 + 3.0f, // ISO 51200 + 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) + }; + + static const float ePerIsoK70 = 4 * 0.5f; + + if (plistener) { + plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); + plistener->setProgress(0.0); + } + + + const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); + int gridSize = 1; + bool nOf3x3 = false; + + switch (gridSize_) { + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: + case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: + gridSize = 1; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3: + gridSize = 3; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid5x5: + gridSize = 5; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid7x7: + gridSize = 7; + break; + + case RAWParams::BayerSensor::ePSMotionCorrection::Grid3x3New: + gridSize = 1; + nOf3x3 = true; + } + + // Lookup table for non adaptive (slider) mode + LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); + + if(detectMotion && !adaptive) { + const float lutStrength = 2.f; + log2Lut[0] = 0; + + for(int i = 2; i < 65536; i += 2) { + log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; + } + } + + const float scaleGreen = 1.f / scale_mul[1]; + + float nRead; + float eperIsoModel; + + int nReadIndex = static_cast(round(log2(idata->getISOSpeed() / 100.f) * 3.f)); + + if(model.find("K-3") != string::npos) { + nRead = nReadK3II[nReadIndex]; + eperIsoModel = ePerIsoK3II; + } else if(model.find("K-1") != string::npos) { + nRead = nReadK1[nReadIndex]; + eperIsoModel = ePerIsoK1; + } else { + nRead = nReadK70[nReadIndex]; + eperIsoModel = ePerIsoK70; + } + + nRead *= pow(2.f, nreadIso); + eperIsoModel *= pow(2.f, eperIso); + eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); + + float eperIsoRed = eperIso / scale_mul[0]; + float eperIsoGreen = eperIso * scaleGreen; + float eperIsoBlue = eperIso / scale_mul[2]; + +// printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); + + prnu /= 100.f; + stddevFactorGreen *= stddevFactorGreen; + stddevFactorRed *= stddevFactorRed; + stddevFactorBlue *= stddevFactorBlue; + + + nRead *= nRead; + + // If the values of two corresponding green pixels differ my more then motionThreshold %, the pixel will be treated as a badGreen pixel + float motionThreshold = 1.f - (motion / 100.f); + // For shades of green motion indicators + const float blendFactor = ((adaptive || motion == 0.f) ? 1.f : 1.f / (1.f - motionThreshold)); + + unsigned int offsX = 0, offsY = 0; + + if(!bayerParams.pixelShiftMedian || !adaptive) { + // We have to adjust the offsets for the selected subframe we use for areas with motion + switch (frame) { + case 0: + offsX = offsY = 0; + break; + + case 1: + offsX = 0; + offsY = 1; + break; + + case 2: + offsX = offsY = 1; + break; + + case 3: + offsX = 1; + offsY = 0; + } + } + + const float thresh = adaptive ? 0.f : motionThreshold; + array2D psRed(winw + 32, winh); // increase width to avoid cache conflicts + array2D psG1(winw + 32, winh); + array2D psG2(winw + 32, winh); + array2D psBlue(winw + 32, winh); + + array2D psMask(winw, winh, ARRAY2D_CLEAR_DATA); +// fill channels psRed, psG1, psG2 and psBlue +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + 1; i < winh - 1; ++i) { + float *greenDest1 = psG1[i]; + float *greenDest2 = psG2[i]; + float *nonGreenDest0 = psRed[i]; + float *nonGreenDest1 = psBlue[i]; + int j = winx + 1; + int c = FC(i, j); + + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels + std::swap(nonGreenDest0, nonGreenDest1); + std::swap(greenDest1, greenDest2); + } + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); + offset ^= 1; // 0 => 1 or 1 => 0 + + for(; j < winw - 1; ++j) { + offset ^= 1; // 0 => 1 or 1 => 0 + + // store the values from the 4 frames into 4 different temporary planes + greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j]; + greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1]; + nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; + nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + } + } + +// now that the temporary planes are filled for easy access we do the motion detection + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *redDest = red[i + offsY]; + float *blueDest = blue[i + offsY]; + int j = winx + border - offsX; + + float greenDifMax[gridSize]; // Here we store the maximum differences per Column + + // green channel motion detection checks the grid around the pixel for differences in green channels + if(detectMotion || (adaptive && checkGreen)) { + if(gridSize == 3) { + // compute maximum of differences for first two columns of 3x3 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } else if(gridSize == 5) { + // compute maximum of differences for first four columns of 5x5 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } else if(gridSize == 7) { + // compute maximum of differences for first six columns of 7x7 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } + + } + + + // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 + int lastIndex = gridSize - 1; + float korr = 0.f; + int c = FC(i, j); + bool blueRow = false; + + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels + blueRow = true; + } + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); +// offset ^= 1; // 0 => 1 or 1 => 0 + + for(; j < winw - (border + offsX); ++j) { + bool greenFromPs = false; + offset ^= 1; // 0 => 1 or 1 => 0 + + if(detectMotion || (adaptive && checkGreen)) { + bool skipNext = false; + float gridMax; + + if(gridSize < 2) { + // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps + gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i); + skipNext = skip; + } else if(gridSize == 3) { + // compute maximum of differences for third column of 3x3 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); + } else if(gridSize == 5) { + // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); + } else if(gridSize == 7) { + // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); + } + + + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; + + // increase motion detection dependent on brightness + if(!adaptive) { + korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; + } + + if (gridMax > thresh - korr) { + if(nOf3x3) { + psMask[i][j] = 1.f; + } else if((offset == (frame & 1)) && checkNonGreenVertical) { + if(frame > 1) { + green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; + } else { + green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; + } + + continue; + } else { + // at least one of the tested green pixels of the grid is detected as motion + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + } + + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; + } + } + } + + if(adaptive && checkNonGreenCross) { + // check red cross + float redTop = psRed[i - 1][ j ]; + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + float redBottom = psRed[i + 1][ j ]; + float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } + + // check blue cross + float blueTop = psBlue[i - 1][ j ]; + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + float blueBottom = psBlue[i + 1][ j ]; + float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + + } + } + + if(adaptive && checkNonGreenHorizontal) { + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + + float redDiffLeft = redLeft - redCentre; + float redDiffRight = redRight - redCentre; + + if(redDiffLeft * redDiffRight >= 0.f) { + float redAvg = (redRight + redLeft) / 2.f; + float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiffHor > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } + } + + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + + float blueDiffLeft = blueLeft - blueCentre; + float blueDiffRight = blueRight - blueCentre; + + if(blueDiffLeft * blueDiffRight >= 0.f) { + float blueAvg = (blueRight + blueLeft) / 2.f; + float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiffHor > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + } + } + } + + if(adaptive && checkNonGreenVertical) { + // check red vertically + float redTop = psRed[i - 1][ j ]; + float redCentre = psRed[ i ][ j ]; + float redBottom = psRed[i + 1][ j ]; + + float redDiffTop = redTop - redCentre; + float redDiffBottom = redBottom - redCentre; + + if(redDiffTop * redDiffBottom >= 0.f) { + float redAvg = (redTop + redBottom) / 2.f; + float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } + } + + // check blue vertically + float blueTop = psBlue[i - 1][ j ]; + float blueCentre = psBlue[ i ][ j ]; + float blueBottom = psBlue[i + 1][ j ]; + + float blueDiffTop = blueTop - blueCentre; + float blueDiffBottom = blueBottom - blueCentre; + + if(blueDiffTop * blueDiffBottom >= 0.f) { + float blueAvg = (blueTop + blueBottom) / 2.f; + float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + } + } + } + + if(adaptive && checkNonGreenAmaze) { + // check current pixel against amaze + float redCentre = psRed[ i ][ j ]; + float redAmaze = red[i + offsY][j + offsX]; + + float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + + if(redDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } + + float blueCentre = psBlue[ i ][ j ]; + float blueAmaze = blue[i + offsY][j + offsX]; + + float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + } + } + + if(adaptive && checkNonGreenCross2) { // for green amaze + float greenCentre = (psG1[ i ][ j ] + psG2[ i ][ j ]) / 2.f; + float greenAmaze = green[i + offsY][j + offsX]; + float greenDiffAmaze = nonGreenDiff(greenCentre, greenAmaze, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); + + if(greenDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = 1.f; + } else { + paintMotionMask(j + offsX, showMotion, greenDiffAmaze, showOnlyMask, greenDest, redDest, blueDest); + } + + continue; + } + } + + if(adaptive && experimental0) { // for experiments + + } + + if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; + } else if(!(adaptive && nOf3x3)) { + // no motion detected, replace the a priori demosaiced values by the pixelshift combined values + red[i + offsY][j + offsX] = psRed[i][j]; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + blue[i + offsY][j + offsX] = psBlue[i][j]; + } + } + } + + if(adaptive && nOf3x3) { + if(blurMap) { + #pragma omp parallel + { + gaussianBlur(psMask, psMask, winw, winh, sigma); + } + } + + array2D mask(W, H, ARRAY2D_CLEAR_DATA); + array2D maskInv(W, H, ARRAY2D_CLEAR_DATA); + #pragma omp parallel for schedule(dynamic,16) + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *redDest = red[i + offsY]; + float *blueDest = blue[i + offsY]; + int j = winx + border - offsX; + float v3sum[3] = {0.f}; + + for(int v = -1; v <= 1; v++) { + for(int h = -1; h < 1; h++) { + v3sum[1 + h] += psMask[i + v][j + h]; + } + } + + float blocksum = v3sum[0] + v3sum[1]; + + for(int voffset = 2; j < winw - (border + offsX); ++j, ++voffset) { + float colSum = psMask[i - 1][j + 1] + psMask[i][j + 1] + psMask[i + 1][j + 1]; + voffset = voffset == 3 ? 0 : voffset; // faster than voffset %= 3; + blocksum -= v3sum[voffset]; + blocksum += colSum; + v3sum[voffset] = colSum; + + if(blocksum >= threshold) { + mask[i][j] = 255; + } + } + } + + if(holeFill) { + invertMask(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), mask, maskInv); + floodFill4(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), maskInv); + xorMasks(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), maskInv, mask); + } + + #pragma omp parallel for schedule(dynamic,16) + + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *redDest = red[i + offsY]; + float *blueDest = blue[i + offsY]; + + for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { + if(mask[i][j] == 255 ) { + paintMotionMask(j + offsX, showMotion, 0.5f, showOnlyMask, greenDest, redDest, blueDest); + continue; + } + + if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; + } else { + red[i + offsY][j + offsX] = psRed[i][j]; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + blue[i + offsY][j + offsX] = psBlue[i][j]; + } + } + } + } + + if(plistener) { + plistener->setProgress(1.0); + } +} +#endif \ No newline at end of file diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 747d60cb4..4526b13f3 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -485,6 +485,17 @@ enum ProcEvent { EvPixelShiftNonGreenCross = 455, EvPixelShiftStddevFactorRed = 456, EvPixelShiftStddevFactorBlue = 457, + EvPixelShiftGreenAmaze = 458, + EvPixelShiftNonGreenAmaze = 459, + EvPixelShiftGreen = 460, + EvPixelShiftRedBlueWeight = 461, + EvPixelShiftBlur = 462, + EvPixelShiftSigma = 463, + EvPixelShiftSum = 464, + EvPixelShiftExp0 = 465, + EvPixelShiftHoleFill = 466, + EvPixelShiftMedian = 467, + EvPixelShiftMedian3 = 468, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5fd8b17ff..a7443a87c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -886,19 +886,30 @@ void RAWParams::setDefaults() //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; bayersensor.pixelShiftMotion = 0; - bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid1x2; - bayersensor.pixelShiftStddevFactorGreen = 3.0; - bayersensor.pixelShiftStddevFactorRed = 3.0; - bayersensor.pixelShiftStddevFactorBlue = 3.0; + bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid3x3New; + bayersensor.pixelShiftStddevFactorGreen = 5.0; + bayersensor.pixelShiftStddevFactorRed = 5.0; + bayersensor.pixelShiftStddevFactorBlue = 5.0; bayersensor.pixelShiftEperIso = 0.0; bayersensor.pixelShiftNreadIso = 0.0; bayersensor.pixelShiftPrnu = 1.0; + bayersensor.pixelShiftSigma = 1.0; + bayersensor.pixelShiftSum = 3.0; + bayersensor.pixelShiftRedBlueWeight = 0.7; bayersensor.pixelshiftShowMotion = false; bayersensor.pixelshiftShowMotionMaskOnly = false; bayersensor.pixelShiftAutomatic = true; bayersensor.pixelShiftNonGreenHorizontal = false; bayersensor.pixelShiftNonGreenVertical = false; - bayersensor.pixelShiftNonGreenCross = false; + bayersensor.pixelShiftHoleFill = true; + bayersensor.pixelShiftMedian = false; + bayersensor.pixelShiftMedian3 = false; + bayersensor.pixelShiftGreen = true; + bayersensor.pixelShiftBlur = true; + bayersensor.pixelShiftExp0 = false; + bayersensor.pixelShiftNonGreenCross = true; + bayersensor.pixelShiftNonGreenCross2 = false; + bayersensor.pixelShiftNonGreenAmaze = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3410,6 +3421,18 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_double ("RAW Bayer", "PixelShiftPrnu", raw.bayersensor.pixelShiftPrnu ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftSigma) { + keyFile.set_double ("RAW Bayer", "PixelShiftSigma", raw.bayersensor.pixelShiftSigma ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftSum) { + keyFile.set_double ("RAW Bayer", "PixelShiftSum", raw.bayersensor.pixelShiftSum ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftRedBlueWeight) { + keyFile.set_double ("RAW Bayer", "PixelShiftRedBlueWeight", raw.bayersensor.pixelShiftRedBlueWeight ); + } + if (!pedited || pedited->raw.bayersensor.pixelshiftShowMotion) { keyFile.set_boolean ("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelshiftShowMotion ); } @@ -3430,11 +3453,41 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenVertical", raw.bayersensor.pixelShiftNonGreenVertical ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftHoleFill) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftHoleFill", raw.bayersensor.pixelShiftHoleFill ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftMedian) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftMedian3) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian3 ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftGreen) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftGreen", raw.bayersensor.pixelShiftGreen ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftBlur) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftBlur", raw.bayersensor.pixelShiftBlur ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftExp0) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftExp0", raw.bayersensor.pixelShiftExp0 ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross) { keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); } - //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross2) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross2", raw.bayersensor.pixelShiftNonGreenCross2 ); + } + + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenAmaze) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenAmaze", raw.bayersensor.pixelShiftNonGreenAmaze ); + } if (!pedited || pedited->raw.xtranssensor.method) { keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); @@ -7556,6 +7609,30 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftSigma")) { + raw.bayersensor.pixelShiftSigma = keyFile.get_double("RAW Bayer", "PixelShiftSigma"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftSigma = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftSum")) { + raw.bayersensor.pixelShiftSum = keyFile.get_double("RAW Bayer", "PixelShiftSum"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftSum = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "PixelShiftRedBlueWeight")) { + raw.bayersensor.pixelShiftRedBlueWeight = keyFile.get_double("RAW Bayer", "PixelShiftRedBlueWeight"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftRedBlueWeight = true; + } + } + if (keyFile.has_key ("RAW Bayer", "PixelShiftShowMotion")) { raw.bayersensor.pixelshiftShowMotion = keyFile.get_boolean("RAW Bayer", "PixelShiftShowMotion"); @@ -7596,6 +7673,54 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftHoleFill")) { + raw.bayersensor.pixelShiftHoleFill = keyFile.get_boolean("RAW Bayer", "pixelShiftHoleFill"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftHoleFill = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftMedian")) { + raw.bayersensor.pixelShiftMedian = keyFile.get_boolean("RAW Bayer", "pixelShiftMedian"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftMedian = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftMedian3")) { + raw.bayersensor.pixelShiftMedian3 = keyFile.get_boolean("RAW Bayer", "pixelShiftMedian3"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftMedian3 = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftGreen")) { + raw.bayersensor.pixelShiftGreen = keyFile.get_boolean("RAW Bayer", "pixelShiftGreen"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftGreen = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftBlur")) { + raw.bayersensor.pixelShiftBlur = keyFile.get_boolean("RAW Bayer", "pixelShiftBlur"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftBlur = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftExp0")) { + raw.bayersensor.pixelShiftExp0 = keyFile.get_boolean("RAW Bayer", "pixelShiftExp0"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftExp0 = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross")) { raw.bayersensor.pixelShiftNonGreenCross = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross"); @@ -7604,7 +7729,21 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - //if (keyFile.has_key ("RAW Bayer", "ALLEnhance")) { raw.bayersensor.all_enhance = keyFile.get_boolean("RAW Bayer", "ALLEnhance"); if (pedited) pedited->raw.bayersensor.allEnhance = true; } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross2")) { + raw.bayersensor.pixelShiftNonGreenCross2 = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross2"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenCross2 = true; + } + } + + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenAmaze")) { + raw.bayersensor.pixelShiftNonGreenAmaze = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenAmaze"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftNonGreenAmaze = true; + } + } } // load X-Trans sensors' raw settings @@ -8051,14 +8190,24 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso && raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso && raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu + && raw.bayersensor.pixelShiftSigma == other.raw.bayersensor.pixelShiftSigma + && raw.bayersensor.pixelShiftSum == other.raw.bayersensor.pixelShiftSum + && raw.bayersensor.pixelShiftRedBlueWeight == other.raw.bayersensor.pixelShiftRedBlueWeight && raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion && raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly && raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic && raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal && raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical + && raw.bayersensor.pixelShiftHoleFill == other.raw.bayersensor.pixelShiftHoleFill + && raw.bayersensor.pixelShiftMedian == other.raw.bayersensor.pixelShiftMedian + && raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3 + && raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen + && raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur + && raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0 && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross + && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 + && raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze && raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance - //&& raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance && raw.xtranssensor.method == other.raw.xtranssensor.method && raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps && raw.xtranssensor.blackred == other.raw.xtranssensor.blackred diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0c06fa315..c3c8296b7 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1188,7 +1188,7 @@ public: numMethods }; // This MUST be the last enum enum ePSMotionCorrection { - Grid1x1, Grid1x2, Grid3x3, Grid5x5, Grid7x7 + Grid1x1, Grid1x2, Grid3x3, Grid5x5, Grid7x7, Grid3x3New }; static const char *methodstring[numMethods]; @@ -1212,12 +1212,23 @@ public: double pixelShiftEperIso; double pixelShiftNreadIso; double pixelShiftPrnu; + double pixelShiftSigma; + double pixelShiftSum; + double pixelShiftRedBlueWeight; bool pixelshiftShowMotion; bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; + bool pixelShiftHoleFill; + bool pixelShiftMedian; + bool pixelShiftMedian3; + bool pixelShiftGreen; + bool pixelShiftBlur; + bool pixelShiftExp0; bool pixelShiftNonGreenCross; + bool pixelShiftNonGreenCross2; + bool pixelShiftNonGreenAmaze; bool dcb_enhance; //bool all_enhance; }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 36b78aa20..566fc77a3 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2022,13 +2022,107 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::ahd] ) { ahd_demosaic (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze] ) { - amaze_demosaic_RT (0, 0, W, H); + amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift] ) { - if(raw.bayersensor.pixelShiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) { - amaze_demosaic_RT (0, 0, W, H); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction - } - if(numFrames == 4) { - pixelshift(0, 0, W, H, raw.bayersensor.pixelShiftMotion > 0, raw.bayersensor.pixelShiftMotion, raw.bayersensor.pixelshiftShowMotion, raw.bayersensor.pixelshiftShowMotionMaskOnly, currFrame, raw.bayersensor.pixelShiftMotionCorrection, raw.bayersensor.pixelShiftAutomatic, raw.bayersensor.pixelShiftStddevFactorGreen, raw.bayersensor.pixelShiftStddevFactorRed, raw.bayersensor.pixelShiftStddevFactorBlue, raw.bayersensor.pixelShiftEperIso, raw.bayersensor.pixelShiftNreadIso, raw.bayersensor.pixelShiftPrnu, ri->get_model(), raw.expos, raw.bayersensor.pixelShiftNonGreenHorizontal, raw.bayersensor.pixelShiftNonGreenVertical, raw.bayersensor.pixelShiftNonGreenCross); + if(numFrames != 4) { // fallback for non pixelshift files + amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); + } else { + if(!raw.bayersensor.pixelshiftShowMotion || raw.bayersensor.pixelShiftNonGreenAmaze || raw.bayersensor.pixelShiftNonGreenCross2) { + if((raw.bayersensor.pixelShiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) && numFrames == 4) { + if(raw.bayersensor.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction + if(!raw.bayersensor.pixelShiftMedian3) { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[0]), red, green, blue); + multi_array2D redTmp(W,H); + multi_array2D greenTmp(W,H); + multi_array2D blueTmp(W,H); + for(int i=0;i<3;i++) { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i]); + } + #pragma omp parallel for schedule(dynamic,16) + for(int i=border;i redTmp(W,H); + multi_array2D greenTmp(W,H); + multi_array2D blueTmp(W,H); + for(int i=0, frameIndex = 0;i<4;++i) { + if(i != currFrame) { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex]); + ++frameIndex; + } + } + unsigned int offsX0 = 0, offsY0 = 0; + unsigned int offsX1 = 0, offsY1 = 0; + unsigned int offsX2 = 0, offsY2 = 0; + + // We have to adjust the offsets for the selected subframe we exclude from median + switch (currFrame) { + case 0: + offsY0 = 1; + offsX0 = 0; + offsY1 = 1; + offsX1 = 1; + offsY2 = 0; + offsX2 = 1; + break; + + case 1: + offsY0 = 0; + offsX0 = 0; + offsY1 = 1; + offsX1 = 1; + offsY2 = 0; + offsX2 = 1; + break; + + case 2: + offsY0 = 0; + offsX0 = 0; + offsY1 = 1; + offsX1 = 0; + offsY2 = 0; + offsX2 = 1; + break; + + case 3: + offsY0 = 0; + offsX0 = 0; + offsY1 = 1; + offsX1 = 0; + offsY2 = 1; + offsX2 = 1; + } + + #pragma omp parallel for schedule(dynamic,16) + for(int i=border;iget_model(), raw.expos); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index f80efeacf..d54bcd49d 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -237,7 +237,7 @@ protected: void jdl_interpolate_omp(); void igv_interpolate(int winw, int winh); void lmmse_interpolate_omp(int winw, int winh, int iterations); - void amaze_demosaic_RT(int winx, int winy, int winw, int winh);//Emil's code for AMaZE + void amaze_demosaic_RT(int winx, int winy, int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue);//Emil's code for AMaZE void fast_demosaic(int winx, int winy, int winw, int winh );//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(int winx, int winy, int winw, int winh); @@ -261,7 +261,7 @@ protected: void xtransborder_interpolate (int border); void xtrans_interpolate (const int passes, const bool useCieLab); void fast_xtrans_interpolate (); - void pixelshift(int winx, int winy, int winw, int winh, bool detectMotion, int motion, bool showMotion, bool showOnlyMask, unsigned int frame, RAWParams::BayerSensor::ePSMotionCorrection gridSize, bool adaptive, float stddevFactorGreen, float stddevFactorRed, float stddevFactorBlue, float eperIso, float nreadIso, float prnu, const std::string &model, float rawWpCorrection, bool checkNonGreenHorizontal, bool checkNonGreenVertical, bool checkNonGreenCross); + void pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection); void hflip (Imagefloat* im); void vflip (Imagefloat* im); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 08e3d2520..3030a4319 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -484,7 +484,18 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftNonGreenVertical DEMOSAIC, // EvPixelShiftNonGreenCross DEMOSAIC, // EvPixelShiftStddevFactorRed - DEMOSAIC // EvPixelShiftStddevFactorBlue + DEMOSAIC, // EvPixelShiftStddevFactorBlue + DEMOSAIC, // EvPixelShiftNonGreenCross2 + DEMOSAIC, // EvPixelShiftNonGreenAmaze + DEMOSAIC, // EvPixelShiftGreen + DEMOSAIC, // EvPixelShiftRedBlueWeight + DEMOSAIC, // EvPixelShiftBlur + DEMOSAIC, // EvPixelShiftSigma + DEMOSAIC, // EvPixelShiftSum + DEMOSAIC, // EvPixelShiftExp0 + DEMOSAIC, // EvPixelShiftHoleFill + DEMOSAIC, // EvPixelShiftMedian + DEMOSAIC // EvPixelShiftMedian3 }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 297a9b65b..701463ac4 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -83,27 +83,58 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftOptions = Gtk::manage (new Gtk::VBox ()); pixelShiftOptions->set_border_width(4); + pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); + pixelShiftShowMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftShowMotion); pixelShiftShowMotionMaskOnly = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); + pixelShiftShowMotionMaskOnly->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftShowMotionMaskOnly); pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); + pixelShiftGreen = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTGREEN"))); + pixelShiftOptions->pack_start(*pixelShiftGreen); + + pixelShiftBlur = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTBLUR"))); + pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTBLUR_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftBlur); + + pixelShiftHoleFill = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); + pixelShiftHoleFill->set_tooltip_text (M("TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftHoleFill); + + pixelShiftMedian = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTMEDIAN"))); + pixelShiftMedian->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftMedian); + + pixelShiftMedian3 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTMEDIAN3"))); + pixelShiftMedian3->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftMedian3); + pixelShiftNonGreenCross = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); + pixelShiftNonGreenCross2 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenCross2); + + pixelShiftNonGreenAmaze = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenAmaze); + pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenVertical); + pixelShiftExp0 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTEXP0"))); + pixelShiftOptions->pack_start(*pixelShiftExp0); + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); - pixelShiftMotion->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); + pixelShiftMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); if (pixelShiftMotion->delay < options.adjusterMaxDelay) { pixelShiftMotion->delay = options.adjusterMaxDelay; @@ -119,13 +150,14 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->append_text("3x3"); pixelShiftMotionCorrection->append_text("5x5"); pixelShiftMotionCorrection->append_text("7x7"); + pixelShiftMotionCorrection->append_text("3x3 new"); pixelShiftMotionCorrection->set_active(0); // pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); pixelShiftMotionCorrection->show(); hb2->pack_start(*pixelShiftMotionCorrection); pixelShiftOptions->pack_start(*hb2); - pixelShiftStddevFactorGreen = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN"), 2, 8, 0.1, 3)); + pixelShiftStddevFactorGreen = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN"), 2, 8, 0.1, 5)); pixelShiftStddevFactorGreen->setAdjusterListener (this); if (pixelShiftStddevFactorGreen->delay < options.adjusterMaxDelay) { @@ -135,7 +167,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftStddevFactorGreen->show(); pixelShiftOptions->pack_start(*pixelShiftStddevFactorGreen); - pixelShiftStddevFactorRed = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORRED"), 1, 8, 0.1, 3)); + pixelShiftStddevFactorRed = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORRED"), 1, 8, 0.1, 5)); pixelShiftStddevFactorRed->setAdjusterListener (this); if (pixelShiftStddevFactorRed->delay < options.adjusterMaxDelay) { @@ -145,7 +177,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftStddevFactorRed->show(); pixelShiftOptions->pack_start(*pixelShiftStddevFactorRed); - pixelShiftStddevFactorBlue = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE"), 1, 8, 0.1, 3)); + pixelShiftStddevFactorBlue = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE"), 1, 8, 0.1, 5)); pixelShiftStddevFactorBlue->setAdjusterListener (this); if (pixelShiftStddevFactorBlue->delay < options.adjusterMaxDelay) { @@ -186,6 +218,36 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftPrnu->show(); pixelShiftOptions->pack_start(*pixelShiftPrnu); + pixelShiftSigma = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSIGMA"), 0.5, 2.5, 0.1, 1.0)); + pixelShiftSigma->setAdjusterListener (this); + + if (pixelShiftSigma->delay < options.adjusterMaxDelay) { + pixelShiftSigma->delay = options.adjusterMaxDelay; + } + + pixelShiftSigma->show(); + pixelShiftOptions->pack_start(*pixelShiftSigma); + + pixelShiftSum = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMASKTHRESHOLD"), 1.0, 8.0, 0.1, 3.0)); + pixelShiftSum->setAdjusterListener (this); + + if (pixelShiftSum->delay < options.adjusterMaxDelay) { + pixelShiftSum->delay = options.adjusterMaxDelay; + } + + pixelShiftSum->show(); + pixelShiftOptions->pack_start(*pixelShiftSum); + + pixelShiftRedBlueWeight = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTREDBLUEWEIGHT"), 0.1, 1.0, 0.1, 0.7)); + pixelShiftRedBlueWeight->setAdjusterListener (this); + + if (pixelShiftRedBlueWeight->delay < options.adjusterMaxDelay) { + pixelShiftRedBlueWeight->delay = options.adjusterMaxDelay; + } + + pixelShiftRedBlueWeight->show(); + pixelShiftOptions->pack_start(*pixelShiftRedBlueWeight); + pack_start( *pixelShiftOptions, Gtk::PACK_SHRINK, 4); @@ -216,8 +278,15 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); + pixelShiftHoleFillconn = pixelShiftHoleFill->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftHoleFillChanged), true); + pixelShiftMedianconn = pixelShiftMedian->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedianChanged), true); + pixelShiftMedian3conn = pixelShiftMedian3->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedian3Changed), true); + pixelShiftGreenconn = pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true); + pixelShiftBlurconn = pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true); + pixelShiftExp0conn = pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); + pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); + pixelShiftNonGreenAmazeconn = pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true); } @@ -250,8 +319,15 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftHoleFill->set_inconsistent(!pedited->raw.bayersensor.pixelShiftHoleFill); + pixelShiftMedian->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian); + pixelShiftMedian3->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian3); + pixelShiftGreen->set_inconsistent(!pedited->raw.bayersensor.pixelShiftGreen); + pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); + pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); - //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); + pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftStddevFactorGreen->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); @@ -260,6 +336,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); pixelShiftPrnu->setEditedState ( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); + pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); + pixelShiftSum->setEditedState ( pedited->raw.bayersensor.pixelShiftSum ? Edited : UnEdited); + pixelShiftRedBlueWeight->setEditedState ( pedited->raw.bayersensor.pixelShiftRedBlueWeight ? Edited : UnEdited); if(!pedited->raw.bayersensor.method) { method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name @@ -281,7 +360,15 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftHoleFill->set_active(pp->raw.bayersensor.pixelShiftHoleFill); + pixelShiftMedian->set_active(pp->raw.bayersensor.pixelShiftMedian); + pixelShiftMedian3->set_active(pp->raw.bayersensor.pixelShiftMedian3); + pixelShiftGreen->set_active(pp->raw.bayersensor.pixelShiftGreen); + pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); + pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); + pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); @@ -292,6 +379,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); + pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); + pixelShiftSum->setValue (pp->raw.bayersensor.pixelShiftSum); + pixelShiftRedBlueWeight->setValue (pp->raw.bayersensor.pixelShiftRedBlueWeight); if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || @@ -349,12 +439,23 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); + pp->raw.bayersensor.pixelShiftSigma = pixelShiftSigma->getValue(); + pp->raw.bayersensor.pixelShiftSum = pixelShiftSum->getValue(); + pp->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getValue(); pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); + pp->raw.bayersensor.pixelShiftHoleFill = pixelShiftHoleFill->get_active(); + pp->raw.bayersensor.pixelShiftMedian = pixelShiftMedian->get_active(); + pp->raw.bayersensor.pixelShiftMedian3 = pixelShiftMedian3->get_active(); + pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->get_active(); + pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); + pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->get_active(); int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -383,12 +484,23 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getEditedState (); pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); + pedited->raw.bayersensor.pixelShiftSigma = pixelShiftSigma->getEditedState (); + pedited->raw.bayersensor.pixelShiftSum = pixelShiftSum->getEditedState (); + pedited->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getEditedState (); pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = !pixelShiftShowMotionMaskOnly->get_inconsistent(); pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftHoleFill = !pixelShiftHoleFill->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftMedian = !pixelShiftMedian->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftMedian3 = !pixelShiftMedian3->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftGreen = !pixelShiftGreen->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftBlur = !pixelShiftBlur->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenAmaze = !pixelShiftNonGreenAmaze->get_inconsistent(); } } @@ -414,6 +526,9 @@ void BayerProcess::setBatchMode(bool batchMode) pixelShiftEperIso->showEditedCB (); pixelShiftNreadIso->showEditedCB (); pixelShiftPrnu->showEditedCB (); + pixelShiftSigma->showEditedCB (); + pixelShiftSum->showEditedCB (); + pixelShiftRedBlueWeight->showEditedCB (); } void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) @@ -427,6 +542,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setDefault( defParams->raw.bayersensor.pixelShiftNreadIso); pixelShiftPrnu->setDefault( defParams->raw.bayersensor.pixelShiftPrnu); + pixelShiftSigma->setDefault( defParams->raw.bayersensor.pixelShiftSigma); + pixelShiftSum->setDefault( defParams->raw.bayersensor.pixelShiftSum); + pixelShiftRedBlueWeight->setDefault( defParams->raw.bayersensor.pixelShiftRedBlueWeight); ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); if (pedited) { @@ -439,6 +557,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); pixelShiftPrnu->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); + pixelShiftSigma->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); + pixelShiftSum->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSum ? Edited : UnEdited); + pixelShiftRedBlueWeight->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftRedBlueWeight ? Edited : UnEdited); ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); } else { dcbIterations->setDefaultEditedState( Irrelevant ); @@ -450,6 +571,9 @@ void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams pixelShiftEperIso->setDefaultEditedState( Irrelevant ); pixelShiftNreadIso->setDefaultEditedState( Irrelevant ); pixelShiftPrnu->setDefaultEditedState( Irrelevant ); + pixelShiftSigma->setDefaultEditedState( Irrelevant ); + pixelShiftSum->setDefaultEditedState( Irrelevant ); + pixelShiftRedBlueWeight->setDefaultEditedState( Irrelevant ); ccSteps->setDefaultEditedState(Irrelevant ); } } @@ -477,6 +601,12 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvPixelShiftNreadIso, a->getTextValue() ); } else if (a == pixelShiftPrnu) { listener->panelChanged (EvPixelShiftPrnu, a->getTextValue() ); + } else if (a == pixelShiftSigma) { + listener->panelChanged (EvPixelShiftSigma, a->getTextValue() ); + } else if (a == pixelShiftSum) { + listener->panelChanged (EvPixelShiftSum, a->getTextValue() ); + } else if (a == pixelShiftRedBlueWeight) { + listener->panelChanged (EvPixelShiftRedBlueWeight, a->getTextValue() ); } } } @@ -631,12 +761,23 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftEperIso->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNreadIso->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftPrnu->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftSigma->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftSum->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftRedBlueWeight->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftStddevFactorGreen->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftStddevFactorRed->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftStddevFactorBlue->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftMedian->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftMedian3->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMedian->get_active()); + pixelShiftGreen->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftExp0->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenCross2->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftNonGreenAmaze->set_sensitive(pixelShiftAutomatic->get_active ()); if (listener) { listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); @@ -684,6 +825,128 @@ void BayerProcess::pixelShiftNonGreenVerticalChanged () } } +void BayerProcess::pixelShiftHoleFillChanged () +{ + if (batchMode) { + if (pixelShiftHoleFill->get_inconsistent()) { + pixelShiftHoleFill->set_inconsistent (false); + pixelShiftHoleFillconn.block (true); + pixelShiftHoleFill->set_active (false); + pixelShiftHoleFillconn.block (false); + } else if (lastDCBen) { + pixelShiftHoleFill->set_inconsistent (true); + } + + lastDCBen = pixelShiftHoleFill->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftHoleFill, pixelShiftHoleFill->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftMedianChanged () +{ + if (batchMode) { + if (pixelShiftMedian->get_inconsistent()) { + pixelShiftMedian->set_inconsistent (false); + pixelShiftMedianconn.block (true); + pixelShiftMedian->set_active (false); + pixelShiftMedianconn.block (false); + } else if (lastDCBen) { + pixelShiftMedian->set_inconsistent (true); + } + + lastDCBen = pixelShiftMedian->get_active (); + } + + pixelShiftMedian3->set_sensitive(pixelShiftMedian->get_active ()); + + if (listener) { + listener->panelChanged (EvPixelShiftMedian, pixelShiftMedian->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftMedian3Changed () +{ + if (batchMode) { + if (pixelShiftMedian3->get_inconsistent()) { + pixelShiftMedian3->set_inconsistent (false); + pixelShiftMedian3conn.block (true); + pixelShiftMedian3->set_active (false); + pixelShiftMedian3conn.block (false); + } else if (lastDCBen) { + pixelShiftMedian3->set_inconsistent (true); + } + + lastDCBen = pixelShiftMedian3->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftMedian3, pixelShiftMedian3->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftGreenChanged () +{ + if (batchMode) { + if (pixelShiftGreen->get_inconsistent()) { + pixelShiftGreen->set_inconsistent (false); + pixelShiftGreenconn.block (true); + pixelShiftGreen->set_active (false); + pixelShiftGreenconn.block (false); + } else if (lastDCBen) { + pixelShiftGreen->set_inconsistent (true); + } + + lastDCBen = pixelShiftGreen->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftGreen, pixelShiftGreen->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftBlurChanged () +{ + if (batchMode) { + if (pixelShiftBlur->get_inconsistent()) { + pixelShiftBlur->set_inconsistent (false); + pixelShiftBlurconn.block (true); + pixelShiftBlur->set_active (false); + pixelShiftBlurconn.block (false); + } else if (lastDCBen) { + pixelShiftBlur->set_inconsistent (true); + } + + lastDCBen = pixelShiftBlur->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftBlur, pixelShiftBlur->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftExp0Changed () +{ + if (batchMode) { + if (pixelShiftExp0->get_inconsistent()) { + pixelShiftExp0->set_inconsistent (false); + pixelShiftExp0conn.block (true); + pixelShiftExp0->set_active (false); + pixelShiftExp0conn.block (false); + } else if (lastDCBen) { + pixelShiftExp0->set_inconsistent (true); + } + + lastDCBen = pixelShiftExp0->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftExp0, pixelShiftExp0->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void BayerProcess::pixelShiftNonGreenCrossChanged () { if (batchMode) { @@ -704,21 +967,42 @@ void BayerProcess::pixelShiftNonGreenCrossChanged () } } - -/*void BayerProcess::allEnhanceChanged () +void BayerProcess::pixelShiftNonGreenCross2Changed () { if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); + if (pixelShiftNonGreenCross2->get_inconsistent()) { + pixelShiftNonGreenCross2->set_inconsistent (false); + pixelShiftNonGreenCross2conn.block (true); + pixelShiftNonGreenCross2->set_active (false); + pixelShiftNonGreenCross2conn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenCross2->set_inconsistent (true); } - else if (lastALLen) - allEnhance->set_inconsistent (true); - lastALLen = allEnhance->get_active (); + lastDCBen = pixelShiftNonGreenCross2->get_active (); } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ + + if (listener) { + listener->panelChanged (EvPixelShiftGreenAmaze, pixelShiftNonGreenCross2->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + +void BayerProcess::pixelShiftNonGreenAmazeChanged () +{ + if (batchMode) { + if (pixelShiftNonGreenAmaze->get_inconsistent()) { + pixelShiftNonGreenAmaze->set_inconsistent (false); + pixelShiftNonGreenAmazeconn.block (true); + pixelShiftNonGreenAmaze->set_active (false); + pixelShiftNonGreenAmazeconn.block (false); + } else if (lastDCBen) { + pixelShiftNonGreenAmaze->set_inconsistent (true); + } + + lastDCBen = pixelShiftNonGreenAmaze->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenAmaze, pixelShiftNonGreenAmaze->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index ca560ad89..79593debf 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -50,16 +50,30 @@ protected: Gtk::CheckButton* pixelShiftNonGreenHorizontal; Gtk::CheckButton* pixelShiftNonGreenVertical; Gtk::CheckButton* pixelShiftNonGreenCross; + Gtk::CheckButton* pixelShiftNonGreenCross2; + Gtk::CheckButton* pixelShiftNonGreenAmaze; + Gtk::CheckButton* pixelShiftGreen; + Gtk::CheckButton* pixelShiftBlur; + Gtk::CheckButton* pixelShiftExp0; + Gtk::CheckButton* pixelShiftHoleFill; + Gtk::CheckButton* pixelShiftMedian; + Gtk::CheckButton* pixelShiftMedian3; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; Adjuster* pixelShiftPrnu; + Adjuster* pixelShiftSigma; + Adjuster* pixelShiftSum; + Adjuster* pixelShiftRedBlueWeight; bool lastDCBen; int oldMethod; //bool lastALLen; - sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftNonGreenCrossconn; //,allEnhconn; + sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, + pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, + pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftHoleFillconn, pixelShiftMedianconn, pixelShiftMedian3conn, pixelShiftNonGreenCrossconn, + pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftExp0conn; public: BayerProcess (); @@ -79,8 +93,15 @@ public: void pixelShiftAutomaticChanged(); void pixelShiftNonGreenHorizontalChanged(); void pixelShiftNonGreenVerticalChanged(); + void pixelShiftHoleFillChanged(); + void pixelShiftMedianChanged(); + void pixelShiftMedian3Changed(); + void pixelShiftGreenChanged(); + void pixelShiftBlurChanged(); + void pixelShiftExp0Changed(); void pixelShiftNonGreenCrossChanged(); - //void allEnhanceChanged(); + void pixelShiftNonGreenCross2Changed(); + void pixelShiftNonGreenAmazeChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index f433ec639..b6127b7d2 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -378,12 +378,23 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftEperIso = v; raw.bayersensor.pixelShiftNreadIso = v; raw.bayersensor.pixelShiftPrnu = v; + raw.bayersensor.pixelShiftSigma = v; + raw.bayersensor.pixelShiftSum = v; + raw.bayersensor.pixelShiftRedBlueWeight = v; raw.bayersensor.pixelshiftShowMotion = v; raw.bayersensor.pixelshiftShowMotionMaskOnly = v; raw.bayersensor.pixelShiftAutomatic = v; raw.bayersensor.pixelShiftNonGreenHorizontal = v; raw.bayersensor.pixelShiftNonGreenVertical = v; + raw.bayersensor.pixelShiftHoleFill = v; + raw.bayersensor.pixelShiftMedian = v; + raw.bayersensor.pixelShiftMedian3 = v; + raw.bayersensor.pixelShiftGreen = v; + raw.bayersensor.pixelShiftBlur = v; + raw.bayersensor.pixelShiftExp0 = v; raw.bayersensor.pixelShiftNonGreenCross = v; + raw.bayersensor.pixelShiftNonGreenCross2 = v; + raw.bayersensor.pixelShiftNonGreenAmaze = v; raw.bayersensor.greenEq = v; raw.bayersensor.linenoise = v; raw.xtranssensor.method = v; @@ -888,12 +899,23 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; raw.bayersensor.pixelShiftNreadIso = raw.bayersensor.pixelShiftNreadIso && p.raw.bayersensor.pixelShiftNreadIso == other.raw.bayersensor.pixelShiftNreadIso; raw.bayersensor.pixelShiftPrnu = raw.bayersensor.pixelShiftPrnu && p.raw.bayersensor.pixelShiftPrnu == other.raw.bayersensor.pixelShiftPrnu; + raw.bayersensor.pixelShiftSigma = raw.bayersensor.pixelShiftSigma && p.raw.bayersensor.pixelShiftSigma == other.raw.bayersensor.pixelShiftSigma; + raw.bayersensor.pixelShiftSum = raw.bayersensor.pixelShiftSum && p.raw.bayersensor.pixelShiftSum == other.raw.bayersensor.pixelShiftSum; + raw.bayersensor.pixelShiftRedBlueWeight = raw.bayersensor.pixelShiftRedBlueWeight && p.raw.bayersensor.pixelShiftRedBlueWeight == other.raw.bayersensor.pixelShiftRedBlueWeight; raw.bayersensor.pixelshiftShowMotion = raw.bayersensor.pixelshiftShowMotion && p.raw.bayersensor.pixelshiftShowMotion == other.raw.bayersensor.pixelshiftShowMotion; raw.bayersensor.pixelshiftShowMotionMaskOnly = raw.bayersensor.pixelshiftShowMotionMaskOnly && p.raw.bayersensor.pixelshiftShowMotionMaskOnly == other.raw.bayersensor.pixelshiftShowMotionMaskOnly; raw.bayersensor.pixelShiftAutomatic = raw.bayersensor.pixelShiftAutomatic && p.raw.bayersensor.pixelShiftAutomatic == other.raw.bayersensor.pixelShiftAutomatic; raw.bayersensor.pixelShiftNonGreenHorizontal = raw.bayersensor.pixelShiftNonGreenHorizontal && p.raw.bayersensor.pixelShiftNonGreenHorizontal == other.raw.bayersensor.pixelShiftNonGreenHorizontal; raw.bayersensor.pixelShiftNonGreenVertical = raw.bayersensor.pixelShiftNonGreenVertical && p.raw.bayersensor.pixelShiftNonGreenVertical == other.raw.bayersensor.pixelShiftNonGreenVertical; + raw.bayersensor.pixelShiftHoleFill = raw.bayersensor.pixelShiftHoleFill && p.raw.bayersensor.pixelShiftHoleFill == other.raw.bayersensor.pixelShiftHoleFill; + raw.bayersensor.pixelShiftMedian = raw.bayersensor.pixelShiftMedian && p.raw.bayersensor.pixelShiftMedian == other.raw.bayersensor.pixelShiftMedian; + raw.bayersensor.pixelShiftMedian3 = raw.bayersensor.pixelShiftMedian3 && p.raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3; + raw.bayersensor.pixelShiftGreen = raw.bayersensor.pixelShiftGreen && p.raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen; + raw.bayersensor.pixelShiftBlur = raw.bayersensor.pixelShiftBlur && p.raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur; + raw.bayersensor.pixelShiftExp0 = raw.bayersensor.pixelShiftExp0 && p.raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; + raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; + 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.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; @@ -2338,6 +2360,18 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftPrnu = mods.raw.bayersensor.pixelShiftPrnu; } + if (raw.bayersensor.pixelShiftSigma) { + toEdit.raw.bayersensor.pixelShiftSigma = mods.raw.bayersensor.pixelShiftSigma; + } + + if (raw.bayersensor.pixelShiftSum) { + toEdit.raw.bayersensor.pixelShiftSum = mods.raw.bayersensor.pixelShiftSum; + } + + if (raw.bayersensor.pixelShiftRedBlueWeight) { + toEdit.raw.bayersensor.pixelShiftRedBlueWeight = mods.raw.bayersensor.pixelShiftRedBlueWeight; + } + if (raw.bayersensor.pixelshiftShowMotion) { toEdit.raw.bayersensor.pixelshiftShowMotion = mods.raw.bayersensor.pixelshiftShowMotion; } @@ -2358,11 +2392,42 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftNonGreenVertical = mods.raw.bayersensor.pixelShiftNonGreenVertical; } + if (raw.bayersensor.pixelShiftHoleFill) { + toEdit.raw.bayersensor.pixelShiftHoleFill = mods.raw.bayersensor.pixelShiftHoleFill; + } + + if (raw.bayersensor.pixelShiftMedian) { + toEdit.raw.bayersensor.pixelShiftMedian = mods.raw.bayersensor.pixelShiftMedian; + } + + if (raw.bayersensor.pixelShiftMedian3) { + toEdit.raw.bayersensor.pixelShiftMedian3 = mods.raw.bayersensor.pixelShiftMedian3; + } + + if (raw.bayersensor.pixelShiftGreen) { + toEdit.raw.bayersensor.pixelShiftGreen = mods.raw.bayersensor.pixelShiftGreen; + } + + if (raw.bayersensor.pixelShiftBlur) { + toEdit.raw.bayersensor.pixelShiftBlur = mods.raw.bayersensor.pixelShiftBlur; + } + + if (raw.bayersensor.pixelShiftExp0) { + toEdit.raw.bayersensor.pixelShiftExp0 = mods.raw.bayersensor.pixelShiftExp0; + } + if (raw.bayersensor.pixelShiftNonGreenCross) { toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; } - //if (raw.bayersensor.allEnhance) toEdit.raw.bayersensor.all_enhance = mods.raw.bayersensor.all_enhance; + if (raw.bayersensor.pixelShiftNonGreenCross2) { + toEdit.raw.bayersensor.pixelShiftNonGreenCross2 = mods.raw.bayersensor.pixelShiftNonGreenCross2; + } + + if (raw.bayersensor.pixelShiftNonGreenAmaze) { + toEdit.raw.bayersensor.pixelShiftNonGreenAmaze = mods.raw.bayersensor.pixelShiftNonGreenAmaze; + } + if (raw.bayersensor.greenEq) { toEdit.raw.bayersensor.greenthresh = dontforceSet && options.baBehav[ADDSET_PREPROCESS_GREENEQUIL] ? toEdit.raw.bayersensor.greenthresh + mods.raw.bayersensor.greenthresh : mods.raw.bayersensor.greenthresh; } @@ -2874,8 +2939,8 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const { return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso - && pixelShiftNreadIso && pixelShiftPrnu && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly - && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftNonGreenCross + && pixelShiftNreadIso && pixelShiftPrnu && pixelShiftSigma && pixelShiftSum && pixelShiftRedBlueWeight && pixelshiftShowMotion && pixelshiftShowMotionMaskOnly + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftExp0 && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index b4af2ad05..6a72f9ffa 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -700,12 +700,23 @@ public: bool pixelShiftEperIso; bool pixelShiftNreadIso; bool pixelShiftPrnu; + bool pixelShiftSigma; + bool pixelShiftSum; + bool pixelShiftRedBlueWeight; bool pixelshiftShowMotion; bool pixelshiftShowMotionMaskOnly; bool pixelShiftAutomatic; bool pixelShiftNonGreenHorizontal; bool pixelShiftNonGreenVertical; + bool pixelShiftHoleFill; + bool pixelShiftMedian; + bool pixelShiftMedian3; + bool pixelShiftGreen; + bool pixelShiftBlur; + bool pixelShiftExp0; bool pixelShiftNonGreenCross; + bool pixelShiftNonGreenCross2; + bool pixelShiftNonGreenAmaze; //bool allEnhance; bool greenEq; From fba1cff9a006cfeed3a0531b6cd8af48b50b4ab7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 13 Jan 2017 21:59:14 +0100 Subject: [PATCH 63/83] Pixelshift: Fix bug saving pixelshift median parameter in pp3 --- rtengine/procparams.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index a7443a87c..d7cbad13c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3462,7 +3462,7 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b } if (!pedited || pedited->raw.bayersensor.pixelShiftMedian3) { - keyFile.set_boolean ("RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian3 ); + keyFile.set_boolean ("RAW Bayer", "pixelShiftMedian3", raw.bayersensor.pixelShiftMedian3 ); } if (!pedited || pedited->raw.bayersensor.pixelShiftGreen) { From dfd7c29b0648f67fda933aad3bfa2d8b8a83238f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 14 Jan 2017 00:36:22 +0100 Subject: [PATCH 64/83] Forgot to add AUTHORS.txt with last commit --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 6aebfcf6e..3aa555bc0 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -56,5 +56,6 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Alberto Righetto Kostia (Kildor) Romanov Johan Thor + Vitalis Tiknius TooWaBoo Colin Walker From 4ecdf8dca9cde1d78ff9971418c006350d7f31af Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 15 Jan 2017 23:11:53 +0100 Subject: [PATCH 65/83] Added one file which I forgot with last commit --- rtgui/cropwindow.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 20dd3eb9d..2dbdf0e8b 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -61,9 +61,10 @@ ZoomStep zoomSteps[] = { {"500%", 5.0, 5000}, {"600%", 6.0, 6000}, {"700%", 7.0, 7000}, - {"800%", 8.0, 8000} + {"800%", 8.0, 8000}, + {"1600%", 16.0, 16000} }; -#define MAXZOOMSTEPS 20 +#define MAXZOOMSTEPS 21 #define ZOOM11INDEX 13 CropWindow::CropWindow (ImageArea* parent, bool isLowUpdatePriority_, bool isDetailWindow) From 70415fdfe5ef87e70ee91b76536c834ad27248cc Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 18 Jan 2017 19:36:35 +0100 Subject: [PATCH 66/83] pixelshift: cleaned gui --- rtdata/languages/default | 2 + rtengine/pixelshift.cc | 45 ++++++++++++-- rtengine/procevents.h | 1 + rtengine/procparams.cc | 45 ++++++++++++++ rtengine/procparams.h | 7 +++ rtengine/rawimagesource.cc | 18 ++++-- rtengine/refreshmap.cc | 3 +- rtgui/bayerprocess.cc | 124 +++++++++++++++++++++++++------------ rtgui/bayerprocess.h | 5 +- rtgui/paramsedited.cc | 8 ++- rtgui/paramsedited.h | 1 + 11 files changed, 206 insertions(+), 53 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 4b1b329e9..2a4943424 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -700,6 +700,7 @@ HISTORY_MSG_465;EvPixelShiftSum HISTORY_MSG_466;EvPixelShiftExp0 HISTORY_MSG_467;EvPixelShiftHoleFill HISTORY_MSG_468;EvPixelShiftMedian +HISTORY_MSG_469;EvPixelShiftMotionMethod HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1700,6 +1701,7 @@ TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a mask showing the r TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;Shows the motion mask without the image TP_RAW_PIXELSHIFTMOTIONCORRECTION;Green motion correction size TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP;1 = 2 pixels\n3 = 3x3 grid\n5 = 5x5 grid +TP_RAW_PIXELSHIFTMOTIONMETHOD;Motion Correction TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN;StdDev factor Green diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index ae2f08fdb..1fde4156d 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -31,6 +31,7 @@ #include "../rtgui/multilangmgr.h" #include "procparams.h" #include "gauss.h" +#include "median.h" #define BENCHMARK #include "StopWatch.h" @@ -1162,9 +1163,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } // now that the temporary planes are filled for easy access we do the motion detection - + int sum0 = 0; + int sum1 = 0; + float pixelcount = ((winh - (border + offsY) - (winy + border - offsY)) * (winw - (border + offsX) - (winx + border - offsX))) / 2.f; #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) + #pragma omp parallel for reduction(+:sum0,sum1) schedule(dynamic,16) #endif for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { @@ -1338,6 +1341,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } if (gridMax > thresh - korr) { + if(offset == 0) { + sum0 ++; + } else { + sum1 ++; + } + if(nOf3x3) { psMask[i][j] = 1.f; } else if((offset == (frame & 1)) && checkNonGreenVertical) { @@ -1357,7 +1366,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA j++; paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; } @@ -1547,6 +1555,20 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } if(adaptive && experimental0) { // for experiments +// float green1Median, green2Median; +// green1Median = median(psG1[ i - 1 ][ j - 1 ],psG1[ i - 1 ][ j + 1 ],psG1[ i ][ j ],psG1[ i + 1 ][ j -1 ],psG1[ i + 1 ][ j + 1 ]); +// green2Median = median(psG2[ i - 1 ][ j - 1 ],psG2[ i - 1 ][ j + 1 ],psG2[ i ][ j ],psG2[ i + 1 ][ j -1 ],psG2[ i + 1 ][ j + 1 ]); +// float greenDiffMedian = nonGreenDiff(green1Median, green2Median, stddevFactorGreen * 0.36f, eperIsoGreen, nRead, prnu, showMotion); +// +// if(greenDiffMedian > 0.f) { +// if(nOf3x3) { +// psMask[i][j] = 1.f; +// } else { +// paintMotionMask(j + offsX, showMotion, greenDiffMedian, showOnlyMask, greenDest, redDest, blueDest); +// } +// +// continue; +// } } @@ -1561,6 +1583,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } + float percent0 = 100.f * sum0 / pixelcount; + float percent1 = 100.f * sum1 / pixelcount; + + std::cout << fileName << " : Green detections at stddev " << std::setprecision( 2 ) << bayerParams.pixelShiftStddevFactorGreen << " : Frame 1/3 : " << std::setprecision( 6 ) << sum0 << " (" << percent0 << "%)" << " Frame 2/4 : " << sum1 << " (" << percent1 << "%)" << std::endl; + if(adaptive && nOf3x3) { if(blurMap) { #pragma omp parallel @@ -1623,9 +1650,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else { - red[i + offsY][j + offsX] = psRed[i][j]; - green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; - blue[i + offsY][j + offsX] = psBlue[i][j]; + if(blurMap && experimental0) { + red[i + offsY][j + offsX] = intp(psMask[i][j], red[i + offsY][j + offsX], psRed[i][j] ); + green[i + offsY][j + offsX] = intp(psMask[i][j],green[i + offsY][j + offsX],(psG1[i][j] + psG2[i][j]) / 2.f); + blue[i + offsY][j + offsX] = intp(psMask[i][j],blue[i + offsY][j + offsX], psBlue[i][j]); + } else { + red[i + offsY][j + offsX] = psRed[i][j]; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + blue[i + offsY][j + offsX] = psBlue[i][j]; + } } } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 4526b13f3..75b64d30d 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -496,6 +496,7 @@ enum ProcEvent { EvPixelShiftHoleFill = 466, EvPixelShiftMedian = 467, EvPixelShiftMedian3 = 468, + EvPixelShiftMotionMethod = 469, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d7cbad13c..0597be182 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -875,6 +875,33 @@ void CoarseTransformParams::setDefaults() hflip = false; vflip = false; } +void RAWParams::BayerSensor::setPixelShiftDefaults() +{ + pixelShiftMotion = 0; + pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid3x3New; + pixelShiftMotionCorrectionMethod = RAWParams::BayerSensor::Automatic; + pixelShiftStddevFactorGreen = 5.0; + pixelShiftStddevFactorRed = 5.0; + pixelShiftStddevFactorBlue = 5.0; + pixelShiftEperIso = 0.0; + pixelShiftNreadIso = 0.0; + pixelShiftPrnu = 1.0; + pixelShiftSigma = 1.0; + pixelShiftSum = 3.0; + pixelShiftRedBlueWeight = 0.7; + pixelShiftAutomatic = true; + pixelShiftNonGreenHorizontal = false; + pixelShiftNonGreenVertical = false; + pixelShiftHoleFill = true; + pixelShiftMedian = false; + pixelShiftMedian3 = false; + pixelShiftGreen = true; + pixelShiftBlur = true; + pixelShiftExp0 = false; + pixelShiftNonGreenCross = true; + pixelShiftNonGreenCross2 = false; + pixelShiftNonGreenAmaze = false; +} void RAWParams::setDefaults() { @@ -887,6 +914,7 @@ void RAWParams::setDefaults() bayersensor.lmmse_iterations = 2; bayersensor.pixelShiftMotion = 0; bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid3x3New; + bayersensor.pixelShiftMotionCorrectionMethod = RAWParams::BayerSensor::Automatic; bayersensor.pixelShiftStddevFactorGreen = 5.0; bayersensor.pixelShiftStddevFactorRed = 5.0; bayersensor.pixelShiftStddevFactorBlue = 5.0; @@ -939,6 +967,10 @@ void RAWParams::setDefaults() hotPixelFilter = false; deadPixelFilter = false; hotdeadpix_thresh = 100; + bayersensor.setPixelShiftDefaults(); + bayersensor.pixelshiftShowMotion = false; + bayersensor.pixelshiftShowMotionMaskOnly = false; + } void ColorManagementParams::setDefaults() @@ -3397,6 +3429,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrection", raw.bayersensor.pixelShiftMotionCorrection ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod) { + keyFile.set_integer ("RAW Bayer", "PixelShiftMotionCorrectionMethod", raw.bayersensor.pixelShiftMotionCorrectionMethod ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftStddevFactorGreen) { keyFile.set_double ("RAW Bayer", "pixelShiftStddevFactorGreen", raw.bayersensor.pixelShiftStddevFactorGreen ); } @@ -7561,6 +7597,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "PixelShiftMotionCorrectionMethod")) { + raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::ePSMotionCorrectionMethod)keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrectionMethod"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftStddevFactorGreen")) { raw.bayersensor.pixelShiftStddevFactorGreen = keyFile.get_double("RAW Bayer", "pixelShiftStddevFactorGreen"); @@ -8184,6 +8228,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations && raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion && raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection + && raw.bayersensor.pixelShiftMotionCorrectionMethod == other.raw.bayersensor.pixelShiftMotionCorrectionMethod && raw.bayersensor.pixelShiftStddevFactorGreen == other.raw.bayersensor.pixelShiftStddevFactorGreen && raw.bayersensor.pixelShiftStddevFactorRed == other.raw.bayersensor.pixelShiftStddevFactorRed && raw.bayersensor.pixelShiftStddevFactorBlue == other.raw.bayersensor.pixelShiftStddevFactorBlue diff --git a/rtengine/procparams.h b/rtengine/procparams.h index c3c8296b7..51d55bedc 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1190,6 +1190,9 @@ public: enum ePSMotionCorrection { Grid1x1, Grid1x2, Grid3x3, Grid5x5, Grid7x7, Grid3x3New }; + enum ePSMotionCorrectionMethod { + Off, Automatic, Custom + }; static const char *methodstring[numMethods]; Glib::ustring method; @@ -1206,6 +1209,7 @@ public: int lmmse_iterations; int pixelShiftMotion; ePSMotionCorrection pixelShiftMotionCorrection; + ePSMotionCorrectionMethod pixelShiftMotionCorrectionMethod; double pixelShiftStddevFactorGreen; double pixelShiftStddevFactorRed; double pixelShiftStddevFactorBlue; @@ -1231,6 +1235,9 @@ public: bool pixelShiftNonGreenAmaze; bool dcb_enhance; //bool all_enhance; + + void setPixelShiftDefaults(); + }; /** diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 566fc77a3..11d7a2af2 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2027,10 +2027,18 @@ void RawImageSource::demosaic(const RAWParams &raw) if(numFrames != 4) { // fallback for non pixelshift files amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); } else { - if(!raw.bayersensor.pixelshiftShowMotion || raw.bayersensor.pixelShiftNonGreenAmaze || raw.bayersensor.pixelShiftNonGreenCross2) { - if((raw.bayersensor.pixelShiftMotion > 0 || raw.bayersensor.pixelShiftAutomatic) && numFrames == 4) { - if(raw.bayersensor.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction - if(!raw.bayersensor.pixelShiftMedian3) { + RAWParams::BayerSensor bayerParams = raw.bayersensor; + if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Automatic) { + bayerParams.setPixelShiftDefaults(); + } else if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Off) { + bayerParams.pixelShiftMotion = 0; + bayerParams.pixelShiftAutomatic = false; + bayerParams.pixelshiftShowMotion = false; + } + if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftExp0)) { + if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic) && numFrames == 4) { + if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction + if(!bayerParams.pixelShiftMedian3) { amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[0]), red, green, blue); multi_array2D redTmp(W,H); multi_array2D greenTmp(W,H); @@ -2122,7 +2130,7 @@ void RawImageSource::demosaic(const RAWParams &raw) amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction } } - pixelshift(0, 0, W, H, raw.bayersensor, raw.bayersensor.pixelShiftExp0 ? 0: currFrame, ri->get_model(), raw.expos); + pixelshift(0, 0, W, H, bayerParams, currFrame, ri->get_model(), raw.expos); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::dcb] ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 3030a4319..72fe3b76a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -495,7 +495,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftExp0 DEMOSAIC, // EvPixelShiftHoleFill DEMOSAIC, // EvPixelShiftMedian - DEMOSAIC // EvPixelShiftMedian3 + DEMOSAIC, // EvPixelShiftMedian3 + DEMOSAIC // EvPixelShiftMotionMethod }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 701463ac4..1fcb2911e 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -50,6 +50,18 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA imageNumberBox->pack_end (*imageNumber, Gtk::PACK_EXPAND_WIDGET, 4); pack_start( *imageNumberBox, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); + ccSteps->setAdjusterListener (this); + + if (ccSteps->delay < options.adjusterMaxDelay) { + ccSteps->delay = options.adjusterMaxDelay; + } + + ccSteps->show(); + pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + + dcbOptions = Gtk::manage (new Gtk::VBox ()); dcbOptions->set_border_width(4); @@ -81,16 +93,30 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA lmmseOptions->pack_start(*lmmseIterations); pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); + pixelShiftFrame = Gtk::manage (new Gtk::VBox ()); + pixelShiftFrame->set_border_width(0); + + Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); + hb3->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); + pixelShiftMotionMethod = Gtk::manage (new MyComboBoxText ()); + pixelShiftMotionMethod->append_text("Off"); + pixelShiftMotionMethod->append_text("Automatic"); + pixelShiftMotionMethod->append_text("Custom"); + pixelShiftMotionMethod->set_active(1); + pixelShiftMotionMethod->show(); + hb3->pack_start(*pixelShiftMotionMethod); + pixelShiftFrame->pack_start(*hb3); + pixelShiftOptions = Gtk::manage (new Gtk::VBox ()); - pixelShiftOptions->set_border_width(4); + pixelShiftOptions->set_border_width(0); pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); pixelShiftShowMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP")); - pixelShiftOptions->pack_start(*pixelShiftShowMotion); + pixelShiftFrame->pack_start(*pixelShiftShowMotion); pixelShiftShowMotionMaskOnly = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); pixelShiftShowMotionMaskOnly->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP")); - pixelShiftOptions->pack_start(*pixelShiftShowMotionMaskOnly); + pixelShiftFrame->pack_start(*pixelShiftShowMotionMaskOnly); pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); @@ -142,8 +168,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotion->show(); pixelShiftOptions->pack_start(*pixelShiftMotion); + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); - hb2->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONCORRECTION") + ": ")), Gtk::PACK_SHRINK, 4); + hb2->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONCORRECTION") + ": ")), Gtk::PACK_SHRINK, 0); pixelShiftMotionCorrection = Gtk::manage (new MyComboBoxText ()); pixelShiftMotionCorrection->append_text("1x1"); pixelShiftMotionCorrection->append_text("1x2"); @@ -152,7 +179,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->append_text("7x7"); pixelShiftMotionCorrection->append_text("3x3 new"); pixelShiftMotionCorrection->set_active(0); -// pixelShiftMotionCorrection->set_tooltip_markup (M("TP_RAW_PIXELSHIFTMOTIONCORRECTION_TOOLTIP")); pixelShiftMotionCorrection->show(); hb2->pack_start(*pixelShiftMotionCorrection); pixelShiftOptions->pack_start(*hb2); @@ -218,7 +244,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftPrnu->show(); pixelShiftOptions->pack_start(*pixelShiftPrnu); - pixelShiftSigma = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSIGMA"), 0.5, 2.5, 0.1, 1.0)); + pixelShiftSigma = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSIGMA"), 0.5, 25, 0.1, 1.0)); pixelShiftSigma->setAdjusterListener (this); if (pixelShiftSigma->delay < options.adjusterMaxDelay) { @@ -248,19 +274,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftRedBlueWeight->show(); pixelShiftOptions->pack_start(*pixelShiftRedBlueWeight); - pack_start( *pixelShiftOptions, Gtk::PACK_SHRINK, 4); + pixelShiftFrame->pack_start(*pixelShiftOptions); + pixelShiftOptions->hide(); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); - ccSteps->setAdjusterListener (this); - - if (ccSteps->delay < options.adjusterMaxDelay) { - ccSteps->delay = options.adjusterMaxDelay; - } - - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + pack_start( *pixelShiftFrame, Gtk::PACK_SHRINK, 4); //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); //allOptions = Gtk::manage (new Gtk::VBox ()); @@ -273,6 +290,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA psmcconn = pixelShiftMotionCorrection->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::psMotionCorrectionChanged) ); imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); + pixelShiftMotionMethodConn = pixelShiftMotionMethod->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::pixelShiftMotionMethodChanged) ); pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); pixelShiftShowMotionMaskOnlyconn = pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true); pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); @@ -349,6 +367,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params if(!pedited->raw.bayersensor.pixelShiftMotionCorrection) { pixelShiftMotionCorrection->set_active_text(M("GENERAL_UNCHANGED")); } + if(!pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod) { + pixelShiftMotionMethod->set_active_text(M("GENERAL_UNCHANGED")); + } } //allEnhance->set_active(pp->raw.bayersensor.all_enhance); @@ -373,6 +394,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); pixelShiftMotionCorrection->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); + pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); pixelShiftStddevFactorGreen->setValue (pp->raw.bayersensor.pixelShiftStddevFactorGreen); pixelShiftStddevFactorRed->setValue (pp->raw.bayersensor.pixelShiftStddevFactorRed); pixelShiftStddevFactorBlue->setValue (pp->raw.bayersensor.pixelShiftStddevFactorBlue); @@ -398,9 +420,14 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::pixelshift] || method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { - pixelShiftOptions->show(); + if(pp->raw.bayersensor.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Custom) { + pixelShiftOptions->show(); + } else { + pixelShiftOptions->hide(); + } + pixelShiftFrame->show(); } else { - pixelShiftOptions->hide(); + pixelShiftFrame->hide(); } // Flase color suppression is applied to all demozaicing method, so don't hide anything @@ -433,6 +460,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); pp->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getIntValue(); pp->raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)pixelShiftMotionCorrection->get_active_row_number(); + pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::ePSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); pp->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getValue(); pp->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getValue(); pp->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getValue(); @@ -478,6 +506,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); pedited->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getEditedState (); pedited->raw.bayersensor.pixelShiftMotionCorrection = pixelShiftMotionCorrection->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = pixelShiftMotionMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getEditedState (); pedited->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getEditedState (); pedited->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getEditedState (); @@ -510,6 +539,8 @@ void BayerProcess::setBatchMode(bool batchMode) method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name pixelShiftMotionCorrection->append_text (M("GENERAL_UNCHANGED")); pixelShiftMotionCorrection->set_active (4); + pixelShiftMotionMethod->append_text (M("GENERAL_UNCHANGED")); + pixelShiftMotionMethod->set_active (4); imageNumber->append_text (M("GENERAL_UNCHANGED")); imageNumber->set_active(4); dcbOptions->hide(); @@ -613,26 +644,16 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) void BayerProcess::psMotionCorrectionChanged () { - int curSelection = pixelShiftMotionCorrection->get_active_row_number(); - Glib::ustring sGrid; - switch (curSelection) { - case 0: - sGrid = "1x1"; - break; - case 1: - sGrid = "1x2"; - break; - case 2: - sGrid = "3x3"; - break; - case 3: - default: - sGrid = "5x5"; - break; + if(pixelShiftMotionCorrection->get_active_row_number() == 5) { + pixelShiftBlur->set_sensitive(true); + pixelShiftHoleFill->set_sensitive(true); + } else { + pixelShiftBlur->set_sensitive(false); + pixelShiftHoleFill->set_sensitive(false); } if (listener) { - listener->panelChanged (EvPixelShiftMotionCorrection, sGrid); + listener->panelChanged (EvPixelShiftMotionCorrection, pixelShiftMotionCorrection->get_active_text()); } } @@ -653,9 +674,14 @@ void BayerProcess::methodChanged () } if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift) { - pixelShiftOptions->show(); + if(pixelShiftMotionMethod->get_active_row_number() == 2) { + pixelShiftOptions->show(); + } else { + pixelShiftOptions->hide(); + } + pixelShiftFrame->show(); } else { - pixelShiftOptions->hide(); + pixelShiftFrame->hide(); } Glib::ustring methodName = ""; @@ -703,6 +729,26 @@ void BayerProcess::dcbEnhanceChanged () } } +void BayerProcess::pixelShiftMotionMethodChanged () +{ + if(pixelShiftMotionMethod->get_active_row_number() == 0) { + pixelShiftOptions->hide(); + pixelShiftShowMotion->hide(); + pixelShiftShowMotionMaskOnly->hide(); + } else if(pixelShiftMotionMethod->get_active_row_number() == 2) { + pixelShiftOptions->show(); + pixelShiftShowMotion->show(); + pixelShiftShowMotionMaskOnly->show(); + } else { + pixelShiftOptions->hide(); + pixelShiftShowMotion->show(); + pixelShiftShowMotionMaskOnly->show(); + } + if (listener) { + listener->panelChanged (EvPixelShiftMotionMethod, pixelShiftMotionMethod->get_active_text()); + } +} + void BayerProcess::pixelShiftShowMotionChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 79593debf..e53cb6816 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -41,9 +41,11 @@ protected: //Gtk::CheckButton* allEnhance; Gtk::VBox *lmmseOptions; Adjuster* lmmseIterations; + Gtk::VBox *pixelShiftFrame; Gtk::VBox *pixelShiftOptions; Adjuster* pixelShiftMotion; MyComboBoxText* pixelShiftMotionCorrection; + MyComboBoxText* pixelShiftMotionMethod; Gtk::CheckButton* pixelShiftShowMotion; Gtk::CheckButton* pixelShiftShowMotionMaskOnly; Gtk::CheckButton* pixelShiftAutomatic; @@ -73,7 +75,7 @@ protected: sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftHoleFillconn, pixelShiftMedianconn, pixelShiftMedian3conn, pixelShiftNonGreenCrossconn, - pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftExp0conn; + pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftExp0conn, pixelShiftMotionMethodConn; public: BayerProcess (); @@ -102,6 +104,7 @@ public: void pixelShiftNonGreenCrossChanged(); void pixelShiftNonGreenCross2Changed(); void pixelShiftNonGreenAmazeChanged(); + void pixelShiftMotionMethodChanged(); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index b6127b7d2..185341e32 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -372,6 +372,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.lmmseIterations = v; raw.bayersensor.pixelShiftMotion = v; raw.bayersensor.pixelShiftMotionCorrection = v; + raw.bayersensor.pixelShiftMotionCorrectionMethod = v; raw.bayersensor.pixelShiftStddevFactorGreen = v; raw.bayersensor.pixelShiftStddevFactorRed = v; raw.bayersensor.pixelShiftStddevFactorBlue = v; @@ -893,6 +894,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; raw.bayersensor.pixelShiftMotion = raw.bayersensor.pixelShiftMotion && p.raw.bayersensor.pixelShiftMotion == other.raw.bayersensor.pixelShiftMotion; raw.bayersensor.pixelShiftMotionCorrection = raw.bayersensor.pixelShiftMotionCorrection && p.raw.bayersensor.pixelShiftMotionCorrection == other.raw.bayersensor.pixelShiftMotionCorrection; + raw.bayersensor.pixelShiftMotionCorrectionMethod = raw.bayersensor.pixelShiftMotionCorrectionMethod && p.raw.bayersensor.pixelShiftMotionCorrectionMethod == other.raw.bayersensor.pixelShiftMotionCorrectionMethod; raw.bayersensor.pixelShiftStddevFactorGreen = raw.bayersensor.pixelShiftStddevFactorGreen && p.raw.bayersensor.pixelShiftStddevFactorGreen == other.raw.bayersensor.pixelShiftStddevFactorGreen; raw.bayersensor.pixelShiftStddevFactorRed = raw.bayersensor.pixelShiftStddevFactorRed && p.raw.bayersensor.pixelShiftStddevFactorRed == other.raw.bayersensor.pixelShiftStddevFactorRed; raw.bayersensor.pixelShiftStddevFactorBlue = raw.bayersensor.pixelShiftStddevFactorBlue && p.raw.bayersensor.pixelShiftStddevFactorBlue == other.raw.bayersensor.pixelShiftStddevFactorBlue; @@ -2336,6 +2338,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftMotionCorrection = mods.raw.bayersensor.pixelShiftMotionCorrection; } + if (raw.bayersensor.pixelShiftMotionCorrectionMethod) { + toEdit.raw.bayersensor.pixelShiftMotionCorrectionMethod = mods.raw.bayersensor.pixelShiftMotionCorrectionMethod; + } + if (raw.bayersensor.pixelShiftStddevFactorGreen) { toEdit.raw.bayersensor.pixelShiftStddevFactorGreen = mods.raw.bayersensor.pixelShiftStddevFactorGreen; } @@ -2938,7 +2944,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten bool RAWParamsEdited::BayerSensor::isUnchanged() const { return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq - && pixelShiftMotion && pixelShiftMotionCorrection && pixelShiftStddevFactorGreen && pixelShiftStddevFactorRed && pixelShiftStddevFactorBlue && pixelShiftEperIso + && 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 && pixelShiftExp0 && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 6a72f9ffa..ceb8b82fd 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -694,6 +694,7 @@ public: bool lmmseIterations; bool pixelShiftMotion; bool pixelShiftMotionCorrection; + bool pixelShiftMotionCorrectionMethod; bool pixelShiftStddevFactorGreen; bool pixelShiftStddevFactorRed; bool pixelShiftStddevFactorBlue; From e231d6c06d497721ee80059cf9972ec8640fcd67 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 18 Jan 2017 20:33:40 +0100 Subject: [PATCH 67/83] pixelshift: minor gui fixes --- rtgui/bayerprocess.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 1fcb2911e..8b8cc9be8 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -405,6 +405,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftSum->setValue (pp->raw.bayersensor.pixelShiftSum); pixelShiftRedBlueWeight->setValue (pp->raw.bayersensor.pixelShiftRedBlueWeight); + pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); + if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { @@ -815,11 +818,11 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftStddevFactorBlue->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); - pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); pixelShiftMedian->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftMedian3->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMedian->get_active()); pixelShiftGreen->set_sensitive(pixelShiftAutomatic->get_active ()); - pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active ()); + pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); pixelShiftExp0->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross2->set_sensitive(pixelShiftAutomatic->get_active ()); From 8d40dbdc0b3c78fe1d9c2d79c23a4ef6f1ecec5a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 19 Jan 2017 18:46:41 +0100 Subject: [PATCH 68/83] pixelshift: option to smooth transitions between regions with and without motion --- rtdata/languages/default | 3 +++ rtengine/pixelshift.cc | 3 ++- rtengine/procevents.h | 1 + rtengine/procparams.cc | 40 ++++++++++++++-------------------------- rtengine/procparams.h | 1 + rtengine/refreshmap.cc | 3 ++- rtgui/bayerprocess.cc | 35 +++++++++++++++++++++++++++++++++++ rtgui/bayerprocess.h | 4 +++- rtgui/paramsedited.cc | 8 +++++++- rtgui/paramsedited.h | 1 + 10 files changed, 69 insertions(+), 30 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 2a4943424..064c4dbdb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -701,6 +701,7 @@ HISTORY_MSG_466;EvPixelShiftExp0 HISTORY_MSG_467;EvPixelShiftHoleFill HISTORY_MSG_468;EvPixelShiftMedian HISTORY_MSG_469;EvPixelShiftMotionMethod +HISTORY_MSG_470;EvPixelShiftSmooth HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1686,6 +1687,7 @@ TP_RAW_PIXELSHIFTMEDIAN;Median TP_RAW_PIXELSHIFTMEDIAN3;Exclude selected frame from median TP_RAW_PIXELSHIFTHOLEFILL;3x3 new: Fill holes TP_RAW_PIXELSHIFTBLUR;3x3 new: Blur +TP_RAW_PIXELSHIFTSMOOTH;3x3 new: Smooth transitions TP_RAW_PIXELSHIFTEXP0;Experimental TP_RAW_PIXELSHIFTGREEN;Check dual green TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross @@ -1695,6 +1697,7 @@ TP_RAW_PIXELSHIFTMOTION;Motion detection level (deprecated) TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;Fill holes in motion mask TP_RAW_PIXELSHIFTBLUR_TOOLTIP;Blur motion mask +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions (requires 3x3 new Blur) TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;Use median of all frames instead of selected frame for regions with motion.\nRemoves objects which are at different places in all frames.\nGives motion effect on slow moving (overlapping) objects. TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP;Excludes selected frame from median.\nUseful if moving objects overlap in frame 2 and 3 TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a mask showing the regions with motion diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 1fde4156d..91aa972ee 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -906,6 +906,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const float threshold = bayerParams.pixelShiftSum; const bool experimental0 = bayerParams.pixelShiftExp0; const bool holeFill = bayerParams.pixelShiftHoleFill; + const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmooth; static const float nReadK3II[] = { 3.4f, // ISO 100 3.1f, // ISO 125 @@ -1650,7 +1651,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else { - if(blurMap && experimental0) { + if(smoothTransitions) { red[i + offsY][j + offsX] = intp(psMask[i][j], red[i + offsY][j + offsX], psRed[i][j] ); green[i + offsY][j + offsX] = intp(psMask[i][j],green[i + offsY][j + offsX],(psG1[i][j] + psG2[i][j]) / 2.f); blue[i + offsY][j + offsX] = intp(psMask[i][j],blue[i + offsY][j + offsX], psBlue[i][j]); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 75b64d30d..86deb7d6d 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -497,6 +497,7 @@ enum ProcEvent { EvPixelShiftMedian = 467, EvPixelShiftMedian3 = 468, EvPixelShiftMotionMethod = 469, + EvPixelShiftSmooth = 470, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 0597be182..2edf7c77e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -897,6 +897,7 @@ void RAWParams::BayerSensor::setPixelShiftDefaults() pixelShiftMedian3 = false; pixelShiftGreen = true; pixelShiftBlur = true; + pixelShiftSmooth = true; pixelShiftExp0 = false; pixelShiftNonGreenCross = true; pixelShiftNonGreenCross2 = false; @@ -912,32 +913,6 @@ void RAWParams::setDefaults() bayersensor.dcb_enhance = true; //bayersensor.all_enhance = false; bayersensor.lmmse_iterations = 2; - bayersensor.pixelShiftMotion = 0; - bayersensor.pixelShiftMotionCorrection = RAWParams::BayerSensor::Grid3x3New; - bayersensor.pixelShiftMotionCorrectionMethod = RAWParams::BayerSensor::Automatic; - bayersensor.pixelShiftStddevFactorGreen = 5.0; - bayersensor.pixelShiftStddevFactorRed = 5.0; - bayersensor.pixelShiftStddevFactorBlue = 5.0; - bayersensor.pixelShiftEperIso = 0.0; - bayersensor.pixelShiftNreadIso = 0.0; - bayersensor.pixelShiftPrnu = 1.0; - bayersensor.pixelShiftSigma = 1.0; - bayersensor.pixelShiftSum = 3.0; - bayersensor.pixelShiftRedBlueWeight = 0.7; - bayersensor.pixelshiftShowMotion = false; - bayersensor.pixelshiftShowMotionMaskOnly = false; - bayersensor.pixelShiftAutomatic = true; - bayersensor.pixelShiftNonGreenHorizontal = false; - bayersensor.pixelShiftNonGreenVertical = false; - bayersensor.pixelShiftHoleFill = true; - bayersensor.pixelShiftMedian = false; - bayersensor.pixelShiftMedian3 = false; - bayersensor.pixelShiftGreen = true; - bayersensor.pixelShiftBlur = true; - bayersensor.pixelShiftExp0 = false; - bayersensor.pixelShiftNonGreenCross = true; - bayersensor.pixelShiftNonGreenCross2 = false; - bayersensor.pixelShiftNonGreenAmaze = false; bayersensor.black0 = 0.0; bayersensor.black1 = 0.0; bayersensor.black2 = 0.0; @@ -3509,6 +3484,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftBlur", raw.bayersensor.pixelShiftBlur ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftSmooth) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftSmooth", raw.bayersensor.pixelShiftSmooth ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftExp0) { keyFile.set_boolean ("RAW Bayer", "pixelShiftExp0", raw.bayersensor.pixelShiftExp0 ); } @@ -7757,6 +7736,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftSmooth")) { + raw.bayersensor.pixelShiftSmooth = keyFile.get_boolean("RAW Bayer", "pixelShiftSmooth"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftSmooth = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftExp0")) { raw.bayersensor.pixelShiftExp0 = keyFile.get_boolean("RAW Bayer", "pixelShiftExp0"); @@ -8248,6 +8235,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3 && raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen && raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur + && raw.bayersensor.pixelShiftSmooth == other.raw.bayersensor.pixelShiftSmooth && raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0 && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 51d55bedc..dbf285fb2 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1229,6 +1229,7 @@ public: bool pixelShiftMedian3; bool pixelShiftGreen; bool pixelShiftBlur; + bool pixelShiftSmooth; bool pixelShiftExp0; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 72fe3b76a..891f191b2 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -496,7 +496,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftHoleFill DEMOSAIC, // EvPixelShiftMedian DEMOSAIC, // EvPixelShiftMedian3 - DEMOSAIC // EvPixelShiftMotionMethod + DEMOSAIC, // EvPixelShiftMotionMethod + DEMOSAIC // EvPixelShiftSmooth }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 8b8cc9be8..5d33ffe18 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -128,6 +128,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTBLUR_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftBlur); + pixelShiftSmooth = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSMOOTH"))); + pixelShiftSmooth->set_tooltip_text (M("TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftSmooth); + pixelShiftHoleFill = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); pixelShiftHoleFill->set_tooltip_text (M("TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftHoleFill); @@ -301,6 +305,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMedian3conn = pixelShiftMedian3->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedian3Changed), true); pixelShiftGreenconn = pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true); pixelShiftBlurconn = pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true); + pixelShiftSmoothconn = pixelShiftSmooth->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftSmoothChanged), true); pixelShiftExp0conn = pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); @@ -342,6 +347,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftMedian3->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_inconsistent(!pedited->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); + pixelShiftSmooth->set_inconsistent(!pedited->raw.bayersensor.pixelShiftSmooth); pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); @@ -386,6 +392,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftMedian3->set_active(pp->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_active(pp->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); + pixelShiftSmooth->set_active(pp->raw.bayersensor.pixelShiftSmooth); pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); @@ -407,6 +414,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftSmooth->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5 && pixelShiftBlur->get_active()); if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || @@ -483,6 +491,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftMedian3 = pixelShiftMedian3->get_active(); pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->get_active(); pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); + pp->raw.bayersensor.pixelShiftSmooth = pixelShiftSmooth->get_active(); pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); @@ -529,6 +538,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftMedian3 = !pixelShiftMedian3->get_inconsistent(); pedited->raw.bayersensor.pixelShiftGreen = !pixelShiftGreen->get_inconsistent(); pedited->raw.bayersensor.pixelShiftBlur = !pixelShiftBlur->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftSmooth = !pixelShiftSmooth->get_inconsistent(); pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); @@ -650,9 +660,11 @@ void BayerProcess::psMotionCorrectionChanged () if(pixelShiftMotionCorrection->get_active_row_number() == 5) { pixelShiftBlur->set_sensitive(true); pixelShiftHoleFill->set_sensitive(true); + pixelShiftSmooth->set_sensitive(pixelShiftBlur->get_active()); } else { pixelShiftBlur->set_sensitive(false); pixelShiftHoleFill->set_sensitive(false); + pixelShiftSmooth->set_sensitive(false); } if (listener) { @@ -823,6 +835,7 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftMedian3->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMedian->get_active()); pixelShiftGreen->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftSmooth->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5 && pixelShiftBlur->get_active()); pixelShiftExp0->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenCross2->set_sensitive(pixelShiftAutomatic->get_active ()); @@ -971,11 +984,33 @@ void BayerProcess::pixelShiftBlurChanged () lastDCBen = pixelShiftBlur->get_active (); } + pixelShiftSmooth->set_sensitive(pixelShiftBlur->get_active ()); + if (listener) { listener->panelChanged (EvPixelShiftBlur, pixelShiftBlur->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } +void BayerProcess::pixelShiftSmoothChanged () +{ + if (batchMode) { + if (pixelShiftSmooth->get_inconsistent()) { + pixelShiftSmooth->set_inconsistent (false); + pixelShiftSmoothconn.block (true); + pixelShiftSmooth->set_active (false); + pixelShiftSmoothconn.block (false); + } else if (lastDCBen) { + pixelShiftSmooth->set_inconsistent (true); + } + + lastDCBen = pixelShiftSmooth->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftSmooth, pixelShiftSmooth->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void BayerProcess::pixelShiftExp0Changed () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index e53cb6816..135c02df5 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -56,6 +56,7 @@ protected: Gtk::CheckButton* pixelShiftNonGreenAmaze; Gtk::CheckButton* pixelShiftGreen; Gtk::CheckButton* pixelShiftBlur; + Gtk::CheckButton* pixelShiftSmooth; Gtk::CheckButton* pixelShiftExp0; Gtk::CheckButton* pixelShiftHoleFill; Gtk::CheckButton* pixelShiftMedian; @@ -75,7 +76,7 @@ protected: sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftHoleFillconn, pixelShiftMedianconn, pixelShiftMedian3conn, pixelShiftNonGreenCrossconn, - pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftExp0conn, pixelShiftMotionMethodConn; + pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftSmoothconn, pixelShiftExp0conn, pixelShiftMotionMethodConn; public: BayerProcess (); @@ -100,6 +101,7 @@ public: void pixelShiftMedian3Changed(); void pixelShiftGreenChanged(); void pixelShiftBlurChanged(); + void pixelShiftSmoothChanged(); void pixelShiftExp0Changed(); void pixelShiftNonGreenCrossChanged(); void pixelShiftNonGreenCross2Changed(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 185341e32..061424acf 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -392,6 +392,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftMedian3 = v; raw.bayersensor.pixelShiftGreen = v; raw.bayersensor.pixelShiftBlur = v; + raw.bayersensor.pixelShiftSmooth = v; raw.bayersensor.pixelShiftExp0 = v; raw.bayersensor.pixelShiftNonGreenCross = v; raw.bayersensor.pixelShiftNonGreenCross2 = v; @@ -914,6 +915,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftMedian3 = raw.bayersensor.pixelShiftMedian3 && p.raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3; raw.bayersensor.pixelShiftGreen = raw.bayersensor.pixelShiftGreen && p.raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen; raw.bayersensor.pixelShiftBlur = raw.bayersensor.pixelShiftBlur && p.raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur; + raw.bayersensor.pixelShiftSmooth = raw.bayersensor.pixelShiftSmooth && p.raw.bayersensor.pixelShiftSmooth == other.raw.bayersensor.pixelShiftSmooth; raw.bayersensor.pixelShiftExp0 = raw.bayersensor.pixelShiftExp0 && p.raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; @@ -2418,6 +2420,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftBlur = mods.raw.bayersensor.pixelShiftBlur; } + if (raw.bayersensor.pixelShiftSmooth) { + toEdit.raw.bayersensor.pixelShiftSmooth = mods.raw.bayersensor.pixelShiftSmooth; + } + if (raw.bayersensor.pixelShiftExp0) { toEdit.raw.bayersensor.pixelShiftExp0 = mods.raw.bayersensor.pixelShiftExp0; } @@ -2946,7 +2952,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && 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 && pixelShiftExp0 + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftExp0 && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ceb8b82fd..23b0e240b 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -714,6 +714,7 @@ public: bool pixelShiftMedian3; bool pixelShiftGreen; bool pixelShiftBlur; + bool pixelShiftSmooth; bool pixelShiftExp0; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; From c0988beb3312b53756ece02e964e91a16c07b158 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 21 Jan 2017 13:44:10 +0100 Subject: [PATCH 69/83] Pixelshift: fixed two small bugs --- rtengine/rawimagesource.cc | 2 +- rtgui/bayerprocess.cc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 11d7a2af2..f5bea64d3 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2035,7 +2035,7 @@ void RawImageSource::demosaic(const RAWParams &raw) bayerParams.pixelShiftAutomatic = false; bayerParams.pixelshiftShowMotion = false; } - if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftExp0)) { + if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftSmooth)) { if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic) && numFrames == 4) { if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction if(!bayerParams.pixelShiftMedian3) { diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5d33ffe18..89b92ebd2 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -831,7 +831,6 @@ void BayerProcess::pixelShiftAutomaticChanged () pixelShiftNonGreenHorizontal->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftNonGreenVertical->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); - pixelShiftMedian->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftMedian3->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMedian->get_active()); pixelShiftGreen->set_sensitive(pixelShiftAutomatic->get_active ()); pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); From 208c179921c35c574ec725a6db8ec400e09fd93c Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 22 Jan 2017 17:44:58 +0100 Subject: [PATCH 70/83] pixelshift: adjuster for smooth transitions --- rtdata/languages/default | 7 ++++--- rtengine/pixelshift.cc | 38 +++++++++++++++++++++++++++++++----- rtengine/procparams.cc | 10 +++++----- rtengine/procparams.h | 2 +- rtengine/rawimagesource.cc | 2 +- rtgui/bayerprocess.cc | 40 +++++++++++++------------------------- rtgui/bayerprocess.h | 3 +-- rtgui/paramsedited.cc | 4 ++-- 8 files changed, 61 insertions(+), 45 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index dcd6fd3da..68386d1bd 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -700,8 +700,9 @@ HISTORY_MSG_465;EvPixelShiftSum HISTORY_MSG_466;EvPixelShiftExp0 HISTORY_MSG_467;EvPixelShiftHoleFill HISTORY_MSG_468;EvPixelShiftMedian -HISTORY_MSG_469;EvPixelShiftMotionMethod -HISTORY_MSG_470;EvPixelShiftSmooth +HISTORY_MSG_469;EvPixelShiftMedian3 +HISTORY_MSG_470;EvPixelShiftMotionMethod +HISTORY_MSG_471;EvPixelShiftSmooth HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1702,7 +1703,7 @@ TP_RAW_PIXELSHIFTMOTION;Motion detection level (deprecated) TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;Fill holes in motion mask TP_RAW_PIXELSHIFTBLUR_TOOLTIP;Blur motion mask -TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions (requires 3x3 new Blur) +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions (requires 3x3 new Blur)\nSet to 0 to disable smooth transitions\nSet to 1 to get Amaze or Median TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;Use median of all frames instead of selected frame for regions with motion.\nRemoves objects which are at different places in all frames.\nGives motion effect on slow moving (overlapping) objects. TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP;Excludes selected frame from median.\nUseful if moving objects overlap in frame 2 and 3 TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a mask showing the regions with motion diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 91aa972ee..188b5f4bf 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -906,7 +906,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const float threshold = bayerParams.pixelShiftSum; const bool experimental0 = bayerParams.pixelShiftExp0; const bool holeFill = bayerParams.pixelShiftHoleFill; - const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmooth; + const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmoothFactor > 0.; + const float smoothFactor = 1.0 - bayerParams.pixelShiftSmoothFactor; static const float nReadK3II[] = { 3.4f, // ISO 100 3.1f, // ISO 125 @@ -1638,12 +1639,34 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #pragma omp parallel for schedule(dynamic,16) for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { +#ifdef __SSE2__ + if(!(showMotion && showOnlyMask) && smoothTransitions) { + if(smoothFactor == 0.f) { + for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { + psMask[i][j] = 1.f; + } + } else { + vfloat zerov = F2V(0.f); + vfloat smoothv = F2V(smoothFactor); + int j = winx + border - offsX; + for(; j < winw - (border + offsX)- 3; j += 4) { + vfloat blendv = LVFU(psMask[i][j]); + blendv = vmaxf(blendv, zerov); + blendv = pow_F(blendv, smoothv); + STVFU(psMask[i][j], blendv); + } + for(; j < winw - (border + offsX); ++j) { + psMask[i][j] = pow_F(std::max(psMask[i][j],0.f),smoothFactor); + } + } + } +#endif float *greenDest = green[i + offsY]; float *redDest = red[i + offsY]; float *blueDest = blue[i + offsY]; for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { - if(mask[i][j] == 255 ) { + if(mask[i][j] == 255) { paintMotionMask(j + offsX, showMotion, 0.5f, showOnlyMask, greenDest, redDest, blueDest); continue; } @@ -1652,9 +1675,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else { if(smoothTransitions) { - red[i + offsY][j + offsX] = intp(psMask[i][j], red[i + offsY][j + offsX], psRed[i][j] ); - green[i + offsY][j + offsX] = intp(psMask[i][j],green[i + offsY][j + offsX],(psG1[i][j] + psG2[i][j]) / 2.f); - blue[i + offsY][j + offsX] = intp(psMask[i][j],blue[i + offsY][j + offsX], psBlue[i][j]); +#ifdef __SSE2__ + float blend = psMask[i][j]; +#else + float blend = pow_F(std::max(psMask[i][j],0.f),smoothFactor); +#endif + red[i + offsY][j + offsX] = intp(blend, red[i + offsY][j + offsX], psRed[i][j] ); + green[i + offsY][j + offsX] = intp(blend, green[i + offsY][j + offsX],(psG1[i][j] + psG2[i][j]) / 2.f); + blue[i + offsY][j + offsX] = intp(blend, blue[i + offsY][j + offsX], psBlue[i][j]); } else { red[i + offsY][j + offsX] = psRed[i][j]; green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 2edf7c77e..d0a79e6a8 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -897,7 +897,7 @@ void RAWParams::BayerSensor::setPixelShiftDefaults() pixelShiftMedian3 = false; pixelShiftGreen = true; pixelShiftBlur = true; - pixelShiftSmooth = true; + pixelShiftSmoothFactor = 0.7; pixelShiftExp0 = false; pixelShiftNonGreenCross = true; pixelShiftNonGreenCross2 = false; @@ -3485,7 +3485,7 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b } if (!pedited || pedited->raw.bayersensor.pixelShiftSmooth) { - keyFile.set_boolean ("RAW Bayer", "pixelShiftSmooth", raw.bayersensor.pixelShiftSmooth ); + keyFile.set_double ("RAW Bayer", "pixelShiftSmoothFactor", raw.bayersensor.pixelShiftSmoothFactor ); } if (!pedited || pedited->raw.bayersensor.pixelShiftExp0) { @@ -7736,8 +7736,8 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } - if (keyFile.has_key ("RAW Bayer", "pixelShiftSmooth")) { - raw.bayersensor.pixelShiftSmooth = keyFile.get_boolean("RAW Bayer", "pixelShiftSmooth"); + if (keyFile.has_key ("RAW Bayer", "pixelShiftSmoothFactor")) { + raw.bayersensor.pixelShiftSmoothFactor = keyFile.get_double("RAW Bayer", "pixelShiftSmoothFactor"); if (pedited) { pedited->raw.bayersensor.pixelShiftSmooth = true; @@ -8235,7 +8235,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3 && raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen && raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur - && raw.bayersensor.pixelShiftSmooth == other.raw.bayersensor.pixelShiftSmooth + && raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor && raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0 && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 diff --git a/rtengine/procparams.h b/rtengine/procparams.h index dbf285fb2..21fe97855 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1229,7 +1229,7 @@ public: bool pixelShiftMedian3; bool pixelShiftGreen; bool pixelShiftBlur; - bool pixelShiftSmooth; + double pixelShiftSmoothFactor; bool pixelShiftExp0; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index f5bea64d3..e5cce8f57 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2035,7 +2035,7 @@ void RawImageSource::demosaic(const RAWParams &raw) bayerParams.pixelShiftAutomatic = false; bayerParams.pixelshiftShowMotion = false; } - if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftSmooth)) { + if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftSmoothFactor > 0.0)) { if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic) && numFrames == 4) { if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction if(!bayerParams.pixelShiftMedian3) { diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 89b92ebd2..8c2b8da48 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -128,8 +128,15 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTBLUR_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftBlur); - pixelShiftSmooth = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSMOOTH"))); + pixelShiftSmooth = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSMOOTH"), 0, 1, 0.05, 0.7)); pixelShiftSmooth->set_tooltip_text (M("TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP")); + pixelShiftSmooth->setAdjusterListener (this); + + if (pixelShiftSmooth->delay < options.adjusterMaxDelay) { + pixelShiftSmooth->delay = options.adjusterMaxDelay; + } + + pixelShiftSmooth->show(); pixelShiftOptions->pack_start(*pixelShiftSmooth); pixelShiftHoleFill = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); @@ -305,7 +312,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMedian3conn = pixelShiftMedian3->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedian3Changed), true); pixelShiftGreenconn = pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true); pixelShiftBlurconn = pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true); - pixelShiftSmoothconn = pixelShiftSmooth->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftSmoothChanged), true); pixelShiftExp0conn = pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); @@ -347,7 +353,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftMedian3->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_inconsistent(!pedited->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); - pixelShiftSmooth->set_inconsistent(!pedited->raw.bayersensor.pixelShiftSmooth); + pixelShiftSmooth->setEditedState ( pedited->raw.bayersensor.pixelShiftSmooth ? Edited : UnEdited); pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); @@ -392,7 +398,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftMedian3->set_active(pp->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_active(pp->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); - pixelShiftSmooth->set_active(pp->raw.bayersensor.pixelShiftSmooth); + pixelShiftSmooth->setValue (pp->raw.bayersensor.pixelShiftSmoothFactor); pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); @@ -491,7 +497,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftMedian3 = pixelShiftMedian3->get_active(); pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->get_active(); pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); - pp->raw.bayersensor.pixelShiftSmooth = pixelShiftSmooth->get_active(); + pp->raw.bayersensor.pixelShiftSmoothFactor = pixelShiftSmooth->getValue(); pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); @@ -538,7 +544,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftMedian3 = !pixelShiftMedian3->get_inconsistent(); pedited->raw.bayersensor.pixelShiftGreen = !pixelShiftGreen->get_inconsistent(); pedited->raw.bayersensor.pixelShiftBlur = !pixelShiftBlur->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftSmooth = !pixelShiftSmooth->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftSmooth = pixelShiftSmooth->getEditedState(); pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); @@ -651,6 +657,8 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvPixelShiftSum, a->getTextValue() ); } else if (a == pixelShiftRedBlueWeight) { listener->panelChanged (EvPixelShiftRedBlueWeight, a->getTextValue() ); + } else if (a == pixelShiftSmooth) { + listener->panelChanged (EvPixelShiftSmooth, a->getTextValue() ); } } } @@ -990,26 +998,6 @@ void BayerProcess::pixelShiftBlurChanged () } } -void BayerProcess::pixelShiftSmoothChanged () -{ - if (batchMode) { - if (pixelShiftSmooth->get_inconsistent()) { - pixelShiftSmooth->set_inconsistent (false); - pixelShiftSmoothconn.block (true); - pixelShiftSmooth->set_active (false); - pixelShiftSmoothconn.block (false); - } else if (lastDCBen) { - pixelShiftSmooth->set_inconsistent (true); - } - - lastDCBen = pixelShiftSmooth->get_active (); - } - - if (listener) { - listener->panelChanged (EvPixelShiftSmooth, pixelShiftSmooth->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - void BayerProcess::pixelShiftExp0Changed () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 135c02df5..def4021ce 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -56,11 +56,11 @@ protected: Gtk::CheckButton* pixelShiftNonGreenAmaze; Gtk::CheckButton* pixelShiftGreen; Gtk::CheckButton* pixelShiftBlur; - Gtk::CheckButton* pixelShiftSmooth; Gtk::CheckButton* pixelShiftExp0; Gtk::CheckButton* pixelShiftHoleFill; Gtk::CheckButton* pixelShiftMedian; Gtk::CheckButton* pixelShiftMedian3; + Adjuster* pixelShiftSmooth; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; @@ -101,7 +101,6 @@ public: void pixelShiftMedian3Changed(); void pixelShiftGreenChanged(); void pixelShiftBlurChanged(); - void pixelShiftSmoothChanged(); void pixelShiftExp0Changed(); void pixelShiftNonGreenCrossChanged(); void pixelShiftNonGreenCross2Changed(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 061424acf..e1303095a 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -915,7 +915,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftMedian3 = raw.bayersensor.pixelShiftMedian3 && p.raw.bayersensor.pixelShiftMedian3 == other.raw.bayersensor.pixelShiftMedian3; raw.bayersensor.pixelShiftGreen = raw.bayersensor.pixelShiftGreen && p.raw.bayersensor.pixelShiftGreen == other.raw.bayersensor.pixelShiftGreen; raw.bayersensor.pixelShiftBlur = raw.bayersensor.pixelShiftBlur && p.raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur; - raw.bayersensor.pixelShiftSmooth = raw.bayersensor.pixelShiftSmooth && p.raw.bayersensor.pixelShiftSmooth == other.raw.bayersensor.pixelShiftSmooth; + raw.bayersensor.pixelShiftSmooth = raw.bayersensor.pixelShiftSmooth && p.raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor; raw.bayersensor.pixelShiftExp0 = raw.bayersensor.pixelShiftExp0 && p.raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; @@ -2421,7 +2421,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten } if (raw.bayersensor.pixelShiftSmooth) { - toEdit.raw.bayersensor.pixelShiftSmooth = mods.raw.bayersensor.pixelShiftSmooth; + toEdit.raw.bayersensor.pixelShiftSmoothFactor = mods.raw.bayersensor.pixelShiftSmoothFactor; } if (raw.bayersensor.pixelShiftExp0) { From 46e078c7396017694fb3047c5ccb827cb1284439 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 27 Jan 2017 14:26:27 +0100 Subject: [PATCH 71/83] pixelshift: speedup and new experimental ISO adaption --- rtengine/pixelshift.cc | 878 ++++++++++++++++++++++------------------- 1 file changed, 464 insertions(+), 414 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 188b5f4bf..26ac2418f 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -169,18 +169,22 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar auto yUp = y - 1, yDown = y + 1; bool lastXUp = false, lastXDown = false, firstXUp = false, firstXDown = false; mask[y][x] = 0; + if(yUp >= yStart && mask[yUp][x] == 255) { coordStack.emplace(x, yUp); firstXUp = lastXUp = true; } + if(yDown < yEnd && mask[yDown][x] == 255) { coordStack.emplace(x, yDown); firstXDown = lastXDown = true; } + auto xr = x + 1; - + while(xr < xEnd && mask[y][xr] == 255) { mask[y][xr] = 0; + if(yUp >= yStart && mask[yUp][xr] == 255) { if(!lastXUp) { coordStack.emplace(xr, yUp); @@ -189,6 +193,7 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar } else { lastXUp = false; } + if(yDown < yEnd && mask[yDown][xr] == 255) { if(!lastXDown) { coordStack.emplace(xr, yDown); @@ -197,14 +202,17 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar } else { lastXDown = false; } + xr++; } auto xl = x - 1; lastXUp = firstXUp; lastXDown = firstXDown; + while(xl >= xStart && mask[y][xl] == 255) { mask[y][xl] = 0; + if(yUp >= yStart && mask[yUp][xl] == 255) { if(!lastXUp) { coordStack.emplace(xl, yUp); @@ -213,6 +221,7 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar } else { lastXUp = false; } + if(yDown < yEnd && mask[yDown][xl] == 255) { if(!lastXDown) { coordStack.emplace(xl, yDown); @@ -221,8 +230,10 @@ void floodFill4Impl(int y, int x, int xStart, int xEnd, int yStart, int yEnd, ar } else { lastXDown = false; } + xl--; } + mask[y][x] = 0; } } @@ -232,55 +243,61 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D &ma { #pragma omp parallel { - std::stack, std::vector>> coordStack; + std::stack, std::vector>> coordStack; - #pragma omp for schedule(dynamic,128) nowait - for(uint16_t i = yStart;i= 0 ;i--) - floodFill4Impl(i, xEnd - 1, xStart, xEnd, yStart, yEnd, mask, coordStack); - - #pragma omp sections nowait - { - #pragma omp section + for(uint16_t i = yStart; i < yEnd; i++) { - uint16_t i = yStart; + floodFill4Impl(i, xStart, xStart, xEnd, yStart, yEnd, mask, coordStack); + } - for(uint16_t j = xStart; j < xEnd; j++) + #pragma omp for schedule(dynamic,128) nowait + + for(int16_t i = yEnd - 1; i >= 0 ; i--) + { + floodFill4Impl(i, xEnd - 1, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + + #pragma omp sections nowait + { + #pragma omp section { - floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + uint16_t i = yStart; + + for(uint16_t j = xStart; j < xEnd; j++) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yStart; + + for(uint16_t j = xEnd - 1; j >= xStart; j--) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yEnd; + + for(uint16_t j = xStart; j < xEnd; j++) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } + } + #pragma omp section + { + uint16_t i = yEnd; + + for(uint16_t j = xEnd - 1; j >= xStart; j--) + { + floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); + } } } - #pragma omp section - { - uint16_t i = yStart; - - for(uint16_t j = xEnd - 1; j >= xStart; j--) - { - floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); - } - } - #pragma omp section - { - uint16_t i = yEnd; - - for(uint16_t j = xStart; j < xEnd; j++) - { - floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); - } - } - #pragma omp section - { - uint16_t i = yEnd; - - for(uint16_t j = xEnd - 1; j >= xStart; j--) - { - floodFill4Impl(i, j, xStart, xEnd, yStart, yEnd, mask, coordStack); - } - } - } } } @@ -900,7 +917,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const bool checkNonGreenAmaze = bayerParams.pixelShiftNonGreenAmaze; const bool checkNonGreenCross2 = bayerParams.pixelShiftNonGreenCross2; const bool checkGreen = bayerParams.pixelShiftGreen; - const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight; + const float greenWeight = 2.f; + const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight + 1.f; const bool blurMap = bayerParams.pixelShiftBlur; const float sigma = bayerParams.pixelShiftSigma; const float threshold = bayerParams.pixelShiftSum; @@ -1077,8 +1095,13 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } nRead *= pow(2.f, nreadIso); - eperIsoModel *= pow(2.f, eperIso); - eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); + eperIsoModel *= pow(2.f, eperIso * 0.5f); + + if(adaptive && experimental0) { + eperIso = eperIsoModel * sqrtf(100.f / (rawWpCorrection * idata->getISOSpeed())); + } else { + eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); + } float eperIsoRed = eperIso / scale_mul[0]; float eperIsoGreen = eperIso * scaleGreen; @@ -1128,8 +1151,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA array2D psG1(winw + 32, winh); array2D psG2(winw + 32, winh); array2D psBlue(winw + 32, winh); + array2D psMask(winw, winh); + + // Fill the mask with value 1.0 + // We work in 1.0 to 2.0 range to avoid performance issues caused by denormal numbers in gaussian blur + for(int i = 0; i < winh; ++i) { + for(int j = 0; j < winw; ++j) { + psMask[i][j] = 1.f; + } + } - array2D psMask(winw, winh, ARRAY2D_CLEAR_DATA); // fill channels psRed, psG1, psG2 and psBlue #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) @@ -1165,433 +1196,447 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } // now that the temporary planes are filled for easy access we do the motion detection - int sum0 = 0; - int sum1 = 0; + int sum[2] = {0}; + float pixelcount = ((winh - (border + offsY) - (winy + border - offsY)) * (winw - (border + offsX) - (winx + border - offsX))) / 2.f; + #ifdef _OPENMP - #pragma omp parallel for reduction(+:sum0,sum1) schedule(dynamic,16) + #pragma omp parallel +#endif + { + int sumThr[2] = {0}; +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) nowait #endif - for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { - float *greenDest = green[i + offsY]; - float *redDest = red[i + offsY]; - float *blueDest = blue[i + offsY]; - int j = winx + border - offsX; + for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { + float *greenDest = green[i + offsY]; + float *redDest = red[i + offsY]; + float *blueDest = blue[i + offsY]; + int j = winx + border - offsX; - float greenDifMax[gridSize]; // Here we store the maximum differences per Column + float greenDifMax[gridSize]; // Here we store the maximum differences per Column + + // green channel motion detection checks the grid around the pixel for differences in green channels + if(detectMotion || (adaptive && checkGreen)) { + if(gridSize == 3) { + // compute maximum of differences for first two columns of 3x3 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } else if(gridSize == 5) { + // compute maximum of differences for first four columns of 5x5 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } else if(gridSize == 7) { + // compute maximum of differences for first six columns of 7x7 grid + greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + } - // green channel motion detection checks the grid around the pixel for differences in green channels - if(detectMotion || (adaptive && checkGreen)) { - if(gridSize == 3) { - // compute maximum of differences for first two columns of 3x3 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - } else if(gridSize == 5) { - // compute maximum of differences for first four columns of 5x5 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - } else if(gridSize == 7) { - // compute maximum of differences for first six columns of 7x7 grid - greenDifMax[0] = std::max({greenDiff(psG1[i - 3][j - 3], psG2[i - 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j - 3], psG2[i - 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j - 3], psG2[i - 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 3], psG2[ i ][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 3], psG2[i + 1][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j - 3], psG2[i + 2][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j - 3], psG2[i + 3][j - 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[1] = std::max({greenDiff(psG1[i - 3][j - 2], psG2[i - 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j - 2], psG2[i - 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j - 2], psG2[i - 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 2], psG2[ i ][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 2], psG2[i + 1][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j - 2], psG2[i + 2][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j - 2], psG2[i + 3][j - 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[2] = std::max({greenDiff(psG1[i - 3][j - 1], psG2[i - 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j - 1], psG2[i - 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j - 1], psG2[i - 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j - 1], psG2[ i ][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j - 1], psG2[i + 1][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j - 1], psG2[i + 2][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j - 1], psG2[i + 3][j - 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[3] = std::max({greenDiff(psG1[i - 3][ j ], psG2[i - 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][ j ], psG2[i - 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][ j ], psG2[i - 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][ j ], psG2[ i ][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][ j ], psG2[i + 1][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][ j ], psG2[i + 2][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][ j ], psG2[i + 3][ j ], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[4] = std::max({greenDiff(psG1[i - 3][j + 1], psG2[i - 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j + 1], psG2[i - 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j + 1], psG2[i + 2][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j + 1], psG2[i + 3][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - greenDifMax[5] = std::max({greenDiff(psG1[i - 3][j + 2], psG2[i - 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j + 2], psG2[i + 3][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); } - } + // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 + int lastIndex = gridSize - 1; + float korr = 0.f; + int c = FC(i, j); + bool blueRow = false; - // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 - int lastIndex = gridSize - 1; - float korr = 0.f; - int c = FC(i, j); - bool blueRow = false; + if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + // row with blue pixels => swap destination pointers for non green pixels + blueRow = true; + } - if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { - // row with blue pixels => swap destination pointers for non green pixels - blueRow = true; - } - - // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop - unsigned int offset = (c & 1); + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); // offset ^= 1; // 0 => 1 or 1 => 0 - for(; j < winw - (border + offsX); ++j) { - bool greenFromPs = false; - offset ^= 1; // 0 => 1 or 1 => 0 + for(; j < winw - (border + offsX); ++j) { + bool greenFromPs = false; + offset ^= 1; // 0 => 1 or 1 => 0 - if(detectMotion || (adaptive && checkGreen)) { - bool skipNext = false; - float gridMax; + if(detectMotion || (adaptive && checkGreen)) { + bool skipNext = false; + float gridMax; - if(gridSize < 2) { - // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps - gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i); - skipNext = skip; - } else if(gridSize == 3) { - // compute maximum of differences for third column of 3x3 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); - } else if(gridSize == 5) { - // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); - } else if(gridSize == 7) { - // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex - greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), - }); - // calculate maximum of whole grid by calculating maximum of grid column max values - gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); - } - - - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - - // increase motion detection dependent on brightness - if(!adaptive) { - korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; - } - - if (gridMax > thresh - korr) { - if(offset == 0) { - sum0 ++; - } else { - sum1 ++; + if(gridSize < 2) { + // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps + gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i); + skipNext = skip; + } else if(gridSize == 3) { + // compute maximum of differences for third column of 3x3 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 1][j + 1], psG2[i - 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 1], psG2[ i ][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 1], psG2[i + 1][j + 1], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); + } else if(gridSize == 5) { + // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 2], psG2[i - 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 2], psG2[ i ][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 2], psG2[i + 1][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 2], psG2[i + 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i) + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); + } else if(gridSize == 7) { + // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex + greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 2][j + 3], psG2[i - 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i - 1][j + 3], psG2[i - 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[ i ][j + 3], psG2[ i ][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 1][j + 3], psG2[i + 1][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 2][j + 3], psG2[i + 2][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + greenDiff(psG1[i + 3][j + 3], psG2[i + 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), + }); + // calculate maximum of whole grid by calculating maximum of grid column max values + gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); } - if(nOf3x3) { - psMask[i][j] = 1.f; - } else if((offset == (frame & 1)) && checkNonGreenVertical) { - if(frame > 1) { - green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; + + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; + + if(!adaptive) { + // increase motion detection dependent on brightness + korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; + } + + if (gridMax > thresh - korr) { + sumThr[offset] ++; + + if(nOf3x3) { + psMask[i][j] = greenWeight; + } else if((offset == (frame & 1)) && checkNonGreenVertical) { + if(frame > 1) { + green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; + } else { + green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; + } + + continue; } else { - green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; - } - - continue; - } else { - // at least one of the tested green pixels of the grid is detected as motion - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); - - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; + // at least one of the tested green pixels of the grid is detected as motion paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + + if(skipNext) { + // treat the horizontally next pixel also as motion + j++; + paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); + } + + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; } - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; } } - } - if(adaptive && checkNonGreenCross) { - // check red cross - float redTop = psRed[i - 1][ j ]; - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - float redBottom = psRed[i + 1][ j ]; - float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(adaptive) { + if(checkNonGreenCross) { + // check red cross + float redTop = psRed[i - 1][ j ]; + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; + float redBottom = psRed[i + 1][ j ]; + float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(redDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); - } + if(redDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + } - continue; - } - - // check blue cross - float blueTop = psBlue[i - 1][ j ]; - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; - float blueBottom = psBlue[i + 1][ j ]; - float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); - } - - continue; - - } - } - - if(adaptive && checkNonGreenHorizontal) { - float redLeft = psRed[ i ][j - 1]; - float redCentre = psRed[ i ][ j ]; - float redRight = psRed[ i ][j + 1]; - - float redDiffLeft = redLeft - redCentre; - float redDiffRight = redRight - redCentre; - - if(redDiffLeft * redDiffRight >= 0.f) { - float redAvg = (redRight + redLeft) / 2.f; - float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - - if(redDiffHor > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); + continue; } - continue; + // check blue cross + float blueTop = psBlue[i - 1][ j ]; + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + float blueBottom = psBlue[i + 1][ j ]; + float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + + } } - } - float blueLeft = psBlue[ i ][j - 1]; - float blueCentre = psBlue[ i ][ j ]; - float blueRight = psBlue[ i ][j + 1]; + if(checkNonGreenHorizontal) { + float redLeft = psRed[ i ][j - 1]; + float redCentre = psRed[ i ][ j ]; + float redRight = psRed[ i ][j + 1]; - float blueDiffLeft = blueLeft - blueCentre; - float blueDiffRight = blueRight - blueCentre; + float redDiffLeft = redLeft - redCentre; + float redDiffRight = redRight - redCentre; - if(blueDiffLeft * blueDiffRight >= 0.f) { - float blueAvg = (blueRight + blueLeft) / 2.f; - float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + if(redDiffLeft * redDiffRight >= 0.f) { + float redAvg = (redRight + redLeft) / 2.f; + float redDiffHor = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(blueDiffHor > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, blueDest, redDest, greenDest); + if(redDiffHor > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiffHor, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } } - continue; + float blueLeft = psBlue[ i ][j - 1]; + float blueCentre = psBlue[ i ][ j ]; + float blueRight = psBlue[ i ][j + 1]; + + float blueDiffLeft = blueLeft - blueCentre; + float blueDiffRight = blueRight - blueCentre; + + if(blueDiffLeft * blueDiffRight >= 0.f) { + float blueAvg = (blueRight + blueLeft) / 2.f; + float blueDiffHor = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiffHor > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiffHor, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + } + } } - } - } - if(adaptive && checkNonGreenVertical) { - // check red vertically - float redTop = psRed[i - 1][ j ]; - float redCentre = psRed[ i ][ j ]; - float redBottom = psRed[i + 1][ j ]; + if(checkNonGreenVertical) { + // check red vertically + float redTop = psRed[i - 1][ j ]; + float redCentre = psRed[ i ][ j ]; + float redBottom = psRed[i + 1][ j ]; - float redDiffTop = redTop - redCentre; - float redDiffBottom = redBottom - redCentre; + float redDiffTop = redTop - redCentre; + float redDiffBottom = redBottom - redCentre; - if(redDiffTop * redDiffBottom >= 0.f) { - float redAvg = (redTop + redBottom) / 2.f; - float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(redDiffTop * redDiffBottom >= 0.f) { + float redAvg = (redTop + redBottom) / 2.f; + float redDiff = nonGreenDiff(redCentre, redAvg, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(redDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + if(redDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); + } + + continue; + } } - continue; + // check blue vertically + float blueTop = psBlue[i - 1][ j ]; + float blueCentre = psBlue[ i ][ j ]; + float blueBottom = psBlue[i + 1][ j ]; + + float blueDiffTop = blueTop - blueCentre; + float blueDiffBottom = blueBottom - blueCentre; + + if(blueDiffTop * blueDiffBottom >= 0.f) { + float blueAvg = (blueTop + blueBottom) / 2.f; + float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + + if(blueDiff > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + } + + continue; + } + } } - } - // check blue vertically - float blueTop = psBlue[i - 1][ j ]; - float blueCentre = psBlue[ i ][ j ]; - float blueBottom = psBlue[i + 1][ j ]; + if(checkNonGreenAmaze) { + // check current pixel against amaze + float redCentre = psRed[ i ][ j ]; + float redAmaze = red[i + offsY][j + offsX]; - float blueDiffTop = blueTop - blueCentre; - float blueDiffBottom = blueBottom - blueCentre; + float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); - if(blueDiffTop * blueDiffBottom >= 0.f) { - float blueAvg = (blueTop + blueBottom) / 2.f; - float blueDiff = nonGreenDiff(blueCentre, blueAvg, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); + if(redDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); + } - if(blueDiff > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); + continue; } - continue; - } - } - } + float blueCentre = psBlue[ i ][ j ]; + float blueAmaze = blue[i + offsY][j + offsX]; - if(adaptive && checkNonGreenAmaze) { - // check current pixel against amaze - float redCentre = psRed[ i ][ j ]; - float redAmaze = red[i + offsY][j + offsX]; + float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - float redDiffAmaze = nonGreenDiff(redCentre, redAmaze, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); + if(blueDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = redBlueWeight; + } else { + paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); + } - if(redDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, redDiffAmaze, showOnlyMask, redDest, blueDest, greenDest); + continue; + } } - continue; - } + if(checkNonGreenCross2) { // for green amaze + float greenCentre = (psG1[ i ][ j ] + psG2[ i ][ j ]) / 2.f; + float greenAmaze = green[i + offsY][j + offsX]; + float greenDiffAmaze = nonGreenDiff(greenCentre, greenAmaze, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); - float blueCentre = psBlue[ i ][ j ]; - float blueAmaze = blue[i + offsY][j + offsX]; + if(greenDiffAmaze > 0.f) { + if(nOf3x3) { + psMask[i][j] = greenWeight; + } else { + paintMotionMask(j + offsX, showMotion, greenDiffAmaze, showOnlyMask, greenDest, redDest, blueDest); + } - float blueDiffAmaze = nonGreenDiff(blueCentre, blueAmaze, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); - - if(blueDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = redBlueWeight; - } else { - paintMotionMask(j + offsX, showMotion, blueDiffAmaze, showOnlyMask, blueDest, redDest, greenDest); + continue; + } } - continue; - } - } + if(experimental0) { // for experiments + // float green1Median, green2Median; + // green1Median = median(psG1[ i - 1 ][ j - 1 ],psG1[ i - 1 ][ j + 1 ],psG1[ i ][ j ],psG1[ i + 1 ][ j -1 ],psG1[ i + 1 ][ j + 1 ]); + // green2Median = median(psG2[ i - 1 ][ j - 1 ],psG2[ i - 1 ][ j + 1 ],psG2[ i ][ j ],psG2[ i + 1 ][ j -1 ],psG2[ i + 1 ][ j + 1 ]); + // float greenDiffMedian = nonGreenDiff(green1Median, green2Median, stddevFactorGreen * 0.36f, eperIsoGreen, nRead, prnu, showMotion); + // + // if(greenDiffMedian > 0.f) { + // if(nOf3x3) { + // psMask[i][j] = 1.f; + // } else { + // paintMotionMask(j + offsX, showMotion, greenDiffMedian, showOnlyMask, greenDest, redDest, blueDest); + // } + // + // continue; + // } - if(adaptive && checkNonGreenCross2) { // for green amaze - float greenCentre = (psG1[ i ][ j ] + psG2[ i ][ j ]) / 2.f; - float greenAmaze = green[i + offsY][j + offsX]; - float greenDiffAmaze = nonGreenDiff(greenCentre, greenAmaze, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); - - if(greenDiffAmaze > 0.f) { - if(nOf3x3) { - psMask[i][j] = 1.f; - } else { - paintMotionMask(j + offsX, showMotion, greenDiffAmaze, showOnlyMask, greenDest, redDest, blueDest); } - - continue; } - } - if(adaptive && experimental0) { // for experiments -// float green1Median, green2Median; -// green1Median = median(psG1[ i - 1 ][ j - 1 ],psG1[ i - 1 ][ j + 1 ],psG1[ i ][ j ],psG1[ i + 1 ][ j -1 ],psG1[ i + 1 ][ j + 1 ]); -// green2Median = median(psG2[ i - 1 ][ j - 1 ],psG2[ i - 1 ][ j + 1 ],psG2[ i ][ j ],psG2[ i + 1 ][ j -1 ],psG2[ i + 1 ][ j + 1 ]); -// float greenDiffMedian = nonGreenDiff(green1Median, green2Median, stddevFactorGreen * 0.36f, eperIsoGreen, nRead, prnu, showMotion); -// -// if(greenDiffMedian > 0.f) { -// if(nOf3x3) { -// psMask[i][j] = 1.f; -// } else { -// paintMotionMask(j + offsX, showMotion, greenDiffMedian, showOnlyMask, greenDest, redDest, blueDest); -// } -// -// continue; -// } - - } - - if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black - red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; - } else if(!(adaptive && nOf3x3)) { - // no motion detected, replace the a priori demosaiced values by the pixelshift combined values - red[i + offsY][j + offsX] = psRed[i][j]; - green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; - blue[i + offsY][j + offsX] = psBlue[i][j]; + if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; + } else if(!(adaptive && nOf3x3)) { + // no motion detected, replace the a priori demosaiced values by the pixelshift combined values + red[i + offsY][j + offsX] = psRed[i][j]; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + blue[i + offsY][j + offsX] = psBlue[i][j]; + } } } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + sum[0] += sumThr[0]; + sum[1] += sumThr[0]; + } } + float percent0 = 100.f * sum[0] / pixelcount; + float percent1 = 100.f * sum[1] / pixelcount; - float percent0 = 100.f * sum0 / pixelcount; - float percent1 = 100.f * sum1 / pixelcount; - - std::cout << fileName << " : Green detections at stddev " << std::setprecision( 2 ) << bayerParams.pixelShiftStddevFactorGreen << " : Frame 1/3 : " << std::setprecision( 6 ) << sum0 << " (" << percent0 << "%)" << " Frame 2/4 : " << sum1 << " (" << percent1 << "%)" << std::endl; + std::cout << fileName << " : Green detections at stddev " << std::setprecision( 2 ) << bayerParams.pixelShiftStddevFactorGreen << " : Frame 1/3 : " << std::setprecision( 6 ) << sum[0] << " (" << percent0 << "%)" << " Frame 2/4 : " << sum[1] << " (" << percent1 << "%)" << std::endl; if(adaptive && nOf3x3) { if(blurMap) { + StopWatch Stop1("Blur"); #pragma omp parallel { gaussianBlur(psMask, psMask, winw, winh, sigma); @@ -1611,14 +1656,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int v = -1; v <= 1; v++) { for(int h = -1; h < 1; h++) { - v3sum[1 + h] += psMask[i + v][j + h]; + v3sum[1 + h] += (psMask[i + v][j + h] - 1.f); } } float blocksum = v3sum[0] + v3sum[1]; for(int voffset = 2; j < winw - (border + offsX); ++j, ++voffset) { - float colSum = psMask[i - 1][j + 1] + psMask[i][j + 1] + psMask[i + 1][j + 1]; + float colSum = psMask[i - 1][j + 1] + psMask[i][j + 1] + psMask[i + 1][j + 1] - 3.f; voffset = voffset == 3 ? 0 : voffset; // faster than voffset %= 3; blocksum -= v3sum[voffset]; blocksum += colSum; @@ -1640,26 +1685,31 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { #ifdef __SSE2__ + if(!(showMotion && showOnlyMask) && smoothTransitions) { if(smoothFactor == 0.f) { for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { - psMask[i][j] = 1.f; + psMask[i][j] = greenWeight - 1.f; } } else { vfloat zerov = F2V(0.f); + vfloat onev = F2V(1.f); vfloat smoothv = F2V(smoothFactor); int j = winx + border - offsX; - for(; j < winw - (border + offsX)- 3; j += 4) { - vfloat blendv = LVFU(psMask[i][j]); + + for(; j < winw - (border + offsX) - 3; j += 4) { + vfloat blendv = LVFU(psMask[i][j]) - onev; blendv = vmaxf(blendv, zerov); blendv = pow_F(blendv, smoothv); STVFU(psMask[i][j], blendv); } + for(; j < winw - (border + offsX); ++j) { - psMask[i][j] = pow_F(std::max(psMask[i][j],0.f),smoothFactor); + psMask[i][j] = pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); } } } + #endif float *greenDest = green[i + offsY]; float *redDest = red[i + offsY]; @@ -1678,10 +1728,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #ifdef __SSE2__ float blend = psMask[i][j]; #else - float blend = pow_F(std::max(psMask[i][j],0.f),smoothFactor); + float blend = pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); #endif red[i + offsY][j + offsX] = intp(blend, red[i + offsY][j + offsX], psRed[i][j] ); - green[i + offsY][j + offsX] = intp(blend, green[i + offsY][j + offsX],(psG1[i][j] + psG2[i][j]) / 2.f); + green[i + offsY][j + offsX] = intp(blend, green[i + offsY][j + offsX], (psG1[i][j] + psG2[i][j]) / 2.f); blue[i + offsY][j + offsX] = intp(blend, blue[i + offsY][j + offsX], psBlue[i][j]); } else { red[i + offsY][j + offsX] = psRed[i][j]; From 262e9291115647ba5d6fc5641480a8099f072a06 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 27 Jan 2017 16:39:39 +0100 Subject: [PATCH 72/83] pxelshift: small optimization for 3x3new --- rtengine/pixelshift.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 26ac2418f..d933c361b 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -921,7 +921,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight + 1.f; const bool blurMap = bayerParams.pixelShiftBlur; const float sigma = bayerParams.pixelShiftSigma; - const float threshold = bayerParams.pixelShiftSum; + const float threshold = bayerParams.pixelShiftSum + 9.f; const bool experimental0 = bayerParams.pixelShiftExp0; const bool holeFill = bayerParams.pixelShiftHoleFill; const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmoothFactor > 0.; @@ -1656,14 +1656,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int v = -1; v <= 1; v++) { for(int h = -1; h < 1; h++) { - v3sum[1 + h] += (psMask[i + v][j + h] - 1.f); + v3sum[1 + h] += (psMask[i + v][j + h]); } } float blocksum = v3sum[0] + v3sum[1]; for(int voffset = 2; j < winw - (border + offsX); ++j, ++voffset) { - float colSum = psMask[i - 1][j + 1] + psMask[i][j + 1] + psMask[i + 1][j + 1] - 3.f; + float colSum = psMask[i - 1][j + 1] + psMask[i][j + 1] + psMask[i + 1][j + 1]; voffset = voffset == 3 ? 0 : voffset; // faster than voffset %= 3; blocksum -= v3sum[voffset]; blocksum += colSum; From bd78989b9cd5f67b84fbc6741304592d5c1f843e Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 27 Jan 2017 22:06:07 +0100 Subject: [PATCH 73/83] pixelshift: fixed accidently commited change to eperiso adjuster --- rtengine/pixelshift.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index d933c361b..ed967c074 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -1095,7 +1095,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } nRead *= pow(2.f, nreadIso); - eperIsoModel *= pow(2.f, eperIso * 0.5f); + eperIsoModel *= pow(2.f, eperIso); if(adaptive && experimental0) { eperIso = eperIsoModel * sqrtf(100.f / (rawWpCorrection * idata->getISOSpeed())); From 3f2f1fb8ef6216920390b733ea4a3944fba65d37 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 29 Jan 2017 15:16:16 +0100 Subject: [PATCH 74/83] pixelshift: fixed wrong weight of red/blue in 3x3new --- rtengine/pixelshift.cc | 97 +++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 58 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index ed967c074..1b9689137 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -1040,7 +1040,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); int gridSize = 1; bool nOf3x3 = false; - switch (gridSize_) { case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: @@ -1064,6 +1063,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA nOf3x3 = true; } + if(adaptive && blurMap && nOf3x3 && smoothFactor == 0.f && !showMotion) { + if(plistener) { + plistener->setProgress(1.0); + } + return; + } + + // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); @@ -1151,15 +1158,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA array2D psG1(winw + 32, winh); array2D psG2(winw + 32, winh); array2D psBlue(winw + 32, winh); - array2D psMask(winw, winh); - - // Fill the mask with value 1.0 - // We work in 1.0 to 2.0 range to avoid performance issues caused by denormal numbers in gaussian blur - for(int i = 0; i < winh; ++i) { - for(int j = 0; j < winw; ++j) { - psMask[i][j] = 1.f; - } - } // fill channels psRed, psG1, psG2 and psBlue #ifdef _OPENMP @@ -1200,6 +1198,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float pixelcount = ((winh - (border + offsY) - (winy + border - offsY)) * (winw - (border + offsX) - (winx + border - offsX))) / 2.f; + array2D psMask(winw, winh); + + #ifdef _OPENMP #pragma omp parallel #endif @@ -1323,10 +1324,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop unsigned int offset = (c & 1); -// offset ^= 1; // 0 => 1 or 1 => 0 for(; j < winw - (border + offsX); ++j) { - bool greenFromPs = false; + psMask[i][j] = 1.f; + offset ^= 1; // 0 => 1 or 1 => 0 if(detectMotion || (adaptive && checkGreen)) { @@ -1345,6 +1346,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA }); // calculate maximum of whole grid by calculating maximum of grid column max values gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2]}); + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; } else if(gridSize == 5) { // compute maximum of differences for fifth column of 5x5 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 2][j + 2], psG2[i - 2][j + 2], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), @@ -1355,6 +1359,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA }); // calculate maximum of whole grid by calculating maximum of grid column max values gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4]}); + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; } else if(gridSize == 7) { // compute maximum of differences for 7th column of 7x7 grid and save at position lastIndex greenDifMax[lastIndex] = std::max({greenDiff(psG1[i - 3][j + 3], psG2[i - 3][j + 3], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i), @@ -1367,13 +1374,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA }); // calculate maximum of whole grid by calculating maximum of grid column max values gridMax = std::max({greenDifMax[0], greenDifMax[1], greenDifMax[2], greenDifMax[3], greenDifMax[4], greenDifMax[5], greenDifMax[6]}); + // adjust index for next column + lastIndex ++; + lastIndex = lastIndex == gridSize ? 0 : lastIndex; } - - // adjust index for next column - lastIndex ++; - lastIndex = lastIndex == gridSize ? 0 : lastIndex; - if(!adaptive) { // increase motion detection dependent on brightness korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; @@ -1391,7 +1396,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA green[i + offsY][j + offsX] = blueRow ? psG2[i][j] : psG1[i][j];; } - continue; } else { // at least one of the tested green pixels of the grid is detected as motion paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); @@ -1401,10 +1405,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA j++; paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); } - - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; } + // do not set the motion pixel values. They have already been set by demosaicer or showMotion + continue; } } @@ -1592,20 +1595,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } if(experimental0) { // for experiments - // float green1Median, green2Median; - // green1Median = median(psG1[ i - 1 ][ j - 1 ],psG1[ i - 1 ][ j + 1 ],psG1[ i ][ j ],psG1[ i + 1 ][ j -1 ],psG1[ i + 1 ][ j + 1 ]); - // green2Median = median(psG2[ i - 1 ][ j - 1 ],psG2[ i - 1 ][ j + 1 ],psG2[ i ][ j ],psG2[ i + 1 ][ j -1 ],psG2[ i + 1 ][ j + 1 ]); - // float greenDiffMedian = nonGreenDiff(green1Median, green2Median, stddevFactorGreen * 0.36f, eperIsoGreen, nRead, prnu, showMotion); - // - // if(greenDiffMedian > 0.f) { - // if(nOf3x3) { - // psMask[i][j] = 1.f; - // } else { - // paintMotionMask(j + offsX, showMotion, greenDiffMedian, showOnlyMask, greenDest, redDest, blueDest); - // } - // - // continue; - // } } } @@ -1629,6 +1618,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA sum[1] += sumThr[0]; } } + + float percent0 = 100.f * sum[0] / pixelcount; float percent1 = 100.f * sum[1] / pixelcount; @@ -1636,7 +1627,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(adaptive && nOf3x3) { if(blurMap) { - StopWatch Stop1("Blur"); #pragma omp parallel { gaussianBlur(psMask, psMask, winw, winh, sigma); @@ -1645,6 +1635,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA array2D mask(W, H, ARRAY2D_CLEAR_DATA); array2D maskInv(W, H, ARRAY2D_CLEAR_DATA); + #pragma omp parallel for schedule(dynamic,16) for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { @@ -1681,32 +1672,25 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA xorMasks(winx + border - offsX, winw - (border + offsX), winy + border - offsY, winh - (border + offsY), maskInv, mask); } + #pragma omp parallel for schedule(dynamic,16) for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { #ifdef __SSE2__ if(!(showMotion && showOnlyMask) && smoothTransitions) { - if(smoothFactor == 0.f) { - for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { - psMask[i][j] = greenWeight - 1.f; - } - } else { - vfloat zerov = F2V(0.f); - vfloat onev = F2V(1.f); - vfloat smoothv = F2V(smoothFactor); - int j = winx + border - offsX; + vfloat onev = F2V(1.f); + vfloat smoothv = F2V(smoothFactor); + int j = winx + border - offsX; - for(; j < winw - (border + offsX) - 3; j += 4) { - vfloat blendv = LVFU(psMask[i][j]) - onev; - blendv = vmaxf(blendv, zerov); - blendv = pow_F(blendv, smoothv); - STVFU(psMask[i][j], blendv); - } + for(; j < winw - (border + offsX) - 3; j += 4) { + vfloat blendv = vmaxf(LVFU(psMask[i][j]), onev) - onev; + blendv = pow_F(blendv, smoothv); + STVFU(psMask[i][j], blendv); + } - for(; j < winw - (border + offsX); ++j) { - psMask[i][j] = pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); - } + for(; j < winw - (border + offsX); ++j) { + psMask[i][j] = pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); } } @@ -1718,10 +1702,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { if(mask[i][j] == 255) { paintMotionMask(j + offsX, showMotion, 0.5f, showOnlyMask, greenDest, redDest, blueDest); - continue; - } - - if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + } else if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else { if(smoothTransitions) { From 291f1ed9667b62ed7d1a832cb936669249352425 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 29 Jan 2017 15:37:15 +0100 Subject: [PATCH 75/83] pixelshift: extended range of eperiso adjuster --- rtgui/bayerprocess.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 8c2b8da48..ef2905f8d 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -224,7 +224,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftStddevFactorBlue->show(); pixelShiftOptions->pack_start(*pixelShiftStddevFactorBlue); - pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -2.0, 2.0, 0.05, 0.0)); + pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -5.0, 5.0, 0.05, 0.0)); pixelShiftEperIso->setAdjusterListener (this); if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { From bcb3ce8164b9d71ecd17f7857b374fb2bbacf6d8 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 29 Jan 2017 17:28:30 +0100 Subject: [PATCH 76/83] pixelshift: changed ePerIso calculation --- rtengine/pixelshift.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 1b9689137..7696c1874 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -958,7 +958,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 1.5f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) }; - static const float ePerIsoK3II = 4 * 0.35f; + static const float ePerIsoK3II = 0.35f; static const float nReadK1[] = { 3.45f, // ISO 100 3.15f, // ISO 125 @@ -996,7 +996,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 2.4f // ISO 204800 }; - static const float ePerIsoK1 = 4 * 0.75f; + static const float ePerIsoK1 = 0.75f; static const float nReadK70[] = { 4.0f, // ISO 100 4.0f, // ISO 125 @@ -1029,7 +1029,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 3.0f // ISO > 51200 (we get a max ISO value of 65535 from dcraw) }; - static const float ePerIsoK70 = 4 * 0.5f; + static const float ePerIsoK70 = 0.5f; if (plistener) { plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::pixelshift])); @@ -1110,9 +1110,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); } - float eperIsoRed = eperIso / scale_mul[0]; - float eperIsoGreen = eperIso * scaleGreen; - float eperIsoBlue = eperIso / scale_mul[2]; + std::cout << "WL: " << c_white[0] << " BL: " << c_black[0] << " ePerIso multiplicator: " << (65535.f / (c_white[0] - c_black[0])) << std::endl; + + float eperIsoRed = (eperIso / scale_mul[0]) * (65535.f / (c_white[0]- c_black[0])); + float eperIsoGreen = (eperIso * scaleGreen) * (65535.f / (c_white[1]- c_black[1])); + float eperIsoBlue = (eperIso / scale_mul[2]) * (65535.f / (c_white[2]- c_black[2])); // printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); From bd492e0ece3de0ab2509b665996ca1b9b4b72132 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 1 Feb 2017 19:35:36 +0100 Subject: [PATCH 77/83] pixelshift: optionally select lmmse for motion in high iso files --- rtdata/languages/default | 2 ++ rtengine/dcraw.cc | 2 +- rtengine/demosaic_algos.cc | 2 +- rtengine/procevents.h | 1 + rtengine/procparams.cc | 14 ++++++++++++++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 32 ++++++++++++++++++++++++++------ rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 3 ++- rtgui/bayerprocess.cc | 28 ++++++++++++++++++++++++++++ rtgui/bayerprocess.h | 4 +++- rtgui/paramsedited.cc | 8 +++++++- rtgui/paramsedited.h | 1 + 13 files changed, 88 insertions(+), 12 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 68386d1bd..7d01c019d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -703,6 +703,7 @@ HISTORY_MSG_468;EvPixelShiftMedian HISTORY_MSG_469;EvPixelShiftMedian3 HISTORY_MSG_470;EvPixelShiftMotionMethod HISTORY_MSG_471;EvPixelShiftSmooth +HISTORY_MSG_472;EvPixelShiftLmmse HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1694,6 +1695,7 @@ TP_RAW_PIXELSHIFTMEDIAN3;Exclude selected frame from median TP_RAW_PIXELSHIFTHOLEFILL;3x3 new: Fill holes TP_RAW_PIXELSHIFTBLUR;3x3 new: Blur TP_RAW_PIXELSHIFTSMOOTH;3x3 new: Smooth transitions +TP_RAW_PIXELSHIFTLMMSE;Use lmmse for motion parts TP_RAW_PIXELSHIFTEXP0;Experimental TP_RAW_PIXELSHIFTGREEN;Check dual green TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 8e973913e..5a517b107 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -9486,7 +9486,7 @@ dng_skip: adobe_coeff (make, model); if(!strncmp(make, "Samsung", 7) && !strncmp(model, "NX1",3)) adobe_coeff (make, model); - if(!strncmp(make, "Pentax", 6) && (!strncmp(model, "K10D",4) || !strncmp(model, "K-70",4))) + if(!strncmp(make, "Pentax", 6) && (!strncmp(model, "K10D",4) || !strncmp(model, "K-70",4) || !strncmp(model, "K-1",3))) adobe_coeff (make, model); if(!strncmp(make, "Leica", 5) && !strncmp(model, "Q",1)) adobe_coeff (make, model); diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index e641ed777..1d8554792 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -1315,7 +1315,7 @@ void RawImageSource::jdl_interpolate_omp() // from "Lassus" // Adapted to RawTherapee by Jacques Desmis 3/2013 // Improved speed and reduced memory consumption by Ingo Weyrich 2/2015 //TODO Tiles to reduce memory consumption -SSEFUNCTION void RawImageSource::lmmse_interpolate_omp(int winw, int winh, int iterations) +SSEFUNCTION void RawImageSource::lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations) { const int width = winw, height = winh; const int ba = 10; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 86deb7d6d..13294c73a 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -498,6 +498,7 @@ enum ProcEvent { EvPixelShiftMedian3 = 468, EvPixelShiftMotionMethod = 469, EvPixelShiftSmooth = 470, + EvPixelShiftLmmse = 471, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 18437431d..dc6b804a1 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -899,6 +899,7 @@ void RAWParams::BayerSensor::setPixelShiftDefaults() pixelShiftBlur = true; pixelShiftSmoothFactor = 0.7; pixelShiftExp0 = false; + pixelShiftLmmse = false; pixelShiftNonGreenCross = true; pixelShiftNonGreenCross2 = false; pixelShiftNonGreenAmaze = false; @@ -3492,6 +3493,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftExp0", raw.bayersensor.pixelShiftExp0 ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftLmmse) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftLmmse", raw.bayersensor.pixelShiftLmmse ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross) { keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); } @@ -7752,6 +7757,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftLmmse")) { + raw.bayersensor.pixelShiftLmmse = keyFile.get_boolean("RAW Bayer", "pixelShiftLmmse"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftLmmse = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross")) { raw.bayersensor.pixelShiftNonGreenCross = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross"); @@ -8237,6 +8250,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur && raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor && raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0 + && raw.bayersensor.pixelShiftLmmse == other.raw.bayersensor.pixelShiftLmmse && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 && raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 21fe97855..096decd90 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1231,6 +1231,7 @@ public: bool pixelShiftBlur; double pixelShiftSmoothFactor; bool pixelShiftExp0; + bool pixelShiftLmmse; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; bool pixelShiftNonGreenAmaze; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index e5cce8f57..327c6e3ba 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2039,12 +2039,20 @@ void RawImageSource::demosaic(const RAWParams &raw) if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic) && numFrames == 4) { if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction if(!bayerParams.pixelShiftMedian3) { - amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[0]), red, green, blue); + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(W, H, *(rawDataFrames[0]), red, green, blue, raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[0]), red, green, blue); + } multi_array2D redTmp(W,H); multi_array2D greenTmp(W,H); multi_array2D blueTmp(W,H); for(int i=0;i<3;i++) { - amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i]); + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(W, H, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i], raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i]); + } } #pragma omp parallel for schedule(dynamic,16) for(int i=border;i blueTmp(W,H); for(int i=0, frameIndex = 0;i<4;++i) { if(i != currFrame) { - amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex]); + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(W, H, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex], raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, W, H, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex]); + } ++frameIndex; } } @@ -2124,10 +2136,18 @@ void RawImageSource::demosaic(const RAWParams &raw) } } } else { - amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(W, H, rawData, red, green, blue, raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction + } } } else { - amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(W, H, rawData, red, green, blue, raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue); // for non pixelshift files use amaze if pixelshift is selected. We need it also for motion correction + } } } pixelshift(0, 0, W, H, bayerParams, currFrame, ri->get_model(), raw.expos); @@ -2139,7 +2159,7 @@ void RawImageSource::demosaic(const RAWParams &raw) } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::igv]) { igv_interpolate(W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::lmmse]) { - lmmse_interpolate_omp(W, H, raw.bayersensor.lmmse_iterations); + lmmse_interpolate_omp(W, H, rawData, red, green, blue, raw.bayersensor.lmmse_iterations); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::fast] ) { fast_demosaic (0, 0, W, H); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::mono] ) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index d54bcd49d..280b546f4 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -236,7 +236,7 @@ protected: void ppg_demosaic(); void jdl_interpolate_omp(); void igv_interpolate(int winw, int winh); - void lmmse_interpolate_omp(int winw, int winh, int iterations); + void lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations); void amaze_demosaic_RT(int winx, int winy, int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue);//Emil's code for AMaZE void fast_demosaic(int winx, int winy, int winw, int winh );//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 891f191b2..d759f6866 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -497,7 +497,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftMedian DEMOSAIC, // EvPixelShiftMedian3 DEMOSAIC, // EvPixelShiftMotionMethod - DEMOSAIC // EvPixelShiftSmooth + DEMOSAIC, // EvPixelShiftSmooth + DEMOSAIC // EvPixelShiftLmmse }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index ef2905f8d..dbf41781a 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -169,6 +169,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftExp0 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTEXP0"))); pixelShiftOptions->pack_start(*pixelShiftExp0); + pixelShiftLmmse = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTLMMSE"))); + pixelShiftOptions->pack_start(*pixelShiftLmmse); + pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); pixelShiftMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); @@ -313,6 +316,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftGreenconn = pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true); pixelShiftBlurconn = pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true); pixelShiftExp0conn = pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true); + pixelShiftLmmseconn = pixelShiftLmmse->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftLmmseChanged), true); pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); pixelShiftNonGreenAmazeconn = pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true); @@ -355,6 +359,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); pixelShiftSmooth->setEditedState ( pedited->raw.bayersensor.pixelShiftSmooth ? Edited : UnEdited); pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); + pixelShiftLmmse->set_inconsistent(!pedited->raw.bayersensor.pixelShiftLmmse); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); @@ -400,6 +405,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); pixelShiftSmooth->setValue (pp->raw.bayersensor.pixelShiftSmoothFactor); pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); + pixelShiftLmmse->set_active(pp->raw.bayersensor.pixelShiftLmmse); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); @@ -499,6 +505,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); pp->raw.bayersensor.pixelShiftSmoothFactor = pixelShiftSmooth->getValue(); pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); + pp->raw.bayersensor.pixelShiftLmmse = pixelShiftLmmse->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->get_active(); @@ -546,6 +553,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.pixelShiftBlur = !pixelShiftBlur->get_inconsistent(); pedited->raw.bayersensor.pixelShiftSmooth = pixelShiftSmooth->getEditedState(); pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftLmmse = !pixelShiftLmmse->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenAmaze = !pixelShiftNonGreenAmaze->get_inconsistent(); @@ -1018,6 +1026,26 @@ void BayerProcess::pixelShiftExp0Changed () } } +void BayerProcess::pixelShiftLmmseChanged () +{ + if (batchMode) { + if (pixelShiftLmmse->get_inconsistent()) { + pixelShiftLmmse->set_inconsistent (false); + pixelShiftLmmseconn.block (true); + pixelShiftLmmse->set_active (false); + pixelShiftLmmseconn.block (false); + } else if (lastDCBen) { + pixelShiftLmmse->set_inconsistent (true); + } + + lastDCBen = pixelShiftLmmse->get_active (); + } + + if (listener) { + listener->panelChanged (EvPixelShiftLmmse, pixelShiftLmmse->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void BayerProcess::pixelShiftNonGreenCrossChanged () { if (batchMode) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index def4021ce..c8658f5bf 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -60,6 +60,7 @@ protected: Gtk::CheckButton* pixelShiftHoleFill; Gtk::CheckButton* pixelShiftMedian; Gtk::CheckButton* pixelShiftMedian3; + Gtk::CheckButton* pixelShiftLmmse; Adjuster* pixelShiftSmooth; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; @@ -76,7 +77,7 @@ protected: sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftHoleFillconn, pixelShiftMedianconn, pixelShiftMedian3conn, pixelShiftNonGreenCrossconn, - pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftSmoothconn, pixelShiftExp0conn, pixelShiftMotionMethodConn; + pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftSmoothconn, pixelShiftExp0conn, pixelShiftLmmseconn, pixelShiftMotionMethodConn; public: BayerProcess (); @@ -102,6 +103,7 @@ public: void pixelShiftGreenChanged(); void pixelShiftBlurChanged(); void pixelShiftExp0Changed(); + void pixelShiftLmmseChanged(); void pixelShiftNonGreenCrossChanged(); void pixelShiftNonGreenCross2Changed(); void pixelShiftNonGreenAmazeChanged(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index e1303095a..939413f18 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -394,6 +394,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftBlur = v; raw.bayersensor.pixelShiftSmooth = v; raw.bayersensor.pixelShiftExp0 = v; + raw.bayersensor.pixelShiftLmmse = v; raw.bayersensor.pixelShiftNonGreenCross = v; raw.bayersensor.pixelShiftNonGreenCross2 = v; raw.bayersensor.pixelShiftNonGreenAmaze = v; @@ -917,6 +918,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftBlur = raw.bayersensor.pixelShiftBlur && p.raw.bayersensor.pixelShiftBlur == other.raw.bayersensor.pixelShiftBlur; raw.bayersensor.pixelShiftSmooth = raw.bayersensor.pixelShiftSmooth && p.raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor; raw.bayersensor.pixelShiftExp0 = raw.bayersensor.pixelShiftExp0 && p.raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0; + raw.bayersensor.pixelShiftLmmse = raw.bayersensor.pixelShiftLmmse && p.raw.bayersensor.pixelShiftLmmse == other.raw.bayersensor.pixelShiftLmmse; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; raw.bayersensor.pixelShiftNonGreenAmaze = raw.bayersensor.pixelShiftNonGreenAmaze && p.raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze; @@ -2428,6 +2430,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftExp0 = mods.raw.bayersensor.pixelShiftExp0; } + if (raw.bayersensor.pixelShiftLmmse) { + toEdit.raw.bayersensor.pixelShiftLmmse = mods.raw.bayersensor.pixelShiftLmmse; + } + if (raw.bayersensor.pixelShiftNonGreenCross) { toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; } @@ -2952,7 +2958,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && 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 + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftExp0 && pixelShiftLmmse && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 23b0e240b..5f66c3d18 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -716,6 +716,7 @@ public: bool pixelShiftBlur; bool pixelShiftSmooth; bool pixelShiftExp0; + bool pixelShiftLmmse; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; bool pixelShiftNonGreenAmaze; From 812bf40d176b21f412b951610720aad76fd8fa5a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 5 Feb 2017 16:06:57 +0100 Subject: [PATCH 78/83] Show raw values in navigator when demosaic 'none' is used --- rtengine/imagesource.h | 1 + rtengine/rawimagesource.cc | 15 +++++++++++++++ rtengine/rawimagesource.h | 1 + rtengine/stdimagesource.h | 3 +++ rtgui/cropwindow.cc | 14 +++++++++++++- 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 98e5446a1..e8740edf4 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -160,6 +160,7 @@ public: { return this; } + virtual void getRawValues(int x, int y, int &R, int &G, int &B) = 0; }; } #endif diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 327c6e3ba..fa433e98c 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -5460,6 +5460,21 @@ void RawImageSource::init () } } +void RawImageSource::getRawValues(int x, int y, int &R, int &G, int &B) +{ + int xnew = x + border; + int ynew = y + border; + int c = FC(ynew,xnew); + int val = rawData[ynew][xnew] / scale_mul[c]; + if(c == 0) { + R = val; G = 0; B = 0; + } else if(c == 2) { + R = 0; G = 0; B = val; + } else { + R = 0; G = val; B = 0; + } +} + void RawImageSource::cleanup () { delete phaseOneIccCurve; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 280b546f4..99363d9e0 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -264,6 +264,7 @@ protected: void pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection); void hflip (Imagefloat* im); void vflip (Imagefloat* im); + void getRawValues(int x, int y, int &R, int &G, int &B); }; } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 733a44c42..775bd484d 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -97,6 +97,9 @@ public: } void setCurrentFrame(unsigned int frameNum) {} + void getRawValues(int x, int y, int &R, int &G, int &B) { R = G = B = 0;} + + }; } #endif diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 2513bb137..c021886fb 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1035,9 +1035,21 @@ void CropWindow::pointerMoved (int bstate, int x, int y) int imheight = cropHandler.cropPixbuf->get_height(); guint8* pix = cropHandler.cropPixbuftrue->get_pixels() + vy * cropHandler.cropPixbuf->get_rowstride() + vx * 3; + int rval = pix[0]; + int gval = pix[1]; + int bval = pix[2]; if (vx < imwidth && vy < imheight) { + rtengine::StagedImageProcessor* ipc = iarea->getImProcCoordinator(); + if(ipc) { + procparams::ProcParams params; + ipc->getParams(¶ms); + if(params.raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::none]) { + ImageSource *isrc = static_cast(ipc->getInitialImage()); + isrc->getRawValues(mx, my, rval, gval, bval); + } + } // pmlistener->pointerMoved (true, cropHandler.colorParams.working, mx, my, pix[0], pix[1], pix[2]); - pmlistener->pointerMoved (true, cropHandler.colorParams.output, cropHandler.colorParams.working, mx, my, pix[0], pix[1], pix[2]); + pmlistener->pointerMoved (true, cropHandler.colorParams.output, cropHandler.colorParams.working, mx, my, rval, gval, bval); if (pmhlistener) // pmhlistener->pointerMoved (true, cropHandler.colorParams.working, mx, my, pix[0], pix[1], pix[2]); From b720a673284c64dd2d2d20b844bcaea950b6c1f7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 5 Feb 2017 16:28:25 +0100 Subject: [PATCH 79/83] getRawValues: round instead of truncate --- rtengine/rawimagesource.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index fa433e98c..00ce631b2 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -5465,7 +5465,7 @@ void RawImageSource::getRawValues(int x, int y, int &R, int &G, int &B) int xnew = x + border; int ynew = y + border; int c = FC(ynew,xnew); - int val = rawData[ynew][xnew] / scale_mul[c]; + int val = round(rawData[ynew][xnew] / scale_mul[c]); if(c == 0) { R = val; G = 0; B = 0; } else if(c == 2) { From d570459f1e82f6a5ec9090bfb8c9931d36ef4809 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 5 Feb 2017 19:03:34 +0100 Subject: [PATCH 80/83] Fixed bug in last commit when image was rotated --- rtengine/imagesource.h | 2 +- rtengine/rawimagesource.cc | 17 ++++++++++++++++- rtengine/rawimagesource.h | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/cropwindow.cc | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index e8740edf4..8998fa848 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -160,7 +160,7 @@ public: { return this; } - virtual void getRawValues(int x, int y, int &R, int &G, int &B) = 0; + virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0; }; } #endif diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 00ce631b2..4fce68bdf 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -5460,10 +5460,25 @@ void RawImageSource::init () } } -void RawImageSource::getRawValues(int x, int y, int &R, int &G, int &B) +void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int &B) { int xnew = x + border; int ynew = y + border; + rotate += ri->get_rotateDegree(); + rotate %= 360; + if (rotate == 90) { + std::swap(xnew,ynew); + ynew = H - 1 - ynew; + } else if (rotate == 180) { + xnew = W - 1 - xnew; + ynew = H - 1 - ynew; + } else if (rotate == 270) { + std::swap(xnew,ynew); + ynew = H - 1 - ynew; + xnew = W - 1 - xnew; + ynew = H - 1 - ynew; + } + int c = FC(ynew,xnew); int val = round(rawData[ynew][xnew] / scale_mul[c]); if(c == 0) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 99363d9e0..948efb355 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -264,7 +264,7 @@ protected: void pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection); void hflip (Imagefloat* im); void vflip (Imagefloat* im); - void getRawValues(int x, int y, int &R, int &G, int &B); + void getRawValues(int x, int y, int rotate, int &R, int &G, int &B); }; } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 775bd484d..1dbddf325 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -97,7 +97,7 @@ public: } void setCurrentFrame(unsigned int frameNum) {} - void getRawValues(int x, int y, int &R, int &G, int &B) { R = G = B = 0;} + void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) { R = G = B = 0;} }; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index c021886fb..a6e93c511 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1045,7 +1045,7 @@ void CropWindow::pointerMoved (int bstate, int x, int y) ipc->getParams(¶ms); if(params.raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::none]) { ImageSource *isrc = static_cast(ipc->getInitialImage()); - isrc->getRawValues(mx, my, rval, gval, bval); + isrc->getRawValues(mx, my, params.coarse.rotate, rval, gval, bval); } } // pmlistener->pointerMoved (true, cropHandler.colorParams.working, mx, my, pix[0], pix[1], pix[2]); From 2feb43f5d510e511944262b1f893f6394fd30893 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 6 Feb 2017 16:43:49 +0100 Subject: [PATCH 81/83] Fix display of raw values in navigator for xtrans --- rtengine/rawimagesource.cc | 2 +- rtgui/cropwindow.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 4fce68bdf..2cb642285 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -5479,7 +5479,7 @@ void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int ynew = H - 1 - ynew; } - int c = FC(ynew,xnew); + int c = ri->getSensorType() == ST_FUJI_XTRANS ? ri->XTRANSFC(ynew,xnew) : ri->FC(ynew,xnew); int val = round(rawData[ynew][xnew] / scale_mul[c]); if(c == 0) { R = val; G = 0; B = 0; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index a6e93c511..71855786e 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1043,7 +1043,7 @@ void CropWindow::pointerMoved (int bstate, int x, int y) if(ipc) { procparams::ProcParams params; ipc->getParams(¶ms); - if(params.raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::none]) { + if(params.raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::none] || params.raw.xtranssensor.method == RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::none]) { ImageSource *isrc = static_cast(ipc->getInitialImage()); isrc->getRawValues(mx, my, params.coarse.rotate, rval, gval, bval); } From 825002378b061385dab0e982a674355bc34418a8 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 10 Mar 2017 23:05:19 +0100 Subject: [PATCH 82/83] =?UTF-8?q?Added=20JK=20Han=20and=20Kalle=20S=C3=B6d?= =?UTF-8?q?erman=20for=20contributing=20to=20Pentax=20pixelshift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 3aa555bc0..ff0f89361 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -45,6 +45,7 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati André Gauthier Sébastien Guyader M. Dávid Gyurkó + JK Han (pinholecam) Arturs Jekabsons Marián Kyral Oscar de Lama @@ -55,6 +56,7 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Wim ter Meer Alberto Righetto Kostia (Kildor) Romanov + Kalle Söderman Johan Thor Vitalis Tiknius TooWaBoo From f226934b5736d8ca2d3f3314bb2ce5777e8ae0be Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 11 Mar 2017 00:25:49 +0100 Subject: [PATCH 83/83] Pixelshift: Added option to equalize brightness of frames and cleaned gui. --- rtdata/languages/default | 22 +- rtengine/pixelshift.cc | 197 ++++++++++++-- rtengine/procevents.h | 1 + rtengine/procparams.cc | 14 + rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 6 + rtengine/refreshmap.cc | 3 +- rtgui/bayerprocess.cc | 531 +++++++++++++++++++++---------------- rtgui/bayerprocess.h | 68 +++-- rtgui/guiutils.h | 22 ++ rtgui/paramsedited.cc | 8 +- rtgui/paramsedited.h | 1 + 12 files changed, 577 insertions(+), 297 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 575cc5136..118e0ed8b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -704,6 +704,7 @@ HISTORY_MSG_469;EvPixelShiftMedian3 HISTORY_MSG_470;EvPixelShiftMotionMethod HISTORY_MSG_471;EvPixelShiftSmooth HISTORY_MSG_472;EvPixelShiftLmmse +HISTORY_MSG_473;EvPixelShiftEqualBright HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1692,20 +1693,24 @@ TP_RAW_PIXELSHIFTNONGREENHORIZONTAL;Check red/blue horizontal TP_RAW_PIXELSHIFTNONGREENVERTICAL;Check red/blue vertical TP_RAW_PIXELSHIFTMEDIAN;Median TP_RAW_PIXELSHIFTMEDIAN3;Exclude selected frame from median -TP_RAW_PIXELSHIFTHOLEFILL;3x3 new: Fill holes -TP_RAW_PIXELSHIFTBLUR;3x3 new: Blur -TP_RAW_PIXELSHIFTSMOOTH;3x3 new: Smooth transitions +TP_RAW_PIXELSHIFTHOLEFILL;Fill holes in motion mask +TP_RAW_PIXELSHIFTBLUR;Blur motion mask +TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;Default radius of 1.0 usually fits good for base ISO. Increase value for high ISO shots,\n5.0 is a good starting point for high ISO shots.\nWatch motion mask while changing the value. +TP_RAW_PIXELSHIFTSMOOTH;Smooth transitions +TP_RAW_PIXELSHIFTLMMSE_TOOLTIP;Use lmmse instead of amaze for motion areas.\nUseful for High ISO images. TP_RAW_PIXELSHIFTLMMSE;Use lmmse for motion parts +TP_RAW_PIXELSHIFTEQUALBRIGHT;Equalize brightness of frames +TP_RAW_PIXELSHIFTEQUALBRIGHT_TOOLTIP;Equalize the brightness of the frames to the brightness of the selected frame.\nIf there are overexposed areas in the frames select the brightest frame to avoid magenta colour cast in overexposed areas or enable motion correction. TP_RAW_PIXELSHIFTEXP0;Experimental -TP_RAW_PIXELSHIFTGREEN;Check dual green -TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue cross +TP_RAW_PIXELSHIFTGREEN;Check green channel for motion +TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue channels for motion TP_RAW_PIXELSHIFTNONGREENCROSS2;Check green amaze TP_RAW_PIXELSHIFTNONGREENAMAZE;Check red/blue amaze TP_RAW_PIXELSHIFTMOTION;Motion detection level (deprecated) TP_RAW_PIXELSHIFTMOTION_TOOLTIP;0 means no motion detection\n1 - 99 means motion will be detected according to this value. Increase value to increase detection rate\n100 means the Amaze demosaiced frame will be used TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;Fill holes in motion mask TP_RAW_PIXELSHIFTBLUR_TOOLTIP;Blur motion mask -TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions (requires 3x3 new Blur)\nSet to 0 to disable smooth transitions\nSet to 1 to get Amaze or Median +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions between areas with and without motion.\nSet to 0 to disable smooth transitions\nSet to 1 to get Amaze/lmmse or Median TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;Use median of all frames instead of selected frame for regions with motion.\nRemoves objects which are at different places in all frames.\nGives motion effect on slow moving (overlapping) objects. TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP;Excludes selected frame from median.\nUseful if moving objects overlap in frame 2 and 3 TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a mask showing the regions with motion @@ -1718,10 +1723,11 @@ TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN;StdDev factor Green TP_RAW_PIXELSHIFTSTDDEVFACTORRED;StdDev factor Red TP_RAW_PIXELSHIFTSTDDEVFACTORBLUE;StdDev factor Blue -TP_RAW_PIXELSHIFTEPERISO;e per ISO +TP_RAW_PIXELSHIFTEPERISO;ISO adaption +TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;The default value (0.0) should work fine for base ISO.\nIncrease the value to improve motion detection for higher ISO.\nIncrease in small steps and watch the motion mask while increasing. TP_RAW_PIXELSHIFTNREADISO;nRead TP_RAW_PIXELSHIFTPRNU;PRNU (%) -TP_RAW_PIXELSHIFTSIGMA;Blur sigma +TP_RAW_PIXELSHIFTSIGMA;Blur radius TP_RAW_PIXELSHIFTMASKTHRESHOLD;3x3 new threshold TP_RAW_PIXELSHIFTREDBLUEWEIGHT;Red&Blue weight TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 7696c1874..8ba9c1cfd 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -45,7 +45,7 @@ float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperI float gDiff = a - b; gDiff *= eperIso; gDiff *= gDiff; - float avg = (a + b) / 2.f; + float avg = (a + b) * 0.5f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); @@ -96,17 +96,17 @@ float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nr float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // check non green cross - float hDiff = (right + left) / 2.f - centre; + float hDiff = (right + left) * 0.5f - centre; hDiff *= eperIso; hDiff *= hDiff; - float vDiff = (top + bottom) / 2.f - centre; + float vDiff = (top + bottom) * 0.5f - centre; vDiff *= eperIso; vDiff *= vDiff; - float avg = (right + left + top + bottom) / 4.f; + float avg = ((right + left) + (top + bottom)) * 0.25f; avg *= eperIso; prnu *= avg; float stddev = stddevFactor * (avg + nreadIso + prnu * prnu); - float result = std::min(hDiff - stddev, vDiff - stddev); + float result = std::min(hDiff, vDiff) - stddev; if(!showMotion) { return result; @@ -896,21 +896,31 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, bool det #else void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection) { - +#ifdef PIXELSHIFTDEV BENCHFUN - +#endif const bool detectMotion = bayerParams.pixelShiftMotion > 0; const int motion = bayerParams.pixelShiftMotion; const bool showMotion = bayerParams.pixelshiftShowMotion; - const bool showOnlyMask = bayerParams.pixelshiftShowMotionMaskOnly; + const bool showOnlyMask = bayerParams.pixelshiftShowMotionMaskOnly && showMotion; const RAWParams::BayerSensor::ePSMotionCorrection gridSize_ = bayerParams.pixelShiftMotionCorrection; const bool adaptive = bayerParams.pixelShiftAutomatic; +#ifdef PIXELSHIFTDEV float stddevFactorGreen = bayerParams.pixelShiftStddevFactorGreen; float stddevFactorRed = bayerParams.pixelShiftStddevFactorRed; float stddevFactorBlue = bayerParams.pixelShiftStddevFactorBlue; - float eperIso = bayerParams.pixelShiftEperIso; float nreadIso = bayerParams.pixelShiftNreadIso; float prnu = bayerParams.pixelShiftPrnu; + const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight + 1.f; +#else + float stddevFactorGreen = 5.f; + float stddevFactorRed = 5.f; + float stddevFactorBlue = 5.f; + float nreadIso = 0.f; + float prnu = 1.f; + const float redBlueWeight = 0.7f + 1.f; +#endif + float eperIso = bayerParams.pixelShiftEperIso; const bool checkNonGreenHorizontal = bayerParams.pixelShiftNonGreenHorizontal; const bool checkNonGreenVertical = bayerParams.pixelShiftNonGreenVertical; const bool checkNonGreenCross = bayerParams.pixelShiftNonGreenCross; @@ -918,13 +928,18 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const bool checkNonGreenCross2 = bayerParams.pixelShiftNonGreenCross2; const bool checkGreen = bayerParams.pixelShiftGreen; const float greenWeight = 2.f; - const float redBlueWeight = bayerParams.pixelShiftRedBlueWeight + 1.f; const bool blurMap = bayerParams.pixelShiftBlur; const float sigma = bayerParams.pixelShiftSigma; +#ifdef PIXELSHIFTDEV const float threshold = bayerParams.pixelShiftSum + 9.f; +#else + const float threshold = 3.f + 9.f; +#endif const bool experimental0 = bayerParams.pixelShiftExp0; const bool holeFill = bayerParams.pixelShiftHoleFill; - const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmoothFactor > 0.; + const bool equalBrightness = bayerParams.pixelShiftEqualBright; + const bool smoothTransitions = blurMap && bayerParams.pixelShiftSmoothFactor > 0. && !showOnlyMask; + const bool automatic = bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Automatic; const float smoothFactor = 1.0 - bayerParams.pixelShiftSmoothFactor; static const float nReadK3II[] = { 3.4f, // ISO 100 @@ -1040,6 +1055,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA const bool skip = (gridSize_ == RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2); int gridSize = 1; bool nOf3x3 = false; + switch (gridSize_) { case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x1: case RAWParams::BayerSensor::ePSMotionCorrection::Grid1x2: @@ -1067,6 +1083,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(plistener) { plistener->setProgress(1.0); } + return; } @@ -1110,11 +1127,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); } +#ifdef PIXELSHIFTDEV std::cout << "WL: " << c_white[0] << " BL: " << c_black[0] << " ePerIso multiplicator: " << (65535.f / (c_white[0] - c_black[0])) << std::endl; - - float eperIsoRed = (eperIso / scale_mul[0]) * (65535.f / (c_white[0]- c_black[0])); - float eperIsoGreen = (eperIso * scaleGreen) * (65535.f / (c_white[1]- c_black[1])); - float eperIsoBlue = (eperIso / scale_mul[2]) * (65535.f / (c_white[2]- c_black[2])); +#endif + float eperIsoRed = (eperIso / scale_mul[0]) * (65535.f / (c_white[0] - c_black[0])); + float eperIsoGreen = (eperIso * scaleGreen) * (65535.f / (c_white[1] - c_black[1])); + float eperIsoBlue = (eperIso / scale_mul[2]) * (65535.f / (c_white[2] - c_black[2])); // printf("Pixelshift parameters : gridSize %d\tadaptive %d\tstdDevFactorGreen %f\telectrons %1.8f\tnread %f\tprnu %1.1f%%\n", gridSize, adaptive, stddevFactorGreen, eperIso, nRead, prnu); @@ -1161,6 +1179,90 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA array2D psG2(winw + 32, winh); array2D psBlue(winw + 32, winh); +// calculate average green brightness for each frame + double greenBrightness[4] = {}; + + if(equalBrightness) { + LUT *histo[4]; + + for(int i = 0; i < 4; ++i) { + histo[i] = new LUT(65536); + histo[i]->clear(); + } + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + LUT *histoThr[4]; + + for(int i = 0; i < 4; ++i) { + histoThr[i] = new LUT(65536); + histoThr[i]->clear(); + } + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for(int i = winy + 1; i < winh - 1; ++i) { + int j = winx + 1; + int c = FC(i, j); + + // offset to keep the code short. It changes its value between 0 and 1 for each iteration of the loop + unsigned int offset = (c & 1); + offset ^= 1; // 0 => 1 or 1 => 0 + + for(; j < winw - 1; ++j) { + offset ^= 1; // 0 => 1 or 1 => 0 + + // store the values from the 4 frames into 4 different temporary planes + float green1 = (*rawDataFrames[1 - offset])[i - offset + 1][j]; + float green2 = (*rawDataFrames[3 - offset])[i + offset][j + 1]; + (*histoThr[1 - offset])[green1]++; + (*histoThr[3 - offset])[green2]++; + } + } + + #pragma omp critical + { + for(int i = 0; i < 4; ++i) { + (*histo[i]) += (*histoThr[i]); + delete histoThr[i]; + } + } + } + + float medians[4]; + + for(int i = 0; i < 4; ++i) { + //find median of histogram + uint32_t median = 0, count = 0; + uint32_t datalen = (winh - 2) * (winw - 2) / 2; + + while (count < datalen / 2) { + count += (*histo[i])[median]; + ++median; + } + + medians[i] = (median + median - 1) / 2.f; + delete histo[i]; + } + + const float medianMaster = medians[frame]; + + for(int i = 0; i < 4; ++i) { + greenBrightness[i] = medianMaster / medians[i]; + } + +#ifdef PIXELSHIFTDEV + std::cout << "brightness factors by median : " << greenBrightness[0] << " " << greenBrightness[1] << " " << greenBrightness[2] << " " << greenBrightness[3] << std::endl; +#endif + + } else { + greenBrightness[0] = greenBrightness[1] = greenBrightness[2] = greenBrightness[3] = 1.f; + } + // fill channels psRed, psG1, psG2 and psBlue #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) @@ -1188,16 +1290,17 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA offset ^= 1; // 0 => 1 or 1 => 0 // store the values from the 4 frames into 4 different temporary planes - greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j]; - greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1]; - nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset]; - nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1]; + greenDest1[j] = (*rawDataFrames[1 - offset])[i - offset + 1][j] * greenBrightness[1 - offset]; + greenDest2[j] = (*rawDataFrames[3 - offset])[i + offset][j + 1] * greenBrightness[3 - offset]; + nonGreenDest0[j] = (*rawDataFrames[(offset << 1) + offset])[i][j + offset] * greenBrightness[(offset << 1) + offset]; + nonGreenDest1[j] = (*rawDataFrames[2 - offset])[i + 1][j - offset + 1] * greenBrightness[2 - offset]; } } // now that the temporary planes are filled for easy access we do the motion detection +#ifdef PIXELSHIFTDEV int sum[2] = {0}; - +#endif float pixelcount = ((winh - (border + offsY) - (winy + border - offsY)) * (winw - (border + offsX) - (winx + border - offsX))) / 2.f; array2D psMask(winw, winh); @@ -1207,7 +1310,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #pragma omp parallel #endif { +#ifdef PIXELSHIFTDEV int sumThr[2] = {0}; +#endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) nowait #endif @@ -1220,7 +1325,10 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float greenDifMax[gridSize]; // Here we store the maximum differences per Column + // green channel motion detection checks the grid around the pixel for differences in green channels +#ifdef PIXELSHIFTDEV + if(detectMotion || (adaptive && checkGreen)) { if(gridSize == 3) { // compute maximum of differences for first two columns of 3x3 grid @@ -1312,6 +1420,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } +#endif // this is the index for the last column of the grid. Obviously we have to start with gridSize - 1 int lastIndex = gridSize - 1; @@ -1336,9 +1445,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA bool skipNext = false; float gridMax; +#ifdef PIXELSHIFTDEV + if(gridSize < 2) { // compute difference for current pixel and skip next pixel, that's roughly the method from dcrawps +#endif gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion, j, i); +#ifdef PIXELSHIFTDEV + skipNext = skip; } else if(gridSize == 3) { // compute maximum of differences for third column of 3x3 grid and save at position lastIndex @@ -1386,12 +1500,19 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; } +#endif + if (gridMax > thresh - korr) { +#ifdef PIXELSHIFTDEV sumThr[offset] ++; if(nOf3x3) { +#endif psMask[i][j] = greenWeight; - } else if((offset == (frame & 1)) && checkNonGreenVertical) { +#ifdef PIXELSHIFTDEV + } + + else if((offset == (frame & 1)) && checkNonGreenVertical) { if(frame > 1) { green[i + offsY][j + offsX] = blueRow ? psG1[i][j] : psG2[i][j]; } else { @@ -1408,6 +1529,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, redDest, blueDest); } } + +#endif // do not set the motion pixel values. They have already been set by demosaicer or showMotion continue; } @@ -1424,12 +1547,17 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); if(redDiff > 0.f) { +#ifdef PIXELSHIFTDEV + if(nOf3x3) { +#endif psMask[i][j] = redBlueWeight; +#ifdef PIXELSHIFTDEV } else { paintMotionMask(j + offsX, showMotion, redDiff, showOnlyMask, redDest, blueDest, greenDest); } +#endif continue; } @@ -1442,17 +1570,24 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); if(blueDiff > 0.f) { +#ifdef PIXELSHIFTDEV + if(nOf3x3) { +#endif psMask[i][j] = redBlueWeight; +#ifdef PIXELSHIFTDEV } else { paintMotionMask(j + offsX, showMotion, blueDiff, showOnlyMask, blueDest, redDest, greenDest); } +#endif continue; } } +#ifdef PIXELSHIFTDEV + if(checkNonGreenHorizontal) { float redLeft = psRed[ i ][j - 1]; float redCentre = psRed[ i ][ j ]; @@ -1599,9 +1734,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA if(experimental0) { // for experiments } + +#endif } - if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + if(showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else if(!(adaptive && nOf3x3)) { // no motion detected, replace the a priori demosaiced values by the pixelshift combined values @@ -1612,6 +1749,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } } +#ifdef PIXELSHIFTDEV + #ifdef _OPENMP #pragma omp critical #endif @@ -1619,13 +1758,16 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA sum[0] += sumThr[0]; sum[1] += sumThr[0]; } +#endif } +#ifdef PIXELSHIFTDEV float percent0 = 100.f * sum[0] / pixelcount; float percent1 = 100.f * sum[1] / pixelcount; std::cout << fileName << " : Green detections at stddev " << std::setprecision( 2 ) << bayerParams.pixelShiftStddevFactorGreen << " : Frame 1/3 : " << std::setprecision( 6 ) << sum[0] << " (" << percent0 << "%)" << " Frame 2/4 : " << sum[1] << " (" << percent1 << "%)" << std::endl; +#endif if(adaptive && nOf3x3) { if(blurMap) { @@ -1641,9 +1783,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #pragma omp parallel for schedule(dynamic,16) for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { - float *greenDest = green[i + offsY]; - float *redDest = red[i + offsY]; - float *blueDest = blue[i + offsY]; int j = winx + border - offsX; float v3sum[3] = {0.f}; @@ -1680,7 +1819,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int i = winy + border - offsY; i < winh - (border + offsY); ++i) { #ifdef __SSE2__ - if(!(showMotion && showOnlyMask) && smoothTransitions) { + if(smoothTransitions) { vfloat onev = F2V(1.f); vfloat smoothv = F2V(smoothFactor); int j = winx + border - offsX; @@ -1704,7 +1843,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA for(int j = winx + border - offsX; j < winw - (border + offsX); ++j) { if(mask[i][j] == 255) { paintMotionMask(j + offsX, showMotion, 0.5f, showOnlyMask, greenDest, redDest, blueDest); - } else if(showMotion && showOnlyMask) { // we want only motion mask => paint areas without motion in pure black + } else if(showOnlyMask) { // we want only motion mask => paint areas without motion in pure black red[i + offsY][j + offsX] = green[i + offsY][j + offsX] = blue[i + offsY][j + offsX] = 0.f; } else { if(smoothTransitions) { @@ -1714,11 +1853,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float blend = pow_F(std::max(psMask[i][j] - 1.f, 0.f), smoothFactor); #endif red[i + offsY][j + offsX] = intp(blend, red[i + offsY][j + offsX], psRed[i][j] ); - green[i + offsY][j + offsX] = intp(blend, green[i + offsY][j + offsX], (psG1[i][j] + psG2[i][j]) / 2.f); + green[i + offsY][j + offsX] = intp(blend, green[i + offsY][j + offsX], (psG1[i][j] + psG2[i][j]) * 0.5f); blue[i + offsY][j + offsX] = intp(blend, blue[i + offsY][j + offsX], psBlue[i][j]); } else { red[i + offsY][j + offsX] = psRed[i][j]; - green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) / 2.f; + green[i + offsY][j + offsX] = (psG1[i][j] + psG2[i][j]) * 0.5f; blue[i + offsY][j + offsX] = psBlue[i][j]; } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 13294c73a..3252bcc86 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -499,6 +499,7 @@ enum ProcEvent { EvPixelShiftMotionMethod = 469, EvPixelShiftSmooth = 470, EvPixelShiftLmmse = 471, + EvPixelShiftEqualBright = 472, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 50b77b8d1..ea18492e2 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -900,6 +900,7 @@ void RAWParams::BayerSensor::setPixelShiftDefaults() pixelShiftSmoothFactor = 0.7; pixelShiftExp0 = false; pixelShiftLmmse = false; + pixelShiftEqualBright = false; pixelShiftNonGreenCross = true; pixelShiftNonGreenCross2 = false; pixelShiftNonGreenAmaze = false; @@ -3497,6 +3498,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("RAW Bayer", "pixelShiftLmmse", raw.bayersensor.pixelShiftLmmse ); } + if (!pedited || pedited->raw.bayersensor.pixelShiftEqualBright) { + keyFile.set_boolean ("RAW Bayer", "pixelShiftEqualBright", raw.bayersensor.pixelShiftEqualBright ); + } + if (!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross) { keyFile.set_boolean ("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross ); } @@ -7765,6 +7770,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("RAW Bayer", "pixelShiftEqualBright")) { + raw.bayersensor.pixelShiftEqualBright = keyFile.get_boolean("RAW Bayer", "pixelShiftEqualBright"); + + if (pedited) { + pedited->raw.bayersensor.pixelShiftEqualBright = true; + } + } + if (keyFile.has_key ("RAW Bayer", "pixelShiftNonGreenCross")) { raw.bayersensor.pixelShiftNonGreenCross = keyFile.get_boolean("RAW Bayer", "pixelShiftNonGreenCross"); @@ -8251,6 +8264,7 @@ bool ProcParams::operator== (const ProcParams& other) && raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor && raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0 && raw.bayersensor.pixelShiftLmmse == other.raw.bayersensor.pixelShiftLmmse + && raw.bayersensor.pixelShiftEqualBright == other.raw.bayersensor.pixelShiftEqualBright && raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross && raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2 && raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 096decd90..77531a072 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1232,6 +1232,7 @@ public: double pixelShiftSmoothFactor; bool pixelShiftExp0; bool pixelShiftLmmse; + bool pixelShiftEqualBright; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; bool pixelShiftNonGreenAmaze; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 2cb642285..1c4b771ea 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2029,7 +2029,9 @@ void RawImageSource::demosaic(const RAWParams &raw) } else { RAWParams::BayerSensor bayerParams = raw.bayersensor; if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Automatic) { + bool pixelShiftEqualBright = bayerParams.pixelShiftEqualBright; bayerParams.setPixelShiftDefaults(); + bayerParams.pixelShiftEqualBright = pixelShiftEqualBright; } else if(bayerParams.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::Off) { bayerParams.pixelShiftMotion = 0; bayerParams.pixelShiftAutomatic = false; @@ -2038,7 +2040,9 @@ void RawImageSource::demosaic(const RAWParams &raw) if(!bayerParams.pixelshiftShowMotion || bayerParams.pixelShiftNonGreenAmaze || bayerParams.pixelShiftNonGreenCross2 || (bayerParams.pixelShiftBlur && bayerParams.pixelShiftSmoothFactor > 0.0)) { if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic) && numFrames == 4) { if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction +#ifdef PIXELSHIFTDEV if(!bayerParams.pixelShiftMedian3) { +#endif if(bayerParams.pixelShiftLmmse) { lmmse_interpolate_omp(W, H, *(rawDataFrames[0]), red, green, blue, raw.bayersensor.lmmse_iterations); } else { @@ -2066,6 +2070,7 @@ void RawImageSource::demosaic(const RAWParams &raw) blue[i][j] = median(blue[i][j],blueTmp[0][i+1][j],blueTmp[1][i+1][j+1],blueTmp[2][i][j+1]); } } +#ifdef PIXELSHIFTDEV } else { multi_array2D redTmp(W,H); multi_array2D greenTmp(W,H); @@ -2135,6 +2140,7 @@ void RawImageSource::demosaic(const RAWParams &raw) } } } +#endif } else { if(bayerParams.pixelShiftLmmse) { lmmse_interpolate_omp(W, H, rawData, red, green, blue, raw.bayersensor.lmmse_iterations); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index d759f6866..fa673b0eb 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -498,7 +498,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvPixelShiftMedian3 DEMOSAIC, // EvPixelShiftMotionMethod DEMOSAIC, // EvPixelShiftSmooth - DEMOSAIC // EvPixelShiftLmmse + DEMOSAIC, // EvPixelShiftLmmse + DEMOSAIC // EvPixelShiftEqualBright }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index dbf41781a..af079e5fa 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -73,7 +73,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA } dcbIterations->show(); - dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); + dcbEnhance = Gtk::manage (new MyCheckButton(M("TP_RAW_DCBENHANCE"))); dcbOptions->pack_start(*dcbIterations); dcbOptions->pack_start(*dcbEnhance); pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); @@ -96,6 +96,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftFrame = Gtk::manage (new Gtk::VBox ()); pixelShiftFrame->set_border_width(0); + pixelShiftEqualBright = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTEQUALBRIGHT"))); + pixelShiftEqualBright->set_tooltip_text (M("TP_RAW_PIXELSHIFTEQUALBRIGHT_TOOLTIP")); + pixelShiftFrame->pack_start(*pixelShiftEqualBright); + Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); hb3->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); pixelShiftMotionMethod = Gtk::manage (new MyComboBoxText ()); @@ -110,24 +114,44 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftOptions = Gtk::manage (new Gtk::VBox ()); pixelShiftOptions->set_border_width(0); - pixelShiftShowMotion = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); + pixelShiftShowMotion = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); pixelShiftShowMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP")); pixelShiftFrame->pack_start(*pixelShiftShowMotion); - pixelShiftShowMotionMaskOnly = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); + pixelShiftShowMotionMaskOnly = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); pixelShiftShowMotionMaskOnly->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP")); pixelShiftFrame->pack_start(*pixelShiftShowMotionMaskOnly); - pixelShiftAutomatic = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); +#ifdef PIXELSHIFTDEV + pixelShiftAutomatic = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); pixelShiftOptions->pack_start(*pixelShiftAutomatic); - - pixelShiftGreen = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTGREEN"))); +#endif + pixelShiftGreen = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTGREEN"))); pixelShiftOptions->pack_start(*pixelShiftGreen); - pixelShiftBlur = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTBLUR"))); - pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTBLUR_TOOLTIP")); + pixelShiftNonGreenCross = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); + pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); + + pixelShiftHoleFill = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); + pixelShiftHoleFill->set_tooltip_text (M("TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP")); + pixelShiftOptions->pack_start(*pixelShiftHoleFill); + + pixelShiftBlur = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTBLUR"))); + pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTSIGMA_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftBlur); + pixelShiftSigma = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSIGMA"), 0.5, 25, 0.1, 1.0)); + pixelShiftSigma->set_tooltip_text (M("TP_RAW_PIXELSHIFTSIGMA_TOOLTIP")); + pixelShiftSigma->setAdjusterListener (this); + + if (pixelShiftSigma->delay < options.adjusterMaxDelay) { + pixelShiftSigma->delay = options.adjusterMaxDelay; + } + + pixelShiftSigma->show(); + pixelShiftOptions->pack_start(*pixelShiftSigma); + + pixelShiftSmooth = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSMOOTH"), 0, 1, 0.05, 0.7)); pixelShiftSmooth->set_tooltip_text (M("TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP")); pixelShiftSmooth->setAdjusterListener (this); @@ -139,39 +163,48 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftSmooth->show(); pixelShiftOptions->pack_start(*pixelShiftSmooth); - pixelShiftHoleFill = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); - pixelShiftHoleFill->set_tooltip_text (M("TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP")); - pixelShiftOptions->pack_start(*pixelShiftHoleFill); + pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -5.0, 5.0, 0.05, 0.0)); + pixelShiftEperIso->set_tooltip_text(M("TP_RAW_PIXELSHIFTEPERISO_TOOLTIP")); + pixelShiftEperIso->setAdjusterListener (this); - pixelShiftMedian = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTMEDIAN"))); + if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { + pixelShiftEperIso->delay = options.adjusterMaxDelay; + } + + pixelShiftEperIso->show(); + pixelShiftOptions->pack_start(*pixelShiftEperIso); + + + pixelShiftMedian = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTMEDIAN"))); pixelShiftMedian->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftMedian); - pixelShiftMedian3 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTMEDIAN3"))); + +#ifdef PIXELSHIFTDEV + pixelShiftMedian3 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTMEDIAN3"))); pixelShiftMedian3->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftMedian3); - pixelShiftNonGreenCross = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); - pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); - - pixelShiftNonGreenCross2 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); + pixelShiftNonGreenCross2 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); + pixelShiftNonGreenAmaze = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenAmaze); - pixelShiftNonGreenHorizontal = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); + pixelShiftNonGreenHorizontal = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); - pixelShiftNonGreenVertical = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"))); + pixelShiftNonGreenVertical = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"))); pixelShiftOptions->pack_start(*pixelShiftNonGreenVertical); - pixelShiftExp0 = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTEXP0"))); + pixelShiftExp0 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTEXP0"))); pixelShiftOptions->pack_start(*pixelShiftExp0); - - pixelShiftLmmse = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_PIXELSHIFTLMMSE"))); +#endif + pixelShiftLmmse = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTLMMSE"))); + pixelShiftLmmse->set_tooltip_text (M("TP_RAW_PIXELSHIFTLMMSE_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftLmmse); +#ifdef PIXELSHIFTDEV pixelShiftMotion = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMOTION"), 0, 100, 1, 70)); pixelShiftMotion->setAdjusterListener (this); pixelShiftMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTMOTION_TOOLTIP")); @@ -182,7 +215,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotion->show(); pixelShiftOptions->pack_start(*pixelShiftMotion); - Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); hb2->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_PIXELSHIFTMOTIONCORRECTION") + ": ")), Gtk::PACK_SHRINK, 0); pixelShiftMotionCorrection = Gtk::manage (new MyComboBoxText ()); @@ -196,7 +228,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftMotionCorrection->show(); hb2->pack_start(*pixelShiftMotionCorrection); pixelShiftOptions->pack_start(*hb2); - pixelShiftStddevFactorGreen = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN"), 2, 8, 0.1, 5)); pixelShiftStddevFactorGreen->setAdjusterListener (this); @@ -226,17 +257,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftStddevFactorBlue->show(); pixelShiftOptions->pack_start(*pixelShiftStddevFactorBlue); +#endif - pixelShiftEperIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTEPERISO"), -5.0, 5.0, 0.05, 0.0)); - pixelShiftEperIso->setAdjusterListener (this); - - if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { - pixelShiftEperIso->delay = options.adjusterMaxDelay; - } - - pixelShiftEperIso->show(); - pixelShiftOptions->pack_start(*pixelShiftEperIso); - +#ifdef PIXELSHIFTDEV pixelShiftNreadIso = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTNREADISO"), -2.0, 2.0, 0.05, 0.0)); pixelShiftNreadIso->setAdjusterListener (this); @@ -258,16 +281,6 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftPrnu->show(); pixelShiftOptions->pack_start(*pixelShiftPrnu); - pixelShiftSigma = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTSIGMA"), 0.5, 25, 0.1, 1.0)); - pixelShiftSigma->setAdjusterListener (this); - - if (pixelShiftSigma->delay < options.adjusterMaxDelay) { - pixelShiftSigma->delay = options.adjusterMaxDelay; - } - - pixelShiftSigma->show(); - pixelShiftOptions->pack_start(*pixelShiftSigma); - pixelShiftSum = Gtk::manage (new Adjuster (M("TP_RAW_PIXELSHIFTMASKTHRESHOLD"), 1.0, 8.0, 0.1, 3.0)); pixelShiftSum->setAdjusterListener (this); @@ -287,6 +300,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftRedBlueWeight->show(); pixelShiftOptions->pack_start(*pixelShiftRedBlueWeight); +#endif pixelShiftFrame->pack_start(*pixelShiftOptions); pixelShiftOptions->hide(); @@ -296,40 +310,42 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); //allOptions = Gtk::manage (new Gtk::VBox ()); //allOptions->set_border_width(2); - //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); + //allEnhance = Gtk::manage (new MyCheckButton(M("TP_RAW_ALLENHANCE"))); //allOptions->pack_start(*allEnhance); //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); - methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); - psmcconn = pixelShiftMotionCorrection->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::psMotionCorrectionChanged) ); - imagenumberconn = imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) ); - dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); - pixelShiftMotionMethodConn = pixelShiftMotionMethod->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::pixelShiftMotionMethodChanged) ); - pixelShiftShowMotionconn = pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true); - pixelShiftShowMotionMaskOnlyconn = pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true); - pixelShiftAutomaticconn = pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true); - pixelShiftNonGreenHorizontalconn = pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true); - pixelShiftNonGreenVerticalconn = pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true); - pixelShiftHoleFillconn = pixelShiftHoleFill->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftHoleFillChanged), true); - pixelShiftMedianconn = pixelShiftMedian->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedianChanged), true); - pixelShiftMedian3conn = pixelShiftMedian3->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedian3Changed), true); - pixelShiftGreenconn = pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true); - pixelShiftBlurconn = pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true); - pixelShiftExp0conn = pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true); - pixelShiftLmmseconn = pixelShiftLmmse->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftLmmseChanged), true); - pixelShiftNonGreenCrossconn = pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true); - pixelShiftNonGreenCross2conn = pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true); - pixelShiftNonGreenAmazeconn = pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true); + method->connect(method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) )); + imageNumber->connect(imageNumber->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::imageNumberChanged) )); + dcbEnhance->connect ( dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true)); + pixelShiftMotionMethod->connect(pixelShiftMotionMethod->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::pixelShiftMotionMethodChanged) )); + pixelShiftShowMotion->connect(pixelShiftShowMotion->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionChanged), true)); + pixelShiftShowMotionMaskOnly->connect(pixelShiftShowMotionMaskOnly->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftShowMotionMaskOnlyChanged), true)); + pixelShiftHoleFill->connect(pixelShiftHoleFill->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftHoleFillChanged), true)); + pixelShiftMedian->connect(pixelShiftMedian->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedianChanged), true)); + pixelShiftGreen->connect(pixelShiftGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftGreenChanged), true)); + pixelShiftBlur->connect(pixelShiftBlur->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftBlurChanged), true)); + pixelShiftLmmse->connect(pixelShiftLmmse->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftLmmseChanged), true)); + pixelShiftEqualBright->connect(pixelShiftEqualBright->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftEqualBrightChanged), true)); + pixelShiftNonGreenCross->connect(pixelShiftNonGreenCross->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCrossChanged), true)); +#ifdef PIXELSHIFTDEV + pixelShiftMotionCorrection->connect(pixelShiftMotionCorrection->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::psMotionCorrectionChanged) )); + pixelShiftAutomatic->connect(pixelShiftAutomatic->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftAutomaticChanged), true)); + pixelShiftNonGreenHorizontal->connect(pixelShiftNonGreenHorizontal->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenHorizontalChanged), true)); + pixelShiftNonGreenVertical->connect(pixelShiftNonGreenVertical->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenVerticalChanged), true)); + pixelShiftMedian3->connect(pixelShiftMedian3->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftMedian3Changed), true)); + pixelShiftExp0->connect(pixelShiftExp0->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftExp0Changed), true)); + pixelShiftNonGreenCross2->connect(pixelShiftNonGreenCross2->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenCross2Changed), true)); + pixelShiftNonGreenAmaze->connect(pixelShiftNonGreenAmaze->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::pixelShiftNonGreenAmazeChanged), true)); +#endif } void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - methodconn.block (true); - dcbEnhconn.block (true); - imagenumberconn.block (true); - psmcconn.block (true); + method->block (true); + dcbEnhance->block (true); + imageNumber->block (true); //allEnhconn.block (true); method->set_active(procparams::RAWParams::BayerSensor::numMethods); @@ -349,31 +365,34 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); pixelShiftShowMotionMaskOnly->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); - pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); - pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); - pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftHoleFill->set_inconsistent(!pedited->raw.bayersensor.pixelShiftHoleFill); pixelShiftMedian->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian); - pixelShiftMedian3->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_inconsistent(!pedited->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); pixelShiftSmooth->setEditedState ( pedited->raw.bayersensor.pixelShiftSmooth ? Edited : UnEdited); - pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); pixelShiftLmmse->set_inconsistent(!pedited->raw.bayersensor.pixelShiftLmmse); + pixelShiftEqualBright->set_inconsistent(!pedited->raw.bayersensor.pixelShiftEqualBright); pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); - pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); + pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); + pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); +#ifdef PIXELSHIFTDEV + pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); + pixelShiftPrnu->setEditedState ( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); pixelShiftStddevFactorGreen->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); pixelShiftStddevFactorRed->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorRed ? Edited : UnEdited); pixelShiftStddevFactorBlue->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorBlue ? Edited : UnEdited); - pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); - pixelShiftNreadIso->setEditedState ( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); - pixelShiftPrnu->setEditedState ( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); - pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); pixelShiftSum->setEditedState ( pedited->raw.bayersensor.pixelShiftSum ? Edited : UnEdited); + pixelShiftAutomatic->set_inconsistent(!pedited->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftMedian3->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian3); + pixelShiftExp0->set_inconsistent(!pedited->raw.bayersensor.pixelShiftExp0); + pixelShiftNonGreenCross2->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenAmaze); + pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftRedBlueWeight->setEditedState ( pedited->raw.bayersensor.pixelShiftRedBlueWeight ? Edited : UnEdited); +#endif if(!pedited->raw.bayersensor.method) { method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name @@ -381,9 +400,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params if(!pedited->raw.bayersensor.imageNum) { imageNumber->set_active_text(M("GENERAL_UNCHANGED")); } +#ifdef PIXELSHIFTDEV if(!pedited->raw.bayersensor.pixelShiftMotionCorrection) { pixelShiftMotionCorrection->set_active_text(M("GENERAL_UNCHANGED")); } +#endif if(!pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod) { pixelShiftMotionMethod->set_active_text(M("GENERAL_UNCHANGED")); } @@ -395,39 +416,41 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); pixelShiftShowMotionMaskOnly->set_active(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); - pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); - pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); - pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); pixelShiftHoleFill->set_active(pp->raw.bayersensor.pixelShiftHoleFill); pixelShiftMedian->set_active(pp->raw.bayersensor.pixelShiftMedian); - pixelShiftMedian3->set_active(pp->raw.bayersensor.pixelShiftMedian3); pixelShiftGreen->set_active(pp->raw.bayersensor.pixelShiftGreen); pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); pixelShiftSmooth->setValue (pp->raw.bayersensor.pixelShiftSmoothFactor); - pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); pixelShiftLmmse->set_active(pp->raw.bayersensor.pixelShiftLmmse); + pixelShiftEqualBright->set_active(pp->raw.bayersensor.pixelShiftEqualBright); pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); - pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); - pixelShiftMotionCorrection->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); + pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); + pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); +#ifdef PIXELSHIFTDEV pixelShiftStddevFactorGreen->setValue (pp->raw.bayersensor.pixelShiftStddevFactorGreen); pixelShiftStddevFactorRed->setValue (pp->raw.bayersensor.pixelShiftStddevFactorRed); pixelShiftStddevFactorBlue->setValue (pp->raw.bayersensor.pixelShiftStddevFactorBlue); - pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); - pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); - pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); - pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); pixelShiftSum->setValue (pp->raw.bayersensor.pixelShiftSum); - pixelShiftRedBlueWeight->setValue (pp->raw.bayersensor.pixelShiftRedBlueWeight); - + pixelShiftMedian3->set_active(pp->raw.bayersensor.pixelShiftMedian3); + pixelShiftMedian3->set_sensitive(pixelShiftMedian->get_active()); + pixelShiftAutomatic->set_active(pp->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->set_active(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->set_active(pp->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftExp0->set_active(pp->raw.bayersensor.pixelShiftExp0); + pixelShiftNonGreenCross2->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->set_active(pp->raw.bayersensor.pixelShiftNonGreenAmaze); + pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); + pixelShiftMotionCorrection->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); pixelShiftHoleFill->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); pixelShiftBlur->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5); pixelShiftSmooth->set_sensitive(pixelShiftAutomatic->get_active () && pixelShiftMotionCorrection->get_active_row_number() == 5 && pixelShiftBlur->get_active()); - + pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); + pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); + pixelShiftRedBlueWeight->setValue (pp->raw.bayersensor.pixelShiftRedBlueWeight); +#endif if (!batchMode) { if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) { @@ -462,13 +485,34 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params ccSteps->hide();*/ } - lastDCBen = pp->raw.bayersensor.dcb_enhance; + dcbEnhance->setLastActive(pp->raw.bayersensor.dcb_enhance); + pixelShiftShowMotion->setLastActive(pp->raw.bayersensor.pixelshiftShowMotion); + pixelShiftShowMotionMaskOnly->setLastActive(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); + pixelShiftNonGreenCross->setLastActive(pp->raw.bayersensor.pixelShiftNonGreenCross); + pixelShiftGreen->setLastActive(pp->raw.bayersensor.pixelShiftGreen); + pixelShiftBlur->setLastActive(pp->raw.bayersensor.pixelShiftBlur); + pixelShiftHoleFill->setLastActive(pp->raw.bayersensor.pixelShiftHoleFill); + pixelShiftMedian->setLastActive(pp->raw.bayersensor.pixelShiftMedian); + pixelShiftLmmse->setLastActive(pp->raw.bayersensor.pixelShiftLmmse); + pixelShiftEqualBright->setLastActive(pp->raw.bayersensor.pixelShiftEqualBright); +#ifdef PIXELSHIFTDEV + pixelShiftMedian3->setLastActive(pp->raw.bayersensor.pixelShiftMedian3); + pixelShiftAutomatic->setLastActive(pp->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->setLastActive(pp->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->setLastActive(pp->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftNonGreenCross2->setLastActive(pp->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->setLastActive(pp->raw.bayersensor.pixelShiftNonGreenAmaze); + pixelShiftExp0->setLastActive(pp->raw.bayersensor.pixelShiftExp0); +#endif + //lastALLen = pp->raw.bayersensor.all_enhance; - methodconn.block (false); - psmcconn.block (false); - imagenumberconn.block (false); - dcbEnhconn.block (false); + method->block (false); +#ifdef PIXELSHIFTDEV + pixelShiftMotionCorrection->block (false); +#endif + imageNumber->block (false); + dcbEnhance->block (false); //allEnhconn.block (false); enableListener (); @@ -481,34 +525,37 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); - pp->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getIntValue(); - pp->raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)pixelShiftMotionCorrection->get_active_row_number(); pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::ePSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); - pp->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getValue(); - pp->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getValue(); - pp->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getValue(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); - pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); - pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); pp->raw.bayersensor.pixelShiftSigma = pixelShiftSigma->getValue(); - pp->raw.bayersensor.pixelShiftSum = pixelShiftSum->getValue(); - pp->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getValue(); pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); - pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); - pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); - pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); pp->raw.bayersensor.pixelShiftHoleFill = pixelShiftHoleFill->get_active(); pp->raw.bayersensor.pixelShiftMedian = pixelShiftMedian->get_active(); - pp->raw.bayersensor.pixelShiftMedian3 = pixelShiftMedian3->get_active(); pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->get_active(); pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); pp->raw.bayersensor.pixelShiftSmoothFactor = pixelShiftSmooth->getValue(); - pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); pp->raw.bayersensor.pixelShiftLmmse = pixelShiftLmmse->get_active(); + pp->raw.bayersensor.pixelShiftEqualBright = pixelShiftEqualBright->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); +#ifdef PIXELSHIFTDEV + pp->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getValue(); + pp->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getValue(); + pp->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getValue(); + pp->raw.bayersensor.pixelShiftSum = pixelShiftSum->getValue(); + pp->raw.bayersensor.pixelShiftMedian3 = pixelShiftMedian3->get_active(); + pp->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getIntValue(); + pp->raw.bayersensor.pixelShiftMotionCorrection = (RAWParams::BayerSensor::ePSMotionCorrection)pixelShiftMotionCorrection->get_active_row_number(); + pp->raw.bayersensor.pixelShiftAutomatic = pixelShiftAutomatic->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->get_active(); + pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->get_active(); + pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->get_active(); pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->get_active(); pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->get_active(); + pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); + pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); + pp->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getValue(); +#endif int currentRow = method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { @@ -529,34 +576,37 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); - pedited->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getEditedState (); - pedited->raw.bayersensor.pixelShiftMotionCorrection = pixelShiftMotionCorrection->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = pixelShiftMotionMethod->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getEditedState (); - pedited->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getEditedState (); - pedited->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getEditedState (); pedited->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getEditedState (); - pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); - pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); pedited->raw.bayersensor.pixelShiftSigma = pixelShiftSigma->getEditedState (); - pedited->raw.bayersensor.pixelShiftSum = pixelShiftSum->getEditedState (); - pedited->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getEditedState (); pedited->raw.bayersensor.pixelshiftShowMotion = !pixelShiftShowMotion->get_inconsistent(); pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly = !pixelShiftShowMotionMaskOnly->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); pedited->raw.bayersensor.pixelShiftHoleFill = !pixelShiftHoleFill->get_inconsistent(); pedited->raw.bayersensor.pixelShiftMedian = !pixelShiftMedian->get_inconsistent(); - pedited->raw.bayersensor.pixelShiftMedian3 = !pixelShiftMedian3->get_inconsistent(); pedited->raw.bayersensor.pixelShiftGreen = !pixelShiftGreen->get_inconsistent(); pedited->raw.bayersensor.pixelShiftBlur = !pixelShiftBlur->get_inconsistent(); pedited->raw.bayersensor.pixelShiftSmooth = pixelShiftSmooth->getEditedState(); - pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); pedited->raw.bayersensor.pixelShiftLmmse = !pixelShiftLmmse->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftEqualBright = !pixelShiftEqualBright->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross = !pixelShiftNonGreenCross->get_inconsistent(); +#ifdef PIXELSHIFTDEV + pedited->raw.bayersensor.pixelShiftStddevFactorGreen = pixelShiftStddevFactorGreen->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactorRed = pixelShiftStddevFactorRed->getEditedState (); + pedited->raw.bayersensor.pixelShiftStddevFactorBlue = pixelShiftStddevFactorBlue->getEditedState (); + pedited->raw.bayersensor.pixelShiftSum = pixelShiftSum->getEditedState (); + pedited->raw.bayersensor.pixelShiftMedian3 = !pixelShiftMedian3->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftMotion = pixelShiftMotion->getEditedState (); + pedited->raw.bayersensor.pixelShiftMotionCorrection = pixelShiftMotionCorrection->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->raw.bayersensor.pixelShiftAutomatic = !pixelShiftAutomatic->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenHorizontal = !pixelShiftNonGreenHorizontal->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNonGreenVertical = !pixelShiftNonGreenVertical->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftExp0 = !pixelShiftExp0->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenCross2 = !pixelShiftNonGreenCross2->get_inconsistent(); pedited->raw.bayersensor.pixelShiftNonGreenAmaze = !pixelShiftNonGreenAmaze->get_inconsistent(); + pedited->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getEditedState (); + pedited->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getEditedState (); + pedited->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getEditedState (); +#endif } } @@ -564,8 +614,10 @@ void BayerProcess::setBatchMode(bool batchMode) { method->append_text (M("GENERAL_UNCHANGED")); method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name +#ifdef PIXELSHIFTDEV pixelShiftMotionCorrection->append_text (M("GENERAL_UNCHANGED")); pixelShiftMotionCorrection->set_active (4); +#endif pixelShiftMotionMethod->append_text (M("GENERAL_UNCHANGED")); pixelShiftMotionMethod->set_active (4); imageNumber->append_text (M("GENERAL_UNCHANGED")); @@ -577,61 +629,69 @@ void BayerProcess::setBatchMode(bool batchMode) ccSteps->showEditedCB (); dcbIterations->showEditedCB (); lmmseIterations->showEditedCB (); +#ifdef PIXELSHIFTDEV pixelShiftMotion->showEditedCB (); + pixelShiftSum->showEditedCB (); pixelShiftStddevFactorGreen->showEditedCB (); pixelShiftStddevFactorRed->showEditedCB (); pixelShiftStddevFactorBlue->showEditedCB (); - pixelShiftEperIso->showEditedCB (); pixelShiftNreadIso->showEditedCB (); pixelShiftPrnu->showEditedCB (); - pixelShiftSigma->showEditedCB (); - pixelShiftSum->showEditedCB (); pixelShiftRedBlueWeight->showEditedCB (); +#endif + pixelShiftEperIso->showEditedCB (); + pixelShiftSigma->showEditedCB (); } void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) { dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); +#ifdef PIXELSHIFTDEV pixelShiftMotion->setDefault( defParams->raw.bayersensor.pixelShiftMotion); + pixelShiftSum->setDefault( defParams->raw.bayersensor.pixelShiftSum); pixelShiftStddevFactorGreen->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorGreen); pixelShiftStddevFactorRed->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorRed); pixelShiftStddevFactorBlue->setDefault( defParams->raw.bayersensor.pixelShiftStddevFactorBlue); - pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); pixelShiftNreadIso->setDefault( defParams->raw.bayersensor.pixelShiftNreadIso); pixelShiftPrnu->setDefault( defParams->raw.bayersensor.pixelShiftPrnu); - pixelShiftSigma->setDefault( defParams->raw.bayersensor.pixelShiftSigma); - pixelShiftSum->setDefault( defParams->raw.bayersensor.pixelShiftSum); pixelShiftRedBlueWeight->setDefault( defParams->raw.bayersensor.pixelShiftRedBlueWeight); +#endif + pixelShiftEperIso->setDefault( defParams->raw.bayersensor.pixelShiftEperIso); + pixelShiftSigma->setDefault( defParams->raw.bayersensor.pixelShiftSigma); ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); if (pedited) { dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); +#ifdef PIXELSHIFTDEV pixelShiftMotion->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); + pixelShiftSum->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSum ? Edited : UnEdited); pixelShiftStddevFactorGreen->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorGreen ? Edited : UnEdited); pixelShiftStddevFactorRed->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorRed ? Edited : UnEdited); pixelShiftStddevFactorBlue->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftStddevFactorBlue ? Edited : UnEdited); - pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftNreadIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftNreadIso ? Edited : UnEdited); pixelShiftPrnu->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftPrnu ? Edited : UnEdited); - pixelShiftSigma->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); - pixelShiftSum->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSum ? Edited : UnEdited); pixelShiftRedBlueWeight->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftRedBlueWeight ? Edited : UnEdited); +#endif + pixelShiftEperIso->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); + pixelShiftSigma->setDefaultEditedState( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); } else { dcbIterations->setDefaultEditedState( Irrelevant ); lmmseIterations->setDefaultEditedState( Irrelevant ); +#ifdef PIXELSHIFTDEV pixelShiftMotion->setDefaultEditedState( Irrelevant ); + pixelShiftSum->setDefaultEditedState( Irrelevant ); pixelShiftStddevFactorGreen->setDefaultEditedState( Irrelevant ); pixelShiftStddevFactorRed->setDefaultEditedState( Irrelevant ); pixelShiftStddevFactorBlue->setDefaultEditedState( Irrelevant ); - pixelShiftEperIso->setDefaultEditedState( Irrelevant ); pixelShiftNreadIso->setDefaultEditedState( Irrelevant ); pixelShiftPrnu->setDefaultEditedState( Irrelevant ); - pixelShiftSigma->setDefaultEditedState( Irrelevant ); - pixelShiftSum->setDefaultEditedState( Irrelevant ); pixelShiftRedBlueWeight->setDefaultEditedState( Irrelevant ); +#endif + pixelShiftEperIso->setDefaultEditedState( Irrelevant ); + pixelShiftSigma->setDefaultEditedState( Irrelevant ); ccSteps->setDefaultEditedState(Irrelevant ); } } @@ -645,32 +705,35 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); } else if (a == lmmseIterations) { listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); +#ifdef PIXELSHIFTDEV } else if (a == pixelShiftMotion) { listener->panelChanged (EvPixelShiftMotion, a->getTextValue() ); + } else if (a == pixelShiftSum) { + listener->panelChanged (EvPixelShiftSum, a->getTextValue() ); } else if (a == pixelShiftStddevFactorGreen) { listener->panelChanged (EvPixelShiftStddevFactorGreen, a->getTextValue() ); } else if (a == pixelShiftStddevFactorRed) { listener->panelChanged (EvPixelShiftStddevFactorRed, a->getTextValue() ); } else if (a == pixelShiftStddevFactorBlue) { listener->panelChanged (EvPixelShiftStddevFactorBlue, a->getTextValue() ); - } else if (a == pixelShiftEperIso) { - listener->panelChanged (EvPixelShiftEperIso, a->getTextValue() ); } else if (a == pixelShiftNreadIso) { listener->panelChanged (EvPixelShiftNreadIso, a->getTextValue() ); } else if (a == pixelShiftPrnu) { listener->panelChanged (EvPixelShiftPrnu, a->getTextValue() ); - } else if (a == pixelShiftSigma) { - listener->panelChanged (EvPixelShiftSigma, a->getTextValue() ); - } else if (a == pixelShiftSum) { - listener->panelChanged (EvPixelShiftSum, a->getTextValue() ); } else if (a == pixelShiftRedBlueWeight) { listener->panelChanged (EvPixelShiftRedBlueWeight, a->getTextValue() ); +#endif + } else if (a == pixelShiftEperIso) { + listener->panelChanged (EvPixelShiftEperIso, a->getTextValue() ); + } else if (a == pixelShiftSigma) { + listener->panelChanged (EvPixelShiftSigma, a->getTextValue() ); } else if (a == pixelShiftSmooth) { listener->panelChanged (EvPixelShiftSmooth, a->getTextValue() ); } } } +#ifdef PIXELSHIFTDEV void BayerProcess::psMotionCorrectionChanged () { if(pixelShiftMotionCorrection->get_active_row_number() == 5) { @@ -687,7 +750,7 @@ void BayerProcess::psMotionCorrectionChanged () listener->panelChanged (EvPixelShiftMotionCorrection, pixelShiftMotionCorrection->get_active_text()); } } - +#endif void BayerProcess::methodChanged () { int curSelection = method->get_active_row_number(); @@ -745,14 +808,14 @@ void BayerProcess::dcbEnhanceChanged () if (batchMode) { if (dcbEnhance->get_inconsistent()) { dcbEnhance->set_inconsistent (false); - dcbEnhconn.block (true); + dcbEnhance->block (true); dcbEnhance->set_active (false); - dcbEnhconn.block (false); - } else if (lastDCBen) { + dcbEnhance->block (false); + } else if (dcbEnhance->getLastActive()) { dcbEnhance->set_inconsistent (true); } - lastDCBen = dcbEnhance->get_active (); + dcbEnhance->setLastActive(); } if (listener) { @@ -785,14 +848,14 @@ void BayerProcess::pixelShiftShowMotionChanged () if (batchMode) { if (pixelShiftShowMotion->get_inconsistent()) { pixelShiftShowMotion->set_inconsistent (false); - pixelShiftShowMotionconn.block (true); + pixelShiftShowMotion->block (true); pixelShiftShowMotion->set_active (false); - pixelShiftShowMotionconn.block (false); - } else if (lastDCBen) { + pixelShiftShowMotion->block (false); + } else if (pixelShiftShowMotion->getLastActive()) { pixelShiftShowMotion->set_inconsistent (true); } - lastDCBen = pixelShiftShowMotion->get_active (); + pixelShiftShowMotion->setLastActive(); } pixelShiftShowMotionMaskOnly->set_sensitive(pixelShiftShowMotion->get_active ()); if (listener) { @@ -805,14 +868,14 @@ void BayerProcess::pixelShiftShowMotionMaskOnlyChanged () if (batchMode) { if (pixelShiftShowMotionMaskOnly->get_inconsistent()) { pixelShiftShowMotionMaskOnly->set_inconsistent (false); - pixelShiftShowMotionMaskOnlyconn.block (true); + pixelShiftShowMotionMaskOnly->block (true); pixelShiftShowMotionMaskOnly->set_active (false); - pixelShiftShowMotionMaskOnlyconn.block (false); - } else if (lastDCBen) { + pixelShiftShowMotionMaskOnly->block (false); + } else if (pixelShiftShowMotionMaskOnly->getLastActive()) { pixelShiftShowMotionMaskOnly->set_inconsistent (true); } - lastDCBen = pixelShiftShowMotionMaskOnly->get_active (); + pixelShiftShowMotionMaskOnly->setLastActive(); } if (listener) { @@ -820,19 +883,20 @@ void BayerProcess::pixelShiftShowMotionMaskOnlyChanged () } } +#ifdef PIXELSHIFTDEV void BayerProcess::pixelShiftAutomaticChanged () { if (batchMode) { if (pixelShiftAutomatic->get_inconsistent()) { pixelShiftAutomatic->set_inconsistent (false); - pixelShiftAutomaticconn.block (true); + pixelShiftAutomatic->block (true); pixelShiftAutomatic->set_active (false); - pixelShiftAutomaticconn.block (false); - } else if (lastDCBen) { + pixelShiftAutomatic->block (false); + } else if (pixelShiftAutomatic->getLastActive()) { pixelShiftAutomatic->set_inconsistent (true); } - lastDCBen = pixelShiftAutomatic->get_active (); + pixelShiftAutomatic->setLastActive(); } pixelShiftMotion->set_sensitive(!pixelShiftAutomatic->get_active ()); pixelShiftEperIso->set_sensitive(pixelShiftAutomatic->get_active ()); @@ -861,20 +925,19 @@ void BayerProcess::pixelShiftAutomaticChanged () } } - void BayerProcess::pixelShiftNonGreenHorizontalChanged () { if (batchMode) { if (pixelShiftNonGreenHorizontal->get_inconsistent()) { pixelShiftNonGreenHorizontal->set_inconsistent (false); - pixelShiftNonGreenHorizontalconn.block (true); + pixelShiftNonGreenHorizontal->block (true); pixelShiftNonGreenHorizontal->set_active (false); - pixelShiftNonGreenHorizontalconn.block (false); - } else if (lastDCBen) { + pixelShiftNonGreenHorizontal->block (false); + } else if (pixelShiftNonGreenHorizontal->getLastActive()) { pixelShiftNonGreenHorizontal->set_inconsistent (true); } - lastDCBen = pixelShiftNonGreenHorizontal->get_active (); + pixelShiftNonGreenHorizontal->setLastActive(); } if (listener) { @@ -887,34 +950,35 @@ void BayerProcess::pixelShiftNonGreenVerticalChanged () if (batchMode) { if (pixelShiftNonGreenVertical->get_inconsistent()) { pixelShiftNonGreenVertical->set_inconsistent (false); - pixelShiftNonGreenVerticalconn.block (true); + pixelShiftNonGreenVertical->block (true); pixelShiftNonGreenVertical->set_active (false); - pixelShiftNonGreenVerticalconn.block (false); - } else if (lastDCBen) { + pixelShiftNonGreenVertical->block (false); + } else if (pixelShiftNonGreenVertical->getLastActive()) { pixelShiftNonGreenVertical->set_inconsistent (true); } - lastDCBen = pixelShiftNonGreenVertical->get_active (); + pixelShiftNonGreenVertical->setLastActive(); } if (listener) { listener->panelChanged (EvPixelShiftNonGreenVertical, pixelShiftNonGreenVertical->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } +#endif void BayerProcess::pixelShiftHoleFillChanged () { if (batchMode) { if (pixelShiftHoleFill->get_inconsistent()) { pixelShiftHoleFill->set_inconsistent (false); - pixelShiftHoleFillconn.block (true); + pixelShiftHoleFill->block (true); pixelShiftHoleFill->set_active (false); - pixelShiftHoleFillconn.block (false); - } else if (lastDCBen) { + pixelShiftHoleFill->block (false); + } else if (pixelShiftHoleFill->getLastActive()) { pixelShiftHoleFill->set_inconsistent (true); } - lastDCBen = pixelShiftHoleFill->get_active (); + pixelShiftHoleFill->setLastActive(); } if (listener) { @@ -927,56 +991,56 @@ void BayerProcess::pixelShiftMedianChanged () if (batchMode) { if (pixelShiftMedian->get_inconsistent()) { pixelShiftMedian->set_inconsistent (false); - pixelShiftMedianconn.block (true); + pixelShiftMedian->block (true); pixelShiftMedian->set_active (false); - pixelShiftMedianconn.block (false); - } else if (lastDCBen) { + pixelShiftMedian->block (false); + } else if (pixelShiftMedian->getLastActive()) { pixelShiftMedian->set_inconsistent (true); } - lastDCBen = pixelShiftMedian->get_active (); + pixelShiftMedian->setLastActive(); } - +#ifdef PIXELSHIFTDEV pixelShiftMedian3->set_sensitive(pixelShiftMedian->get_active ()); - +#endif if (listener) { listener->panelChanged (EvPixelShiftMedian, pixelShiftMedian->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } - +#ifdef PIXELSHIFTDEV void BayerProcess::pixelShiftMedian3Changed () { if (batchMode) { if (pixelShiftMedian3->get_inconsistent()) { pixelShiftMedian3->set_inconsistent (false); - pixelShiftMedian3conn.block (true); + pixelShiftMedian3->block (true); pixelShiftMedian3->set_active (false); - pixelShiftMedian3conn.block (false); - } else if (lastDCBen) { + pixelShiftMedian3->block (false); + } else if (pixelShiftMedian3->getLastActive()) { pixelShiftMedian3->set_inconsistent (true); } - lastDCBen = pixelShiftMedian3->get_active (); + pixelShiftMedian3->setLastActive(); } if (listener) { listener->panelChanged (EvPixelShiftMedian3, pixelShiftMedian3->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } - +#endif void BayerProcess::pixelShiftGreenChanged () { if (batchMode) { if (pixelShiftGreen->get_inconsistent()) { pixelShiftGreen->set_inconsistent (false); - pixelShiftGreenconn.block (true); + pixelShiftGreen->block (true); pixelShiftGreen->set_active (false); - pixelShiftGreenconn.block (false); - } else if (lastDCBen) { + pixelShiftGreen->block (false); + } else if (pixelShiftGreen->getLastActive()) { pixelShiftGreen->set_inconsistent (true); } - lastDCBen = pixelShiftGreen->get_active (); + pixelShiftGreen->setLastActive(); } if (listener) { @@ -989,56 +1053,56 @@ void BayerProcess::pixelShiftBlurChanged () if (batchMode) { if (pixelShiftBlur->get_inconsistent()) { pixelShiftBlur->set_inconsistent (false); - pixelShiftBlurconn.block (true); + pixelShiftBlur->block (true); pixelShiftBlur->set_active (false); - pixelShiftBlurconn.block (false); - } else if (lastDCBen) { + pixelShiftBlur->block (false); + } else if (pixelShiftBlur->getLastActive()) { pixelShiftBlur->set_inconsistent (true); } - lastDCBen = pixelShiftBlur->get_active (); + pixelShiftBlur->setLastActive(); } pixelShiftSmooth->set_sensitive(pixelShiftBlur->get_active ()); - + pixelShiftSigma->set_sensitive(pixelShiftBlur->get_active ()); if (listener) { listener->panelChanged (EvPixelShiftBlur, pixelShiftBlur->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } - +#ifdef PIXELSHIFTDEV void BayerProcess::pixelShiftExp0Changed () { if (batchMode) { if (pixelShiftExp0->get_inconsistent()) { pixelShiftExp0->set_inconsistent (false); - pixelShiftExp0conn.block (true); + pixelShiftExp0->block (true); pixelShiftExp0->set_active (false); - pixelShiftExp0conn.block (false); - } else if (lastDCBen) { + pixelShiftExp0->block (false); + } else if (pixelShiftExp0->getLastActive()) { pixelShiftExp0->set_inconsistent (true); } - lastDCBen = pixelShiftExp0->get_active (); + pixelShiftExp0->setLastActive(); } if (listener) { listener->panelChanged (EvPixelShiftExp0, pixelShiftExp0->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } - +#endif void BayerProcess::pixelShiftLmmseChanged () { if (batchMode) { if (pixelShiftLmmse->get_inconsistent()) { pixelShiftLmmse->set_inconsistent (false); - pixelShiftLmmseconn.block (true); + pixelShiftLmmse->block (true); pixelShiftLmmse->set_active (false); - pixelShiftLmmseconn.block (false); - } else if (lastDCBen) { + pixelShiftLmmse->block (false); + } else if (pixelShiftLmmse->getLastActive()) { pixelShiftLmmse->set_inconsistent (true); } - lastDCBen = pixelShiftLmmse->get_active (); + pixelShiftLmmse->setLastActive(); } if (listener) { @@ -1046,39 +1110,59 @@ void BayerProcess::pixelShiftLmmseChanged () } } +void BayerProcess::pixelShiftEqualBrightChanged () +{ + if (batchMode) { + if (pixelShiftEqualBright->get_inconsistent()) { + pixelShiftEqualBright->set_inconsistent (false); + pixelShiftEqualBright->block (true); + pixelShiftEqualBright->set_active (false); + pixelShiftEqualBright->block (false); + } else if (pixelShiftEqualBright->getLastActive()) { + pixelShiftEqualBright->set_inconsistent (true); + } + + pixelShiftEqualBright->setLastActive(); + } + + if (listener) { + listener->panelChanged (EvPixelShiftEqualBright, pixelShiftEqualBright->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void BayerProcess::pixelShiftNonGreenCrossChanged () { if (batchMode) { if (pixelShiftNonGreenCross->get_inconsistent()) { pixelShiftNonGreenCross->set_inconsistent (false); - pixelShiftNonGreenCrossconn.block (true); + pixelShiftNonGreenCross->block (true); pixelShiftNonGreenCross->set_active (false); - pixelShiftNonGreenCrossconn.block (false); - } else if (lastDCBen) { + pixelShiftNonGreenCross->block (false); + } else if (pixelShiftNonGreenCross->getLastActive()) { pixelShiftNonGreenCross->set_inconsistent (true); } - lastDCBen = pixelShiftNonGreenCross->get_active (); + pixelShiftNonGreenCross->setLastActive(); } if (listener) { listener->panelChanged (EvPixelShiftNonGreenCross, pixelShiftNonGreenCross->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } - +#ifdef PIXELSHIFTDEV void BayerProcess::pixelShiftNonGreenCross2Changed () { if (batchMode) { if (pixelShiftNonGreenCross2->get_inconsistent()) { pixelShiftNonGreenCross2->set_inconsistent (false); - pixelShiftNonGreenCross2conn.block (true); + pixelShiftNonGreenCross2->block (true); pixelShiftNonGreenCross2->set_active (false); - pixelShiftNonGreenCross2conn.block (false); - } else if (lastDCBen) { + pixelShiftNonGreenCross2->block (false); + } else if (pixelShiftNonGreenCross2->getLastActive()) { pixelShiftNonGreenCross2->set_inconsistent (true); } - lastDCBen = pixelShiftNonGreenCross2->get_active (); + pixelShiftNonGreenCross2->setLastActive(); } if (listener) { @@ -1091,17 +1175,18 @@ void BayerProcess::pixelShiftNonGreenAmazeChanged () if (batchMode) { if (pixelShiftNonGreenAmaze->get_inconsistent()) { pixelShiftNonGreenAmaze->set_inconsistent (false); - pixelShiftNonGreenAmazeconn.block (true); + pixelShiftNonGreenAmaze->block (true); pixelShiftNonGreenAmaze->set_active (false); - pixelShiftNonGreenAmazeconn.block (false); - } else if (lastDCBen) { + pixelShiftNonGreenAmaze->block (false); + } else if (pixelShiftNonGreenAmaze->getLastActive()) { pixelShiftNonGreenAmaze->set_inconsistent (true); } - lastDCBen = pixelShiftNonGreenAmaze->get_active (); + pixelShiftNonGreenAmaze->setLastActive(); } if (listener) { listener->panelChanged (EvPixelShiftNonGreenAmaze, pixelShiftNonGreenAmaze->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } +#endif \ No newline at end of file diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index c8658f5bf..463e8fb58 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -36,48 +36,43 @@ protected: Adjuster* ccSteps; Gtk::VBox *dcbOptions; Adjuster* dcbIterations; - Gtk::CheckButton* dcbEnhance; - //Gtk::VBox *allOptions; - //Gtk::CheckButton* allEnhance; + MyCheckButton* dcbEnhance; Gtk::VBox *lmmseOptions; Adjuster* lmmseIterations; Gtk::VBox *pixelShiftFrame; Gtk::VBox *pixelShiftOptions; + MyComboBoxText* pixelShiftMotionMethod; + MyCheckButton* pixelShiftShowMotion; + MyCheckButton* pixelShiftShowMotionMaskOnly; + MyCheckButton* pixelShiftNonGreenCross; + MyCheckButton* pixelShiftGreen; + MyCheckButton* pixelShiftBlur; + MyCheckButton* pixelShiftHoleFill; + MyCheckButton* pixelShiftMedian; + MyCheckButton* pixelShiftLmmse; + MyCheckButton* pixelShiftEqualBright; + Adjuster* pixelShiftSmooth; + Adjuster* pixelShiftEperIso; + Adjuster* pixelShiftSigma; +#ifdef PIXELSHIFTDEV + Adjuster* pixelShiftSum; Adjuster* pixelShiftMotion; MyComboBoxText* pixelShiftMotionCorrection; - MyComboBoxText* pixelShiftMotionMethod; - Gtk::CheckButton* pixelShiftShowMotion; - Gtk::CheckButton* pixelShiftShowMotionMaskOnly; - Gtk::CheckButton* pixelShiftAutomatic; - Gtk::CheckButton* pixelShiftNonGreenHorizontal; - Gtk::CheckButton* pixelShiftNonGreenVertical; - Gtk::CheckButton* pixelShiftNonGreenCross; - Gtk::CheckButton* pixelShiftNonGreenCross2; - Gtk::CheckButton* pixelShiftNonGreenAmaze; - Gtk::CheckButton* pixelShiftGreen; - Gtk::CheckButton* pixelShiftBlur; - Gtk::CheckButton* pixelShiftExp0; - Gtk::CheckButton* pixelShiftHoleFill; - Gtk::CheckButton* pixelShiftMedian; - Gtk::CheckButton* pixelShiftMedian3; - Gtk::CheckButton* pixelShiftLmmse; - Adjuster* pixelShiftSmooth; + MyCheckButton* pixelShiftAutomatic; + MyCheckButton* pixelShiftNonGreenHorizontal; + MyCheckButton* pixelShiftNonGreenVertical; + MyCheckButton* pixelShiftNonGreenCross2; + MyCheckButton* pixelShiftNonGreenAmaze; + MyCheckButton* pixelShiftExp0; + MyCheckButton* pixelShiftMedian3; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; - Adjuster* pixelShiftEperIso; Adjuster* pixelShiftNreadIso; Adjuster* pixelShiftPrnu; - Adjuster* pixelShiftSigma; - Adjuster* pixelShiftSum; Adjuster* pixelShiftRedBlueWeight; - bool lastDCBen; +#endif int oldMethod; - //bool lastALLen; - sigc::connection methodconn, imagenumberconn, psmcconn, dcbEnhconn, - pixelShiftShowMotionconn, pixelShiftShowMotionMaskOnlyconn, pixelShiftAutomaticconn, - pixelShiftNonGreenHorizontalconn, pixelShiftNonGreenVerticalconn, pixelShiftHoleFillconn, pixelShiftMedianconn, pixelShiftMedian3conn, pixelShiftNonGreenCrossconn, - pixelShiftNonGreenCross2conn, pixelShiftNonGreenAmazeconn, pixelShiftGreenconn, pixelShiftBlurconn, pixelShiftSmoothconn, pixelShiftExp0conn, pixelShiftLmmseconn, pixelShiftMotionMethodConn; public: BayerProcess (); @@ -88,26 +83,29 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); void methodChanged (); - void psMotionCorrectionChanged (); void imageNumberChanged (); void adjusterChanged (Adjuster* a, double newval); void dcbEnhanceChanged(); void pixelShiftShowMotionChanged(); void pixelShiftShowMotionMaskOnlyChanged(); - void pixelShiftAutomaticChanged(); - void pixelShiftNonGreenHorizontalChanged(); - void pixelShiftNonGreenVerticalChanged(); void pixelShiftHoleFillChanged(); void pixelShiftMedianChanged(); void pixelShiftMedian3Changed(); void pixelShiftGreenChanged(); void pixelShiftBlurChanged(); - void pixelShiftExp0Changed(); void pixelShiftLmmseChanged(); + void pixelShiftEqualBrightChanged(); void pixelShiftNonGreenCrossChanged(); + void pixelShiftMotionMethodChanged(); +#ifdef PIXELSHIFTDEV + void psMotionCorrectionChanged (); + void pixelShiftAutomaticChanged(); + void pixelShiftNonGreenHorizontalChanged(); + void pixelShiftNonGreenVerticalChanged(); + void pixelShiftExp0Changed(); void pixelShiftNonGreenCross2Changed(); void pixelShiftNonGreenAmazeChanged(); - void pixelShiftMotionMethodChanged(); +#endif }; #endif diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 597173086..0803a2573 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -24,6 +24,7 @@ #include "../rtengine/coord.h" #include #include +#include Glib::ustring escapeHtmlChars(const Glib::ustring &src); bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference = true); @@ -259,6 +260,24 @@ public: MyScrolledWindow(); }; +/** + * @brief subclass of Gtk::CheckButton in order to handle the last active state + */ +class MyCheckButton : public Gtk::CheckButton +{ + + bool lastActive = false; + sigc::connection myConnection; +public: + using CheckButton::CheckButton; + void setLastActive() {lastActive = get_active();}; + void setLastActive(bool active) {lastActive = active;}; + bool getLastActive() {return lastActive;}; + void connect(const sigc::connection &connection) {myConnection = connection;}; + void block(bool blocked) {myConnection.block(blocked);}; +}; + + /** * @brief subclass of Gtk::ComboBox in order to handle the scrollwheel */ @@ -278,9 +297,12 @@ class MyComboBoxText : public Gtk::ComboBoxText { bool on_scroll_event (GdkEventScroll* event); + sigc::connection myConnection; public: MyComboBoxText (); + void connect(const sigc::connection &connection) {myConnection = connection;}; + void block(bool blocked) {myConnection.block(blocked);}; }; /** diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 939413f18..a84d1e8be 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -395,6 +395,7 @@ void ParamsEdited::set (bool v) raw.bayersensor.pixelShiftSmooth = v; raw.bayersensor.pixelShiftExp0 = v; raw.bayersensor.pixelShiftLmmse = v; + raw.bayersensor.pixelShiftEqualBright = v; raw.bayersensor.pixelShiftNonGreenCross = v; raw.bayersensor.pixelShiftNonGreenCross2 = v; raw.bayersensor.pixelShiftNonGreenAmaze = v; @@ -919,6 +920,7 @@ void ParamsEdited::initFrom (const std::vector raw.bayersensor.pixelShiftSmooth = raw.bayersensor.pixelShiftSmooth && p.raw.bayersensor.pixelShiftSmoothFactor == other.raw.bayersensor.pixelShiftSmoothFactor; raw.bayersensor.pixelShiftExp0 = raw.bayersensor.pixelShiftExp0 && p.raw.bayersensor.pixelShiftExp0 == other.raw.bayersensor.pixelShiftExp0; raw.bayersensor.pixelShiftLmmse = raw.bayersensor.pixelShiftLmmse && p.raw.bayersensor.pixelShiftLmmse == other.raw.bayersensor.pixelShiftLmmse; + raw.bayersensor.pixelShiftEqualBright = raw.bayersensor.pixelShiftEqualBright && p.raw.bayersensor.pixelShiftEqualBright == other.raw.bayersensor.pixelShiftEqualBright; raw.bayersensor.pixelShiftNonGreenCross = raw.bayersensor.pixelShiftNonGreenCross && p.raw.bayersensor.pixelShiftNonGreenCross == other.raw.bayersensor.pixelShiftNonGreenCross; raw.bayersensor.pixelShiftNonGreenCross2 = raw.bayersensor.pixelShiftNonGreenCross2 && p.raw.bayersensor.pixelShiftNonGreenCross2 == other.raw.bayersensor.pixelShiftNonGreenCross2; raw.bayersensor.pixelShiftNonGreenAmaze = raw.bayersensor.pixelShiftNonGreenAmaze && p.raw.bayersensor.pixelShiftNonGreenAmaze == other.raw.bayersensor.pixelShiftNonGreenAmaze; @@ -2434,6 +2436,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.raw.bayersensor.pixelShiftLmmse = mods.raw.bayersensor.pixelShiftLmmse; } + if (raw.bayersensor.pixelShiftEqualBright) { + toEdit.raw.bayersensor.pixelShiftEqualBright = mods.raw.bayersensor.pixelShiftEqualBright; + } + if (raw.bayersensor.pixelShiftNonGreenCross) { toEdit.raw.bayersensor.pixelShiftNonGreenCross = mods.raw.bayersensor.pixelShiftNonGreenCross; } @@ -2958,7 +2964,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const return method && imageNum && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq && 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 + && pixelShiftAutomatic && pixelShiftNonGreenHorizontal && pixelShiftNonGreenVertical && pixelShiftHoleFill && pixelShiftMedian && pixelShiftMedian3 && pixelShiftNonGreenCross && pixelShiftNonGreenCross2 && pixelShiftNonGreenAmaze && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftExp0 && pixelShiftLmmse && pixelShiftEqualBright && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 5f66c3d18..89a490b7f 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -717,6 +717,7 @@ public: bool pixelShiftSmooth; bool pixelShiftExp0; bool pixelShiftLmmse; + bool pixelShiftEqualBright; bool pixelShiftNonGreenCross; bool pixelShiftNonGreenCross2; bool pixelShiftNonGreenAmaze;