From 3f13a98135d7bfe8d03c6603b435cc99e2051355 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 1 Nov 2016 02:20:43 +0100 Subject: [PATCH 001/110] 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 002/110] 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 003/110] 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 004/110] 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 005/110] 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 006/110] 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 007/110] 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 008/110] 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 009/110] 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 010/110] 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 011/110] 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 012/110] 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 013/110] 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 014/110] 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 015/110] 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 016/110] 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 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 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 017/110] 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 018/110] 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 019/110] 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 020/110] 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 021/110] 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 022/110] 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 023/110] 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 024/110] 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 025/110] 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 026/110] 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 027/110] 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 028/110] 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 029/110] 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 030/110] 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 031/110] 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 032/110] 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 033/110] 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 034/110] 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 035/110] 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 036/110] 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 037/110] 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 038/110] 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 039/110] 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 040/110] 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 041/110] 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 042/110] 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 043/110] 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 044/110] 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 045/110] 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 046/110] 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 047/110] 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 048/110] 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 049/110] 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 050/110] 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 051/110] 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 052/110] 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 053/110] 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 054/110] 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 055/110] 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 056/110] 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 057/110] 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 058/110] 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 059/110] 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 060/110] 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 061/110] 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 062/110] 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 063/110] 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 064/110] 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 065/110] 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 066/110] 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 067/110] 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 068/110] 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 069/110] 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 070/110] 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 071/110] 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 072/110] 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 073/110] 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 074/110] 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 075/110] 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 076/110] 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 7b4d51238d7309a1a647e228a5cdac1f9155e94c Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 29 Jan 2017 18:14:06 +0100 Subject: [PATCH 077/110] New CLI version of rawtherapee.exe --- rtgui/main-cli.cc | 702 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 rtgui/main-cli.cc diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc new file mode 100644 index 000000000..33627e514 --- /dev/null +++ b/rtgui/main-cli.cc @@ -0,0 +1,702 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifdef __GNUC__ +#if defined(__FAST_MATH__) +#error Using the -ffast-math CFLAG is known to lead to problems. Disable it to compile RawTherapee. +#endif +#endif + +#include "config.h" +#include +#include +#include +#include +#include "rtwindow.h" +#include +#include +#include +#include "options.h" +#include "soundman.h" +#include "rtimage.h" +#include "version.h" +#include "extprog.h" + +#ifndef WIN32 +#include +#include +#include +#include +#else +#include +#include "conio.h" +#endif + +extern Options options; + +// stores path to data files +Glib::ustring argv0; +Glib::ustring creditsPath; +Glib::ustring licensePath; +Glib::ustring argv1; +bool simpleEditor; +//Glib::Threads::Thread* mainThread; + +namespace +{ + +// For an unknown reason, Glib::filename_to_utf8 doesn't work on reliably Windows, +// so we're using Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows. +Glib::ustring fname_to_utf8 (const char* fname) +{ +#ifdef WIN32 + + try { + return Glib::locale_to_utf8 (fname); + } catch (Glib::Error&) { + return Glib::convert_with_fallback (fname, "UTF-8", "ISO-8859-1", "?"); + } + +#else + + return Glib::filename_to_utf8 (fname); + +#endif +} + +} + +// This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex +#ifdef WIN32 +static Glib::RecMutex myGdkRecMutex; +#else +static Glib::Threads::RecMutex myGdkRecMutex; +#endif + +static void myGdkLockEnter() +{ + myGdkRecMutex.lock(); +} +static void myGdkLockLeave() +{ + // Automatic gdk_flush for non main tread +#if AUTO_GDK_FLUSH + //if (Glib::Thread::self() != mainThread) { + // gdk_flush(); + //} + +#endif + myGdkRecMutex.unlock(); +} + +/* Process line command options + * Returns + * 0 if process in batch has executed + * 1 to start GUI (with a dir or file option) + * 2 to start GUI because no files found + * -1 if there is an error in parameters + * -2 if an error occurred during processing + * -3 if at least one required procparam file was not found */ +int processLineParams( int argc, char **argv ); + +int main(int argc, char **argv) +{ + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); // to set decimal point to "." + + Glib::init(); // called by Gtk::Main, but this may be important for thread handling, so we call it ourselves now + gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); + gdk_threads_init(); + Gio::init (); + + //mainThread = Glib::Threads::Thread::self(); + +#ifdef BUILD_BUNDLE + char exname[512] = {0}; + Glib::ustring exePath; + // get the path where the rawtherapee executable is stored +#ifdef WIN32 + WCHAR exnameU[512] = {0}; + GetModuleFileNameW (NULL, exnameU, 512); + WideCharToMultiByte(CP_UTF8, 0, exnameU, -1, exname, 512, 0, 0 ); +#else + + if (readlink("/proc/self/exe", exname, 512) < 0) { + strncpy(exname, argv[0], 512); + } + +#endif + exePath = Glib::path_get_dirname(exname); + + // set paths + if (Glib::path_is_absolute(DATA_SEARCH_PATH)) { + argv0 = DATA_SEARCH_PATH; + } else { + argv0 = Glib::build_filename(exePath, DATA_SEARCH_PATH); + } + + if (Glib::path_is_absolute(CREDITS_SEARCH_PATH)) { + creditsPath = CREDITS_SEARCH_PATH; + } else { + creditsPath = Glib::build_filename(exePath, CREDITS_SEARCH_PATH); + } + + if (Glib::path_is_absolute(LICENCE_SEARCH_PATH)) { + licensePath = LICENCE_SEARCH_PATH; + } else { + licensePath = Glib::build_filename(exePath, LICENCE_SEARCH_PATH); + } + +#else + argv0 = DATA_SEARCH_PATH; + creditsPath = CREDITS_SEARCH_PATH; + licensePath = LICENCE_SEARCH_PATH; +#endif + + if (!Options::load ()) { + printf("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!\n"); + return -2; + } + + TIFFSetWarningHandler(nullptr); // avoid annoying message boxes + +#ifndef WIN32 + + // Move the old path to the new one if the new does not exist + if (Glib::file_test(Glib::build_filename(options.rtdir, "cache"), Glib::FILE_TEST_IS_DIR) && !Glib::file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) { + g_rename(Glib::build_filename (options.rtdir, "cache").c_str (), options.cacheBaseDir.c_str ()); + } + +#endif + +#if not RT_CMDLINE + extProgStore->init(); + SoundManager::init(); +#endif + + // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing + std::cout << "RawTherapee, version " << VERSION << std::endl; + if (argc > 1) { + int ret = processLineParams( argc, argv); + + if( ret <= 0 ) { + return ret; + } + } + else { + std::cout << "Terminating without anything to do." << std::endl; + } + + return 0; +} + +void deleteProcParams(std::vector &pparams) +{ + for (unsigned int i = 0; i < pparams.size(); i++) { + pparams[i]->deleteInstance(); + delete pparams[i]; + pparams[i] = NULL; + } + + return; +} + +int processLineParams( int argc, char **argv ) +{ + rtengine::procparams::PartialProfile *rawParams = nullptr, *imgParams = nullptr; + std::vector inputFiles; + Glib::ustring outputPath = ""; + std::vector processingParams; + bool outputDirectory = false; + bool overwriteFiles = false; + bool sideProcParams = false; + bool copyParamsFile = false; + bool skipIfNoSidecar = false; + bool useDefault = false; + unsigned int sideCarFilePos = 0; + int compression = 92; + int subsampling = 3; + int bits = -1; + std::string outputType = ""; + unsigned errors = 0; + + for( int iArg = 1; iArg < argc; iArg++) { + if( argv[iArg][0] == '-' ) { + switch( argv[iArg][1] ) { + case 'O': + copyParamsFile = true; + + case 'o': // outputfile or dir + if( iArg + 1 < argc ) { + iArg++; + outputPath = fname_to_utf8 (argv[iArg]); + + if( Glib::file_test (outputPath, Glib::FILE_TEST_IS_DIR)) { + outputDirectory = true; + } + } + + break; + + case 'p': // processing parameters for all inputs; all set procparams are required, so + + // RT stop if any of them can't be loaded for any reason. + if( iArg + 1 < argc ) { + iArg++; + Glib::ustring fname = fname_to_utf8 (argv[iArg]); + + if (fname.at(0) == '-') { + std::cerr << "Error: filename missing next to the -p switch" << std::endl; + deleteProcParams(processingParams); + return -3; + } + + rtengine::procparams::PartialProfile* currentParams = new rtengine::procparams::PartialProfile(true); + + if (!(currentParams->load ( fname ))) { + processingParams.push_back(currentParams); + } else { + std::cerr << "Error: \"" << fname << "\" not found" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } + + break; + + case 'S': + skipIfNoSidecar = true; + + case 's': // Processing params next to file (file extension appended) + sideProcParams = true; + sideCarFilePos = processingParams.size(); + break; + + case 'd': + useDefault = true; + break; + + case 'Y': + overwriteFiles = true; + break; + + case 'j': + if (strlen(argv[iArg]) > 2 && argv[iArg][2] == 's') { + if (strlen(argv[iArg]) == 3) { + std::cerr << "Error: the -js switch requires a mandatory value!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + + // looking for the subsampling parameter + sscanf(&argv[iArg][3], "%d", &subsampling); + + if (subsampling < 1 || subsampling > 3) { + std::cerr << "Error: the value accompanying the -js switch has to be in the [1-3] range!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } else { + outputType = "jpg"; + sscanf(&argv[iArg][2], "%d", &compression); + + if (compression < 0 || compression > 100) { + std::cerr << "Error: the value accompanying the -j switch has to be in the [0-100] range!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } + + break; + + case 'b': + sscanf(&argv[iArg][2], "%d", &bits); + + if (bits != 8 && bits != 16) { + std::cerr << "Error: specify -b8 for 8-bit or -b16 for 16-bit output." << std::endl; + deleteProcParams(processingParams); + return -3; + } + + break; + + case 't': + outputType = "tif"; + compression = ((argv[iArg][2] != 'z') ? 0 : 1); + break; + + case 'n': + outputType = "png"; + compression = -1; + break; + + case 'c': // MUST be last option + while (iArg + 1 < argc) { + iArg++; + + const auto argument = fname_to_utf8 (argv[iArg]); + + if (Glib::file_test (argument, Glib::FILE_TEST_IS_REGULAR)) { + inputFiles.emplace_back (argument); + continue; + } + + if (Glib::file_test (argument, Glib::FILE_TEST_IS_DIR)) { + + auto dir = Gio::File::create_for_path (argument); + if (!dir || !dir->query_exists()) { + continue; + } + + try { + + auto enumerator = dir->enumerate_children (); + + while (auto file = enumerator->next_file ()) { + + const auto fileName = Glib::build_filename (argument, file->get_name ()); + + if (Glib::file_test (fileName, Glib::FILE_TEST_IS_DIR)) { + continue; + } + + // skip files without extension and sidecar files + auto lastdot = fileName.find_last_of('.'); + if (lastdot == Glib::ustring::npos) { + continue; + } + + if (fileName.substr (lastdot).compare (paramFileExtension) == 0) { + continue; + } + + inputFiles.emplace_back (fileName); + } + + } catch (Glib::Exception&) {} + + continue; + } + + std::cerr << "\"" << argument << "\" is neither a regular file nor a directory." << std::endl; + } + + break; +#ifdef WIN32 + + case 'w': // This case is handled outside this function + break; +#endif + + case 'h': + case '?': + default: { + Glib::ustring pparamsExt = paramFileExtension.substr(1); + std::cout << " An advanced, cross-platform program for developing raw photos." << std::endl; + std::cout << std::endl; + std::cout << " Website: http://www.rawtherapee.com/" << std::endl; + std::cout << " Documentation: http://rawpedia.rawtherapee.com/" << std::endl; + std::cout << " Forum: https://discuss.pixls.us/c/software/rawtherapee" << std::endl; + std::cout << " Code and bug reports: https://github.com/Beep6581/RawTherapee" << std::endl; + std::cout << std::endl; + std::cout << "Symbols:" << std::endl; + std::cout << " indicate parameters you can change." << std::endl; + std::cout << " [Square brackets] mean the parameter is optional." << std::endl; + std::cout << " The pipe symbol | indicates a choice of one or the other." << std::endl; + std::cout << " The dash symbol - denotes a range of possible values from one to the other." << std::endl; + std::cout << std::endl; + std::cout << "Usage:" << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " -c

