* GHS GUI first step * GHS GUI first step * GUI step 3 * Hide show ghsmethod * Siril functions for ghs * Init ghs in iplocallab * ghs step 2 * ghs step 4 * Comment copyright Pixlnsight 2021 * Smooth highlights and tooltips * Enabled saturation and luminance ghs mode * First tooltip * Ghs tooltips * Remove wrong packstart inverssh * Change labels and tooltips * Disabled mask in global and other improvments * Comment code * appimage and windows yml ghs * Change tooltip * Ghsmethod hue and change tolltips * Change tooltip * Inverse Stretch step 1 * Inverse GHS * GHS tooltips * Change tooltips * Change tooltip * Linear black point * Small change to blackpoint * Change tooltip * Clean and comment code * forgotten GHS highlight attenuation msg in history * Comment code with Transformation equations * Change tooltip * Wrong default value balck point * Comment code iplocallab * Ghs curve step 1 * GHS curve step 2 * Show GHS setting in a Curve Box * Tooltip for ghs S curve * Disabled warning in compilation simpleprocess * Simplified code part 1 * Simplified code GHS graph part 2 * Improve black point with negatives values * Improve BP and tooltip * Listener enable only with GHS * White point for GHS * Change label and tooltip * Improve behavior white point and black point * Link sliders ghs_SP ghs_LP ghs_HP and change code to avoid balck screen * hide unused button in diagonal curve GHS * prevents the GHS representation in S from displaying artifacts if ghs-d=0 * Change tooltips * Improvment and tooltips * Forgotten tooltip * Improve GUI GHS S curve - change tooltips * Set transition gray areas in S curve GHS with values of the RT-spot * Change label GHS * setlogscale blackpoint and symmetry * Set recursive reference enable by default in controlspotpanel * Change lastlocalCurvesDir Dirghs in locallabtools and options - change labels * Added in converttonormal ghsMode.. not sure if this is useful * DIY to make GHS curve work without the choices * Change RGB calculation with luminance function working profile * 5 modes GHS method * Label to show datas clipped Black point and White point * Various change white point tooltips * Bad behavior wp bp labels * Small change to improccordinator call to ghschanged ghsbwchanged * Set log scale ghs_D * Hide Graduated filter if GHS enable * Luminance Lab in ghsmethod * Lab slope factor step 1 * Slope and Chromaticity GHS improvments * Fixed bad sqrt line 17477 iplocallab * Workaround linear GHS - re-enable Graduated filer GHS * Change limits slope lab factor * Ghs chromaticity Lab (Lch) * Improve ghs chromaticity * Change labels and tooltips Lab chroma * Slope Lab to 100 * Noise and saturation RGB * Saturation RGB standard and labels * Change histogram and navigator panel without gamma when using working profile * Remove gray in GHS curve * Local contrast a minima * Regularization stretch * Improve Graduated Filter in all cases GHS Color and Light etc. * Improves nlmeans to reduce noise after GHS * Change to GF - tooltip Nlmeans * Added oW oH tW tH etc. * Added call GF * tX tY for previewProps * Comment code GF * Improve local contrast ghs * Change norm to norm2 * Improve GUI mode complexity and Lab GHS * Show values BP WP in GUI * Labgrid ghs step 1 * Labgrid for simulation GHS - step 2 * More points for Labgrid ghs * Clean and comment code * Fixed crash in inverse GHS white point - set to 10 points for GSH simulation * Change to black point in inverse GHS * Intilialize simulation with nothing if new spot * Remove curve GHS - optimize code simulation - improve GUI * set ghs default - fixed crash is case HP SP LP * Fixed crash - I hope in inverse GHS * Simplify WP and BP limits to avoid crash in inverse GHS * Clean code with ghscurve - ghsshape * Change tooltips * Change to D - GUI - comment code * Simulation with 4 more points * Best simulation with point 0.05 and 0.95 * Clean code - change for crsah in Inverse GHS * Show values WP and BP * Change tooltips * Midtones after GHS * Modification code WP BP * Tests changes in settings for transition and Shape detection - see Preferences * Change order labels luma chroma hue * Fixed bad behavior localllistener denchanged in dcrop.cc * Save work * Work on graduated filter * Improve a little graduated filter SH and others... * 3 configurations tests graduated filter SH plain image - color more sk - exposure normal * Forgotten code ... * Change improccordinator parameter * Save work printf parameters GF * New test for GF * Hide plain image calculation GF * Small chnages and comment code * Change tooltip exp graduated filter * Change tooltip exp graduated filter * Save work * Change GF for some tools only in Global and Fullimage - test for GF SH mode plain image * Fixed crash and GUI part 1 * Others change GF * Change label - allow GF plain image in SH * Change GF with cx cy sk * Adapt locallabtool and locallabtools2 to GF * Clean code * GF wavelet only in fullimage and global * GF - Empirical correction to cx and cy in function of sk * Change label GHS and position in GUI * Fixed Black point bad behavior history - an oversight may be age * Change real strength of GF - to look like GF main * Include ksk - Skip correction in all code GF * Passed other parameters to try * New parameter for GF * Change position graph-curv ghs and labels black and white point * Change behavior and default value white point * Save provisory work * Save provisory work * Curve GHS with 21 points including 0 and 1 * Two prameters added to change behavior GF - rationalize their using * Change Black point direction * Change range black-point for negatives values - chnage tooltips * Change tooltips * Various change to avoid crash and settings defaults * Disabled showmùaskmethod - set max white point to 5 * Fixed bad behavior when change fullimage to global for mask * Clean comment code * Fixed - I hope - bad behavior when we go from Fullimage to Global and vice versa * Fixed crash in output tif and show time to calculate WP and BP * Change tooltip BP and WP * Change tooltips BP WP * move GF after GHS so as not to influence BP and WP * Clean code * Disable all mask and modifications in Global but remain active in fullimage and normal * Change tooltip graduated filter * Restore GF in normal mode - and increases GF strength as before * Clean code locallabtools 1 2 * Comment in calclocalGradientParams in iplocallab for changes in Graduated F * Change convention labels - tooltips * Change tooltips * improves (I hope) the readability of the tooltips * Remove with comment change complexity in Settings * Improve settings BP WP - improve tooltips * Refactor GHS curve and increase resolution Simplify how the curve parameters are passed to the drawing area. Use up to 400 line segments to draw the curve. * Update GHS curve tooltip Remove statement regarding the number of points used because it is no longer accurate. * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Change Luma with Lightness * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Update rtdata/languages/default Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> * Remove warnings in icmpanel * Changes suggested by Lawrence37 * GHS - Hide inverse always show in some cases - improve tooltip BP WP * Change tooltip * Change tooltip * Small changes * Change tootip suggested by Lawrence37 - set midtones and LC set_sensitive in function of D * Add tooltip as suggest by Lawrence37 for LC and midtones * Remove tooltip on Frame LC and Midtones * Remove all traces toottips frame LD and Midtones * set sensitive BLP and HLP to false if stretch = 0 * Change Beep6581 to Rawtherapee in appimage.yml and Windows.yml * Hide LC and midtones when Stretch = 0 * Clean up Generalized Hyperbolic Stretch code Convert some ints into enum classes. Replace new/delete with std::unique_ptr for image. Remove unused GHS parameters in ProcParams and ParamsEdited which were used to draw the curve. Revert changes to the curve editors because they are not needed. Simplify the drawing of the curve background for efficiency. Restore the const-ness of some variables. * Change appimage.yml and windows.yml --------- Co-authored-by: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com>
2153 lines
97 KiB
C++
2153 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& ghslocalcurve2 = parent->ghslocalcurve;
|
|
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;
|
|
//big bug found 29//11/2024
|
|
std::vector<LocallabListener::locallabDenoiseLC> localldenoiselc;
|
|
|
|
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 localghsutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).ghscurve, ghslocalcurve2, 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;
|
|
}
|
|
|
|
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;
|
|
int ghsbpwp[2];
|
|
float ghsbpwpvalue[2];
|
|
|
|
/* 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), trafx, trafy, trafw, trafh , skip, locRETgainCurve, locRETtransCurve,
|
|
lllocalcurve2,locallutili,
|
|
cllocalcurve2, localclutili,
|
|
lclocalcurve2, locallcutili,
|
|
loclhCurve, lochhCurve, locchCurve,
|
|
lochhCurvejz, locchCurvejz, loclhCurvejz,
|
|
|
|
lmasklocalcurve2, localmaskutili,
|
|
lmaskexplocalcurve2, localmaskexputili,
|
|
lmaskSHlocalcurve2, localmaskSHutili,
|
|
// ghslocalcurve2, localghsutili,
|
|
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,
|
|
ghsbpwp, ghsbpwpvalue);
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
*/
|
|
} 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), trafx, trafy, trafw , trafh, skip, locRETgainCurve, locRETtransCurve,
|
|
lllocalcurve2,locallutili,
|
|
cllocalcurve2, localclutili,
|
|
lclocalcurve2, locallcutili,
|
|
loclhCurve, lochhCurve, locchCurve,
|
|
lochhCurvejz, locchCurvejz, loclhCurvejz,
|
|
lmasklocalcurve2, localmaskutili,
|
|
lmaskexplocalcurve2, localmaskexputili,
|
|
lmaskSHlocalcurve2, localmaskSHutili,
|
|
// ghslocalcurve2, localghsutili,
|
|
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,
|
|
ghsbpwp, ghsbpwpvalue);
|
|
}
|
|
|
|
|
|
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->locallListener) {
|
|
parent->locallListener->denChanged(localldenoiselc, params.locallab.selspot);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
}
|