diff --git a/rtdata/languages/default b/rtdata/languages/default index 0b5256e35..0c2c439c5 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -842,7 +842,8 @@ HISTORY_MSG_591;Local - Avoid color shift HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction -HISTORY_MSG_DUALDEMOSAIC_CONTRAST;AMaZE+VNG4 - Contrast threshold +HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold +HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D @@ -2046,6 +2047,8 @@ 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.\nPixel Shift is for Pentax/Sony Pixel Shift files. It falls back to AMaZE for non-Pixel Shift files. +TP_RAW_DUALDEMOSAICAUTOCONTRAST;Auto threshold +TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;If the check-box is checked (recommended), RawTherapee calculates an optimum value based on flat regions in the image.\nIf there is no flat region in the image or the image is too noisy, the value will be set to 0.\nTo set the value manually, uncheck the check-box first (reasonable values depend on the image). TP_RAW_DUALDEMOSAICCONTRAST;Contrast threshold TP_RAW_EAHD;EAHD TP_RAW_FALSECOLOR;False color suppression steps diff --git a/rtengine/camconst.json b/rtengine/camconst.json index fdaaeef92..eb4174577 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1225,6 +1225,11 @@ Camera constants: } }, + { // Quality C + "make_model": "DJI FC6310", + "ranges": { "white": 64886 } + }, + { // Quality B "make_model": "FUJIFILM GFX 50S", "dcraw_matrix": [ 11756,-4754,-874,-3056,11045,2305,-381,1457,6006 ], // DNGv9.9 D65 @@ -1338,13 +1343,13 @@ Camera constants: "make_model": "LG mobile LG-H815", "dcraw_matrix": [ 5859,547,-1250,-6484,15547,547,-2422,5625,3906 ], // DNG D65 //"dcraw_matrix": [ 11563,-2891,-3203,-5313,15625,625,-781,2813,5625 ], // DNG A - "ranges": { "white_max": 1000 } + "ranges": { "white": 1000 } }, { // Quality C "make_model": "LG mobile LG-H850", //"dcraw_matrix": [ 10000,-2188,-2813,-5156,15469,625,-703,2734,5078 ], // DNG A "dcraw_matrix": [ 5313,1016,-1172,-6250,15391,547,-2344,5547,3359 ], // DNG D65 - "ranges": { "white_max": 1000 } + "ranges": { "white": 1000 } }, { // Quality A @@ -1578,6 +1583,13 @@ Camera constants: "ranges": { "white": 3980 } // 12-bit files. }, + { // Quality C, only colour matrix and PDAF lines info + "make_model" : "Nikon Z 7", + "dcraw_matrix" : [10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785], // Adobe DNG Converter 11.0 ColorMatrix2 + "pdaf_pattern" : [0, 12], + "pdaf_offset" : 29 + }, + { // Quality B, 16Mp and 64Mp raw frames "make_model": "OLYMPUS E-M5MarkII", "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // DNG_v8.8 D65 diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 73f9c948f..035dab2b2 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6462,17 +6462,20 @@ guess_cfa_pc: unsigned oldOrder = order; order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 unsigned ntags = get4(); // read the number of opcodes - while (ntags--) { - unsigned opcode = get4(); - fseek (ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently - if (opcode == 4) { // FixBadPixelsConstant - fseek (ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte - if(get4() == 0) { // if raw 0 values should be treated as bad pixels, set zero_is_bad to true (1). That's the only value currently supported by rt - zero_is_bad = 1; + + if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310) + while (ntags-- && !ifp->eof) { + unsigned opcode = get4(); + fseek (ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + if (opcode == 4) { // FixBadPixelsConstant + fseek (ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte + if(get4() == 0) { // if raw 0 values should be treated as bad pixels, set zero_is_bad to true (1). That's the only value currently supported by rt + zero_is_bad = 1; + } + } else { + fseek (ifp, get4(), SEEK_CUR); + } } - } else { - fseek (ifp, get4(), SEEK_CUR); - } } order = oldOrder; break; @@ -10062,6 +10065,10 @@ dng_skip: adobe_coeff (make, model); if((!strncmp(make, "XIAOYI", 6) || !strncmp(make, "YI", 2)) && !strncmp(model, "M1",2)) adobe_coeff (make, model); + if(!strncmp(make, "DJI", 3) && !strncmp(model, "FC6310", 6)) // DNG files from this camera have wrong (too high) white level + adobe_coeff (make, model); + if (!strncmp(make, "LG", 2) && (!strncmp(model, "LG-H850",7) || !strncmp(model, "LG-H815",7))) + adobe_coeff (make, model); if (raw_color) adobe_coeff (make, model); if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index c0d0c2a2b..10ef0dd0e 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -37,7 +37,7 @@ #include "sleef.c" #include "opthelper.h" #include "median.h" -#define BENCHMARK +//#define BENCHMARK #include "StopWatch.h" #ifdef _OPENMP #include diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 6e92fd1e2..4ffac9296 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -36,11 +36,11 @@ using namespace std; namespace rtengine { -void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast, int autoX, int autoY) +void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast) { BENCHFUN - if (contrast == 0.0 && !autoContrast) { + if (contrast == 0.f && !autoContrast) { // contrast == 0.0 means only first demosaicer will be used if(isBayer) { if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) ) { @@ -91,24 +91,6 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi { 0.019334, 0.119193, 0.950227 } }; - if (autoContrast && autoX >= 0 && autoY >= 0) { - constexpr int rectSize = 40; - const int autoWidth = min(rectSize, winw - autoX); - const int autoHeight = min(rectSize, winh - autoY); - if (std::min(autoWidth, autoHeight) > 20) { - array2D autoL(autoWidth, autoHeight); - for(int i = 0; i < autoHeight; ++i) { - Color::RGB2L(red[i + autoY] + autoX, green[i + autoY] + autoX, blue[i + autoY] + autoX, autoL[i], xyz_rgb, autoWidth); - } - // calculate contrast based blend factors to use vng4 in regions with low contrast - JaggedArray blend(autoWidth - 2, autoHeight - 2); - int c = calcContrastThreshold(autoL, blend, autoWidth, autoHeight); - if(c < 100) { - contrast = c; // alternative : contrast = c - 1 - } - } - } - #pragma omp parallel { #pragma omp for @@ -118,7 +100,10 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi } // calculate contrast based blend factors to use vng4 in regions with low contrast JaggedArray blend(winw, winh); - buildBlendMask(L, blend, winw, winh, contrast / 100.f); + float contrastf = contrast / 100.f; + + buildBlendMask(L, blend, winw, winh, contrastf, 1.f, autoContrast); + contrast = contrastf * 100.f; // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache #pragma omp parallel for diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index e01f22b16..a7c867e08 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -83,6 +83,7 @@ public: virtual void setBorder (unsigned int border) {} virtual void setCurrentFrame (unsigned int frameNum) = 0; virtual int getFrameCount () = 0; + virtual int getFlatFieldAutoClipValue () = 0; // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8e5d42a3c..7f435ebda 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -101,7 +101,7 @@ ImProcCoordinator::ImProcCoordinator() fw(0), fh(0), tr(0), fullw(1), fullh(1), pW(-1), pH(-1), - plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), awbListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), + plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), awbListener(nullptr), flatFieldAutoClipListener(nullptr), bayerAutoContrastListener(nullptr), xtransAutoContrastListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), thread(nullptr), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), wavcontlutili(false), locallutili(false), localcutili(false), localskutili(false), localexutili(false), LHutili(false), HHutili(false), @@ -228,6 +228,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); imgsrc->preprocess(rp, params.lensProf, params.coarse); + if (flatFieldAutoClipListener && rp.ff_AutoClipControl) { + flatFieldAutoClipListener->flatFieldAutoClipValueChanged(imgsrc->getFlatFieldAutoClipValue()); + } imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); highDetailPreprocessComputed = highDetailNeeded; @@ -268,10 +271,17 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); } } - bool autoContrast = false; - double contrastThreshold = 0.f; + bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; + double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic + if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener && autoContrast) { + bayerAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); + } + if (imgsrc->getSensorType() == ST_FUJI_XTRANS && xtransAutoContrastListener && autoContrast) { + xtransAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); + } + // if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag todo |= M_INIT; @@ -1022,7 +1032,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // process crop, if needed for (size_t i = 0; i < crops.size(); i++) - if (crops[i]->hasListener() && (panningRelatedChange || (todo & (M_MONITOR | M_RGBCURVE | M_LUMACURVE)) || crops[i]->get_skip() == 1)) { + if (crops[i]->hasListener() && (panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar) || (todo & (M_MONITOR | M_RGBCURVE | M_LUMACURVE)) || crops[i]->get_skip() == 1)) { crops[i]->update(todo); // may call ourselves } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 85f601932..54e1c45af 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -182,6 +182,9 @@ protected: AutoCamListener* acListener; AutoBWListener* abwListener; AutoWBListener* awbListener; + FlatFieldAutoClipListener *flatFieldAutoClipListener; + AutoContrastListener *bayerAutoContrastListener; + AutoContrastListener *xtransAutoContrastListener; FrameCountListener *frameCountListener; ImageTypeListener *imageTypeListener; AutoColorTonListener* actListener; @@ -407,6 +410,20 @@ public: frameCountListener = fcl; } + void setFlatFieldAutoClipListener (FlatFieldAutoClipListener* ffacl) + { + flatFieldAutoClipListener = ffacl; + } + void setBayerAutoContrastListener (AutoContrastListener* acl) + { + bayerAutoContrastListener = acl; + } + + void setXtransAutoContrastListener (AutoContrastListener* acl) + { + xtransAutoContrastListener = acl; + } + void setImageTypeListener(ImageTypeListener* itl) { imageTypeListener = itl; diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 4d790bf1e..cee216bdd 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -176,7 +176,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(luminance, blend, W, H, sharpenParam.contrast / 100.f, sharpenParam.deconvamount / 100.0); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(luminance, blend, W, H, contrast, sharpenParam.deconvamount / 100.f); const float damping = sharpenParam.deconvdamping / 5.0; const bool needdamp = sharpenParam.deconvdamping > 0; @@ -292,7 +293,8 @@ void ImProcFunctions::sharpening (LabImage* lab, const SharpeningParams &sharpen if(showMask) { // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(lab->L, blend, W, H, sharpenParam.contrast / 100.f, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.0 : 1.f); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(lab->L, blend, W, H, contrast, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.f : 1.f); #ifdef _OPENMP #pragma omp parallel for #endif @@ -326,7 +328,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(lab->L, blend, W, H, sharpenParam.contrast / 100.f); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(lab->L, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel @@ -680,7 +683,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(luminance, blend, W, H, params->sharpenMicro.contrast / 100.f); + float contrast = params->sharpenMicro.contrast / 100.f; + buildBlendMask(luminance, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel @@ -889,7 +893,8 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) if(showMask) { // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(ncie->sh_p, blend, W, H, params->sharpening.contrast / 100.f); + float contrast = params->sharpening.contrast / 100.f; + buildBlendMask(ncie->sh_p, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel for #endif @@ -922,7 +927,8 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(ncie->sh_p, blend, W, H, params->sharpening.contrast / 100.f); + float contrast = params->sharpening.contrast / 100.f; + buildBlendMask(ncie->sh_p, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index ed24e87f0..5d449b44c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2635,6 +2635,7 @@ RAWParams::BayerSensor::BayerSensor() : greenthresh(0), dcb_iterations(2), lmmse_iterations(2), + dualDemosaicAutoContrast(true), dualDemosaicContrast(20), pixelShiftMotionCorrectionMethod(PSMotionCorrectionMethod::AUTO), pixelShiftEperIso(0.0), @@ -2672,6 +2673,7 @@ bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const && greenthresh == other.greenthresh && dcb_iterations == other.dcb_iterations && lmmse_iterations == other.lmmse_iterations + && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast && dualDemosaicContrast == other.dualDemosaicContrast && pixelShiftMotionCorrectionMethod == other.pixelShiftMotionCorrectionMethod && pixelShiftEperIso == other.pixelShiftEperIso @@ -2759,6 +2761,7 @@ Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod RAWParams::XTransSensor::XTransSensor() : method(getMethodString(Method::THREE_PASS)), + dualDemosaicAutoContrast(true), dualDemosaicContrast(20), ccSteps(0), blackred(0.0), @@ -2771,6 +2774,7 @@ bool RAWParams::XTransSensor::operator ==(const XTransSensor& other) const { return method == other.method + && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast && dualDemosaicContrast == other.dualDemosaicContrast && ccSteps == other.ccSteps && blackred == other.blackred @@ -3776,6 +3780,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbIterations, "RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbEnhance, "RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.lmmseIterations, "RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations, keyFile); + saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicAutoContrast, "RAW Bayer", "DualDemosaicAutoContrast", raw.bayersensor.dualDemosaicAutoContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicContrast, "RAW Bayer", "DualDemosaicContrast", raw.bayersensor.dualDemosaicContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod, "RAW Bayer", "PixelShiftMotionCorrectionMethod", toUnderlying(raw.bayersensor.pixelShiftMotionCorrectionMethod), keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftEperIso, "RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso, keyFile); @@ -3793,6 +3798,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftDemosaicMethod, "RAW Bayer", "pixelShiftDemosaicMethod", raw.bayersensor.pixelShiftDemosaicMethod, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pdafLinesFilter, "RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.method, "RAW X-Trans", "Method", raw.xtranssensor.method, keyFile); + saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicAutoContrast, "RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicContrast, "RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.ccSteps, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackRed, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile); @@ -5458,6 +5464,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "RAW Bayer", "DCBIterations", pedited, raw.bayersensor.dcb_iterations, pedited->raw.bayersensor.dcbIterations); assignFromKeyfile(keyFile, "RAW Bayer", "DCBEnhance", pedited, raw.bayersensor.dcb_enhance, pedited->raw.bayersensor.dcbEnhance); assignFromKeyfile(keyFile, "RAW Bayer", "LMMSEIterations", pedited, raw.bayersensor.lmmse_iterations, pedited->raw.bayersensor.lmmseIterations); + assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicAutoContrast", pedited, raw.bayersensor.dualDemosaicAutoContrast, pedited->raw.bayersensor.dualDemosaicAutoContrast); + if (ppVersion < 345) { + raw.bayersensor.dualDemosaicAutoContrast = false; + if (pedited) { + pedited->raw.bayersensor.dualDemosaicAutoContrast = true; + } + } assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicContrast", pedited, raw.bayersensor.dualDemosaicContrast, pedited->raw.bayersensor.dualDemosaicContrast); if (keyFile.has_key("RAW Bayer", "PixelShiftMotionCorrectionMethod")) { @@ -5509,6 +5522,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("RAW X-Trans")) { assignFromKeyfile(keyFile, "RAW X-Trans", "Method", pedited, raw.xtranssensor.method, pedited->raw.xtranssensor.method); + assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicAutoContrast", pedited, raw.xtranssensor.dualDemosaicAutoContrast, pedited->raw.xtranssensor.dualDemosaicAutoContrast); + if (ppVersion < 345) { + raw.xtranssensor.dualDemosaicAutoContrast = false; + if (pedited) { + pedited->raw.xtranssensor.dualDemosaicAutoContrast = true; + } + } assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicContrast", pedited, raw.xtranssensor.dualDemosaicContrast, pedited->raw.xtranssensor.dualDemosaicContrast); assignFromKeyfile(keyFile, "RAW X-Trans", "CcSteps", pedited, raw.xtranssensor.ccSteps, pedited->raw.xtranssensor.ccSteps); assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackRed", pedited, raw.xtranssensor.blackred, pedited->raw.xtranssensor.exBlackRed); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index a180ad654..b53ec6c4d 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1416,6 +1416,7 @@ struct RAWParams { int greenthresh; int dcb_iterations; int lmmse_iterations; + bool dualDemosaicAutoContrast; double dualDemosaicContrast; PSMotionCorrectionMethod pixelShiftMotionCorrectionMethod; double pixelShiftEperIso; @@ -1463,6 +1464,7 @@ struct RAWParams { }; Glib::ustring method; + bool dualDemosaicAutoContrast; double dualDemosaicContrast; int ccSteps; double blackred; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1f967c90b..5ad66b612 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2086,7 +2086,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c double threshold = raw.bayersensor.dualDemosaicContrast; dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, threshold, false); } else { - dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, contrastThreshold, true, 0, 0); + dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, contrastThreshold, true); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { pixelshift(0, 0, W, H, raw, currFrame, ri->get_maker(), ri->get_model(), raw.expos); @@ -2119,7 +2119,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c double threshold = raw.xtranssensor.dualDemosaicContrast; dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, threshold, false); } else { - dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, contrastThreshold, true, 0, 0); + dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, contrastThreshold, true); } } else if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO)) { nodemosaic(true); @@ -2883,8 +2883,6 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile float limitFactor = 1.f; if (raw.ff_AutoClipControl) { -// int clipControlGui = 0; - for (int m = 0; m < 2; m++) for (int n = 0; n < 2; n++) { float maxval = 0.f; @@ -2928,7 +2926,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile } } -// clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui + flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui } else { limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); } @@ -3014,7 +3012,6 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile if (raw.ff_AutoClipControl) { // determine maximum calculated value to avoid clipping -// int clipControlGui = 0; float maxval = 0.f; // xtrans files have only one black level actually, so we can simplify the code a bit #ifdef _OPENMP @@ -3049,7 +3046,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile // there's only one white level for xtrans if (maxval + black[0] > ri->get_white(0)) { limitFactor = ri->get_white(0) / (maxval + black[0]); -// clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui + flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui } } else { limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 2c4ec13fe..1b9698974 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -74,7 +74,7 @@ protected: RawImage* riFrames[4] = {nullptr}; unsigned int currFrame = 0; unsigned int numFrames = 0; - + int flatFieldAutoClipValue = 0; array2D rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column array2D *rawDataFrames[4] = {nullptr}; array2D *rawDataBuffer[3] = {nullptr}; @@ -212,10 +212,9 @@ public: currFrame = std::min(numFrames - 1, frameNum); ri = riFrames[currFrame]; } - int getFrameCount() - { - return numFrames; - } + int getFrameCount(){return numFrames;} + int getFlatFieldAutoClipValue() {return flatFieldAutoClipValue;} + class GreenEqulibrateThreshold { public: @@ -278,7 +277,7 @@ protected: void igv_interpolate(int winw, int winh); 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, const array2D &rawData, array2D &red, array2D &green, array2D &blue);//Emil's code for AMaZE - void dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false, int autoX = -1, int autoY = -1); + void dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false); void fast_demosaic();//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(); diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index c56a72a2c..ae385508a 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef _OPENMP #include #endif @@ -32,6 +33,7 @@ #include "rt_algo.h" #include "rt_math.h" #include "sleef.c" +#include "jaggedarray.h" namespace { float calcBlendFactor(float val, float threshold) { @@ -190,75 +192,166 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& maxOut += minVal; } -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount) { +void buildBlendMask(float** luminance, float **blend, int W, int H, float &contrastThreshold, float amount, bool autoContrast) { - constexpr float scale = 0.0625f / 327.68f; - - if(contrastThreshold == 0.f) { + if(contrastThreshold == 0.f && !autoContrast) { for(int j = 0; j < H; ++j) { for(int i = 0; i < W; ++i) { blend[j][i] = amount; } } } else { -#ifdef _OPENMP - #pragma omp parallel -#endif - { -#ifdef __SSE2__ - const vfloat contrastThresholdv = F2V(contrastThreshold); - const vfloat scalev = F2V(scale); - const vfloat amountv = F2V(amount); -#endif -#ifdef _OPENMP - #pragma omp for schedule(dynamic,16) -#endif + constexpr float scale = 0.0625f / 327.68f; + if (autoContrast) { + for (int pass = 0; pass < 2; ++pass) { + const int tilesize = 80 / (pass + 1); + const int numTilesW = W / tilesize; + const int numTilesH = H / tilesize; + std::vector>> variances(numTilesH, std::vector>(numTilesW)); - for(int j = 2; j < H - 2; ++j) { - int i = 2; + #pragma omp parallel for + for (int i = 0; i < numTilesH; ++i) { + int tileY = i * tilesize; + for (int j = 0; j < numTilesW; ++j) { + int tileX = j * tilesize; #ifdef __SSE2__ - for(; i < W - 5; i += 4) { - vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + - SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; - - STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv)); + vfloat avgv = ZEROV; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x += 4) { + avgv += LVFU(luminance[y][x]); + } + } + float avg = vhadd(avgv); +#else + float avg = 0.; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + avg += luminance[y][x]; + } + } +#endif + avg /= SQR(tilesize); +#ifdef __SSE2__ + vfloat varv = ZEROV; + avgv = F2V(avg); + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x +=4) { + varv += SQRV(LVFU(luminance[y][x]) - avgv); + } + } + float var = vhadd(varv); +#else + float var = 0.0; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + var += SQR(luminance[y][x] - avg); + } + } + #endif + var /= (SQR(tilesize) * avg); + variances[i][j].first = var; + variances[i][j].second = avg; + } } -#endif - for(; i < W - 2; ++i) { - float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) + - rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale; + float minvar = RT_INFINITY_F; + int minI = 0, minJ = 0; + for (int i = 0; i < numTilesH; ++i) { + for (int j = 0; j < numTilesW; ++j) { + if (variances[i][j].first < minvar && variances[i][j].second > 2000.f && variances[i][j].second < 20000.f) { + minvar = variances[i][j].first; + minI = i; + minJ = j; + } + } + } - blend[j][i] = amount * calcBlendFactor(contrast, contrastThreshold); + const int minY = tilesize * minI; + const int minX = tilesize * minJ; + +// std::cout << pass << ": minvar : " << minvar << std::endl; + if (minvar <= 1.f || pass == 1) { + // a variance <= 1 means we already found a flat region and can skip second pass + // in second pass we allow a variance of 2 + JaggedArray Lum(tilesize, tilesize); + JaggedArray Blend(tilesize, tilesize); + for (int i = 0; i < tilesize; ++i) { + for (int j = 0; j < tilesize; ++j) { + Lum[i][j] = luminance[i + minY][j + minX]; + } + } + contrastThreshold = (pass == 0 || minvar <= 2.f) ? calcContrastThreshold(Lum, Blend, tilesize, tilesize) / 100.f : 0.f; + break; } } + } + if(contrastThreshold == 0.f) { + for(int j = 0; j < H; ++j) { + for(int i = 0; i < W; ++i) { + blend[j][i] = amount; + } + } + } else { #ifdef _OPENMP - #pragma omp single + #pragma omp parallel #endif { - // upper border - for(int j = 0; j < 2; ++j) { - for(int i = 2; i < W - 2; ++i) { - blend[j][i] = blend[2][i]; - } - } - // lower border - for(int j = H - 2; j < H; ++j) { - for(int i = 2; i < W - 2; ++i) { - blend[j][i] = blend[H-3][i]; - } - } - for(int j = 0; j < H; ++j) { - // left border - blend[j][0] = blend[j][1] = blend[j][2]; - // right border - blend[j][W - 2] = blend[j][W - 1] = blend[j][W - 3]; - } - } +#ifdef __SSE2__ + const vfloat contrastThresholdv = F2V(contrastThreshold); + const vfloat scalev = F2V(scale); + const vfloat amountv = F2V(amount); +#endif +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif - // blur blend mask to smooth transitions - gaussianBlur(blend, blend, W, H, 2.0); + for(int j = 2; j < H - 2; ++j) { + int i = 2; +#ifdef __SSE2__ + for(; i < W - 5; i += 4) { + vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + + SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; + + STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv)); + } +#endif + for(; i < W - 2; ++i) { + + float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) + + rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale; + + blend[j][i] = amount * calcBlendFactor(contrast, contrastThreshold); + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + // upper border + for(int j = 0; j < 2; ++j) { + for(int i = 2; i < W - 2; ++i) { + blend[j][i] = blend[2][i]; + } + } + // lower border + for(int j = H - 2; j < H; ++j) { + for(int i = 2; i < W - 2; ++i) { + blend[j][i] = blend[H-3][i]; + } + } + for(int j = 0; j < H; ++j) { + // left border + blend[j][0] = blend[j][1] = blend[j][2]; + // right border + blend[j][W - 2] = blend[j][W - 1] = blend[j][W - 3]; + } + } + + // blur blend mask to smooth transitions + gaussianBlur(blend, blend, W, H, 2.0); + } } } } @@ -289,7 +382,7 @@ int calcContrastThreshold(float** luminance, float **blend, int W, int H) { } } - const float limit = (W - 2) * (H - 2) / 100.f; + const float limit = (W - 4) * (H - 4) / 100.f; int c; for (c = 1; c < 100; ++c) { @@ -318,6 +411,7 @@ int calcContrastThreshold(float** luminance, float **blend, int W, int H) { break; } } + return c; } } diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index e20713b8f..0207e6f57 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -24,6 +24,6 @@ namespace rtengine { void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true); -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount = 1.f); +void buildBlendMask(float** luminance, float **blend, int W, int H, float &contrastThreshold, float amount = 1.f, bool autoContrast = false); int calcContrastThreshold(float** luminance, float **blend, int W, int H); } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 986a88b48..cb81f0eb0 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -372,6 +372,13 @@ public: virtual void FrameCountChanged(int n, int frameNum) = 0; }; +class FlatFieldAutoClipListener +{ +public: + virtual ~FlatFieldAutoClipListener() = default; + virtual void flatFieldAutoClipValueChanged(int n) = 0; +}; + class ImageTypeListener { public: @@ -379,6 +386,13 @@ public: virtual void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false) = 0; }; +class AutoContrastListener +{ +public : + virtual ~AutoContrastListener() = default; + virtual void autoContrastChanged (double autoContrast) = 0; +}; + class WaveletListener { public: @@ -482,7 +496,10 @@ public: virtual void setHistogramListener (HistogramListener *l) = 0; virtual void setPreviewImageListener (PreviewImageListener* l) = 0; virtual void setAutoCamListener (AutoCamListener* l) = 0; + virtual void setFlatFieldAutoClipListener (FlatFieldAutoClipListener* l) = 0; virtual void setFrameCountListener (FrameCountListener* l) = 0; + virtual void setBayerAutoContrastListener (AutoContrastListener* l) = 0; + virtual void setXtransAutoContrastListener (AutoContrastListener* l) = 0; virtual void setAutoBWListener (AutoBWListener* l) = 0; virtual void setAutoWBListener (AutoWBListener* l) = 0; virtual void setAutoColorTonListener (AutoColorTonListener* l) = 0; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index a5b84e186..065819f40 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -214,8 +214,10 @@ private: if (pl) { pl->setProgress(0.20); } - double contrastThresholdDummy; - imgsrc->demosaic (params.raw, false, contrastThresholdDummy); + bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; + double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; + + imgsrc->demosaic (params.raw, autoContrast, contrastThreshold); if (pl) { diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 62cca7d4f..1dbb65001 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -100,6 +100,7 @@ public: } void setCurrentFrame(unsigned int frameNum) {} int getFrameCount() {return 1;} + int getFlatFieldAutoClipValue() {return 0;} void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) { R = G = B = 0;} diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index 3f12b0cfb..46aa3952b 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -239,10 +239,12 @@ void Adjuster::autoToggled () // Disable the slider and spin button spin->set_sensitive(false); slider->set_sensitive(false); + reset->set_sensitive(false); } else { // Enable the slider and spin button spin->set_sensitive(true); slider->set_sensitive(true); + reset->set_sensitive(true); } } @@ -471,10 +473,12 @@ void Adjuster::setAutoValue (bool a) // Disable the slider and spin button spin->set_sensitive(false); slider->set_sensitive(false); + reset->set_sensitive(false); } else { // Enable the slider and spin button spin->set_sensitive(true); slider->set_sensitive(true); + reset->set_sensitive(true); } } } diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index b698ee9d6..83a0f37ae 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -322,7 +322,7 @@ void BatchQueuePanel::addBatchQueueJobs(const std::vector& ent bool BatchQueuePanel::canStartNext () { - +// GThreadLock lock; if (qStartStop->get_active()) { return true; } else { diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 6d5c17753..d80086d75 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -385,9 +385,8 @@ void BatchToolPanelCoordinator::initSession () } } -void BatchToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) +void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) { - if (selected.empty()) { return; } @@ -613,9 +612,14 @@ void BatchToolPanelCoordinator::endBatchPParamsChange() * Using a Profile panel in the batch tool panel editor is actually * not supported by BatchToolPanelCoordinator::profileChange! */ -void BatchToolPanelCoordinator::profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) +void BatchToolPanelCoordinator::profileChange( + const PartialProfile* nparams, + const rtengine::ProcEvent& event, + const Glib::ustring& descr, + const ParamsEdited* paramsEdited, + bool fromLastSave +) { - if (event == rtengine::EvProfileChanged) { // a profile has been selected in a hypothetical Profile panel // -> ACTUALLY NOT SUPPORTED diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h index 4efcea6fa..204750047 100644 --- a/rtgui/batchtoolpanelcoord.h +++ b/rtgui/batchtoolpanelcoord.h @@ -51,30 +51,36 @@ public: explicit BatchToolPanelCoordinator (FilePanel* parent); // FileSelectionChangeListener interface - void selectionChanged (const std::vector& selected); + void selectionChanged (const std::vector& selected) override; // toolpanellistener interface - void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr); + void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) override; // profilechangelistener interface - void profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited = nullptr); + void profileChange( + const rtengine::procparams::PartialProfile* nparams, + const rtengine::ProcEvent& event, + const Glib::ustring& descr, + const ParamsEdited* paramsEdited = nullptr, + bool fromLastSave = false + ) override; // wbprovider interface - void getAutoWB (double& temp, double& green, double equal, double tempBias); + void getAutoWB (double& temp, double& green, double equal, double tempBias) override; void getCamWB (double& temp, double& green); // thumbnaillistener interface - void procParamsChanged (Thumbnail* thm, int whoChangedIt); + void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; // batchpparamschangelistener interface - void beginBatchPParamsChange(int numberOfEntries); - void endBatchPParamsChange(); + void beginBatchPParamsChange(int numberOfEntries) override; + void endBatchPParamsChange() override; // imageareatoollistener interface - void spotWBselected (int x, int y, Thumbnail* thm = nullptr); - void cropSelectionReady (); - void rotateSelectionReady (double rotate_deg, Thumbnail* thm = nullptr); - CropGUIListener* startCropEditing (Thumbnail* thm = nullptr); + void spotWBselected (int x, int y, Thumbnail* thm = nullptr) override; + void cropSelectionReady () override; + void rotateSelectionReady (double rotate_deg, Thumbnail* thm = nullptr) override; + CropGUIListener* startCropEditing (Thumbnail* thm = nullptr) override; void optionsChanged (); }; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 758b1b795..2a65a158e 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -30,6 +30,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA auto m = ProcEventMapper::getInstance(); EvDemosaicBorder = m->newEvent(DEMOSAIC, "HISTORY_MSG_RAW_BORDER"); EvDemosaicContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_CONTRAST"); + EvDemosaicAutoContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST"); EvDemosaicPixelshiftDemosaicMethod = m->newEvent(DEMOSAIC, "HISTORY_MSG_PIXELSHIFT_DEMOSAIC"); Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); @@ -46,12 +47,12 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); pack_start( *hb1, Gtk::PACK_SHRINK, 4); + dualDemosaicOptions = Gtk::manage(new Gtk::VBox()); - dualDemosaicOptions = Gtk::manage (new Gtk::VBox ()); - - dualDemosaicContrast = Gtk::manage(new Adjuster (M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); - dualDemosaicContrast->setAdjusterListener (this); - + dualDemosaicContrast = Gtk::manage(new Adjuster(M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); + dualDemosaicContrast->setAdjusterListener(this); + dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); + dualDemosaicContrast->setAutoValue(true); if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { dualDemosaicContrast->delay = options.adjusterMaxDelay; } @@ -250,6 +251,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA } +BayerProcess::~BayerProcess () +{ + idle_register.destroy(); +} void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { @@ -300,7 +305,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenCross->setValue (pp->raw.bayersensor.pixelShiftNonGreenCross); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); + dualDemosaicContrast->setAutoValue(pp->raw.bayersensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.bayersensor.dualDemosaicContrast); + pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); @@ -325,6 +332,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenCross->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenCross); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); dualDemosaicContrast->setEditedState ( pedited->raw.bayersensor.dualDemosaicContrast ? Edited : UnEdited); + dualDemosaicContrast->setAutoInconsistent (multiImage && !pedited->raw.bayersensor.dualDemosaicAutoContrast); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); @@ -345,6 +353,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } } + lastAutoContrast = pp->raw.bayersensor.dualDemosaicAutoContrast; if (!batchMode) { dcbOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCB) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4)); @@ -385,6 +394,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->getLastActive (); pp->raw.bayersensor.border = border->getIntValue(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); + pp->raw.bayersensor.dualDemosaicAutoContrast = dualDemosaicContrast->getAutoValue(); pp->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::PSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); @@ -425,6 +435,7 @@ 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.dualDemosaicAutoContrast = !dualDemosaicContrast->getAutoInconsistent (); pedited->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = pixelShiftMotionMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftDemosaicMethod = pixelShiftDemosaicMethod->get_active_text() != M("GENERAL_UNCHANGED"); @@ -539,10 +550,6 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) } } -void BayerProcess::adjusterAutoToggled(Adjuster* a, bool newval) -{ -} - void BayerProcess::methodChanged () { const int currentSelection = method->get_active_row_number(); @@ -660,6 +667,33 @@ void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) } } +void BayerProcess::adjusterAutoToggled(Adjuster* a, bool newval) +{ + if (multiImage) { + if (dualDemosaicContrast->getAutoInconsistent()) { + dualDemosaicContrast->setAutoInconsistent (false); + dualDemosaicContrast->setAutoValue (false); + } else if (lastAutoContrast) { + dualDemosaicContrast->setAutoInconsistent (true); + } + + lastAutoContrast = dualDemosaicContrast->getAutoValue(); + } + + if (listener) { + + if (a == dualDemosaicContrast) { + if (dualDemosaicContrast->getAutoInconsistent()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_UNCHANGED")); + } else if (dualDemosaicContrast->getAutoValue()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_DISABLED")); + } + } + } +} + void BayerProcess::pixelShiftMotionMethodChanged () { if (!batchMode) { @@ -715,23 +749,23 @@ void BayerProcess::FrameCountChanged(int n, int frameNum) }; idle_register.add(func, new Data { this, n, frameNum }); - - // GThreadLock lock; - // imageNumber->block (true); - - // imageNumber->remove_all(); - // imageNumber->append("1"); - // for(int i = 2; i <= std::min(n, 4); ++i) { - // std::ostringstream entry; - // entry << i; - // imageNumber->append(entry.str()); - // } - // imageNumber->set_active(std::min(frameNum, n - 1)); - // if(n == 1) { - // imageNumberBox->hide(); - // } else { - // imageNumberBox->show(); - // } - // imageNumber->block (false); } +void BayerProcess::autoContrastChanged (double autoContrast) +{ + struct Data { + BayerProcess *me; + double autoContrast; + }; + const auto func = [](gpointer data) -> gboolean { + Data *d = static_cast(data); + BayerProcess *me = d->me; + me->disableListener(); + me->dualDemosaicContrast->setValue(d->autoContrast); + me->enableListener(); + delete d; + return FALSE; + }; + + idle_register.add(func, new Data { this, autoContrast }); +} diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 88b38cc16..b0974e7a4 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -25,7 +25,7 @@ #include "guiutils.h" #include "toolpanel.h" -class BayerProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FrameCountListener +class BayerProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FrameCountListener, public rtengine::AutoContrastListener { protected: @@ -60,15 +60,17 @@ protected: Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; int oldMethod; - + bool lastAutoContrast; IdleRegister idle_register; rtengine::ProcEvent EvDemosaicBorder; + rtengine::ProcEvent EvDemosaicAutoContrast; rtengine::ProcEvent EvDemosaicContrast; rtengine::ProcEvent EvDemosaicPixelshiftDemosaicMethod; public: BayerProcess (); + ~BayerProcess (); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); @@ -84,6 +86,7 @@ public: void checkBoxToggled(CheckBox* c, CheckValue newval); void pixelShiftMotionMethodChanged(); void pixelShiftDemosaicMethodChanged(); + void autoContrastChanged (double autoContrast); void FrameCountChanged(int n, int frameNum); }; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 83ab15127..057ce731c 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -104,6 +104,11 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L } } +FlatField::~FlatField () +{ + idle_register.destroy(); +} + void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener (); @@ -403,3 +408,22 @@ void FlatField::setShortcutPath(const Glib::ustring& path) } catch (Glib::Error&) {} } + +void FlatField::flatFieldAutoClipValueChanged(int n) +{ + struct Data { + FlatField *me; + int n; + }; + const auto func = [](gpointer data) -> gboolean { + Data *d = static_cast(data); + FlatField *me = d->me; + me->disableListener(); + me->flatFieldClipControl->setValue (d->n); + me->enableListener(); + delete d; + return FALSE; + }; + + idle_register.add(func, new Data { this, n }); +} \ No newline at end of file diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 4c0a33a54..599589b68 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -35,7 +35,7 @@ public: // add other info here }; -class FlatField : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class FlatField : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::FlatFieldAutoClipListener { protected: @@ -58,9 +58,11 @@ protected: bool b_filter_asCurrent; bool israw; + IdleRegister idle_register; public: FlatField (); + ~FlatField (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); @@ -80,6 +82,7 @@ public: { ffp = p; }; + void flatFieldAutoClipValueChanged(int n = 0); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a72b513f7..ca1448a82 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -521,6 +521,7 @@ void ParamsEdited::set(bool v) raw.bayersensor.dcbEnhance = v; //raw.bayersensor.allEnhance = v; raw.bayersensor.lmmseIterations = v; + raw.bayersensor.dualDemosaicAutoContrast = v; raw.bayersensor.dualDemosaicContrast = v; raw.bayersensor.pixelShiftMotionCorrectionMethod = v; raw.bayersensor.pixelShiftEperIso = v; @@ -541,6 +542,7 @@ void ParamsEdited::set(bool v) raw.bayersensor.linenoiseDirection = v; raw.bayersensor.pdafLinesFilter = v; raw.xtranssensor.method = v; + raw.xtranssensor.dualDemosaicAutoContrast = v; raw.xtranssensor.dualDemosaicContrast = v; raw.xtranssensor.ccSteps = v; raw.xtranssensor.exBlackRed = v; @@ -1194,6 +1196,7 @@ 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.dualDemosaicAutoContrast = raw.bayersensor.dualDemosaicAutoContrast && p.raw.bayersensor.dualDemosaicAutoContrast == other.raw.bayersensor.dualDemosaicAutoContrast; raw.bayersensor.dualDemosaicContrast = raw.bayersensor.dualDemosaicContrast && p.raw.bayersensor.dualDemosaicContrast == other.raw.bayersensor.dualDemosaicContrast; raw.bayersensor.pixelShiftMotionCorrectionMethod = raw.bayersensor.pixelShiftMotionCorrectionMethod && p.raw.bayersensor.pixelShiftMotionCorrectionMethod == other.raw.bayersensor.pixelShiftMotionCorrectionMethod; raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; @@ -1214,6 +1217,7 @@ void ParamsEdited::initFrom(const std::vector& raw.bayersensor.linenoiseDirection = raw.bayersensor.linenoiseDirection && p.raw.bayersensor.linenoiseDirection == other.raw.bayersensor.linenoiseDirection; raw.bayersensor.pdafLinesFilter = raw.bayersensor.pdafLinesFilter && p.raw.bayersensor.pdafLinesFilter == other.raw.bayersensor.pdafLinesFilter; raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; + raw.xtranssensor.dualDemosaicAutoContrast = raw.xtranssensor.dualDemosaicAutoContrast && p.raw.xtranssensor.dualDemosaicAutoContrast == other.raw.xtranssensor.dualDemosaicAutoContrast; raw.xtranssensor.dualDemosaicContrast = raw.xtranssensor.dualDemosaicContrast && p.raw.xtranssensor.dualDemosaicContrast == other.raw.xtranssensor.dualDemosaicContrast; raw.xtranssensor.ccSteps = raw.xtranssensor.ccSteps && p.raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps; raw.xtranssensor.exBlackRed = raw.xtranssensor.exBlackRed && p.raw.xtranssensor.blackred == other.raw.xtranssensor.blackred; @@ -3169,6 +3173,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.bayersensor.lmmse_iterations = mods.raw.bayersensor.lmmse_iterations; } + if (raw.bayersensor.dualDemosaicAutoContrast) { + toEdit.raw.bayersensor.dualDemosaicAutoContrast = mods.raw.bayersensor.dualDemosaicAutoContrast; + } + if (raw.bayersensor.dualDemosaicContrast) { toEdit.raw.bayersensor.dualDemosaicContrast = mods.raw.bayersensor.dualDemosaicContrast; } @@ -3249,6 +3257,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.xtranssensor.method = mods.raw.xtranssensor.method; } + if (raw.xtranssensor.dualDemosaicAutoContrast) { + toEdit.raw.xtranssensor.dualDemosaicAutoContrast = mods.raw.xtranssensor.dualDemosaicAutoContrast; + } + if (raw.xtranssensor.dualDemosaicContrast) { toEdit.raw.xtranssensor.dualDemosaicContrast = mods.raw.xtranssensor.dualDemosaicContrast; } @@ -3769,7 +3781,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng bool RAWParamsEdited::BayerSensor::isUnchanged() const { - return method && border && imageNum && dcbIterations && dcbEnhance && lmmseIterations && dualDemosaicContrast /*&& allEnhance*/ && greenEq + return method && border && imageNum && dcbIterations && dcbEnhance && lmmseIterations && dualDemosaicAutoContrast && dualDemosaicContrast /*&& allEnhance*/ && greenEq && pixelShiftMotionCorrectionMethod && pixelShiftEperIso && pixelShiftSigma && pixelShiftShowMotion && pixelShiftShowMotionMaskOnly && pixelShiftHoleFill && pixelShiftMedian && pixelShiftNonGreenCross && pixelShiftDemosaicMethod && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftEqualBright && pixelShiftEqualBrightChannel && linenoise && linenoiseDirection && pdafLinesFilter && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; @@ -3777,7 +3789,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const bool RAWParamsEdited::XTransSensor::isUnchanged() const { - return method && exBlackRed && exBlackGreen && exBlackBlue; + return method && exBlackRed && exBlackGreen && exBlackBlue && dualDemosaicAutoContrast && dualDemosaicContrast; } bool RAWParamsEdited::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index c0699be1e..6978ca6f3 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -857,6 +857,7 @@ public: bool dcbIterations; bool dcbEnhance; bool lmmseIterations; + bool dualDemosaicAutoContrast; bool dualDemosaicContrast; bool pixelShiftMotionCorrectionMethod; bool pixelShiftEperIso; @@ -887,6 +888,7 @@ public: public: bool method; + bool dualDemosaicAutoContrast; bool dualDemosaicContrast; bool ccSteps; bool exBlackRed; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 6b192dba9..91e542e85 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -828,8 +828,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!raw_method->get_active ()) { filterPE.raw.bayersensor.method = falsePE.raw.bayersensor.method; + filterPE.raw.bayersensor.dualDemosaicAutoContrast = falsePE.raw.bayersensor.dualDemosaicAutoContrast; filterPE.raw.bayersensor.dualDemosaicContrast = falsePE.raw.bayersensor.dualDemosaicContrast; filterPE.raw.xtranssensor.method = falsePE.raw.xtranssensor.method; + filterPE.raw.xtranssensor.dualDemosaicAutoContrast = falsePE.raw.xtranssensor.dualDemosaicAutoContrast; filterPE.raw.xtranssensor.dualDemosaicContrast = falsePE.raw.xtranssensor.dualDemosaicContrast; } diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index e09355311..f853741f0 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,13 +1,15 @@ #pragma once // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 345 +#define PPVERSION 346 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes - 345 2018-09-25 - Added Locallab tool parameters + 346 2018-09-25 + Added Locallab tool parameters + 345 2018-10-21 + dual demosaic auto contrast threshold 344 2018-10-04 added Lab/RGB color space selection for shadows/highlights 343 2018-09-06 diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 284df6a54..7b3cb5e14 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -598,6 +598,9 @@ void ToolPanelCoordinator::initImage(rtengine::StagedImageProcessor* ipc_, bool ipc->setAutoCamListener(colorappearance); ipc->setAutoBWListener(blackwhite); ipc->setFrameCountListener(bayerprocess); + ipc->setFlatFieldAutoClipListener (flatfield); + ipc->setBayerAutoContrastListener (bayerprocess); + ipc->setXtransAutoContrastListener (xtransprocess); ipc->setAutoWBListener(whitebalance); ipc->setAutoColorTonListener(colortoning); ipc->setAutoChromaListener(dirpyrdenoise); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index f6bc12643..3cd05655e 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -237,6 +237,7 @@ public: void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool isMono = false); +// void autoContrastChanged (double autoContrast); // profilechangelistener interface void profileChange( const rtengine::procparams::PartialProfile* nparams, diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 744c6f148..47556e54f 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -28,6 +28,7 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP { auto m = ProcEventMapper::getInstance(); EvDemosaicContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_CONTRAST"); + EvDemosaicAutoContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST"); Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); @@ -71,6 +72,8 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP dualDemosaicContrast = Gtk::manage(new Adjuster (M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); dualDemosaicContrast->setAdjusterListener (this); + dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); + dualDemosaicContrast->setAutoValue(true); if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { dualDemosaicContrast->delay = options.adjusterMaxDelay; @@ -94,6 +97,9 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &XTransProcess::methodChanged) ); } +XTransProcess::~XTransProcess () { + idle_register.destroy(); +} void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { @@ -108,6 +114,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param } if(pedited ) { + dualDemosaicContrast->setAutoInconsistent (multiImage && !pedited->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setEditedState ( pedited->raw.xtranssensor.dualDemosaicContrast ? Edited : UnEdited); ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); @@ -115,8 +122,12 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param method->set_active_text(M("GENERAL_UNCHANGED")); } } + dualDemosaicContrast->setAutoValue(pp->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.xtranssensor.dualDemosaicContrast); ccSteps->setValue (pp->raw.xtranssensor.ccSteps); + + lastAutoContrast = pp->raw.bayersensor.dualDemosaicAutoContrast; + if (!batchMode) { dualDemosaicOptions->set_visible(pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS) || pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::TWO_PASS)); @@ -129,6 +140,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { + pp->raw.xtranssensor.dualDemosaicAutoContrast = dualDemosaicContrast->getAutoValue(); pp->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); @@ -140,6 +152,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p if (pedited) { pedited->raw.xtranssensor.method = method->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->raw.xtranssensor.dualDemosaicAutoContrast = !dualDemosaicContrast->getAutoInconsistent (); pedited->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.xtranssensor.ccSteps = ccSteps->getEditedState (); } @@ -187,6 +200,29 @@ void XTransProcess::adjusterChanged(Adjuster* a, double newval) void XTransProcess::adjusterAutoToggled(Adjuster* a, bool newval) { + if (multiImage) { + if (dualDemosaicContrast->getAutoInconsistent()) { + dualDemosaicContrast->setAutoInconsistent (false); + dualDemosaicContrast->setAutoValue (false); + } else if (lastAutoContrast) { + dualDemosaicContrast->setAutoInconsistent (true); + } + + lastAutoContrast = dualDemosaicContrast->getAutoValue(); + } + + if (listener) { + + if (a == dualDemosaicContrast) { + if (dualDemosaicContrast->getAutoInconsistent()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_UNCHANGED")); + } else if (dualDemosaicContrast->getAutoValue()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_DISABLED")); + } + } + } } void XTransProcess::methodChanged () @@ -211,3 +247,26 @@ void XTransProcess::methodChanged () : EvDemosaicMethod, method->get_active_text()); } } + +void XTransProcess::checkBoxToggled (CheckBox* c, CheckValue newval) +{ +} + +void XTransProcess::autoContrastChanged (double autoContrast) +{ + struct Data { + XTransProcess *me; + double autoContrast; + }; + const auto func = [](gpointer data) -> gboolean { + Data *d = static_cast(data); + XTransProcess *me = d->me; + me->disableListener(); + me->dualDemosaicContrast->setValue(d->autoContrast); + me->enableListener(); + delete d; + return FALSE; + }; + + idle_register.add(func, new Data { this, autoContrast }); +} diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index bd2086f77..7a706b1ac 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -21,11 +21,12 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" -class XTransProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class XTransProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::AutoContrastListener { protected: @@ -34,14 +35,18 @@ protected: Adjuster* ccSteps; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; + bool lastAutoContrast; int oldSelection; sigc::connection methodconn; + IdleRegister idle_register; + rtengine::ProcEvent EvDemosaicAutoContrast; rtengine::ProcEvent EvDemosaicContrast; public: XTransProcess (); + ~XTransProcess (); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); @@ -50,7 +55,9 @@ public: void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); void methodChanged(); + void autoContrastChanged (double autoContrast); void adjusterChanged(Adjuster* a, double newval); + void checkBoxToggled(CheckBox* c, CheckValue newval); void adjusterAutoToggled(Adjuster* a, bool newval); };