* Init levels trc GUI * Levels TRC * Complete with gamma based attenuation * Limit RGB channel Slope with checkbox * Improve GUI and code channel TRC * Change default values - compexity levels RGB channels * Relative gamma mode RGB channel TRC * Change label and ponderation rolloff * Change rolloff level * Threshold attenuation * Threshold attenuation 2 part * GUI Link R G B * Linked RGB with Green slope - RGB channels * Set Freeman TM functions with ImProcFunctions * First GUI Abstract profile highlight attenuation * GUI AP part 2 * Restore olg GUI AP * Expander AP primaries adn illuminant * Disable RGB channel TRC * Expander contrast AP * Slider attenuation response * Save work GUI local contrast * Save GUI part 2 AP curve * Local contrast GUI Abstract Profile * Move Abstract profile in toolpanel and ICMpanel * rtengine variable contrast * Variable contrast 2 * Variable contrast engine 3 * Variable contrast engine 4 * Variable contrast engine * Detail levels pyramid * Engine residual contrast * Residual contrast * Change settings detail levels * Expander refinement - new tooltips - low resid contrast * Change contrast profile and labels * Remove warning message GUI Gtk * Gamutcontrol code - disabled * Improve with calceffect * Other improvement variable contrast * Offset variable contrast * Range offset - comment code * Parametric inva fot lut * Clean cmakelist.txt * Change contrast profiles * Comment code ipwavelet * Added orthogonal Daubechies scaling D20 * Change strenght curve - tooltip Daubechies * Forgotten changes * Comment code * Move variable in process - take into account highlight attenuation * Display label maximum preview and preset selection * Remove console message * harmonize levels wavelets iplocallab * Tooltips contrast enhancement * Change tooltip Contrast profile * Chnage tooltip Contrast * Message warning preview size * Change gamma TRC values in GUI * Remove itanium architecture support for windows as PR 7105 * Change windows.yml and appimage.yml * Windows.yml apseimprov * Clean and comment ipwavelet * Clean comment icmpanel.cc * Harmonize local contrast wavelet Selective editing with Abstract profile * Harmonize with AP - offset * vanishing moment D20 - Selective editing wavelet * Offset only in advanced mode * GUI expander contrast enable and pyrwavtrc * Clean and comment code * merge with dev * Prepare sigmoid based * Contrast sigmoid GUI * Skew sigmoid GUI * Sigmoid tone mapper in iplocallab * Change GUI settings * White-point and black-point auto * Change EvDCP to ALLNORAW as others events DCP * Change default skew * Change settings - enable scale Yb * Display white point - advanced mode * Improve GUI * Clean unused variable * new sigmoid Q in cam16 * Change tooltips and default sigmoid Q settings * Sigmoid Jz * Clean code Jz and sigmoid * Harmonize Sigmoid Q and Sigmoid RGB * Harmonize Sigmoid Jz * Clean code * Improve labels wit cd/m2 * Slope base Q methode first * GUI slope based Q * Change default settings and tooltips * Change tooltips * Clean code - change default setting * Change default local contrast & wavelet to wavelet & basic mode * Fixed bad assignation slopesmoq * Improve sigmoid and slope based Q - GUI for Log encoding Color appearance * Remove wrong change * various small improvments * Allows black and white AP and SDA in basic mode * Change the writing of wGamma and wSlope - attenuates the effect of the first 2 AP contrast profiles * Clean code wgamma wslope * Set curve Cam16 in basic mode * Change position curve in GUI cam16 * Enable tonecurve1 in colorappearance & lighting in standard mode * Fixed bug scale yb scene - ciecam curve - change default contrast enhancement * not reset curve shape ciecam in strandard * Change label Tone mapping operators and tooltips * Change some labels and tooltips - Appearance - Mask and Mofifications - Recovery Based On Luminance Mask * Forgotten changes * Clean locallabtools2.cc * Maxlevel wavelet minimum to 5 * Reset mask and modifications in SE wavelet and all tools in Global * Show modified areas SE wavelet * Tooltip show wavelets decomposition * Fixed another bad behavior in Global - changes also in color & light for merge file * Change behavior fullimage - global as in PR GHS * Disable all mask and modifications in Global but remain active in fullimage and normal * Set expander expanded = true * Chane contrast enhancement coef * Replace VBox trcWavVBox by ToolParamBlock trcWavFBox * Forgotten code in icmpanel read pedited opacityShapeWLI - hope solve batch mode * Change RGB Slope behavior with link * No access to last level contrast enhancement * Move Abstract Profile tooltip to title The tooltip was popping up when the cursor was over almost any part of the tool which was inconvenient. Now, the tooltip only appears when hovering over the title. * Improve Color Management expanders behavior By default, collapse Abstract Profile and leave it's sub-expanders expanded. Keep the expanded state of all the sub-expanders during the editing session. Fix the right-click behavior. The clicked expander should be expanded and all siblings, if any, should be collapsed. * Fix RGB slope tone mapping RGB linkage Synchronize the red, green, and blue values before updating the preview to avoid using incorrect values to generate the preview. * Fix SE CAM tone mapping slider defocus Avoid unnecessarily hiding then showing the adjusters in tone mapping so that focus is not lost while adjusting the adjusters. * Delete history kslopesmo - remove IcmOpacityCurveWL * change the tooltips as suggested by Lawrence * Review L37 - change strengthjz strengthlc - MIDDLE_GREY MIDDLE_GREYjz - artifacts ciecam * Change name Tone map freeman functions * Remove gamutcont - rename localcont - change allocation memory wdspot * Clean procparams * remove sigmoidsenscie - logcieq * Added * to three labels 'sigmoid' - change tooltip which shows the incompatibility with 5.11 * Forgotten correction suggested by Lawrence * Compatibility 5.11 log encoding - sigmoid part 1 * Compatibility 5.11 part 2 * Compatibility 5.11 - step 3 * Compatibility 5.11 - step 4 * Compatibility 5.11 step xx * Compatibility 5.11 - combobox operators Q and J * Compatibility 5.11 Cam16 GUI first part * Improve GUI Cam16 sigmoid compatibility * Compatibility 5.11 Jz - sigmoid - step 1 * Compatibility 5.11 Jz gui step 2 * Compatibility 5.11 Jz GUI step x * Compatibility 5.11 Jz - history - etc. * Various change labels - history ... * Improve GUI - hide show 5.11 5.12 * Jz 5.11 in iplocallab - step 1 * Compatibility 5.11 iplocallab cam16 step 1 * Improve GUI hide show 511 512 * Solved - I hope - GUI problem with tone mapper Q and J 5.11 and 5.12 * Compatibility 5.11 iplocallab Cam16 step 2 * Improve GUI compatibility 5.11 labels tooltips * Small improvments GUI - labels - history... * Fixed typo in paramsedited.cc clcurve issue 7283 * Change tooltips method 5.12 - 5.11 for cam16 and Jz brightness Q or J * Clean and refine code * Various change dafult language and CAM16 CAM02 replace by Cam16 Cam02 * Change modeQJ method for 5.11 in function ppversion * Change labels as suggested by Wayne PR 7111 * Others changes suggested for label * Change tooltips as suggested in PR * Use unique pointer instead of manual management * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Change all Cam16 references to CAM16 * Change convention uppercase and lowercase in frame - checkbox * Improve tooltips for Tone Mapping Operators * Another change CIECAM and uppercase lowercase in checkbox * Remove appimage and windows yml --------- Co-authored-by: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com>
2152 lines
97 KiB
C++
2152 lines
97 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <glibmm/ustring.h>
|
|
#include <glibmm/timer.h>
|
|
|
|
#include "cieimage.h"
|
|
#include "color.h"
|
|
#include "curves.h"
|
|
#include "dcp.h"
|
|
#include "dcrop.h"
|
|
#include "guidedfilter.h"
|
|
#include "image8.h"
|
|
#include "imagefloat.h"
|
|
#include "improccoordinator.h"
|
|
#include "labimage.h"
|
|
#include "mytime.h"
|
|
#include "procparams.h"
|
|
#include "refreshmap.h"
|
|
#include "rt_math.h"
|
|
#include "utils.h"
|
|
|
|
#include "rtgui/editcallbacks.h"
|
|
|
|
#pragma GCC diagnostic warning "-Wall"
|
|
#pragma GCC diagnostic warning "-Wextra"
|
|
namespace
|
|
{
|
|
|
|
// "ceil" rounding
|
|
template<typename T>
|
|
constexpr T skips(T a, T b)
|
|
{
|
|
return a / b + static_cast<bool>(a % b);
|
|
}
|
|
|
|
}
|
|
|
|
namespace rtengine
|
|
{
|
|
|
|
Crop::Crop(ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow)
|
|
: PipetteBuffer(editDataProvider), origCrop(nullptr), spotCrop(nullptr), laboCrop(nullptr), labnCrop(nullptr),
|
|
cropImg(nullptr), shbuf_real(nullptr), transCrop(nullptr), cieCrop(nullptr), shbuffer(nullptr),
|
|
updating(false), newUpdatePending(false), skip(10),
|
|
cropx(0), cropy(0), cropw(-1), croph(-1),
|
|
trafx(0), trafy(0), trafw(-1), trafh(-1),
|
|
rqcropx(0), rqcropy(0), rqcropw(-1), rqcroph(-1),
|
|
borderRequested(32), upperBorder(0), leftBorder(0),
|
|
cropAllocated(false),
|
|
cropImageListener(nullptr), parent(parent), isDetailWindow(isDetailWindow)
|
|
{
|
|
parent->crops.push_back(this);
|
|
}
|
|
|
|
Crop::~Crop()
|
|
{
|
|
|
|
MyMutex::MyLock cropLock(cropMutex);
|
|
|
|
std::vector<Crop*>::iterator i = std::find(parent->crops.begin(), parent->crops.end(), this);
|
|
|
|
if (i != parent->crops.end()) {
|
|
parent->crops.erase(i);
|
|
}
|
|
|
|
MyMutex::MyLock processingLock(parent->mProcessing);
|
|
freeAll();
|
|
}
|
|
|
|
void Crop::destroy()
|
|
{
|
|
MyMutex::MyLock lock(cropMutex);
|
|
MyMutex::MyLock processingLock(parent->mProcessing);
|
|
freeAll();
|
|
}
|
|
|
|
void Crop::setListener(DetailedCropListener* il)
|
|
{
|
|
// We can make reads in the IF, because the mProcessing lock is only needed for change
|
|
if (cropImageListener != il) {
|
|
MyMutex::MyLock lock(cropMutex);
|
|
cropImageListener = il;
|
|
}
|
|
}
|
|
|
|
EditUniqueID Crop::getCurrEditID() const
|
|
{
|
|
const EditSubscriber *subscriber = PipetteBuffer::dataProvider ? PipetteBuffer::dataProvider->getCurrSubscriber() : nullptr;
|
|
return subscriber ? subscriber->getEditID() : EUID_None;
|
|
}
|
|
|
|
/*
|
|
* Delete the edit image buffer if there's no subscriber anymore.
|
|
* If allocation has to be done, it is deferred to Crop::update
|
|
*/
|
|
void Crop::setEditSubscriber(EditSubscriber* newSubscriber)
|
|
{
|
|
MyMutex::MyLock lock(cropMutex);
|
|
|
|
// At this point, editCrop.dataProvider->currSubscriber is the old subscriber
|
|
const EditSubscriber *oldSubscriber = PipetteBuffer::dataProvider ? PipetteBuffer::dataProvider->getCurrSubscriber() : nullptr;
|
|
|
|
if (newSubscriber == nullptr || (oldSubscriber != nullptr && oldSubscriber->getPipetteBufferType() != newSubscriber->getPipetteBufferType())) {
|
|
if (PipetteBuffer::imgFloatBuffer != nullptr) {
|
|
delete PipetteBuffer::imgFloatBuffer;
|
|
PipetteBuffer::imgFloatBuffer = nullptr;
|
|
}
|
|
|
|
if (PipetteBuffer::LabBuffer != nullptr) {
|
|
delete PipetteBuffer::LabBuffer;
|
|
PipetteBuffer::LabBuffer = nullptr;
|
|
}
|
|
|
|
if (PipetteBuffer::singlePlaneBuffer.getWidth() != -1) {
|
|
PipetteBuffer::singlePlaneBuffer.flushData();
|
|
}
|
|
}
|
|
|
|
// If oldSubscriber == NULL && newSubscriber != NULL && newSubscriber->getEditingType() == ET_PIPETTE-> the image will be allocated when necessary
|
|
}
|
|
|
|
bool Crop::hasListener()
|
|
{
|
|
MyMutex::MyLock cropLock(cropMutex);
|
|
return cropImageListener;
|
|
}
|
|
|
|
void Crop::update(int todo)
|
|
{
|
|
MyMutex::MyLock cropLock(cropMutex);
|
|
|
|
ProcParams& params = *parent->params;
|
|
// CropGUIListener* cropgl;
|
|
|
|
// No need to update todo here, since it has already been changed in ImprocCoordinator::updatePreviewImage,
|
|
// and Crop::update ask to do ALL anyway
|
|
|
|
// give possibility to the listener to modify crop window (as the full image dimensions are already known at this point)
|
|
int wx, wy, ww, wh, ws;
|
|
const bool overrideWindow = cropImageListener;
|
|
bool spotsDone = false;
|
|
|
|
if (overrideWindow) {
|
|
cropImageListener->getWindow(wx, wy, ww, wh, ws);
|
|
}
|
|
|
|
// re-allocate sub-images and arrays if their dimensions changed
|
|
bool needsinitupdate = false;
|
|
|
|
if (!overrideWindow) {
|
|
needsinitupdate = setCropSizes(rqcropx, rqcropy, rqcropw, rqcroph, skip, true);
|
|
} else {
|
|
needsinitupdate = setCropSizes(wx, wy, ww, wh, ws, true); // this set skip=ws
|
|
}
|
|
|
|
// it something has been reallocated, all processing steps have to be performed
|
|
if (needsinitupdate || (todo & M_HIGHQUAL)) {
|
|
todo = ALL;
|
|
}
|
|
|
|
// Tells to the ImProcFunctions' tool what is the preview scale, which may lead to some simplifications
|
|
parent->ipf.setScale(skip);
|
|
|
|
Imagefloat* baseCrop = origCrop;
|
|
int widIm = parent->fw;//full image
|
|
int heiIm = parent->fh;
|
|
|
|
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
|
|
MyMutex::MyLock lock(parent->minit); // Also used in improccoord
|
|
|
|
int tr = getCoarseBitMask(params.coarse);
|
|
|
|
if (!needsinitupdate) {
|
|
setCropSizes(rqcropx, rqcropy, rqcropw, rqcroph, skip, true);
|
|
}
|
|
|
|
// printf("x=%d y=%d crow=%d croh=%d skip=%d\n",rqcropx, rqcropy, rqcropw, rqcroph, skip);
|
|
// printf("trafx=%d trafyy=%d trafwsk=%d trafHs=%d \n",trafx, trafy, trafw*skip, trafh*skip);
|
|
|
|
Imagefloat *calclum = nullptr;//for Luminance denoise curve
|
|
NoiseCurve noiseLCurve;
|
|
NoiseCurve noiseCCurve;
|
|
float autoNR = (float) settings->nrauto;//
|
|
float autoNRmax = (float) settings->nrautomax;//
|
|
|
|
params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve);
|
|
|
|
const int tilesize = settings->leveldnti == 0 ? 1024 : 768;
|
|
const int overlap = settings->leveldnti == 0 ? 128 : 96;
|
|
|
|
int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip;
|
|
|
|
parent->ipf.Tile_calc(tilesize, overlap, 2, widIm, heiIm, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip);
|
|
|
|
float *min_b = new float [9];
|
|
float *min_r = new float [9];
|
|
float *lumL = new float [9];
|
|
float *chromC = new float [9];
|
|
float *ry = new float [9];
|
|
float *sk = new float [9];
|
|
float *pcsk = new float [9];
|
|
int *centerTile_X = new int [numtiles_W];
|
|
int *centerTile_Y = new int [numtiles_H];
|
|
|
|
for (int cX = 0; cX < numtiles_W; cX++) {
|
|
centerTile_X[cX] = tileWskip / 2 + tileWskip * cX;
|
|
}
|
|
|
|
for (int cY = 0; cY < numtiles_H; cY++) {
|
|
centerTile_Y[cY] = tileHskip / 2 + tileHskip * cY;
|
|
}
|
|
|
|
if (settings->leveldnautsimpl == 1) {
|
|
if (params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON") {
|
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
|
}
|
|
} else {
|
|
if (params.dirpyrDenoise.C2method == "MANU") {
|
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
|
}
|
|
}
|
|
|
|
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) {
|
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
|
|
|
if ((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) {
|
|
float lowdenoise = 1.f;
|
|
int levaut = settings->leveldnaut;
|
|
|
|
if (levaut == 1) { //Standard
|
|
lowdenoise = 0.7f;
|
|
}
|
|
|
|
int CenterPreview_X = trafx + (trafw * skip) / 2;
|
|
int CenterPreview_Y = trafy + (trafh * skip) / 2;
|
|
int minimuX = 20000;
|
|
int minimuY = 20000;
|
|
int poscenterX = 0;
|
|
int poscenterY = 0;
|
|
|
|
for (int cc = 0; cc < numtiles_W; cc++) {
|
|
if (abs(centerTile_X[cc] - CenterPreview_X) < minimuX) {
|
|
minimuX = abs(centerTile_X[cc] - CenterPreview_X);
|
|
poscenterX = cc;
|
|
}
|
|
}
|
|
|
|
for (int cc = 0; cc < numtiles_H; cc++) {
|
|
if (abs(centerTile_Y[cc] - CenterPreview_Y) < minimuY) {
|
|
minimuY = abs(centerTile_Y[cc] - CenterPreview_Y);
|
|
poscenterY = cc;
|
|
}
|
|
}
|
|
|
|
// printf("TileCX=%d TileCY=%d prevX=%d prevY=%d \n",centerTile_X[poscenterX],centerTile_Y[poscenterY],CenterPreview_X,CenterPreview_Y);
|
|
int crW;
|
|
|
|
if (settings->leveldnv == 0) {
|
|
crW = 100;
|
|
}
|
|
|
|
if (settings->leveldnv == 1) {
|
|
crW = 250;
|
|
}
|
|
|
|
// if (settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview
|
|
if (settings->leveldnv == 2) {
|
|
crW = int (tileWskip / 2);
|
|
}
|
|
|
|
if (settings->leveldnv == 3) {
|
|
crW = tileWskip - 10;
|
|
}
|
|
|
|
float adjustr = 1.f;
|
|
|
|
if (params.icm.workingProfile == "ProPhoto") {
|
|
adjustr = 1.f;
|
|
} else if (params.icm.workingProfile == "Adobe RGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.workingProfile == "sRGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.workingProfile == "WideGamut") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.workingProfile == "Beta RGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.workingProfile == "BestRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.workingProfile == "BruceRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
}
|
|
|
|
if (parent->adnListener) {
|
|
parent->adnListener->noiseTilePrev(centerTile_X[poscenterX], centerTile_Y[poscenterY], CenterPreview_X, CenterPreview_Y, crW, trafw * skip);
|
|
}
|
|
|
|
// I have tried "blind" some solutions..to move review ...but GUI is not my truc !
|
|
// int W,H;
|
|
// cropgl->cropMoved (centerTile_X[poscenterX],centerTile_Y[poscenterY] , W, H);
|
|
// cropImageListener->setPosition (int x, int y, bool update=true);
|
|
// bool update;
|
|
// cropImageListener->setPosition (centerTile_X[poscenterX],centerTile_Y[poscenterY] , true);
|
|
//setCropSizes (centerTile_X[poscenterX], centerTile_Y[poscenterY], trafw*skip,trafh*skip , skip, true);
|
|
|
|
// we only need image reduced to 1/4 here
|
|
int W = origCrop->getWidth();
|
|
int H = origCrop->getHeight();
|
|
Imagefloat *provicalc = new Imagefloat((W + 1) / 2, (H + 1) / 2); //for denoise curves
|
|
|
|
for (int ii = 0; ii < H; ii += 2) {
|
|
for (int jj = 0; jj < W; jj += 2) {
|
|
provicalc->r(ii >> 1, jj >> 1) = origCrop->r(ii, jj);
|
|
provicalc->g(ii >> 1, jj >> 1) = origCrop->g(ii, jj);
|
|
provicalc->b(ii >> 1, jj >> 1) = origCrop->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
parent->imgsrc->convertColorSpace(provicalc, params.icm, parent->currWB); //for denoise luminance curve
|
|
|
|
float maxr = 0.f;
|
|
float maxb = 0.f;
|
|
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
|
int Nb;
|
|
|
|
chaut = 0.f;
|
|
redaut = 0.f;
|
|
blueaut = 0.f;
|
|
maxredaut = 0.f;
|
|
maxblueaut = 0.f;
|
|
minredaut = 0.f;
|
|
minblueaut = 0.f;
|
|
LUTf gamcurve(65536, 0);
|
|
float gam, gamthresh, gamslope;
|
|
parent->ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
|
|
parent->ipf.RGB_denoise_info(origCrop, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc, true);
|
|
// printf("redy=%f skin=%f pcskin=%f\n",redyel, skinc,nsknc);
|
|
// printf("DCROP skip=%d cha=%4.0f Nb=%d red=%4.0f bl=%4.0f redM=%4.0f bluM=%4.0f L=%4.0f sigL=%4.0f Ch=%4.0f Si=%4.0f\n",skip, chaut,Nb, redaut,blueaut, maxredaut, maxblueaut, lumema, sigma_L, chromina, sigma);
|
|
float multip = 1.f;
|
|
|
|
if (!parent->imgsrc->isRAW()) {
|
|
multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good for gamma=1
|
|
}
|
|
|
|
float maxmax = max(maxredaut, maxblueaut);
|
|
float delta;
|
|
int mode = 0;
|
|
// float redyel, skinc, nsknc;
|
|
int lissage = settings->leveldnliss;
|
|
parent->ipf.calcautodn_info(chaut, delta, Nb, levaut, maxmax, lumema, chromina, mode, lissage, redyel, skinc, nsknc);
|
|
|
|
|
|
if (maxredaut > maxblueaut) {
|
|
// maxr=(maxredaut-chaut)/((autoNRmax*multip*adjustr)/2.f);
|
|
maxr = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
|
|
if (minblueaut <= minredaut && minblueaut < chaut) {
|
|
maxb = (-chaut + minblueaut) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
}
|
|
} else {
|
|
// maxb=(maxblueaut-chaut)/((autoNRmax*multip*adjustr)/2.f);
|
|
maxb = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
|
|
if (minredaut <= minblueaut && minredaut < chaut) {
|
|
maxr = (-chaut + minredaut) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
}
|
|
}//maxb mxr - empirical evaluation red / blue
|
|
|
|
|
|
params.dirpyrDenoise.chroma = chaut / (autoNR * multip * adjustr * lowdenoise);
|
|
params.dirpyrDenoise.redchro = maxr;
|
|
params.dirpyrDenoise.bluechro = maxb;
|
|
parent->adnListener->chromaChanged(params.dirpyrDenoise.chroma, params.dirpyrDenoise.redchro, params.dirpyrDenoise.bluechro);
|
|
|
|
delete provicalc;
|
|
}
|
|
}
|
|
|
|
if (skip == 1 && params.dirpyrDenoise.enabled && !parent->denoiseInfoStore.valid && ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO"))) {
|
|
MyTime t1aue, t2aue;
|
|
t1aue.set();
|
|
|
|
int crW = 100; // settings->leveldnv == 0
|
|
int crH = 100; // settings->leveldnv == 0
|
|
|
|
if (settings->leveldnv == 1) {
|
|
crW = 250;
|
|
crH = 250;
|
|
}
|
|
|
|
// if (settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview
|
|
if (settings->leveldnv == 2) {
|
|
crW = int (tileWskip / 2);
|
|
crH = int (tileHskip / 2);
|
|
}
|
|
|
|
if (settings->leveldnv == 3) {
|
|
crW = tileWskip - 10;
|
|
crH = tileHskip - 10;
|
|
}
|
|
|
|
float lowdenoise = 1.f;
|
|
int levaut = settings->leveldnaut;
|
|
|
|
if (levaut == 1) { //Standard
|
|
lowdenoise = 0.7f;
|
|
}
|
|
|
|
LUTf gamcurve(65536, 0);
|
|
float gam, gamthresh, gamslope;
|
|
parent->ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
|
|
int Nb[9];
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
Imagefloat *origCropPart = new Imagefloat(crW, crH); //allocate memory
|
|
Imagefloat *provicalc = new Imagefloat((crW + 1) / 2, (crH + 1) / 2); //for denoise curves
|
|
|
|
int coordW[3];//coordinate of part of image to measure noise
|
|
int coordH[3];
|
|
int begW = 50;
|
|
int begH = 50;
|
|
coordW[0] = begW;
|
|
coordW[1] = widIm / 2 - crW / 2;
|
|
coordW[2] = widIm - crW - begW;
|
|
coordH[0] = begH;
|
|
coordH[1] = heiIm / 2 - crH / 2;
|
|
coordH[2] = heiIm - crH - begH;
|
|
#ifdef _OPENMP
|
|
#pragma omp for schedule(dynamic) collapse(2) nowait
|
|
#endif
|
|
|
|
for (int wcr = 0; wcr <= 2; wcr++) {
|
|
for (int hcr = 0; hcr <= 2; hcr++) {
|
|
PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1);
|
|
parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
|
|
|
|
// we only need image reduced to 1/4 here
|
|
for (int ii = 0; ii < crH; ii += 2) {
|
|
for (int jj = 0; jj < crW; jj += 2) {
|
|
provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj);
|
|
provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj);
|
|
provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
parent->imgsrc->convertColorSpace(provicalc, params.icm, parent->currWB); //for denoise luminance curve
|
|
|
|
float pondcorrec = 1.0f;
|
|
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
|
int nb = 0;
|
|
parent->ipf.RGB_denoise_info(origCropPart, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
|
|
|
//printf("DCROP skip=%d cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f\n",skip, chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema);
|
|
Nb[hcr * 3 + wcr] = nb;
|
|
parent->denoiseInfoStore.ch_M[hcr * 3 + wcr] = pondcorrec * chaut;
|
|
parent->denoiseInfoStore.max_r[hcr * 3 + wcr] = pondcorrec * maxredaut;
|
|
parent->denoiseInfoStore.max_b[hcr * 3 + wcr] = pondcorrec * maxblueaut;
|
|
min_r[hcr * 3 + wcr] = pondcorrec * minredaut;
|
|
min_b[hcr * 3 + wcr] = pondcorrec * minblueaut;
|
|
lumL[hcr * 3 + wcr] = lumema;
|
|
chromC[hcr * 3 + wcr] = chromina;
|
|
ry[hcr * 3 + wcr] = redyel;
|
|
sk[hcr * 3 + wcr] = skinc;
|
|
pcsk[hcr * 3 + wcr] = nsknc;
|
|
|
|
}
|
|
}
|
|
|
|
delete provicalc;
|
|
delete origCropPart;
|
|
}
|
|
float chM = 0.f;
|
|
float MaxR = 0.f;
|
|
float MaxB = 0.f;
|
|
float MinR = 100000000000.f;
|
|
float MinB = 100000000000.f;
|
|
float maxr = 0.f;
|
|
float maxb = 0.f;
|
|
float Max_R[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
|
float Max_B[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
|
float Min_R[9];
|
|
float Min_B[9];
|
|
float MaxRMoy = 0.f;
|
|
float MaxBMoy = 0.f;
|
|
float MinRMoy = 0.f;
|
|
float MinBMoy = 0.f;
|
|
|
|
float multip = 1.f;
|
|
|
|
if (!parent->imgsrc->isRAW()) {
|
|
multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good for gamma=1
|
|
}
|
|
|
|
float adjustr = 1.f;
|
|
|
|
if (params.icm.workingProfile == "ProPhoto") {
|
|
adjustr = 1.f; //
|
|
} else if (params.icm.workingProfile == "Adobe RGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.workingProfile == "sRGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.workingProfile == "WideGamut") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.workingProfile == "Beta RGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.workingProfile == "BestRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.workingProfile == "BruceRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
}
|
|
|
|
float delta[9];
|
|
int mode = 1;
|
|
int lissage = settings->leveldnliss;
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
float maxmax = max(parent->denoiseInfoStore.max_r[k], parent->denoiseInfoStore.max_b[k]);
|
|
parent->ipf.calcautodn_info(parent->denoiseInfoStore.ch_M[k], delta[k], Nb[k], levaut, maxmax, lumL[k], chromC[k], mode, lissage, ry[k], sk[k], pcsk[k]);
|
|
// printf("ch_M=%f delta=%f\n",ch_M[k], delta[k]);
|
|
}
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
if (parent->denoiseInfoStore.max_r[k] > parent->denoiseInfoStore.max_b[k]) {
|
|
Max_R[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
Min_B[k] = - (parent->denoiseInfoStore.ch_M[k] - min_b[k]) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
Max_B[k] = 0.f;
|
|
Min_R[k] = 0.f;
|
|
} else {
|
|
Max_B[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
Min_R[k] = - (parent->denoiseInfoStore.ch_M[k] - min_r[k]) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
Min_B[k] = 0.f;
|
|
Max_R[k] = 0.f;
|
|
}
|
|
}
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
// printf("ch_M= %f Max_R=%f Max_B=%f min_r=%f min_b=%f\n",ch_M[k],Max_R[k], Max_B[k],Min_R[k], Min_B[k]);
|
|
chM += parent->denoiseInfoStore.ch_M[k];
|
|
MaxBMoy += Max_B[k];
|
|
MaxRMoy += Max_R[k];
|
|
MinRMoy += Min_R[k];
|
|
MinBMoy += Min_B[k];
|
|
|
|
if (Max_R[k] > MaxR) {
|
|
MaxR = Max_R[k];
|
|
}
|
|
|
|
if (Max_B[k] > MaxB) {
|
|
MaxB = Max_B[k];
|
|
}
|
|
|
|
if (Min_R[k] < MinR) {
|
|
MinR = Min_R[k];
|
|
}
|
|
|
|
if (Min_B[k] < MinB) {
|
|
MinB = Min_B[k];
|
|
}
|
|
}
|
|
|
|
chM /= 9;
|
|
MaxBMoy /= 9;
|
|
MaxRMoy /= 9;
|
|
MinBMoy /= 9;
|
|
MinRMoy /= 9;
|
|
|
|
if (MaxR > MaxB) {
|
|
maxr = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev
|
|
//maxb=MinB;
|
|
maxb = MinBMoy + (MinB - MinBMoy) * 0.66f;
|
|
} else {
|
|
maxb = MaxBMoy + (MaxB - MaxBMoy) * 0.66f;
|
|
maxr = MinRMoy + (MinR - MinRMoy) * 0.66f;
|
|
}
|
|
|
|
// printf("DCROP skip=%d cha=%f red=%f bl=%f \n",skip, chM,maxr,maxb);
|
|
params.dirpyrDenoise.chroma = chM / (autoNR * multip * adjustr);
|
|
params.dirpyrDenoise.redchro = maxr;
|
|
params.dirpyrDenoise.bluechro = maxb;
|
|
parent->denoiseInfoStore.valid = true;
|
|
if (parent->adnListener) {
|
|
parent->adnListener->chromaChanged(params.dirpyrDenoise.chroma, params.dirpyrDenoise.redchro, params.dirpyrDenoise.bluechro);
|
|
}
|
|
|
|
if (settings->verbose) {
|
|
t2aue.set();
|
|
printf("Info denoise auto performed in %d usec:\n", t2aue.etime(t1aue));
|
|
}
|
|
|
|
//end evaluate noise
|
|
}
|
|
|
|
// if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto
|
|
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto
|
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
|
}
|
|
|
|
if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) {
|
|
spotsDone = true;
|
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
//parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
|
parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, nullptr, tr);
|
|
}
|
|
|
|
DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise;
|
|
|
|
if (params.dirpyrDenoise.Lmethod == "CUR") {
|
|
if (noiseLCurve) {
|
|
denoiseParams.luma = 0.5f; //very small value to init process - select curve or slider
|
|
} else {
|
|
denoiseParams.luma = 0.0f;
|
|
}
|
|
} else if (denoiseParams.Lmethod == "SLI") {
|
|
noiseLCurve.Reset();
|
|
}
|
|
|
|
if ((noiseLCurve || noiseCCurve) && skip == 1 && denoiseParams.enabled) { //only allocate memory if enabled and skip
|
|
// we only need image reduced to 1/4 here
|
|
int W = origCrop->getWidth();
|
|
int H = origCrop->getHeight();
|
|
calclum = new Imagefloat((W + 1) / 2, (H + 1) / 2); //for denoise curves
|
|
|
|
for (int ii = 0; ii < H; ii += 2) {
|
|
for (int jj = 0; jj < W; jj += 2) {
|
|
calclum->r(ii >> 1, jj >> 1) = origCrop->r(ii, jj);
|
|
calclum->g(ii >> 1, jj >> 1) = origCrop->g(ii, jj);
|
|
calclum->b(ii >> 1, jj >> 1) = origCrop->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
parent->imgsrc->convertColorSpace(calclum, params.icm, parent->currWB); //for denoise luminance curve
|
|
}
|
|
|
|
if (skip != 1) if (parent->adnListener) {
|
|
parent->adnListener->noiseChanged(0.f, 0.f);
|
|
}
|
|
|
|
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
|
|
|
|
if (skip == 1 && denoiseParams.enabled) {
|
|
|
|
float nresi, highresi;
|
|
parent->ipf.RGB_denoise(0, origCrop, origCrop, calclum, parent->denoiseInfoStore.ch_M, parent->denoiseInfoStore.max_r, parent->denoiseInfoStore.max_b, parent->imgsrc->isRAW(), /*Roffset,*/ denoiseParams, parent->imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, nresi, highresi);
|
|
|
|
if (parent->adnListener) {
|
|
parent->adnListener->noiseChanged(nresi, highresi);
|
|
}
|
|
|
|
if (settings->leveldnautsimpl == 1) {
|
|
if ((denoiseParams.Cmethod == "AUT" || denoiseParams.Cmethod == "PRE") && (parent->adnListener)) { // force display value of sliders
|
|
parent->adnListener->chromaChanged(denoiseParams.chroma, denoiseParams.redchro, denoiseParams.bluechro);
|
|
}
|
|
} else {
|
|
if ((denoiseParams.C2method == "AUTO" || denoiseParams.C2method == "PREV") && (parent->adnListener)) { // force display value of sliders
|
|
parent->adnListener->chromaChanged(denoiseParams.chroma, denoiseParams.redchro, denoiseParams.bluechro);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (params.filmNegative.enabled && params.filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) {
|
|
parent->ipf.filmNegativeProcess(baseCrop, baseCrop, params.filmNegative);
|
|
}
|
|
|
|
parent->imgsrc->convertColorSpace(origCrop, params.icm, parent->currWB);
|
|
|
|
if (params.filmNegative.enabled && params.filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) {
|
|
parent->ipf.filmNegativeProcess(baseCrop, baseCrop, params.filmNegative);
|
|
}
|
|
|
|
if (params.cg.enabled) {//gamut compression
|
|
parent->ipf.gamutcompr(baseCrop, baseCrop);
|
|
}
|
|
|
|
delete [] min_r;
|
|
delete [] min_b;
|
|
delete [] lumL;
|
|
delete [] chromC;
|
|
delete [] ry;
|
|
delete [] sk;
|
|
delete [] pcsk;
|
|
delete [] centerTile_X;
|
|
delete [] centerTile_Y;
|
|
|
|
}
|
|
|
|
// has to be called after setCropSizes! Tools prior to this point can't handle the Edit mechanism, but that shouldn't be a problem.
|
|
createBuffer(cropw, croph);
|
|
|
|
// Apply Spot removal
|
|
if ((todo & M_SPOT) && !spotsDone) {
|
|
if (params.spot.enabled && !params.spot.entries.empty()) {
|
|
if(!spotCrop) {
|
|
spotCrop = new Imagefloat (cropw, croph);
|
|
}
|
|
baseCrop->copyData (spotCrop);
|
|
PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip);
|
|
int tr = getCoarseBitMask(params.coarse);
|
|
parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, ¶ms.icm, tr);
|
|
} else {
|
|
if (spotCrop) {
|
|
delete spotCrop;
|
|
spotCrop = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (spotCrop) {
|
|
baseCrop = spotCrop;
|
|
}
|
|
|
|
std::unique_ptr<Imagefloat> fattalCrop;
|
|
|
|
if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) {
|
|
Imagefloat *f = origCrop;
|
|
int fw = skips(parent->fw, skip);
|
|
int fh = skips(parent->fh, skip);
|
|
bool need_cropping = false;
|
|
bool need_fattal = true;
|
|
|
|
if (trafx || trafy || trafw != fw || trafh != fh) {
|
|
need_cropping = true;
|
|
|
|
// fattal needs to work on the full image. So here we get the full
|
|
// image from imgsrc, and replace the denoised crop in case
|
|
if (!params.dirpyrDenoise.enabled && skip == 1 && parent->fattal_11_dcrop_cache) {
|
|
f = parent->fattal_11_dcrop_cache;
|
|
need_fattal = false;
|
|
} else {
|
|
f = new Imagefloat(fw, fh);
|
|
fattalCrop.reset(f);
|
|
PreviewProps pp(0, 0, parent->fw, parent->fh, skip);
|
|
int tr = getCoarseBitMask(params.coarse);
|
|
parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw);
|
|
parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB);
|
|
|
|
if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) {
|
|
// copy the denoised crop
|
|
int oy = trafy / skip;
|
|
int ox = trafx / skip;
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int y = 0; y < baseCrop->getHeight(); ++y) {
|
|
int dy = oy + y;
|
|
|
|
for (int x = 0; x < baseCrop->getWidth(); ++x) {
|
|
int dx = ox + x;
|
|
f->r(dy, dx) = baseCrop->r(y, x);
|
|
f->g(dy, dx) = baseCrop->g(y, x);
|
|
f->b(dy, dx) = baseCrop->b(y, x);
|
|
}
|
|
}
|
|
} else if (skip == 1) {
|
|
parent->fattal_11_dcrop_cache = f; // cache this globally
|
|
fattalCrop.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (need_fattal) {
|
|
parent->ipf.dehaze(f, params.dehaze);
|
|
parent->ipf.ToneMapFattal02(f, params.fattal, 3, 0, nullptr, 0, 0, 0, false);
|
|
}
|
|
|
|
// crop back to the size expected by the rest of the pipeline
|
|
if (need_cropping) {
|
|
Imagefloat *c = origCrop;
|
|
|
|
int oy = trafy / skip;
|
|
int ox = trafx / skip;
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int y = 0; y < trafh; ++y) {
|
|
int cy = y + oy;
|
|
|
|
for (int x = 0; x < trafw; ++x) {
|
|
int cx = x + ox;
|
|
c->r(y, x) = f->r(cy, cx);
|
|
c->g(y, x) = f->g(cy, cx);
|
|
c->b(y, x) = f->b(cy, cx);
|
|
}
|
|
}
|
|
|
|
baseCrop = c;
|
|
} else {
|
|
baseCrop = f;
|
|
}
|
|
}
|
|
|
|
const bool needstransform = parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData());
|
|
const bool cam02 = params.colorappearance.modelmethod == "02" && params.colorappearance.enabled;
|
|
|
|
// transform
|
|
// if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled)) {
|
|
if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !cam02)) {
|
|
if (!transCrop) {
|
|
transCrop = new Imagefloat(cropw, croph);
|
|
}
|
|
|
|
if (needstransform)
|
|
parent->ipf.transform(baseCrop, transCrop, cropx / skip, cropy / skip, trafx / skip, trafy / skip, skips(parent->fw, skip), skips(parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(),
|
|
parent->imgsrc->getMetaData(),
|
|
parent->imgsrc->getRotateDegree(), false);
|
|
else {
|
|
baseCrop->copyData(transCrop);
|
|
}
|
|
|
|
if (transCrop) {
|
|
baseCrop = transCrop;
|
|
}
|
|
} else {
|
|
delete transCrop;
|
|
transCrop = nullptr;
|
|
}
|
|
|
|
// if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) {
|
|
if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !cam02) {
|
|
|
|
const int W = baseCrop->getWidth();
|
|
const int H = baseCrop->getHeight();
|
|
LabImage labcbdl(W, H);
|
|
parent->ipf.rgb2lab(*baseCrop, labcbdl, params.icm.workingProfile);
|
|
parent->ipf.dirpyrequalizer(&labcbdl, skip);
|
|
parent->ipf.lab2rgb(labcbdl, *baseCrop, params.icm.workingProfile);
|
|
|
|
}
|
|
|
|
|
|
if ((todo & (M_AUTOEXP | M_RGBCURVE)) && params.locallab.enabled && !params.locallab.spots.empty()) {
|
|
|
|
//I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here.
|
|
parent->ipf.rgb2lab(*baseCrop, *laboCrop, params.icm.workingProfile);
|
|
|
|
|
|
labnCrop->CopyFrom(laboCrop);
|
|
|
|
const std::unique_ptr<LabImage> reservCrop(new LabImage(*laboCrop, true));
|
|
const std::unique_ptr<LabImage> lastorigCrop(new LabImage(*laboCrop, true));
|
|
std::unique_ptr<LabImage> savenormtmCrop;
|
|
std::unique_ptr<LabImage> savenormretiCrop;
|
|
auto& lllocalcurve2 = parent->lllocalcurve;
|
|
auto& cllocalcurve2 = parent->cllocalcurve;
|
|
auto& lclocalcurve2 = parent->lclocalcurve;
|
|
auto& cclocalcurve2 = parent->cclocalcurve;
|
|
auto& rgblocalcurve2 = parent->rgblocalcurve;
|
|
auto& exlocalcurve2 = parent->exlocalcurve;
|
|
auto& lmasklocalcurve2 = parent->lmasklocalcurve;
|
|
auto& lmaskexplocalcurve2 = parent->lmaskexplocalcurve;
|
|
auto& lmaskSHlocalcurve2 = parent->lmaskSHlocalcurve;
|
|
auto& lmaskviblocalcurve2 = parent->lmaskviblocalcurve;
|
|
auto& lmasktmlocalcurve2 = parent->lmasktmlocalcurve;
|
|
auto& lmaskretilocalcurve2 = parent->lmaskretilocalcurve;
|
|
auto& lmaskcblocalcurve2 = parent->lmaskcblocalcurve;
|
|
auto& lmaskbllocalcurve2 = parent->lmaskbllocalcurve;
|
|
auto& lmasklclocalcurve2 = parent->lmasklclocalcurve;
|
|
auto& lmaskloglocalcurve2 = parent->lmaskloglocalcurve;
|
|
auto& lmaskcielocalcurve2 = parent->lmaskcielocalcurve;
|
|
auto& cielocalcurve2 = parent->cielocalcurve;
|
|
auto& cielocalcurve22 = parent->cielocalcurve2;
|
|
auto& jzlocalcurve2 = parent->jzlocalcurve;
|
|
auto& czlocalcurve2 = parent->czlocalcurve;
|
|
auto& czjzlocalcurve2 = parent->czjzlocalcurve;
|
|
auto& hltonecurveloc2 = parent->hltonecurveloc;
|
|
auto& shtonecurveloc2 = parent->shtonecurveloc;
|
|
auto& tonecurveloc2 = parent->tonecurveloc;
|
|
auto& lightCurveloc2 = parent->lightCurveloc;
|
|
auto& locRETgainCurve = parent->locRETgainCurve;
|
|
auto& locRETtransCurve = parent->locRETtransCurve;
|
|
auto& loclhCurve = parent->loclhCurve;
|
|
auto& lochhCurve = parent->lochhCurve;
|
|
auto& locchCurve = parent->locchCurve;
|
|
auto& lochhCurvejz = parent->lochhCurvejz;
|
|
auto& locchCurvejz = parent->locchCurvejz;
|
|
auto& loclhCurvejz = parent->loclhCurvejz;
|
|
auto& locccmasCurve = parent->locccmasCurve;
|
|
auto& locllmasCurve = parent->locllmasCurve;
|
|
auto& lochhmasCurve = parent->lochhmasCurve;
|
|
auto& lochhhmasCurve = parent->lochhhmasCurve;
|
|
auto& lochhhmascieCurve = parent->lochhhmascieCurve;
|
|
auto& locccmasexpCurve = parent->locccmasexpCurve;
|
|
auto& locllmasexpCurve = parent->locllmasexpCurve;
|
|
auto& lochhmasexpCurve = parent->lochhmasexpCurve;
|
|
auto& locccmasSHCurve = parent->locccmasSHCurve;
|
|
auto& locllmasSHCurve = parent->locllmasSHCurve;
|
|
auto& lochhmasSHCurve = parent->lochhmasSHCurve;
|
|
auto& locccmasvibCurve = parent->locccmasvibCurve;
|
|
auto& locllmasvibCurve = parent->locllmasvibCurve;
|
|
auto& lochhmasvibCurve = parent->lochhmasvibCurve;
|
|
auto& locccmaslcCurve = parent->locccmaslcCurve;
|
|
auto& locllmaslcCurve = parent->locllmaslcCurve;
|
|
auto& lochhmaslcCurve = parent->lochhmaslcCurve;
|
|
auto& locccmascbCurve = parent->locccmascbCurve;
|
|
auto& locllmascbCurve = parent->locllmascbCurve;
|
|
auto& lochhmascbCurve = parent->lochhmascbCurve;
|
|
auto& locccmasretiCurve = parent->locccmasretiCurve;
|
|
auto& locllmasretiCurve = parent->locllmasretiCurve;
|
|
auto& lochhmasretiCurve = parent->lochhmasretiCurve;
|
|
auto& locccmastmCurve = parent->locccmastmCurve;
|
|
auto& locllmastmCurve = parent->locllmastmCurve;
|
|
auto& lochhmastmCurve = parent->lochhmastmCurve;
|
|
auto& locccmasblCurve = parent->locccmasblCurve;
|
|
auto& locllmasblCurve = parent->locllmasblCurve;
|
|
auto& lochhmasblCurve = parent->lochhmasblCurve;
|
|
auto& locccmaslogCurve = parent->locccmaslogCurve;
|
|
auto& locllmaslogCurve = parent->locllmaslogCurve;
|
|
auto& lochhmaslogCurve = parent->lochhmaslogCurve;
|
|
auto& locccmascieCurve = parent->locccmascieCurve;
|
|
auto& locllmascieCurve = parent->locllmascieCurve;
|
|
auto& lochhmascieCurve = parent->lochhmascieCurve;
|
|
|
|
auto& locccmas_Curve = parent->locccmas_Curve;
|
|
auto& locllmas_Curve = parent->locllmas_Curve;
|
|
auto& lochhmas_Curve = parent->lochhmas_Curve;
|
|
auto& lochhhmas_Curve = parent->lochhhmas_Curve;
|
|
auto& locwavCurve = parent->locwavCurve;
|
|
auto& locwavCurvejz = parent->locwavCurvejz;
|
|
auto& loclmasCurveblwav = parent->loclmasCurveblwav;
|
|
auto& loclmasCurvecolwav = parent->loclmasCurvecolwav;
|
|
auto& loclmasCurveciewav = parent->loclmasCurveciewav;
|
|
auto& loclevwavCurve = parent->loclevwavCurve;
|
|
auto& locconwavCurve = parent->locconwavCurve;
|
|
auto& loccompwavCurve = parent->loccompwavCurve;
|
|
auto& loccomprewavCurve = parent->loccomprewavCurve;
|
|
auto& locedgwavCurve = parent->locedgwavCurve;
|
|
auto& locwavCurvehue = parent->locwavCurvehue;
|
|
auto& locwavCurveden = parent->locwavCurveden;
|
|
auto& lmasklocal_curve2 = parent->lmasklocal_curve;
|
|
auto& loclmasCurve_wav = parent->loclmasCurve_wav;
|
|
|
|
for (int sp = 0; sp < (int)params.locallab.spots.size(); sp++) {
|
|
locRETgainCurve.Set(params.locallab.spots.at(sp).localTgaincurve);
|
|
locRETtransCurve.Set(params.locallab.spots.at(sp).localTtranscurve);
|
|
const bool LHutili = loclhCurve.Set(params.locallab.spots.at(sp).LHcurve);
|
|
const bool HHutili = lochhCurve.Set(params.locallab.spots.at(sp).HHcurve);
|
|
const bool CHutili = locchCurve.Set(params.locallab.spots.at(sp).CHcurve);
|
|
const bool HHutilijz = lochhCurvejz.Set(params.locallab.spots.at(sp).HHcurvejz);
|
|
const bool CHutilijz = locchCurvejz.Set(params.locallab.spots.at(sp).CHcurvejz);
|
|
const bool LHutilijz = loclhCurvejz.Set(params.locallab.spots.at(sp).LHcurvejz);
|
|
const bool lcmasutili = locccmasCurve.Set(params.locallab.spots.at(sp).CCmaskcurve);
|
|
const bool llmasutili = locllmasCurve.Set(params.locallab.spots.at(sp).LLmaskcurve);
|
|
const bool lhmasutili = lochhmasCurve.Set(params.locallab.spots.at(sp).HHmaskcurve);
|
|
const bool lhhmasutili = lochhhmasCurve.Set(params.locallab.spots.at(sp).HHhmaskcurve);
|
|
const bool lhhmascieutili = lochhhmascieCurve.Set(params.locallab.spots.at(sp).HHhmaskciecurve);
|
|
const bool lcmasexputili = locccmasexpCurve.Set(params.locallab.spots.at(sp).CCmaskexpcurve);
|
|
const bool llmasexputili = locllmasexpCurve.Set(params.locallab.spots.at(sp).LLmaskexpcurve);
|
|
const bool lhmasexputili = lochhmasexpCurve.Set(params.locallab.spots.at(sp).HHmaskexpcurve);
|
|
const bool lcmasSHutili = locccmasSHCurve.Set(params.locallab.spots.at(sp).CCmaskSHcurve);
|
|
const bool llmasSHutili = locllmasSHCurve.Set(params.locallab.spots.at(sp).LLmaskSHcurve);
|
|
const bool lhmasSHutili = lochhmasSHCurve.Set(params.locallab.spots.at(sp).HHmaskSHcurve);
|
|
const bool lcmasvibutili = locccmasvibCurve.Set(params.locallab.spots.at(sp).CCmaskvibcurve);
|
|
const bool llmasvibutili = locllmasvibCurve.Set(params.locallab.spots.at(sp).LLmaskvibcurve);
|
|
const bool lhmasvibutili = lochhmasvibCurve.Set(params.locallab.spots.at(sp).HHmaskvibcurve);
|
|
const bool lcmascbutili = locccmascbCurve.Set(params.locallab.spots.at(sp).CCmaskcbcurve);
|
|
const bool llmascbutili = locllmascbCurve.Set(params.locallab.spots.at(sp).LLmaskcbcurve);
|
|
const bool lhmascbutili = lochhmascbCurve.Set(params.locallab.spots.at(sp).HHmaskcbcurve);
|
|
const bool lcmasretiutili = locccmasretiCurve.Set(params.locallab.spots.at(sp).CCmaskreticurve);
|
|
const bool llmasretiutili = locllmasretiCurve.Set(params.locallab.spots.at(sp).LLmaskreticurve);
|
|
const bool lhmasretiutili = lochhmasretiCurve.Set(params.locallab.spots.at(sp).HHmaskreticurve);
|
|
const bool lcmastmutili = locccmastmCurve.Set(params.locallab.spots.at(sp).CCmasktmcurve);
|
|
const bool llmastmutili = locllmastmCurve.Set(params.locallab.spots.at(sp).LLmasktmcurve);
|
|
const bool lhmastmutili = lochhmastmCurve.Set(params.locallab.spots.at(sp).HHmasktmcurve);
|
|
const bool lcmasblutili = locccmasblCurve.Set(params.locallab.spots.at(sp).CCmaskblcurve);
|
|
const bool llmasblutili = locllmasblCurve.Set(params.locallab.spots.at(sp).LLmaskblcurve);
|
|
const bool lhmasblutili = lochhmasblCurve.Set(params.locallab.spots.at(sp).HHmaskblcurve);
|
|
const bool lcmaslogutili = locccmaslogCurve.Set(params.locallab.spots.at(sp).CCmaskcurveL);
|
|
const bool llmaslogutili = locllmaslogCurve.Set(params.locallab.spots.at(sp).LLmaskcurveL);
|
|
const bool lhmaslogutili = lochhmaslogCurve.Set(params.locallab.spots.at(sp).HHmaskcurveL);
|
|
const bool lcmascieutili = locccmascieCurve.Set(params.locallab.spots.at(sp).CCmaskciecurve);
|
|
const bool llmascieutili = locllmascieCurve.Set(params.locallab.spots.at(sp).LLmaskciecurve);
|
|
const bool lhmascieutili = lochhmascieCurve.Set(params.locallab.spots.at(sp).HHmaskciecurve);
|
|
|
|
const bool lcmas_utili = locccmas_Curve.Set(params.locallab.spots.at(sp).CCmask_curve);
|
|
const bool llmas_utili = locllmas_Curve.Set(params.locallab.spots.at(sp).LLmask_curve);
|
|
const bool lhmas_utili = lochhmas_Curve.Set(params.locallab.spots.at(sp).HHmask_curve);
|
|
const bool lhhmas_utili = lochhhmas_Curve.Set(params.locallab.spots.at(sp).HHhmask_curve);
|
|
const bool lmasutili_wav = loclmasCurve_wav.Set(params.locallab.spots.at(sp).LLmask_curvewav);
|
|
const bool lmasutiliblwav = loclmasCurveblwav.Set(params.locallab.spots.at(sp).LLmaskblcurvewav);
|
|
const bool lmasutilicolwav = loclmasCurvecolwav.Set(params.locallab.spots.at(sp).LLmaskcolcurvewav);
|
|
const bool lmasutiliciewav = loclmasCurveciewav.Set(params.locallab.spots.at(sp).LLmaskciecurvewav);
|
|
const bool lcmaslcutili = locccmaslcCurve.Set(params.locallab.spots.at(sp).CCmasklccurve);
|
|
const bool llmaslcutili = locllmaslcCurve.Set(params.locallab.spots.at(sp).LLmasklccurve);
|
|
const bool lhmaslcutili = lochhmaslcCurve.Set(params.locallab.spots.at(sp).HHmasklccurve);
|
|
const bool locwavutili = locwavCurve.Set(params.locallab.spots.at(sp).locwavcurve);
|
|
const bool locwavutilijz = locwavCurvejz.Set(params.locallab.spots.at(sp).locwavcurvejz);
|
|
const bool locwavhueutili = locwavCurvehue.Set(params.locallab.spots.at(sp).locwavcurvehue);
|
|
const bool locwavdenutili = locwavCurveden.Set(params.locallab.spots.at(sp).locwavcurveden);
|
|
const bool loclevwavutili = loclevwavCurve.Set(params.locallab.spots.at(sp).loclevwavcurve);
|
|
const bool locconwavutili = locconwavCurve.Set(params.locallab.spots.at(sp).locconwavcurve);
|
|
const bool loccompwavutili = loccompwavCurve.Set(params.locallab.spots.at(sp).loccompwavcurve);
|
|
const bool loccomprewavutili = loccomprewavCurve.Set(params.locallab.spots.at(sp).loccomprewavcurve);
|
|
const bool locedgwavutili = locedgwavCurve.Set(params.locallab.spots.at(sp).locedgwavcurve);
|
|
const bool locallutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).llcurve, lllocalcurve2, skip);
|
|
const bool localclutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).clcurve, cllocalcurve2, skip);
|
|
const bool locallcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).lccurve, lclocalcurve2, skip);
|
|
const bool localrgbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).rgbcurve, rgblocalcurve2, skip);
|
|
const bool localcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).cccurve, cclocalcurve2, skip);
|
|
const bool localexutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).excurve, exlocalcurve2, skip);
|
|
const bool localmaskutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve2, skip);
|
|
const bool localmaskexputili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve2, skip);
|
|
const bool localmaskSHutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve2, skip);
|
|
const bool localmaskvibutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve2, skip);
|
|
const bool localmasktmutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve2, skip);
|
|
const bool localmaskretiutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve2, skip);
|
|
const bool localmaskcbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve2, skip);
|
|
const bool localmasklcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve2, skip);
|
|
const bool localmaskblutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve2, skip);
|
|
const bool localmasklogutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskcurveL, lmaskloglocalcurve2, skip);
|
|
const bool localmask_utili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmask_curve, lmasklocal_curve2, skip);
|
|
const bool localmaskcieutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskciecurve, lmaskcielocalcurve2, skip);
|
|
const bool localcieutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).ciecurve, cielocalcurve2, skip);
|
|
const bool localcieutili2 = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).ciecurve2, cielocalcurve22, skip);
|
|
const bool localjzutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).jzcurve, jzlocalcurve2, skip);
|
|
const bool localczutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).czcurve, czlocalcurve2, skip);
|
|
const bool localczjzutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).czjzcurve, czjzlocalcurve2, skip);
|
|
|
|
double ecomp = params.locallab.spots.at(sp).expcomp;
|
|
double black = params.locallab.spots.at(sp).black;
|
|
double hlcompr = params.locallab.spots.at(sp).hlcompr;
|
|
double hlcomprthresh = params.locallab.spots.at(sp).hlcomprthresh;
|
|
double shcompr = params.locallab.spots.at(sp).shcompr;
|
|
double br = params.locallab.spots.at(sp).lightness;
|
|
if (black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) {
|
|
black *= 1.5;
|
|
}
|
|
std::vector<LocallabListener::locallabDenoiseLC> localldenoiselc;
|
|
|
|
double cont = params.locallab.spots.at(sp).contrast;
|
|
double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre;
|
|
huerefblu = parent->huerefblurs[sp];
|
|
chromarefblu = parent->chromarefblurs[sp];
|
|
lumarefblu = parent->lumarefblurs[sp];
|
|
huere = parent->huerefs[sp];
|
|
chromare = parent->chromarefs[sp];
|
|
lumare = parent->lumarefs[sp];
|
|
sobelre = parent->sobelrefs[sp];
|
|
const float avge = parent->avgs[sp];
|
|
float meantme = parent->meantms[sp];
|
|
float stdtme = parent->stdtms[sp];
|
|
float meanretie = parent->meanretis[sp];
|
|
float stdretie = parent->stdretis[sp];
|
|
|
|
float fab = 1.f;
|
|
float maxicam = -1000.f;
|
|
float rdx, rdy, grx, gry, blx, bly = 0.f;
|
|
float meanx, meany, meanxe, meanye = 0.f;
|
|
int ill = 2;
|
|
int prim = 3;
|
|
float minCD;
|
|
float maxCD;
|
|
float mini;
|
|
float maxi;
|
|
float Tmean;
|
|
float Tsigma;
|
|
float Tmin;
|
|
float Tmax;
|
|
int lastsav;
|
|
float highresi = 0.f;
|
|
float nresi = 0.f;
|
|
float highresi46 =0.f;
|
|
float nresi46 = 0.f;
|
|
float Lhighresi = 0.f;
|
|
float Lnresi = 0.f;
|
|
float Lhighresi46 = 0.f;
|
|
float Lnresi46 = 0.f;
|
|
float contsig = params.locallab.spots.at(sp).contsigqcie;
|
|
float slopeg = 1.f;
|
|
bool linkrgb = true;
|
|
float lightsig = params.locallab.spots.at(sp).lightsigqcie;
|
|
/* huerefp[sp] = huere;
|
|
chromarefp[sp] = chromare;
|
|
lumarefp[sp] = lumare;
|
|
*/
|
|
CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumare,
|
|
hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, avge,
|
|
skip);
|
|
// Locallab mask are only shown for selected spot
|
|
int fh = parent->fh;
|
|
int fw = parent->fw;
|
|
|
|
if (sp == params.locallab.selspot) {
|
|
|
|
parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop.get(), savenormtmCrop.get(), savenormretiCrop.get(), lastorigCrop.get(), fw, fh, cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve,
|
|
lllocalcurve2,locallutili,
|
|
cllocalcurve2, localclutili,
|
|
lclocalcurve2, locallcutili,
|
|
loclhCurve, lochhCurve, locchCurve,
|
|
lochhCurvejz, locchCurvejz, loclhCurvejz,
|
|
|
|
lmasklocalcurve2, localmaskutili,
|
|
lmaskexplocalcurve2, localmaskexputili,
|
|
lmaskSHlocalcurve2, localmaskSHutili,
|
|
lmaskviblocalcurve2, localmaskvibutili,
|
|
lmasktmlocalcurve2, localmasktmutili,
|
|
lmaskretilocalcurve2, localmaskretiutili,
|
|
lmaskcblocalcurve2, localmaskcbutili,
|
|
lmaskbllocalcurve2, localmaskblutili,
|
|
lmasklclocalcurve2, localmasklcutili,
|
|
lmaskloglocalcurve2, localmasklogutili,
|
|
lmasklocal_curve2, localmask_utili,
|
|
lmaskcielocalcurve2, localmaskcieutili,
|
|
cielocalcurve2,localcieutili,
|
|
cielocalcurve22,localcieutili2,
|
|
jzlocalcurve2,localjzutili,
|
|
czlocalcurve2,localczutili,
|
|
czjzlocalcurve2,localczjzutili,
|
|
|
|
locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, lochhhmascieCurve, lhhmascieutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili,
|
|
locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili,
|
|
locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili,
|
|
locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili,
|
|
locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili,
|
|
locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili,
|
|
locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili,
|
|
locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili,
|
|
locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili,
|
|
|
|
locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili,
|
|
locccmascieCurve, lcmascieutili, locllmascieCurve, llmasSHutili, lochhmascieCurve, lhmascieutili,
|
|
|
|
lochhhmas_Curve, lhhmas_utili,
|
|
loclmasCurveblwav,lmasutiliblwav,
|
|
loclmasCurvecolwav,lmasutilicolwav,
|
|
loclmasCurveciewav,lmasutiliciewav,
|
|
locwavCurve, locwavutili,
|
|
locwavCurvejz, locwavutilijz,
|
|
loclevwavCurve, loclevwavutili,
|
|
locconwavCurve, locconwavutili,
|
|
loccompwavCurve, loccompwavutili,
|
|
loccomprewavCurve, loccomprewavutili,
|
|
locwavCurvehue, locwavhueutili,
|
|
locwavCurveden, locwavdenutili,
|
|
locedgwavCurve, locedgwavutili,
|
|
loclmasCurve_wav,lmasutili_wav,
|
|
LHutili, HHutili, CHutili, HHutilijz, CHutilijz, LHutilijz, cclocalcurve2, localcutili, rgblocalcurve2, localrgbutili, localexutili, exlocalcurve2, hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2,
|
|
huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav,
|
|
parent->previewDeltaE, parent->locallColorMask, parent->locallColorMaskinv, parent->locallExpMask, parent->locallExpMaskinv, parent->locallSHMask, parent->locallSHMaskinv, parent->locallvibMask, parent->localllcMask, parent->locallsharMask, parent->locallcbMask, parent->locallretiMask, parent->locallsoftMask, parent->localltmMask, parent->locallblMask,
|
|
parent->localllogMask, parent->locall_Mask, parent->locallcieMask, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax,
|
|
meantme, stdtme, meanretie, stdretie, fab, maxicam,rdx, rdy, grx, gry, blx, bly, meanx, meany, meanxe, meanye, prim, ill, contsig, lightsig,
|
|
highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46, slopeg, linkrgb);
|
|
|
|
LocallabListener::locallabDenoiseLC denoiselc;
|
|
denoiselc.highres = highresi;
|
|
denoiselc.nres = nresi;
|
|
denoiselc.highres46 = highresi46;
|
|
denoiselc.nres46 = nresi46;
|
|
denoiselc.Lhighres = Lhighresi;
|
|
denoiselc.Lnres = Lnresi;
|
|
denoiselc.Lhighres46 = Lhighresi46;
|
|
denoiselc.Lnres46 = Lnresi46;
|
|
localldenoiselc.push_back(denoiselc);
|
|
|
|
if (parent->previewDeltaE || parent->locallColorMask == 5 || parent->locallvibMask == 4 || parent->locallExpMask == 5 || parent->locallSHMask == 4 || parent->localllcMask == 4 || parent->localltmMask == 4 || parent->localllogMask == 4 || parent->locallsoftMask == 6 || parent->localllcMask == 4 || parent->locallcieMask == 4) {
|
|
params.blackwhite.enabled = false;
|
|
params.colorToning.enabled = false;
|
|
params.rgbCurves.enabled = false;
|
|
params.chmixer.enabled = false;
|
|
params.hsvequalizer.enabled = false;
|
|
params.filmSimulation.enabled = false;
|
|
params.toneCurve.black = 0.f;
|
|
params.toneCurve.saturation = 0.f;
|
|
params.toneCurve.brightness= 0.f;
|
|
params.toneCurve.contrast = 0.f;
|
|
params.toneCurve.hlcompr = 0.f;
|
|
//these 3 are "before" LA
|
|
//params.toneCurve.expcomp = 0;
|
|
//params.toneCurve.curve = { 0 };
|
|
//params.toneCurve.curve2 = { 0 };
|
|
params.colorappearance.enabled = false;
|
|
params.vibrance.enabled = false;
|
|
params.labCurve.enabled = false;
|
|
params.wavelet.enabled = false;
|
|
params.epd.enabled = false;
|
|
params.softlight.enabled = false;
|
|
}
|
|
/*
|
|
if (parent->locallListener) {
|
|
parent->locallListener->refChanged2(huerefp, chromarefp, lumarefp, fabrefp, params.locallab.selspot);
|
|
|
|
}
|
|
*/
|
|
denoiselc.highres = highresi;
|
|
denoiselc.nres = nresi;
|
|
denoiselc.highres46 = highresi46;
|
|
denoiselc.nres46 = nresi46;
|
|
denoiselc.Lhighres = Lhighresi;
|
|
denoiselc.Lnres = Lnresi;
|
|
denoiselc.Lhighres46 = Lhighresi46;
|
|
denoiselc.Lnres46 = Lnresi46;
|
|
localldenoiselc.push_back(denoiselc);
|
|
|
|
|
|
if (parent->locallListener) {
|
|
parent->locallListener->denChanged(localldenoiselc, params.locallab.selspot);
|
|
}
|
|
|
|
} else {
|
|
parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop.get(), savenormtmCrop.get(), savenormretiCrop.get(), lastorigCrop.get(), fw, fh, cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve,
|
|
lllocalcurve2,locallutili,
|
|
cllocalcurve2, localclutili,
|
|
lclocalcurve2, locallcutili,
|
|
loclhCurve, lochhCurve, locchCurve,
|
|
lochhCurvejz, locchCurvejz, loclhCurvejz,
|
|
lmasklocalcurve2, localmaskutili,
|
|
lmaskexplocalcurve2, localmaskexputili,
|
|
lmaskSHlocalcurve2, localmaskSHutili,
|
|
lmaskviblocalcurve2, localmaskvibutili,
|
|
lmasktmlocalcurve2, localmasktmutili,
|
|
lmaskretilocalcurve2, localmaskretiutili,
|
|
lmaskcblocalcurve2, localmaskcbutili,
|
|
lmaskbllocalcurve2, localmaskblutili,
|
|
lmasklclocalcurve2, localmasklcutili,
|
|
lmaskloglocalcurve2, localmasklogutili,
|
|
lmasklocal_curve2, localmask_utili,
|
|
lmaskcielocalcurve2, localmaskcieutili,
|
|
cielocalcurve2,localcieutili,
|
|
cielocalcurve22,localcieutili2,
|
|
jzlocalcurve2,localjzutili,
|
|
czlocalcurve2,localczutili,
|
|
czjzlocalcurve2,localczjzutili,
|
|
|
|
locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili,lochhhmasCurve, lhhmasutili, lochhhmascieCurve, lhhmascieutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili,
|
|
locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili,
|
|
locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili,
|
|
locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili,
|
|
locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili,
|
|
locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili,
|
|
locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili,
|
|
locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili,
|
|
locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili,
|
|
|
|
locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili,
|
|
locccmascieCurve, lcmascieutili, locllmascieCurve, llmascieutili, lochhmascieCurve, lhmascieutili,
|
|
lochhhmas_Curve, lhhmas_utili,
|
|
|
|
loclmasCurveblwav,lmasutiliblwav,
|
|
loclmasCurvecolwav,lmasutilicolwav,
|
|
loclmasCurveciewav,lmasutiliciewav,
|
|
locwavCurve, locwavutili,
|
|
locwavCurvejz, locwavutilijz,
|
|
loclevwavCurve, loclevwavutili,
|
|
locconwavCurve, locconwavutili,
|
|
loccompwavCurve, loccompwavutili,
|
|
loccomprewavCurve, loccomprewavutili,
|
|
locwavCurvehue, locwavhueutili,
|
|
locwavCurveden, locwavdenutili,
|
|
locedgwavCurve, locedgwavutili,
|
|
loclmasCurve_wav,lmasutili_wav,
|
|
LHutili, HHutili, CHutili, HHutilijz, CHutilijz, LHutilijz, cclocalcurve2, localcutili, rgblocalcurve2, localrgbutili, localexutili, exlocalcurve2, hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2,
|
|
huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax,
|
|
meantme, stdtme, meanretie, stdretie, fab, maxicam, rdx, rdy, grx, gry, blx, bly, meanx, meany, meanxe, meanye, prim, ill, contsig, lightsig,
|
|
highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46, slopeg, linkrgb);
|
|
}
|
|
|
|
|
|
if (sp + 1u < params.locallab.spots.size()) {
|
|
// do not copy for last spot as it is not needed anymore
|
|
lastorigCrop->CopyFrom(labnCrop);
|
|
}
|
|
|
|
if (skip <= 2) {
|
|
Glib::usleep(settings->cropsleep); //wait to avoid crash when crop 100% and move window
|
|
}
|
|
}
|
|
/*
|
|
delete [] huerefp;
|
|
delete [] chromarefp;
|
|
delete [] lumarefp;
|
|
delete [] fabrefp;
|
|
*/
|
|
|
|
parent->ipf.lab2rgb(*labnCrop, *baseCrop, params.icm.workingProfile);
|
|
}
|
|
|
|
if (todo & M_RGBCURVE) {
|
|
double rrm, ggm, bbm;
|
|
DCPProfileApplyState as;
|
|
DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as);
|
|
|
|
LUTu histToneCurve;
|
|
parent->ipf.rgbProc (baseCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve,
|
|
params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->colourToningSatLimit, parent->colourToningSatLimitOpacity, parent->ctColorCurve, parent->ctOpacityCurve, parent->opautili, parent->clToningcurve, parent->cl2Toningcurve,
|
|
parent->customToneCurve1, parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW, rrm, ggm, bbm,
|
|
parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf, as, histToneCurve);
|
|
}
|
|
|
|
// apply luminance operations
|
|
if (todo & (M_LUMINANCE + M_COLOR)) { //
|
|
//I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here.
|
|
labnCrop->CopyFrom(laboCrop);
|
|
|
|
bool utili = parent->utili;
|
|
bool autili = parent->autili;
|
|
bool butili = parent->butili;
|
|
bool ccutili = parent->ccutili;
|
|
bool clcutili = parent->clcutili;
|
|
bool cclutili = parent->cclutili;
|
|
|
|
LUTu dummy;
|
|
if (params.colorToning.enabled && params.colorToning.method == "LabGrid") {
|
|
parent->ipf.colorToningLabGrid(labnCrop, 0,labnCrop->W , 0, labnCrop->H, false);
|
|
}
|
|
|
|
parent->ipf.shadowsHighlights(labnCrop, params.sh.enabled, params.sh.lab,params.sh.highlights ,params.sh.shadows, params.sh.radius, skip, params.sh.htonalwidth, params.sh.stonalwidth);
|
|
|
|
if (params.localContrast.enabled) {
|
|
// Alberto's local contrast
|
|
parent->ipf.localContrast(labnCrop, labnCrop->L, params.localContrast, false, skip);
|
|
}
|
|
parent->ipf.chromiLuminanceCurve(this, 1, labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->clcurve, parent->lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy);
|
|
parent->ipf.vibrance(labnCrop, params.vibrance, params.toneCurve.hrenabled, params.icm.workingProfile);
|
|
parent->ipf.labColorCorrectionRegions(labnCrop);
|
|
|
|
// if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) {
|
|
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!cam02)) {
|
|
parent->ipf.EPDToneMap(labnCrop, 0, skip);
|
|
}
|
|
|
|
//parent->ipf.EPDToneMap(labnCrop, 5, 1); //Go with much fewer than normal iterates for fast redisplay.
|
|
// for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled
|
|
if (skip == 1) {
|
|
// if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || (!cam02)) {
|
|
parent->ipf.impulsedenoise(labnCrop);
|
|
parent->ipf.defringe(labnCrop);
|
|
}
|
|
|
|
parent->ipf.MLsharpen(labnCrop);
|
|
|
|
// if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || (!cam02)) {
|
|
parent->ipf.MLmicrocontrast(labnCrop);
|
|
parent->ipf.sharpening(labnCrop, params.sharpening, parent->sharpMask);
|
|
}
|
|
}
|
|
|
|
// if (skip==1) {
|
|
|
|
if (params.dirpyrequalizer.cbdlMethod == "aft") {
|
|
// if (((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled))) {
|
|
if (((params.colorappearance.enabled && !settings->autocielab) || (!cam02))) {
|
|
parent->ipf.dirpyrequalizer(labnCrop, skip);
|
|
// parent->ipf.Lanczoslab (labnCrop,labnCrop , 1.f/skip);
|
|
}
|
|
}
|
|
|
|
if ((params.wavelet.enabled)) {
|
|
WaveletParams WaveParams = params.wavelet;
|
|
int kall = 0;
|
|
int minwin = min(labnCrop->W, labnCrop->H);
|
|
int maxlevelcrop = 10;
|
|
|
|
// if (cp.mul[9]!=0)maxlevelcrop=10;
|
|
// adap maximum level wavelet to size of crop
|
|
if (minwin * skip < 1024) {
|
|
maxlevelcrop = 9; //sampling wavelet 512
|
|
}
|
|
|
|
if (minwin * skip < 512) {
|
|
maxlevelcrop = 8; //sampling wavelet 256
|
|
}
|
|
|
|
if (minwin * skip < 256) {
|
|
maxlevelcrop = 7; //sampling 128
|
|
}
|
|
|
|
if (minwin * skip < 128) {
|
|
maxlevelcrop = 6;
|
|
}
|
|
|
|
if (minwin < 64) {
|
|
maxlevelcrop = 5;
|
|
}
|
|
|
|
int realtile;
|
|
|
|
if (params.wavelet.Tilesmethod == "big") {
|
|
realtile = 22;
|
|
} else /*if (params.wavelet.Tilesmethod == "lit")*/ {
|
|
realtile = 12;
|
|
}
|
|
|
|
int tilesize = 128 * realtile;
|
|
int overlap = (int) tilesize * 0.125f;
|
|
|
|
int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip;
|
|
|
|
parent->ipf.Tile_calc(tilesize, overlap, kall, labnCrop->W, labnCrop->H, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip);
|
|
//now we have tile dimensions, overlaps
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
int minsizetile = min(tilewidth, tileheight);
|
|
int maxlev2 = 10;
|
|
|
|
if (minsizetile < 1024 && maxlevelcrop == 10) {
|
|
maxlev2 = 9;
|
|
}
|
|
|
|
if (minsizetile < 512) {
|
|
maxlev2 = 8;
|
|
}
|
|
|
|
if (minsizetile < 256) {
|
|
maxlev2 = 7;
|
|
}
|
|
|
|
if (minsizetile < 128) {
|
|
maxlev2 = 6;
|
|
}
|
|
|
|
int maxL = min(maxlev2, maxlevelcrop);
|
|
|
|
if (parent->awavListener) {
|
|
parent->awavListener->wavChanged(float (maxL));
|
|
}
|
|
|
|
WavCurve wavCLVCurve;
|
|
WavCurve wavdenoise;
|
|
WavCurve wavdenoiseh;
|
|
Wavblcurve wavblcurve;
|
|
WavOpacityCurveRG waOpacityCurveRG;
|
|
WavOpacityCurveSH waOpacityCurveSH;
|
|
WavOpacityCurveBY waOpacityCurveBY;
|
|
WavOpacityCurveW waOpacityCurveW;
|
|
WavOpacityCurveWL waOpacityCurveWL;
|
|
LUTf wavclCurve;
|
|
|
|
params.wavelet.getCurves(wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL);
|
|
LabImage *unshar = nullptr;
|
|
Glib::ustring provis;
|
|
LabImage *provradius = nullptr;
|
|
bool procont = WaveParams.expcontrast;
|
|
bool prochro = WaveParams.expchroma;
|
|
bool proedge = WaveParams.expedge;
|
|
bool profin = WaveParams.expfinal;
|
|
bool proton = WaveParams.exptoning;
|
|
bool pronois = WaveParams.expnoise;
|
|
|
|
if (WaveParams.showmask) {
|
|
// WaveParams.showmask = false;
|
|
// WaveParams.expclari = true;
|
|
}
|
|
|
|
|
|
if (WaveParams.softrad > 0.f) {
|
|
provradius = new LabImage(*labnCrop, true);
|
|
}
|
|
|
|
|
|
|
|
if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") {
|
|
|
|
provis = params.wavelet.CLmethod;
|
|
params.wavelet.CLmethod = "all";
|
|
parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip);
|
|
unshar = new LabImage(*labnCrop, true);
|
|
|
|
params.wavelet.CLmethod = provis;
|
|
|
|
WaveParams.expcontrast = false;
|
|
WaveParams.expchroma = false;
|
|
WaveParams.expedge = false;
|
|
WaveParams.expfinal = false;
|
|
WaveParams.exptoning = false;
|
|
WaveParams.expnoise = false;
|
|
}
|
|
|
|
|
|
|
|
// parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip);
|
|
|
|
parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip);
|
|
|
|
if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") {
|
|
WaveParams.expcontrast = procont;
|
|
WaveParams.expchroma = prochro;
|
|
WaveParams.expedge = proedge;
|
|
WaveParams.expfinal = profin;
|
|
WaveParams.exptoning = proton;
|
|
WaveParams.expnoise = pronois;
|
|
if (WaveParams.softrad > 0.f) {
|
|
array2D<float> ble(labnCrop->W, labnCrop->H);
|
|
array2D<float> guid(labnCrop->W, labnCrop->H);
|
|
Imagefloat *tmpImage = nullptr;
|
|
tmpImage = new Imagefloat(labnCrop->W, labnCrop->H);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < labnCrop->H ; ir++)
|
|
for (int jr = 0; jr < labnCrop->W; jr++) {
|
|
float X, Y, Z;
|
|
float L = provradius->L[ir][jr];
|
|
float a = provradius->a[ir][jr];
|
|
float b = provradius->b[ir][jr];
|
|
Color::Lab2XYZ(L, a, b, X, Y, Z);
|
|
|
|
guid[ir][jr] = Y / 32768.f;
|
|
float La = labnCrop->L[ir][jr];
|
|
float aa = labnCrop->a[ir][jr];
|
|
float ba = labnCrop->b[ir][jr];
|
|
Color::Lab2XYZ(La, aa, ba, X, Y, Z);
|
|
tmpImage->r(ir, jr) = X;
|
|
tmpImage->g(ir, jr) = Y;
|
|
tmpImage->b(ir, jr) = Z;
|
|
ble[ir][jr] = Y / 32768.f;
|
|
}
|
|
double epsilmax = 0.0001;
|
|
double epsilmin = 0.00001;
|
|
double aepsil = (epsilmax - epsilmin) / 100.f;
|
|
double bepsil = epsilmin; //epsilmax - 100.f * aepsil;
|
|
double epsil = aepsil * WaveParams.softrad + bepsil;
|
|
|
|
float blur = 10.f / skip * (0.5f + 0.8f * WaveParams.softrad);
|
|
rtengine::guidedFilter(guid, ble, ble, blur, epsil, false);
|
|
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < labnCrop->H; ir++)
|
|
for (int jr = 0; jr < labnCrop->W; jr++) {
|
|
float X = tmpImage->r(ir, jr);
|
|
float Y = 32768.f * ble[ir][jr];
|
|
float Z = tmpImage->b(ir, jr);
|
|
float L, a, b;
|
|
Color::XYZ2Lab(X, Y, Z, L, a, b);
|
|
labnCrop->L[ir][jr] = L;
|
|
}
|
|
delete tmpImage;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") {
|
|
|
|
float mL = (float)(WaveParams.mergeL / 100.f);
|
|
float mC = (float)(WaveParams.mergeC / 100.f);
|
|
float mL0;
|
|
float mC0;
|
|
float background = 0.f;
|
|
int show = 0;
|
|
|
|
if ((WaveParams.CLmethod == "one" || WaveParams.CLmethod == "inf") && WaveParams.Backmethod == "black") {
|
|
mL0 = mC0 = 0.f;
|
|
mL = -1.5f * mL;
|
|
mC = -mC;
|
|
background = 12000.f;
|
|
show = 0;
|
|
} else if (WaveParams.CLmethod == "sup" && WaveParams.Backmethod == "resid") {
|
|
mL0 = mL;
|
|
mC0 = mC;
|
|
background = 0.f;
|
|
show = 0;
|
|
} else {
|
|
mL0 = mL = mC0 = mC = 0.f;
|
|
background = 0.f;
|
|
show = 0;
|
|
}
|
|
|
|
float indic = 1.f;
|
|
if (WaveParams.showmask){
|
|
mL0 = mC0 = -1.f;
|
|
indic = -1.f;
|
|
mL = fabs(mL);
|
|
mC = fabs(mC);
|
|
show = 1;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int x = 0; x < labnCrop->H; x++)
|
|
for (int y = 0; y < labnCrop->W; y++) {
|
|
labnCrop->L[x][y] = LIM((1.f + mL0) * (unshar->L[x][y]) + show * background - mL * indic * labnCrop->L[x][y], 0.f, 32768.f);
|
|
labnCrop->a[x][y] = (1.f + mC0) * (unshar->a[x][y]) - mC * indic * labnCrop->a[x][y];
|
|
labnCrop->b[x][y] = (1.f + mC0) * (unshar->b[x][y]) - mC * indic * labnCrop->b[x][y];
|
|
}
|
|
|
|
delete unshar;
|
|
unshar = NULL;
|
|
if (WaveParams.softrad > 0.f) {
|
|
delete provradius;
|
|
provradius = NULL;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
parent->ipf.softLight(labnCrop, params.softlight);
|
|
|
|
if (params.icm.workingTRC != ColorManagementParams::WorkingTrc::NONE && params.icm.trcExp) {
|
|
const int GW = labnCrop->W;
|
|
const int GH = labnCrop->H;
|
|
if(params.icm.trcExp) {//local contrast
|
|
int level_hr = 7;
|
|
int maxlevpo = 9;
|
|
bool wavcurvecont = false;
|
|
WaveletParams WaveParams = params.wavelet;
|
|
ColorManagementParams Colparams = params.icm;
|
|
WavOpacityCurveWL icmOpacityCurveWL;
|
|
Colparams.getCurves(icmOpacityCurveWL);
|
|
parent->ipf.complete_local_contrast(labnCrop, labnCrop, WaveParams, Colparams, icmOpacityCurveWL, skip, level_hr, maxlevpo, wavcurvecont);
|
|
bool enall = false;
|
|
enall = wavcurvecont && Colparams.wavExp;//enable message only if curve enable and Expander on
|
|
if (parent->primListener) {
|
|
parent->primListener->wavlocChanged(float (maxlevpo), float (level_hr), enall);
|
|
}
|
|
|
|
}
|
|
|
|
std::unique_ptr<LabImage> provis;
|
|
const float pres = 0.01f * params.icm.preser;
|
|
if (pres > 0.f && params.icm.wprim != ColorManagementParams::Primaries::DEFAULT) {
|
|
provis.reset(new LabImage(GW, GH));
|
|
provis->CopyFrom(labnCrop);
|
|
}
|
|
|
|
const std::unique_ptr<Imagefloat> tmpImage1(new Imagefloat(GW, GH));
|
|
|
|
parent->ipf.lab2rgb(*labnCrop, *tmpImage1, params.icm.workingProfile);
|
|
|
|
const float gamtone = parent->params->icm.wGamma;
|
|
const float slotone = parent->params->icm.wSlope;
|
|
|
|
int illum = rtengine::toUnderlying(params.icm.will);
|
|
const int prim = rtengine::toUnderlying(params.icm.wprim);
|
|
|
|
Glib::ustring prof = params.icm.workingProfile;
|
|
|
|
cmsHTRANSFORM cmsDummy = nullptr;
|
|
int ill = 0;
|
|
int locprim = 0;
|
|
bool gamutcontrol = params.icm.gamut;
|
|
int catc = rtengine::toUnderlying(params.icm.wcat);
|
|
float rdx, rdy, grx, gry, blx, bly = 0.f;
|
|
float meanx, meany, meanxe, meanye = 0.f;
|
|
parent->ipf.workingtrc(0, tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, 0, ill, 0, 0, rdx, rdy, grx, gry, blx, bly,meanx, meany, meanxe, meanye, cmsDummy, true, false, false, false);
|
|
parent->ipf.workingtrc(0, tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, catc, illum, prim, locprim, rdx, rdy, grx, gry, blx, bly, meanx, meany, meanxe, meanye, cmsDummy, false, true, true, gamutcontrol);
|
|
const int midton = params.icm.wmidtcie;
|
|
|
|
if(midton != 0) {
|
|
ToneEqualizerParams params;
|
|
params.enabled = true;
|
|
params.regularization = 0.f;
|
|
params.pivot = 0.f;
|
|
params.bands[0] = 0;
|
|
params.bands[2] = midton;
|
|
params.bands[4] = 0;
|
|
params.bands[5] = 0;
|
|
int mid = abs(midton);
|
|
int threshmid = 50;
|
|
if(mid > threshmid) {
|
|
params.bands[1] = sign(midton) * (mid - threshmid);
|
|
params.bands[3] = sign(midton) * (mid - threshmid);
|
|
}
|
|
parent->ipf.toneEqualizer(tmpImage1.get(), params, prof, skip, false);
|
|
}
|
|
|
|
const bool smoothi = params.icm.wsmoothcie;
|
|
if(smoothi) {
|
|
ToneEqualizerParams params;
|
|
params.enabled = true;
|
|
params.regularization = 0.f;
|
|
params.pivot = 0.f;
|
|
params.bands[0] = 0;
|
|
params.bands[1] = 0;
|
|
params.bands[2] = 0;
|
|
params.bands[3] = 0;
|
|
params.bands[4] = -40;//arbitrary value to adapt with WhiteEvjz - here White Ev # 10
|
|
params.bands[5] = -80;//8 Ev and above
|
|
bool Evsix = true;
|
|
if(Evsix) {//EV = 6 majority of images
|
|
params.bands[4] = -15;
|
|
}
|
|
|
|
parent->ipf.toneEqualizer(tmpImage1.get(), params, prof, skip, false);
|
|
}
|
|
|
|
parent->ipf.rgb2lab(*tmpImage1, *labnCrop, params.icm.workingProfile);
|
|
//labnCrop and provis
|
|
if (provis) {
|
|
parent->ipf.preserv(labnCrop, provis.get(), GW, GH);
|
|
}
|
|
if (params.icm.fbw) {
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (int x = 0; x < GH; x++)
|
|
for (int y = 0; y < GW; y++) {
|
|
labnCrop->a[x][y] = 0.f;
|
|
labnCrop->b[x][y] = 0.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (params.colorappearance.enabled) {
|
|
float fnum = parent->imgsrc->getMetaData()->getFNumber(); // F number
|
|
float fiso = parent->imgsrc->getMetaData()->getISOSpeed() ; // ISO
|
|
float fspeed = parent->imgsrc->getMetaData()->getShutterSpeed() ; // Speed
|
|
double fcomp = parent->imgsrc->getMetaData()->getExpComp(); // Compensation +/-
|
|
double adap; // Scene's luminosity adaptation factor
|
|
|
|
if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong
|
|
adap = 2000.;
|
|
} else {
|
|
double E_V = fcomp + log2(double ((fnum * fnum) / fspeed / (fiso / 100.f)));
|
|
double kexp = 0.;
|
|
E_V += kexp * params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
|
|
E_V += 0.5 * log2(params.raw.expos); // exposure raw white point ; log2 ==> linear to EV
|
|
adap = pow(2., E_V - 3.); // cd / m2
|
|
// end calculation adaptation scene luminosity
|
|
}
|
|
|
|
bool execsharp = false;
|
|
|
|
if (skip == 1) {
|
|
execsharp = true;
|
|
}
|
|
|
|
if (!cieCrop) {
|
|
cieCrop = new CieImage(cropw, croph);
|
|
}
|
|
|
|
float d, dj, yb; // not used after this block
|
|
parent->ipf.ciecam_02float(cieCrop, float (adap), 1, 2, labnCrop, ¶ms, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3,
|
|
dummy, dummy, parent->CAMBrightCurveJ, parent->CAMBrightCurveQ, parent->CAMMean, 0, skip, execsharp, d, dj, yb, 1, parent->sharpMask);
|
|
} else {
|
|
// CIECAM is disabled, we free up its image buffer to save some space
|
|
if (cieCrop) {
|
|
delete cieCrop;
|
|
}
|
|
|
|
cieCrop = nullptr;
|
|
}
|
|
}
|
|
|
|
// all pipette buffer processing should be finished now
|
|
PipetteBuffer::setReady();
|
|
|
|
|
|
|
|
// Computing the preview image, i.e. converting from lab->Monitor color space (soft-proofing disabled) or lab->Output profile->Monitor color space (soft-proofing enabled)
|
|
parent->ipf.lab2monitorRgb(labnCrop, cropImg);
|
|
|
|
if (cropImageListener) {
|
|
// Computing the internal image for analysis, i.e. conversion from lab->Output profile (rtSettings.HistogramWorking disabled) or lab->WCS (rtSettings.HistogramWorking enabled)
|
|
|
|
// internal image in output color space for analysis
|
|
Image8 *cropImgtrue = parent->ipf.lab2rgb(labnCrop, 0, 0, cropw, croph, params.icm);
|
|
|
|
int finalW = rqcropw;
|
|
|
|
if (cropImg->getWidth() - leftBorder < finalW) {
|
|
finalW = cropImg->getWidth() - leftBorder;
|
|
}
|
|
|
|
int finalH = rqcroph;
|
|
|
|
if (cropImg->getHeight() - upperBorder < finalH) {
|
|
finalH = cropImg->getHeight() - upperBorder;
|
|
}
|
|
|
|
Image8* final = new Image8(finalW, finalH);
|
|
Image8* finaltrue = new Image8(finalW, finalH);
|
|
|
|
for (int i = 0; i < finalH; i++) {
|
|
memcpy(final->data + 3 * i * finalW, cropImg->data + 3 * (i + upperBorder)*cropw + 3 * leftBorder, 3 * finalW);
|
|
memcpy(finaltrue->data + 3 * i * finalW, cropImgtrue->data + 3 * (i + upperBorder)*cropw + 3 * leftBorder, 3 * finalW);
|
|
}
|
|
|
|
cropImageListener->setDetailedCrop(final, finaltrue, params.icm, params.crop, rqcropx, rqcropy, rqcropw, rqcroph, skip);
|
|
delete final;
|
|
delete finaltrue;
|
|
delete cropImgtrue;
|
|
}
|
|
}
|
|
|
|
void Crop::freeAll()
|
|
{
|
|
|
|
if (cropAllocated) {
|
|
if (origCrop) {
|
|
delete origCrop;
|
|
origCrop = nullptr;
|
|
}
|
|
|
|
if (transCrop) {
|
|
delete transCrop;
|
|
transCrop = nullptr;
|
|
}
|
|
|
|
if (laboCrop) {
|
|
delete laboCrop;
|
|
laboCrop = nullptr;
|
|
}
|
|
|
|
|
|
if (labnCrop) {
|
|
delete labnCrop;
|
|
labnCrop = nullptr;
|
|
}
|
|
|
|
if (cropImg) {
|
|
delete cropImg;
|
|
cropImg = nullptr;
|
|
}
|
|
|
|
if (cieCrop) {
|
|
delete cieCrop;
|
|
cieCrop = nullptr;
|
|
}
|
|
|
|
if (shbuffer) {
|
|
delete [] shbuffer;
|
|
shbuffer = nullptr;
|
|
}
|
|
|
|
if (shbuf_real) {
|
|
delete [] shbuf_real;
|
|
shbuf_real = nullptr;
|
|
}
|
|
|
|
PipetteBuffer::flush();
|
|
}
|
|
|
|
cropAllocated = false;
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
bool check_need_larger_crop_for_lcp_distortion(int fw, int fh, int x, int y, int w, int h, const procparams::ProcParams ¶ms)
|
|
{
|
|
if (x == 0 && y == 0 && w == fw && h == fh) {
|
|
return false;
|
|
}
|
|
|
|
return (params.lensProf.useDist && (params.lensProf.useLensfun() || params.lensProf.useLcp() || params.lensProf.useMetadata()));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/** @brief Handles crop's image buffer reallocation and trigger sizeChanged of SizeListener[s]
|
|
* If the scale changes, this method will free all buffers and reallocate ones of the new size.
|
|
* It will then tell to the SizeListener that size has changed (sizeChanged)
|
|
*/
|
|
bool Crop::setCropSizes(int cropX, int cropY, int cropW, int cropH, int skip, bool internal)
|
|
{
|
|
|
|
if (!internal) {
|
|
cropMutex.lock();
|
|
}
|
|
|
|
bool changed = false;
|
|
|
|
rqcropx = cropX;
|
|
rqcropy = cropY;
|
|
rqcropw = cropW;
|
|
rqcroph = cropH;
|
|
|
|
// store and set requested crop size
|
|
int rqx1 = LIM(rqcropx, 0, parent->fullw - 1);
|
|
int rqy1 = LIM(rqcropy, 0, parent->fullh - 1);
|
|
int rqx2 = rqx1 + rqcropw - 1;
|
|
int rqy2 = rqy1 + rqcroph - 1;
|
|
rqx2 = LIM(rqx2, 0, parent->fullw - 1);
|
|
rqy2 = LIM(rqy2, 0, parent->fullh - 1);
|
|
|
|
this->skip = skip;
|
|
|
|
// add border, if possible
|
|
int bx1 = rqx1 - skip * borderRequested;
|
|
int by1 = rqy1 - skip * borderRequested;
|
|
int bx2 = rqx2 + skip * borderRequested;
|
|
int by2 = rqy2 + skip * borderRequested;
|
|
// clip it to fit into image area
|
|
bx1 = LIM(bx1, 0, parent->fullw - 1);
|
|
by1 = LIM(by1, 0, parent->fullh - 1);
|
|
bx2 = LIM(bx2, 0, parent->fullw - 1);
|
|
by2 = LIM(by2, 0, parent->fullh - 1);
|
|
int bw = bx2 - bx1 + 1;
|
|
int bh = by2 - by1 + 1;
|
|
|
|
// determine which part of the source image is required to compute the crop rectangle
|
|
int orx, ory, orw, orh;
|
|
orx = bx1;
|
|
ory = by1;
|
|
orw = bw;
|
|
orh = bh;
|
|
|
|
parent->ipf.transCoord(parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh);
|
|
|
|
if (parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData())) {
|
|
if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) {
|
|
// TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise
|
|
int dW = int (double (parent->fw) * 0.15 / (2 * skip));
|
|
int dH = int (double (parent->fh) * 0.15 / (2 * skip));
|
|
int x1 = orx - dW;
|
|
int x2 = orx + orw + dW;
|
|
int y1 = ory - dH;
|
|
int y2 = ory + orh + dH;
|
|
|
|
if (x1 < 0) {
|
|
x2 += -x1;
|
|
x1 = 0;
|
|
}
|
|
|
|
if (x2 > parent->fw) {
|
|
x1 -= x2 - parent->fw;
|
|
x2 = parent->fw;
|
|
}
|
|
|
|
if (y1 < 0) {
|
|
y2 += -y1;
|
|
y1 = 0;
|
|
}
|
|
|
|
if (y2 > parent->fh) {
|
|
y1 -= y2 - parent->fh;
|
|
y2 = parent->fh;
|
|
}
|
|
|
|
orx = max(x1, 0);
|
|
ory = max(y1, 0);
|
|
orw = min(x2 - x1, parent->fw - orx);
|
|
orh = min(y2 - y1, parent->fh - ory);
|
|
}
|
|
}
|
|
leftBorder = skips(rqx1 - bx1, skip);
|
|
upperBorder = skips(rqy1 - by1, skip);
|
|
|
|
PreviewProps cp(orx, ory, orw, orh, skip);
|
|
int orW, orH;
|
|
parent->imgsrc->getSize(cp, orW, orH);
|
|
|
|
if (trafx != orx || trafy != ory) {
|
|
trafx = orx;
|
|
trafy = ory;
|
|
changed = true;
|
|
}
|
|
|
|
int cw = skips(bw, skip);
|
|
int ch = skips(bh, skip);
|
|
|
|
EditType editType = ET_PIPETTE;
|
|
|
|
if (const auto editProvider = PipetteBuffer::getDataProvider()) {
|
|
if (const auto editSubscriber = editProvider->getCurrSubscriber()) {
|
|
editType = editSubscriber->getEditingType();
|
|
}
|
|
}
|
|
|
|
if (cw != cropw || ch != croph || orW != trafw || orH != trafh) {
|
|
|
|
cropw = cw;
|
|
croph = ch;
|
|
trafw = orW;
|
|
trafh = orH;
|
|
|
|
if (!origCrop) {
|
|
origCrop = new Imagefloat;
|
|
}
|
|
|
|
origCrop->allocate(trafw, trafh); // Resizing the buffer (optimization)
|
|
|
|
// if transCrop doesn't exist yet, it'll be created where necessary
|
|
if (transCrop) {
|
|
transCrop->allocate(cropw, croph);
|
|
}
|
|
|
|
if (laboCrop) {
|
|
delete laboCrop; // laboCrop can't be resized
|
|
}
|
|
|
|
laboCrop = new LabImage(cropw, croph);
|
|
|
|
// if (translabCrop) translabCrop->reallocLab();
|
|
|
|
if (labnCrop) {
|
|
delete labnCrop; // labnCrop can't be resized
|
|
}
|
|
|
|
labnCrop = new LabImage(cropw, croph);
|
|
|
|
if (!cropImg) {
|
|
cropImg = new Image8;
|
|
}
|
|
|
|
cropImg->allocate(cropw, croph); // Resizing the buffer (optimization)
|
|
|
|
//cieCrop is only used in Crop::update, it is destroyed now but will be allocated on first use
|
|
if (cieCrop) {
|
|
delete cieCrop;
|
|
cieCrop = nullptr;
|
|
}
|
|
|
|
if (shbuffer) {
|
|
delete [] shbuffer;
|
|
}
|
|
|
|
if (shbuf_real) {
|
|
delete [] shbuf_real;
|
|
}
|
|
|
|
shbuffer = new float*[croph];
|
|
shbuf_real = new float[(croph + 2)*cropw];
|
|
|
|
for (int i = 0; i < croph; i++) {
|
|
shbuffer[i] = shbuf_real + cropw * i + cropw;
|
|
}
|
|
|
|
if (editType == ET_PIPETTE) {
|
|
PipetteBuffer::resize(cropw, croph);
|
|
} else if (PipetteBuffer::bufferCreated()) {
|
|
PipetteBuffer::flush();
|
|
}
|
|
|
|
cropAllocated = true;
|
|
|
|
changed = true;
|
|
}
|
|
|
|
cropx = bx1;
|
|
cropy = by1;
|
|
|
|
if (!internal) {
|
|
cropMutex.unlock();
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
/** @brief Look out if a new thread has to be started to process the update
|
|
*
|
|
* @return If true, a new updating thread has to be created. If false, the current updating thread will be used
|
|
*/
|
|
bool Crop::tryUpdate()
|
|
{
|
|
bool needsNewThread = true;
|
|
|
|
if (updating) {
|
|
// tells to the updater thread that a new update is pending
|
|
newUpdatePending = true;
|
|
// no need for a new thread, the current one will do the job
|
|
needsNewThread = false;
|
|
} else
|
|
// the crop is now being updated ...well, when fullUpdate will be called
|
|
{
|
|
updating = true;
|
|
}
|
|
|
|
return needsNewThread;
|
|
}
|
|
|
|
/* @brief Handles Crop updating in its own thread
|
|
*
|
|
* This method will cycle updates as long as Crop::newUpdatePending will be true. During the processing,
|
|
* intermediary update will be automatically flushed by Crop::tryUpdate.
|
|
*
|
|
* This method is called when the visible part of the crop has changed (resize, zoom, etc..), so it needs a full update
|
|
*/
|
|
void Crop::fullUpdate()
|
|
{
|
|
|
|
parent->updaterThreadStart.lock();
|
|
|
|
if (parent->updaterRunning && parent->thread) {
|
|
// Do NOT reset changes here, since in a long chain of events it will lead to chroma_scale not being updated,
|
|
// causing Color::lab2rgb to return a black image on some opens
|
|
//parent->changeSinceLast = 0;
|
|
parent->thread->join();
|
|
}
|
|
|
|
if (parent->plistener) {
|
|
parent->plistener->setProgressState(true);
|
|
}
|
|
|
|
// If there are more update request, the following WHILE will collect it
|
|
newUpdatePending = true;
|
|
|
|
while (newUpdatePending) {
|
|
newUpdatePending = false;
|
|
update(ALL);
|
|
}
|
|
|
|
updating = false; // end of crop update
|
|
|
|
if (parent->plistener) {
|
|
parent->plistener->setProgressState(false);
|
|
}
|
|
|
|
parent->updaterThreadStart.unlock();
|
|
}
|
|
|
|
int Crop::get_skip()
|
|
{
|
|
MyMutex::MyLock lock(cropMutex);
|
|
return skip;
|
|
}
|
|
|
|
int Crop::getLeftBorder()
|
|
{
|
|
MyMutex::MyLock lock(cropMutex);
|
|
return leftBorder;
|
|
}
|
|
|
|
int Crop::getUpperBorder()
|
|
{
|
|
MyMutex::MyLock lock(cropMutex);
|
|
return upperBorder;
|
|
}
|
|
|
|
}
|