| Convert files in batch with default parameters." << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " -c | Convert files in batch with your own settings." << std::endl; + std::cout << std::endl; +#ifdef WIN32 + std::cout << " -w Do not open the Windows console" << std::endl; + std::cout << std::endl; +#endif + std::cout << "Options:" << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c " << std::endl; + std::cout << std::endl; + std::cout << " -c Specify one or more input files." << std::endl; + std::cout << " -c must be the last option." << std::endl; + std::cout << " -o | Set output file or folder." << std::endl; + std::cout << " Saves output file alongside input file if -o is not specified." << std::endl; + std::cout << " -O | Set output file or folder and copy " << pparamsExt << " file into it." << std::endl; + std::cout << " Saves output file alongside input file if -O is not specified." << std::endl; + std::cout << " -s Use the existing sidecar file to build the processing parameters," << std::endl; + std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in the same folder." << std::endl; + std::cout << " If the sidecar file does not exist, neutral values will be used." << std::endl; + std::cout << " -S Like -s but skip if the sidecar file does not exist." << std::endl; + std::cout << " -p Specify processing profile to be used for all conversions." << std::endl; + std::cout << " You can specify as many sets of \"-p \" options as you like," << std::endl; + std::cout << " each will be built on top of the previous one, as explained below." << std::endl; + std::cout << " -d Use the default raw or non-raw processing profile as set in" << std::endl; + std::cout << " Preferences > Image Processing > Default Processing Profile" << std::endl; + std::cout << " -j[1-100] Specify output to be JPEG (default, if -t and -n are not set)." << std::endl; + std::cout << " Optionally, specify compression 1-100 (default value: 92)." << std::endl; + std::cout << " -js<1-3> Specify the JPEG chroma subsampling parameter, where:" << std::endl; + std::cout << " 1 = Best compression: 2x2, 1x1, 1x1 (4:2:0)" << std::endl; + std::cout << " Chroma halved vertically and horizontally." << std::endl; + std::cout << " 2 = Balanced (default): 2x1, 1x1, 1x1 (4:2:2)" << std::endl; + std::cout << " Chroma halved horizontally." << std::endl; + std::cout << " 3 = Best quality: 1x1, 1x1, 1x1 (4:4:4)" << std::endl; + std::cout << " No chroma subsampling." << std::endl; + std::cout << " -b<8|16> Specify bit depth per channel (default value: 16 for TIFF, 8 for PNG)." << std::endl; + std::cout << " Only applies to TIFF and PNG output, JPEG is always 8." << std::endl; + std::cout << " -t[z] Specify output to be TIFF." << std::endl; + std::cout << " Uncompressed by default, or deflate compression with 'z'." << std::endl; + std::cout << " -n Specify output to be compressed PNG." << std::endl; + std::cout << " Compression is hard-coded to 6." << std::endl; + std::cout << " -Y Overwrite output if present." << std::endl; + std::cout << std::endl; + std::cout << "Your " << pparamsExt << " files can be incomplete, RawTherapee will build the final values as follows:" << std::endl; + std::cout << " 1- A new processing profile is created using neutral values," << std::endl; + std::cout << " 2- If the \"-d\" option is set, the values are overridden by those found in" << std::endl; + std::cout << " the default raw or non-raw processing profile." << std::endl; + std::cout << " 3- If one or more \"-p\" options are set, the values are overridden by those" << std::endl; + std::cout << " found in these processing profiles." << std::endl; + std::cout << " 4- If the \"-s\" or \"-S\" options are set, the values are finally overridden by those" << std::endl; + std::cout << " found in the sidecar files." << std::endl; + std::cout << " The processing profiles are processed in the order specified on the command line." << std::endl; + return -1; + } + } + } else { + argv1 = fname_to_utf8 (argv[iArg]); + + if( outputDirectory ) { + options.savePathFolder = outputPath; + options.saveUsePathTemplate = false; + } else { + options.saveUsePathTemplate = true; + + if (options.savePathTemplate.empty()) + // If the save path template is empty, we use its default value + { + options.savePathTemplate = "%p1/converted/%f"; + } + } + + if (outputType == "jpg") { + options.saveFormat.format = outputType; + options.saveFormat.jpegQuality = compression; + options.saveFormat.jpegSubSamp = subsampling; + } else if (outputType == "tif") { + options.saveFormat.format = outputType; + } else if (outputType == "png") { + options.saveFormat.format = outputType; + } + + break; + } + } + + if( !argv1.empty() ) { + return 1; + } + + if( inputFiles.empty() ) { + return 2; + } + + if (useDefault) { + rawParams = new rtengine::procparams::PartialProfile(true, true); + Glib::ustring profPath = options.findProfilePath(options.defProfRaw); + + if (options.is_defProfRawMissing() || profPath.empty() || rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension))) { + std::cerr << "Error: default raw processing profile not found" << std::endl; + rawParams->deleteInstance(); + delete rawParams; + deleteProcParams(processingParams); + return -3; + } + + imgParams = new rtengine::procparams::PartialProfile(true); + profPath = options.findProfilePath(options.defProfImg); + + if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension))) { + std::cerr << "Error: default non-raw processing profile not found" << std::endl; + imgParams->deleteInstance(); + delete imgParams; + rawParams->deleteInstance(); + delete rawParams; + deleteProcParams(processingParams); + return -3; + } + } + + for( size_t iFile = 0; iFile < inputFiles.size(); iFile++) { + + // Has to be reinstanciated at each profile to have a ProcParams object with default values + rtengine::procparams::ProcParams currentParams; + + Glib::ustring inputFile = inputFiles[iFile]; + std::cout << "Processing: " << inputFile << std::endl; + + rtengine::InitialImage* ii = nullptr; + rtengine::ProcessingJob* job = nullptr; + int errorCode; + bool isRaw = false; + + Glib::ustring outputFile; + + if( outputType.empty() ) { + outputType = "jpg"; + } + + if( outputPath.empty() ) { + Glib::ustring s = inputFile; + Glib::ustring::size_type ext = s.find_last_of('.'); + outputFile = s.substr(0, ext) + "." + outputType; + } else if( outputDirectory ) { + Glib::ustring s = Glib::path_get_basename( inputFile ); + Glib::ustring::size_type ext = s.find_last_of('.'); + outputFile = outputPath + "/" + s.substr(0, ext) + "." + outputType; + } else { + Glib::ustring s = outputPath; + Glib::ustring::size_type ext = s.find_last_of('.'); + outputFile = s.substr(0, ext) + "." + outputType; + } + + if( inputFile == outputFile) { + std::cerr << "Cannot overwrite: " << inputFile << std::endl; + continue; + } + + if( !overwriteFiles && Glib::file_test( outputFile , Glib::FILE_TEST_EXISTS ) ) { + std::cerr << outputFile << " already exists: use -Y option to overwrite. This image has been skipped." << std::endl; + continue; + } + + // Load the image + isRaw = true; + Glib::ustring ext = getExtension (inputFile); + + if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg" || ext.lowercase() == "tif" || ext.lowercase() == "tiff" || ext.lowercase() == "png") { + isRaw = false; + } + + ii = rtengine::InitialImage::load ( inputFile, isRaw, &errorCode, nullptr ); + + if (!ii) { + errors++; + std::cerr << "Error loading file: " << inputFile << std::endl; + continue; + } + + if (useDefault) { + if (isRaw) { + std::cout << " Merging default raw processing profile" << std::endl; + rawParams->applyTo(¤tParams); + } else { + std::cout << " Merging default non-raw processing profile" << std::endl; + imgParams->applyTo(¤tParams); + } + } + + bool sideCarFound = false; + unsigned int i = 0; + + // Iterate the procparams file list in order to build the final ProcParams + do { + if (sideProcParams && i == sideCarFilePos) { + // using the sidecar file + Glib::ustring sideProcessingParams = inputFile + paramFileExtension; + + // the "load" method don't reset the procparams values anymore, so values found in the procparam file override the one of currentParams + if( !Glib::file_test( sideProcessingParams, Glib::FILE_TEST_EXISTS ) || currentParams.load ( sideProcessingParams )) { + std::cerr << "Warning: sidecar file requested but not found for: " << sideProcessingParams << std::endl; + } else { + sideCarFound = true; + std::cout << " Merging sidecar procparams" << std::endl; + } + } + + if( processingParams.size() > i ) { + std::cout << " Merging procparams #" << i << std::endl; + processingParams[i]->applyTo(¤tParams); + } + + i++; + } while (i < processingParams.size() + (sideProcParams ? 1 : 0)); + + if( sideProcParams && !sideCarFound && skipIfNoSidecar ) { + delete ii; + errors++; + std::cerr << "Error: no sidecar procparams found for: " << inputFile << std::endl; + continue; + } + + job = rtengine::ProcessingJob::create (ii, currentParams); + + if( !job ) { + errors++; + std::cerr << "Error creating processing for: " << inputFile << std::endl; + ii->decreaseRef(); + continue; + } + + // Process image + rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, nullptr, options.tunnelMetaData); + + if( !resultImage ) { + errors++; + std::cerr << "Error processing: " << inputFile << std::endl; + rtengine::ProcessingJob::destroy( job ); + continue; + } + + // save image to disk + if( outputType == "jpg" ) { + errorCode = resultImage->saveAsJPEG( outputFile, compression, subsampling ); + } else if( outputType == "tif" ) { + errorCode = resultImage->saveAsTIFF( outputFile, bits, compression == 0 ); + } else if( outputType == "png" ) { + errorCode = resultImage->saveAsPNG( outputFile, compression, bits ); + } else { + errorCode = resultImage->saveToFile (outputFile); + } + + if(errorCode) { + errors++; + std::cerr << "Error saving to: " << outputFile << std::endl; + } else { + if( copyParamsFile ) { + Glib::ustring outputProcessingParams = outputFile + paramFileExtension; + currentParams.save( outputProcessingParams ); + } + } + + ii->decreaseRef(); + resultImage->free(); + } + + if (imgParams) { + imgParams->deleteInstance(); + delete imgParams; + } + + if (rawParams) { + rawParams->deleteInstance(); + delete rawParams; + } + + deleteProcParams(processingParams); + + return errors > 0 ? -2 : 0; +} From bd492e0ece3de0ab2509b665996ca1b9b4b72132 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 1 Feb 2017 19:35:36 +0100 Subject: [PATCH 078/110] 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 079/110] 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 080/110] 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 081/110] 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 082/110] 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 a04b3eefbaa88b38917d257337d3cc861b3adbad Mon Sep 17 00:00:00 2001 From: Hombre Date: Mon, 13 Feb 2017 23:38:05 +0100 Subject: [PATCH 083/110] Adding rawtherapee-cli.exe, '-q' (quick start mode) added Standard rawtherapee.exe now has almost no command line options left. Use '-h' to see options for each executables. --- CMakeLists.txt | 1 + rtengine/CMakeLists.txt | 2 +- rtengine/dcp.cc | 21 +- rtengine/dcp.h | 4 +- rtengine/iccstore.cc | 12 +- rtengine/iccstore.h | 2 +- rtengine/icons.cc | 120 ++++++++++ rtengine/icons.h | 33 +++ rtengine/init.cc | 5 +- rtengine/rawimagesource.cc | 3 + rtengine/rtengine.h | 5 +- rtgui/CMakeLists.txt | 34 ++- rtgui/edit.cc | 12 +- rtgui/edit.h | 2 - rtgui/editwindow.cc | 3 +- rtgui/guiutils.cc | 39 +--- rtgui/guiutils.h | 6 +- rtgui/main-cli.cc | 135 ++++++++---- rtgui/main.cc | 441 +------------------------------------ rtgui/options.cc | 4 +- rtgui/options.h | 2 +- rtgui/pathutils.cc | 48 ++++ rtgui/pathutils.h | 34 +++ rtgui/preferences.cc | 5 +- rtgui/rtimage.cc | 100 +-------- rtgui/rtimage.h | 3 - rtgui/rtwindow.cc | 3 +- 27 files changed, 436 insertions(+), 643 deletions(-) create mode 100644 rtengine/icons.cc create mode 100644 rtengine/icons.h create mode 100644 rtgui/pathutils.cc create mode 100644 rtgui/pathutils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ee54705f6..eed53e527 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ pkg_check_modules (GTK REQUIRED gtk+-3.0>=3.16) pkg_check_modules (GLIB2 REQUIRED glib-2.0>=2.44) pkg_check_modules (GLIBMM REQUIRED glibmm-2.4>=2.44) pkg_check_modules (GTKMM REQUIRED gtkmm-3.0>=3.16) +pkg_check_modules (CAIROMM REQUIRED cairomm-1.0) pkg_check_modules (GIO REQUIRED gio-2.0>=2.44) pkg_check_modules (GIOMM REQUIRED giomm-2.4>=2.44) pkg_check_modules (GTHREAD REQUIRED gthread-2.0>=2.44) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 477ccecae..eb9abe828 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -13,7 +13,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc fast_demo.cc amaze_demosaic_RT.cc CA_correct_RT.cc cfa_linedn_RT.cc green_equil_RT.cc hilite_recon.cc expo_before_b.cc stdimagesource.cc myfile.cc iccjpeg.cc improccoordinator.cc pipettebuffer.cc coord.cc processingjob.cc rtthumbnail.cc utils.cc labimage.cc slicer.cc cieimage.cc - iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc ipvibrance.cc + iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc ipvibrance.cc icons.cc imagedimensions.cc jpeg_ijg/jpeg_memsrc.cc jdatasrc.cc iimage.cc EdgePreservingDecomposition.cc cplx_wavelet_dec.cc FTblockDN.cc PF_correct_RT.cc previewimage.cc ipwavelet.cc diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index a597fa8db..86e348c75 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -406,6 +406,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : has_tone_curve(false), has_baseline_exposure_offset(false), will_interpolate(false), + valid(false), baseline_exposure_offset(0.0) { constexpr int tiff_float_size = 4; @@ -691,6 +692,11 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : FILE* const file = g_fopen(filename.c_str(), "rb"); + if (file == nullptr) { + printf ("Unable to load DCP profile '%s' !", filename.c_str()); + return; + } + std::unique_ptr tagDir(ExifManager::parseTIFF(file, false)); Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1)); @@ -738,6 +744,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : if (!tag) { std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; + fclose(file); return; } @@ -935,6 +942,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : if (file) { fclose(file); } + + valid = true; } DCPProfile::~DCPProfile() @@ -1683,13 +1692,18 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vectorisValid()) { // Add profile profile_cache[filename] = res; + if (options.rtSettings.verbose) { + printf("DCP profile '%s' loaded from disk\n", filename.c_str()); + } return res; } diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 8b781ce6b..215137ac8 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -75,6 +75,7 @@ public: bool getHasBaselineExposureOffset() const; Illuminants getIlluminants() const; + bool isValid(); void apply( Imagefloat* img, @@ -130,6 +131,7 @@ private: bool has_tone_curve; bool has_baseline_exposure_offset; bool will_interpolate; + bool valid; Matrix forward_matrix_1; Matrix forward_matrix_2; double temperature_1; @@ -152,7 +154,7 @@ class DCPStore final : public: static DCPStore* getInstance(); - void init(const Glib::ustring& rt_profile_dir); + void init(const Glib::ustring& rt_profile_dir, bool loadAll = true); bool isValidDCPFileName(const Glib::ustring& filename) const; diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 16ae455b6..2898f48c8 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -767,7 +767,7 @@ uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const } // Reads all profiles from the given profiles dir -void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir) +void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) { MyMutex::MyLock lock (mutex_); @@ -776,15 +776,19 @@ void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCD profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); - loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false); + if (loadAll) { + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false); + } // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); + if (loadAll) { + loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); + } } // Determine the first monitor default profile of operating system, if selected diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 58ddfdbc9..ae4026b28 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -92,7 +92,7 @@ public: static ICCStore* getInstance (); - void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); + void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir, bool loadAll); static void getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga); static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); diff --git a/rtengine/icons.cc b/rtengine/icons.cc new file mode 100644 index 000000000..2c5075007 --- /dev/null +++ b/rtengine/icons.cc @@ -0,0 +1,120 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2011 Jean-Christophe FRISCH + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "icons.h" + +#include + +namespace rtengine +{ + +std::vector imagePaths; + +bool loadIconSet(const Glib::ustring& iconSet) +{ + try { + + Glib::KeyFile keyFile; + keyFile.load_from_file (iconSet); + + auto iconSetDir = keyFile.get_string ("General", "Iconset"); + + if (!iconSetDir.empty ()) { + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "actions")); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir)); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "devices")); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "places")); + } + + iconSetDir = keyFile.get_string ("General", "FallbackIconset"); + + if (!iconSetDir.empty ()) { + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "actions")); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir)); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "devices")); + imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "places")); + } + + return true; + + } catch (const Glib::Exception& exception) { + + if (options.rtSettings.verbose) { + std::cerr << "Failed to load icon set \"" << iconSet << "\": " << exception.what() << std::endl; + } + + return false; + + } +} + +Glib::ustring findIconAbsolutePath (const Glib::ustring& iconName) +{ + try { + + for (const auto& imagePath : imagePaths) { + const auto iconPath = Glib::build_filename(imagePath, iconName); + + if (Glib::file_test(iconPath, Glib::FILE_TEST_IS_REGULAR)) { + return iconPath; + } + } + + } catch(const Glib::Exception&) {} + + if (options.rtSettings.verbose) { + std::cerr << "Icon \"" << iconName << "\" could not be found!" << std::endl; + } + + return Glib::ustring(); +} + +void setPaths (const Options& options) +{ + // TODO: Forcing the Dark theme, so reading the icon set files is useless for now... + + /*Glib::ustring iconSet; + + // Either use the system icon set or the one specified in the options. + if (options.useSystemTheme) { + iconSet = Glib::build_filename (argv0, "themes", "system.iconset"); + } else { + iconSet = Glib::build_filename (argv0, "themes", options.theme + ".iconset"); + } + + imagePaths.clear (); + + if (!loadIconSet (iconSet)) { + // If the preferred icon set is unavailable, fall back to the default icon set. + loadIconSet (Glib::build_filename (argv0, "themes", "Default.iconset")); + }*/ + + imagePaths.clear (); + + imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark")); + imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "actions")); + imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "devices")); + imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "places")); + + // The images folder is the second fallback solution. + imagePaths.push_back (Glib::build_filename(argv0, "images")); +} + +} diff --git a/rtengine/icons.h b/rtengine/icons.h new file mode 100644 index 000000000..9f6654a9c --- /dev/null +++ b/rtengine/icons.h @@ -0,0 +1,33 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _ICONS_ +#define _ICONS_ + +#include +#include "../rtgui/options.h" + +namespace rtengine +{ + +Glib::ustring findIconAbsolutePath (const Glib::ustring& iconName); +void setPaths (const Options& options); + +} + +#endif diff --git a/rtengine/init.cc b/rtengine/init.cc index 27edd976b..66ff5baf6 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -37,15 +37,14 @@ const Settings* settings; MyMutex* lcmsMutex = nullptr; -int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir) +int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir, bool loadAll) { settings = s; - iccStore->init (s->iccDirectory, baseDir + "/iccprofiles"); + iccStore->init (s->iccDirectory, baseDir + "/iccprofiles", loadAll); iccStore->findDefaultMonitorProfile(); DCPStore::getInstance()->init (baseDir + "/dcpprofiles"); CameraConstantsStore::getInstance ()->init (baseDir, userSettingsDir); - profileStore.init (); ProcParams::init (); Color::init (); PerceptualToneCurve::init (); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 049c509f5..6dd71a7e3 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -894,6 +894,9 @@ DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp & findInputProfile(cmp.input, nullptr, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); if (dcpProf == nullptr) { + if (settings->verbose) { + printf("Can't load DCP profile '%s'!\n", cmp.input.c_str()); + } return nullptr; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 61c779fb7..43fcbf06f 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -435,8 +435,9 @@ public: * @brief Initializes the RT engine * @param s is a struct of basic settings * @param baseDir base directory of RT's installation dir - * @param userSettingsDir RT's base directory in the user's settings dir */ -int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir); + * @param userSettingsDir RT's base directory in the user's settings dir + * @param loadAll if false, don't load the various dependencies (profiles, HALDClut files, ...), they'll be loaded from disk each time they'll be used (launching time improvement) */ +int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir, bool loadAll = true); /** Cleanup the RT engine (static variables) */ void cleanup (); diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index ad896041f..e7c1c6ffa 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -1,5 +1,10 @@ +# common source files for both CLI and non-CLI execautables +set (CLISOURCEFILES + paramsedited.cc options.cc multilangmgr.cc pathutils.cc edit.cc threadutils.cc + #cachemanager.cc cacheimagedata.cc + main-cli.cc) -set (BASESOURCEFILES +set (NONCLISOURCEFILES editwindow.cc batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc previewmodepanel.cc filterpanel.cc exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc @@ -21,7 +26,7 @@ set (BASESOURCEFILES preferences.cc profilepanel.cc saveasdlg.cc saveformatpanel.cc soundman.cc splash.cc thumbnail.cc tonecurve.cc toolbar.cc - guiutils.cc threadutils.cc zoompanel.cc toolpanelcoord.cc + pathutils.cc guiutils.cc threadutils.cc zoompanel.cc toolpanelcoord.cc thumbbrowserentrybase.cc batchqueueentry.cc batchqueue.cc lwbutton.cc lwbuttonset.cc batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc @@ -41,7 +46,8 @@ if (APPLE) set (EXTRA_INCDIR ${EXTRA_INCDIR} ${MacIntegration_INCLUDE_DIRS}) endif (APPLE) if (WIN32) - set (EXTRA_SRC windirmonitor.cc myicon.rc) + set (EXTRA_SRC_CLI myicon.rc) + set (EXTRA_SRC_NONCLI myicon.rc windirmonitor.cc) set (EXTRA_LIB_RTGUI winmm) include_directories (${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS}) @@ -61,14 +67,26 @@ endif (WIN32) # create config.h which defines where data are stored configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h") -add_executable (rth ${EXTRA_SRC} ${BASESOURCEFILES}) -add_dependencies (rth AboutFile) +# create new executables targets +add_executable (rth ${EXTRA_SRC_NONCLI} ${NONCLISOURCEFILES}) +add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) +# add dependencies to executables targets +add_dependencies (rth AboutFile) +add_dependencies (rth-cli AboutFile) + +# set executables targets properties, i.e. output filename and compile flags set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee) -#target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} -# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES}) +set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) + +# add linked libraries dependencies to executables targets target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${CANBERRA-GTK_LIBRARIES} ${EXTRA_LIB_RTGUI}) -install (TARGETS rth DESTINATION ${BINDIR}) +target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} + ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} + ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) +# install executables +install (TARGETS rth DESTINATION ${BINDIR}) +install (TARGETS rth-cli DESTINATION ${BINDIR}) diff --git a/rtgui/edit.cc b/rtgui/edit.cc index 58d856bb5..2f9b5eeef 100644 --- a/rtgui/edit.cc +++ b/rtgui/edit.cc @@ -18,7 +18,7 @@ */ #include "edit.h" -#include "rtimage.h" +#include "../rtengine/icons.h" ObjectMOBuffer::ObjectMOBuffer(EditDataProvider *dataProvider) : objectMap(nullptr), objectMode(OM_255), dataProvider(dataProvider) {} @@ -834,23 +834,23 @@ OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustri Glib::ustring draggedImage, Glib::ustring insensitiveImage, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) { if (!normalImage.empty()) { - normalImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(normalImage) ); + normalImg = Cairo::ImageSurface::create_from_png( rtengine::findIconAbsolutePath(normalImage) ); } if (!prelightImage.empty()) { - prelightImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(prelightImage) ); + prelightImg = Cairo::ImageSurface::create_from_png( rtengine::findIconAbsolutePath(prelightImage) ); } if (!activeImage.empty()) { - activeImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(activeImage) ); + activeImg = Cairo::ImageSurface::create_from_png( rtengine::findIconAbsolutePath(activeImage) ); } if (!draggedImage.empty()) { - draggedImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(draggedImage) ); + draggedImg = Cairo::ImageSurface::create_from_png( rtengine::findIconAbsolutePath(draggedImage) ); } if (!insensitiveImage.empty()) { - insensitiveImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(insensitiveImage) ); + insensitiveImg = Cairo::ImageSurface::create_from_png( rtengine::findIconAbsolutePath(insensitiveImage) ); } } diff --git a/rtgui/edit.h b/rtgui/edit.h index e28a6acec..eeeca694d 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -409,10 +409,8 @@ private: Cairo::RefPtr draggedImg; Cairo::RefPtr insensitiveImg; - static void setPaths(Options &opt); static void updateImages(); void changeImage(Glib::ustring &newImage); - static Glib::ustring findIconAbsolutePath(const Glib::ustring &iconFName); void drawImage (const Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); void drawMOImage (const Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); void drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H); diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index 355c22876..1d08ac783 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -23,6 +23,7 @@ #include #include "rtimage.h" #include "threadutils.h" +#include "../rtengine/icons.h" // Check if the system has more than one display and option is set bool EditWindow::isMultiDisplayEnabled() @@ -59,7 +60,7 @@ EditWindow::EditWindow (RTWindow* p) : parent(p) , isFullscreen(false) { Glib::ustring fName = "rt-logo-tiny.png"; - Glib::ustring fullPath = RTImage::findIconAbsolutePath(fName); + Glib::ustring fullPath = rtengine::findIconAbsolutePath(fName); try { set_default_icon_from_file (fullPath); diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 43bfc11b0..e637314cc 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -22,6 +22,7 @@ #include "options.h" #include "../rtengine/rt_math.h" #include "../rtengine/utils.h" +#include "../rtengine/icons.h" #include "rtimage.h" #include "multilangmgr.h" @@ -169,34 +170,6 @@ void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, } } -Glib::ustring removeExtension (const Glib::ustring& filename) -{ - - Glib::ustring bname = Glib::path_get_basename(filename); - size_t lastdot = bname.find_last_of ('.'); - size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); - - if (lastdot != bname.npos && (lastwhitespace == bname.npos || lastdot > lastwhitespace)) { - return filename.substr (0, filename.size() - (bname.size() - lastdot)); - } else { - return filename; - } -} - -Glib::ustring getExtension (const Glib::ustring& filename) -{ - - Glib::ustring bname = Glib::path_get_basename(filename); - size_t lastdot = bname.find_last_of ('.'); - size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); - - if (lastdot != bname.npos && (lastwhitespace == bname.npos || lastdot > lastwhitespace)) { - return filename.substr (filename.size() - (bname.size() - lastdot) + 1, filename.npos); - } else { - return ""; - } -} - bool confirmOverwrite (Gtk::Window& parent, const std::string& filename) { bool safe = true; @@ -542,11 +515,11 @@ void ExpanderBox::hideBox() void MyExpander::init() { - inconsistentPBuf = Gdk::Pixbuf::create_from_file(RTImage::findIconAbsolutePath("expanderInconsistent.png")); - enabledPBuf = Gdk::Pixbuf::create_from_file(RTImage::findIconAbsolutePath("expanderEnabled.png")); - disabledPBuf = Gdk::Pixbuf::create_from_file(RTImage::findIconAbsolutePath("expanderDisabled.png")); - openedPBuf = Gdk::Pixbuf::create_from_file(RTImage::findIconAbsolutePath("expanderOpened.png")); - closedPBuf = Gdk::Pixbuf::create_from_file(RTImage::findIconAbsolutePath("expanderClosed.png")); + inconsistentPBuf = Gdk::Pixbuf::create_from_file(rtengine::findIconAbsolutePath("expanderInconsistent.png")); + enabledPBuf = Gdk::Pixbuf::create_from_file(rtengine::findIconAbsolutePath("expanderEnabled.png")); + disabledPBuf = Gdk::Pixbuf::create_from_file(rtengine::findIconAbsolutePath("expanderDisabled.png")); + openedPBuf = Gdk::Pixbuf::create_from_file(rtengine::findIconAbsolutePath("expanderOpened.png")); + closedPBuf = Gdk::Pixbuf::create_from_file(rtengine::findIconAbsolutePath("expanderClosed.png")); } MyExpander::MyExpander(bool useEnabled, Gtk::Widget* titleWidget) : diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index e5919c9e4..5005b6f3c 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -27,11 +27,13 @@ #include #include +// for convenience... +#include "pathutils.h" + + Glib::ustring escapeHtmlChars(const Glib::ustring &src); bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference = true); void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); -Glib::ustring removeExtension (const Glib::ustring& filename); -Glib::ustring getExtension (const Glib::ustring& filename); bool confirmOverwrite (Gtk::Window& parent, const std::string& filename); void writeFailed (Gtk::Window& parent, const std::string& filename); void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams, bool drawGuide = true, bool useBgColor = true, bool fullImageVisible = true); diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 33627e514..1e35e00c6 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -33,6 +33,7 @@ #include #include #include "options.h" +#include "../rtengine/icons.h" #include "soundman.h" #include "rtimage.h" #include "version.h" @@ -82,29 +83,6 @@ Glib::ustring fname_to_utf8 (const char* fname) } -// This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex -#ifdef WIN32 -static Glib::RecMutex myGdkRecMutex; -#else -static Glib::Threads::RecMutex myGdkRecMutex; -#endif - -static void myGdkLockEnter() -{ - myGdkRecMutex.lock(); -} -static void myGdkLockLeave() -{ - // Automatic gdk_flush for non main tread -#if AUTO_GDK_FLUSH - //if (Glib::Thread::self() != mainThread) { - // gdk_flush(); - //} - -#endif - myGdkRecMutex.unlock(); -} - /* Process line command options * Returns * 0 if process in batch has executed @@ -115,14 +93,13 @@ static void myGdkLockLeave() * -3 if at least one required procparam file was not found */ int processLineParams( int argc, char **argv ); +bool dontLoadCache( int argc, char **argv ); + int main(int argc, char **argv) { setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); // to set decimal point to "." - Glib::init(); // called by Gtk::Main, but this may be important for thread handling, so we call it ourselves now - gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); - gdk_threads_init(); Gio::init (); //mainThread = Glib::Threads::Thread::self(); @@ -169,11 +146,15 @@ int main(int argc, char **argv) licensePath = LICENCE_SEARCH_PATH; #endif - if (!Options::load ()) { + bool quickstart = dontLoadCache(argc, argv); + + if (!Options::load (quickstart)) { printf("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!\n"); return -2; } + rtengine::setPaths(options); + TIFFSetWarningHandler(nullptr); // avoid annoying message boxes #ifndef WIN32 @@ -185,25 +166,87 @@ int main(int argc, char **argv) #endif -#if not RT_CMDLINE - extProgStore->init(); - SoundManager::init(); +#ifdef WIN32 + bool consoleOpened = false; + + if (argc > 1 || options.rtSettings.verbose) { + if (options.rtSettings.verbose || ( !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_EXISTS ) && !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_IS_DIR))) { + bool stdoutRedirectedtoFile = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == 0x0001); + bool stderrRedirectedtoFile = (GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == 0x0001); + + // no console, if stdout and stderr both are redirected to file + if( !(stdoutRedirectedtoFile && stderrRedirectedtoFile)) { + // check if parameter -w was passed. + // We have to do that in this step, because it controls whether to open a console to show the output of following steps + bool Console = true; + + for(int i = 1; i < argc; i++) + if(!strcmp(argv[i], "-w")) { + Console = false; + break; + } + + if(Console) { + AllocConsole(); + AttachConsole( GetCurrentProcessId() ) ; + // Don't allow CTRL-C in console to terminate RT + SetConsoleCtrlHandler( NULL, true ); + // Set title of console + char consoletitle[128]; + sprintf(consoletitle, "RawTherapee %s Console", VERSION); + SetConsoleTitle(consoletitle); + // increase size of screen buffer + COORD c; + c.X = 200; + c.Y = 1000; + SetConsoleScreenBufferSize( GetStdHandle( STD_OUTPUT_HANDLE ), c ); + // Disable console-Cursor + CONSOLE_CURSOR_INFO cursorInfo; + cursorInfo.dwSize = 100; + cursorInfo.bVisible = false; + SetConsoleCursorInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &cursorInfo ); + + if(!stdoutRedirectedtoFile) { + freopen( "CON", "w", stdout ) ; + } + + if(!stderrRedirectedtoFile) { + freopen( "CON", "w", stderr ) ; + } + + freopen( "CON", "r", stdin ) ; + + consoleOpened = true; + + // printing RT's version in every case, particularly useful for the 'verbose' mode, but also for the batch processing + std::cout << "RawTherapee, version " << VERSION << ", command line" << std::endl; + std::cout << "WARNING: closing this window will close RawTherapee!" << std::endl << std::endl; + } + } + } + } #endif - // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing - std::cout << "RawTherapee, version " << VERSION << std::endl; - if (argc > 1) { - int ret = processLineParams( argc, argv); + int ret = 0; - if( ret <= 0 ) { - return ret; - } + // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing + std::cout << "RawTherapee, version " << VERSION << ", command line" << std::endl; + if (argc > 1) { + ret = processLineParams(argc, argv); } else { std::cout << "Terminating without anything to do." << std::endl; } - return 0; +#ifdef WIN32 + if(consoleOpened) { + printf("Press any key to exit RawTherapee\n"); + FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); + getch(); + } +#endif + + return ret; } void deleteProcParams(std::vector &pparams) @@ -217,6 +260,18 @@ void deleteProcParams(std::vector &pparam return; } + +bool dontLoadCache( int argc, char **argv ) +{ + for( int iArg = 1; iArg < argc; iArg++) { + if( argv[iArg][0] == '-' && argv[iArg][1] == 'q' ) { + return true; + } + } + + return false; +} + int processLineParams( int argc, char **argv ) { rtengine::procparams::PartialProfile *rawParams = nullptr, *imgParams = nullptr; @@ -292,6 +347,9 @@ int processLineParams( int argc, char **argv ) useDefault = true; break; + case 'q': + break; + case 'Y': overwriteFiles = true; break; @@ -432,6 +490,7 @@ int processLineParams( int argc, char **argv ) std::cout << "Options:" << std::endl; std::cout << " " << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c " << std::endl; std::cout << std::endl; + std::cout << " -q Quick Start mode : do not load cached files to speedup start time." << std::endl; std::cout << " -c Specify one or more input files." << std::endl; std::cout << " -c must be the last option." << std::endl; std::cout << " -o | Set output file or folder." << std::endl; diff --git a/rtgui/main.cc b/rtgui/main.cc index f27a0f32f..689d108c2 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -28,6 +28,7 @@ #include #include #include +#include "../rtengine/icons.h" #include "rtwindow.h" #include #include @@ -179,6 +180,7 @@ int main(int argc, char **argv) return -2; } + profileStore.init (); extProgStore->init(); SoundManager::init(); @@ -300,8 +302,8 @@ int main(int argc, char **argv) Glib::RefPtr defaultIconTheme = Gtk::IconTheme::get_default(); defaultIconTheme->append_search_path(icon_path); - RTImage::setPaths(options); - MyExpander::init(); // has to stay AFTER RTImage::setPaths + rtengine::setPaths(options); + MyExpander::init(); // has to stay AFTER rtengine::setPaths // ------- loading theme files @@ -410,185 +412,11 @@ void deleteProcParams(std::vector &pparam int processLineParams( int argc, char **argv ) { - rtengine::procparams::PartialProfile *rawParams = nullptr, *imgParams = nullptr; - std::vector inputFiles; - Glib::ustring outputPath = ""; - std::vector processingParams; - bool outputDirectory = false; - bool overwriteFiles = false; - bool sideProcParams = false; - bool copyParamsFile = false; - bool skipIfNoSidecar = false; - bool useDefault = false; - unsigned int sideCarFilePos = 0; - int compression = 92; - int subsampling = 3; - int bits = -1; - std::string outputType = ""; unsigned errors = 0; for( int iArg = 1; iArg < argc; iArg++) { if( argv[iArg][0] == '-' ) { switch( argv[iArg][1] ) { - case 'O': - copyParamsFile = true; - - case 'o': // outputfile or dir - if( iArg + 1 < argc ) { - iArg++; - outputPath = fname_to_utf8 (argv[iArg]); - - if( Glib::file_test (outputPath, Glib::FILE_TEST_IS_DIR)) { - outputDirectory = true; - } - } - - break; - - case 'p': // processing parameters for all inputs; all set procparams are required, so - - // RT stop if any of them can't be loaded for any reason. - if( iArg + 1 < argc ) { - iArg++; - Glib::ustring fname = fname_to_utf8 (argv[iArg]); - - if (fname.at(0) == '-') { - std::cerr << "Error: filename missing next to the -p switch" << std::endl; - deleteProcParams(processingParams); - return -3; - } - - rtengine::procparams::PartialProfile* currentParams = new rtengine::procparams::PartialProfile(true); - - if (!(currentParams->load ( fname ))) { - processingParams.push_back(currentParams); - } else { - std::cerr << "Error: \"" << fname << "\" not found" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } - - break; - - case 'S': - skipIfNoSidecar = true; - - case 's': // Processing params next to file (file extension appended) - sideProcParams = true; - sideCarFilePos = processingParams.size(); - break; - - case 'd': - useDefault = true; - break; - - case 'Y': - overwriteFiles = true; - break; - - case 'j': - if (strlen(argv[iArg]) > 2 && argv[iArg][2] == 's') { - if (strlen(argv[iArg]) == 3) { - std::cerr << "Error: the -js switch requires a mandatory value!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - - // looking for the subsampling parameter - sscanf(&argv[iArg][3], "%d", &subsampling); - - if (subsampling < 1 || subsampling > 3) { - std::cerr << "Error: the value accompanying the -js switch has to be in the [1-3] range!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } else { - outputType = "jpg"; - sscanf(&argv[iArg][2], "%d", &compression); - - if (compression < 0 || compression > 100) { - std::cerr << "Error: the value accompanying the -j switch has to be in the [0-100] range!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } - - break; - - case 'b': - sscanf(&argv[iArg][2], "%d", &bits); - - if (bits != 8 && bits != 16) { - std::cerr << "Error: specify -b8 for 8-bit or -b16 for 16-bit output." << std::endl; - deleteProcParams(processingParams); - return -3; - } - - break; - - case 't': - outputType = "tif"; - compression = ((argv[iArg][2] != 'z') ? 0 : 1); - break; - - case 'n': - outputType = "png"; - compression = -1; - break; - - case 'c': // MUST be last option - while (iArg + 1 < argc) { - iArg++; - - const auto argument = fname_to_utf8 (argv[iArg]); - - if (Glib::file_test (argument, Glib::FILE_TEST_IS_REGULAR)) { - inputFiles.emplace_back (argument); - continue; - } - - if (Glib::file_test (argument, Glib::FILE_TEST_IS_DIR)) { - - auto dir = Gio::File::create_for_path (argument); - if (!dir || !dir->query_exists()) { - continue; - } - - try { - - auto enumerator = dir->enumerate_children (); - - while (auto file = enumerator->next_file ()) { - - const auto fileName = Glib::build_filename (argument, file->get_name ()); - - if (Glib::file_test (fileName, Glib::FILE_TEST_IS_DIR)) { - continue; - } - - // skip files without extension and sidecar files - auto lastdot = fileName.find_last_of('.'); - if (lastdot == Glib::ustring::npos) { - continue; - } - - if (fileName.substr (lastdot).compare (paramFileExtension) == 0) { - continue; - } - - inputFiles.emplace_back (fileName); - } - - } catch (Glib::Exception&) {} - - continue; - } - - std::cerr << "\"" << argument << "\" is neither a regular file nor a directory." << std::endl; - } - - break; #ifdef WIN32 case 'w': // This case is handled outside this function @@ -615,86 +443,17 @@ int processLineParams( int argc, char **argv ) std::cout << "Usage:" << std::endl; std::cout << " " << Glib::path_get_basename(argv[0]) << " Start File Browser inside folder." << std::endl; std::cout << " " << Glib::path_get_basename(argv[0]) << " Start Image Editor with file." << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " -c | Convert files in batch with default parameters." << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " -c | Convert files in batch with your own settings." << std::endl; std::cout << std::endl; + std::cout << "Options:" << std::endl; #ifdef WIN32 std::cout << " -w Do not open the Windows console" << std::endl; - std::cout << std::endl; #endif - std::cout << "Options:" << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p [-p ...] ] [-d] [ -j[1-100] [-js<1-3>] | [-b<8|16>] [-t[z] | [-n]] ] [-Y] -c " << std::endl; - std::cout << std::endl; - std::cout << " -c Specify one or more input files." << std::endl; - std::cout << " -c must be the last option." << std::endl; - std::cout << " -o | Set output file or folder." << std::endl; - std::cout << " Saves output file alongside input file if -o is not specified." << std::endl; - std::cout << " -O | Set output file or folder and copy " << pparamsExt << " file into it." << std::endl; - std::cout << " Saves output file alongside input file if -O is not specified." << std::endl; - std::cout << " -s Use the existing sidecar file to build the processing parameters," << std::endl; - std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in the same folder." << std::endl; - std::cout << " If the sidecar file does not exist, neutral values will be used." << std::endl; - std::cout << " -S Like -s but skip if the sidecar file does not exist." << std::endl; - std::cout << " -p Specify processing profile to be used for all conversions." << std::endl; - std::cout << " You can specify as many sets of \"-p \" options as you like," << std::endl; - std::cout << " each will be built on top of the previous one, as explained below." << std::endl; - std::cout << " -d Use the default raw or non-raw processing profile as set in" << std::endl; - std::cout << " Preferences > Image Processing > Default Processing Profile" << std::endl; - std::cout << " -j[1-100] Specify output to be JPEG (default, if -t and -n are not set)." << std::endl; - std::cout << " Optionally, specify compression 1-100 (default value: 92)." << std::endl; - std::cout << " -js<1-3> Specify the JPEG chroma subsampling parameter, where:" << std::endl; - std::cout << " 1 = Best compression: 2x2, 1x1, 1x1 (4:2:0)" << std::endl; - std::cout << " Chroma halved vertically and horizontally." << std::endl; - std::cout << " 2 = Balanced (default): 2x1, 1x1, 1x1 (4:2:2)" << std::endl; - std::cout << " Chroma halved horizontally." << std::endl; - std::cout << " 3 = Best quality: 1x1, 1x1, 1x1 (4:4:4)" << std::endl; - std::cout << " No chroma subsampling." << std::endl; - std::cout << " -b<8|16> Specify bit depth per channel (default value: 16 for TIFF, 8 for PNG)." << std::endl; - std::cout << " Only applies to TIFF and PNG output, JPEG is always 8." << std::endl; - std::cout << " -t[z] Specify output to be TIFF." << std::endl; - std::cout << " Uncompressed by default, or deflate compression with 'z'." << std::endl; - std::cout << " -n Specify output to be compressed PNG." << std::endl; - std::cout << " Compression is hard-coded to 6." << std::endl; - std::cout << " -Y Overwrite output if present." << std::endl; - std::cout << std::endl; - std::cout << "Your " << pparamsExt << " files can be incomplete, RawTherapee will build the final values as follows:" << std::endl; - std::cout << " 1- A new processing profile is created using neutral values," << std::endl; - std::cout << " 2- If the \"-d\" option is set, the values are overridden by those found in" << std::endl; - std::cout << " the default raw or non-raw processing profile." << std::endl; - std::cout << " 3- If one or more \"-p\" options are set, the values are overridden by those" << std::endl; - std::cout << " found in these processing profiles." << std::endl; - std::cout << " 4- If the \"-s\" or \"-S\" options are set, the values are finally overridden by those" << std::endl; - std::cout << " found in the sidecar files." << std::endl; - std::cout << " The processing profiles are processed in the order specified on the command line." << std::endl; + std::cout << " -h -? Display this help message" << std::endl; return -1; } } } else { argv1 = fname_to_utf8 (argv[iArg]); - - if( outputDirectory ) { - options.savePathFolder = outputPath; - options.saveUsePathTemplate = false; - } else { - options.saveUsePathTemplate = true; - - if (options.savePathTemplate.empty()) - // If the save path template is empty, we use its default value - { - options.savePathTemplate = "%p1/converted/%f"; - } - } - - if (outputType == "jpg") { - options.saveFormat.format = outputType; - options.saveFormat.jpegQuality = compression; - options.saveFormat.jpegSubSamp = subsampling; - } else if (outputType == "tif") { - options.saveFormat.format = outputType; - } else if (outputType == "png") { - options.saveFormat.format = outputType; - } - break; } } @@ -703,193 +462,5 @@ int processLineParams( int argc, char **argv ) return 1; } - if( inputFiles.empty() ) { - return 2; - } - - if (useDefault) { - rawParams = new rtengine::procparams::PartialProfile(true, true); - Glib::ustring profPath = options.findProfilePath(options.defProfRaw); - - if (options.is_defProfRawMissing() || profPath.empty() || rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension))) { - std::cerr << "Error: default raw processing profile not found" << std::endl; - rawParams->deleteInstance(); - delete rawParams; - deleteProcParams(processingParams); - return -3; - } - - imgParams = new rtengine::procparams::PartialProfile(true); - profPath = options.findProfilePath(options.defProfImg); - - if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension))) { - std::cerr << "Error: default non-raw processing profile not found" << std::endl; - imgParams->deleteInstance(); - delete imgParams; - rawParams->deleteInstance(); - delete rawParams; - deleteProcParams(processingParams); - return -3; - } - } - - for( size_t iFile = 0; iFile < inputFiles.size(); iFile++) { - - // Has to be reinstanciated at each profile to have a ProcParams object with default values - rtengine::procparams::ProcParams currentParams; - - Glib::ustring inputFile = inputFiles[iFile]; - std::cout << "Processing: " << inputFile << std::endl; - - rtengine::InitialImage* ii = nullptr; - rtengine::ProcessingJob* job = nullptr; - int errorCode; - bool isRaw = false; - - Glib::ustring outputFile; - - if( outputType.empty() ) { - outputType = "jpg"; - } - - if( outputPath.empty() ) { - Glib::ustring s = inputFile; - Glib::ustring::size_type ext = s.find_last_of('.'); - outputFile = s.substr(0, ext) + "." + outputType; - } else if( outputDirectory ) { - Glib::ustring s = Glib::path_get_basename( inputFile ); - Glib::ustring::size_type ext = s.find_last_of('.'); - outputFile = outputPath + "/" + s.substr(0, ext) + "." + outputType; - } else { - Glib::ustring s = outputPath; - Glib::ustring::size_type ext = s.find_last_of('.'); - outputFile = s.substr(0, ext) + "." + outputType; - } - - if( inputFile == outputFile) { - std::cerr << "Cannot overwrite: " << inputFile << std::endl; - continue; - } - - if( !overwriteFiles && Glib::file_test( outputFile , Glib::FILE_TEST_EXISTS ) ) { - std::cerr << outputFile << " already exists: use -Y option to overwrite. This image has been skipped." << std::endl; - continue; - } - - // Load the image - isRaw = true; - Glib::ustring ext = getExtension (inputFile); - - if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg" || ext.lowercase() == "tif" || ext.lowercase() == "tiff" || ext.lowercase() == "png") { - isRaw = false; - } - - ii = rtengine::InitialImage::load ( inputFile, isRaw, &errorCode, nullptr ); - - if (!ii) { - errors++; - std::cerr << "Error loading file: " << inputFile << std::endl; - continue; - } - - if (useDefault) { - if (isRaw) { - std::cout << " Merging default raw processing profile" << std::endl; - rawParams->applyTo(¤tParams); - } else { - std::cout << " Merging default non-raw processing profile" << std::endl; - imgParams->applyTo(¤tParams); - } - } - - bool sideCarFound = false; - unsigned int i = 0; - - // Iterate the procparams file list in order to build the final ProcParams - do { - if (sideProcParams && i == sideCarFilePos) { - // using the sidecar file - Glib::ustring sideProcessingParams = inputFile + paramFileExtension; - - // the "load" method don't reset the procparams values anymore, so values found in the procparam file override the one of currentParams - if( !Glib::file_test( sideProcessingParams, Glib::FILE_TEST_EXISTS ) || currentParams.load ( sideProcessingParams )) { - std::cerr << "Warning: sidecar file requested but not found for: " << sideProcessingParams << std::endl; - } else { - sideCarFound = true; - std::cout << " Merging sidecar procparams" << std::endl; - } - } - - if( processingParams.size() > i ) { - std::cout << " Merging procparams #" << i << std::endl; - processingParams[i]->applyTo(¤tParams); - } - - i++; - } while (i < processingParams.size() + (sideProcParams ? 1 : 0)); - - if( sideProcParams && !sideCarFound && skipIfNoSidecar ) { - delete ii; - errors++; - std::cerr << "Error: no sidecar procparams found for: " << inputFile << std::endl; - continue; - } - - job = rtengine::ProcessingJob::create (ii, currentParams); - - if( !job ) { - errors++; - std::cerr << "Error creating processing for: " << inputFile << std::endl; - ii->decreaseRef(); - continue; - } - - // Process image - rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, nullptr, options.tunnelMetaData); - - if( !resultImage ) { - errors++; - std::cerr << "Error processing: " << inputFile << std::endl; - rtengine::ProcessingJob::destroy( job ); - continue; - } - - // save image to disk - if( outputType == "jpg" ) { - errorCode = resultImage->saveAsJPEG( outputFile, compression, subsampling ); - } else if( outputType == "tif" ) { - errorCode = resultImage->saveAsTIFF( outputFile, bits, compression == 0 ); - } else if( outputType == "png" ) { - errorCode = resultImage->saveAsPNG( outputFile, compression, bits ); - } else { - errorCode = resultImage->saveToFile (outputFile); - } - - if(errorCode) { - errors++; - std::cerr << "Error saving to: " << outputFile << std::endl; - } else { - if( copyParamsFile ) { - Glib::ustring outputProcessingParams = outputFile + paramFileExtension; - currentParams.save( outputProcessingParams ); - } - } - - ii->decreaseRef(); - resultImage->free(); - } - - if (imgParams) { - imgParams->deleteInstance(); - delete imgParams; - } - - if (rawParams) { - rawParams->deleteInstance(); - delete rawParams; - } - - deleteProcParams(processingParams); - return errors > 0 ? -2 : 0; } diff --git a/rtgui/options.cc b/rtgui/options.cc index 2b8203728..390778063 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2177,7 +2177,7 @@ int Options::saveToFile (Glib::ustring fname) } } -bool Options::load () +bool Options::load (bool lightweight) { // Find the application data path @@ -2338,7 +2338,7 @@ bool Options::load () langMgr.load (localeTranslation, new MultiLangMgr (languageTranslation, new MultiLangMgr (defaultTranslation))); - rtengine::init (&options.rtSettings, argv0, rtdir); + rtengine::init (&options.rtSettings, argv0, rtdir, !lightweight); return true; } diff --git a/rtgui/options.h b/rtgui/options.h index 446e8d2cc..54c457cf6 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -306,7 +306,7 @@ public: void setDefaults (); int readFromFile (Glib::ustring fname); int saveToFile (Glib::ustring fname); - static bool load (); + static bool load (bool lightweight = false); static void save (); // if multiUser=false, send back the global profile path diff --git a/rtgui/pathutils.cc b/rtgui/pathutils.cc new file mode 100644 index 000000000..21c452d4c --- /dev/null +++ b/rtgui/pathutils.cc @@ -0,0 +1,48 @@ +/* + * This file is part of RawTherapee. + * + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "pathutils.h" + + +Glib::ustring removeExtension (const Glib::ustring& filename) +{ + + Glib::ustring bname = Glib::path_get_basename(filename); + size_t lastdot = bname.find_last_of ('.'); + size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); + + if (lastdot != bname.npos && (lastwhitespace == bname.npos || lastdot > lastwhitespace)) { + return filename.substr (0, filename.size() - (bname.size() - lastdot)); + } else { + return filename; + } +} + +Glib::ustring getExtension (const Glib::ustring& filename) +{ + + Glib::ustring bname = Glib::path_get_basename(filename); + size_t lastdot = bname.find_last_of ('.'); + size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); + + if (lastdot != bname.npos && (lastwhitespace == bname.npos || lastdot > lastwhitespace)) { + return filename.substr (filename.size() - (bname.size() - lastdot) + 1, filename.npos); + } else { + return ""; + } +} diff --git a/rtgui/pathutils.h b/rtgui/pathutils.h new file mode 100644 index 000000000..ce58103b9 --- /dev/null +++ b/rtgui/pathutils.h @@ -0,0 +1,34 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef __PATH_UTILS_ +#define __PATH_UTILS_ + +#include +#include +#include "../rtengine/rtengine.h" +#include "../rtengine/coord.h" +#include "rtimage.h" +#include +#include + +// Removed from guiutils because used by rawtherapee-cli +Glib::ustring removeExtension (const Glib::ustring& filename); +Glib::ustring getExtension (const Glib::ustring& filename); + +#endif diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 04f3b1fe1..bcd8540fc 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -22,6 +22,7 @@ #include "splash.h" #include "cachemanager.h" #include "addsetids.h" +#include "../rtengine/icons.h" #include "../rtengine/dfmanager.h" #include "../rtengine/ffmanager.h" #include @@ -2026,7 +2027,7 @@ void Preferences::cancelPressed () { // set the initial theme back if (themeFNames.at(theme->get_active_row_number ()).longFName != options.theme) { - RTImage::setPaths(options); + rtengine::setPaths(options); RTImage::updateImages(); switchThemeTo(options.theme); } @@ -2079,7 +2080,7 @@ void Preferences::themeChanged () { moptions.theme = themeFNames.at(theme->get_active_row_number ()).longFName; - RTImage::setPaths(moptions); + rtengine::setPaths(moptions); RTImage::updateImages(); switchThemeTo(moptions.theme); } diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 464123b0f..16e8e3286 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -23,51 +23,13 @@ #include #include "options.h" +#include "../rtengine/icons.h" namespace { -std::vector imagePaths; std::map> pixbufCache; -bool loadIconSet(const Glib::ustring& iconSet) -{ - try { - - Glib::KeyFile keyFile; - keyFile.load_from_file (iconSet); - - auto iconSetDir = keyFile.get_string ("General", "Iconset"); - - if (!iconSetDir.empty ()) { - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "actions")); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir)); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "devices")); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "places")); - } - - iconSetDir = keyFile.get_string ("General", "FallbackIconset"); - - if (!iconSetDir.empty ()) { - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "actions")); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir)); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "devices")); - imagePaths.push_back (Glib::build_filename (argv0, "images", iconSetDir, "places")); - } - - return true; - - } catch (const Glib::Exception& exception) { - - if (options.rtSettings.verbose) { - std::cerr << "Failed to load icon set \"" << iconSet << "\": " << exception.what() << std::endl; - } - - return false; - - } -} - } RTImage::RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName) : Gtk::Image() @@ -90,7 +52,7 @@ void RTImage::changeImage (const Glib::ustring& imageName) auto iterator = pixbufCache.find (imageName); if (iterator == pixbufCache.end ()) { - const auto imagePath = findIconAbsolutePath (imageName); + const auto imagePath = rtengine::findIconAbsolutePath (imageName); const auto pixbuf = Gdk::Pixbuf::create_from_file (imagePath); iterator = pixbufCache.emplace (imageName, pixbuf).first; @@ -102,70 +64,18 @@ void RTImage::changeImage (const Glib::ustring& imageName) void RTImage::updateImages() { for (auto& entry : pixbufCache) { - const auto imagePath = findIconAbsolutePath (entry.first); + const auto imagePath = rtengine::findIconAbsolutePath (entry.first); entry.second = Gdk::Pixbuf::create_from_file (imagePath); } } -Glib::ustring RTImage::findIconAbsolutePath (const Glib::ustring& iconName) -{ - try { - - for (const auto& imagePath : imagePaths) { - const auto iconPath = Glib::build_filename(imagePath, iconName); - - if (Glib::file_test(iconPath, Glib::FILE_TEST_IS_REGULAR)) { - return iconPath; - } - } - - } catch(const Glib::Exception&) {} - - if (options.rtSettings.verbose) { - std::cerr << "Icon \"" << iconName << "\" could not be found!" << std::endl; - } - - return Glib::ustring(); -} - -void RTImage::setPaths (const Options& options) -{ - // TODO: Forcing the Dark theme, so reading the icon set files is useless for now... - - /*Glib::ustring iconSet; - - // Either use the system icon set or the one specified in the options. - if (options.useSystemTheme) { - iconSet = Glib::build_filename (argv0, "themes", "system.iconset"); - } else { - iconSet = Glib::build_filename (argv0, "themes", options.theme + ".iconset"); - } - - imagePaths.clear (); - - if (!loadIconSet (iconSet)) { - // If the preferred icon set is unavailable, fall back to the default icon set. - loadIconSet (Glib::build_filename (argv0, "themes", "Default.iconset")); - }*/ - - imagePaths.clear (); - - imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark")); - imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "actions")); - imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "devices")); - imagePaths.push_back (Glib::build_filename(argv0, "images", "Dark", "places")); - - // The images folder is the second fallback solution. - imagePaths.push_back (Glib::build_filename(argv0, "images")); -} - Glib::RefPtr RTImage::createFromFile (const Glib::ustring& fileName) { Glib::RefPtr pixbuf; try { - const auto filePath = findIconAbsolutePath (fileName); + const auto filePath = rtengine::findIconAbsolutePath (fileName); if (!filePath.empty ()) { pixbuf = Gdk::Pixbuf::create_from_file (filePath); @@ -188,7 +98,7 @@ Cairo::RefPtr RTImage::createFromPng (const Glib::ustring& try { - const auto filePath = findIconAbsolutePath (fileName); + const auto filePath = rtengine::findIconAbsolutePath (fileName); if (!filePath.empty()) { surface = Cairo::ImageSurface::create_from_png (Glib::locale_from_utf8 (filePath)); diff --git a/rtgui/rtimage.h b/rtgui/rtimage.h index cfc7a5fa1..0286d990b 100644 --- a/rtgui/rtimage.h +++ b/rtgui/rtimage.h @@ -34,9 +34,6 @@ public: void changeImage (const Glib::ustring& imageName); static void updateImages (); - static Glib::ustring findIconAbsolutePath (const Glib::ustring& iconName); - static void setPaths (const Options& options); - static Glib::RefPtr createFromFile (const Glib::ustring& fileName); static Cairo::RefPtr createFromPng (const Glib::ustring& fileName); }; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 9fc593d22..be7a68b25 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -24,6 +24,7 @@ #include "cursormanager.h" #include "rtimage.h" #include "whitebalance.h" +#include "../rtengine/icons.h" #if defined(__APPLE__) static gboolean @@ -93,7 +94,7 @@ RTWindow::RTWindow () ProfilePanel::init (this); Glib::ustring fName = "rt-logo-small.png"; - Glib::ustring fullPath = RTImage::findIconAbsolutePath(fName); + Glib::ustring fullPath = rtengine::findIconAbsolutePath(fName); try { set_default_icon_from_file (fullPath); From 1b70ad2ec64374f75179dc605ea5bae81adf4519 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 14 Feb 2017 01:11:48 +0100 Subject: [PATCH 084/110] Bugfix --- rtgui/main-cli.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 1e35e00c6..d92643489 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -193,7 +193,7 @@ int main(int argc, char **argv) SetConsoleCtrlHandler( NULL, true ); // Set title of console char consoletitle[128]; - sprintf(consoletitle, "RawTherapee %s Console", VERSION); + sprintf(consoletitle, "RawTherapee %s Console", RTVERSION); SetConsoleTitle(consoletitle); // increase size of screen buffer COORD c; @@ -219,7 +219,7 @@ int main(int argc, char **argv) consoleOpened = true; // printing RT's version in every case, particularly useful for the 'verbose' mode, but also for the batch processing - std::cout << "RawTherapee, version " << VERSION << ", command line" << std::endl; + std::cout << "RawTherapee, version " << RTVERSION << ", command line" << std::endl; std::cout << "WARNING: closing this window will close RawTherapee!" << std::endl << std::endl; } } @@ -230,7 +230,7 @@ int main(int argc, char **argv) int ret = 0; // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing - std::cout << "RawTherapee, version " << VERSION << ", command line" << std::endl; + std::cout << "RawTherapee, version " << RTVERSION << ", command line" << std::endl; if (argc > 1) { ret = processLineParams(argc, argv); } From 825002378b061385dab0e982a674355bc34418a8 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 10 Mar 2017 23:05:19 +0100 Subject: [PATCH 085/110] =?UTF-8?q?Added=20JK=20Han=20and=20Kalle=20S?= =?UTF-8?q?=C3=B6derman=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 086/110] 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; From 174949e0f0a55cb88875a08828d37334aa0eb3da Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 12 Mar 2017 20:39:03 +0100 Subject: [PATCH 087/110] Fix slowdown for decode of non pixelshift files --- rtengine/rawimagesource.cc | 57 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 28d3c1e89..a25e63e56 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1518,32 +1518,39 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) numFrames = ri->getFrameCount(); errCode = 0; -#ifdef _OPENMP -#pragma omp parallel if(numFrames > 1) -#endif -{ - int errCodeThr = 0; -#ifdef _OPENMP -#pragma omp for nowait -#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[i]->compress_image(i); - } -#ifdef _OPENMP -#pragma omp critical -#endif -{ - errCode = errCodeThr ? errCodeThr : errCode; -} -} + if(numFrames > 1) { +#ifdef _OPENMP + #pragma omp parallel +#endif + { + int errCodeThr = 0; +#ifdef _OPENMP + #pragma omp for nowait +#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[i]->compress_image(i); + } +#ifdef _OPENMP + #pragma omp critical +#endif + { + errCode = errCodeThr ? errCodeThr : errCode; + } + } + } else { + riFrames[0] = ri; + errCode = riFrames[0]->loadRaw (true, 0, true, plistener, 0.8); + riFrames[0]->compress_image(0); + } + if(errCode) { return errCode; } From b26622553967e516201e57f6bd171365253fe73f Mon Sep 17 00:00:00 2001 From: TooWaBoo Date: Sun, 12 Mar 2017 22:16:22 +0100 Subject: [PATCH 088/110] Fix for issue https://github.com/Beep6581/RawTherapee/issues/3751 --- rtdata/themes/RawTherapee-GTK3-20_.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 27d2b5f13..c1768f913 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -243,6 +243,13 @@ scale trough { margin: 6px 6px; /* have to be half of "scale slider / min-width min-height" */ background-color: #2A2A2A; } +scale.fine-tune trough { + margin: 5px; + padding: 1px; +} +scale.fine-tune trough highlight { + margin: -2px; +} scale:disabled trough { background-color: #444; border-color: #282828; From 567ed3629cd5f2f6cdb308347b622a026eb16756 Mon Sep 17 00:00:00 2001 From: Hombre Date: Mon, 13 Mar 2017 01:30:34 +0100 Subject: [PATCH 089/110] Automatically selected profiles are now correctly loaded on first use. --- rtengine/dcp.cc | 25 ++++++++++--- rtengine/dcp.h | 1 + rtengine/iccstore.cc | 89 +++++++++++++++++++++++++++++++++++++++++--- rtengine/iccstore.h | 33 ++++++++-------- rtengine/init.cc | 4 +- rtgui/options.cc | 6 +-- 6 files changed, 126 insertions(+), 32 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 86e348c75..b97f913e7 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1709,6 +1709,11 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) file_std_profiles.clear(); + if (!loadAll) { + profileDir.assign (rt_profile_dir); + return; + } + if (!rt_profile_dir.empty()) { std::deque dirs = { rt_profile_dir @@ -1731,10 +1736,8 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) return; } - dirname += '/'; - for (const Glib::ustring& sname : *dir) { - const Glib::ustring fname = dirname + sname; + const Glib::ustring fname = Glib::build_filename(dirname, sname); if (!Glib::file_test(fname, Glib::FILE_TEST_IS_DIR)) { // File @@ -1797,15 +1800,25 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const return nullptr; } -DCPProfile* DCPStore::getStdProfile(const Glib::ustring& cam_short_name) const +DCPProfile* DCPStore::getStdProfile(const Glib::ustring& requested_cam_short_name) const { - const Glib::ustring name = cam_short_name.uppercase(); + const Glib::ustring name = requested_cam_short_name.uppercase(); // Warning: do NOT use map.find(), since it does not seem to work reliably here - for (const auto& file_std_profile : file_std_profiles) + for (const auto& file_std_profile : file_std_profiles) { if (file_std_profile.first == name) { return getProfile(file_std_profile.second); } + } + + // profile not found, looking if we're in loadAll=false mode + if (!profileDir.empty()) { + const Glib::ustring fname = Glib::build_filename(profileDir, requested_cam_short_name + Glib::ustring(".dcp")); + + if (Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) { + return getProfile(fname); + } + } return nullptr; } diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 215137ac8..5a6858099 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -165,6 +165,7 @@ private: DCPStore() = default; mutable MyMutex mutex; + Glib::ustring profileDir; // these contain standard profiles from RT. keys are all in uppercase, file path is value std::map file_std_profiles; diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 2898f48c8..7bc21d5d4 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -36,6 +36,7 @@ namespace rtengine { extern const Settings* settings; +// not recursive void loadProfiles (const Glib::ustring& dirName, std::map* profiles, std::map* profileContents, @@ -96,6 +97,60 @@ void loadProfiles (const Glib::ustring& dirName, } catch (Glib::Exception&) {} } +// version dedicated to single profile load when loadAll==false (cli version "-q" mode) +bool loadProfile (Glib::ustring profile, const Glib::ustring dirName, + std::map* profiles, + std::map* profileContents) +{ + if (dirName.empty () || profiles == nullptr) { + return false; + } + + try { + + Glib::Dir dir (dirName); + + for (Glib::DirIterator entry = dir.begin (); entry != dir.end (); ++entry) { + + const Glib::ustring fileName = *entry; + + if (fileName.size () < 4) { + continue; + } + + const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); + + if (extension.compare (".icc") != 0 && extension.compare (".icm") != 0) { + continue; + } + + const Glib::ustring filePath = Glib::build_filename (dirName, fileName); + + if (!Glib::file_test (filePath, Glib::FILE_TEST_IS_REGULAR)) { + continue; + } + + Glib::ustring name = fileName.substr (0, fileName.size() - 4); + + if (name == profile) { + const ProfileContent content (filePath); + const cmsHPROFILE profile = content.toProfile (); + + if (profile) { + profiles->insert (std::make_pair (name, profile)); + + if (profileContents) { + profileContents->insert (std::make_pair (name, content)); + } + return true; + } + } + } + } catch (Glib::Exception&) {} + + return false; +} + inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, uint8_t& result) { if (cmsIsIntentSupported (profile, intent, direction)) { @@ -305,6 +360,7 @@ ICCStore* ICCStore::getInstance () } ICCStore::ICCStore () : + loadAll(true), xyz (createXYZProfile ()), srgb (cmsCreate_sRGBProfile ()) { @@ -674,7 +730,7 @@ bool ICCStore::outputProfileExist (const Glib::ustring& name) const return fileProfiles.find(name) != fileProfiles.end(); } -cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const +cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) { MyMutex::MyLock lock (mutex_); @@ -695,12 +751,21 @@ cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const return profile; } + } else if (!loadAll) { + // look for a standard profile + if (!loadProfile (name, profilesDir, &fileProfiles, &fileProfileContents)) { + loadProfile (name, userICCDir, &fileProfiles, &fileProfileContents); + } + const ProfileMap::const_iterator r = fileProfiles.find (name); + if (r != fileProfiles.end ()) { + return r->second; + } } return nullptr; } -cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) const +cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) { const Glib::ustring nameUpper = name.uppercase (); @@ -712,6 +777,15 @@ cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) const // return profile from store if (r != fileStdProfiles.end ()) { return r->second; + } else if (!loadAll) { + // directory not scanned, so looking and adding now... + if (!loadProfile (name, profilesDir, &fileProfiles, &fileProfileContents)) { + loadProfile (name, userICCDir, &fileProfiles, &fileProfileContents); + } + const ProfileMap::const_iterator r = fileProfiles.find (name); + if (r != fileProfiles.end ()) { + return r->second; + } } // profile is not yet in store @@ -745,21 +819,21 @@ ProfileContent ICCStore::getContent (const Glib::ustring& name) const return r != fileProfileContents.end () ? r->second : ProfileContent(); } -uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_INPUT); } -uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); } -uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) { MyMutex::MyLock lock (mutex_); @@ -772,13 +846,16 @@ void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCD MyMutex::MyLock lock (mutex_); + this->loadAll = loadAll; + // RawTherapee's profiles take precedence if a user's profile of the same name exists profilesDir = Glib::build_filename (rtICCDir, "output"); + userICCDir = usrICCDir; fileProfiles.clear(); fileProfileContents.clear(); if (loadAll) { loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); - loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false); + loadProfiles (userICCDir, &fileProfiles, &fileProfileContents, nullptr, false); } // Input profiles diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index ae4026b28..5d8ccd5f0 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -65,6 +65,7 @@ class ICCStore // these contain profiles from user/system directory (supplied on init) Glib::ustring profilesDir; + Glib::ustring userICCDir; ProfileMap fileProfiles; ContentMap fileProfileContents; @@ -75,6 +76,8 @@ class ICCStore Glib::ustring defaultMonitorProfile; + bool loadAll; + const cmsHPROFILE xyz; const cmsHPROFILE srgb; @@ -102,8 +105,8 @@ public: // Main monitors standard profile name, from OS void findDefaultMonitorProfile (); - cmsHPROFILE getDefaultMonitorProfile () const; - Glib::ustring getDefaultMonitorProfileName () const; + cmsHPROFILE getDefaultMonitorProfile (); + Glib::ustring getDefaultMonitorProfileName (); cmsHPROFILE workingSpace (const Glib::ustring& name) const; cmsHPROFILE workingSpaceGamma (const Glib::ustring& name) const; @@ -111,8 +114,8 @@ public: TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; bool outputProfileExist (const Glib::ustring& name) const; - cmsHPROFILE getProfile (const Glib::ustring& name) const; - cmsHPROFILE getStdProfile (const Glib::ustring& name) const; + cmsHPROFILE getProfile (const Glib::ustring& name); + cmsHPROFILE getStdProfile (const Glib::ustring& name); ProfileContent getContent (const Glib::ustring& name) const; cmsHPROFILE getXYZProfile () const; @@ -121,13 +124,13 @@ public: std::vector getProfiles (const ProfileType type = ProfileType::MONITOR) const; std::vector getProfilesFromDir (const Glib::ustring& dirName) const; - uint8_t getInputIntents (cmsHPROFILE profile) const; - uint8_t getOutputIntents (cmsHPROFILE profile) const; - uint8_t getProofIntents (cmsHPROFILE profile) const; + uint8_t getInputIntents (cmsHPROFILE profile); + uint8_t getOutputIntents (cmsHPROFILE profile); + uint8_t getProofIntents (cmsHPROFILE profile); - uint8_t getInputIntents (const Glib::ustring& name) const; - uint8_t getOutputIntents (const Glib::ustring& name) const; - uint8_t getProofIntents (const Glib::ustring& name) const; + uint8_t getInputIntents (const Glib::ustring& name); + uint8_t getOutputIntents (const Glib::ustring& name); + uint8_t getProofIntents (const Glib::ustring& name); }; #define iccStore ICCStore::getInstance() @@ -143,27 +146,27 @@ inline ProfileContent::~ProfileContent () delete [] data; } -inline cmsHPROFILE ICCStore::getDefaultMonitorProfile () const +inline cmsHPROFILE ICCStore::getDefaultMonitorProfile () { return getProfile (defaultMonitorProfile); } -inline Glib::ustring ICCStore::getDefaultMonitorProfileName () const +inline Glib::ustring ICCStore::getDefaultMonitorProfileName () { return defaultMonitorProfile; } -inline uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getInputIntents (const Glib::ustring &name) { return getInputIntents (getProfile (name)); } -inline uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) { return getOutputIntents (getProfile (name)); } -inline uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getProofIntents (const Glib::ustring &name) { return getProofIntents (getProfile (name)); } diff --git a/rtengine/init.cc b/rtengine/init.cc index 66ff5baf6..d6bba9f2b 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -40,9 +40,9 @@ MyMutex* lcmsMutex = nullptr; int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir, bool loadAll) { settings = s; - iccStore->init (s->iccDirectory, baseDir + "/iccprofiles", loadAll); + iccStore->init (s->iccDirectory, Glib::build_filename (baseDir, "iccprofiles"), loadAll); iccStore->findDefaultMonitorProfile(); - DCPStore::getInstance()->init (baseDir + "/dcpprofiles"); + DCPStore::getInstance()->init (Glib::build_filename (baseDir, "dcpprofiles"), loadAll); CameraConstantsStore::getInstance ()->init (baseDir, userSettingsDir); ProcParams::init (); diff --git a/rtgui/options.cc b/rtgui/options.cc index 72ce93335..95bb59061 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2315,7 +2315,7 @@ bool Options::load (bool lightweight) // out which are the parent translations. Furthermore, there must be a file for each locale () -- you cannot have // 'French (CA)' unless there is a file 'French'. - Glib::ustring defaultTranslation = argv0 + "/languages/default"; + Glib::ustring defaultTranslation = Glib::build_filename (argv0, "languages", "default"); Glib::ustring languageTranslation = ""; Glib::ustring localeTranslation = ""; @@ -2327,11 +2327,11 @@ bool Options::load (bool lightweight) std::vector langPortions = Glib::Regex::split_simple (" ", options.language); if (langPortions.size() >= 1) { - languageTranslation = argv0 + "/languages/" + langPortions.at (0); + languageTranslation = Glib::build_filename (argv0, "languages", langPortions.at (0)); } if (langPortions.size() >= 2) { - localeTranslation = argv0 + "/languages/" + options.language; + localeTranslation = Glib::build_filename (argv0, "languages", options.language); } } From 845ebe6906ddb4d5ed4e3630030e00f26ee82fc2 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 13 Mar 2017 15:44:36 +0100 Subject: [PATCH 090/110] Faster loading of pixelshift files --- rtengine/rawimagesource.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a25e63e56..71d1e10a1 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1536,7 +1536,6 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) riFrames[i] = new RawImage(fname); errCodeThr = riFrames[i]->loadRaw (true, i); } - riFrames[i]->compress_image(i); } #ifdef _OPENMP #pragma omp critical @@ -1548,10 +1547,13 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) } else { riFrames[0] = ri; errCode = riFrames[0]->loadRaw (true, 0, true, plistener, 0.8); - riFrames[0]->compress_image(0); } - if(errCode) { + if(!errCode) { + for(unsigned int i = 0; i < numFrames; ++i) { + riFrames[i]->compress_image(i); + } + } else { return errCode; } From c9d9715e6dcbac93b7d0a09b8378c5d0311ab127 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 13 Mar 2017 21:38:52 +0100 Subject: [PATCH 091/110] pixelshift: cleaned code --- rtengine/pixelshift.cc | 826 ++++++----------------------------------- 1 file changed, 122 insertions(+), 704 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 2e001f686..692e3d584 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -2,7 +2,6 @@ // // pentax pixelshift algorithm with motion detection // -// 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 @@ -37,10 +36,12 @@ namespace { -float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion, int x, int y) +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 +#ifdef PIXELSHIFTDEV if(adaptive) { +#endif float gDiff = a - b; gDiff *= eperIso; gDiff *= gDiff; @@ -48,12 +49,6 @@ 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) { @@ -63,14 +58,18 @@ float greenDiff(float a, float b, bool adaptive, float stddevFactor, float eperI } else { return 0.f; } +#ifdef PIXELSHIFTDEV + } 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; } +#endif } +#ifdef PIXELSHIFTDEV float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { // calculate the difference between two nongreen samples @@ -91,6 +90,7 @@ float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nr return 0.f; } } +#endif float nonGreenDiffCross(float right, float left, float top, float bottom, float centre, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { @@ -300,611 +300,22 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D &ma } } - } 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) -{ - - 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 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); - - 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; - -#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 *nonGreenDest0 = red[i + offsY]; - 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]; - 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); - std::swap(stddevFactorNonGreen0, stddevFactorNonGreen2); - } - - // 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]; - - // 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((*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, 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, 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) - }); - } - - } - - 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; - float korr = 0.f; - - for(; j < winw - (border + offsX); ++j) { - 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 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, 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, 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, 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, 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]}); - } - - - // 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]; - } - - if (gridMax > thresh - korr) { - // at least one of the tested pixels of the grid is detected as motion - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); - - if(skipNext) { - // treat the horizontally next pixel also as motion - j++; - paintMotionMask(j + offsX, showMotion, (gridMax - thresh + korr) * blendFactor, showOnlyMask, greenDest, nonGreenDest0, nonGreenDest1); - offset ^= 1; - } - - // do not set the motion pixel values. They have already been set by demosaicer or showMotion - continue; - } - - if(adaptive && checkNonGreenCross) { - 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; - - 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)]; - diffRight = ngRight - ngCentre; - diffLeft = ngLeft - ngCentre; - - 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]; - float diffRight = ngRight - ngCentre; - float diffLeft = ngLeft - ngCentre; - - if(diffRight * diffLeft >= 0.f) { - float avg = (ngRight + ngLeft) / 2.f; - float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - - if(diff > 0.f) { - 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)]; - diffRight = ngRight - ngCentre; - diffLeft = ngLeft - ngCentre; - - if(diffRight * diffLeft >= 0.f) { - float avg = (ngRight + ngLeft) / 2.f; - float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); - continue; - } - } - } - - if(adaptive && checkNonGreenVertical) { - 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 diffTop = ngTop - ngCentre; - float diffBottom = ngBottom - ngCentre; - - if(diffTop * diffBottom >= 0.f) { - float avg = (ngTop + ngBottom) / 2.f; - float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen0, eperIsoNonGreen0, nRead, prnu, showMotion); - - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest0, nonGreenDest1, greenDest); - continue; - } - } - - 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]; - - diffTop = ngTop - ngCentre; - diffBottom = ngBottom - ngCentre; - - if(diffTop * diffBottom >= 0.f) { - float avg = (ngTop + ngBottom) / 2.f; - float diff = nonGreenDiff(ngCentre, avg, stddevFactorNonGreen2, eperIsoNonGreen2, nRead, prnu, showMotion); - - if(diff > 0.f) { - paintMotionMask(j + offsX, showMotion, diff, showOnlyMask, nonGreenDest1, nonGreenDest0, greenDest); - continue; - } - } - } - } - - 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] = ((*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]; - } - } - - if(plistener) { - 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) { #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 && showMotion; const RAWParams::BayerSensor::ePSMotionCorrection gridSize_ = bayerParams.pixelShiftMotionCorrection; const bool adaptive = bayerParams.pixelShiftAutomatic; #ifdef PIXELSHIFTDEV + const bool detectMotion = bayerParams.pixelShiftMotion > 0; float stddevFactorGreen = bayerParams.pixelShiftStddevFactorGreen; float stddevFactorRed = bayerParams.pixelShiftStddevFactorRed; float stddevFactorBlue = bayerParams.pixelShiftStddevFactorBlue; @@ -932,7 +343,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #ifdef PIXELSHIFTDEV const float threshold = bayerParams.pixelShiftSum + 9.f; #else - const float threshold = 3.f + 9.f; + constexpr float threshold = 3.f + 9.f; #endif const bool experimental0 = bayerParams.pixelShiftExp0; const bool holeFill = bayerParams.pixelShiftHoleFill; @@ -1086,7 +497,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA return; } - +#ifdef PIXELSHIFTDEV // Lookup table for non adaptive (slider) mode LUTf log2Lut(32768, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); @@ -1098,6 +509,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA log2Lut[i >> 1] = lutStrength * log2(i) / 100.f; } } +#endif const float scaleGreen = 1.f / scale_mul[1]; @@ -1120,11 +532,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA nRead *= pow(2.f, nreadIso); eperIsoModel *= pow(2.f, eperIso); +#ifdef PIXELSHIFTDEV if(adaptive && experimental0) { eperIso = eperIsoModel * sqrtf(100.f / (rawWpCorrection * idata->getISOSpeed())); } else { eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); } +#else + eperIso = eperIsoModel * (100.f / (rawWpCorrection * idata->getISOSpeed())); +#endif #ifdef PIXELSHIFTDEV std::cout << "WL: " << c_white[0] << " BL: " << c_black[0] << " ePerIso multiplicator: " << (65535.f / (c_white[0] - c_black[0])) << std::endl; @@ -1133,8 +549,6 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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); - prnu /= 100.f; stddevFactorGreen *= stddevFactorGreen; stddevFactorRed *= stddevFactorRed; @@ -1178,8 +592,8 @@ 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] = {}; + // calculate average green brightness for each frame + float greenBrightness[4] = {1.f, 1.f, 1.f, 1.f}; if(equalBrightness) { LUT *histo[4]; @@ -1209,17 +623,14 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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 + unsigned int offset = c & 1; 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]++; + offset ^= 1; // 0 => 1 or 1 => 0 } } @@ -1244,22 +655,19 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA ++median; } - medians[i] = (median + median - 1) / 2.f; + const float weight = (count - datalen / 2.f) / (*histo[i])[median - 1]; + medians[i] = intp(weight, (float)(median - 2), (float)(median - 1)); delete histo[i]; } - const float medianMaster = medians[frame]; - for(int i = 0; i < 4; ++i) { - greenBrightness[i] = medianMaster / medians[i]; + greenBrightness[i] = medians[frame] / 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 @@ -1322,8 +730,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA float *blueDest = blue[i + offsY]; int j = winx + border - offsX; +#ifdef PIXELSHIFTDEV float greenDifMax[gridSize]; // Here we store the maximum differences per Column - +#endif // green channel motion detection checks the grid around the pixel for differences in green channels #ifdef PIXELSHIFTDEV @@ -1331,89 +740,89 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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[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, 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) + 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, 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[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, 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[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, 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[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, 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[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, 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[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, 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[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, 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[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, 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[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, 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[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, 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[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) }); } @@ -1422,7 +831,10 @@ 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 +#ifdef PIXELSHIFTDEV int lastIndex = gridSize - 1; +#endif + float korr = 0.f; int c = FC(i, j); bool blueRow = false; @@ -1440,8 +852,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA offset ^= 1; // 0 => 1 or 1 => 0 +#ifdef PIXELSHIFTDEV if(detectMotion || (adaptive && checkGreen)) { bool skipNext = false; +#else + if(adaptive && checkGreen) { +#endif float gridMax; #ifdef PIXELSHIFTDEV @@ -1449,15 +865,15 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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); + gridMax = greenDiff(psG1[i][j], psG2[i][j], adaptive, stddevFactorGreen, eperIsoGreen, nRead, prnu, showMotion); #ifdef PIXELSHIFTDEV 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) + 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]}); @@ -1466,11 +882,11 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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), - 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[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]}); @@ -1479,13 +895,13 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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), - 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[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]}); @@ -1499,9 +915,12 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA korr = log2Lut[((int)(psG1[i][j] * scaleGreen)) >> 1]; } + if (gridMax > thresh - korr) { +#else + if (gridMax > thresh) { + #endif - if (gridMax > thresh - korr) { #ifdef PIXELSHIFTDEV sumThr[offset] ++; @@ -1755,7 +1174,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #endif { sum[0] += sumThr[0]; - sum[1] += sumThr[0]; + sum[1] += sumThr[1]; } #endif } @@ -1818,7 +1237,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(smoothTransitions) { + if(smoothTransitions) { // vfloat onev = F2V(1.f); vfloat smoothv = F2V(smoothFactor); int j = winx + border - offsX; @@ -1868,4 +1287,3 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA plistener->setProgress(1.0); } } -#endif \ No newline at end of file From 499ca64a2c614827988f700b7f24402002e99f7c Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 15 Mar 2017 01:17:17 +0100 Subject: [PATCH 092/110] pixelshift: Allow translation of previously hardcoded motion correction methods Off/Automatic/Custom --- rtdata/languages/default | 3 +++ rtgui/bayerprocess.cc | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 02260f2e5..4d3bdab5c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1730,6 +1730,9 @@ TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;Shows the motion mask without the im 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_PIXELSHIFTMM_OFF;Off +TP_RAW_PIXELSHIFTMM_AUTO;Automatic +TP_RAW_PIXELSHIFTMM_CUSTOM;Custom TP_RAW_PIXELSHIFTSHOWMOTION;Show motion TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show mask only TP_RAW_PIXELSHIFTSTDDEVFACTORGREEN;StdDev factor Green diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5c559fc1f..f8ac4b5a3 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -101,10 +101,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA 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("Off"); - pixelShiftMotionMethod->append("Automatic"); - pixelShiftMotionMethod->append("Custom"); - pixelShiftMotionMethod->set_active(1); + pixelShiftMotionMethod->append(M("TP_RAW_PIXELSHIFTMM_OFF")); + pixelShiftMotionMethod->append(M("TP_RAW_PIXELSHIFTMM_AUTO")); + pixelShiftMotionMethod->append(M("TP_RAW_PIXELSHIFTMM_CUSTOM")); + pixelShiftMotionMethod->set_active(RAWParams::BayerSensor::ePSMotionCorrectionMethod::Automatic); pixelShiftMotionMethod->show(); hb3->pack_start(*pixelShiftMotionMethod); pixelShiftFrame->pack_start(*hb3); @@ -762,7 +762,7 @@ void BayerProcess::methodChanged () } if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift) { - if(pixelShiftMotionMethod->get_active_row_number() == 2) { + if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Custom) { pixelShiftOptions->show(); } else { pixelShiftOptions->hide(); @@ -819,11 +819,11 @@ void BayerProcess::dcbEnhanceChanged () void BayerProcess::pixelShiftMotionMethodChanged () { - if(pixelShiftMotionMethod->get_active_row_number() == 0) { + if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Off) { pixelShiftOptions->hide(); pixelShiftShowMotion->hide(); pixelShiftShowMotionMaskOnly->hide(); - } else if(pixelShiftMotionMethod->get_active_row_number() == 2) { + } else if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Custom) { pixelShiftOptions->show(); pixelShiftShowMotion->show(); pixelShiftShowMotionMaskOnly->show(); From 28015d8c26b906d854dbb3edb867eedffd1f730d Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 15 Mar 2017 23:24:18 +0100 Subject: [PATCH 093/110] =?UTF-8?q?Pixelshift:=20reduce=20number=20of=20fa?= =?UTF-8?q?lse=20positive=20motion=20detections=20for=20red/blue=20check?= =?UTF-8?q?=20on=20transitions=20between=20overexposed=20a=C5=84d=20correc?= =?UTF-8?q?tly=20exposed=20regions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rtengine/pixelshift.cc | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 692e3d584..41e1c9af2 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -92,8 +92,11 @@ float nonGreenDiff(float a, float b, float stddevFactor, float eperIso, float nr } #endif -float nonGreenDiffCross(float right, float left, float top, float bottom, 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 clippedVal, float stddevFactor, float eperIso, float nreadIso, float prnu, bool showMotion) { + if(rtengine::max(right, left, top, bottom, centre) > clippedVal) { + return 0.f; + } // check non green cross float hDiff = (right + left) * 0.5f - centre; hDiff *= eperIso; @@ -549,6 +552,9 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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])); + const float clippedRed = 65535.f / scale_mul[0]; + const float clippedBlue = 65535.f / scale_mul[2]; + prnu /= 100.f; stddevFactorGreen *= stddevFactorGreen; stddevFactorRed *= stddevFactorRed; @@ -615,7 +621,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA } #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) + #pragma omp for schedule(dynamic,16) nowait #endif for(int i = winy + 1; i < winh - 1; ++i) { @@ -683,36 +689,33 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA int j = winx + 1; int c = FC(i, j); - if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { + if ((c + FC(i, j + 1)) == 3) { // 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 + unsigned int offset = c & 1; 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] * 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]; + offset ^= 1; // 0 => 1 or 1 => 0 } } // 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; +#endif array2D psMask(winw, winh); - #ifdef _OPENMP #pragma omp parallel #endif @@ -732,10 +735,8 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA #ifdef PIXELSHIFTDEV float greenDifMax[gridSize]; // Here we store the maximum differences per Column -#endif // green channel motion detection checks the grid around the pixel for differences in green channels -#ifdef PIXELSHIFTDEV if(detectMotion || (adaptive && checkGreen)) { if(gridSize == 3) { @@ -828,24 +829,22 @@ 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 -#ifdef PIXELSHIFTDEV int lastIndex = gridSize - 1; + float korr = 0.f; + bool blueRow = false; #endif - float korr = 0.f; int c = FC(i, j); - bool blueRow = false; +#ifdef PIXELSHIFTDEV if (c == 2 || ((c & 1) && FC(i, j + 1) == 2)) { // row with blue pixels => swap destination pointers for non green pixels blueRow = true; } - +#endif // 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); + unsigned int offset = c & 1; for(; j < winw - (border + offsX); ++j) { psMask[i][j] = 1.f; @@ -962,7 +961,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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); + float redDiff = nonGreenDiffCross(redRight, redLeft, redTop, redBottom, redCentre, clippedRed, stddevFactorRed, eperIsoRed, nRead, prnu, showMotion); if(redDiff > 0.f) { #ifdef PIXELSHIFTDEV @@ -985,7 +984,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA 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); + float blueDiff = nonGreenDiffCross(blueRight, blueLeft, blueTop, blueBottom, blueCentre, clippedBlue, stddevFactorBlue, eperIsoBlue, nRead, prnu, showMotion); if(blueDiff > 0.f) { #ifdef PIXELSHIFTDEV From a25a5856732b417b7170abf023d2674bbe7f9d51 Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 16 Mar 2017 01:16:37 +0100 Subject: [PATCH 094/110] Checkbox class added to simplify event handling. (issue #3739) --- rtgui/CMakeLists.txt | 2 +- rtgui/bayerprocess.cc | 825 +++++++++++++++--------------------------- rtgui/bayerprocess.h | 57 ++- rtgui/checkbox.cc | 162 +++++++++ rtgui/checkbox.h | 78 ++++ rtgui/guiutils.h | 22 +- 6 files changed, 547 insertions(+), 599 deletions(-) create mode 100644 rtgui/checkbox.cc create mode 100644 rtgui/checkbox.h diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 153c1a0ef..795f6f28d 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -1,7 +1,7 @@ set (BASESOURCEFILES editwindow.cc batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc previewmodepanel.cc filterpanel.cc - exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc + exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc checkbox.cc ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc thresholdselector.cc thresholdadjuster.cc clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc coloredbar.cc edit.cc coordinateadjuster.cc diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index f8ac4b5a3..75b27b360 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -22,6 +22,7 @@ using namespace rtengine; using namespace rtengine::procparams; + BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), true) { Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); @@ -72,7 +73,8 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA } dcbIterations->show(); - dcbEnhance = Gtk::manage (new MyCheckButton(M("TP_RAW_DCBENHANCE"))); + dcbEnhance = Gtk::manage (new CheckBox(M("TP_RAW_DCBENHANCE"), multiImage)); + dcbEnhance->setCheckBoxListener (this); dcbOptions->pack_start(*dcbIterations); dcbOptions->pack_start(*dcbEnhance); pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); @@ -94,7 +96,8 @@ 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 = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTEQUALBRIGHT"), multiImage)); + pixelShiftEqualBright->setCheckBoxListener (this); pixelShiftEqualBright->set_tooltip_text (M("TP_RAW_PIXELSHIFTEQUALBRIGHT_TOOLTIP")); pixelShiftFrame->pack_start(*pixelShiftEqualBright); @@ -112,29 +115,36 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftOptions = Gtk::manage (new Gtk::VBox ()); pixelShiftOptions->set_border_width(0); - pixelShiftShowMotion = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTION"))); + pixelShiftShowMotion = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTSHOWMOTION"), multiImage)); + pixelShiftShowMotion->setCheckBoxListener (this); pixelShiftShowMotion->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP")); pixelShiftFrame->pack_start(*pixelShiftShowMotion); - pixelShiftShowMotionMaskOnly = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"))); + pixelShiftShowMotionMaskOnly = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY"), multiImage)); + pixelShiftShowMotionMaskOnly->setCheckBoxListener (this); pixelShiftShowMotionMaskOnly->set_tooltip_text (M("TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP")); pixelShiftFrame->pack_start(*pixelShiftShowMotionMaskOnly); #ifdef PIXELSHIFTDEV - pixelShiftAutomatic = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTADAPTIVE"))); + pixelShiftAutomatic = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTADAPTIVE"), multiImage)); + pixelShiftAutomatic->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftAutomatic); #endif - pixelShiftGreen = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTGREEN"))); + pixelShiftGreen = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTGREEN"), multiImage)); + pixelShiftGreen->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftGreen); - pixelShiftNonGreenCross = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS"))); + pixelShiftNonGreenCross = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTNONGREENCROSS"), multiImage)); + pixelShiftNonGreenCross->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross); - pixelShiftHoleFill = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTHOLEFILL"))); + pixelShiftHoleFill = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTHOLEFILL"), multiImage)); + pixelShiftHoleFill->setCheckBoxListener (this); pixelShiftHoleFill->set_tooltip_text (M("TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftHoleFill); - pixelShiftBlur = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTBLUR"))); + pixelShiftBlur = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTBLUR"), multiImage)); + pixelShiftBlur->setCheckBoxListener (this); pixelShiftBlur->set_tooltip_text (M("TP_RAW_PIXELSHIFTSIGMA_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftBlur); @@ -173,32 +183,40 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftOptions->pack_start(*pixelShiftEperIso); - pixelShiftMedian = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTMEDIAN"))); + pixelShiftMedian = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTMEDIAN"), multiImage)); + pixelShiftMedian->setCheckBoxListener (this); pixelShiftMedian->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftMedian); #ifdef PIXELSHIFTDEV - pixelShiftMedian3 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTMEDIAN3"))); + pixelShiftMedian3 = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTMEDIAN3"), multiImage)); + pixelShiftMedian3->setCheckBoxListener (this); pixelShiftMedian3->set_tooltip_text (M("TP_RAW_PIXELSHIFTMEDIAN3_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftMedian3); - pixelShiftNonGreenCross2 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"))); + pixelShiftNonGreenCross2 = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTNONGREENCROSS2"), multiImage)); + pixelShiftNonGreenCross2->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftNonGreenCross2); - pixelShiftNonGreenAmaze = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"))); + pixelShiftNonGreenAmaze = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTNONGREENAMAZE"), multiImage)); + pixelShiftNonGreenAmaze->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftNonGreenAmaze); - pixelShiftNonGreenHorizontal = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"))); + pixelShiftNonGreenHorizontal = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTNONGREENHORIZONTAL"), multiImage)); + pixelShiftNonGreenHorizontal->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftNonGreenHorizontal); - pixelShiftNonGreenVertical = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"))); + pixelShiftNonGreenVertical = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTNONGREENVERTICAL"), multiImage)); + pixelShiftNonGreenVertical->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftNonGreenVertical); - pixelShiftExp0 = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTEXP0"))); + pixelShiftExp0 = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTEXP0"), multiImage)); + pixelShiftExp0->setCheckBoxListener (this); pixelShiftOptions->pack_start(*pixelShiftExp0); #endif - pixelShiftLmmse = Gtk::manage (new MyCheckButton(M("TP_RAW_PIXELSHIFTLMMSE"))); + pixelShiftLmmse = Gtk::manage (new CheckBox(M("TP_RAW_PIXELSHIFTLMMSE"), multiImage)); + pixelShiftLmmse->setCheckBoxListener (this); pixelShiftLmmse->set_tooltip_text (M("TP_RAW_PIXELSHIFTLMMSE_TOOLTIP")); pixelShiftOptions->pack_start(*pixelShiftLmmse); @@ -307,26 +325,9 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA 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 } @@ -335,9 +336,11 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params { disableListener (); method->block (true); - dcbEnhance->block (true); imageNumber->block (true); //allEnhconn.block (true); +#ifdef PIXELSHIFTDEV + pixelShiftMotionCorrection->block (true); +#endif method->set_active(procparams::RAWParams::BayerSensor::numMethods); imageNumber->set_active(pp->raw.bayersensor.imageNum); @@ -350,20 +353,75 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } } + //allEnhance->set_active(pp->raw.bayersensor.all_enhance); + + dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); + dcbEnhance->setValue (pp->raw.bayersensor.dcb_enhance); + pixelShiftShowMotion->setValue (pp->raw.bayersensor.pixelshiftShowMotion); + if (!batchMode) { + pixelShiftShowMotionMaskOnly->set_sensitive (pp->raw.bayersensor.pixelshiftShowMotion); + } + pixelShiftShowMotionMaskOnly->setValue (pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); + pixelShiftHoleFill->setValue (pp->raw.bayersensor.pixelShiftHoleFill); + pixelShiftMedian->setValue (pp->raw.bayersensor.pixelShiftMedian); + pixelShiftGreen->setValue (pp->raw.bayersensor.pixelShiftGreen); + pixelShiftBlur->setValue (pp->raw.bayersensor.pixelShiftBlur); + if (!batchMode) { + pixelShiftSmooth->set_sensitive (pp->raw.bayersensor.pixelShiftBlur); + } + pixelShiftSmooth->setValue (pp->raw.bayersensor.pixelShiftSmoothFactor); + pixelShiftLmmse->setValue (pp->raw.bayersensor.pixelShiftLmmse); + pixelShiftEqualBright->setValue (pp->raw.bayersensor.pixelShiftEqualBright); + pixelShiftNonGreenCross->setValue (pp->raw.bayersensor.pixelShiftNonGreenCross); + ccSteps->setValue (pp->raw.bayersensor.ccSteps); + lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); + pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); + pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); + pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); + if (!batchMode) { + pixelShiftSigma->set_sensitive (pp->raw.bayersensor.pixelShiftBlur); + } +#ifdef PIXELSHIFTDEV + pixelShiftStddevFactorGreen->setValue (pp->raw.bayersensor.pixelShiftStddevFactorGreen); + pixelShiftStddevFactorRed->setValue (pp->raw.bayersensor.pixelShiftStddevFactorRed); + pixelShiftStddevFactorBlue->setValue (pp->raw.bayersensor.pixelShiftStddevFactorBlue); + pixelShiftSum->setValue (pp->raw.bayersensor.pixelShiftSum); + pixelShiftMedian3->setValue (pp->raw.bayersensor.pixelShiftMedian3); + if (!batchMode) { + pixelShiftMedian3->set_sensitive (pixelShiftMedian->getValue() != CheckValue::off); + } + pixelShiftAutomatic->setValue (pp->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->setValue (pp->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->setValue (pp->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftExp0->setValue (pp->raw.bayersensor.pixelShiftExp0); + pixelShiftNonGreenCross2->setValue (pp->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->setValue (pp->raw.bayersensor.pixelShiftNonGreenAmaze); + pixelShiftMotion->setValue (pp->raw.bayersensor.pixelShiftMotion); + pixelShiftMotionCorrection->setValue ((int)pp->raw.bayersensor.pixelShiftMotionCorrection); + if (!batchMode) { + pixelShiftHoleFill->set_sensitive (pixelShiftAutomatic->getValue () != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftBlur->set_sensitive(pixelShiftAutomatic->getValue () != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftSmooth->set_sensitive(pixelShiftAutomatic->getValue () != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5 && pixelShiftBlur->getValue() != CheckValue::off); + } + pixelShiftNreadIso->setValue (pp->raw.bayersensor.pixelShiftNreadIso); + pixelShiftPrnu->setValue (pp->raw.bayersensor.pixelShiftPrnu); + pixelShiftRedBlueWeight->setValue (pp->raw.bayersensor.pixelShiftRedBlueWeight); +#endif + 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); - pixelShiftShowMotion->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotion); - pixelShiftShowMotionMaskOnly->set_inconsistent(!pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); - pixelShiftHoleFill->set_inconsistent(!pedited->raw.bayersensor.pixelShiftHoleFill); - pixelShiftMedian->set_inconsistent(!pedited->raw.bayersensor.pixelShiftMedian); - pixelShiftGreen->set_inconsistent(!pedited->raw.bayersensor.pixelShiftGreen); - pixelShiftBlur->set_inconsistent(!pedited->raw.bayersensor.pixelShiftBlur); + dcbEnhance->setEdited (pedited->raw.bayersensor.dcbEnhance); + pixelShiftShowMotion->setEdited (pedited->raw.bayersensor.pixelshiftShowMotion); + pixelShiftShowMotionMaskOnly->setEdited (pedited->raw.bayersensor.pixelshiftShowMotionMaskOnly); + pixelShiftHoleFill->setEdited (pedited->raw.bayersensor.pixelShiftHoleFill); + pixelShiftMedian->setEdited(pedited->raw.bayersensor.pixelShiftMedian); + pixelShiftGreen->setEdited (pedited->raw.bayersensor.pixelShiftGreen); + pixelShiftBlur->setEdited (pedited->raw.bayersensor.pixelShiftBlur); pixelShiftSmooth->setEditedState ( pedited->raw.bayersensor.pixelShiftSmooth ? Edited : UnEdited); - pixelShiftLmmse->set_inconsistent(!pedited->raw.bayersensor.pixelShiftLmmse); - pixelShiftEqualBright->set_inconsistent(!pedited->raw.bayersensor.pixelShiftEqualBright); - pixelShiftNonGreenCross->set_inconsistent(!pedited->raw.bayersensor.pixelShiftNonGreenCross); + pixelShiftLmmse->setEdited (pedited->raw.bayersensor.pixelShiftLmmse); + pixelShiftEqualBright->setEdited (pedited->raw.bayersensor.pixelShiftEqualBright); + pixelShiftNonGreenCross->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenCross); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); @@ -374,13 +432,13 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftStddevFactorRed->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorRed ? Edited : UnEdited); pixelShiftStddevFactorBlue->setEditedState ( pedited->raw.bayersensor.pixelShiftStddevFactorBlue ? 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); + pixelShiftAutomatic->setEdited (pedited->raw.bayersensor.pixelShiftAutomatic); + pixelShiftNonGreenHorizontal->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenHorizontal); + pixelShiftNonGreenVertical->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenVertical); + pixelShiftMedian3->setEdited (pedited->raw.bayersensor.pixelShiftMedian3); + pixelShiftExp0->setEdited (pedited->raw.bayersensor.pixelShiftExp0); + pixelShiftNonGreenCross2->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenCross2); + pixelShiftNonGreenAmaze->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenAmaze); pixelShiftMotion->setEditedState ( pedited->raw.bayersensor.pixelShiftMotion ? Edited : UnEdited); pixelShiftRedBlueWeight->setEditedState ( pedited->raw.bayersensor.pixelShiftRedBlueWeight ? Edited : UnEdited); #endif @@ -401,50 +459,6 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } } - //allEnhance->set_active(pp->raw.bayersensor.all_enhance); - - dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); - dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); - pixelShiftShowMotion->set_active(pp->raw.bayersensor.pixelshiftShowMotion); - pixelShiftShowMotionMaskOnly->set_sensitive(pp->raw.bayersensor.pixelshiftShowMotion); - pixelShiftShowMotionMaskOnly->set_active(pp->raw.bayersensor.pixelshiftShowMotionMaskOnly); - pixelShiftHoleFill->set_active(pp->raw.bayersensor.pixelShiftHoleFill); - pixelShiftMedian->set_active(pp->raw.bayersensor.pixelShiftMedian); - pixelShiftGreen->set_active(pp->raw.bayersensor.pixelShiftGreen); - pixelShiftBlur->set_active(pp->raw.bayersensor.pixelShiftBlur); - pixelShiftSmooth->set_sensitive (pp->raw.bayersensor.pixelShiftBlur); - pixelShiftSmooth->setValue (pp->raw.bayersensor.pixelShiftSmoothFactor); - pixelShiftLmmse->set_active(pp->raw.bayersensor.pixelShiftLmmse); - pixelShiftEqualBright->set_active(pp->raw.bayersensor.pixelShiftEqualBright); - pixelShiftNonGreenCross->set_active(pp->raw.bayersensor.pixelShiftNonGreenCross); - ccSteps->setValue (pp->raw.bayersensor.ccSteps); - lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); - pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); - pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); - pixelShiftSigma->set_sensitive (pp->raw.bayersensor.pixelShiftBlur); -#ifdef PIXELSHIFTDEV - pixelShiftStddevFactorGreen->setValue (pp->raw.bayersensor.pixelShiftStddevFactorGreen); - pixelShiftStddevFactorRed->setValue (pp->raw.bayersensor.pixelShiftStddevFactorRed); - pixelShiftStddevFactorBlue->setValue (pp->raw.bayersensor.pixelShiftStddevFactorBlue); - pixelShiftSum->setValue (pp->raw.bayersensor.pixelShiftSum); - 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) { @@ -479,26 +493,6 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params ccSteps->hide();*/ } - 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; method->block (false); @@ -506,7 +500,6 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftMotionCorrection->block (false); #endif imageNumber->block (false); - dcbEnhance->block (false); //allEnhconn.block (false); enableListener (); @@ -516,36 +509,36 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe { pp->raw.bayersensor.ccSteps = ccSteps->getIntValue(); pp->raw.bayersensor.dcb_iterations = dcbIterations->getIntValue(); - pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); - //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); + pp->raw.bayersensor.dcb_enhance = dcbEnhance->getLastActive (); + //pp->raw.bayersensor.all_enhance = allEnhance->getLastActive (); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::ePSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); pp->raw.bayersensor.pixelShiftSigma = pixelShiftSigma->getValue(); - pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->get_active(); - pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->get_active(); - pp->raw.bayersensor.pixelShiftHoleFill = pixelShiftHoleFill->get_active(); - pp->raw.bayersensor.pixelShiftMedian = pixelShiftMedian->get_active(); - pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->get_active(); - pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->get_active(); + pp->raw.bayersensor.pixelshiftShowMotion = pixelShiftShowMotion->getLastActive (); + pp->raw.bayersensor.pixelshiftShowMotionMaskOnly = pixelShiftShowMotionMaskOnly->getLastActive (); + pp->raw.bayersensor.pixelShiftHoleFill = pixelShiftHoleFill->getLastActive (); + pp->raw.bayersensor.pixelShiftMedian = pixelShiftMedian->getLastActive (); + pp->raw.bayersensor.pixelShiftGreen = pixelShiftGreen->getLastActive (); + pp->raw.bayersensor.pixelShiftBlur = pixelShiftBlur->getLastActive (); pp->raw.bayersensor.pixelShiftSmoothFactor = pixelShiftSmooth->getValue(); - pp->raw.bayersensor.pixelShiftLmmse = pixelShiftLmmse->get_active(); - pp->raw.bayersensor.pixelShiftEqualBright = pixelShiftEqualBright->get_active(); - pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->get_active(); + pp->raw.bayersensor.pixelShiftLmmse = pixelShiftLmmse->getLastActive (); + pp->raw.bayersensor.pixelShiftEqualBright = pixelShiftEqualBright->getLastActive (); + pp->raw.bayersensor.pixelShiftNonGreenCross = pixelShiftNonGreenCross->getLastActive (); #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.pixelShiftMedian3 = pixelShiftMedian3->getLastActive (); 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.pixelShiftAutomatic = pixelShiftAutomatic->getLastActive (); + pp->raw.bayersensor.pixelShiftNonGreenHorizontal = pixelShiftNonGreenHorizontal->getLastActive (); + pp->raw.bayersensor.pixelShiftNonGreenVertical = pixelShiftNonGreenVertical->getLastActive (); + pp->raw.bayersensor.pixelShiftExp0 = pixelShiftExp0->getLastActive (); + pp->raw.bayersensor.pixelShiftNonGreenCross2 = pixelShiftNonGreenCross2->getLastActive (); + pp->raw.bayersensor.pixelShiftNonGreenAmaze = pixelShiftNonGreenAmaze->getLastActive (); pp->raw.bayersensor.pixelShiftNreadIso = pixelShiftNreadIso->getValue(); pp->raw.bayersensor.pixelShiftPrnu = pixelShiftPrnu->getValue(); pp->raw.bayersensor.pixelShiftRedBlueWeight = pixelShiftRedBlueWeight->getValue(); @@ -610,15 +603,12 @@ void BayerProcess::setBatchMode(bool batchMode) method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name #ifdef PIXELSHIFTDEV pixelShiftMotionCorrection->append (M("GENERAL_UNCHANGED")); - pixelShiftMotionCorrection->set_active (4); + pixelShiftMotionCorrection->set_active_text (M("GENERAL_UNCHANGED")); #endif pixelShiftMotionMethod->append (M("GENERAL_UNCHANGED")); - pixelShiftMotionMethod->set_active (4); + pixelShiftMotionMethod->set_active_text (M("GENERAL_UNCHANGED")); imageNumber->append (M("GENERAL_UNCHANGED")); - imageNumber->set_active(4); - dcbOptions->hide(); - lmmseOptions->hide(); - pixelShiftOptions->hide(); + imageNumber->set_active_text (M("GENERAL_UNCHANGED")); ToolPanel::setBatchMode (batchMode); ccSteps->showEditedCB (); dcbIterations->showEditedCB (); @@ -730,14 +720,16 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) #ifdef PIXELSHIFTDEV 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 (!batchMode) { + if(pixelShiftMotionCorrection->get_active_row_number() == 5) { + pixelShiftBlur->set_sensitive(true); + pixelShiftHoleFill->set_sensitive(true); + pixelShiftSmooth->set_sensitive(pixelShiftBlur->getValue() != CheckValue::off); + } else { + pixelShiftBlur->set_sensitive(false); + pixelShiftHoleFill->set_sensitive(false); + pixelShiftSmooth->set_sensitive(false); + } } if (listener) { @@ -745,31 +737,34 @@ void BayerProcess::psMotionCorrectionChanged () } } #endif + void BayerProcess::methodChanged () { int curSelection = method->get_active_row_number(); - if ( curSelection == procparams::RAWParams::BayerSensor::dcb) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - - if ( curSelection == procparams::RAWParams::BayerSensor::lmmse) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } - - if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift) { - if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Custom) { - pixelShiftOptions->show(); + if (!batchMode) { + if ( curSelection == procparams::RAWParams::BayerSensor::dcb) { + dcbOptions->show(); } else { - pixelShiftOptions->hide(); + dcbOptions->hide(); + } + + if ( curSelection == procparams::RAWParams::BayerSensor::lmmse) { + lmmseOptions->show(); + } else { + lmmseOptions->hide(); + } + + if ( curSelection == procparams::RAWParams::BayerSensor::pixelshift) { + if(pixelShiftMotionMethod->get_active_row_number() == 2) { + pixelShiftOptions->show(); + } else { + pixelShiftOptions->hide(); + } + pixelShiftFrame->show(); + } else { + pixelShiftFrame->hide(); } - pixelShiftFrame->show(); - } else { - pixelShiftFrame->hide(); } Glib::ustring methodName = ""; @@ -797,390 +792,136 @@ void BayerProcess::imageNumberChanged () } } -void BayerProcess::dcbEnhanceChanged () +void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) { - if (batchMode) { - if (dcbEnhance->get_inconsistent()) { - dcbEnhance->set_inconsistent (false); - dcbEnhance->block (true); - dcbEnhance->set_active (false); - dcbEnhance->block (false); - } else if (dcbEnhance->getLastActive()) { - dcbEnhance->set_inconsistent (true); + if (c == dcbEnhance) { + if (listener) { + listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->getValueAsStr ()); + } + } else if (c == pixelShiftShowMotion) { + if (!batchMode) { + pixelShiftShowMotionMaskOnly->set_sensitive(newval != CheckValue::off); + } + if (listener) { + listener->panelChanged (EvPixelshiftShowMotion, pixelShiftShowMotion->getValueAsStr ()); + } + } else if (c == pixelShiftShowMotionMaskOnly) { + if (listener) { + listener->panelChanged (EvPixelshiftShowMotionMaskOnly, pixelShiftShowMotionMaskOnly->getValueAsStr ()); + } + } else if (c == pixelShiftHoleFill) { + if (listener) { + listener->panelChanged (EvPixelShiftHoleFill, pixelShiftHoleFill->getValueAsStr ()); + } + } else if (c == pixelShiftMedian) { +#ifdef PIXELSHIFTDEV + if (!batchMode) { + pixelShiftMedian3->set_sensitive(newval != CheckValue::off); + } +#endif + if (listener) { + listener->panelChanged (EvPixelShiftMedian, pixelShiftMedian->getValueAsStr ()); + } + } else if (c == pixelShiftGreen) { + if (listener) { + listener->panelChanged (EvPixelShiftGreen, pixelShiftGreen->getValueAsStr ()); + } + } else if (c == pixelShiftBlur) { + if (!batchMode) { + pixelShiftSmooth->set_sensitive(newval != CheckValue::off); + pixelShiftSigma->set_sensitive(newval != CheckValue::off); + } + if (listener) { + listener->panelChanged (EvPixelShiftBlur, pixelShiftBlur->getValueAsStr ()); + } + } else if (c == pixelShiftLmmse) { + if (listener) { + listener->panelChanged (EvPixelShiftLmmse, pixelShiftLmmse->getValueAsStr ()); + } + } else if (c == pixelShiftEqualBright) { + if (listener) { + listener->panelChanged (EvPixelShiftEqualBright, pixelShiftEqualBright->getValueAsStr ()); + } + } else if (c == pixelShiftNonGreenCross) { + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenCross, pixelShiftNonGreenCross->getValueAsStr ()); + } + } +#ifdef PIXELSHIFTDEV + else if (c == pixelShiftAutomatic) { + if (!batchMode) { + pixelShiftMotion->set_sensitive(!newval != CheckValue::off); + pixelShiftEperIso->set_sensitive(newval != CheckValue::off); + pixelShiftNreadIso->set_sensitive(newval != CheckValue::off); + pixelShiftPrnu->set_sensitive(newval != CheckValue::off); + pixelShiftSigma->set_sensitive(newval != CheckValue::off); + pixelShiftSum->set_sensitive(newval != CheckValue::off); + pixelShiftRedBlueWeight->set_sensitive(newval != CheckValue::off); + pixelShiftStddevFactorGreen->set_sensitive(newval != CheckValue::off); + pixelShiftStddevFactorRed->set_sensitive(newval != CheckValue::off); + pixelShiftStddevFactorBlue->set_sensitive(newval != CheckValue::off); + pixelShiftNonGreenHorizontal->set_sensitive(newval != CheckValue::off); + pixelShiftNonGreenVertical->set_sensitive(newval != CheckValue::off); + pixelShiftHoleFill->set_sensitive(newval != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftMedian3->set_sensitive(newval != CheckValue::off && pixelShiftMedian->getValue () != CheckValue::off); + pixelShiftGreen->set_sensitive(newval != CheckValue::off); + pixelShiftBlur->set_sensitive(newval != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5); + pixelShiftSmooth->set_sensitive(newval != CheckValue::off && pixelShiftMotionCorrection->get_active_row_number() == 5 && pixelShiftBlur->getValue () != CheckValue::off); + pixelShiftExp0->set_sensitive(newval != CheckValue::off); + pixelShiftNonGreenCross->set_sensitive(newval != CheckValue::off); + pixelShiftNonGreenCross2->set_sensitive(newval != CheckValue::off); + pixelShiftNonGreenAmaze->set_sensitive(newval != CheckValue::off); } - dcbEnhance->setLastActive(); - } - - if (listener) { - listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (listener) { + listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->getValueAsStr ()); + } + } else if (c == pixelShiftNonGreenHorizontal) { + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenHorizontal, pixelShiftNonGreenHorizontal->getValueAsStr ()); + } + } else if (c == pixelShiftNonGreenVertical) { + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenVertical, pixelShiftNonGreenVertical->getValueAsStr ()); + } + } else if (c == pixelShiftMedian3) { + if (listener) { + listener->panelChanged (EvPixelShiftMedian3, pixelShiftMedian3->getValueAsStr ()); + } + } else if (c == pixelShiftExp0) { + if (listener) { + listener->panelChanged (EvPixelShiftExp0, pixelShiftExp0->getValueAsStr ()); + } + } else if (c == pixelShiftNonGreenCross2) { + if (listener) { + listener->panelChanged (EvPixelShiftGreenAmaze, pixelShiftNonGreenCross2->getValueAsStr ()); + } + } else if (c == pixelShiftNonGreenAmaze) { + if (listener) { + listener->panelChanged (EvPixelShiftNonGreenAmaze, pixelShiftNonGreenAmaze->getValueAsStr ()); + } } +#endif } void BayerProcess::pixelShiftMotionMethodChanged () { - if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Off) { - pixelShiftOptions->hide(); - pixelShiftShowMotion->hide(); - pixelShiftShowMotionMaskOnly->hide(); - } else if(pixelShiftMotionMethod->get_active_row_number() == RAWParams::BayerSensor::ePSMotionCorrectionMethod::Custom) { - pixelShiftOptions->show(); - pixelShiftShowMotion->show(); - pixelShiftShowMotionMaskOnly->show(); - } else { - pixelShiftOptions->hide(); - pixelShiftShowMotion->show(); - pixelShiftShowMotionMaskOnly->show(); + if (!batchMode) { + 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) { - if (pixelShiftShowMotion->get_inconsistent()) { - pixelShiftShowMotion->set_inconsistent (false); - pixelShiftShowMotion->block (true); - pixelShiftShowMotion->set_active (false); - pixelShiftShowMotion->block (false); - } else if (pixelShiftShowMotion->getLastActive()) { - pixelShiftShowMotion->set_inconsistent (true); - } - - pixelShiftShowMotion->setLastActive(); - } - pixelShiftShowMotionMaskOnly->set_sensitive(pixelShiftShowMotion->get_active ()); - if (listener) { - listener->panelChanged (EvPixelshiftShowMotion, pixelShiftShowMotion->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -void BayerProcess::pixelShiftShowMotionMaskOnlyChanged () -{ - if (batchMode) { - if (pixelShiftShowMotionMaskOnly->get_inconsistent()) { - pixelShiftShowMotionMaskOnly->set_inconsistent (false); - pixelShiftShowMotionMaskOnly->block (true); - pixelShiftShowMotionMaskOnly->set_active (false); - pixelShiftShowMotionMaskOnly->block (false); - } else if (pixelShiftShowMotionMaskOnly->getLastActive()) { - pixelShiftShowMotionMaskOnly->set_inconsistent (true); - } - - pixelShiftShowMotionMaskOnly->setLastActive(); - } - - if (listener) { - listener->panelChanged (EvPixelshiftShowMotionMaskOnly, pixelShiftShowMotionMaskOnly->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -#ifdef PIXELSHIFTDEV -void BayerProcess::pixelShiftAutomaticChanged () -{ - if (batchMode) { - if (pixelShiftAutomatic->get_inconsistent()) { - pixelShiftAutomatic->set_inconsistent (false); - pixelShiftAutomatic->block (true); - pixelShiftAutomatic->set_active (false); - pixelShiftAutomatic->block (false); - } else if (pixelShiftAutomatic->getLastActive()) { - pixelShiftAutomatic->set_inconsistent (true); - } - - pixelShiftAutomatic->setLastActive(); - } - pixelShiftMotion->set_sensitive(!pixelShiftAutomatic->get_active ()); - 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 () && pixelShiftMotionCorrection->get_active_row_number() == 5); - 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 ()); - pixelShiftNonGreenAmaze->set_sensitive(pixelShiftAutomatic->get_active ()); - - if (listener) { - listener->panelChanged (EvPixelShiftAutomatic, pixelShiftAutomatic->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -void BayerProcess::pixelShiftNonGreenHorizontalChanged () -{ - if (batchMode) { - if (pixelShiftNonGreenHorizontal->get_inconsistent()) { - pixelShiftNonGreenHorizontal->set_inconsistent (false); - pixelShiftNonGreenHorizontal->block (true); - pixelShiftNonGreenHorizontal->set_active (false); - pixelShiftNonGreenHorizontal->block (false); - } else if (pixelShiftNonGreenHorizontal->getLastActive()) { - pixelShiftNonGreenHorizontal->set_inconsistent (true); - } - - pixelShiftNonGreenHorizontal->setLastActive(); - } - - if (listener) { - listener->panelChanged (EvPixelShiftNonGreenHorizontal, pixelShiftNonGreenHorizontal->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -void BayerProcess::pixelShiftNonGreenVerticalChanged () -{ - if (batchMode) { - if (pixelShiftNonGreenVertical->get_inconsistent()) { - pixelShiftNonGreenVertical->set_inconsistent (false); - pixelShiftNonGreenVertical->block (true); - pixelShiftNonGreenVertical->set_active (false); - pixelShiftNonGreenVertical->block (false); - } else if (pixelShiftNonGreenVertical->getLastActive()) { - pixelShiftNonGreenVertical->set_inconsistent (true); - } - - 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); - pixelShiftHoleFill->block (true); - pixelShiftHoleFill->set_active (false); - pixelShiftHoleFill->block (false); - } else if (pixelShiftHoleFill->getLastActive()) { - pixelShiftHoleFill->set_inconsistent (true); - } - - pixelShiftHoleFill->setLastActive(); - } - - 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); - pixelShiftMedian->block (true); - pixelShiftMedian->set_active (false); - pixelShiftMedian->block (false); - } else if (pixelShiftMedian->getLastActive()) { - pixelShiftMedian->set_inconsistent (true); - } - - 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); - pixelShiftMedian3->block (true); - pixelShiftMedian3->set_active (false); - pixelShiftMedian3->block (false); - } else if (pixelShiftMedian3->getLastActive()) { - pixelShiftMedian3->set_inconsistent (true); - } - - 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); - pixelShiftGreen->block (true); - pixelShiftGreen->set_active (false); - pixelShiftGreen->block (false); - } else if (pixelShiftGreen->getLastActive()) { - pixelShiftGreen->set_inconsistent (true); - } - - pixelShiftGreen->setLastActive(); - } - - 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); - pixelShiftBlur->block (true); - pixelShiftBlur->set_active (false); - pixelShiftBlur->block (false); - } else if (pixelShiftBlur->getLastActive()) { - pixelShiftBlur->set_inconsistent (true); - } - - 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); - pixelShiftExp0->block (true); - pixelShiftExp0->set_active (false); - pixelShiftExp0->block (false); - } else if (pixelShiftExp0->getLastActive()) { - pixelShiftExp0->set_inconsistent (true); - } - - 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); - pixelShiftLmmse->block (true); - pixelShiftLmmse->set_active (false); - pixelShiftLmmse->block (false); - } else if (pixelShiftLmmse->getLastActive()) { - pixelShiftLmmse->set_inconsistent (true); - } - - pixelShiftLmmse->setLastActive(); - } - - if (listener) { - listener->panelChanged (EvPixelShiftLmmse, pixelShiftLmmse->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -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); - pixelShiftNonGreenCross->block (true); - pixelShiftNonGreenCross->set_active (false); - pixelShiftNonGreenCross->block (false); - } else if (pixelShiftNonGreenCross->getLastActive()) { - pixelShiftNonGreenCross->set_inconsistent (true); - } - - 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); - pixelShiftNonGreenCross2->block (true); - pixelShiftNonGreenCross2->set_active (false); - pixelShiftNonGreenCross2->block (false); - } else if (pixelShiftNonGreenCross2->getLastActive()) { - pixelShiftNonGreenCross2->set_inconsistent (true); - } - - pixelShiftNonGreenCross2->setLastActive(); - } - - 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); - pixelShiftNonGreenAmaze->block (true); - pixelShiftNonGreenAmaze->set_active (false); - pixelShiftNonGreenAmaze->block (false); - } else if (pixelShiftNonGreenAmaze->getLastActive()) { - pixelShiftNonGreenAmaze->set_inconsistent (true); - } - - 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 463e8fb58..9c2285951 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -21,11 +21,12 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" -class BayerProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class BayerProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel { protected: @@ -36,21 +37,21 @@ protected: Adjuster* ccSteps; Gtk::VBox *dcbOptions; Adjuster* dcbIterations; - MyCheckButton* dcbEnhance; + CheckBox* 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; + CheckBox* pixelShiftShowMotion; + CheckBox* pixelShiftShowMotionMaskOnly; + CheckBox* pixelShiftNonGreenCross; + CheckBox* pixelShiftGreen; + CheckBox* pixelShiftBlur; + CheckBox* pixelShiftHoleFill; + CheckBox* pixelShiftMedian; + CheckBox* pixelShiftLmmse; + CheckBox* pixelShiftEqualBright; Adjuster* pixelShiftSmooth; Adjuster* pixelShiftEperIso; Adjuster* pixelShiftSigma; @@ -58,13 +59,13 @@ protected: Adjuster* pixelShiftSum; Adjuster* pixelShiftMotion; MyComboBoxText* pixelShiftMotionCorrection; - MyCheckButton* pixelShiftAutomatic; - MyCheckButton* pixelShiftNonGreenHorizontal; - MyCheckButton* pixelShiftNonGreenVertical; - MyCheckButton* pixelShiftNonGreenCross2; - MyCheckButton* pixelShiftNonGreenAmaze; - MyCheckButton* pixelShiftExp0; - MyCheckButton* pixelShiftMedian3; + CheckBox* pixelShiftAutomatic; + CheckBox* pixelShiftNonGreenHorizontal; + CheckBox* pixelShiftNonGreenVertical; + CheckBox* pixelShiftNonGreenCross2; + CheckBox* pixelShiftNonGreenAmaze; + CheckBox* pixelShiftExp0; + CheckBox* pixelShiftMedian3; Adjuster* pixelShiftStddevFactorGreen; Adjuster* pixelShiftStddevFactorRed; Adjuster* pixelShiftStddevFactorBlue; @@ -84,27 +85,11 @@ public: void methodChanged (); void imageNumberChanged (); - void adjusterChanged (Adjuster* a, double newval); - void dcbEnhanceChanged(); - void pixelShiftShowMotionChanged(); - void pixelShiftShowMotionMaskOnlyChanged(); - void pixelShiftHoleFillChanged(); - void pixelShiftMedianChanged(); - void pixelShiftMedian3Changed(); - void pixelShiftGreenChanged(); - void pixelShiftBlurChanged(); - void pixelShiftLmmseChanged(); - void pixelShiftEqualBrightChanged(); - void pixelShiftNonGreenCrossChanged(); + void adjusterChanged (Adjuster* a, double newval); + void checkBoxToggled (CheckBox* c, CheckValue newval); void pixelShiftMotionMethodChanged(); #ifdef PIXELSHIFTDEV void psMotionCorrectionChanged (); - void pixelShiftAutomaticChanged(); - void pixelShiftNonGreenHorizontalChanged(); - void pixelShiftNonGreenVerticalChanged(); - void pixelShiftExp0Changed(); - void pixelShiftNonGreenCross2Changed(); - void pixelShiftNonGreenAmazeChanged(); #endif }; diff --git a/rtgui/checkbox.cc b/rtgui/checkbox.cc new file mode 100644 index 000000000..3c8d0d3e0 --- /dev/null +++ b/rtgui/checkbox.cc @@ -0,0 +1,162 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include + +#include "multilangmgr.h" +#include "checkbox.h" +#include "guiutils.h" + +CheckBox::CheckBox (Glib::ustring label, bool const& multiImageVal) + : Gtk::CheckButton (label) + , listener (nullptr) + , lastActive (false) + , inBatchMode (false) + , multiImage (multiImageVal) +{ + conn = signal_toggled().connect( sigc::mem_fun(*this, &CheckBox::buttonToggled) ); +} + +void CheckBox::buttonToggled () +{ + + CheckValue newValue; + + if (multiImage) { + if (get_inconsistent()) { + set_inconsistent (false); + ConnectionBlocker bloker (conn); + set_active (false); + newValue = CheckValue::off; + } else if (getLastActive()) { + set_inconsistent (true); + newValue = CheckValue::unchanged; + } + } else { + newValue = get_active () ? CheckValue::on : CheckValue::off; + } + setLastActive(); + + if (listener) { + listener->checkBoxToggled(this, newValue); + } +} + +void CheckBox::setLastActive() +{ + lastActive = get_active(); +} + +// return the actual bool value, ignoring the inconsistent state +bool CheckBox::getLastActive () +{ + return lastActive; +} + +void CheckBox::setValue (CheckValue newValue) +{ + + ConnectionBlocker blocker (conn); + switch (newValue) { + case CheckValue::on: + set_inconsistent (false); + set_active(true); + lastActive = true; + break; + case CheckValue::off: + set_inconsistent (false); + set_active(true); + lastActive = false; + break; + case CheckValue::unchanged: + set_inconsistent (true); + break; + default: + break; + } +} + +void CheckBox::setValue (bool active) +{ + + ConnectionBlocker blocker (conn); + if (active) { + set_inconsistent (false); + set_active(true); + lastActive = true; + } else { + set_inconsistent (false); + set_active(true); + lastActive = false; + } +} + +CheckValue CheckBox::getValue () +{ + return (get_inconsistent() ? CheckValue::unchanged : get_active() ? CheckValue::on : CheckValue::off); +} + +Glib::ustring CheckBox::getValueAsStr () +{ + if (get_inconsistent()) { + return M("GENERAL_UNCHANGED"); + } else if (get_active ()) { + return M("GENERAL_ENABLED"); + } else { + return M("GENERAL_DISABLED"); + } +} + +/* +void CheckBox::set_sensitive (bool isSensitive) +{ + Gtk::CheckButton::set_sensitive(isSensitive); +} + +void CheckBox::set_tooltip_text (const Glib::ustring& tooltip) +{ + Gtk::CheckButton::set_tooltip_text (tooltip); +} + +void CheckBox::set_tooltip_markup (const Glib::ustring& tooltip) +{ + Gtk::CheckButton::set_tooltip_markup (tooltip); +} +*/ + +void CheckBox::setEdited (bool edited) +{ + + ConnectionBlocker blocker (conn); + set_inconsistent (!edited); + if (edited) { + set_active (lastActive); + } +} + +bool CheckBox::getEdited () +{ + + return !get_inconsistent (); +} + +void CheckBox::setCheckBoxListener (CheckBoxListener* cblistener) +{ + listener = cblistener; +} diff --git a/rtgui/checkbox.h b/rtgui/checkbox.h new file mode 100644 index 000000000..86d8e3622 --- /dev/null +++ b/rtgui/checkbox.h @@ -0,0 +1,78 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _CHECKBOX_H_ +#define _CHECKBOX_H_ + +#include +#include "editedstate.h" +#include "guiutils.h" + +class CheckBox; + +enum class CheckValue { + on, + off, + unchanged +}; + +class CheckBoxListener +{ + +public: + virtual ~CheckBoxListener() {}; + virtual void checkBoxToggled (CheckBox* c, CheckValue newval) {} +}; + + +/** + * @brief subclass of Gtk::CheckButton for convenience + */ +class CheckBox : public Gtk::CheckButton // Should ideally be private, but in this case build fail on the instantiation +{ + + CheckBoxListener *listener; + bool lastActive; + bool inBatchMode; + bool const& multiImage; + sigc::connection conn; + void buttonToggled (); + void setLastActive(); + +public: + //using CheckButton::CheckButton; + explicit CheckBox (Glib::ustring label, bool const& multiImageVal); + bool getLastActive(); + void setValue (CheckValue newValue); + void setValue (bool active); + CheckValue getValue (); + void setEdited (bool edited); + bool getEdited (); + Glib::ustring getValueAsStr (); + + void setCheckBoxListener (CheckBoxListener* cblistener); + + /* Used if the Gtk::CheckButton parent class can be private + * + void set_sensitive (bool isSensitive = true); + void set_tooltip_text (const Glib::ustring& tooltip); + void set_tooltip_markup (const Glib::ustring& tooltip); + */ +}; + +#endif diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 5601d28f3..f41e21b93 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -290,24 +290,6 @@ 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 */ @@ -341,8 +323,8 @@ public: MyComboBoxText (bool has_entry = false); void setPreferredWidth (int minimum_width, int natural_width); - void connect(const sigc::connection &connection) {myConnection = connection;}; - void block(bool blocked) {myConnection.block(blocked);}; + void connect(const sigc::connection &connection) { myConnection = connection; } + void block(bool blocked) { myConnection.block(blocked); } }; /** From bb518eeef826f8fbc2eacb48bf39c5bf696a8bdc Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 16 Mar 2017 13:34:11 +0100 Subject: [PATCH 095/110] Used new CheckBox in rawcacorrection; don't zero red and blue when autoca is enabled --- rtengine/CA_correct_RT.cc | 5 +-- rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtgui/rawcacorrection.cc | 76 ++++++++++---------------------------- rtgui/rawcacorrection.h | 10 ++--- 5 files changed, 29 insertions(+), 68 deletions(-) diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 97450a61a..fc9967619 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, array2D &rawData) +void RawImageSource::CA_correct_RT(const bool autoCA, const double cared, const double cablue, const double caautostrength, array2D &rawData) { // multithreaded and partly vectorized by Ingo Weyrich constexpr int ts = 128; @@ -134,7 +134,6 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons plistener->setProgress (progress); } - const bool autoCA = (cared == 0 && cablue == 0); // local variables const int width = W, height = H; //temporary array to store simple interpolation of G @@ -695,7 +694,7 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons //fitparams[polyord*i+j] gives the coefficients of (vblock^i hblock^j) in a polynomial fit for i,j<=4 } //end of initialization for CA correction pass - //only executed if cared and cablue are zero + //only executed if autoCA is true } // Main algorithm: Tile loop diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 71d1e10a1..38f0a260e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1980,10 +1980,10 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } 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]); + CA_correct_RT(raw.ca_autocorrect, raw.cared, raw.cablue, 10.0 - raw.caautostrength, *rawDataFrames[i]); } } else { - CA_correct_RT(raw.cared, raw.cablue, 10.0 - raw.caautostrength, rawData); + CA_correct_RT(raw.ca_autocorrect, raw.cared, raw.cablue, 10.0 - raw.caautostrength, rawData); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index cac29c138..0efa2b828 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -216,7 +216,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, array2D &rawData); + void CA_correct_RT (const bool autoCA, 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, array2D &rawData); // exposure before interpolation diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index d619ab112..01dccb39c 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -18,7 +18,6 @@ */ #include "rawcacorrection.h" #include "guiutils.h" -#include #include "rtimage.h" using namespace rtengine; @@ -31,7 +30,8 @@ RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_CHROM Gtk::Image* icablueL = Gtk::manage (new RTImage ("ajd-ca-blue1.png")); Gtk::Image* icablueR = Gtk::manage (new RTImage ("ajd-ca-blue2.png")); - caAutocorrect = Gtk::manage(new Gtk::CheckButton((M("TP_RAWCACORR_AUTO")))); + caAutocorrect = Gtk::manage (new CheckBox(M("TP_RAWCACORR_AUTO"), multiImage)); + caAutocorrect->setCheckBoxListener (this); caStrength = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CASTR"), 2.0, 8.0, 0.5, 6.0)); caStrength->setAdjusterListener (this); @@ -62,40 +62,35 @@ RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_CHROM pack_start( *caRed, Gtk::PACK_SHRINK, 4); pack_start( *caBlue, Gtk::PACK_SHRINK, 4); - caacsconn = caAutocorrect->signal_toggled().connect ( sigc::mem_fun(*this, &RAWCACorr::caCorrectionChanged), true); } void RAWCACorr::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - caacsconn.block (true); if(pedited ) { - caAutocorrect->set_inconsistent(!pedited->raw.caCorrection); + caAutocorrect->setEdited(pedited->raw.caCorrection); caStrength->setEditedState( pedited->raw.caAutoStrength ? Edited : UnEdited ); caRed->setEditedState( pedited->raw.caRed ? Edited : UnEdited ); caBlue->setEditedState( pedited->raw.caBlue ? Edited : UnEdited ); } - lastCA = pp->raw.ca_autocorrect; - caStrength->set_sensitive(pp->raw.ca_autocorrect); // disable Red and Blue sliders when caAutocorrect is enabled caRed->set_sensitive(!pp->raw.ca_autocorrect); caBlue->set_sensitive(!pp->raw.ca_autocorrect); - caAutocorrect->set_active(pp->raw.ca_autocorrect); + caAutocorrect->setValue(pp->raw.ca_autocorrect); caStrength->setValue (pp->raw.caautostrength); caRed->setValue (pp->raw.cared); caBlue->setValue (pp->raw.cablue); - caacsconn.block (false); enableListener (); } void RAWCACorr::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { - pp->raw.ca_autocorrect = caAutocorrect->get_active(); + pp->raw.ca_autocorrect = caAutocorrect->getLastActive(); pp->raw.caautostrength = caStrength->getValue(); pp->raw.cared = caRed->getValue(); pp->raw.cablue = caBlue->getValue(); @@ -125,6 +120,21 @@ void RAWCACorr::adjusterChanged (Adjuster* a, double newval) } } +void RAWCACorr::checkBoxToggled (CheckBox* c, CheckValue newval) +{ + if (c == caAutocorrect) { + if (!batchMode) { + caStrength->set_sensitive(caAutocorrect->get_active ()); + // disable Red and Blue sliders when caAutocorrect is enabled + caRed->set_sensitive(!caAutocorrect->get_active ()); + caBlue->set_sensitive(!caAutocorrect->get_active ()); + } + if (listener) { + listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } + } +} + void RAWCACorr::setBatchMode(bool batchMode) { ToolPanel::setBatchMode (batchMode); @@ -150,52 +160,6 @@ void RAWCACorr::setDefaults(const rtengine::procparams::ProcParams* defParams, c } } -void RAWCACorr::caCorrectionChanged() -{ - if (batchMode) { - if (caAutocorrect->get_inconsistent()) { - caAutocorrect->set_inconsistent (false); - caacsconn.block (true); - caAutocorrect->set_active (false); - caacsconn.block (false); - } else if (lastCA) { - caAutocorrect->set_inconsistent (true); - } - - lastCA = caAutocorrect->get_active (); - - } - - /*else { - // For non batch mode, we disable the red and blue slider if caAutocorrect is true - if (caAutocorrect->get_active ()) { - caRed->set_sensitive(false); - caBlue->set_sensitive(false); - } - else { - caRed->set_sensitive(true); - caBlue->set_sensitive(true); - } - }*/ - - caStrength->set_sensitive(caAutocorrect->get_active ()); - // disable Red and Blue sliders when caAutocorrect is enabled - caRed->set_sensitive(!caAutocorrect->get_active ()); - caBlue->set_sensitive(!caAutocorrect->get_active ()); - - if (caAutocorrect->get_active ()) { - // set caRed and caBlue to 0 as RawImageSource::CA_correct_RT uses this as - // a condition for auto-CA correction. Alternative would be to change - // RawImageSource::CA_correct_RT and pass it ca_autocorrect value - caRed->setValue(0); - caBlue->setValue(0); - } - - if (listener) { - listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - void RAWCACorr::setAdjusterBehavior (bool caadd) { diff --git a/rtgui/rawcacorrection.h b/rtgui/rawcacorrection.h index 4edf9f9f2..a1873b2ad 100644 --- a/rtgui/rawcacorrection.h +++ b/rtgui/rawcacorrection.h @@ -21,19 +21,17 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "toolpanel.h" -#include "../rtengine/rawimage.h" -class RAWCACorr : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class RAWCACorr : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel { protected: - Gtk::CheckButton* caAutocorrect; + CheckBox* caAutocorrect; Adjuster* caStrength; Adjuster* caRed; Adjuster* caBlue; - bool lastCA; - sigc::connection caacsconn; public: @@ -47,7 +45,7 @@ public: void trimValues (rtengine::procparams::ProcParams* pp); void adjusterChanged (Adjuster* a, double newval); - void caCorrectionChanged (); + void checkBoxToggled (CheckBox* c, CheckValue newval); }; #endif From df37ab6b4c04c5e3c638d5cd7a21383a5585d2c3 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 16 Mar 2017 15:09:56 +0100 Subject: [PATCH 096/110] used new CheckBox class in bayerrawexposure.* --- rtgui/bayerrawexposure.cc | 52 ++++++++++++--------------------------- rtgui/bayerrawexposure.h | 12 +++------ rtgui/rawcacorrection.cc | 8 +++--- 3 files changed, 24 insertions(+), 48 deletions(-) diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index ee9b4fc4d..2194d1639 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -18,7 +18,6 @@ */ #include "bayerrawexposure.h" #include "guiutils.h" -#include using namespace rtengine; using namespace rtengine::procparams; @@ -57,9 +56,9 @@ BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposur } PexBlack0->show(); - PextwoGreen = Gtk::manage(new Gtk::CheckButton((M("TP_RAWEXPOS_TWOGREEN"))));// two green + PextwoGreen = Gtk::manage(new CheckBox(M("TP_RAWEXPOS_TWOGREEN"), multiImage));// two green PextwoGreen->set_active (true); - greenconn = PextwoGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerRAWExposure::GreenChanged)); + PextwoGreen->setCheckBoxListener (this); pack_start( *PexBlack1, Gtk::PACK_SHRINK, 0);//black R pack_start( *PexBlack0, Gtk::PACK_SHRINK, 0);//black G1 @@ -79,16 +78,13 @@ void BayerRAWExposure::read(const rtengine::procparams::ProcParams* pp, const Pa PexBlack3->setEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited ); } - greenconn.block (true); - PextwoGreen->set_active (pp->raw.bayersensor.twogreen); - greenconn.block (false); - lastPextwoGreen = pp->raw.bayersensor.twogreen; + PextwoGreen->setValue (pp->raw.bayersensor.twogreen); PexBlack0->setValue (pp->raw.bayersensor.black0);//black PexBlack1->setValue (pp->raw.bayersensor.black1);//black PexBlack2->setValue (pp->raw.bayersensor.black2);//black - if(!PextwoGreen->get_active()) { + if(!PextwoGreen->getLastActive()) { PexBlack3->setValue (pp->raw.bayersensor.black3); } else { PexBlack3->setValue (PexBlack0->getValue()); @@ -102,9 +98,9 @@ void BayerRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited pp->raw.bayersensor.black0 = PexBlack0->getValue();// black pp->raw.bayersensor.black1 = PexBlack1->getValue();// black pp->raw.bayersensor.black2 = PexBlack2->getValue();// black - pp->raw.bayersensor.twogreen = PextwoGreen->get_active(); + pp->raw.bayersensor.twogreen = PextwoGreen->getLastActive(); - if(PextwoGreen->get_active()) { + if(PextwoGreen->getLastActive()) { pp->raw.bayersensor.black3 = pp->raw.bayersensor.black0; // active or desactive 2 green together } else { pp->raw.bayersensor.black3 = PexBlack3->getValue(); @@ -126,7 +122,7 @@ void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval) Glib::ustring value = a->getTextValue(); if (a == PexBlack0) { - if(!PextwoGreen->get_active()) { + if(!PextwoGreen->getLastActive()) { listener->panelChanged (EvPreProcessExpBlackzero, value ); } else { listener->panelChanged (EvPreProcessExpBlackzero, value ); @@ -137,7 +133,7 @@ void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval) } else if (a == PexBlack2) { listener->panelChanged (EvPreProcessExpBlacktwo, value ); } else if (a == PexBlack3) { - if(!PextwoGreen->get_active()) { + if(!PextwoGreen->getLastActive()) { listener->panelChanged (EvPreProcessExpBlackthree, value ); } else { listener->panelChanged (EvPreProcessExpBlackthree, value ); @@ -146,33 +142,17 @@ void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval) } } } -void BayerRAWExposure::GreenChanged() + +void BayerRAWExposure::checkBoxToggled (CheckBox* c, CheckValue newval) { - if (batchMode) { - if (PextwoGreen->get_inconsistent()) { - PextwoGreen->set_inconsistent (false); - greenconn.block (true); - PextwoGreen->set_active (false); - greenconn.block (false); - } else if (lastPextwoGreen) { - PextwoGreen->set_inconsistent (true); + if (c == PextwoGreen) { + if (listener) { + listener->panelChanged (EvPreProcessExptwoGreen, PextwoGreen->getLastActive() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (PextwoGreen->getLastActive()) { + PexBlack3->setValue (PexBlack0->getValue());//two green together + } } - - lastPextwoGreen = PextwoGreen->get_active (); } - - if (listener) { - if (PextwoGreen->get_active()) { - listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_ENABLED")); - PexBlack3->setValue (PexBlack0->getValue());//two green together - } - - else { - listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_DISABLED")); - } - - } - } void BayerRAWExposure::setBatchMode(bool batchMode) diff --git a/rtgui/bayerrawexposure.h b/rtgui/bayerrawexposure.h index 733aafc25..5d51babbb 100644 --- a/rtgui/bayerrawexposure.h +++ b/rtgui/bayerrawexposure.h @@ -21,10 +21,10 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "toolpanel.h" -#include "../rtengine/rawimage.h" -class BayerRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class BayerRAWExposure : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel { protected: @@ -32,12 +32,8 @@ protected: Adjuster* PexBlack1; Adjuster* PexBlack2; Adjuster* PexBlack3; - bool lastPextwoGreen; - sigc::connection greenconn; - Gtk::CheckButton* PextwoGreen; + CheckBox* PextwoGreen; -private: -// Gtk::CheckButton* PextwoGreen; public: BayerRAWExposure (); @@ -46,8 +42,8 @@ public: void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); void setBatchMode (bool batchMode); void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void GreenChanged() ; void adjusterChanged (Adjuster* a, double newval); + void checkBoxToggled (CheckBox* c, CheckValue newval); void setAdjusterBehavior (bool pexblackadd); void trimValues (rtengine::procparams::ProcParams* pp); }; diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 01dccb39c..683dcc97f 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -124,13 +124,13 @@ void RAWCACorr::checkBoxToggled (CheckBox* c, CheckValue newval) { if (c == caAutocorrect) { if (!batchMode) { - caStrength->set_sensitive(caAutocorrect->get_active ()); + caStrength->set_sensitive(caAutocorrect->getLastActive ()); // disable Red and Blue sliders when caAutocorrect is enabled - caRed->set_sensitive(!caAutocorrect->get_active ()); - caBlue->set_sensitive(!caAutocorrect->get_active ()); + caRed->set_sensitive(!caAutocorrect->getLastActive ()); + caBlue->set_sensitive(!caAutocorrect->getLastActive ()); } if (listener) { - listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->getLastActive() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } } From fe026d2b0383173d75907cd59637b7c4a06d828a Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 16 Mar 2017 21:25:10 +0100 Subject: [PATCH 097/110] Updated copyright notes, no issue --- rtgui/checkbox.cc | 2 +- rtgui/checkbox.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/checkbox.cc b/rtgui/checkbox.cc index 3c8d0d3e0..22a03d816 100644 --- a/rtgui/checkbox.cc +++ b/rtgui/checkbox.cc @@ -1,7 +1,7 @@ /* * This file is part of RawTherapee. * - * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2017 Jean-Christophe FRISCH * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/rtgui/checkbox.h b/rtgui/checkbox.h index 86d8e3622..8745de6d3 100644 --- a/rtgui/checkbox.h +++ b/rtgui/checkbox.h @@ -1,7 +1,7 @@ /* * This file is part of RawTherapee. * - * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2017 Jean-Christophe FRISCH * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 3db29b206006cbf7ea974c616fc9b8f5de7f159d Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 16 Mar 2017 23:54:59 +0100 Subject: [PATCH 098/110] Fixed bug with raw ca-correction when pixelshift image was opened with amaze demosaic and then method was switched to pixelshift --- rtengine/rawimagesource.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 38f0a260e..9e63ce529 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1978,7 +1978,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]) { + if(numFrames == 4) { for(int i=0; i<4; ++i) { CA_correct_RT(raw.ca_autocorrect, raw.cared, raw.cablue, 10.0 - raw.caautostrength, *rawDataFrames[i]); } From 6f1438e09d604f1a668077f5a9f6ada25e53cbd6 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 17 Mar 2017 16:05:54 +0100 Subject: [PATCH 099/110] fixed bug in CheckBox::setValue (bool active) --- rtgui/checkbox.cc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/rtgui/checkbox.cc b/rtgui/checkbox.cc index 22a03d816..716802f0f 100644 --- a/rtgui/checkbox.cc +++ b/rtgui/checkbox.cc @@ -96,15 +96,9 @@ void CheckBox::setValue (bool active) { ConnectionBlocker blocker (conn); - if (active) { - set_inconsistent (false); - set_active(true); - lastActive = true; - } else { - set_inconsistent (false); - set_active(true); - lastActive = false; - } + set_inconsistent (false); + set_active(active); + lastActive = active; } CheckValue CheckBox::getValue () From 75895515f31298cbda95587b7d48226dc332dcde Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 17 Mar 2017 23:09:55 +0100 Subject: [PATCH 100/110] pixelshift: don't generate demosaiced motion replacement when motion correction is disabled --- rtengine/rawimagesource.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 9e63ce529..ca74921ca 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2159,7 +2159,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 } } - } else { + } else if(bayerParams.pixelShiftMotionCorrectionMethod != RAWParams::BayerSensor::Off) { if(bayerParams.pixelShiftLmmse) { lmmse_interpolate_omp(W, H, rawData, red, green, blue, raw.bayersensor.lmmse_iterations); } else { From 97caf21b5c79069529d177e0a7680c0bfa63d92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sat, 18 Mar 2017 11:57:29 +0100 Subject: [PATCH 101/110] PIMPLed and streamlined `ICCStore` (#3691) --- rtengine/FTblockDN.cc | 10 +- rtengine/clutstore.cc | 6 +- rtengine/curves.cc | 4 +- rtengine/dcp.cc | 6 +- rtengine/iccstore.cc | 1422 ++++++++++++++++++--------------- rtengine/iccstore.h | 201 ++--- rtengine/imagefloat.cc | 2 +- rtengine/imageio.cc | 2 +- rtengine/imageio.h | 2 +- rtengine/improccoordinator.cc | 4 +- rtengine/improcfun.cc | 30 +- rtengine/init.cc | 4 +- rtengine/iplab2rgb.cc | 10 +- rtengine/ipvibrance.cc | 2 +- rtengine/ipwavelet.cc | 2 +- rtengine/rawimagesource.cc | 18 +- rtengine/rtengine.h | 7 - rtengine/rtthumbnail.cc | 6 +- rtengine/simpleprocess.cc | 16 +- rtengine/stdimagesource.cc | 10 +- rtgui/editorpanel.cc | 8 +- rtgui/icmpanel.cc | 10 +- 22 files changed, 941 insertions(+), 841 deletions(-) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 6bb0c4c3c..b50320631 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -497,7 +497,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef if (useNoiseLCurve || useNoiseCCurve) { int hei = calclum->height; int wid = calclum->width; - TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wprofi = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); const float wpi[3][3] = { {static_cast(wprofi[0][0]), static_cast(wprofi[0][1]), static_cast(wprofi[0][2])}, @@ -764,7 +764,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef } } - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); //inverse matrix user select const float wip[3][3] = { {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, @@ -772,7 +772,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef {static_cast(wiprof[2][0]), static_cast(wiprof[2][1]), static_cast(wiprof[2][2])} }; - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, @@ -3117,7 +3117,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat float** bcalc; hei = provicalc->height; wid = provicalc->width; - TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wprofi = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); const float wpi[3][3] = { {static_cast(wprofi[0][0]), static_cast(wprofi[0][1]), static_cast(wprofi[0][2])}, @@ -3192,7 +3192,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 9e9958418..7a5f6fd19 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -2,10 +2,12 @@ #include "clutstore.h" +#include "iccstore.h" +#include "imagefloat.h" #include "opthelper.h" #include "rt_math.h" -#include "imagefloat.h" #include "stdimagesource.h" + #include "../rtgui/options.h" namespace @@ -284,7 +286,7 @@ void rtengine::HaldCLUT::splitClutFilename( profile_name = "sRGB"; if (!name.empty()) { - for (const auto& working_profile : rtengine::getWorkingProfiles()) { + for (const auto& working_profile : rtengine::ICCStore::getWorkingProfiles()) { if ( !working_profile.empty() // This isn't strictly needed, but an empty wp name should be skipped anyway && std::search(name.rbegin(), name.rend(), working_profile.rbegin(), working_profile.rend()) == name.rbegin() diff --git a/rtengine/curves.cc b/rtengine/curves.cc index cf2fd0d04..8f2aa03d3 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -2140,7 +2140,7 @@ void PerceptualToneCurve::initApplyState(PerceptualToneCurveState & state, Glib: state.isProphoto = true; } else { state.isProphoto = false; - TMatrix Work = iccStore->workingSpaceMatrix(workingSpace); + TMatrix Work = ICCStore::getInstance()->workingSpaceMatrix(workingSpace); memset(state.Working2Prophoto, 0, sizeof(state.Working2Prophoto)); for (int i = 0; i < 3; i++) @@ -2149,7 +2149,7 @@ void PerceptualToneCurve::initApplyState(PerceptualToneCurveState & state, Glib: state.Working2Prophoto[i][j] += prophoto_xyz[i][k] * Work[k][j]; } - Work = iccStore->workingSpaceInverseMatrix (workingSpace); + Work = ICCStore::getInstance()->workingSpaceInverseMatrix (workingSpace); memset(state.Prophoto2Working, 0, sizeof(state.Prophoto2Working)); for (int i = 0; i < 3; i++) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index b97f913e7..2914fcd74 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -997,7 +997,7 @@ void DCPProfile::apply( ) const { - const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); + const TMatrix work_matrix = ICCStore::getInstance()->workingSpaceInverseMatrix(working_space); const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix @@ -1119,7 +1119,7 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use as_out.data->already_pro_photo = false; TMatrix mWork; - mWork = iccStore->workingSpaceMatrix (working_space); + mWork = ICCStore::getInstance()->workingSpaceMatrix (working_space); memset(as_out.data->pro_photo, 0, sizeof(as_out.data->pro_photo)); for (int i = 0; i < 3; i++) @@ -1128,7 +1128,7 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use as_out.data->pro_photo[i][j] += prophoto_xyz[i][k] * mWork[k][j]; } - mWork = iccStore->workingSpaceInverseMatrix (working_space); + mWork = ICCStore::getInstance()->workingSpaceInverseMatrix (working_space); memset(as_out.data->work, 0, sizeof(as_out.data->work)); for (int i = 0; i < 3; i++) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 7bc21d5d4..bfb08e472 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -1,12 +1,12 @@ /* * This file is part of RawTherapee. * - * Copyright (c) 2004-2010 Gabor Horvath + * Copyright(c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + *(at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,149 +16,161 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "iccstore.h" - #include +#include +#include + #ifdef WIN32 #include #else #include #endif -#include +#include "iccstore.h" #include "iccmatrices.h" +#include "procparams.h" #include "../rtgui/options.h" +#include "../rtgui/threadutils.h" namespace rtengine { + extern const Settings* settings; -// not recursive -void loadProfiles (const Glib::ustring& dirName, - std::map* profiles, - std::map* profileContents, - std::map* profileNames, - bool nameUpper) +} + +namespace { - if (dirName.empty ()) { + +// Not recursive +void loadProfiles( + const Glib::ustring& dirName, + std::map* profiles, + std::map* profileContents, + std::map* profileNames, + bool nameUpper +) +{ + if (dirName.empty()) { return; } try { + Glib::Dir dir(dirName); - Glib::Dir dir (dirName); - - for (Glib::DirIterator entry = dir.begin (); entry != dir.end (); ++entry) { - + for (Glib::DirIterator entry = dir.begin(); entry != dir.end(); ++entry) { const Glib::ustring fileName = *entry; - if (fileName.size () < 4) { + if (fileName.size() < 4) { continue; } - const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); + const Glib::ustring extension = rtengine::getFileExtension(fileName); - if (extension.compare (".icc") != 0 && extension.compare (".icm") != 0) { + if (extension != ".icc" && extension != ".icm") { continue; } - const Glib::ustring filePath = Glib::build_filename (dirName, fileName); + const Glib::ustring filePath = Glib::build_filename(dirName, fileName); - if (!Glib::file_test (filePath, Glib::FILE_TEST_IS_REGULAR)) { + if (!Glib::file_test(filePath, Glib::FILE_TEST_IS_REGULAR)) { continue; } - Glib::ustring name = fileName.substr (0, fileName.size() - 4); + Glib::ustring name = fileName.substr(0, fileName.size() - 4); if (nameUpper) { - name = name.uppercase (); + name = name.uppercase(); } if (profiles) { - const ProfileContent content (filePath); - const cmsHPROFILE profile = content.toProfile (); + const rtengine::ProfileContent content(filePath); + const cmsHPROFILE profile = content.toProfile(); if (profile) { - profiles->insert (std::make_pair (name, profile)); + profiles->emplace(name, profile); if (profileContents) { - profileContents->insert (std::make_pair (name, content)); + profileContents->emplace(name, content); } } } if (profileNames) { - profileNames->insert (std::make_pair (name, filePath)); + profileNames->emplace(name, filePath); } } - } catch (Glib::Exception&) {} + } catch (Glib::Exception&) { + } } -// version dedicated to single profile load when loadAll==false (cli version "-q" mode) -bool loadProfile (Glib::ustring profile, const Glib::ustring dirName, - std::map* profiles, - std::map* profileContents) +// Version dedicated to single profile load when loadAll==false (cli version "-q" mode) +bool loadProfile( + const Glib::ustring& profile, + const Glib::ustring& dirName, + std::map* profiles, + std::map* profileContents +) { - if (dirName.empty () || profiles == nullptr) { + if (dirName.empty() || profiles == nullptr) { return false; } try { + Glib::Dir dir(dirName); - Glib::Dir dir (dirName); - - for (Glib::DirIterator entry = dir.begin (); entry != dir.end (); ++entry) { - + for (Glib::DirIterator entry = dir.begin(); entry != dir.end(); ++entry) { const Glib::ustring fileName = *entry; - if (fileName.size () < 4) { + if (fileName.size() < 4) { continue; } - const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); + const Glib::ustring extension = rtengine::getFileExtension(fileName); - if (extension.compare (".icc") != 0 && extension.compare (".icm") != 0) { + if (extension != ".icc" && extension != ".icm") { continue; } - const Glib::ustring filePath = Glib::build_filename (dirName, fileName); + const Glib::ustring filePath = Glib::build_filename(dirName, fileName); - if (!Glib::file_test (filePath, Glib::FILE_TEST_IS_REGULAR)) { + if (!Glib::file_test(filePath, Glib::FILE_TEST_IS_REGULAR)) { continue; } - Glib::ustring name = fileName.substr (0, fileName.size() - 4); + const Glib::ustring name = fileName.substr(0, fileName.size() - 4); if (name == profile) { - const ProfileContent content (filePath); - const cmsHPROFILE profile = content.toProfile (); + const rtengine::ProfileContent content(filePath); + const cmsHPROFILE profile = content.toProfile(); if (profile) { - profiles->insert (std::make_pair (name, profile)); + profiles->emplace(name, profile); if (profileContents) { - profileContents->insert (std::make_pair (name, content)); + profileContents->emplace(name, content); } return true; } } } - } catch (Glib::Exception&) {} + } catch (Glib::Exception&) { + } return false; } -inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, uint8_t& result) +void getSupportedIntent(cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, uint8_t& result) { - if (cmsIsIntentSupported (profile, intent, direction)) { + if (cmsIsIntentSupported(profile, intent, direction)) { result |= 1 << intent; } } -inline uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) +uint8_t getSupportedIntents(cmsHPROFILE profile, cmsUInt32Number direction) { if (!profile) { return 0; @@ -166,22 +178,22 @@ inline uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number directi uint8_t result = 0; - getSupportedIntent (profile, INTENT_PERCEPTUAL, direction, result); - getSupportedIntent (profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); - getSupportedIntent (profile, INTENT_SATURATION, direction, result); - getSupportedIntent (profile, INTENT_ABSOLUTE_COLORIMETRIC, direction, result); + getSupportedIntent(profile, INTENT_PERCEPTUAL, direction, result); + getSupportedIntent(profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); + getSupportedIntent(profile, INTENT_SATURATION, direction, result); + getSupportedIntent(profile, INTENT_ABSOLUTE_COLORIMETRIC, direction, result); return result; } -inline cmsHPROFILE createXYZProfile () +cmsHPROFILE createXYZProfile() { double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0} }; - return ICCStore::createFromMatrix (mat, false, "XYZ"); + return rtengine::ICCStore::createFromMatrix(mat, false, "XYZ"); } -const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best, xyz_rec2020}; -const double (*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz, rec2020_xyz}; +const double(*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best, xyz_rec2020}; +const double(*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz, rec2020_xyz}; const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB", "Rec2020"}; const char* wpgamma[] = {"default", "BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "linear_g1.0", "standard_g2.2", "standard_g1.8", "High_g1.3_s3.35", "Low_g2.6_s6.9"}; //gamma free //default = gamma inside profile @@ -193,238 +205,566 @@ const char* wpgamma[] = {"default", "BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "line } -namespace rtengine +rtengine::ProfileContent::ProfileContent() = default; + +rtengine::ProfileContent::ProfileContent(const Glib::ustring& fileName) { + FILE* const f = g_fopen(fileName.c_str(), "rb"); -std::vector getGamma () -{ - - std::vector res; - - for (unsigned int i = 0; i < sizeof (wpgamma) / sizeof (wpgamma[0]); i++) { - res.push_back (wpgamma[i]); + if (!f) { + return; } - return res; + fseek(f, 0, SEEK_END); + const long length = ftell(f); + fseek(f, 0, SEEK_SET); + char* d = new char[length + 1]; + fread(d, length, 1, f); + d[length] = 0; + fclose(f); + + data.assign(d, length + 1); + delete[] d; } -std::vector getWorkingProfiles () +rtengine::ProfileContent::ProfileContent(cmsHPROFILE hProfile) { + if (hProfile != nullptr) { + cmsUInt32Number bytesNeeded = 0; + cmsSaveProfileToMem(hProfile, nullptr, &bytesNeeded); - std::vector res; - - for (unsigned int i = 0; i < sizeof (wpnames) / sizeof (wpnames[0]); i++) { - res.push_back (wpnames[i]); + if (bytesNeeded > 0) { + char* d = new char[bytesNeeded + 1]; + cmsSaveProfileToMem(hProfile, d, &bytesNeeded); + data.assign(d, bytesNeeded + 1); + delete[] d; + } } - - return res; } -std::vector ICCStore::getProfiles (const ProfileType type) const +cmsHPROFILE rtengine::ProfileContent::toProfile() const { - MyMutex::MyLock lock (mutex_); + return + !data.empty() + ? cmsOpenProfileFromMem(data.data(), data.size()) + : nullptr; +} - std::vector res; +const std::string& rtengine::ProfileContent::getData() const +{ + return data; +} - for (const auto profile : fileProfiles) { - if ( (type==ICCStore::ProfileType::MONITOR && cmsGetDeviceClass(profile.second) == cmsSigDisplayClass && cmsGetColorSpace (profile.second) == cmsSigRgbData) - || (type==ICCStore::ProfileType::PRINTER && cmsGetDeviceClass(profile.second) == cmsSigOutputClass) - || (type==ICCStore::ProfileType::OUTPUT && cmsGetDeviceClass(profile.second) == cmsSigDisplayClass && cmsGetColorSpace (profile.second) == cmsSigRgbData) ) - { - res.push_back (profile.first); +class rtengine::ICCStore::Implementation +{ +public: + Implementation() : + loadAll(true), + xyz(createXYZProfile()), + srgb(cmsCreate_sRGBProfile()) + { + //cmsErrorAction(LCMS_ERROR_SHOW); + + constexpr int N = sizeof(wpnames) / sizeof(wpnames[0]); + + for (int i = 0; i < N; ++i) { + wProfiles[wpnames[i]] = createFromMatrix(wprofiles[i]); + wProfilesGamma[wpnames[i]] = createFromMatrix(wprofiles[i], true); + wMatrices[wpnames[i]] = wprofiles[i]; + iwMatrices[wpnames[i]] = iwprofiles[i]; } } - return res; -} + void init(const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) + { + // Reads all profiles from the given profiles dir -std::vector ICCStore::getProfilesFromDir (const Glib::ustring& dirName) const -{ + MyMutex::MyLock lock(mutex); - MyMutex::MyLock lock (mutex_); + this->loadAll = loadAll; - std::vector res; + // RawTherapee's profiles take precedence if a user's profile of the same name exists + profilesDir = Glib::build_filename(rtICCDir, "output"); + userICCDir = usrICCDir; + fileProfiles.clear(); + fileProfileContents.clear(); + if (loadAll) { + loadProfiles(profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); + loadProfiles(userICCDir, &fileProfiles, &fileProfileContents, nullptr, false); + } - ProfileMap profiles; - - loadProfiles (profilesDir, &profiles, nullptr, nullptr, false); - loadProfiles (dirName, &profiles, nullptr, nullptr, false); - - for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) { - res.push_back (profile->first); - } - - return res; -} - -cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) -{ - // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma - if (!iprof) { - return nullptr; - } - - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem (iprof, nullptr, &bytesNeeded); - - if (bytesNeeded == 0) { - return nullptr; - } - - uint8_t *data = new uint8_t[bytesNeeded + 1]; - cmsSaveProfileToMem (iprof, data, &bytesNeeded); - const uint8_t *p = &data[128]; // skip 128 byte header - uint32_t tag_count; - memcpy (&tag_count, p, 4); - p += 4; - tag_count = ntohl (tag_count); - - struct icctag { - uint32_t sig; - uint32_t offset; - uint32_t size; - } tags[tag_count]; - - const uint32_t gamma = 0x239; - int gamma_size = (gamma == 0 || gamma == 256) ? 12 : 14; - int data_size = (gamma_size + 3) & ~3; - - for (uint32_t i = 0; i < tag_count; i++) { - memcpy (&tags[i], p, 12); - tags[i].sig = ntohl (tags[i].sig); - tags[i].offset = ntohl (tags[i].offset); - tags[i].size = ntohl (tags[i].size); - p += 12; - - if (tags[i].sig != 0x62545243 && // bTRC - tags[i].sig != 0x67545243 && // gTRC - tags[i].sig != 0x72545243 && // rTRC - tags[i].sig != 0x6B545243) { // kTRC - data_size += (tags[i].size + 3) & ~3; + // Input profiles + // Load these to different areas, since the short name(e.g. "NIKON D700" may overlap between system/user and RT dir) + stdProfilesDir = Glib::build_filename(rtICCDir, "input"); + fileStdProfiles.clear(); + fileStdProfilesFileNames.clear(); + if (loadAll) { + loadProfiles(stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); } } - uint32_t sz = 128 + 4 + tag_count * 12 + data_size; - uint8_t *nd = new uint8_t[sz]; - memset (nd, 0, sz); - memcpy (nd, data, 128 + 4); - sz = htonl (sz); - memcpy (nd, &sz, 4); - uint32_t offset = 128 + 4 + tag_count * 12; - uint32_t gamma_offset = 0; + void findDefaultMonitorProfile() + { + // Determine the first monitor default profile of operating system, if selected - for (uint32_t i = 0; i < tag_count; i++) { - struct icctag tag; - tag.sig = htonl (tags[i].sig); + defaultMonitorProfile.clear(); - if (tags[i].sig == 0x62545243 || // bTRC - tags[i].sig == 0x67545243 || // gTRC - tags[i].sig == 0x72545243 || // rTRC - tags[i].sig == 0x6B545243) { // kTRC - if (gamma_offset == 0) { - gamma_offset = offset; - uint32_t pcurve[] = { htonl(0x63757276), htonl(0), htonl(gamma_size == 12 ? 0U : 1U) }; - memcpy (&nd[offset], pcurve, 12); + #ifdef WIN32 + // Get current main monitor. Could be fine tuned to get the current windows monitor(multi monitor setup), + // but problem is that we live in RTEngine with no GUI window to query around + HDC hDC = GetDC(nullptr); - if (gamma_size == 14) { - uint16_t gm = htons (gamma); - memcpy (&nd[offset + 12], &gm, 2); + if (hDC != nullptr) { + if (SetICMMode(hDC, ICM_ON)) { + char profileName[MAX_PATH + 1]; + DWORD profileLength = MAX_PATH; + + if (GetICMProfileA(hDC, &profileLength, profileName)) { + defaultMonitorProfile = Glib::ustring(profileName); + defaultMonitorProfile = Glib::path_get_basename(defaultMonitorProfile); + size_t pos = defaultMonitorProfile.rfind("."); + + if (pos != Glib::ustring::npos) { + defaultMonitorProfile = defaultMonitorProfile.substr(0, pos); + } } - offset += (gamma_size + 3) & ~3; + // might fail if e.g. the monitor has no profile } - tag.offset = htonl (gamma_offset); - tag.size = htonl (gamma_size); - } else { - tag.offset = htonl (offset); - tag.size = htonl (tags[i].size); - memcpy (&nd[offset], &data[tags[i].offset], tags[i].size); - offset += (tags[i].size + 3) & ~3; + ReleaseDC(NULL, hDC); } - memcpy (&nd[128 + 4 + i * 12], &tag, 12); + #else + // TODO: Add other OS specific code here + #endif + + if (options.rtSettings.verbose) { + printf("Default monitor profile is: %s\n", defaultMonitorProfile.c_str()); + } } - cmsHPROFILE oprof = cmsOpenProfileFromMem (nd, ntohl (sz)); - delete [] nd; - delete [] data; - return oprof; -} - -ICCStore* ICCStore::getInstance () -{ - static ICCStore instance_; - return &instance_; -} - -ICCStore::ICCStore () : - loadAll(true), - xyz (createXYZProfile ()), - srgb (cmsCreate_sRGBProfile ()) -{ - //cmsErrorAction (LCMS_ERROR_SHOW); - - int N = sizeof (wpnames) / sizeof (wpnames[0]); - - for (int i = 0; i < N; i++) { - wProfiles[wpnames[i]] = createFromMatrix (wprofiles[i]); - wProfilesGamma[wpnames[i]] = createFromMatrix (wprofiles[i], true); - wMatrices[wpnames[i]] = wprofiles[i]; - iwMatrices[wpnames[i]] = iwprofiles[i]; + cmsHPROFILE getDefaultMonitorProfile() + { + return getProfile(defaultMonitorProfile); } + + Glib::ustring getDefaultMonitorProfileName() const + { + return defaultMonitorProfile; + } + + cmsHPROFILE workingSpace(const Glib::ustring& name) const + { + const ProfileMap::const_iterator r = wProfiles.find(name); + + return + r != wProfiles.end() + ? r->second + : wProfiles.find("sRGB")->second; + } + + cmsHPROFILE workingSpaceGamma(const Glib::ustring& name) const + { + + const ProfileMap::const_iterator r = wProfilesGamma.find(name); + + return + r != wProfilesGamma.end() + ? r->second + : wProfilesGamma.find("sRGB")->second; + } + + TMatrix workingSpaceMatrix(const Glib::ustring& name) const + { + const MatrixMap::const_iterator r = wMatrices.find(name); + + return + r != wMatrices.end() + ? r->second + : wMatrices.find("sRGB")->second; + } + + TMatrix workingSpaceInverseMatrix(const Glib::ustring& name) const + { + + const MatrixMap::const_iterator r = iwMatrices.find(name); + + return + r != iwMatrices.end() + ? r->second + : iwMatrices.find("sRGB")->second; + } + + bool outputProfileExist(const Glib::ustring& name) const + { + MyMutex::MyLock lock(mutex); + return fileProfiles.find(name) != fileProfiles.end(); + } + + cmsHPROFILE getProfile(const Glib::ustring& name) + { + MyMutex::MyLock lock(mutex); + + const ProfileMap::const_iterator r = fileProfiles.find(name); + + if (r != fileProfiles.end()) { + return r->second; + } + + if (!name.compare(0, 5, "file:")) { + const ProfileContent content(name.substr(5)); + const cmsHPROFILE profile = content.toProfile(); + + if (profile) { + fileProfiles.emplace(name, profile); + fileProfileContents.emplace(name, content); + + return profile; + } + } else if (!loadAll) { + // Look for a standard profile + if (!loadProfile(name, profilesDir, &fileProfiles, &fileProfileContents)) { + loadProfile(name, userICCDir, &fileProfiles, &fileProfileContents); + } + const ProfileMap::const_iterator r = fileProfiles.find(name); + if (r != fileProfiles.end()) { + return r->second; + } + } + + return nullptr; + } + + cmsHPROFILE getStdProfile(const Glib::ustring& name) + { + const Glib::ustring nameUpper = name.uppercase(); + + MyMutex::MyLock lock(mutex); + + const ProfileMap::const_iterator r = fileStdProfiles.find(nameUpper); + + // Return profile from store + if (r != fileStdProfiles.end()) { + return r->second; + } else if (!loadAll) { + // Directory not scanned, so looking and adding now... + if (!loadProfile(name, profilesDir, &fileProfiles, &fileProfileContents)) { + loadProfile(name, userICCDir, &fileProfiles, &fileProfileContents); + } + const ProfileMap::const_iterator r = fileProfiles.find(name); + if (r != fileProfiles.end()) { + return r->second; + } + } + + // Profile is not yet in store + const NameMap::const_iterator f = fileStdProfilesFileNames.find(nameUpper); + + // Profile does not exist + if (f == fileStdProfilesFileNames.end()) { + return nullptr; + } + + // But there exists one --> load it + const ProfileContent content(f->second); + const cmsHPROFILE profile = content.toProfile(); + + if (profile) { + fileStdProfiles.emplace(f->first, profile); + } + + // Profile invalid or stored now --> remove entry from fileStdProfilesFileNames + fileStdProfilesFileNames.erase(f); + return profile; + } + + ProfileContent getContent(const Glib::ustring& name) const + { + MyMutex::MyLock lock(mutex); + + const ContentMap::const_iterator r = fileProfileContents.find(name); + + return + r != fileProfileContents.end() + ? r->second + : ProfileContent(); + } + + cmsHPROFILE getXYZProfile() const + { + return xyz; + } + + cmsHPROFILE getsRGBProfile() const + { + return srgb; + } + + std::vector getProfiles(ProfileType type) const + { + std::vector res; + + MyMutex::MyLock lock(mutex); + + for (const auto profile : fileProfiles) { + if ( +( + type==ICCStore::ProfileType::MONITOR + && cmsGetDeviceClass(profile.second) == cmsSigDisplayClass + && cmsGetColorSpace(profile.second) == cmsSigRgbData + ) + ||( + type==ICCStore::ProfileType::PRINTER + && cmsGetDeviceClass(profile.second) == cmsSigOutputClass + ) + ||( + type==ICCStore::ProfileType::OUTPUT + && cmsGetDeviceClass(profile.second) == cmsSigDisplayClass + && cmsGetColorSpace(profile.second) == cmsSigRgbData + ) + ) { + res.push_back(profile.first); + } + } + + return res; + } + + std::vector getProfilesFromDir(const Glib::ustring& dirName) const + { + std::vector res; + ProfileMap profiles; + + MyMutex::MyLock lock(mutex); + + loadProfiles(profilesDir, &profiles, nullptr, nullptr, false); + loadProfiles(dirName, &profiles, nullptr, nullptr, false); + + for (const auto& profile : profiles) { + res.push_back(profile.first); + } + + return res; + } + + std::uint8_t getInputIntents(cmsHPROFILE profile) + { + MyMutex::MyLock lock(mutex); + + return getSupportedIntents(profile, LCMS_USED_AS_INPUT); + } + + std::uint8_t getOutputIntents(cmsHPROFILE profile) + { + MyMutex::MyLock lock(mutex); + + return getSupportedIntents(profile, LCMS_USED_AS_OUTPUT); + } + + std::uint8_t getProofIntents(cmsHPROFILE profile) + { + MyMutex::MyLock lock(mutex); + + return getSupportedIntents(profile, LCMS_USED_AS_PROOF); + } + + std::uint8_t getInputIntents(const Glib::ustring &name) + { + return getInputIntents(getProfile(name)); + } + + std::uint8_t getOutputIntents(const Glib::ustring &name) + { + return getOutputIntents(getProfile(name)); + } + + std::uint8_t getProofIntents(const Glib::ustring &name) + { + return getProofIntents(getProfile(name)); + } + +private: + using ProfileMap = std::map; + using MatrixMap = std::map; + using ContentMap = std::map; + using NameMap = std::map; + + ProfileMap wProfiles; + ProfileMap wProfilesGamma; + MatrixMap wMatrices; + MatrixMap iwMatrices; + + // These contain profiles from user/system directory(supplied on init) + Glib::ustring profilesDir; + Glib::ustring userICCDir; + ProfileMap fileProfiles; + ContentMap fileProfileContents; + + //These contain standard profiles from RT. Keys are all in uppercase. + Glib::ustring stdProfilesDir; + NameMap fileStdProfilesFileNames; + ProfileMap fileStdProfiles; + + Glib::ustring defaultMonitorProfile; + + bool loadAll; + + const cmsHPROFILE xyz; + const cmsHPROFILE srgb; + + mutable MyMutex mutex; +}; + +rtengine::ICCStore* rtengine::ICCStore::getInstance() +{ + static rtengine::ICCStore instance; + return &instance; } -TMatrix ICCStore::workingSpaceMatrix (const Glib::ustring& name) const +void rtengine::ICCStore::init(const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir, bool loadAll) +{ + implementation->init(usrICCDir, stdICCDir, loadAll); +} + +void rtengine::ICCStore::findDefaultMonitorProfile() +{ + implementation->findDefaultMonitorProfile(); +} + +cmsHPROFILE rtengine::ICCStore::getDefaultMonitorProfile() const +{ + return implementation->getDefaultMonitorProfile(); +} + +Glib::ustring rtengine::ICCStore::getDefaultMonitorProfileName() const +{ + return implementation->getDefaultMonitorProfileName(); +} + +cmsHPROFILE rtengine::ICCStore::workingSpace(const Glib::ustring& name) const +{ + return implementation->workingSpace(name); +} + +cmsHPROFILE rtengine::ICCStore::workingSpaceGamma(const Glib::ustring& name) const +{ + return implementation->workingSpaceGamma(name); +} + +rtengine::TMatrix rtengine::ICCStore::workingSpaceMatrix(const Glib::ustring& name) const +{ + return implementation->workingSpaceMatrix(name); +} + +rtengine::TMatrix rtengine::ICCStore::workingSpaceInverseMatrix(const Glib::ustring& name) const +{ + return implementation->workingSpaceInverseMatrix(name); +} + +bool rtengine::ICCStore::outputProfileExist(const Glib::ustring& name) const +{ + return implementation->outputProfileExist(name); +} + +cmsHPROFILE rtengine::ICCStore::getProfile(const Glib::ustring& name) const +{ + return implementation->getProfile(name); +} + +cmsHPROFILE rtengine::ICCStore::getStdProfile(const Glib::ustring& name) const +{ + return implementation->getStdProfile(name); +} + +rtengine::ProfileContent rtengine::ICCStore::getContent(const Glib::ustring& name) const +{ + return implementation->getContent(name); +} + +cmsHPROFILE rtengine::ICCStore::getXYZProfile() const +{ + return implementation->getXYZProfile(); +} + +cmsHPROFILE rtengine::ICCStore::getsRGBProfile() const +{ + return implementation->getXYZProfile(); +} + +std::vector rtengine::ICCStore::getProfiles(ProfileType type) const +{ + return implementation->getProfiles(type); +} + +std::vector rtengine::ICCStore::getProfilesFromDir(const Glib::ustring& dirName) const +{ + return implementation->getProfilesFromDir(dirName); +} + +std::uint8_t rtengine::ICCStore::getInputIntents(cmsHPROFILE profile) const +{ + return implementation->getInputIntents(profile); +} + +std::uint8_t rtengine::ICCStore::getOutputIntents(cmsHPROFILE profile) const +{ + return implementation->getOutputIntents(profile); +} + +std::uint8_t rtengine::ICCStore::getProofIntents(cmsHPROFILE profile) const +{ + return implementation->getProofIntents(profile); +} + +std::uint8_t rtengine::ICCStore::getInputIntents(const Glib::ustring& name) const +{ + return implementation->getInputIntents(name); +} + +std::uint8_t rtengine::ICCStore::getOutputIntents(const Glib::ustring& name) const +{ + return implementation->getOutputIntents(name); +} + +std::uint8_t rtengine::ICCStore::getProofIntents(const Glib::ustring& name) const +{ + return implementation->getProofIntents(name); +} + +rtengine::ICCStore::ICCStore() : + implementation(new Implementation) +{ +} + +rtengine::ICCStore::~ICCStore() = default; + +std::vector rtengine::ICCStore::getWorkingProfiles() { - const MatrixMap::const_iterator r = wMatrices.find (name); + std::vector res; - if (r != wMatrices.end()) { - return r->second; - } else { - return wMatrices.find ("sRGB")->second; + for (unsigned int i = 0; i < sizeof(wpnames) / sizeof(wpnames[0]); i++) { + res.push_back(wpnames[i]); } + + return res; } -TMatrix ICCStore::workingSpaceInverseMatrix (const Glib::ustring& name) const +std::vector rtengine::ICCStore::getGamma() { - const MatrixMap::const_iterator r = iwMatrices.find (name); + std::vector res; - if (r != iwMatrices.end()) { - return r->second; - } else { - return iwMatrices.find ("sRGB")->second; + for (unsigned int i = 0; i < sizeof(wpgamma) / sizeof(wpgamma[0]); i++) { + res.push_back(wpgamma[i]); } + + return res; } -cmsHPROFILE ICCStore::workingSpace (const Glib::ustring& name) const -{ - - const ProfileMap::const_iterator r = wProfiles.find (name); - - if (r != wProfiles.end()) { - return r->second; - } else { - return wProfiles.find ("sRGB")->second; - } -} - -cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const -{ - - const ProfileMap::const_iterator r = wProfilesGamma.find (name); - - if (r != wProfilesGamma.end()) { - return r->second; - } else { - return wProfilesGamma.find ("sRGB")->second; - } -} - -void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga) +void rtengine::ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga) { const double eps = 0.000000001; // not divide by zero if (!icm.freegamma) {//if Free gamma not selected @@ -454,19 +794,19 @@ void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Gamma ga[3] = 0.144928; ga[4] = 0.076332; } else if (icm.gamma == "standard_g2.2") { - ga[0] = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) + ga[0] = 2.2; //gamma=2.2(as gamma of Adobe, Widegamut...) ga[1] = 1.; ga[2] = 0.; ga[3] = 1. / eps; ga[4] = 0.; } else if (icm.gamma == "standard_g1.8") { - ga[0] = 1.8; //gamma=1.8 (as gamma of Prophoto) + ga[0] = 1.8; //gamma=1.8(as gamma of Prophoto) ga[1] = 1.; ga[2] = 0.; ga[3] = 1. / eps; ga[4] = 0.; } else /* if (icm.gamma == "linear_g1.0") */ { - ga[0] = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) + ga[0] = 1.0; //gamma=1 linear : for high dynamic images(cf : D.Coffin...) ga[1] = 1.; ga[2] = 0.; ga[3] = 1. / eps; @@ -485,8 +825,8 @@ void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Gamma ga[4] = g_a[3] * ts; //printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4); ga[0] = icm.gampos; - ga[1] = 1. / (1.0 + g_a[4]); - ga[2] = g_a[4] / (1.0 + g_a[4]); + ga[1] = 1. /(1.0 + g_a[4]); + ga[2] = g_a[4] /(1.0 + g_a[4]); ga[3] = 1. / slope; ga[5] = 0.0; ga[6] = 0.0; @@ -495,7 +835,197 @@ void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Gamma } // WARNING: the caller must lock lcmsMutex -cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { +cmsHPROFILE rtengine::ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) +{ + // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma + if (!iprof) { + return nullptr; + } + + cmsUInt32Number bytesNeeded = 0; + cmsSaveProfileToMem(iprof, nullptr, &bytesNeeded); + + if (bytesNeeded == 0) { + return nullptr; + } + + uint8_t *data = new uint8_t[bytesNeeded + 1]; + cmsSaveProfileToMem(iprof, data, &bytesNeeded); + const uint8_t *p = &data[128]; // skip 128 byte header + uint32_t tag_count; + memcpy(&tag_count, p, 4); + p += 4; + tag_count = ntohl(tag_count); + + struct icctag { + uint32_t sig; + uint32_t offset; + uint32_t size; + } tags[tag_count]; + + const uint32_t gamma = 0x239; + int gamma_size =(gamma == 0 || gamma == 256) ? 12 : 14; + int data_size =(gamma_size + 3) & ~3; + + for (uint32_t i = 0; i < tag_count; i++) { + memcpy(&tags[i], p, 12); + tags[i].sig = ntohl(tags[i].sig); + tags[i].offset = ntohl(tags[i].offset); + tags[i].size = ntohl(tags[i].size); + p += 12; + + if (tags[i].sig != 0x62545243 && // bTRC + tags[i].sig != 0x67545243 && // gTRC + tags[i].sig != 0x72545243 && // rTRC + tags[i].sig != 0x6B545243) { // kTRC + data_size +=(tags[i].size + 3) & ~3; + } + } + + uint32_t sz = 128 + 4 + tag_count * 12 + data_size; + uint8_t *nd = new uint8_t[sz]; + memset(nd, 0, sz); + memcpy(nd, data, 128 + 4); + sz = htonl(sz); + memcpy(nd, &sz, 4); + uint32_t offset = 128 + 4 + tag_count * 12; + uint32_t gamma_offset = 0; + + for (uint32_t i = 0; i < tag_count; i++) { + struct icctag tag; + tag.sig = htonl(tags[i].sig); + + if (tags[i].sig == 0x62545243 || // bTRC + tags[i].sig == 0x67545243 || // gTRC + tags[i].sig == 0x72545243 || // rTRC + tags[i].sig == 0x6B545243) { // kTRC + if (gamma_offset == 0) { + gamma_offset = offset; + uint32_t pcurve[] = { htonl(0x63757276), htonl(0), htonl(gamma_size == 12 ? 0U : 1U) }; + memcpy(&nd[offset], pcurve, 12); + + if (gamma_size == 14) { + uint16_t gm = htons(gamma); + memcpy(&nd[offset + 12], &gm, 2); + } + + offset +=(gamma_size + 3) & ~3; + } + + tag.offset = htonl(gamma_offset); + tag.size = htonl(gamma_size); + } else { + tag.offset = htonl(offset); + tag.size = htonl(tags[i].size); + memcpy(&nd[offset], &data[tags[i].offset], tags[i].size); + offset +=(tags[i].size + 3) & ~3; + } + + memcpy(&nd[128 + 4 + i * 12], &tag, 12); + } + + cmsHPROFILE oprof = cmsOpenProfileFromMem(nd, ntohl(sz)); + delete [] nd; + delete [] data; + return oprof; +} + +cmsHPROFILE rtengine::ICCStore::createFromMatrix(const double matrix[3][3], bool gamma, const Glib::ustring& name) +{ + + static const unsigned phead[] = { + 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, + 0x61637370, 0, 0, 0, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d + }; + unsigned pbody[] = { + 10, 0x63707274, 0, 36, /* cprt */ + 0x64657363, 0, 40, /* desc */ + 0x77747074, 0, 20, /* wtpt */ + 0x626b7074, 0, 20, /* bkpt */ + 0x72545243, 0, 14, /* rTRC */ + 0x67545243, 0, 14, /* gTRC */ + 0x62545243, 0, 14, /* bTRC */ + 0x7258595a, 0, 20, /* rXYZ */ + 0x6758595a, 0, 20, /* gXYZ */ + 0x6258595a, 0, 20 + }; /* bXYZ */ + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc };//D65 + //static const unsigned pwhite[] = { 0xf6d6, 0x10000, 0xd340 };//D50 + + // 0x63757276 : curveType, 0 : reserved, 1 : entries(1=gamma, 0=identity), 0x1000000=1.0 + unsigned pcurve[] = { 0x63757276, 0, 0, 0x1000000 }; +// unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; + + if (gamma) { + pcurve[2] = 1; + // pcurve[3] = 0x1f00000;// pcurve for gamma BT709 : g=2.22 s=4.5 + // normalize gamma in RT, default(Emil's choice = sRGB) + pcurve[3] = 0x2390000;//pcurve for gamma sRGB : g:2.4 s=12.92 + + } else { + // lcms2 up to 2.4 has a bug with linear gamma causing precision loss(banding) + // of floating point data when a normal icc encoding of linear gamma is used + //(i e 0 table entries), but by encoding a gamma curve which is 1.0 the + // floating point path is taken within lcms2 so no precision loss occurs and + // gamma is still 1.0. + pcurve[2] = 1; + pcurve[3] = 0x1000000; //pcurve for gamma 1 + } + + // constructing profile header + unsigned* oprof = new unsigned [phead[0] / sizeof(unsigned)]; + memset(oprof, 0, phead[0]); + memcpy(oprof, phead, sizeof(phead)); + + oprof[0] = 132 + 12 * pbody[0]; + + // constructing tag directory(pointers inside the file), and types + // 0x74657874 : text + // 0x64657363 : description tag + for (unsigned int i = 0; i < pbody[0]; i++) { + oprof[oprof[0] / 4] = i ?(i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; + pbody[i * 3 + 2] = oprof[0]; + oprof[0] +=(pbody[i * 3 + 3] + 3) & -4; + } + + memcpy(oprof + 32, pbody, sizeof(pbody)); + + // wtpt + memcpy((char *)oprof + pbody[8] + 8, pwhite, sizeof(pwhite)); + + // r/g/b TRC + for (int i = 4; i < 7; i++) { + memcpy((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof(pcurve)); + } + + // r/g/b XYZ +// pseudoinverse((double(*)[3]) out_rgb[output_color-1], inverse, 3); + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) { + oprof[pbody[j * 3 + 23] / 4 + i + 2] = matrix[i][j] * 0x10000 + 0.5; +// for (num = k=0; k < 3; k++) +// num += xyzd50_srgb[i][k] * inverse[j][k]; + } + + // convert to network byte order + for (unsigned int i = 0; i < phead[0] / 4; i++) { + oprof[i] = htonl(oprof[i]); + } + + // cprt + strcpy((char *)oprof + pbody[2] + 8, "--rawtherapee profile--"); + + // desc + oprof[pbody[5] / 4 + 2] = name.size() + 1; + strcpy((char *)oprof + pbody[5] + 12, name.c_str()); + + + cmsHPROFILE p = cmsOpenProfileFromMem(oprof, ntohl(oprof[0])); + delete [] oprof; + return p; +} + +cmsHPROFILE rtengine::ICCStore::createGammaProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) { float p[6]; //primaries ga[6] = 0.0; @@ -580,49 +1110,49 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam // 7 parameters for smoother curves cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ; - //lcmsMutex->lock (); Mutex acquired by the caller - cmsWhitePointFromTemp(&xyD, (double)temp); + //lcmsMutex->lock(); Mutex acquired by the caller + cmsWhitePointFromTemp(&xyD,(double)temp); GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, Parameters); //5 = smoother than 4 cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile cmsFreeToneCurve(GammaTRC[0]); - //lcmsMutex->unlock (); + //lcmsMutex->unlock(); return oprofdef; } // WARNING: the caller must lock lcmsMutex -cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { +cmsHPROFILE rtengine::ICCStore::createCustomGammaOutputProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) { bool pro = false; Glib::ustring outProfile; cmsHPROFILE outputProfile = nullptr; if (icm.freegamma && icm.gampos < 1.35) { pro = true; //select profil with gammaTRC modified : - } else if (icm.gamma == "linear_g1.0" || (icm.gamma == "High_g1.3_s3.35")) { + } else if (icm.gamma == "linear_g1.0" ||(icm.gamma == "High_g1.3_s3.35")) { pro = true; //pro=0 RT_sRGB || Prophoto } // Check that output profiles exist, otherwise use LCMS2 // Use the icc/icm profiles associated to possible working profiles, set in "options" - if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto) && !pro) { + if (icm.working == "ProPhoto" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.prophoto) && !pro) { outProfile = options.rtSettings.prophoto; - } else if (icm.working == "Adobe RGB" && iccStore->outputProfileExist(options.rtSettings.adobe) ) { + } else if (icm.working == "Adobe RGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.adobe) ) { outProfile = options.rtSettings.adobe; - } else if (icm.working == "WideGamut" && iccStore->outputProfileExist(options.rtSettings.widegamut) ) { + } else if (icm.working == "WideGamut" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.widegamut) ) { outProfile = options.rtSettings.widegamut; - } else if (icm.working == "Beta RGB" && iccStore->outputProfileExist(options.rtSettings.beta) ) { + } else if (icm.working == "Beta RGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.beta) ) { outProfile = options.rtSettings.beta; - } else if (icm.working == "BestRGB" && iccStore->outputProfileExist(options.rtSettings.best) ) { + } else if (icm.working == "BestRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.best) ) { outProfile = options.rtSettings.best; - } else if (icm.working == "BruceRGB" && iccStore->outputProfileExist(options.rtSettings.bruce) ) { + } else if (icm.working == "BruceRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.bruce) ) { outProfile = options.rtSettings.bruce; - } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb) && !pro) { + } else if (icm.working == "sRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.srgb) && !pro) { outProfile = options.rtSettings.srgb; - } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb10) && pro) { + } else if (icm.working == "sRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.srgb10) && pro) { outProfile = options.rtSettings.srgb10; - } else if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto10) && pro) { + } else if (icm.working == "ProPhoto" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.prophoto10) && pro) { outProfile = options.rtSettings.prophoto10; - } else if (icm.working == "Rec2020" && iccStore->outputProfileExist(options.rtSettings.rec2020) ) { + } else if (icm.working == "Rec2020" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.rec2020) ) { outProfile = options.rtSettings.rec2020; } else { // Should not occurs @@ -639,7 +1169,7 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str() } - outputProfile = iccStore->getProfile(outProfile); //get output profile + outputProfile = ICCStore::getInstance()->getProfile(outProfile); //get output profile if (outputProfile == nullptr) { @@ -687,7 +1217,7 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan // create description with gamma + slope + primaries std::wostringstream gammaWs; gammaWs.precision(2); - gammaWs << "Manual GammaTRC: g=" << (float)icm.gampos << " s=" << (float)icm.slpos; + gammaWs << "Manual GammaTRC: g=" <<(float)icm.gampos << " s=" <<(float)icm.slpos; cmsMLUsetWide(mlu, "en", "US", gammaWs.str().c_str()); } @@ -706,15 +1236,15 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan */ - cmsMLUfree (mlu); + cmsMLUfree(mlu); } // Calculate output profile's rTRC gTRC bTRC cmsToneCurve* GammaTRC = nullptr; GammaTRC = cmsBuildParametricToneCurve(nullptr, 5, Parameters); - cmsWriteTag(outputProfile, cmsSigRedTRCTag, (void*)GammaTRC ); - cmsWriteTag(outputProfile, cmsSigGreenTRCTag, (void*)GammaTRC ); - cmsWriteTag(outputProfile, cmsSigBlueTRCTag, (void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigRedTRCTag,(void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigGreenTRCTag,(void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigBlueTRCTag,(void*)GammaTRC ); if (GammaTRC) { cmsFreeToneCurve(GammaTRC); @@ -722,359 +1252,3 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan return outputProfile; } - -bool ICCStore::outputProfileExist (const Glib::ustring& name) const -{ - - MyMutex::MyLock lock(mutex_); - return fileProfiles.find(name) != fileProfiles.end(); -} - -cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) -{ - - MyMutex::MyLock lock (mutex_); - - const ProfileMap::const_iterator r = fileProfiles.find (name); - - if (r != fileProfiles.end ()) { - return r->second; - } - - if (name.compare (0, 5, "file:") == 0) { - const ProfileContent content (name.substr (5)); - const cmsHPROFILE profile = content.toProfile (); - - if (profile) { - const_cast (fileProfiles).insert (std::make_pair (name, profile)); - const_cast (fileProfileContents).insert (std::make_pair (name, content)); - - return profile; - } - } else if (!loadAll) { - // look for a standard profile - if (!loadProfile (name, profilesDir, &fileProfiles, &fileProfileContents)) { - loadProfile (name, userICCDir, &fileProfiles, &fileProfileContents); - } - const ProfileMap::const_iterator r = fileProfiles.find (name); - if (r != fileProfiles.end ()) { - return r->second; - } - } - - return nullptr; -} - -cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) -{ - - const Glib::ustring nameUpper = name.uppercase (); - - MyMutex::MyLock lock (mutex_); - - const ProfileMap::const_iterator r = fileStdProfiles.find (nameUpper); - - // return profile from store - if (r != fileStdProfiles.end ()) { - return r->second; - } else if (!loadAll) { - // directory not scanned, so looking and adding now... - if (!loadProfile (name, profilesDir, &fileProfiles, &fileProfileContents)) { - loadProfile (name, userICCDir, &fileProfiles, &fileProfileContents); - } - const ProfileMap::const_iterator r = fileProfiles.find (name); - if (r != fileProfiles.end ()) { - return r->second; - } - } - - // profile is not yet in store - const NameMap::const_iterator f = fileStdProfilesFileNames.find (nameUpper); - - // profile does not exist - if (f == fileStdProfilesFileNames.end ()) { - return nullptr; - } - - // but there exists one => load it - const ProfileContent content (f->second); - const cmsHPROFILE profile = content.toProfile (); - - if (profile) { - const_cast (fileStdProfiles).insert (std::make_pair (f->first, profile)); - } - - // profile is not valid or it is now stored => remove entry from fileStdProfilesFileNames - const_cast (fileStdProfilesFileNames).erase (f); - return profile; -} - -ProfileContent ICCStore::getContent (const Glib::ustring& name) const -{ - - MyMutex::MyLock lock (mutex_); - - const ContentMap::const_iterator r = fileProfileContents.find (name); - - return r != fileProfileContents.end () ? r->second : ProfileContent(); -} - -uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) -{ - MyMutex::MyLock lock (mutex_); - - return getSupportedIntents (profile, LCMS_USED_AS_INPUT); -} - -uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) -{ - MyMutex::MyLock lock (mutex_); - - return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); -} - -uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) -{ - MyMutex::MyLock lock (mutex_); - - return getSupportedIntents (profile, LCMS_USED_AS_PROOF); -} - -// Reads all profiles from the given profiles dir -void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) -{ - - MyMutex::MyLock lock (mutex_); - - this->loadAll = loadAll; - - // RawTherapee's profiles take precedence if a user's profile of the same name exists - profilesDir = Glib::build_filename (rtICCDir, "output"); - userICCDir = usrICCDir; - fileProfiles.clear(); - fileProfileContents.clear(); - if (loadAll) { - loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); - loadProfiles (userICCDir, &fileProfiles, &fileProfileContents, nullptr, false); - } - - // Input profiles - // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) - stdProfilesDir = Glib::build_filename (rtICCDir, "input"); - fileStdProfiles.clear(); - fileStdProfilesFileNames.clear(); - if (loadAll) { - loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); - } -} - -// Determine the first monitor default profile of operating system, if selected -void ICCStore::findDefaultMonitorProfile () -{ - defaultMonitorProfile.clear (); - -#ifdef WIN32 - // Get current main monitor. Could be fine tuned to get the current windows monitor (multi monitor setup), - // but problem is that we live in RTEngine with no GUI window to query around - HDC hDC = GetDC (NULL); - - if (hDC != NULL) { - if (SetICMMode (hDC, ICM_ON)) { - char profileName[MAX_PATH + 1]; - DWORD profileLength = MAX_PATH; - - if (GetICMProfileA (hDC, &profileLength, profileName)) { - defaultMonitorProfile = Glib::ustring (profileName); - defaultMonitorProfile = Glib::path_get_basename (defaultMonitorProfile); - size_t pos = defaultMonitorProfile.rfind ("."); - - if (pos != Glib::ustring::npos) { - defaultMonitorProfile = defaultMonitorProfile.substr (0, pos); - } - } - - // might fail if e.g. the monitor has no profile - } - - ReleaseDC (NULL, hDC); - } - -#else -// TODO: Add other OS specific code here -#endif - - if (options.rtSettings.verbose) { - printf ("Default monitor profile is: %s\n", defaultMonitorProfile.c_str()); - } -} - -ProfileContent::ProfileContent (const Glib::ustring& fileName) : data(nullptr), length(0) -{ - - FILE* f = g_fopen (fileName.c_str (), "rb"); - - if (!f) { - return; - } - - fseek (f, 0, SEEK_END); - length = ftell (f); - fseek (f, 0, SEEK_SET); - data = new char[length + 1]; - fread (data, length, 1, f); - data[length] = 0; - fclose (f); -} - -ProfileContent::ProfileContent (const ProfileContent& other) -{ - - length = other.length; - - if (other.data) { - data = new char[length + 1]; - memcpy (data, other.data, length + 1); - } else { - data = nullptr; - } -} - -ProfileContent::ProfileContent (cmsHPROFILE hProfile) : data(nullptr), length(0) -{ - - if (hProfile != nullptr) { - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem (hProfile, nullptr, &bytesNeeded); - - if (bytesNeeded > 0) { - data = new char[bytesNeeded + 1]; - cmsSaveProfileToMem (hProfile, data, &bytesNeeded); - length = (int)bytesNeeded; - } - } -} - - -ProfileContent& ProfileContent::operator= (const ProfileContent& other) -{ - - length = other.length; - - delete [] data; - - if (other.data) { - data = new char[length + 1]; - memcpy (data, other.data, length + 1); - } else { - data = nullptr; - } - - return *this; -} - -cmsHPROFILE ProfileContent::toProfile () const -{ - - if (data) { - return cmsOpenProfileFromMem (data, length); - } else { - return nullptr; - } -} - -cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, const Glib::ustring& name) -{ - - static const unsigned phead[] = { - 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, - 0x61637370, 0, 0, 0, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d - }; - unsigned pbody[] = { - 10, 0x63707274, 0, 36, /* cprt */ - 0x64657363, 0, 40, /* desc */ - 0x77747074, 0, 20, /* wtpt */ - 0x626b7074, 0, 20, /* bkpt */ - 0x72545243, 0, 14, /* rTRC */ - 0x67545243, 0, 14, /* gTRC */ - 0x62545243, 0, 14, /* bTRC */ - 0x7258595a, 0, 20, /* rXYZ */ - 0x6758595a, 0, 20, /* gXYZ */ - 0x6258595a, 0, 20 - }; /* bXYZ */ - static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc };//D65 - //static const unsigned pwhite[] = { 0xf6d6, 0x10000, 0xd340 };//D50 - - // 0x63757276 : curveType, 0 : reserved, 1 : entries (1=gamma, 0=identity), 0x1000000=1.0 - unsigned pcurve[] = { 0x63757276, 0, 0, 0x1000000 }; -// unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; - - if (gamma) { - pcurve[2] = 1; - // pcurve[3] = 0x1f00000;// pcurve for gamma BT709 : g=2.22 s=4.5 - // normalize gamma in RT, default (Emil's choice = sRGB) - pcurve[3] = 0x2390000;//pcurve for gamma sRGB : g:2.4 s=12.92 - - } else { - // lcms2 up to 2.4 has a bug with linear gamma causing precision loss (banding) - // of floating point data when a normal icc encoding of linear gamma is used - // (i e 0 table entries), but by encoding a gamma curve which is 1.0 the - // floating point path is taken within lcms2 so no precision loss occurs and - // gamma is still 1.0. - pcurve[2] = 1; - pcurve[3] = 0x1000000; //pcurve for gamma 1 - } - - // constructing profile header - unsigned* oprof = new unsigned [phead[0] / sizeof (unsigned)]; - memset (oprof, 0, phead[0]); - memcpy (oprof, phead, sizeof (phead)); - - oprof[0] = 132 + 12 * pbody[0]; - - // constructing tag directory (pointers inside the file), and types - // 0x74657874 : text - // 0x64657363 : description tag - for (unsigned int i = 0; i < pbody[0]; i++) { - oprof[oprof[0] / 4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; - pbody[i * 3 + 2] = oprof[0]; - oprof[0] += (pbody[i * 3 + 3] + 3) & -4; - } - - memcpy (oprof + 32, pbody, sizeof (pbody)); - - // wtpt - memcpy ((char *)oprof + pbody[8] + 8, pwhite, sizeof (pwhite)); - - // r/g/b TRC - for (int i = 4; i < 7; i++) { - memcpy ((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof (pcurve)); - } - - // r/g/b XYZ -// pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) { - oprof[pbody[j * 3 + 23] / 4 + i + 2] = matrix[i][j] * 0x10000 + 0.5; -// for (num = k=0; k < 3; k++) -// num += xyzd50_srgb[i][k] * inverse[j][k]; - } - - // convert to network byte order - for (unsigned int i = 0; i < phead[0] / 4; i++) { - oprof[i] = htonl (oprof[i]); - } - - // cprt - strcpy ((char *)oprof + pbody[2] + 8, "--rawtherapee profile--"); - - // desc - oprof[pbody[5] / 4 + 2] = name.size() + 1; - strcpy ((char *)oprof + pbody[5] + 12, name.c_str()); - - - cmsHPROFILE p = cmsOpenProfileFromMem (oprof, ntohl (oprof[0])); - delete [] oprof; - return p; -} - -} diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 5d8ccd5f0..9562f3144 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -1,12 +1,12 @@ /* * This file is part of RawTherapee. * - * Copyright (c) 2004-2010 Gabor Horvath + * Copyright(c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + *(at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,172 +16,103 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef __ICCSTORE__ -#define __ICCSTORE__ +#pragma once + +#include +#include +#include + +#include #include -#include -#include -#include -#include -#include "procparams.h" + #include "color.h" -#include "../rtgui/threadutils.h" namespace rtengine { -typedef const double (*TMatrix)[3]; +namespace procparams +{ + + class ColorManagementParams; + +} + +typedef const double(*TMatrix)[3]; class ProfileContent { - public: - char* data; - int length; + ProfileContent(); - ProfileContent (); - ~ProfileContent (); + explicit ProfileContent(const Glib::ustring& fileName); + explicit ProfileContent(cmsHPROFILE hProfile); + cmsHPROFILE toProfile() const; - ProfileContent (const ProfileContent& other); - ProfileContent& operator= (const rtengine::ProfileContent& other); + const std::string& getData() const; - explicit ProfileContent (const Glib::ustring& fileName); - explicit ProfileContent (cmsHPROFILE hProfile); - cmsHPROFILE toProfile () const; +private: + std::string data; }; class ICCStore { - typedef std::map ProfileMap; - typedef std::map MatrixMap; - typedef std::map ContentMap; - typedef std::map NameMap; - - ProfileMap wProfiles; - ProfileMap wProfilesGamma; - MatrixMap wMatrices; - MatrixMap iwMatrices; - - // these contain profiles from user/system directory (supplied on init) - Glib::ustring profilesDir; - Glib::ustring userICCDir; - ProfileMap fileProfiles; - ContentMap fileProfileContents; - - // these contain standard profiles from RT. keys are all in uppercase - Glib::ustring stdProfilesDir; - NameMap fileStdProfilesFileNames; - ProfileMap fileStdProfiles; - - Glib::ustring defaultMonitorProfile; - - bool loadAll; - - const cmsHPROFILE xyz; - const cmsHPROFILE srgb; - - mutable MyMutex mutex_; - - ICCStore (); - public: - enum class ProfileType { MONITOR, PRINTER, - OUTPUT // (actually correspond to the same profiles than with MONITOR) + OUTPUT //(actually correspond to the same profiles than with MONITOR) }; - static ICCStore* getInstance (); + static ICCStore* getInstance(); - void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir, bool loadAll); - - static void getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga); - static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); - static cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); - static cmsHPROFILE createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); - static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); + void init(const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir, bool loadAll); // Main monitors standard profile name, from OS - void findDefaultMonitorProfile (); - cmsHPROFILE getDefaultMonitorProfile (); - Glib::ustring getDefaultMonitorProfileName (); + void findDefaultMonitorProfile(); + cmsHPROFILE getDefaultMonitorProfile() const; + Glib::ustring getDefaultMonitorProfileName() const; - cmsHPROFILE workingSpace (const Glib::ustring& name) const; - cmsHPROFILE workingSpaceGamma (const Glib::ustring& name) const; - TMatrix workingSpaceMatrix (const Glib::ustring& name) const; - TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; + cmsHPROFILE workingSpace(const Glib::ustring& name) const; + cmsHPROFILE workingSpaceGamma(const Glib::ustring& name) const; + TMatrix workingSpaceMatrix(const Glib::ustring& name) const; + TMatrix workingSpaceInverseMatrix(const Glib::ustring& name) const; - bool outputProfileExist (const Glib::ustring& name) const; - cmsHPROFILE getProfile (const Glib::ustring& name); - cmsHPROFILE getStdProfile (const Glib::ustring& name); - ProfileContent getContent (const Glib::ustring& name) const; + bool outputProfileExist(const Glib::ustring& name) const; + cmsHPROFILE getProfile(const Glib::ustring& name) const; + cmsHPROFILE getStdProfile(const Glib::ustring& name) const; + ProfileContent getContent(const Glib::ustring& name) const; - cmsHPROFILE getXYZProfile () const; - cmsHPROFILE getsRGBProfile () const; + cmsHPROFILE getXYZProfile() const; + cmsHPROFILE getsRGBProfile() const; - std::vector getProfiles (const ProfileType type = ProfileType::MONITOR) const; - std::vector getProfilesFromDir (const Glib::ustring& dirName) const; + std::vector getProfiles(ProfileType type = ProfileType::MONITOR) const; + std::vector getProfilesFromDir(const Glib::ustring& dirName) const; - uint8_t getInputIntents (cmsHPROFILE profile); - uint8_t getOutputIntents (cmsHPROFILE profile); - uint8_t getProofIntents (cmsHPROFILE profile); + std::uint8_t getInputIntents(cmsHPROFILE profile) const; + std::uint8_t getOutputIntents(cmsHPROFILE profile) const; + std::uint8_t getProofIntents(cmsHPROFILE profile) const; - uint8_t getInputIntents (const Glib::ustring& name); - uint8_t getOutputIntents (const Glib::ustring& name); - uint8_t getProofIntents (const Glib::ustring& name); + std::uint8_t getInputIntents(const Glib::ustring& name) const; + std::uint8_t getOutputIntents(const Glib::ustring& name) const; + std::uint8_t getProofIntents(const Glib::ustring& name) const; + + static std::vector getWorkingProfiles(); + static std::vector getGamma(); + + static void getGammaArray(const procparams::ColorManagementParams& icm, GammaValues& ga); + static cmsHPROFILE makeStdGammaProfile(cmsHPROFILE iprof); + static cmsHPROFILE createFromMatrix(const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); + static cmsHPROFILE createGammaProfile(const procparams::ColorManagementParams& icm, GammaValues& ga); + static cmsHPROFILE createCustomGammaOutputProfile(const procparams::ColorManagementParams& icm, GammaValues& ga); + +private: + class Implementation; + + ICCStore(); + ~ICCStore(); + + const std::unique_ptr implementation; }; -#define iccStore ICCStore::getInstance() - -inline ProfileContent::ProfileContent () : - data(nullptr), - length(0) -{ } - -inline ProfileContent::~ProfileContent () -{ - delete [] data; -} - -inline cmsHPROFILE ICCStore::getDefaultMonitorProfile () -{ - return getProfile (defaultMonitorProfile); -} - -inline Glib::ustring ICCStore::getDefaultMonitorProfileName () -{ - return defaultMonitorProfile; -} - -inline uint8_t ICCStore::getInputIntents (const Glib::ustring &name) -{ - return getInputIntents (getProfile (name)); -} - -inline uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) -{ - return getOutputIntents (getProfile (name)); -} - -inline uint8_t ICCStore::getProofIntents (const Glib::ustring &name) -{ - return getProofIntents (getProfile (name)); -} - -inline cmsHPROFILE ICCStore::getXYZProfile () const -{ - return xyz; -} - -inline cmsHPROFILE ICCStore::getsRGBProfile () const -{ - return srgb; -} - -} - -#endif - diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index f4629682d..665ba3ac6 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -429,7 +429,7 @@ void Imagefloat::calcCroppedHistogram(const ProcParams ¶ms, float scale, LUT hist.clear(); // Set up factors to calc the lightness - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.working); float facRed = wprof[1][0]; float facGreen = wprof[1][1]; diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 05684aaa7..b8f2fb580 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -175,7 +175,7 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr iptc_data_sort (iptc); } -void ImageIO::setOutputProfile (char* pdata, int plen) +void ImageIO::setOutputProfile (const char* pdata, int plen) { delete [] profileData; diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 00bdbece1..1fbeb6e2d 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -176,7 +176,7 @@ public: void setMetadata (const rtexif::TagDirectory* eroot); void setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc); - void setOutputProfile (char* pdata, int plen); + void setOutputProfile (const char* pdata, int plen); MyMutex& mutex () { return imutex; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 46cf031bd..e5422f6b3 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -452,13 +452,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) opautili = false; if(params.colorToning.enabled) { - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.working); double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, {wprof[2][0], wprof[2][1], wprof[2][2]} }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params.icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 1a3a969ae..757b6e0b2 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -80,9 +80,9 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, cmsHPROFILE monitor = nullptr; if (!monitorProfile.empty()) { #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB - monitor = iccStore->getProfile (monitorProfile); + monitor = ICCStore::getInstance()->getProfile (monitorProfile); #else - monitor = iccStore->getProfile ("RT_sRGB"); + monitor = ICCStore::getInstance()->getProfile ("RT_sRGB"); #endif } @@ -97,7 +97,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, if (softProof) { cmsHPROFILE oprof = nullptr; if (!settings->printerProfile.empty()) { - oprof = iccStore->getProfile(settings->printerProfile); + oprof = ICCStore::getInstance()->getProfile(settings->printerProfile); } if (oprof) { @@ -137,7 +137,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) { - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.working); lumimul[0] = wprof[1][0]; lumimul[1] = wprof[1][1]; @@ -557,7 +557,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh #endif { //matrix for current working space - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, @@ -1287,7 +1287,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh #pragma omp parallel default(shared) firstprivate(lab,xw2,yw2,zw2,chr,yb,la2,yb2, height,width,begh, endh, nc2,f2,c2, gamu, highlight,pW) #endif { - TMatrix wiprofa = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprofa = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); double wipa[3][3] = { {wiprofa[0][0], wiprofa[0][1], wiprofa[0][2]}, {wiprofa[1][0], wiprofa[1][1], wiprofa[1][2]}, @@ -1891,7 +1891,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //matrix for current working space - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); const float wip[3][3] = { {(float)wiprof[0][0], (float)wiprof[0][1], (float)wiprof[0][2]}, {(float)wiprof[1][0], (float)wiprof[1][1], (float)wiprof[1][2]}, @@ -2986,8 +2986,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool processLCE = params->sh.enabled && shmap && params->sh.localcontrast > 0; double lceamount = params->sh.localcontrast / 200.0; - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); float toxyz[3][3] = { { @@ -3102,8 +3102,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer clutAndWorkingProfilesAreSame = hald_clut->getProfile() == params->icm.working; if ( !clutAndWorkingProfilesAreSame ) { - xyz2clut = iccStore->workingSpaceInverseMatrix( hald_clut->getProfile() ); - clut2xyz = iccStore->workingSpaceMatrix( hald_clut->getProfile() ); + xyz2clut = ICCStore::getInstance()->workingSpaceInverseMatrix( hald_clut->getProfile() ); + clut2xyz = ICCStore::getInstance()->workingSpaceMatrix( hald_clut->getProfile() ); #ifdef __SSE2__ @@ -5642,14 +5642,14 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu const bool gamutLch = settings->gamutLch; const float amountchroma = (float) settings->amchroma; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, @@ -6983,7 +6983,7 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace) { - TMatrix wprof = iccStore->workingSpaceMatrix( workingSpace ); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix( workingSpace ); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, @@ -7009,7 +7009,7 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: SSEFUNCTION void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) { - TMatrix wiprof = iccStore->workingSpaceInverseMatrix( workingSpace ); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix( workingSpace ); const float wip[3][3] = { {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, {static_cast(wiprof[1][0]), static_cast(wiprof[1][1]), static_cast(wiprof[1][2])}, diff --git a/rtengine/init.cc b/rtengine/init.cc index d6bba9f2b..8b270f1d7 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -40,8 +40,8 @@ MyMutex* lcmsMutex = nullptr; int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir, bool loadAll) { settings = s; - iccStore->init (s->iccDirectory, Glib::build_filename (baseDir, "iccprofiles"), loadAll); - iccStore->findDefaultMonitorProfile(); + ICCStore::getInstance()->init (s->iccDirectory, Glib::build_filename (baseDir, "iccprofiles"), loadAll); + ICCStore::getInstance()->findDefaultMonitorProfile(); DCPStore::getInstance()->init (Glib::build_filename (baseDir, "dcpprofiles"), loadAll); CameraConstantsStore::getInstance ()->init (baseDir, userSettingsDir); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index f970e3a54..dac24411d 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -158,7 +158,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, standard_gamma = false; } - cmsHPROFILE oprof = iccStore->getProfile (profile); + cmsHPROFILE oprof = ICCStore::getInstance()->getProfile (profile); if (oprof) { cmsHPROFILE oprofG = oprof; @@ -216,7 +216,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, } } else { - const auto xyz_rgb = iccStore->workingSpaceInverseMatrix (profile); + const auto xyz_rgb = ICCStore::getInstance()->workingSpaceInverseMatrix (profile); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) @@ -286,11 +286,11 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE oprof = nullptr; if (ga) { lcmsMutex->lock (); - iccStore->getGammaArray(icm, *ga); - oprof = iccStore->createGammaProfile(icm, *ga); + ICCStore::getInstance()->getGammaArray(icm, *ga); + oprof = ICCStore::getInstance()->createGammaProfile(icm, *ga); lcmsMutex->unlock (); } else { - oprof = iccStore->getProfile (icm.output); + oprof = ICCStore::getInstance()->getProfile (icm.output); } if (oprof) { diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 60994175b..8eb565434 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -170,7 +170,7 @@ void ImProcFunctions::vibrance (LabImage* lab) const bool protectskins = params->vibrance.protectskins; const bool avoidcolorshift = params->vibrance.avoidcolorshift; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); //inverse matrix user select const double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index ee8f10ad1..67402cac4 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -148,7 +148,7 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int // init variables to display Munsell corrections MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); #endif - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 6dd71a7e3..80e1f65ba 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1557,7 +1557,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool batch) imatrices.xyz_cam[i][j] += xyz_sRGB[i][k] * imatrices.rgb_cam[k][j]; } - camProfile = iccStore->createFromMatrix (imatrices.xyz_cam, false, "Camera"); + camProfile = ICCStore::getInstance()->createFromMatrix (imatrices.xyz_cam, false, "Camera"); inverse33 (imatrices.xyz_cam, imatrices.cam_xyz); for (int c = 0; c < 4; c++) { @@ -2168,7 +2168,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } } else { - TMatrix wprof = iccStore->workingSpaceMatrix (cmp.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (cmp.working); float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, @@ -2445,7 +2445,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } } else { - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (cmp.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (cmp.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, @@ -3802,7 +3802,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam // in this case we avoid using the slllllooooooowwww lcms // Calculate matrix for direct conversion raw>working space - TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); + TMatrix work = ICCStore::getInstance()->workingSpaceInverseMatrix (cmp.working); double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (int i = 0; i < 3; i++) @@ -3894,7 +3894,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam // Initialize transform cmsHTRANSFORM hTransform; - cmsHPROFILE prophoto = iccStore->workingSpace("ProPhoto"); // We always use Prophoto to apply the ICC profile to minimize problems with clipping in LUT conversion. + cmsHPROFILE prophoto = ICCStore::getInstance()->workingSpace("ProPhoto"); // We always use Prophoto to apply the ICC profile to minimize problems with clipping in LUT conversion. bool transform_via_pcs_lab = false; bool separate_pcs_lab_highlights = false; lcmsMutex->lock (); @@ -3940,8 +3940,8 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam TMatrix toxyz = {}, torgb = {}; if (!working_space_is_prophoto) { - toxyz = iccStore->workingSpaceMatrix ("ProPhoto"); - torgb = iccStore->workingSpaceInverseMatrix (cmp.working); //sRGB .. Adobe...Wide... + toxyz = ICCStore::getInstance()->workingSpaceMatrix ("ProPhoto"); + torgb = ICCStore::getInstance()->workingSpaceInverseMatrix (cmp.working); //sRGB .. Adobe...Wide... } #ifdef _OPENMP @@ -4154,7 +4154,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed *dcpProf = DCPStore::getInstance()->getStdProfile(camName); if (*dcpProf == nullptr) { - in = iccStore->getStdProfile(camName); + in = ICCStore::getInstance()->getStdProfile(camName); } } else if (inProfile != "(camera)" && inProfile != "") { Glib::ustring normalName = inProfile; @@ -4168,7 +4168,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed } if (*dcpProf == nullptr) { - in = iccStore->getProfile (inProfile); + in = ICCStore::getInstance()->getProfile (inProfile); } } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 43fcbf06f..f99df3fe3 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -442,13 +442,6 @@ int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDi /** Cleanup the RT engine (static variables) */ void cleanup (); -/** Returns the available working profile names - * @return a vector of the available working profile names */ -std::vector getWorkingProfiles (); -/** Returns the available output gammas - * @return a vector of the available gamma names */ -std::vector getGamma (); - /** This class holds all the necessary informations to accomplish the full processing of the image */ class ProcessingJob { diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 257a3eeb3..86729fce2 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -768,7 +768,7 @@ void Thumbnail::init () cam2xyz[i][j] += xyz_sRGB[i][k] * colorMatrix[k][j]; } - camProfile = iccStore->createFromMatrix (cam2xyz, false, "Camera"); + camProfile = ICCStore::getInstance()->createFromMatrix (cam2xyz, false, "Camera"); } Thumbnail::Thumbnail () : @@ -1029,13 +1029,13 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei bool opautili = false; if(params.colorToning.enabled) { - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.working); double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, {wprof[2][0], wprof[2][1], wprof[2][2]} }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params.icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 4fb193c2b..0f3aea0d0 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -805,13 +805,13 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p bool opautili = false; if(params.colorToning.enabled) { - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.working); double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, {wprof[2][0], wprof[2][1], wprof[2][2]} }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params.icm.working); double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, @@ -1165,7 +1165,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p //or selected Free gamma useLCMS = false; - if ((jprof = iccStore->createCustomGammaOutputProfile (params.icm, ga)) == nullptr) { + if ((jprof = ICCStore::getInstance()->createCustomGammaOutputProfile (params.icm, ga)) == nullptr) { useLCMS = true; } @@ -1221,15 +1221,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if (!useLCMS) { // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma ProfileContent pc(jprof); - readyImg->setOutputProfile (pc.data, pc.length); + readyImg->setOutputProfile(pc.getData().data(), pc.getData().size()); } } else { // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) { - // if iccStore->getProfile send back an object, then iccStore->getContent will do too - cmsHPROFILE jprof = iccStore->getProfile(params.icm.output); //get outProfile + // if ICCStore::getInstance()->getProfile send back an object, then ICCStore::getInstance()->getContent will do too + cmsHPROFILE jprof = ICCStore::getInstance()->getProfile(params.icm.output); //get outProfile if (jprof == nullptr) { if (settings->verbose) { @@ -1240,8 +1240,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p printf("Using \"%s\" output profile\n", params.icm.output.c_str()); } - ProfileContent pc = iccStore->getContent (params.icm.output); - readyImg->setOutputProfile (pc.data, pc.length); + ProfileContent pc = ICCStore::getInstance()->getContent (params.icm.output); + readyImg->setOutputProfile(pc.getData().data(), pc.getData().size()); } } else { // No ICM diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 95475e6a4..ed960508e 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -218,7 +218,7 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement bool skipTransform = false; cmsHPROFILE in = nullptr; - cmsHPROFILE out = iccStore->workingSpace (cmp.working); + cmsHPROFILE out = ICCStore::getInstance()->workingSpace (cmp.working); if (cmp.input == "(embedded)" || cmp.input == "" || cmp.input == "(camera)" || cmp.input == "(cameraICC)") { if (embedded) { @@ -227,12 +227,12 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT)) { skipTransform = true; } else { - in = iccStore->getsRGBProfile (); + in = ICCStore::getInstance()->getsRGBProfile (); } } } else { if (cmp.input != "(none)") { - in = iccStore->getProfile (cmp.input); + in = ICCStore::getInstance()->getProfile (cmp.input); if (in == nullptr && embedded) { in = embedded; @@ -240,7 +240,7 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT)) { skipTransform = true; } else { - in = iccStore->getsRGBProfile (); + in = ICCStore::getInstance()->getsRGBProfile (); } } } @@ -249,7 +249,7 @@ void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagement if (!skipTransform && in) { if(in == embedded && cmsGetColorSpace(in) != cmsSigRgbData) { // if embedded profile is not an RGB profile, use sRGB printf("embedded profile is not an RGB profile, using sRGB as input profile\n"); - in = iccStore->getsRGBProfile (); + in = ICCStore::getInstance()->getsRGBProfile (); } lcmsMutex->lock (); diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 8da176fc3..7bc1631d3 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -96,12 +96,12 @@ private: profileBox.append (M ("PREFERENCES_PROFILE_NONE")); #ifdef WIN32 - profileBox.append (M ("MONITOR_PROFILE_SYSTEM") + " (" + rtengine::iccStore->getDefaultMonitorProfileName() + ")"); + profileBox.append (M ("MONITOR_PROFILE_SYSTEM") + " (" + rtengine::ICCStore::getInstance()->getDefaultMonitorProfileName() + ")"); profileBox.set_active (options.rtSettings.autoMonitorProfile ? 1 : 0); #else profileBox.set_active (0); #endif - const std::vector profiles = rtengine::iccStore->getProfiles (rtengine::ICCStore::ProfileType::MONITOR); + const std::vector profiles = rtengine::ICCStore::getInstance()->getProfiles (rtengine::ICCStore::ProfileType::MONITOR); for (const auto profile: profiles) { profileBox.append (profile); } @@ -176,7 +176,7 @@ private: #if !defined(__APPLE__) // monitor profile not supported on apple #ifdef WIN32 if (profileBox.get_active_row_number () == 1) { - profile = rtengine::iccStore->getDefaultMonitorProfileName (); + profile = rtengine::ICCStore::getInstance()->getDefaultMonitorProfileName (); if (profile.empty ()) { profile = options.rtSettings.monitorProfile; } @@ -206,7 +206,7 @@ private: profileBox.set_tooltip_text (""); } else { - const uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const uint8_t supportedIntents = rtengine::ICCStore::getInstance()->getProofIntents (profile); const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; const bool supportsAbsoluteColorimetric = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 5b4883dce..232d626a0 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -166,7 +166,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch wnames = Gtk::manage (new MyComboBoxText ()); wVBox->pack_start (*wnames, Gtk::PACK_SHRINK); - std::vector wpnames = rtengine::getWorkingProfiles (); + std::vector wpnames = rtengine::ICCStore::getWorkingProfiles(); for (size_t i = 0; i < wpnames.size(); i++) { wnames->append (wpnames[i]); @@ -193,7 +193,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch onames->append (M("TP_ICM_NOICM")); onames->set_active (0); - std::vector opnames = iccStore->getProfiles (rtengine::ICCStore::ProfileType::OUTPUT); + std::vector opnames = ICCStore::getInstance()->getProfiles (rtengine::ICCStore::ProfileType::OUTPUT); for (size_t i = 0; i < opnames.size(); i++) { onames->append (opnames[i]); @@ -232,7 +232,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch oVBox->pack_start(*gaHBox, Gtk::PACK_EXPAND_WIDGET); - std::vector wpgamma = rtengine::getGamma (); + std::vector wpgamma = rtengine::ICCStore::getGamma(); for (size_t i = 0; i < wpgamma.size(); i++) { wgamma->append (wpgamma[i]); @@ -332,7 +332,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch } void ICMPanel::updateRenderingIntent (const Glib::ustring &profile) { - const uint8_t supportedIntents = rtengine::iccStore->getOutputIntents (profile); + const uint8_t supportedIntents = rtengine::ICCStore::getInstance()->getOutputIntents (profile); const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; const bool supportsRelative = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; const bool supportsSaturation = supportedIntents & 1 << INTENT_SATURATION; @@ -1033,7 +1033,7 @@ void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) iembedded->set_active (!raw); icamera->set_sensitive (raw); camName = pMeta->getCamera(); - icameraICC->set_sensitive (raw && (iccStore->getStdProfile(pMeta->getCamera()) != nullptr || DCPStore::getInstance()->getStdProfile(pMeta->getCamera()) != nullptr)); + icameraICC->set_sensitive (raw && (ICCStore::getInstance()->getStdProfile(pMeta->getCamera()) != nullptr || DCPStore::getInstance()->getStdProfile(pMeta->getCamera()) != nullptr)); iembedded->set_sensitive (!raw); enableListener (); From 5349fea8c136a452845fd9b40c0d691bdfbf6c98 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 18 Mar 2017 15:15:20 +0100 Subject: [PATCH 102/110] pixelshift: moved code from rawimagesource.cc to pixelshift.cc and fixed a bug --- rtengine/pixelshift.cc | 148 ++++++++++++++++++++++++++++++++++++- rtengine/rawimagesource.cc | 135 +-------------------------------- 2 files changed, 146 insertions(+), 137 deletions(-) diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 41e1c9af2..0ef4f6b6b 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -30,6 +30,7 @@ #include "../rtgui/multilangmgr.h" #include "procparams.h" #include "gauss.h" +#include "median.h" #define BENCHMARK #include "StopWatch.h" @@ -307,11 +308,151 @@ void floodFill4(int xStart, int xEnd, int yStart, int yEnd, array2D &ma using namespace std; using namespace rtengine; -void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParams, unsigned int frame, const std::string &model, float rawWpCorrection) +void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RAWParams::BayerSensor &bayerParamsIn, unsigned int frame, const std::string &model, float rawWpCorrection) { #ifdef PIXELSHIFTDEV BENCHFUN #endif + + if(numFrames != 4) { // fallback for non pixelshift files + amaze_demosaic_RT (0, 0, winw, winh, rawData, red, green, blue); + return; + } + + RAWParams::BayerSensor bayerParams = bayerParamsIn; + +#ifndef PIXELSHIFTDEV + bayerParams.pixelShiftAutomatic = true; +#endif + + 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; + bayerParams.pixelshiftShowMotion = false; + } + + if((bayerParams.pixelShiftMotion > 0 || bayerParams.pixelShiftAutomatic)) { + if(bayerParams.pixelShiftMedian) { // We need the amaze demosaiced frames for motion correction +#ifdef PIXELSHIFTDEV + if(!bayerParams.pixelShiftMedian3) { +#endif + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, winw, winh, *(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++) { + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i+1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, winw, winh, *(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) { + if(bayerParams.pixelShiftLmmse) { + lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i]), redTmp[frameIndex], greenTmp[frameIndex], blueTmp[frameIndex], raw.bayersensor.lmmse_iterations); + } else { + amaze_demosaic_RT (0, 0, winw, winh, *(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;i 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 { - 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++) { - 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 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) { - 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; - } - } - 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); - } + pixelshift(0, 0, W, H, raw.bayersensor, 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); } else if (raw.bayersensor.method == RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::eahd]) { From 7134f36cda406d70b424a3c52a329cf963388758 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 18 Mar 2017 17:37:54 +0100 Subject: [PATCH 103/110] Add new high ISO values for Pentax KP --- rtexif/pentaxattribs.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc index 13dca86b1..e18be36cd 100644 --- a/rtexif/pentaxattribs.cc +++ b/rtexif/pentaxattribs.cc @@ -372,6 +372,12 @@ public: choices[37] = "128000"; choices[38] = "160000"; choices[39] = "204800"; + choices[40] = "256000"; + choices[41] = "320000"; + choices[42] = "409600"; + choices[43] = "512000"; + choices[44] = "640000"; + choices[45] = "819200"; choices[50] = "50"; choices[100] = "100"; choices[200] = "200"; From ace00a8c8d0c31fe83e0d40b7de391f13af83fc9 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 18 Mar 2017 18:16:58 +0100 Subject: [PATCH 104/110] Added raw crop for PENTAX KP --- rtengine/camconst.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index f506a190e..679c7a134 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1768,6 +1768,11 @@ Camera constants: "ranges": { "white": 4080 } // nominal at ISO200 4094 }, + { // Quality C, only Raw crop + "make_model": [ "RICOH PENTAX KP", "PENTAX KP" ], + "raw_crop": [ 52, 28, 6032, 4028 ] + }, + { // Quality B, Intemediate ISO samples missing, Pentax_DNG WLtags are after BL sutraction and not valid "make_model": [ "RICOH PENTAX K-70", "PENTAX K-70" ], //"dcraw_matrix": [ 8050,-2061,-1264,-4359,12953,1515,-1096,1965,6075 ], // PENTAX DNG D65 From 5d7191070b3edb1707f73d4c4f3853c9c818c8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sat, 18 Mar 2017 19:48:04 +0100 Subject: [PATCH 105/110] Fix a OOB access in CropHandler::setDetailedCrop() (#3763) --- rtgui/crophandler.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index 42c6eb756..10280f5c9 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -376,12 +376,12 @@ void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procp imh = ch->wh; } - Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); + Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, ch->cropimg_height, 3 * ch->cropimg_width); ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); tmpPixbuf.clear (); - Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2 * ch->cropimg_height, 3 * ch->cropimg_width); + Glib::RefPtr tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, ch->cropimg_height, 3 * ch->cropimg_width); ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom / 1000.0, czoom / 1000.0, Gdk::INTERP_NEAREST); tmpPixbuftrue.clear (); From 42047cb6650ead909bf8adfb62ce5414198249ce Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 18 Mar 2017 22:35:13 +0100 Subject: [PATCH 106/110] Fix broken build by disabling rth-cli target --- rtgui/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index bc12ea6aa..98382bf07 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -69,25 +69,25 @@ configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINAR # create new executables targets add_executable (rth ${EXTRA_SRC_NONCLI} ${NONCLISOURCEFILES}) -add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) +#add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) # add dependencies to executables targets add_dependencies (rth UpdateInfo) -add_dependencies (rth-cli UpdateInfo) +#add_dependencies (rth-cli UpdateInfo) # set executables targets properties, i.e. output filename and compile flags set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee) -set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) +#set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) # add linked libraries dependencies to executables targets target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${CANBERRA-GTK_LIBRARIES} ${EXTRA_LIB_RTGUI}) -target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} - ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} - ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) +#target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} +# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} +# ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) # install executables install (TARGETS rth DESTINATION ${BINDIR}) -install (TARGETS rth-cli DESTINATION ${BINDIR}) +#install (TARGETS rth-cli DESTINATION ${BINDIR}) From 50bdf91a23c3c4a4bf8e917933fb59e5820d4b99 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 19 Mar 2017 00:55:58 +0100 Subject: [PATCH 107/110] Revert "Fix broken build by disabling rth-cli target" This reverts commit 42047cb6650ead909bf8adfb62ce5414198249ce. --- rtgui/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 98382bf07..bc12ea6aa 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -69,25 +69,25 @@ configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINAR # create new executables targets add_executable (rth ${EXTRA_SRC_NONCLI} ${NONCLISOURCEFILES}) -#add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) +add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) # add dependencies to executables targets add_dependencies (rth UpdateInfo) -#add_dependencies (rth-cli UpdateInfo) +add_dependencies (rth-cli UpdateInfo) # set executables targets properties, i.e. output filename and compile flags set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee) -#set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) +set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) # add linked libraries dependencies to executables targets target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${CANBERRA-GTK_LIBRARIES} ${EXTRA_LIB_RTGUI}) -#target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} -# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} -# ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) +target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} + ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} + ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) # install executables install (TARGETS rth DESTINATION ${BINDIR}) -#install (TARGETS rth-cli DESTINATION ${BINDIR}) +install (TARGETS rth-cli DESTINATION ${BINDIR}) From 99f0d723b5d1c3d0c05d56a994b6c5c9c4c68601 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 19 Mar 2017 03:31:33 +0100 Subject: [PATCH 108/110] Fixing missing output Profiles bug + disabling rt-cli (see #3691) --- rtengine/iccstore.cc | 4 ++-- rtgui/CMakeLists.txt | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 527dae568..a78304c09 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -70,7 +70,7 @@ void loadProfiles( const Glib::ustring extension = rtengine::getFileExtension(fileName); - if (extension != ".icc" && extension != ".icm") { + if (extension != "icc" && extension != "icm") { continue; } @@ -131,7 +131,7 @@ bool loadProfile( const Glib::ustring extension = rtengine::getFileExtension(fileName); - if (extension != ".icc" && extension != ".icm") { + if (extension != "icc" && extension != "icm") { continue; } diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index bc12ea6aa..98382bf07 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -69,25 +69,25 @@ configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINAR # create new executables targets add_executable (rth ${EXTRA_SRC_NONCLI} ${NONCLISOURCEFILES}) -add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) +#add_executable (rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) # add dependencies to executables targets add_dependencies (rth UpdateInfo) -add_dependencies (rth-cli UpdateInfo) +#add_dependencies (rth-cli UpdateInfo) # set executables targets properties, i.e. output filename and compile flags set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee) -set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) +#set_target_properties (rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) # add linked libraries dependencies to executables targets target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${CANBERRA-GTK_LIBRARIES} ${EXTRA_LIB_RTGUI}) -target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} - ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} - ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) +#target_link_libraries (rth-cli rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} +# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${CAIROMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} +# ${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) # install executables install (TARGETS rth DESTINATION ${BINDIR}) -install (TARGETS rth-cli DESTINATION ${BINDIR}) +#install (TARGETS rth-cli DESTINATION ${BINDIR}) From 5632c787a3b44f4987dfff33c52d85670d410613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 19 Mar 2017 11:18:13 +0100 Subject: [PATCH 109/110] Don't return `XYZ` for `sRGB` (#3691) Also fix length of `ProfileContent` to match the old implementation. --- rtengine/iccstore.cc | 18 ++++++++++-------- rtengine/iccstore.h | 4 ++-- rtengine/simpleprocess.cc | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index a78304c09..4c749e3c4 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -1,12 +1,12 @@ /* * This file is part of RawTherapee. * - * Copyright(c) 2004-2010 Gabor Horvath + * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - *(at your option) any later version. + * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -223,7 +223,7 @@ rtengine::ProfileContent::ProfileContent(const Glib::ustring& fileName) d[length] = 0; fclose(f); - data.assign(d, length + 1); + data.assign(d, length); delete[] d; } @@ -236,7 +236,7 @@ rtengine::ProfileContent::ProfileContent(cmsHPROFILE hProfile) if (bytesNeeded > 0) { char* d = new char[bytesNeeded + 1]; cmsSaveProfileToMem(hProfile, d, &bytesNeeded); - data.assign(d, bytesNeeded + 1); + data.assign(d, bytesNeeded); delete[] d; } } @@ -247,7 +247,7 @@ cmsHPROFILE rtengine::ProfileContent::toProfile() const return !data.empty() - ? cmsOpenProfileFromMem(data.data(), data.size()) + ? cmsOpenProfileFromMem(data.c_str(), data.size()) : nullptr; } @@ -690,7 +690,7 @@ cmsHPROFILE rtengine::ICCStore::getXYZProfile() const cmsHPROFILE rtengine::ICCStore::getsRGBProfile() const { - return implementation->getXYZProfile(); + return implementation->getsRGBProfile(); } std::vector rtengine::ICCStore::getProfiles(ProfileType type) const @@ -1025,7 +1025,8 @@ cmsHPROFILE rtengine::ICCStore::createFromMatrix(const double matrix[3][3], bool return p; } -cmsHPROFILE rtengine::ICCStore::createGammaProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) { +cmsHPROFILE rtengine::ICCStore::createGammaProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) +{ float p[6]; //primaries ga[6] = 0.0; @@ -1121,7 +1122,8 @@ cmsHPROFILE rtengine::ICCStore::createGammaProfile(const procparams::ColorManage } // WARNING: the caller must lock lcmsMutex -cmsHPROFILE rtengine::ICCStore::createCustomGammaOutputProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) { +cmsHPROFILE rtengine::ICCStore::createCustomGammaOutputProfile(const procparams::ColorManagementParams &icm, GammaValues &ga) +{ bool pro = false; Glib::ustring outProfile; cmsHPROFILE outputProfile = nullptr; diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 9562f3144..d0c5ef400 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -1,12 +1,12 @@ /* * This file is part of RawTherapee. * - * Copyright(c) 2004-2010 Gabor Horvath + * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - *(at your option) any later version. + * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c7a05ab1a..ec0b31b3f 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1222,7 +1222,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if (!useLCMS) { // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma ProfileContent pc(jprof); - readyImg->setOutputProfile(pc.getData().data(), pc.getData().size()); + readyImg->setOutputProfile(pc.getData().c_str(), pc.getData().size()); } } else { // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma @@ -1242,7 +1242,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } ProfileContent pc = ICCStore::getInstance()->getContent (params.icm.output); - readyImg->setOutputProfile(pc.getData().data(), pc.getData().size()); + readyImg->setOutputProfile(pc.getData().c_str(), pc.getData().size()); } } else { // No ICM From 2228159ff83a27477e94a5e6d8173095e22255a7 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 19 Mar 2017 18:41:35 +0100 Subject: [PATCH 110/110] Rawtherapee hanging on Windows if verbose = true, fixes #3768 --- rtgui/main.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rtgui/main.cc b/rtgui/main.cc index 00cdc3b94..155d9f3ba 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -204,8 +204,7 @@ int main(int argc, char **argv) break; } - if(Console) { - AllocConsole(); + if(Console && AllocConsole()) { AttachConsole( GetCurrentProcessId() ) ; // Don't allow CTRL-C in console to terminate RT SetConsoleCtrlHandler( NULL, true ); @@ -243,16 +242,18 @@ int main(int argc, char **argv) } } - int ret = processLineParams( argc, argv); + if(argc > 1) { + int ret = processLineParams( argc, argv); - if( ret <= 0 ) { - if(consoleOpened) { - printf("Press any key to exit RawTherapee\n"); - FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); - getch(); + if( ret <= 0 ) { + if(consoleOpened) { + printf("Press any key to exit RawTherapee\n"); + FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); + getch(); + } + + return ret; } - - return ret; } }