* 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>
3433 lines
144 KiB
C++
3433 lines
144 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
|
|
* 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 <fstream>
|
|
|
|
#include <glibmm/thread.h>
|
|
|
|
#include "improccoordinator.h"
|
|
|
|
#include "array2D.h"
|
|
#include "cieimage.h"
|
|
#include "color.h"
|
|
#include "colortemp.h"
|
|
#include "curves.h"
|
|
#include "dcp.h"
|
|
#include "guidedfilter.h"
|
|
#include "iccstore.h"
|
|
#include "image8.h"
|
|
#include "imagefloat.h"
|
|
#include "improcfun.h"
|
|
#include "metadata.h"
|
|
#include "labimage.h"
|
|
#include "lcp.h"
|
|
#include "procparams.h"
|
|
#include "tweakoperator.h"
|
|
#include "refreshmap.h"
|
|
#include "utils.h"
|
|
|
|
#include "rtgui/options.h"
|
|
|
|
#ifdef _OPENMP
|
|
#include <omp.h>
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr int VECTORSCOPE_SIZE = 128;
|
|
|
|
}
|
|
|
|
namespace rtengine
|
|
{
|
|
|
|
ImProcCoordinator::ImProcCoordinator() :
|
|
orig_prev(nullptr),
|
|
oprevi(nullptr),
|
|
spotprev(nullptr),
|
|
oprevl(nullptr),
|
|
nprevl(nullptr),
|
|
fattal_11_dcrop_cache(nullptr),
|
|
previmg(nullptr),
|
|
workimg(nullptr),
|
|
ncie(nullptr),
|
|
imgsrc(nullptr),
|
|
lastAwbEqual(0.),
|
|
lastAwbTempBias(0.0),
|
|
lastAwbauto(""),
|
|
monitorIntent(RI_RELATIVE),
|
|
softProof(false),
|
|
gamutCheck(false),
|
|
sharpMask(false),
|
|
sharpMaskChanged(false),
|
|
scale(10),
|
|
highDetailPreprocessComputed(false),
|
|
highDetailRawComputed(false),
|
|
allocated(false),
|
|
bwAutoR(-9000.f),
|
|
bwAutoG(-9000.f),
|
|
bwAutoB(-9000.f),
|
|
CAMMean(NAN),
|
|
hltonecurve(65536),
|
|
shtonecurve(65536),
|
|
tonecurve(65536, 0), //,1);
|
|
lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation
|
|
chroma_acurve(65536, 0),
|
|
chroma_bcurve(65536, 0),
|
|
satcurve(65536, 0),
|
|
lhskcurve(65536, 0),
|
|
clcurve(65536, 0),
|
|
conversionBuffer(1, 1),
|
|
wavclCurve(65536, 0),
|
|
clToningcurve(65536, 0),
|
|
cl2Toningcurve(65536, 0),
|
|
Noisecurve(65536, 0),
|
|
NoiseCCcurve(65536, 0),
|
|
vhist16(65536), vhist16bw(65536),
|
|
lhist16CAM(65536),
|
|
lhist16CCAM(65536),
|
|
lhist16RETI(),
|
|
lhist16LClad(65536),
|
|
histRed(256), histRedRaw(256),
|
|
histGreen(256), histGreenRaw(256),
|
|
histBlue(256), histBlueRaw(256),
|
|
histLuma(256),
|
|
histToneCurve(256),
|
|
histToneCurveBW(256),
|
|
histLCurve(256),
|
|
histCCurve(256),
|
|
histLLCurve(256),
|
|
|
|
histLCAM(256),
|
|
histCCAM(256),
|
|
histClad(256),
|
|
bcabhist(256),
|
|
histChroma(256),
|
|
|
|
histLRETI(256),
|
|
|
|
hist_lrgb_dirty(false),
|
|
hist_raw_dirty(false),
|
|
|
|
vectorscopeScale(0),
|
|
vectorscope_hc_dirty(false),
|
|
vectorscope_hs_dirty(false),
|
|
vectorscope_hc(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE),
|
|
vectorscope_hs(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE),
|
|
waveformScale(0),
|
|
waveform_dirty(false),
|
|
waveformRed(0, 0),
|
|
waveformGreen(0, 0),
|
|
waveformBlue(0, 0),
|
|
waveformLuma(0, 0),
|
|
|
|
CAMBrightCurveJ(), CAMBrightCurveQ(),
|
|
|
|
rCurve(),
|
|
gCurve(),
|
|
bCurve(),
|
|
ctColorCurve(),
|
|
rcurvehist(256), rcurvehistCropped(256), rbeforehist(256),
|
|
gcurvehist(256), gcurvehistCropped(256), gbeforehist(256),
|
|
bcurvehist(256), bcurvehistCropped(256), bbeforehist(256),
|
|
fw(0), fh(0), tr(0),
|
|
fullw(1), fullh(1),
|
|
pW(-1), pH(-1),
|
|
plistener(nullptr),
|
|
imageListener(nullptr),
|
|
aeListener(nullptr),
|
|
acListener(nullptr),
|
|
ablListener(nullptr),
|
|
abwListener(nullptr),
|
|
awbListener(nullptr),
|
|
flatFieldAutoClipListener(nullptr),
|
|
bayerAutoContrastListener(nullptr),
|
|
xtransAutoContrastListener(nullptr),
|
|
pdSharpenAutoContrastListener(nullptr),
|
|
pdSharpenAutoRadiusListener(nullptr),
|
|
frameCountListener(nullptr),
|
|
imageTypeListener(nullptr),
|
|
filmNegListener(nullptr),
|
|
actListener(nullptr),
|
|
primListener(nullptr),
|
|
adnListener(nullptr),
|
|
awavListener(nullptr),
|
|
dehaListener(nullptr),
|
|
hListener(nullptr),
|
|
resultValid(false),
|
|
params(new procparams::ProcParams),
|
|
tweakOperator(nullptr),
|
|
lastOutputProfile("BADFOOD"),
|
|
lastOutputIntent(RI__COUNT),
|
|
lastOutputBPC(false),
|
|
thread(nullptr),
|
|
changeSinceLast(0),
|
|
updaterRunning(false),
|
|
nextParams(new procparams::ProcParams),
|
|
destroying(false),
|
|
utili(false),
|
|
autili(false),
|
|
butili(false),
|
|
ccutili(false),
|
|
cclutili(false),
|
|
clcutili(false),
|
|
opautili(false),
|
|
wavcontlutili(false),
|
|
colourToningSatLimit(0.f),
|
|
colourToningSatLimitOpacity(0.f),
|
|
highQualityComputed(false),
|
|
customTransformIn(nullptr),
|
|
customTransformOut(nullptr),
|
|
ipf(params.get(), true),
|
|
|
|
// Locallab
|
|
locallListener(nullptr),
|
|
lllocalcurve(65536, LUT_CLIP_OFF),
|
|
cllocalcurve(65536, LUT_CLIP_OFF),
|
|
lclocalcurve(65536, LUT_CLIP_OFF),
|
|
cclocalcurve(65536, LUT_CLIP_OFF),
|
|
rgblocalcurve(65536, LUT_CLIP_OFF),
|
|
exlocalcurve(65536, LUT_CLIP_OFF),
|
|
hltonecurveloc(65536, LUT_CLIP_OFF), //32768
|
|
shtonecurveloc(65536, LUT_CLIP_OFF),
|
|
tonecurveloc(65536, LUT_CLIP_OFF),
|
|
lightCurveloc(32770, LUT_CLIP_OFF),
|
|
lmasklocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskexplocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskSHlocalcurve(65536, LUT_CLIP_OFF),
|
|
ghslocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskviblocalcurve(65536, LUT_CLIP_OFF),
|
|
lmasktmlocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskretilocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskcblocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskbllocalcurve(65536, LUT_CLIP_OFF),
|
|
lmasklclocalcurve(65536, LUT_CLIP_OFF),
|
|
lmaskloglocalcurve(65536, LUT_CLIP_OFF),
|
|
lmasklocal_curve(65536, LUT_CLIP_OFF),
|
|
lmaskcielocalcurve(65536, LUT_CLIP_OFF),
|
|
cielocalcurve(65536, LUT_CLIP_OFF),
|
|
cielocalcurve2(65536, LUT_CLIP_OFF),
|
|
jzlocalcurve(65536, LUT_CLIP_OFF),
|
|
czlocalcurve(65536, LUT_CLIP_OFF),
|
|
czjzlocalcurve(65536, LUT_CLIP_OFF),
|
|
lastspotdup(false),
|
|
previewDeltaE(false),
|
|
locallColorMask(0),
|
|
locallColorMaskinv(0),
|
|
locallExpMask(0),
|
|
locallExpMaskinv(0),
|
|
locallSHMask(0),
|
|
locallSHMaskinv(0),
|
|
locallvibMask(0),
|
|
localllcMask(0),
|
|
locallcbMask(0),
|
|
locallretiMask(0),
|
|
locallsoftMask(0),
|
|
localltmMask(0),
|
|
locallblMask(0),
|
|
locallsharMask(0),
|
|
localllogMask(0),
|
|
locall_Mask(0),
|
|
locallcieMask(0),
|
|
retistrsav(nullptr)
|
|
{
|
|
}
|
|
|
|
ImProcCoordinator::~ImProcCoordinator()
|
|
{
|
|
|
|
destroying = true;
|
|
updaterThreadStart.lock();
|
|
|
|
if (updaterRunning && thread) {
|
|
thread->join();
|
|
}
|
|
|
|
mProcessing.lock();
|
|
mProcessing.unlock();
|
|
freeAll();
|
|
|
|
if (fattal_11_dcrop_cache) {
|
|
delete fattal_11_dcrop_cache;
|
|
fattal_11_dcrop_cache = nullptr;
|
|
}
|
|
|
|
std::vector<Crop*> toDel = crops;
|
|
|
|
for (size_t i = 0; i < toDel.size(); i++) {
|
|
delete toDel[i];
|
|
}
|
|
|
|
imgsrc->decreaseRef();
|
|
|
|
if (customTransformIn) {
|
|
cmsDeleteTransform(customTransformIn);
|
|
customTransformIn = nullptr;
|
|
}
|
|
|
|
if (customTransformOut) {
|
|
cmsDeleteTransform(customTransformOut);
|
|
customTransformOut = nullptr;
|
|
}
|
|
|
|
updaterThreadStart.unlock();
|
|
}
|
|
|
|
void ImProcCoordinator::assign(ImageSource* imgsrc)
|
|
{
|
|
this->imgsrc = imgsrc;
|
|
}
|
|
|
|
void ImProcCoordinator::getParams(procparams::ProcParams* dst, bool tweaked)
|
|
{
|
|
if (!tweaked && paramsBackup.operator bool()) {
|
|
*dst = *paramsBackup;
|
|
} else {
|
|
*dst = *params;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::backupParams()
|
|
{
|
|
if (!params) {
|
|
return;
|
|
}
|
|
|
|
if (!paramsBackup) {
|
|
paramsBackup.reset(new ProcParams());
|
|
}
|
|
|
|
*paramsBackup = *params;
|
|
}
|
|
|
|
void ImProcCoordinator::restoreParams()
|
|
{
|
|
if (!paramsBackup || !params) {
|
|
return;
|
|
}
|
|
|
|
*params = *paramsBackup;
|
|
}
|
|
|
|
DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider, bool isDetailWindow)
|
|
{
|
|
|
|
return new Crop(this, editDataProvider, isDetailWindow);
|
|
}
|
|
|
|
|
|
// todo: bitmask containing desired actions, taken from changesSinceLast
|
|
void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
|
|
{
|
|
// TODO Locallab printf
|
|
MyMutex::MyLock processingLock(mProcessing);
|
|
|
|
bool highDetailNeeded = options.prevdemo == PD_Sidecar ? true : (todo & M_HIGHQUAL);
|
|
// printf("metwb=%s \n", params->wb.method.c_str());
|
|
|
|
// Check if any detail crops need high detail. If not, take a fast path short cut
|
|
if (!highDetailNeeded) {
|
|
for (size_t i = 0; i < crops.size(); i++) {
|
|
if (crops[i]->get_skip() == 1) { // skip=1 -> full resolution
|
|
highDetailNeeded = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (((todo & ALL) == ALL) || (todo & M_MONITOR) || panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar)) {
|
|
bwAutoR = bwAutoG = bwAutoB = -9000.f;
|
|
|
|
if (todo == CROP && ipf.needsPCVignetting()) {
|
|
todo |= TRANSFORM; // Change about Crop does affect TRANSFORM
|
|
}
|
|
|
|
RAWParams rp = params->raw;
|
|
ColorManagementParams cmp = params->icm;
|
|
LCurveParams lcur = params->labCurve;
|
|
bool spotsDone = false;
|
|
|
|
if (!highDetailNeeded) {
|
|
// if below 100% magnification, take a fast path
|
|
if (rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE) && rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)) {
|
|
rp.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
|
|
}
|
|
|
|
//bayerrp.all_enhance = false;
|
|
|
|
if (rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE) && rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO)) {
|
|
rp.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
|
|
}
|
|
|
|
rp.bayersensor.ccSteps = 0;
|
|
rp.xtranssensor.ccSteps = 0;
|
|
//rp.deadPixelFilter = rp.hotPixelFilter = false;
|
|
}
|
|
|
|
if (frameCountListener) {
|
|
frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params->raw.bayersensor.imageNum);
|
|
}
|
|
|
|
// raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed
|
|
float reddeha = 0.f;//initialize black red, blue, green for dehaze
|
|
float greendeha = 0.f;
|
|
float bluedeha = 0.f;
|
|
|
|
if ((todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) {
|
|
imgsrc->setCurrentFrame(params->raw.bayersensor.imageNum);
|
|
imgsrc->preprocess(rp, params->lensProf, params->coarse, reddeha, greendeha, bluedeha, true);
|
|
if(imgsrc->getSensorType() == ST_BAYER) {//Bayer
|
|
if (ablListener) {
|
|
if(rp.bayersensor.Dehablack) {
|
|
ablListener->autoBlackChanged(reddeha, greendeha, bluedeha);
|
|
}
|
|
}
|
|
} else if(imgsrc->getSensorType() == ST_FUJI_XTRANS) {//X trans
|
|
if (ablxListener) {
|
|
if(rp.xtranssensor.Dehablackx) {
|
|
ablxListener->autoBlackxChanged(reddeha, greendeha, bluedeha);
|
|
}
|
|
}
|
|
}
|
|
if (flatFieldAutoClipListener && rp.ff_AutoClipControl) {
|
|
flatFieldAutoClipListener->flatFieldAutoClipValueChanged(imgsrc->getFlatFieldAutoClipValue());
|
|
}
|
|
|
|
imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw);
|
|
hist_raw_dirty = !(hListener && hListener->updateHistogramRaw());
|
|
|
|
highDetailPreprocessComputed = highDetailNeeded;
|
|
}
|
|
|
|
/*
|
|
Demosaic is kicked off only when
|
|
Detail considerations:
|
|
accurate detail is not displayed yet needed based on preview specifics (driven via highDetailNeeded flag)
|
|
OR
|
|
HLR considerations:
|
|
Color HLR alters rgb output of demosaic, so re-demosaic is needed when Color HLR is being turned off;
|
|
if HLR is enabled and changing method *from* Color to any other method
|
|
OR HLR gets disabled when Color method was selected
|
|
If white balance changed with inpaint opposed, because inpaint opposed depends on the white balance
|
|
*/
|
|
// If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST
|
|
|
|
if (imageTypeListener) {
|
|
imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported());
|
|
}
|
|
|
|
bool iscolor = (params->toneCurve.method == "Color" || params->toneCurve.method == "Coloropp");
|
|
if ((todo & M_WB) && params->toneCurve.hrenabled && params->toneCurve.method == "Coloropp") {
|
|
todo |= DEMOSAIC;
|
|
}
|
|
|
|
if ((todo & M_RAW)
|
|
|| (!highDetailRawComputed && highDetailNeeded)
|
|
// || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
|
|
// || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
|
|
|| (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified())
|
|
|| (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) {
|
|
|
|
if (settings->verbose) {
|
|
if (imgsrc->getSensorType() == ST_BAYER) {
|
|
printf("Demosaic Bayer image n.%d using method: %s\n", rp.bayersensor.imageNum + 1, rp.bayersensor.method.c_str());
|
|
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
|
|
printf("Demosaic X-Trans image with using method: %s\n", rp.xtranssensor.method.c_str());
|
|
}
|
|
}
|
|
|
|
if (imgsrc->getSensorType() == ST_BAYER) {
|
|
if (params->raw.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) {
|
|
imgsrc->setBorder(params->raw.bayersensor.border);
|
|
} else {
|
|
imgsrc->setBorder(std::max(params->raw.bayersensor.border, 2));
|
|
}
|
|
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
|
|
imgsrc->setBorder(params->raw.xtranssensor.border);
|
|
}
|
|
|
|
bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params->raw.bayersensor.dualDemosaicAutoContrast : params->raw.xtranssensor.dualDemosaicAutoContrast;
|
|
double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params->raw.bayersensor.dualDemosaicContrast : params->raw.xtranssensor.dualDemosaicContrast;
|
|
imgsrc->demosaic(rp, autoContrast, contrastThreshold, params->pdsharpening.enabled);
|
|
|
|
if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener && autoContrast) {
|
|
bayerAutoContrastListener->autoContrastChanged(contrastThreshold);
|
|
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS && xtransAutoContrastListener && autoContrast) {
|
|
|
|
xtransAutoContrastListener->autoContrastChanged(contrastThreshold);
|
|
}
|
|
|
|
// if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag
|
|
todo |= (M_INIT | M_CSHARP);
|
|
|
|
}
|
|
|
|
if ((todo & (M_RAW | M_CSHARP)) && params->pdsharpening.enabled) {
|
|
double pdSharpencontrastThreshold = params->pdsharpening.contrast;
|
|
double pdSharpenRadius = params->pdsharpening.deconvradius;
|
|
imgsrc->captureSharpening(params->pdsharpening, sharpMask, pdSharpencontrastThreshold, pdSharpenRadius);
|
|
|
|
if (pdSharpenAutoContrastListener && params->pdsharpening.autoContrast) {
|
|
pdSharpenAutoContrastListener->autoContrastChanged(pdSharpencontrastThreshold);
|
|
}
|
|
|
|
if (pdSharpenAutoRadiusListener && params->pdsharpening.autoRadius) {
|
|
pdSharpenAutoRadiusListener->autoRadiusChanged(pdSharpenRadius);
|
|
}
|
|
}
|
|
|
|
|
|
if ((todo & M_RAW)
|
|
|| (!highDetailRawComputed && highDetailNeeded)
|
|
// || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
|
|
// || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
|
|
|| (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified())
|
|
|| (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) {
|
|
if (highDetailNeeded) {
|
|
highDetailRawComputed = true;
|
|
} else {
|
|
highDetailRawComputed = false;
|
|
}
|
|
|
|
if (params->retinex.enabled) {
|
|
lhist16RETI(32768);
|
|
lhist16RETI.clear();
|
|
|
|
imgsrc->retinexPrepareBuffers(params->icm, params->retinex, conversionBuffer, lhist16RETI);
|
|
}
|
|
}
|
|
|
|
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
|
|
if (params->wb.method == "autitcgreen") {
|
|
imgsrc->getrgbloc(0, 0, fh, fw, 0, 0, fh, fw, params->wb);
|
|
}
|
|
}
|
|
|
|
if ((todo & (M_RETINEX | M_INIT)) && params->retinex.enabled) {
|
|
bool dehacontlutili = false;
|
|
bool mapcontlutili = false;
|
|
bool useHsl = false;
|
|
LUTf cdcurve(65536, 0);
|
|
LUTf mapcurve(65536, 0);
|
|
|
|
imgsrc->retinexPrepareCurves(params->retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI);
|
|
float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax;
|
|
imgsrc->retinex(params->icm, params->retinex, params->toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI); //enabled Retinex
|
|
|
|
if (dehaListener) {
|
|
dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax);
|
|
}
|
|
}
|
|
|
|
// const bool autowb = (params->wb.method == "autold" || params->wb.method == "autitcgreen");
|
|
|
|
if (settings->verbose) {
|
|
printf("automethod=%s \n", params->wb.method.c_str());
|
|
}
|
|
|
|
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
|
|
MyMutex::MyLock initLock(minit); // Also used in crop window
|
|
//imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery
|
|
|
|
|
|
if (settings->verbose) {
|
|
printf("Applying white balance, color correction & sRBG conversion...\n");
|
|
}
|
|
|
|
currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer);
|
|
int tempnotisraw = 6501;//D65 with Observer 2° - 6473 with Observer 10°
|
|
double greennotisraw = 1.;//D65 with Observer 2° - 0.967 with Observer 10°
|
|
|
|
if (!imgsrc->isRAW() && params->wb.method == "autitcgreen") {
|
|
if (params->wb.compat_version == 1) {
|
|
// ITCWB compatibility version 1 used 5000 K and observer 10
|
|
// degrees for non-raw files.
|
|
auto currWBitc = ColorTemp(5000., 1., 1., params->wb.method, StandardObserver::TEN_DEGREES);
|
|
currWBitc = currWBitc.convertObserver(params->wb.observer);
|
|
tempnotisraw = currWBitc.getTemp();
|
|
greennotisraw = currWBitc.getGreen();
|
|
} else {
|
|
auto currWBitc = imgsrc->getWB();//if jpg TIF with another illuminant
|
|
currWBitc = currWBitc.convertObserver(params->wb.observer);
|
|
tempnotisraw = currWBitc.getTemp();
|
|
greennotisraw = currWBitc.getGreen();
|
|
}
|
|
}
|
|
|
|
int dread = 0;
|
|
int bia = 1;
|
|
float studgood = 1000.f;
|
|
int nocam = 0;
|
|
int kcam = 0;
|
|
float minchrom = 1000.f;
|
|
float delta = 0.f;
|
|
int kmin = 20;
|
|
float minhist = 1000000000.f;
|
|
float maxhist = -1000.f;
|
|
double greenitc = 1.;
|
|
float temp0 = 5000.f;
|
|
bool extra = false;
|
|
bool forcewbgrey = false;
|
|
|
|
if (!params->wb.enabled) {
|
|
currWB = ColorTemp();
|
|
} else if (params->wb.method == "Camera") {
|
|
currWB = imgsrc->getWB();
|
|
lastAwbauto = ""; //reinitialize auto
|
|
|
|
} else if (params->wb.method == "autold") {
|
|
if (lastAwbEqual != params->wb.equal || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) {
|
|
double rm, gm, bm;
|
|
if (params->wb.compat_version == 1 && !imgsrc->isRAW()) {
|
|
// RGB grey compatibility version 1 used the identity
|
|
// multipliers plus temperature bias for non-raw files.
|
|
rm = gm = bm = 1.;
|
|
} else {
|
|
imgsrc->getAutoWBMultipliers(rm, gm, bm);
|
|
}
|
|
|
|
if (rm != -1.) {
|
|
double bias = params->wb.tempBias;
|
|
|
|
autoWB.update(rm, gm, bm, params->wb.equal, params->wb.observer, bias);
|
|
lastAwbEqual = params->wb.equal;
|
|
lastAwbObserver = params->wb.observer;
|
|
lastAwbTempBias = params->wb.tempBias;
|
|
lastAwbauto = params->wb.method;
|
|
} else {
|
|
lastAwbEqual = -1.;
|
|
lastAwbObserver = ColorTemp::DEFAULT_OBSERVER;
|
|
lastAwbTempBias = 0.0;
|
|
lastAwbauto = "";
|
|
autoWB.useDefaults(params->wb.equal, params->wb.observer);
|
|
|
|
}
|
|
|
|
//double rr,gg,bb;
|
|
//autoWB.getMultipliers(rr,gg,bb);
|
|
}
|
|
currWB = autoWB;
|
|
// lastAwbauto = ""; //reinitialize auto
|
|
} else if (params->wb.method == "autitcgreen") { //(// autowb) {
|
|
double rm;
|
|
double gm;
|
|
double bm;
|
|
imgsrc->getAutoWBMultipliersItcGreen(
|
|
*params,
|
|
forcewbgrey,
|
|
kcam,
|
|
greenitc,
|
|
extra,
|
|
temp0,
|
|
delta,
|
|
bia,
|
|
dread,
|
|
nocam,
|
|
studgood,
|
|
minchrom,
|
|
kmin,
|
|
minhist,
|
|
maxhist,
|
|
fh,
|
|
fw,
|
|
currWB,
|
|
tempnotisraw,
|
|
greennotisraw,
|
|
lastAwbEqual == params->wb.equal && lastAwbObserver == params->wb.observer && lastAwbTempBias == params->wb.tempBias && lastAwbauto == params->wb.method,
|
|
autoWB,
|
|
rm,
|
|
gm,
|
|
bm);
|
|
|
|
if (imgsrc->isRAW() || lastAwbEqual != params->wb.equal || lastAwbObserver != params->wb.observer || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) {
|
|
if (rm != -1.) {
|
|
autoWB.update(rm, gm, bm, params->wb.equal, params->wb.observer);
|
|
lastAwbEqual = params->wb.equal;
|
|
lastAwbObserver = params->wb.observer;
|
|
lastAwbTempBias = params->wb.tempBias;
|
|
lastAwbauto = params->wb.method;
|
|
} else {
|
|
lastAwbEqual = -1.;
|
|
lastAwbObserver = ColorTemp::DEFAULT_OBSERVER;
|
|
lastAwbTempBias = 0.0;
|
|
lastAwbauto = "";
|
|
autoWB.useDefaults(params->wb.equal, params->wb.observer);
|
|
}
|
|
}
|
|
|
|
currWB = autoWB;
|
|
}
|
|
|
|
double rw = 1.;
|
|
double gw = 1.;
|
|
double bw = 1.;
|
|
if (params->wb.enabled) {
|
|
currWB = currWB.convertObserver(params->wb.observer);
|
|
params->wb.temperature = static_cast<int>(currWB.getTemp());
|
|
params->wb.green = currWB.getGreen();
|
|
|
|
currWB.getMultipliers(rw, gw, bw);
|
|
imgsrc->wbMul2Camera(rw, gw, bw);
|
|
// params->wb.itcwb_sampling = false;
|
|
/*
|
|
printf("ra=%f ga=%f ba=%f\n", rw, gw, bw);
|
|
//recalculate temp and green with wb multipliers.
|
|
imgsrc->wbCamera2Mul(rw, gw, bw);
|
|
ColorTemp ct(rw, gw, bw, 1.0, currWB.getObserver());
|
|
//allows to calculate temp and green with multipliers in case of we want in GUI
|
|
float tem = ct.getTemp();
|
|
float gre = ct.getGreen();
|
|
printf("tem=%f gre=%f \n", (double) tem, (double) gre);
|
|
*/
|
|
}
|
|
|
|
int met = 0;
|
|
|
|
if (awbListener && params->wb.enabled) {
|
|
if (params->wb.method == "autitcgreen" && imgsrc->isRAW()) {//Raw files
|
|
if (params->wb.itcwb_sampling) {
|
|
dread = 1;
|
|
studgood = 1.f;
|
|
awbListener->WBChanged(met, params->wb.temperature, params->wb.green, rw, gw, bw, 0, 1, 0, dread, studgood, 0, 0, 0, 0, AutoWBListener::AWBMode::TEMP_CORRELATION_RAW);
|
|
|
|
} else {
|
|
minchrom = LIM(minchrom, 0.f, 0.9f);
|
|
delta = LIM(delta, 0.f, 0.9f);
|
|
minhist = std::max(minhist, 100.f);
|
|
maxhist = std::max(maxhist, 1000.f);
|
|
kmin = std::max(kmin, 18);
|
|
dread = LIM(dread, 10, 239);
|
|
awbListener->WBChanged(met, params->wb.temperature, params->wb.green, rw, gw, bw, temp0, delta, bia, dread, studgood, minchrom, kmin, minhist, maxhist, AutoWBListener::AWBMode::TEMP_CORRELATION_RAW);
|
|
}
|
|
} else if (params->wb.method == "autitcgreen" && !imgsrc->isRAW()) {//non raw files
|
|
params->wb.temperature = tempnotisraw;
|
|
params->wb.green = greennotisraw;
|
|
currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer);
|
|
|
|
awbListener->WBChanged(met, params->wb.temperature, params->wb.green, rw, gw, bw, -1.f, -1.f, 1, 1, -1.f, -1.f, 1, -1.f, -1.f, AutoWBListener::AWBMode::TEMP_CORRELATION_NON_RAW);//false => hide settings
|
|
|
|
} else if (params->wb.method == "autold"){
|
|
awbListener->WBChanged(met, params->wb.temperature, params->wb.green, rw, gw, bw, -1.f, -1.f, 1, 1, -1.f, -1.f, 1, -1.f, -1.f, AutoWBListener::AWBMode::RGB_GREY);
|
|
} else {
|
|
awbListener->WBChanged(met, params->wb.temperature, params->wb.green, rw, gw, bw, -1.f, -1.f, 1, 1, -1.f, -1.f, 1, -1.f, -1.f, AutoWBListener::AWBMode::NONE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
GammaValues g_a;
|
|
double pwr = 1.0 / params->icm.gampos;
|
|
double ts = params->icm.slpos;
|
|
|
|
|
|
int mode = 0;
|
|
Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope
|
|
printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", g_a[0],g_a[1],g_a[2],g_a[3],g_a[4]);
|
|
|
|
Glib::ustring datal;
|
|
datal = "lutsrgb.txt";
|
|
ofstream fou(datal, ios::out | ios::trunc);
|
|
|
|
for(int i=0; i < 212; i++) {
|
|
//printf("igamma2=%i\n", (int) 65535.f*Color::igamma2(i/212.0));
|
|
float gam = Color::igamma2(i/211.0);
|
|
int lutga = nearbyint(65535.f* gam);
|
|
// fou << 65535*(int)Color::igamma2(i/212.0) << endl;
|
|
fou << i << " " << lutga << endl;
|
|
|
|
}
|
|
fou.close();
|
|
*/
|
|
int tr = getCoarseBitMask(params->coarse);
|
|
|
|
imgsrc->getFullSize(fw, fh, tr);
|
|
|
|
// Will (re)allocate the preview's buffers
|
|
setScale(scale);
|
|
PreviewProps pp(0, 0, fw, fh, scale);
|
|
// Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications
|
|
ipf.setScale(scale);
|
|
imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw);
|
|
|
|
if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) {
|
|
spotsDone = true;
|
|
PreviewProps pp(0, 0, fw, fh, scale);
|
|
ipf.removeSpots(orig_prev, imgsrc, params->spot.entries, pp, currWB, nullptr, tr);
|
|
}
|
|
|
|
denoiseInfoStore.valid = false;
|
|
//ColorTemp::CAT02 (orig_prev, ¶ms) ;
|
|
// printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale);
|
|
/* Issue 2785, disabled some 1:1 tools
|
|
if (todo & M_LINDENOISE) {
|
|
DirPyrDenoiseParams denoiseParams = params->dirpyrDenoise;
|
|
if (denoiseParams.enabled && (scale==1)) {
|
|
Imagefloat *calclum = NULL ;
|
|
|
|
denoiseParams.getCurves(noiseLCurve,noiseCCurve);
|
|
int nbw=6;//nb tile W
|
|
int nbh=4;//
|
|
|
|
float ch_M[nbw*nbh];
|
|
float max_r[nbw*nbh];
|
|
float max_b[nbw*nbh];
|
|
|
|
if (denoiseParams.Lmethod == "CUR") {
|
|
if (noiseLCurve)
|
|
denoiseParams.luma = 0.5f;
|
|
else
|
|
denoiseParams.luma = 0.0f;
|
|
} else if (denoiseParams.Lmethod == "SLI")
|
|
noiseLCurve.Reset();
|
|
|
|
|
|
if (noiseLCurve || noiseCCurve){//only allocate memory if enabled and scale=1
|
|
// we only need image reduced to 1/4 here
|
|
calclum = new Imagefloat ((pW+1)/2, (pH+1)/2);//for luminance denoise curve
|
|
for(int ii=0;ii<pH;ii+=2){
|
|
for(int jj=0;jj<pW;jj+=2){
|
|
calclum->r(ii>>1,jj>>1) = orig_prev->r(ii,jj);
|
|
calclum->g(ii>>1,jj>>1) = orig_prev->g(ii,jj);
|
|
calclum->b(ii>>1,jj>>1) = orig_prev->b(ii,jj);
|
|
}
|
|
}
|
|
imgsrc->convertColorSpace(calclum, params->icm, currWB);//calculate values after colorspace conversion
|
|
}
|
|
|
|
int kall=1;
|
|
ipf.RGB_denoise(kall, orig_prev, orig_prev, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi);
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (params->filmNegative.enabled) {
|
|
|
|
// Process film negative AFTER colorspace conversion
|
|
if (params->filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) {
|
|
imgsrc->convertColorSpace(orig_prev, params->icm, currWB);
|
|
}
|
|
|
|
// Perform negative inversion. If needed, upgrade filmNegative params for backwards compatibility with old profiles
|
|
if (ipf.filmNegativeProcess(orig_prev, orig_prev, params->filmNegative, params->raw, imgsrc, currWB) && filmNegListener) {
|
|
filmNegListener->filmRefValuesChanged(params->filmNegative.refInput, params->filmNegative.refOutput);
|
|
}
|
|
|
|
// Process film negative BEFORE colorspace conversion (legacy mode)
|
|
if (params->filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) {
|
|
imgsrc->convertColorSpace(orig_prev, params->icm, currWB);
|
|
}
|
|
|
|
} else {
|
|
imgsrc->convertColorSpace(orig_prev, params->icm, currWB);
|
|
}
|
|
|
|
if (params->cg.enabled) {//gamut compression
|
|
ipf.gamutcompr(orig_prev, orig_prev);
|
|
}
|
|
|
|
ipf.firstAnalysis(orig_prev, *params, vhist16);
|
|
}
|
|
|
|
oprevi = orig_prev;
|
|
|
|
if ((todo & M_SPOT) && !spotsDone) {
|
|
if (params->spot.enabled && !params->spot.entries.empty()) {
|
|
allocCache(spotprev);
|
|
orig_prev->copyData(spotprev);
|
|
PreviewProps pp(0, 0, fw, fh, scale);
|
|
ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, ¶ms->icm, tr);
|
|
} else {
|
|
if (spotprev) {
|
|
delete spotprev;
|
|
spotprev = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (spotprev) {
|
|
spotprev->copyData(orig_prev);
|
|
}
|
|
|
|
if ((todo & M_HDR) && (params->fattal.enabled || params->dehaze.enabled)) {
|
|
if (fattal_11_dcrop_cache) {
|
|
delete fattal_11_dcrop_cache;
|
|
fattal_11_dcrop_cache = nullptr;
|
|
}
|
|
|
|
ipf.dehaze(orig_prev, params->dehaze);
|
|
ipf.ToneMapFattal02(orig_prev, params->fattal, 3, 0, nullptr, 0, 0, 0, false);
|
|
|
|
if (oprevi != orig_prev) {
|
|
delete oprevi;
|
|
}
|
|
}
|
|
|
|
// Remove transformation if unneeded
|
|
bool needstransform = ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData());
|
|
|
|
const bool cam02 = params->colorappearance.modelmethod == "02" && params->colorappearance.enabled;
|
|
// 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))) {
|
|
// Forking the image
|
|
assert(oprevi);
|
|
Imagefloat *op = oprevi;
|
|
oprevi = new Imagefloat(pW, pH);
|
|
|
|
if (needstransform)
|
|
ipf.transform(op, oprevi, 0, 0, 0, 0, pW, pH, fw, fh,
|
|
imgsrc->getMetaData(), imgsrc->getRotateDegree(), false);
|
|
else {
|
|
op->copyData(oprevi);
|
|
}
|
|
}
|
|
|
|
for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) {
|
|
if(params->locallab.spots.at(sp).expsharp && params->dirpyrequalizer.cbdlMethod == "bef") {
|
|
if(params->locallab.spots.at(sp).shardamping < 1) {
|
|
params->locallab.spots.at(sp).shardamping = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 = oprevi->getWidth();
|
|
const int H = oprevi->getHeight();
|
|
LabImage labcbdl(W, H);
|
|
ipf.rgb2lab(*oprevi, labcbdl, params->icm.workingProfile);
|
|
ipf.dirpyrequalizer(&labcbdl, scale);
|
|
ipf.lab2rgb(labcbdl, *oprevi, params->icm.workingProfile);
|
|
}
|
|
|
|
if (todo & M_AUTOEXP) {
|
|
if (params->toneCurve.autoexp) {
|
|
LUTu aehist;
|
|
int aehistcompr;
|
|
imgsrc->getAutoExpHistogram(aehist, aehistcompr);
|
|
ipf.getAutoExp(aehist, aehistcompr, params->toneCurve.clip, params->toneCurve.expcomp,
|
|
params->toneCurve.brightness, params->toneCurve.contrast, params->toneCurve.black, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh);
|
|
|
|
if (aeListener)
|
|
aeListener->autoExpChanged(params->toneCurve.expcomp, params->toneCurve.brightness, params->toneCurve.contrast,
|
|
params->toneCurve.black, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, params->toneCurve.hrenabled);
|
|
}
|
|
|
|
if (params->toneCurve.histmatching ) {
|
|
bool exectrcexp = false;//store if Abstract profile enabled
|
|
exectrcexp = params->icm.trcExp;
|
|
if (!params->toneCurve.fromHistMatching) {
|
|
if(params->icm.trcExp) {
|
|
params->icm.trcExp = false;//disabled Abstract profile, if hismatching
|
|
}
|
|
imgsrc->getAutoMatchedToneCurve(params->icm, params->raw, params->wb.observer, params->toneCurve.curve);
|
|
params->icm.trcExp = exectrcexp;//restore Abstract profile
|
|
}
|
|
|
|
if (params->toneCurve.autoexp) {
|
|
params->toneCurve.expcomp = 0.0;
|
|
}
|
|
|
|
params->toneCurve.autoexp = false;
|
|
params->toneCurve.curveMode = ToneCurveMode::FILMLIKE;
|
|
params->toneCurve.curve2 = { 0 };
|
|
params->toneCurve.brightness = 0;
|
|
params->toneCurve.contrast = 0;
|
|
params->toneCurve.black = 0;
|
|
params->toneCurve.fromHistMatching = true;
|
|
|
|
if (aeListener) {
|
|
aeListener->autoMatchedToneCurveChanged(params->toneCurve.curveMode, params->toneCurve.curve);
|
|
}
|
|
}
|
|
|
|
// Encoding log with locallab
|
|
if (params->locallab.enabled && !params->locallab.spots.empty()) {
|
|
const int sizespot = (int)params->locallab.spots.size();
|
|
const LocallabParams::LocallabSpot defSpot;
|
|
std::vector<LocallabListener::locallabcieBEF> locallciebef;
|
|
|
|
float *sourceg = nullptr;
|
|
sourceg = new float[sizespot];
|
|
float *sourceab = nullptr;
|
|
sourceab = new float[sizespot];
|
|
float *targetg = nullptr;
|
|
targetg = new float[sizespot];
|
|
bool *log = nullptr;
|
|
log = new bool[sizespot];
|
|
bool *cie = nullptr;
|
|
cie = new bool[sizespot];
|
|
bool *autocomput = nullptr;
|
|
autocomput = new bool[sizespot];
|
|
float *blackev = nullptr;
|
|
blackev = new float[sizespot];
|
|
float *whiteev = nullptr;
|
|
whiteev = new float[sizespot];
|
|
bool *Autogr = nullptr;
|
|
Autogr = new bool[sizespot];
|
|
bool *autocie = nullptr;
|
|
autocie = new bool[sizespot];
|
|
int *whits = nullptr;
|
|
whits = new int[sizespot];
|
|
int *blacks = nullptr;
|
|
blacks = new int[sizespot];
|
|
int *whitslog = nullptr;
|
|
whitslog = new int[sizespot];
|
|
int *blackslog = nullptr;
|
|
blackslog = new int[sizespot];
|
|
|
|
|
|
float *locx = nullptr;
|
|
locx = new float[sizespot];
|
|
float *locy = nullptr;
|
|
locy = new float[sizespot];
|
|
float *locxL = nullptr;
|
|
locxL = new float[sizespot];
|
|
float *locyT = nullptr;
|
|
locyT = new float[sizespot];
|
|
float *centx = nullptr;
|
|
centx = new float[sizespot];
|
|
float *centy = nullptr;
|
|
centy = new float[sizespot];
|
|
|
|
for (int sp = 0; sp < sizespot; sp++) {
|
|
log[sp] = params->locallab.spots.at(sp).explog;
|
|
cie[sp] = params->locallab.spots.at(sp).expcie;
|
|
autocomput[sp] = params->locallab.spots.at(sp).autocompute;
|
|
autocie[sp] = params->locallab.spots.at(sp).Autograycie;
|
|
blackev[sp] = params->locallab.spots.at(sp).blackEv;
|
|
whiteev[sp] = params->locallab.spots.at(sp).whiteEv;
|
|
sourceg[sp] = params->locallab.spots.at(sp).sourceGray;
|
|
sourceab[sp] = params->locallab.spots.at(sp).sourceabs;
|
|
whits[sp] = params->locallab.spots.at(sp).whitescie;
|
|
blacks[sp] = params->locallab.spots.at(sp).blackscie;
|
|
whitslog[sp] = params->locallab.spots.at(sp).whiteslog;
|
|
blackslog[sp] = params->locallab.spots.at(sp).blackslog;
|
|
Autogr[sp] = params->locallab.spots.at(sp).Autogray;
|
|
targetg[sp] = params->locallab.spots.at(sp).targetGray;
|
|
locx[sp] = params->locallab.spots.at(sp).loc.at(0) / 2000.0;
|
|
locy[sp] = params->locallab.spots.at(sp).loc.at(2) / 2000.0;
|
|
locxL[sp] = params->locallab.spots.at(sp).loc.at(1) / 2000.0;
|
|
locyT[sp] = params->locallab.spots.at(sp).loc.at(3) / 2000.0;
|
|
centx[sp] = params->locallab.spots.at(sp).centerX / 2000.0 + 0.5;
|
|
centy[sp] = params->locallab.spots.at(sp).centerY / 2000.0 + 0.5;
|
|
|
|
const bool fullimstd = params->locallab.spots.at(sp).fullimage;//for log encoding standard
|
|
const bool fullimjz = true;//always force fullimage in log encoding Jz - always possible to put a checkbox if need
|
|
|
|
if ((log[sp] && autocomput[sp]) || (cie[sp] && autocie[sp])) {
|
|
constexpr int SCALE = 10;
|
|
int fw, fh, tr = TR_NONE;
|
|
imgsrc->getFullSize(fw, fh, tr);
|
|
PreviewProps pp(0, 0, fw, fh, SCALE);
|
|
|
|
float ysta = std::max(static_cast<float>(centy[sp] - locyT[sp]), 0.f);
|
|
float yend = std::min(static_cast<float>(centy[sp] + locy[sp]), 1.f);
|
|
float xsta = std::max(static_cast<float>(centx[sp] - locxL[sp]), 0.f);
|
|
float xend = std::min(static_cast<float>(centx[sp] + locx[sp]), 1.f);
|
|
|
|
if (fullimstd && (log[sp] && autocomput[sp])) {
|
|
ysta = 0.f;
|
|
yend = 1.f;
|
|
xsta = 0.f;
|
|
xend = 1.f;
|
|
}
|
|
|
|
if (fullimjz && (cie[sp] && autocie[sp])) {
|
|
ysta = 0.f;
|
|
yend = 1.f;
|
|
xsta = 0.f;
|
|
xend = 1.f;
|
|
}
|
|
ipf.getAutoLogloc(sp, imgsrc, sourceg, blackev, whiteev, Autogr, sourceab, whits, blacks, whitslog, blackslog, fw, fh, xsta, xend, ysta, yend, SCALE);
|
|
params->locallab.spots.at(sp).blackEv = blackev[sp];
|
|
params->locallab.spots.at(sp).whiteEv = whiteev[sp];
|
|
params->locallab.spots.at(sp).blackEvjz = blackev[sp];
|
|
params->locallab.spots.at(sp).whiteEvjz = whiteev[sp];
|
|
params->locallab.spots.at(sp).sourceGray = sourceg[sp];
|
|
params->locallab.spots.at(sp).sourceabs = sourceab[sp];
|
|
params->locallab.spots.at(sp).sourceGraycie = sourceg[sp];
|
|
params->locallab.spots.at(sp).sourceabscie = sourceab[sp];
|
|
params->locallab.spots.at(sp).whitescie = whits[sp];
|
|
params->locallab.spots.at(sp).blackscie = blacks[sp];
|
|
params->locallab.spots.at(sp).whiteslog = whitslog[sp];
|
|
params->locallab.spots.at(sp).blackslog = blackslog[sp];
|
|
float jz1 = defSpot.jz100;
|
|
|
|
LocallabListener::locallabcieBEF locciebef;
|
|
locciebef.blackevbef = blackev[sp];
|
|
locciebef.whiteevbef = whiteev[sp];
|
|
locciebef.sourcegbef = sourceg[sp];
|
|
locciebef.sourceabbef = sourceab[sp];
|
|
locciebef.targetgbef = targetg[sp];
|
|
locciebef.autocomputbef = autocomput[sp];
|
|
locciebef.autociebef = autocie[sp];
|
|
locciebef.jz1bef = jz1;
|
|
locallciebef.push_back(locciebef);
|
|
|
|
if (locallListener) {
|
|
locallListener->ciebefChanged(locallciebef,params->locallab.selspot);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] locx;
|
|
delete [] locy;
|
|
delete [] locxL;
|
|
delete [] locyT;
|
|
delete [] centx;
|
|
delete [] centy;
|
|
|
|
delete [] autocie;
|
|
delete [] Autogr;
|
|
delete [] whiteev;
|
|
delete [] blackev;
|
|
delete [] targetg;
|
|
delete [] sourceab;
|
|
delete [] whits;
|
|
delete [] blacks;
|
|
delete [] whitslog;
|
|
delete [] blackslog;
|
|
delete [] sourceg;
|
|
delete [] cie;
|
|
delete [] log;
|
|
delete [] autocomput;
|
|
}
|
|
}
|
|
|
|
|
|
if ((todo & (M_AUTOEXP | M_RGBCURVE | M_CROP)) && params->locallab.enabled && !params->locallab.spots.empty()) {
|
|
|
|
ipf.rgb2lab(*oprevi, *oprevl, params->icm.workingProfile);
|
|
|
|
nprevl->CopyFrom(oprevl);
|
|
// int maxspot = 1;
|
|
//*************************************************************
|
|
// locallab
|
|
//*************************************************************
|
|
|
|
/*
|
|
* 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
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
* 2017 2018 Jacques Desmis <jdesmis@gmail.com>
|
|
* 2019 Pierre Cabrera <pierre.cab@gmail.com>
|
|
*/
|
|
const std::unique_ptr<LabImage> reserv(new LabImage(*oprevl, true));
|
|
const std::unique_ptr<LabImage> lastorigimp(new LabImage(*oprevl, true));
|
|
std::unique_ptr<LabImage> savenormdr;
|
|
std::unique_ptr<LabImage> savenormtm;
|
|
std::unique_ptr<LabImage> savenormreti;
|
|
float **shbuffer = nullptr;
|
|
int sca = 1;
|
|
double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre;
|
|
float avge, meantme, stdtme, meanretie, stdretie;
|
|
//std::vector<LocallabListener::locallabRef> locallref;
|
|
std::vector<LocallabListener::locallabRetiMinMax> locallretiminmax;
|
|
std::vector<LocallabListener::locallabcieLC> locallcielc;
|
|
std::vector<LocallabListener::locallabshGHSbw> locallshgshbw;
|
|
std::vector<LocallabListener::locallabsetLC> locallsetlc;
|
|
std::vector<LocallabListener::locallabcieSIG> locallciesig;
|
|
huerefs.resize(params->locallab.spots.size());
|
|
huerefblurs.resize(params->locallab.spots.size());
|
|
chromarefblurs.resize(params->locallab.spots.size());
|
|
lumarefblurs.resize(params->locallab.spots.size());
|
|
chromarefs.resize(params->locallab.spots.size());
|
|
lumarefs.resize(params->locallab.spots.size());
|
|
sobelrefs.resize(params->locallab.spots.size());
|
|
avgs.resize(params->locallab.spots.size());
|
|
meantms.resize(params->locallab.spots.size());
|
|
stdtms.resize(params->locallab.spots.size());
|
|
meanretis.resize(params->locallab.spots.size());
|
|
stdretis.resize(params->locallab.spots.size());
|
|
const int sizespot = (int)params->locallab.spots.size();
|
|
|
|
float *huerefp = nullptr;
|
|
huerefp = new float[sizespot];
|
|
float *chromarefp = nullptr;
|
|
chromarefp = new float[sizespot];
|
|
float *lumarefp = nullptr;
|
|
lumarefp = new float[sizespot];
|
|
float *fabrefp = nullptr;
|
|
fabrefp = new float[sizespot];
|
|
//new controls mainfp and scopefp with multi spots
|
|
int *mainfp = nullptr;
|
|
mainfp = new int[sizespot];
|
|
int *scopefp = nullptr;
|
|
scopefp = new int[sizespot];
|
|
|
|
for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) {
|
|
|
|
if (params->locallab.spots.at(sp).equiltm && params->locallab.spots.at(sp).exptonemap) {
|
|
savenormtm.reset(new LabImage(*oprevl, true));
|
|
}
|
|
|
|
if (params->locallab.spots.at(sp).equilret && params->locallab.spots.at(sp).expreti) {
|
|
savenormreti.reset(new LabImage(*oprevl, true));
|
|
}
|
|
|
|
// if(params->locallab.spots.at(sp).colorscope != 30) {//compatibility with old method in controlspotpanel to change scope - default value 30
|
|
// scopefp[sp]= params->locallab.spots.at(sp).colorscope;
|
|
// }
|
|
|
|
// Set local curves of current spot to LUT
|
|
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 llmasexputili = locllmasexpCurve.Set(params->locallab.spots.at(sp).LLmaskexpcurve);
|
|
const bool lcmasexputili = locccmasexpCurve.Set(params->locallab.spots.at(sp).CCmaskexpcurve);
|
|
const bool lhmasexputili = lochhmasexpCurve.Set(params->locallab.spots.at(sp).HHmaskexpcurve);
|
|
const bool llmasSHutili = locllmasSHCurve.Set(params->locallab.spots.at(sp).LLmaskSHcurve);
|
|
const bool lcmasSHutili = locccmasSHCurve.Set(params->locallab.spots.at(sp).CCmaskSHcurve);
|
|
const bool lhmasSHutili = lochhmasSHCurve.Set(params->locallab.spots.at(sp).HHmaskSHcurve);
|
|
const bool llmasvibutili = locllmasvibCurve.Set(params->locallab.spots.at(sp).LLmaskvibcurve);
|
|
const bool lcmasvibutili = locccmasvibCurve.Set(params->locallab.spots.at(sp).CCmaskvibcurve);
|
|
const bool lhmasvibutili = lochhmasvibCurve.Set(params->locallab.spots.at(sp).HHmaskvibcurve);
|
|
const bool llmascbutili = locllmascbCurve.Set(params->locallab.spots.at(sp).LLmaskcbcurve);
|
|
const bool lcmascbutili = locccmascbCurve.Set(params->locallab.spots.at(sp).CCmaskcbcurve);
|
|
const bool lhmascbutili = lochhmascbCurve.Set(params->locallab.spots.at(sp).HHmaskcbcurve);
|
|
const bool llmaslcutili = locllmaslcCurve.Set(params->locallab.spots.at(sp).LLmasklccurve);
|
|
const bool lcmaslcutili = locccmaslcCurve.Set(params->locallab.spots.at(sp).CCmasklccurve);
|
|
const bool lhmaslcutili = lochhmaslcCurve.Set(params->locallab.spots.at(sp).HHmasklccurve);
|
|
const bool llmasretiutili = locllmasretiCurve.Set(params->locallab.spots.at(sp).LLmaskreticurve);
|
|
const bool lcmasretiutili = locccmasretiCurve.Set(params->locallab.spots.at(sp).CCmaskreticurve);
|
|
const bool lhmasretiutili = lochhmasretiCurve.Set(params->locallab.spots.at(sp).HHmaskreticurve);
|
|
const bool llmastmutili = locllmastmCurve.Set(params->locallab.spots.at(sp).LLmasktmcurve);
|
|
const bool lcmastmutili = locccmastmCurve.Set(params->locallab.spots.at(sp).CCmasktmcurve);
|
|
const bool lhmastmutili = lochhmastmCurve.Set(params->locallab.spots.at(sp).HHmasktmcurve);
|
|
const bool llmasblutili = locllmasblCurve.Set(params->locallab.spots.at(sp).LLmaskblcurve);
|
|
const bool lcmasblutili = locccmasblCurve.Set(params->locallab.spots.at(sp).CCmaskblcurve);
|
|
const bool lhmasblutili = lochhmasblCurve.Set(params->locallab.spots.at(sp).HHmaskblcurve);
|
|
const bool llmaslogutili = locllmaslogCurve.Set(params->locallab.spots.at(sp).LLmaskcurveL);
|
|
const bool lcmaslogutili = locccmaslogCurve.Set(params->locallab.spots.at(sp).CCmaskcurveL);
|
|
const bool lhmaslogutili = lochhmaslogCurve.Set(params->locallab.spots.at(sp).HHmaskcurveL);
|
|
const bool llmascieutili = locllmascieCurve.Set(params->locallab.spots.at(sp).LLmaskciecurve);
|
|
const bool lcmascieutili = locccmascieCurve.Set(params->locallab.spots.at(sp).CCmaskciecurve);
|
|
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 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 locwavutili = locwavCurve.Set(params->locallab.spots.at(sp).locwavcurve);
|
|
const bool locwavutilijz = locwavCurvejz.Set(params->locallab.spots.at(sp).locwavcurvejz);
|
|
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 locwavhueutili = locwavCurvehue.Set(params->locallab.spots.at(sp).locwavcurvehue);
|
|
const bool locwavdenutili = locwavCurveden.Set(params->locallab.spots.at(sp).locwavcurveden);
|
|
const bool locedgwavutili = locedgwavCurve.Set(params->locallab.spots.at(sp).locedgwavcurve);
|
|
const bool lmasutili_wav = loclmasCurve_wav.Set(params->locallab.spots.at(sp).LLmask_curvewav);
|
|
const bool locallutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).llcurve, lllocalcurve, sca);
|
|
const bool localclutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).clcurve, cllocalcurve, sca);
|
|
const bool locallcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).lccurve, lclocalcurve, sca);
|
|
const bool localcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).cccurve, cclocalcurve, sca);
|
|
const bool localrgbutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).rgbcurve, rgblocalcurve, sca);
|
|
const bool localexutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).excurve, exlocalcurve, sca);
|
|
const bool localmaskutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve, sca);
|
|
const bool localmaskexputili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve, sca);
|
|
const bool localmaskSHutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve, sca);
|
|
// const bool localghsutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).ghscurve, ghslocalcurve, sca);
|
|
const bool localmaskvibutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve, sca);
|
|
const bool localmasktmutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve, sca);
|
|
const bool localmaskretiutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve, sca);
|
|
const bool localmaskcbutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve, sca);
|
|
const bool localmaskblutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve, sca);
|
|
const bool localmasklcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve, sca);
|
|
const bool localmasklogutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).LmaskcurveL, lmaskloglocalcurve, sca);
|
|
const bool localmask_utili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmask_curve, lmasklocal_curve, sca);
|
|
const bool localmaskcieutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskciecurve, lmaskcielocalcurve, sca);
|
|
const bool localcieutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).ciecurve, cielocalcurve, sca);
|
|
const bool localcieutili2 = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).ciecurve2, cielocalcurve2, sca);
|
|
const bool localjzutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).jzcurve, jzlocalcurve, sca);
|
|
const bool localczutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).czcurve, czlocalcurve, sca);
|
|
const bool localczjzutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).czjzcurve, czjzlocalcurve, sca);
|
|
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;
|
|
double cont = params->locallab.spots.at(sp).contrast;
|
|
float contsig = params->locallab.spots.at(sp).contsigqcie;
|
|
|
|
float lightsig = params->locallab.spots.at(sp).lightsigqcie;
|
|
|
|
if (black < 0. && params->locallab.spots.at(sp).expMethod == "pde") {
|
|
black *= 1.5;
|
|
}
|
|
|
|
// Reference parameters computation
|
|
if (params->locallab.spots.at(sp).spotMethod == "exc") {
|
|
ipf.calc_ref(sp, reserv.get(), reserv.get(), 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili);
|
|
} else {
|
|
ipf.calc_ref(sp, nprevl, nprevl, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili);
|
|
}
|
|
|
|
meantme = 0.f;
|
|
stdtme = 0.f;
|
|
meanretie = 0.f;
|
|
stdretie = 0.f;
|
|
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;
|
|
bool istm = params->locallab.spots.at(sp).equiltm && params->locallab.spots.at(sp).exptonemap;
|
|
bool isreti = params->locallab.spots.at(sp).equilret && params->locallab.spots.at(sp).expreti;
|
|
//preparation for mean and sigma on current RT-spot
|
|
float locx = 0.f;
|
|
float locy = 0.f;
|
|
float locxl = 0.f;
|
|
float locyt = 0.f;
|
|
float centx = 0.f;
|
|
float centy = 0.f;
|
|
float ysta = 0.f;
|
|
float yend = 1.f;
|
|
float xsta = 0.f;
|
|
float xend = 1.f;
|
|
|
|
if (istm || isreti) {
|
|
locx = params->locallab.spots.at(sp).loc.at(0) / 2000.0;
|
|
locy = params->locallab.spots.at(sp).loc.at(2) / 2000.0;
|
|
locxl = params->locallab.spots.at(sp).loc.at(1) / 2000.0;
|
|
locyt = params->locallab.spots.at(sp).loc.at(3) / 2000.0;
|
|
centx = params->locallab.spots.at(sp).centerX / 2000.0 + 0.5;
|
|
centy = params->locallab.spots.at(sp).centerY / 2000.0 + 0.5;
|
|
ysta = std::max(static_cast<float>(centy - locyt), 0.f);
|
|
yend = std::min(static_cast<float>(centy + locy), 1.f);
|
|
xsta = std::max(static_cast<float>(centx - locxl), 0.f);
|
|
xend = std::min(static_cast<float>(centx + locx), 1.f);
|
|
}
|
|
|
|
int ww = nprevl->W;
|
|
int hh = nprevl->H;
|
|
int xxs = xsta * ww;
|
|
int xxe = xend * ww;
|
|
int yys = ysta * hh;
|
|
int yye = yend * hh;
|
|
|
|
if (istm) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt
|
|
ipf.mean_sig(nprevl->L, meantme, stdtme, xxs, xxe, yys, yye);
|
|
}
|
|
|
|
if (isreti) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt
|
|
ipf.mean_sig(nprevl->L, meanretie, stdretie, xxs, xxe, yys, yye) ;
|
|
}
|
|
|
|
double huerblu = huerefblurs[sp] = huerefblu;
|
|
double chromarblu = chromarefblurs[sp] = chromarefblu;
|
|
double lumarblu = lumarefblurs[sp] = lumarefblu;
|
|
double huer = huerefs[sp] = huere;
|
|
double chromar = chromarefs[sp] = chromare;
|
|
double lumar = lumarefs[sp] = lumare ;
|
|
double sobeler = sobelrefs[sp] = sobelre;
|
|
float avg = avgs[sp] = avge;
|
|
float meantm = meantms[sp] = meantme;
|
|
float stdtm = stdtms[sp] = stdtme;
|
|
float meanreti = meanretis[sp] = meanretie;
|
|
float stdreti = stdretis[sp] = stdretie;
|
|
huerefp[sp] = huer;
|
|
chromarefp[sp] = chromar;
|
|
lumarefp[sp] = lumar;
|
|
|
|
CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumar,
|
|
hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, avg,
|
|
sca);
|
|
|
|
// Save Locallab mask curve references for current spot
|
|
// Locallab tools computation
|
|
/* Notes:
|
|
* - shbuffer is used as nullptr
|
|
*/
|
|
|
|
// Locallab mask is only showed in detailed image
|
|
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;
|
|
int ghsbpwp[2] = {0, 0};
|
|
float ghsbpwpvalue[2] = {0.f, 1.f};
|
|
|
|
Glib::ustring prof = params->icm.workingProfile;
|
|
if(params->locallab.spots.at(sp).complexcie == 2) {
|
|
params->locallab.spots.at(sp).primMethod = prof;//in Basic mode set to Working profile
|
|
}
|
|
float slopeg = 1.f;
|
|
bool linkrgb = true;
|
|
|
|
ipf.Lab_Local(3, sp, (float**)shbuffer, nprevl, nprevl, reserv.get(), savenormtm.get(), savenormreti.get(), lastorigimp.get(), fw, fh, 0, 0, pW, pH, pW, pH, pW, pH, scale, locRETgainCurve, locRETtransCurve,
|
|
// ipf.Lab_Local(3, sp, (float**)shbuffer, nprevl, nprevl, reserv.get(), savenormtm.get(), savenormreti.get(), lastorigimp.get(), fw, fh, 0, 0, pW, pH, scale, locRETgainCurve, locRETtransCurve,
|
|
lllocalcurve, locallutili,
|
|
cllocalcurve, localclutili,
|
|
lclocalcurve, locallcutili,
|
|
loclhCurve, lochhCurve, locchCurve,
|
|
lochhCurvejz, locchCurvejz, loclhCurvejz,
|
|
lmasklocalcurve, localmaskutili,
|
|
lmaskexplocalcurve, localmaskexputili,
|
|
lmaskSHlocalcurve, localmaskSHutili,
|
|
// ghslocalcurve, localghsutili,
|
|
lmaskviblocalcurve, localmaskvibutili,
|
|
lmasktmlocalcurve, localmasktmutili,
|
|
lmaskretilocalcurve, localmaskretiutili,
|
|
lmaskcblocalcurve, localmaskcbutili,
|
|
lmaskbllocalcurve, localmaskblutili,
|
|
lmasklclocalcurve, localmasklcutili,
|
|
lmaskloglocalcurve, localmasklogutili,
|
|
lmasklocal_curve, localmask_utili,
|
|
lmaskcielocalcurve, localmaskcieutili,
|
|
cielocalcurve, localcieutili,
|
|
cielocalcurve2, localcieutili2,
|
|
jzlocalcurve, localjzutili,
|
|
czlocalcurve, localczutili,
|
|
czjzlocalcurve, 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, cclocalcurve, localcutili, rgblocalcurve, localrgbutili, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc,
|
|
huerblu, chromarblu, lumarblu, huer, chromar, lumar, sobeler, 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,
|
|
meantm, stdtm, meanreti, stdreti, 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);
|
|
|
|
|
|
fabrefp[sp] = fab;
|
|
|
|
//Illuminant
|
|
float w_x = 0.3f;
|
|
float w_y = 0.3f;
|
|
if(ill == 2) {
|
|
w_x = 0.3457f;
|
|
w_y = 0.3585f;
|
|
} else if(ill == 4) {
|
|
w_x = 0.3217f;
|
|
w_y = 0.3377f;
|
|
} else if(ill == 5) {
|
|
w_x = 0.3127f;
|
|
w_y = 0.3290f;
|
|
} else if(ill == 1) {
|
|
w_x = 0.376137f;
|
|
w_y = 0.374021f;
|
|
} else if(ill == 3) {
|
|
w_x = 0.332424f;
|
|
w_y = 0.347426f;
|
|
} else if(ill == 6) {
|
|
w_x = 0.293756f;
|
|
w_y = 0.309185f;
|
|
} else if(ill == 7) {//D120
|
|
w_x = 0.269669f;
|
|
w_y = 0.28078f;
|
|
} else if(ill == 8) {//stdA
|
|
w_x = 0.447573f;
|
|
w_y = 0.407440f;
|
|
} else if(ill == 9) {//2000K
|
|
w_x = 0.526591f;
|
|
w_y = 0.41331f;
|
|
} else if(ill == 10) {//1500K
|
|
w_x = 0.585703f;
|
|
w_y = 0.393157f;
|
|
} else if(ill == 20) {
|
|
w_x = 0.333333f;
|
|
w_y = 0.333333f;
|
|
}
|
|
//move white-point in GUI
|
|
double refin = params->locallab.spots.at(sp).refi;
|
|
double arefi = (w_y - meany) / (w_x - meanx);
|
|
double brefi = w_y - arefi * w_x;
|
|
double scalrefi = meanx - w_x;
|
|
w_x = w_x + scalrefi * refin;
|
|
w_y = w_x * arefi + brefi;
|
|
|
|
|
|
|
|
if (istm) { //calculate mean and sigma on full image for use by normalize_mean_dt
|
|
float meanf = 0.f;
|
|
float stdf = 0.f;
|
|
ipf.mean_sig(savenormtm->L, meanf, stdf, xxs, xxe, yys, yye);
|
|
|
|
//using 2 unused variables noiselumc and softradiustm
|
|
params->locallab.spots.at(sp).noiselumc = (int) meanf;
|
|
params->locallab.spots.at(sp).softradiustm = stdf ;
|
|
}
|
|
|
|
if (isreti) { //calculate mean and sigma on full image for use by normalize_mean_dt
|
|
float meanf = 0.f;
|
|
float stdf = 0.f;
|
|
ipf.mean_sig(savenormreti->L, meanf, stdf, xxs, xxe, yys, yye);
|
|
//using 2 unused variables sensihs and sensiv
|
|
params->locallab.spots.at(sp).sensihs = (int) meanf;
|
|
params->locallab.spots.at(sp).sensiv = (int) stdf;
|
|
}
|
|
|
|
|
|
if (sp + 1u < params->locallab.spots.size()) {
|
|
// do not copy for last spot as it is not needed anymore
|
|
lastorigimp->CopyFrom(nprevl);
|
|
}
|
|
|
|
// Save Locallab Retinex min/max for current spot
|
|
LocallabListener::locallabRetiMinMax retiMinMax;
|
|
retiMinMax.cdma = maxCD;
|
|
retiMinMax.cdmin = minCD;
|
|
retiMinMax.mini = mini;
|
|
retiMinMax.maxi = maxi;
|
|
retiMinMax.Tmean = Tmean;
|
|
retiMinMax.Tsigma = Tsigma;
|
|
retiMinMax.Tmin = Tmin;
|
|
retiMinMax.Tmax = Tmax;
|
|
locallretiminmax.push_back(retiMinMax);
|
|
|
|
//save Locallab CIE primaries and white for current spot
|
|
LocallabListener::locallabcieLC loccielc;
|
|
loccielc.redxlc = rdx;
|
|
loccielc.redylc = rdy;
|
|
loccielc.grexlc = grx;
|
|
loccielc.greylc = gry;
|
|
loccielc.bluxlc = blx;
|
|
loccielc.bluylc = bly;
|
|
loccielc.wxlc = w_x;
|
|
loccielc.wylc = w_y;
|
|
loccielc.meanxlc = meanx;
|
|
loccielc.meanylc = meany;
|
|
loccielc.meanxelc = meanxe;
|
|
loccielc.meanyelc = meanye;
|
|
loccielc.slopeglc = slopeg;
|
|
loccielc.linkrgblc = linkrgb;
|
|
locallcielc.push_back(loccielc);
|
|
|
|
LocallabListener::locallabcieSIG locciesig;
|
|
locciesig.contsigq = contsig;
|
|
locciesig.lightsigq = lightsig;
|
|
locallciesig.push_back(locciesig);
|
|
|
|
LocallabListener::locallabshGHSbw locshghsbw;//ghs S curve
|
|
for(int j = 0; j < 2; j++) {
|
|
locshghsbw.ghsbw[j] = ghsbpwp[j];
|
|
locshghsbw.ghsbwvalue[j] = ghsbpwpvalue[j];
|
|
}
|
|
locallshgshbw.push_back(locshghsbw);
|
|
|
|
|
|
// Recalculate references after
|
|
if (params->locallab.spots.at(sp).spotMethod == "exc") {
|
|
ipf.calc_ref(sp, reserv.get(), reserv.get(), 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huer, chromar, lumar, sobeler, avg, locwavCurveden, locwavdenutili);
|
|
} else {
|
|
ipf.calc_ref(sp, nprevl, nprevl, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huer, chromar, lumar, sobeler, avg, locwavCurveden, locwavdenutili);
|
|
}
|
|
|
|
// Update Locallab reference values according to recurs parameter
|
|
if (params->locallab.spots.at(sp).recurs) {
|
|
huerefp[sp] = huer;
|
|
chromarefp[sp] = chromar;
|
|
lumarefp[sp] = lumar;
|
|
fabrefp[sp] = fab;
|
|
|
|
}
|
|
|
|
|
|
|
|
// new used linked to global and scope
|
|
mainfp[sp] = 0;
|
|
if (params->locallab.spots.at(sp).spotMethod == "main") {
|
|
mainfp[sp] = 3;
|
|
} else if (params->locallab.spots.at(sp).spotMethod == "full") {
|
|
mainfp[sp] = 2;
|
|
}
|
|
//keep using tools
|
|
bool iscolor = params->locallab.spots.at(sp).expcolor;
|
|
bool issh = params->locallab.spots.at(sp).expshadhigh;
|
|
bool isvib = params->locallab.spots.at(sp).expvibrance;
|
|
bool isexpos = params->locallab.spots.at(sp).expexpose;
|
|
bool issoft = params->locallab.spots.at(sp).expsoft;
|
|
bool isblur = params->locallab.spots.at(sp).expblur;
|
|
bool istom = params->locallab.spots.at(sp).exptonemap;
|
|
bool isret = params->locallab.spots.at(sp).expreti;
|
|
bool issharp = params->locallab.spots.at(sp).expsharp;
|
|
bool iscont = params->locallab.spots.at(sp).expcontrast;
|
|
bool iscbdl = params->locallab.spots.at(sp).expcbdl;
|
|
bool islog = params->locallab.spots.at(sp).explog;
|
|
bool ismas = params->locallab.spots.at(sp).expmask;
|
|
bool isci = params->locallab.spots.at(sp).expcie;
|
|
// bool isset = iscolor || issh || isvib;
|
|
|
|
//set select spot settings
|
|
LocallabListener::locallabsetLC locsetlc;
|
|
locsetlc.mainf = mainfp[sp];
|
|
locsetlc.iscolo = iscolor;
|
|
locsetlc.iss = issh;
|
|
locsetlc.isvi = isvib;
|
|
locsetlc.isexpo = isexpos;
|
|
locsetlc.issof = issoft;
|
|
locsetlc.isblu = isblur;
|
|
locsetlc.isto = istom;
|
|
locsetlc.isre = isret;
|
|
locsetlc.isshar = issharp;
|
|
locsetlc.iscon = iscont;
|
|
locsetlc.iscbd = iscbdl;
|
|
locsetlc.islo = islog;
|
|
locsetlc.isma = ismas;
|
|
locsetlc.isci = isci;
|
|
locallsetlc.push_back(locsetlc);
|
|
|
|
if (locallListener) {
|
|
locallListener->refChanged2(huerefp, chromarefp, lumarefp, fabrefp, params->locallab.selspot);
|
|
locallListener->minmaxChanged(locallretiminmax, params->locallab.selspot);
|
|
if (params->locallab.spots.at(sp).expprecam) {
|
|
locallListener->cieChanged(locallcielc,params->locallab.selspot);
|
|
}
|
|
locallListener->sigChanged(locallciesig,params->locallab.selspot);
|
|
if (params->locallab.spots.at(sp).expshadhigh && params->locallab.spots.at(sp).shMethod == "ghs") {
|
|
locallListener->ghsbwChanged(locallshgshbw,params->locallab.selspot);//Black and White point
|
|
}
|
|
|
|
/*
|
|
if(params->locallab.spots.at(sp).colorscope != 0) {//compatibility with old method in controlspotpanel
|
|
locallListener->scopeChangedcol(scopefp[sp], params->locallab.selspot, iscolor);
|
|
locallListener->scopeChangedsh(scopefp[sp], params->locallab.selspot, issh);
|
|
locallListener->scopeChangedvib(scopefp[sp], params->locallab.selspot, isvib);
|
|
locallListener->scopeChangedset(scopefp[sp], params->locallab.selspot, isset);
|
|
//params->locallab.spots.at(sp).colorscope = 30;
|
|
}
|
|
*/
|
|
// if (mainfp[sp] >= 0) {//minimize call to idle register
|
|
//used by Global fullimage.
|
|
locallListener->maiChanged(locallsetlc,params->locallab.selspot);
|
|
// }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete [] huerefp;
|
|
delete [] chromarefp;
|
|
delete [] lumarefp;
|
|
delete [] fabrefp;
|
|
delete [] mainfp;
|
|
delete [] scopefp;
|
|
ipf.lab2rgb(*nprevl, *oprevi, params->icm.workingProfile);
|
|
//*************************************************************
|
|
// end locallab
|
|
//*************************************************************
|
|
|
|
}
|
|
if ((todo & M_RGBCURVE) || (todo & M_CROP)) {
|
|
//complexCurve also calculated pre-curves histogram depending on crop
|
|
CurveFactory::complexCurve(params->toneCurve.expcomp, params->toneCurve.black / 65535.0,
|
|
params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh,
|
|
params->toneCurve.shcompr, params->toneCurve.brightness, params->toneCurve.contrast,
|
|
params->toneCurve.curve, params->toneCurve.curve2,
|
|
vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1);
|
|
|
|
CurveFactory::RGBCurve(params->rgbCurves.rcurve, rCurve, 1);
|
|
CurveFactory::RGBCurve(params->rgbCurves.gcurve, gCurve, 1);
|
|
CurveFactory::RGBCurve(params->rgbCurves.bcurve, bCurve, 1);
|
|
|
|
|
|
opautili = false;
|
|
|
|
if (params->colorToning.enabled) {
|
|
TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile);
|
|
double wp[3][3] = {
|
|
{wprof[0][0], wprof[0][1], wprof[0][2]},
|
|
{wprof[1][0], wprof[1][1], wprof[1][2]},
|
|
{wprof[2][0], wprof[2][1], wprof[2][2]}
|
|
};
|
|
params->colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili);
|
|
CurveFactory::diagonalCurve2Lut(params->colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16);
|
|
CurveFactory::diagonalCurve2Lut(params->colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16);
|
|
}
|
|
|
|
if (params->blackwhite.enabled) {
|
|
CurveFactory::curveBW(params->blackwhite.beforeCurve, params->blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1);
|
|
}
|
|
|
|
colourToningSatLimit = float (params->colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f;
|
|
colourToningSatLimitOpacity = 1.f - (float (params->colorToning.saturatedOpacity) / 100.f);
|
|
|
|
int satTH = 80;
|
|
int satPR = 30;
|
|
int indi = 0;
|
|
|
|
if (params->colorToning.enabled && params->colorToning.autosat && params->colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings
|
|
float moyS = 0.f;
|
|
float eqty = 0.f;
|
|
ipf.moyeqt(oprevi, moyS, eqty); //return image : mean saturation and standard dev of saturation
|
|
//printf("moy=%f ET=%f\n", moyS,eqty);
|
|
float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale
|
|
|
|
if (satp >= 0.92f) {
|
|
satp = 0.92f; //avoid values too high (out of gamut)
|
|
}
|
|
|
|
if (satp <= 0.15f) {
|
|
satp = 0.15f; //avoid too low values
|
|
}
|
|
|
|
//satTH=(int) 100.f*satp;
|
|
//satPR=(int) 100.f*(moyS-0.85f*eqty);//-0.85 sigma==>20% pixels with low saturation
|
|
colourToningSatLimit = 100.f * satp;
|
|
satTH = (int) 100.f * satp;
|
|
|
|
colourToningSatLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation
|
|
satPR = (int) 100.f * (moyS - 0.85f * eqty);
|
|
}
|
|
|
|
if (actListener && params->colorToning.enabled) {
|
|
if (params->blackwhite.enabled && params->colorToning.autosat) {
|
|
actListener->autoColorTonChanged(0, satTH, satPR); //hide sliders only if autosat
|
|
indi = 0;
|
|
} else {
|
|
if (params->colorToning.autosat) {
|
|
if (params->colorToning.method == "Lab") {
|
|
indi = 1;
|
|
} else if (params->colorToning.method == "RGBCurves") {
|
|
indi = 1;
|
|
} else if (params->colorToning.method == "RGBSliders") {
|
|
indi = 1;
|
|
} else if (params->colorToning.method == "Splico") {
|
|
indi = 2;
|
|
} else if (params->colorToning.method == "Splitlr") {
|
|
indi = 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if it's just crop we just need the histogram, no image updates
|
|
if (todo & M_RGBCURVE) {
|
|
//initialize rrm bbm ggm different from zero to avoid black screen in some cases
|
|
double rrm = 33.;
|
|
double ggm = 33.;
|
|
double bbm = 33.;
|
|
|
|
DCPProfileApplyState as;
|
|
DCPProfile *dcpProf = imgsrc->getDCP(params->icm, as);
|
|
|
|
ipf.rgbProc(oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params->toneCurve.saturation,
|
|
rCurve, gCurve, bCurve, colourToningSatLimit, colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, as, histToneCurve);
|
|
|
|
if (params->blackwhite.enabled && params->blackwhite.autoc && abwListener) {
|
|
if (settings->verbose) {
|
|
printf("ImProcCoordinator / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", static_cast<double>(bwAutoR), static_cast<double>(bwAutoG), static_cast<double>(bwAutoB));
|
|
}
|
|
|
|
abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm);
|
|
}
|
|
|
|
if (params->colorToning.enabled && params->colorToning.autosat && actListener) {
|
|
actListener->autoColorTonChanged(indi, (int) colourToningSatLimit, (int)colourToningSatLimitOpacity); //change sliders autosat
|
|
}
|
|
|
|
// correct GUI black and white with value
|
|
}
|
|
|
|
// ipf.Lab_Tile(oprevl, oprevl, scale);
|
|
|
|
// compute L channel histogram
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
}
|
|
|
|
// lhist16(32768);
|
|
if (todo & (M_LUMACURVE | M_CROP)) {
|
|
LUTu lhist16(32768);
|
|
lhist16.clear();
|
|
#ifdef _OPENMP
|
|
const int numThreads = min(max(pW * pH / (int)lhist16.getSize(), 1), omp_get_max_threads());
|
|
#pragma omp parallel num_threads(numThreads) if (numThreads>1)
|
|
#endif
|
|
{
|
|
LUTu lhist16thr(lhist16.getSize());
|
|
lhist16thr.clear();
|
|
#ifdef _OPENMP
|
|
#pragma omp for nowait
|
|
#endif
|
|
|
|
for (int x = 0; x < pH; x++)
|
|
for (int y = 0; y < pW; y++) {
|
|
int pos = (int)(oprevl->L[x][y]);
|
|
lhist16thr[pos]++;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp critical
|
|
#endif
|
|
lhist16 += lhist16thr;
|
|
}
|
|
#ifdef _OPENMP
|
|
static_cast<void>(numThreads); // to silence cppcheck warning
|
|
#endif
|
|
CurveFactory::complexLCurve(params->labCurve.brightness, params->labCurve.contrast, params->labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili);
|
|
}
|
|
|
|
if (todo & M_LUMACURVE) {
|
|
|
|
clcutili = CurveFactory::diagonalCurve2Lut(params->labCurve.clcurve, clcurve, scale == 1 ? 1 : 16);
|
|
|
|
CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params->labCurve.acurve, params->labCurve.bcurve, params->labCurve.cccurve,
|
|
params->labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16);
|
|
}
|
|
|
|
//scale = 1;
|
|
|
|
if ((todo & (M_LUMINANCE + M_COLOR)) || (todo & M_AUTOEXP)) {
|
|
nprevl->CopyFrom(oprevl);
|
|
histCCurve.clear();
|
|
histLCurve.clear();
|
|
|
|
if (params->colorToning.enabled && params->colorToning.method == "LabGrid") {
|
|
ipf.colorToningLabGrid(nprevl, 0, nprevl->W, 0, nprevl->H, false);
|
|
}
|
|
|
|
ipf.shadowsHighlights(nprevl, params->sh.enabled, params->sh.lab, params->sh.highlights, params->sh.shadows, params->sh.radius, scale, params->sh.htonalwidth, params->sh.stonalwidth);
|
|
|
|
if (params->localContrast.enabled) {
|
|
// Alberto's local contrast
|
|
ipf.localContrast(nprevl, nprevl->L, params->localContrast, false, scale);
|
|
}
|
|
|
|
ipf.chromiLuminanceCurve(nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve);
|
|
ipf.vibrance(nprevl, params->vibrance, params->toneCurve.hrenabled, params->icm.workingProfile);
|
|
ipf.labColorCorrectionRegions(nprevl);
|
|
|
|
// if ((params->colorappearance.enabled && !params->colorappearance.tonecie) || (!params->colorappearance.enabled)) {
|
|
if ((params->colorappearance.enabled && !params->colorappearance.tonecie) || (!cam02)) {
|
|
ipf.EPDToneMap(nprevl, 0, scale);
|
|
}
|
|
|
|
if (params->dirpyrequalizer.cbdlMethod == "aft") {
|
|
// if (((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled))) {
|
|
if (((params->colorappearance.enabled && !settings->autocielab) || (!cam02))) {
|
|
ipf.dirpyrequalizer(nprevl, scale);
|
|
}
|
|
}
|
|
|
|
wavcontlutili = CurveFactory::diagonalCurve2Lut(params->wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16);
|
|
|
|
if ((params->wavelet.enabled)) {
|
|
WaveletParams WaveParams = params->wavelet;
|
|
WaveParams.getCurves(wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL);
|
|
int kall = 0;
|
|
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(*nprevl, true);
|
|
}
|
|
|
|
if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") {
|
|
provis = params->wavelet.CLmethod;
|
|
params->wavelet.CLmethod = "all";
|
|
ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale);
|
|
unshar = new LabImage(*nprevl, true);
|
|
|
|
params->wavelet.CLmethod = provis;
|
|
|
|
WaveParams.expcontrast = false;
|
|
WaveParams.expchroma = false;
|
|
WaveParams.expedge = false;
|
|
WaveParams.expfinal = false;
|
|
WaveParams.exptoning = false;
|
|
WaveParams.expnoise = false;
|
|
}
|
|
|
|
ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale);
|
|
|
|
|
|
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(pW, pH);
|
|
array2D<float> guid(pW, pH);
|
|
Imagefloat *tmpImage = nullptr;
|
|
tmpImage = new Imagefloat(pW, pH);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < pH; ir++)
|
|
for (int jr = 0; jr < pW; 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 = nprevl->L[ir][jr];
|
|
float aa = nprevl->a[ir][jr];
|
|
float ba = nprevl->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 / scale * (0.5f + 0.8f * WaveParams.softrad);
|
|
// rtengine::guidedFilter(guid, ble, ble, blur, 0.001, multiTh);
|
|
rtengine::guidedFilter(guid, ble, ble, blur, epsil, false);
|
|
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < pH; ir++)
|
|
for (int jr = 0; jr < pW; 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);
|
|
nprevl->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 < pH; x++)
|
|
for (int y = 0; y < pW; y++) {
|
|
nprevl->L[x][y] = LIM((1.f + mL0) * (unshar->L[x][y]) + show * background - mL * indic * nprevl->L[x][y], 0.f, 32768.f);
|
|
nprevl->a[x][y] = (1.f + mC0) * (unshar->a[x][y]) - mC * indic * nprevl->a[x][y];
|
|
nprevl->b[x][y] = (1.f + mC0) * (unshar->b[x][y]) - mC * indic * nprevl->b[x][y];
|
|
}
|
|
|
|
delete unshar;
|
|
unshar = NULL;
|
|
|
|
|
|
/*
|
|
if (WaveParams.softrad > 0.f) {
|
|
array2D<float> ble(pW, pH);
|
|
array2D<float> guid(pW, pH);
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < pH; ir++)
|
|
for (int jr = 0; jr < pW; jr++) {
|
|
ble[ir][jr] = (nprevl->L[ir][jr] - provradius->L[ir][jr]) / 32768.f;
|
|
guid[ir][jr] = provradius->L[ir][jr] / 32768.f;
|
|
}
|
|
double epsilmax = 0.001;
|
|
double epsilmin = 0.0001;
|
|
double aepsil = (epsilmax - epsilmin) / 90.f;
|
|
double bepsil = epsilmax - 100.f * aepsil;
|
|
double epsil = aepsil * WaveParams.softrad + bepsil;
|
|
|
|
float blur = 10.f / scale * (0.001f + 0.8f * WaveParams.softrad);
|
|
// rtengine::guidedFilter(guid, ble, ble, blur, 0.001, multiTh);
|
|
rtengine::guidedFilter(guid, ble, ble, blur, epsil, false);
|
|
|
|
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int ir = 0; ir < pH; ir++)
|
|
for (int jr = 0; jr < pW; jr++) {
|
|
nprevl->L[ir][jr] = provradius->L[ir][jr] + 32768.f * ble[ir][jr];
|
|
}
|
|
}
|
|
*/
|
|
if (WaveParams.softrad > 0.f) {
|
|
|
|
delete provradius;
|
|
provradius = NULL;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ipf.softLight(nprevl, params->softlight);
|
|
|
|
if (params->icm.workingTRC != ColorManagementParams::WorkingTrc::NONE && params->icm.trcExp) {
|
|
const int GW = nprevl->W;
|
|
const int GH = nprevl->H;
|
|
std::unique_ptr<LabImage> provis;
|
|
const float pres = 0.01f * params->icm.preser;
|
|
if(params->icm.trcExp) {//local contrast
|
|
int level_hr = 7;
|
|
int maxlevpo = 9;
|
|
bool wavcurvecont = false;
|
|
WaveletParams WaveParams = params->wavelet;
|
|
ColorManagementParams Colparams = params->icm;
|
|
Colparams.getCurves(icmOpacityCurveWL);
|
|
ipf.complete_local_contrast(nprevl, nprevl, WaveParams,Colparams, icmOpacityCurveWL, scale, level_hr, maxlevpo, wavcurvecont);
|
|
}
|
|
|
|
if (pres > 0.f && params->icm.wprim != ColorManagementParams::Primaries::DEFAULT) {
|
|
provis.reset(new LabImage(GW, GH));
|
|
provis->CopyFrom(nprevl);
|
|
}
|
|
|
|
std::unique_ptr<Imagefloat> tmpImage1(new Imagefloat(GW, GH));
|
|
|
|
ipf.lab2rgb(*nprevl, *tmpImage1, params->icm.workingProfile);
|
|
|
|
const float gamtone = params->icm.wGamma;
|
|
const float slotone = params->icm.wSlope;
|
|
int illum = toUnderlying(params->icm.will);
|
|
const int prim = toUnderlying(params->icm.wprim);
|
|
|
|
Glib::ustring prof = params->icm.workingProfile;
|
|
|
|
cmsHTRANSFORM dummy = nullptr;
|
|
int ill = 0;
|
|
bool gamutcontrol = params->icm.gamut;
|
|
int catc = toUnderlying(params->icm.wcat);
|
|
int locprim = 0;
|
|
float rdx, rdy, grx, gry, blx, bly = 0.f;
|
|
float meanx, meany, meanxe, meanye = 0.f;
|
|
|
|
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, dummy, true, false, false, false);
|
|
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, dummy, 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);
|
|
}
|
|
ipf.toneEqualizer(tmpImage1.get(), params, prof, scale, 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;
|
|
}
|
|
|
|
ipf.toneEqualizer(tmpImage1.get(), params, prof, scale, false);
|
|
}
|
|
|
|
ipf.rgb2lab(*tmpImage1, *nprevl, params->icm.workingProfile);
|
|
|
|
//nprevl and provis
|
|
if (provis) {
|
|
ipf.preserv(nprevl, 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++) {
|
|
nprevl->a[x][y] = 0.f;
|
|
nprevl->b[x][y] = 0.f;
|
|
}
|
|
}
|
|
|
|
tmpImage1.reset();
|
|
|
|
if (prim == 14) {//pass red gre blue xy in function of area dats Ciexy
|
|
float redgraphx = params->icm.labgridcieALow;
|
|
float redgraphy = params->icm.labgridcieBLow;
|
|
float blugraphx = params->icm.labgridcieAHigh;
|
|
float blugraphy = params->icm.labgridcieBHigh;
|
|
float gregraphx = params->icm.labgridcieGx;
|
|
float gregraphy = params->icm.labgridcieGy;
|
|
float redxx = 0.55f * (redgraphx + 1.f) - 0.1f;
|
|
redxx = rtengine::LIM(redxx, 0.41f, 1.f);
|
|
float redyy = 0.55f * (redgraphy + 1.f) - 0.1f;
|
|
redyy = rtengine::LIM(redyy, 0.f, 0.7f);
|
|
float bluxx = 0.55f * (blugraphx + 1.f) - 0.1f;
|
|
bluxx = rtengine::LIM(bluxx, -0.1f, 0.5f);
|
|
float bluyy = 0.55f * (blugraphy + 1.f) - 0.1f;
|
|
bluyy = rtengine::LIM(bluyy, -0.1f, 0.5f);
|
|
|
|
float grexx = 0.55f * (gregraphx + 1.f) - 0.1f;
|
|
grexx = rtengine::LIM(grexx, -0.1f, 0.4f);
|
|
float greyy = 0.55f * (gregraphy + 1.f) - 0.1f;
|
|
greyy = rtengine::LIM(greyy, 0.5f, 1.f);
|
|
|
|
if (primListener) {
|
|
primListener->primChanged(redxx, redyy, bluxx, bluyy, grexx, greyy);
|
|
}
|
|
} else {//all other cases - pass Cie xy to update graph Ciexy
|
|
float r_x = params->icm.redx;
|
|
float r_y = params->icm.redy;
|
|
float b_x = params->icm.blux;
|
|
float b_y = params->icm.bluy;
|
|
float g_x = params->icm.grex;
|
|
float g_y = params->icm.grey;
|
|
//printf("rx=%f ry=%f \n", (double) r_x, (double) r_y);
|
|
float wx = 0.33f;
|
|
float wy = 0.33f;
|
|
|
|
switch (illum) {
|
|
case 1://D41
|
|
wx = 0.37798f;
|
|
wy = 0.38123f;
|
|
break;
|
|
|
|
case 2://D50
|
|
wx = 0.3457f;
|
|
wy = 0.3585f;
|
|
break;
|
|
|
|
case 3://D55
|
|
wx = 0.3324f;
|
|
wy = 0.3474f;
|
|
break;
|
|
|
|
case 4://D60
|
|
wx = 0.3217f;
|
|
wy = 0.3377f;
|
|
break;
|
|
|
|
case 5://D65
|
|
wx = 0.3127f;
|
|
wy = 0.3290f;
|
|
break;
|
|
|
|
case 6://D80
|
|
wx = 0.2937f;
|
|
wy = 0.3092f;
|
|
break;
|
|
|
|
case 7://D120
|
|
wx = 0.2697f;
|
|
wy = 0.2808f;
|
|
break;
|
|
|
|
case 8://stdA
|
|
wx = 0.4476f;
|
|
wy = 0.4074f;
|
|
break;
|
|
|
|
case 9://2000K
|
|
wx = 0.5266f;
|
|
wy = 0.4133f;
|
|
break;
|
|
|
|
case 10://1500K
|
|
wx = 0.5857f;
|
|
wy = 0.3932f;
|
|
break;
|
|
}
|
|
|
|
|
|
//move white point in GUI
|
|
double refin = params->icm.refi;
|
|
double arefi = (wy - meany) / (wx - meanx);
|
|
double brefi = wy - arefi * wx;
|
|
double scalrefi = meanx - wx;
|
|
wx = wx + scalrefi * refin;
|
|
wy = wx * arefi + brefi;
|
|
|
|
if (primListener) {
|
|
primListener->iprimChanged(r_x, r_y, b_x, b_y, g_x, g_y, wx, wy, meanx, meany);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (params->colorappearance.enabled) {
|
|
// L histo and Chroma histo for ciecam
|
|
// histogram will be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
lhist16CAM.clear();
|
|
lhist16CCAM.clear();
|
|
|
|
if (!params->colorappearance.datacie) {
|
|
for (int x = 0; x < pH; x++)
|
|
for (int y = 0; y < pW; y++) {
|
|
int pos = CLIP((int)(nprevl->L[x][y]));
|
|
int posc = CLIP((int)sqrt(nprevl->a[x][y] * nprevl->a[x][y] + nprevl->b[x][y] * nprevl->b[x][y]));
|
|
lhist16CAM[pos]++;
|
|
lhist16CCAM[posc]++;
|
|
}
|
|
}
|
|
|
|
CurveFactory::curveLightBrightColor(params->colorappearance.curve, params->colorappearance.curve2, params->colorappearance.curve3,
|
|
lhist16CAM, histLCAM, lhist16CCAM, histCCAM,
|
|
customColCurve1, customColCurve2, customColCurve3, 1);
|
|
|
|
const FramesMetaData* metaData = imgsrc->getMetaData();
|
|
float fnum = metaData->getFNumber(); // F number
|
|
float fiso = metaData->getISOSpeed() ; // ISO
|
|
float fspeed = metaData->getShutterSpeed() ; // Speed
|
|
double fcomp = metaData->getExpComp(); // Compensation +/-
|
|
double adap;
|
|
|
|
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.0, E_V - 3.0); // cd / m2
|
|
// end calculation adaptation scene luminosity
|
|
}
|
|
|
|
if (params->colorappearance.catmethod == "symg") { //force abolute luminance scenescene to 400 in symmetric
|
|
adap = 400.;
|
|
}
|
|
|
|
float d, dj, yb;
|
|
bool execsharp = false;
|
|
|
|
if (!ncie) {
|
|
ncie = new CieImage(pW, pH);
|
|
}
|
|
|
|
if (!CAMBrightCurveJ && (params->colorappearance.algo == "JC" || params->colorappearance.algo == "JS" || params->colorappearance.algo == "ALL")) {
|
|
CAMBrightCurveJ(32768, 0);
|
|
}
|
|
|
|
if (!CAMBrightCurveQ && (params->colorappearance.algo == "QM" || params->colorappearance.algo == "ALL")) {
|
|
CAMBrightCurveQ(32768, 0);
|
|
}
|
|
|
|
// Issue 2785, only float version of ciecam02 for navigator and pan background
|
|
CAMMean = NAN;
|
|
CAMBrightCurveJ.dirty = true;
|
|
CAMBrightCurveQ.dirty = true;
|
|
|
|
ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 0, scale, execsharp, d, dj, yb, 1);
|
|
|
|
//call listener
|
|
if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled) {
|
|
if (params->colorappearance.catmethod == "symg") { //force chromatic adaptation to 90 in symmetric
|
|
d = 0.9;
|
|
dj = 0.9;
|
|
}
|
|
|
|
acListener->autoCamChanged(100.* (double)d, 100.* (double)dj);
|
|
}
|
|
|
|
if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled) {
|
|
acListener->adapCamChanged(adap); //real value of adapt scene, force to 400 in symmetric
|
|
}
|
|
|
|
if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) {
|
|
if (params->colorappearance.catmethod == "symg") { //force yb scene to 18 in symmetric
|
|
yb = 18;
|
|
}
|
|
|
|
acListener->ybCamChanged((int) yb); //real value Yb scene
|
|
}
|
|
|
|
double tempsym = 5003.;
|
|
double greensym = 1.;
|
|
int wmodel = 0;//wmodel allows - arbitrary - choice of illuminant and temp with choice
|
|
|
|
if (params->colorappearance.wbmodel == "RawT") {
|
|
wmodel = 0;
|
|
} else if (params->colorappearance.wbmodel == "RawTCAT02") {
|
|
wmodel = 1;
|
|
} else if (params->colorappearance.wbmodel == "free") {
|
|
wmodel = 2;//force white balance in symmetric
|
|
}
|
|
|
|
if (params->colorappearance.catmethod == "symg" && wmodel == 2) {
|
|
tempsym = params->wb.temperature;//force white balance in symmetric
|
|
} else if(params->colorappearance.autotempout) {
|
|
if (params->colorappearance.illum == "iA") {//otherwise force illuminant source
|
|
tempsym = 2856.;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "i41") {
|
|
tempsym = 4100.;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "i50") {
|
|
tempsym = 5003.;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "i55") {
|
|
tempsym = 5503.;
|
|
} else if (params->colorappearance.illum == "i60") {
|
|
tempsym = 6000. ;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "i65") {
|
|
tempsym = 6504.;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "i75") {
|
|
tempsym = 7504.;
|
|
greensym = 1.;
|
|
} else if (params->colorappearance.illum == "ifree") {
|
|
tempsym = params->wb.temperature;//force white balance in symmetric
|
|
greensym = 1.;
|
|
}
|
|
} else {
|
|
tempsym = params->colorappearance.tempout;
|
|
greensym = params->colorappearance.greenout;
|
|
}
|
|
if (params->colorappearance.enabled && acListener) {
|
|
acListener->wbCamChanged(tempsym, greensym, params->colorappearance.autotempout); //real temp and tint.
|
|
}
|
|
|
|
} else {
|
|
// CIECAM is disabled, we free up its image buffer to save some space
|
|
if (ncie) {
|
|
delete ncie;
|
|
}
|
|
|
|
ncie = nullptr;
|
|
|
|
if (CAMBrightCurveJ) {
|
|
CAMBrightCurveJ.reset();
|
|
}
|
|
|
|
if (CAMBrightCurveQ) {
|
|
CAMBrightCurveQ.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
// if (todo & (M_AUTOEXP | M_RGBCURVE)) {
|
|
|
|
// Update the monitor color transform if necessary
|
|
if ((todo & M_MONITOR) || (lastOutputProfile != params->icm.outputProfile) || lastOutputIntent != params->icm.outputIntent || lastOutputBPC != params->icm.outputBPC) {
|
|
lastOutputProfile = params->icm.outputProfile;
|
|
lastOutputIntent = params->icm.outputIntent;
|
|
lastOutputBPC = params->icm.outputBPC;
|
|
ipf.updateColorProfiles(monitorProfile, monitorIntent, softProof, gamutCheck);
|
|
}
|
|
}
|
|
|
|
// process crop, if needed
|
|
for (size_t i = 0; i < crops.size(); i++)
|
|
if (crops[i]->hasListener() && (panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar) || (todo & (M_MONITOR | M_RGBCURVE | M_LUMACURVE)) || crops[i]->get_skip() == 1)) {
|
|
crops[i]->update(todo); // may call ourselves
|
|
}
|
|
|
|
if (panningRelatedChange || (todo & M_MONITOR)) {
|
|
if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) {
|
|
MyMutex::MyLock prevImgLock(previmg->getMutex());
|
|
|
|
try {
|
|
// Computing the preview image, i.e. converting from WCS->Monitor color space (soft-proofing disabled) or WCS->Printer profile->Monitor color space (soft-proofing enabled)
|
|
ipf.lab2monitorRgb(nprevl, previmg);
|
|
|
|
// Computing the internal image for analysis, i.e. conversion from WCS->Output profile
|
|
delete workimg;
|
|
workimg = nullptr;
|
|
|
|
workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params->icm);
|
|
} catch (std::exception&) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!resultValid) {
|
|
resultValid = true;
|
|
|
|
if (imageListener) {
|
|
imageListener->setImage(previmg, scale, params->crop);
|
|
}
|
|
}
|
|
|
|
if (imageListener)
|
|
// TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values
|
|
{
|
|
imageListener->imageReady(params->crop);
|
|
}
|
|
|
|
hist_lrgb_dirty = vectorscope_hc_dirty = vectorscope_hs_dirty = waveform_dirty = true;
|
|
|
|
if (hListener) {
|
|
if (hListener->updateHistogram()) {
|
|
updateLRGBHistograms();
|
|
}
|
|
|
|
if (hListener->updateVectorscopeHC()) {
|
|
updateVectorscopeHC();
|
|
}
|
|
|
|
if (hListener->updateVectorscopeHS()) {
|
|
updateVectorscopeHS();
|
|
}
|
|
|
|
if (hListener->updateWaveform()) {
|
|
updateWaveforms();
|
|
}
|
|
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
if (orig_prev != oprevi) {
|
|
delete oprevi;
|
|
oprevi = nullptr;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::setTweakOperator(TweakOperator *tOperator)
|
|
{
|
|
if (tOperator) {
|
|
tweakOperator = tOperator;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::unsetTweakOperator(TweakOperator *tOperator)
|
|
{
|
|
if (tOperator && tOperator == tweakOperator) {
|
|
tweakOperator = nullptr;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::freeAll()
|
|
{
|
|
|
|
if (allocated) {
|
|
if (spotprev && spotprev != oprevi) {
|
|
delete spotprev;
|
|
}
|
|
|
|
spotprev = nullptr;
|
|
|
|
if (orig_prev != oprevi) {
|
|
delete oprevi;
|
|
}
|
|
|
|
oprevi = nullptr;
|
|
delete orig_prev;
|
|
orig_prev = nullptr;
|
|
delete oprevl;
|
|
oprevl = nullptr;
|
|
delete nprevl;
|
|
nprevl = nullptr;
|
|
|
|
if (ncie) {
|
|
delete ncie;
|
|
}
|
|
|
|
ncie = nullptr;
|
|
|
|
if (imageListener) {
|
|
imageListener->delImage(previmg);
|
|
} else {
|
|
delete previmg;
|
|
}
|
|
|
|
delete workimg;
|
|
workimg = nullptr;
|
|
|
|
}
|
|
|
|
allocated = false;
|
|
}
|
|
|
|
void ImProcCoordinator::allocCache(Imagefloat* &imgfloat)
|
|
{
|
|
if (imgfloat == nullptr) {
|
|
imgfloat = new Imagefloat(pW, pH);
|
|
} else {
|
|
imgfloat->allocate(pW, pH);
|
|
}
|
|
}
|
|
|
|
/** @brief Handles image buffer (re)allocation and trigger sizeChanged of SizeListener[s]
|
|
* If the scale change, 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)
|
|
*
|
|
* @param prevscale New Preview's scale.
|
|
*/
|
|
void ImProcCoordinator::setScale(int prevscale)
|
|
{
|
|
|
|
tr = getCoarseBitMask(params->coarse);
|
|
|
|
int nW, nH;
|
|
imgsrc->getFullSize(fw, fh, tr);
|
|
|
|
prevscale++;
|
|
|
|
do {
|
|
prevscale--;
|
|
PreviewProps pp(0, 0, fw, fh, prevscale);
|
|
imgsrc->getSize(pp, nW, nH);
|
|
} while (nH < 400 && prevscale > 1 && (nW * nH < 1000000)); // actually hardcoded values, perhaps a better choice is possible
|
|
|
|
if (nW != pW || nH != pH) {
|
|
|
|
freeAll();
|
|
|
|
pW = nW;
|
|
pH = nH;
|
|
|
|
orig_prev = new Imagefloat(pW, pH);
|
|
oprevi = orig_prev;
|
|
oprevl = new LabImage(pW, pH);
|
|
nprevl = new LabImage(pW, pH);
|
|
|
|
//ncie is only used in ImProcCoordinator::updatePreviewImage, it will be allocated on first use and deleted if not used anymore
|
|
previmg = new Image8(pW, pH);
|
|
workimg = new Image8(pW, pH);
|
|
|
|
allocated = true;
|
|
}
|
|
|
|
scale = prevscale;
|
|
resultValid = false;
|
|
fullw = fw;
|
|
fullh = fh;
|
|
|
|
if (!sizeListeners.empty())
|
|
for (size_t i = 0; i < sizeListeners.size(); i++) {
|
|
sizeListeners[i]->sizeChanged(fullw, fullh, fw, fh);
|
|
}
|
|
}
|
|
|
|
|
|
void ImProcCoordinator::notifyHistogramChanged()
|
|
{
|
|
if (hListener) {
|
|
hListener->histogramChanged(
|
|
histRed,
|
|
histGreen,
|
|
histBlue,
|
|
histLuma,
|
|
histToneCurve,
|
|
histLCurve,
|
|
histCCurve,
|
|
histLCAM,
|
|
histCCAM,
|
|
histRedRaw,
|
|
histGreenRaw,
|
|
histBlueRaw,
|
|
histChroma,
|
|
histLRETI,
|
|
vectorscopeScale,
|
|
vectorscope_hc,
|
|
vectorscope_hs,
|
|
waveformScale,
|
|
waveformRed,
|
|
waveformGreen,
|
|
waveformBlue,
|
|
waveformLuma
|
|
);
|
|
}
|
|
}
|
|
|
|
bool ImProcCoordinator::updateLRGBHistograms()
|
|
{
|
|
|
|
if (!hist_lrgb_dirty) {
|
|
return false;
|
|
}
|
|
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel sections
|
|
#endif
|
|
{
|
|
#ifdef _OPENMP
|
|
#pragma omp section
|
|
#endif
|
|
{
|
|
histChroma.clear();
|
|
|
|
for (int i = y1; i < y2; i++)
|
|
for (int j = x1; j < x2; j++)
|
|
{
|
|
histChroma[(int)(sqrtf(SQR(nprevl->a[i][j]) + SQR(nprevl->b[i][j])) / 188.f)]++; //188 = 48000/256
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp section
|
|
#endif
|
|
{
|
|
histLuma.clear();
|
|
|
|
for (int i = y1; i < y2; i++)
|
|
for (int j = x1; j < x2; j++)
|
|
{
|
|
histLuma[(int)(nprevl->L[i][j] / 128.f)]++;
|
|
}
|
|
}
|
|
#ifdef _OPENMP
|
|
#pragma omp section
|
|
#endif
|
|
{
|
|
histRed.clear();
|
|
histGreen.clear();
|
|
histBlue.clear();
|
|
|
|
for (int i = y1; i < y2; i++)
|
|
{
|
|
int ofs = (i * pW + x1) * 3;
|
|
|
|
for (int j = x1; j < x2; j++) {
|
|
int r = workimg->data[ofs++];
|
|
int g = workimg->data[ofs++];
|
|
int b = workimg->data[ofs++];
|
|
|
|
histRed[r]++;
|
|
histGreen[g]++;
|
|
histBlue[b]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
hist_lrgb_dirty = false;
|
|
return true;
|
|
|
|
}
|
|
|
|
bool ImProcCoordinator::updateVectorscopeHC()
|
|
{
|
|
if (!workimg || !vectorscope_hc_dirty) {
|
|
return false;
|
|
}
|
|
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
|
|
constexpr int size = VECTORSCOPE_SIZE;
|
|
constexpr float norm_factor = size / (128.f * 655.36f);
|
|
vectorscope_hc.fill(0);
|
|
|
|
vectorscopeScale = (x2 - x1) * (y2 - y1);
|
|
|
|
const std::unique_ptr<float[]> a(new float[vectorscopeScale]);
|
|
const std::unique_ptr<float[]> b(new float[vectorscopeScale]);
|
|
const std::unique_ptr<float[]> L(new float[vectorscopeScale]);
|
|
ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm);
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
array2D<int> vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA);
|
|
#ifdef _OPENMP
|
|
#pragma omp for nowait
|
|
#endif
|
|
|
|
for (int i = y1; i < y2; ++i) {
|
|
for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) {
|
|
const int col = norm_factor * a[ofs_lab] + size / 2 + 0.5f;
|
|
const int row = norm_factor * b[ofs_lab] + size / 2 + 0.5f;
|
|
|
|
if (col >= 0 && col < size && row >= 0 && row < size) {
|
|
vectorscopeThr[row][col]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp critical
|
|
#endif
|
|
{
|
|
vectorscope_hc += vectorscopeThr;
|
|
}
|
|
}
|
|
|
|
vectorscope_hc_dirty = false;
|
|
return true;
|
|
}
|
|
|
|
bool ImProcCoordinator::updateVectorscopeHS()
|
|
{
|
|
if (!workimg || !vectorscope_hs_dirty) {
|
|
return false;
|
|
}
|
|
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
|
|
constexpr int size = VECTORSCOPE_SIZE;
|
|
vectorscope_hs.fill(0);
|
|
|
|
vectorscopeScale = (x2 - x1) * (y2 - y1);
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
array2D<int> vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA);
|
|
#ifdef _OPENMP
|
|
#pragma omp for nowait
|
|
#endif
|
|
|
|
for (int i = y1; i < y2; ++i) {
|
|
int ofs = (i * pW + x1) * 3;
|
|
|
|
for (int j = x1; j < x2; ++j) {
|
|
const float red = 257.f * workimg->data[ofs++];
|
|
const float green = 257.f * workimg->data[ofs++];
|
|
const float blue = 257.f * workimg->data[ofs++];
|
|
float h, s, l;
|
|
Color::rgb2hslfloat(red, green, blue, h, s, l);
|
|
const auto sincosval = xsincosf(2.f * RT_PI_F * h);
|
|
const int col = s * sincosval.y * (size / 2) + size / 2;
|
|
const int row = s * sincosval.x * (size / 2) + size / 2;
|
|
|
|
if (col >= 0 && col < size && row >= 0 && row < size) {
|
|
vectorscopeThr[row][col]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp critical
|
|
#endif
|
|
{
|
|
vectorscope_hs += vectorscopeThr;
|
|
}
|
|
}
|
|
|
|
vectorscope_hs_dirty = false;
|
|
return true;
|
|
}
|
|
|
|
bool ImProcCoordinator::updateWaveforms()
|
|
{
|
|
if (!workimg) {
|
|
// free memory
|
|
waveformRed.free();
|
|
waveformGreen.free();
|
|
waveformBlue.free();
|
|
waveformLuma.free();
|
|
return true;
|
|
}
|
|
|
|
if (!waveform_dirty) {
|
|
return false;
|
|
}
|
|
|
|
int x1, y1, x2, y2;
|
|
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
|
int waveform_width = waveformRed.getWidth();
|
|
|
|
if (waveform_width != x2 - x1) {
|
|
// Resize waveform arrays.
|
|
waveform_width = x2 - x1;
|
|
waveformRed(waveform_width, 256);
|
|
waveformGreen(waveform_width, 256);
|
|
waveformBlue(waveform_width, 256);
|
|
waveformLuma(waveform_width, 256);
|
|
}
|
|
|
|
// Start with zero.
|
|
waveformRed.fill(0);
|
|
waveformGreen.fill(0);
|
|
waveformBlue.fill(0);
|
|
waveformLuma.fill(0);
|
|
|
|
constexpr float luma_factor = 255.f / 32768.f;
|
|
|
|
for (int i = y1; i < y2; i++) {
|
|
int ofs = (i * pW + x1) * 3;
|
|
float* L_row = nprevl->L[i] + x1;
|
|
|
|
for (int j = 0; j < waveform_width; j++) {
|
|
waveformRed[workimg->data[ofs++]][j]++;
|
|
waveformGreen[workimg->data[ofs++]][j]++;
|
|
waveformBlue[workimg->data[ofs++]][j]++;
|
|
waveformLuma[LIM<int>(L_row[j] * luma_factor, 0, 255)][j]++;
|
|
}
|
|
}
|
|
|
|
waveformScale = y2 - y1;
|
|
waveform_dirty = false;
|
|
return true;
|
|
}
|
|
|
|
bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, StandardObserver observer, double tempBias)
|
|
{
|
|
|
|
if (imgsrc) {
|
|
if (lastAwbEqual != equal || lastAwbObserver != observer || lastAwbTempBias != tempBias || lastAwbauto != params->wb.method) {
|
|
// Issue 2500 MyMutex::MyLock lock(minit); // Also used in crop window
|
|
double rm, gm, bm;
|
|
params->wb.method = "autold";//same result as before multiple Auto WB
|
|
|
|
// imgsrc->getAutoWBMultipliers(rm, gm, bm);
|
|
double tempitc = 5000.;
|
|
double greenitc = 1.;
|
|
int dread = 0;
|
|
int bia = 0;
|
|
float temp0 = 5000.f;
|
|
float studgood = 1000.f;
|
|
int nocam = 0;
|
|
int kcam = 0;
|
|
float minchrom = 1000.f;
|
|
float delta = 0.f;
|
|
int kmin = 20;
|
|
float minhist = 10000000.f;
|
|
float maxhist = -1000.f;
|
|
double tempref, greenref;
|
|
bool extra = false;
|
|
imgsrc->getAutoWBMultipliersitc(extra, tempref, greenref, tempitc, greenitc, temp0, delta, bia, dread, kcam, nocam, studgood, minchrom, kmin, minhist, maxhist, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve);
|
|
|
|
if (rm != -1) {
|
|
autoWB.update(rm, gm, bm, equal, observer, tempBias);
|
|
lastAwbEqual = equal;
|
|
lastAwbObserver = observer;
|
|
lastAwbTempBias = tempBias;
|
|
lastAwbauto = params->wb.method;
|
|
} else {
|
|
lastAwbEqual = -1.;
|
|
lastAwbObserver = ColorTemp::DEFAULT_OBSERVER;
|
|
autoWB.useDefaults(equal, observer);
|
|
lastAwbauto = "";
|
|
lastAwbTempBias = 0.0;
|
|
}
|
|
}
|
|
|
|
temp = autoWB.getTemp();
|
|
green = autoWB.getGreen();
|
|
return true;
|
|
} else {
|
|
//temp = autoWB.getTemp();
|
|
temp = -1.0;
|
|
green = -1.0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::getCamWB(double& temp, double& green, StandardObserver observer)
|
|
{
|
|
|
|
if (imgsrc) {
|
|
const ColorTemp color_temp = imgsrc->getWB().convertObserver(observer);
|
|
temp = color_temp.getTemp();
|
|
green = color_temp.getGreen();
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double& tgreen)
|
|
{
|
|
|
|
ColorTemp ret;
|
|
|
|
{
|
|
MyMutex::MyLock lock(mProcessing);
|
|
std::vector<Coord2D> points, red, green, blue;
|
|
|
|
for (int i = y - rect; i <= y + rect; i++)
|
|
for (int j = x - rect; j <= x + rect; j++) {
|
|
points.push_back(Coord2D(j, i));
|
|
}
|
|
|
|
ipf.transCoord(fw, fh, points, red, green, blue);
|
|
|
|
int tr = getCoarseBitMask(params->coarse);
|
|
|
|
ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal, params->wb.observer);
|
|
currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer);
|
|
//double rr,gg,bb;
|
|
//currWB.getMultipliers(rr,gg,bb);
|
|
|
|
} // end of mutex lockong
|
|
|
|
if (ret.getTemp() > 0) {
|
|
temp = ret.getTemp();
|
|
tgreen = ret.getGreen();
|
|
} else {
|
|
temp = currWB.getTemp();
|
|
tgreen = currWB.getGreen();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImProcCoordinator::getAutoCrop(double ratio, int &x, int &y, int &w, int &h)
|
|
{
|
|
|
|
MyMutex::MyLock lock(mProcessing);
|
|
|
|
LensCorrection *pLCPMap = nullptr;
|
|
|
|
if (params->lensProf.useLcp() && imgsrc->getMetaData()->getFocalLen() > 0) {
|
|
const std::shared_ptr<LCPProfile> pLCPProf = LCPStore::getInstance()->getProfile(params->lensProf.lcpFile);
|
|
|
|
if (pLCPProf) pLCPMap = new LCPMapper(pLCPProf, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(),
|
|
0, false, params->lensProf.useDist, fullw, fullh, params->coarse, imgsrc->getRotateDegree());
|
|
}
|
|
|
|
double fillscale = ipf.getTransformAutoFill(fullw, fullh, pLCPMap);
|
|
|
|
if (ratio > 0) {
|
|
w = fullw * fillscale;
|
|
h = w / ratio;
|
|
|
|
if (h > fullh * fillscale) {
|
|
h = fullh * fillscale;
|
|
w = h * ratio;
|
|
}
|
|
} else {
|
|
w = fullw * fillscale;
|
|
h = fullh * fillscale;
|
|
}
|
|
|
|
x = (fullw - w) / 2;
|
|
y = (fullh - h) / 2;
|
|
}
|
|
|
|
void ImProcCoordinator::setMonitorProfile(const Glib::ustring& profile, RenderingIntent intent)
|
|
{
|
|
monitorProfile = profile;
|
|
monitorIntent = intent;
|
|
}
|
|
|
|
void ImProcCoordinator::getMonitorProfile(Glib::ustring& profile, RenderingIntent& intent) const
|
|
{
|
|
profile = monitorProfile;
|
|
intent = monitorIntent;
|
|
}
|
|
|
|
void ImProcCoordinator::setSoftProofing(bool softProof, bool gamutCheck)
|
|
{
|
|
this->softProof = softProof;
|
|
this->gamutCheck = gamutCheck;
|
|
}
|
|
|
|
void ImProcCoordinator::getSoftProofing(bool &softProof, bool &gamutCheck)
|
|
{
|
|
softProof = this->softProof;
|
|
gamutCheck = this->gamutCheck;
|
|
}
|
|
|
|
ProcEvent ImProcCoordinator::setSharpMask(bool sharpMask)
|
|
{
|
|
if (this->sharpMask != sharpMask) {
|
|
sharpMaskChanged = true;
|
|
this->sharpMask = sharpMask;
|
|
return params->pdsharpening.enabled ? rtengine::EvPdShrMaskToggled : rtengine::EvShrEnabled;
|
|
} else {
|
|
sharpMaskChanged = false;
|
|
return rtengine::EvShrEnabled;
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool apply_wb)
|
|
{
|
|
|
|
MyMutex::MyLock lock(mProcessing);
|
|
|
|
int fW, fH;
|
|
std::unique_ptr<ProcParams> validParams(new ProcParams());
|
|
getParams(validParams.get());
|
|
|
|
int tr = getCoarseBitMask(validParams->coarse);
|
|
|
|
imgsrc->getFullSize(fW, fH, tr);
|
|
PreviewProps pp(0, 0, fW, fH, 1);
|
|
ProcParams ppar = *validParams;
|
|
ppar.toneCurve.hrenabled = false;
|
|
ppar.icm.inputProfile = "(none)";
|
|
Imagefloat* im = new Imagefloat(fW, fH);
|
|
float reddeha = 0.f;
|
|
float greendeha = 0.f;
|
|
float bluedeha = 0.f;
|
|
imgsrc->preprocess(ppar.raw, ppar.lensProf, ppar.coarse,reddeha, greendeha, bluedeha, true);
|
|
double dummy = 0.0;
|
|
imgsrc->demosaic(ppar.raw, false, dummy);
|
|
ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method, validParams->wb.observer);
|
|
|
|
if (validParams->wb.method == "Camera") {
|
|
currWB = imgsrc->getWB();
|
|
} else if (validParams->wb.method == "autold") {
|
|
if (lastAwbEqual != validParams->wb.equal || lastAwbObserver != validParams->wb.observer || lastAwbTempBias != validParams->wb.tempBias) {
|
|
double rm, gm, bm;
|
|
imgsrc->getAutoWBMultipliers(rm, gm, bm);
|
|
|
|
if (rm != -1.) {
|
|
autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.observer, validParams->wb.tempBias);
|
|
lastAwbEqual = validParams->wb.equal;
|
|
lastAwbObserver = validParams->wb.observer;
|
|
lastAwbTempBias = validParams->wb.tempBias;
|
|
} else {
|
|
lastAwbEqual = -1.;
|
|
lastAwbObserver = ColorTemp::DEFAULT_OBSERVER;
|
|
lastAwbTempBias = 0.0;
|
|
autoWB.useDefaults(validParams->wb.equal, validParams->wb.observer);
|
|
}
|
|
}
|
|
|
|
currWB = autoWB;
|
|
}
|
|
|
|
if (!apply_wb) {
|
|
currWB = ColorTemp(); // = no white balance
|
|
}
|
|
|
|
imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw);
|
|
ImProcFunctions ipf(&ppar, true);
|
|
|
|
if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) {
|
|
Imagefloat* trImg = new Imagefloat(fW, fH);
|
|
ipf.transform(im, trImg, 0, 0, 0, 0, fW, fH, fW, fH,
|
|
imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
|
|
delete im;
|
|
im = trImg;
|
|
}
|
|
|
|
if (validParams->crop.enabled) {
|
|
Imagefloat *tmpim = new Imagefloat(validParams->crop.w, validParams->crop.h);
|
|
int cx = validParams->crop.x;
|
|
int cy = validParams->crop.y;
|
|
int cw = validParams->crop.w;
|
|
int ch = validParams->crop.h;
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int i = cy; i < cy + ch; i++) {
|
|
for (int j = cx; j < cx + cw; j++) {
|
|
tmpim->r(i - cy, j - cx) = im->r(i, j);
|
|
tmpim->g(i - cy, j - cx) = im->g(i, j);
|
|
tmpim->b(i - cy, j - cx) = im->b(i, j);
|
|
}
|
|
}
|
|
|
|
delete im;
|
|
im = tmpim;
|
|
}
|
|
|
|
// image may contain out of range samples, clip them to avoid wrap-arounds
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
|
|
for (int i = 0; i < im->getHeight(); i++) {
|
|
for (int j = 0; j < im->getWidth(); j++) {
|
|
im->r(i, j) = CLIP(im->r(i, j));
|
|
im->g(i, j) = CLIP(im->g(i, j));
|
|
im->b(i, j) = CLIP(im->b(i, j));
|
|
}
|
|
}
|
|
|
|
int imw, imh;
|
|
double tmpScale = ipf.resizeScale(validParams.get(), fW, fH, imw, imh);
|
|
|
|
if (tmpScale != 1.0) {
|
|
Imagefloat* tempImage = new Imagefloat(imw, imh);
|
|
ipf.resize(im, tempImage, tmpScale);
|
|
delete im;
|
|
im = tempImage;
|
|
}
|
|
|
|
im->setMetadata(Exiv2Metadata(imgsrc->getFileName(), false));
|
|
|
|
im->saveTIFF(fname, 16, false, true);
|
|
delete im;
|
|
|
|
if (plistener) {
|
|
plistener->setProgressState(false);
|
|
}
|
|
|
|
//im->saveJPEG (fname, 85);
|
|
}
|
|
|
|
void ImProcCoordinator::stopProcessing()
|
|
{
|
|
|
|
updaterThreadStart.lock();
|
|
|
|
if (updaterRunning && thread) {
|
|
changeSinceLast = 0;
|
|
thread->join();
|
|
}
|
|
|
|
updaterThreadStart.unlock();
|
|
}
|
|
|
|
void ImProcCoordinator::startProcessing()
|
|
{
|
|
|
|
#undef THREAD_PRIORITY_NORMAL
|
|
|
|
if (!destroying) {
|
|
if (!updaterRunning) {
|
|
updaterThreadStart.lock();
|
|
thread = nullptr;
|
|
updaterRunning = true;
|
|
updaterThreadStart.unlock();
|
|
|
|
//batchThread->yield(); //the running batch should wait other threads to avoid conflict
|
|
|
|
thread = Glib::Thread::create(sigc::mem_fun(*this, &ImProcCoordinator::process), 0, true, true, Glib::THREAD_PRIORITY_NORMAL);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::startProcessing(int changeCode)
|
|
{
|
|
paramsUpdateMutex.lock();
|
|
changeSinceLast |= changeCode;
|
|
paramsUpdateMutex.unlock();
|
|
|
|
startProcessing();
|
|
}
|
|
|
|
void ImProcCoordinator::process()
|
|
{
|
|
if (plistener) {
|
|
plistener->setProgressState(true);
|
|
}
|
|
|
|
paramsUpdateMutex.lock();
|
|
|
|
while (changeSinceLast) {
|
|
const bool panningRelatedChange =
|
|
params->toneCurve.isPanningRelatedChange(nextParams->toneCurve)
|
|
|| params->labCurve != nextParams->labCurve
|
|
|| params->locallab != nextParams->locallab
|
|
|| params->localContrast != nextParams->localContrast
|
|
|| params->rgbCurves != nextParams->rgbCurves
|
|
|| params->colorToning != nextParams->colorToning
|
|
|| params->vibrance != nextParams->vibrance
|
|
// || params->wb != nextParams->wb //isPanningRelatedChange(nextParams->wb)
|
|
|| params->wb.isPanningRelatedChange(nextParams->wb)
|
|
|| params->colorappearance != nextParams->colorappearance
|
|
|| params->epd != nextParams->epd
|
|
|| params->fattal != nextParams->fattal
|
|
|| params->sh != nextParams->sh
|
|
|| params->toneEqualizer != nextParams->toneEqualizer
|
|
|| params->crop != nextParams->crop
|
|
|| params->coarse != nextParams->coarse
|
|
|| params->commonTrans != nextParams->commonTrans
|
|
|| params->rotate != nextParams->rotate
|
|
|| params->distortion != nextParams->distortion
|
|
|| params->lensProf != nextParams->lensProf
|
|
|| params->perspective != nextParams->perspective
|
|
|| params->gradient != nextParams->gradient
|
|
|| params->pcvignette != nextParams->pcvignette
|
|
|| params->cacorrection != nextParams->cacorrection
|
|
|| params->vignetting != nextParams->vignetting
|
|
|| params->chmixer != nextParams->chmixer
|
|
|| params->blackwhite != nextParams->blackwhite
|
|
|| params->icm != nextParams->icm
|
|
|| params->hsvequalizer != nextParams->hsvequalizer
|
|
|| params->filmSimulation != nextParams->filmSimulation
|
|
|| params->softlight != nextParams->softlight
|
|
|| params->raw != nextParams->raw
|
|
|| params->retinex != nextParams->retinex
|
|
|| params->wavelet != nextParams->wavelet
|
|
|| params->dirpyrequalizer != nextParams->dirpyrequalizer
|
|
|| params->dehaze != nextParams->dehaze
|
|
|| params->pdsharpening != nextParams->pdsharpening
|
|
|| params->filmNegative != nextParams->filmNegative
|
|
|| params->spot.enabled != nextParams->spot.enabled
|
|
|| sharpMaskChanged;
|
|
|
|
sharpMaskChanged = false;
|
|
*params = *nextParams;
|
|
int change = changeSinceLast;
|
|
changeSinceLast = 0;
|
|
|
|
if (tweakOperator) {
|
|
// TWEAKING THE PROCPARAMS FOR THE SPOT ADJUSTMENT MODE
|
|
backupParams();
|
|
tweakOperator->tweakParams(*params);
|
|
} else if (paramsBackup) {
|
|
paramsBackup.release();
|
|
}
|
|
|
|
paramsUpdateMutex.unlock();
|
|
|
|
// M_VOID means no update, and is a bit higher that the rest
|
|
if (change & (~M_VOID)) {
|
|
updatePreviewImage(change, panningRelatedChange);
|
|
}
|
|
|
|
paramsUpdateMutex.lock();
|
|
}
|
|
|
|
paramsUpdateMutex.unlock();
|
|
updaterRunning = false;
|
|
|
|
if (plistener) {
|
|
plistener->setProgressState(false);
|
|
}
|
|
}
|
|
|
|
ProcParams* ImProcCoordinator::beginUpdateParams()
|
|
{
|
|
paramsUpdateMutex.lock();
|
|
|
|
return nextParams.get();
|
|
}
|
|
|
|
void ImProcCoordinator::endUpdateParams(ProcEvent change)
|
|
{
|
|
int action = RefreshMapper::getInstance()->getAction(change);
|
|
endUpdateParams(action);
|
|
}
|
|
|
|
void ImProcCoordinator::endUpdateParams(int changeFlags)
|
|
{
|
|
changeSinceLast |= changeFlags;
|
|
|
|
paramsUpdateMutex.unlock();
|
|
startProcessing();
|
|
}
|
|
|
|
bool ImProcCoordinator::getHighQualComputed()
|
|
{
|
|
// this function may only be called from detail windows
|
|
if (!highQualityComputed) {
|
|
if (options.prevdemo == PD_Sidecar) {
|
|
// we already have high quality preview
|
|
setHighQualComputed();
|
|
} else {
|
|
for (size_t i = 0; i < crops.size() - 1; ++i) { // -1, because last entry is the freshly created detail window
|
|
if (crops[i]->get_skip() == 1) { // there is at least one crop with skip == 1 => we already have high quality preview
|
|
setHighQualComputed();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return highQualityComputed;
|
|
}
|
|
|
|
void ImProcCoordinator::setHighQualComputed()
|
|
{
|
|
highQualityComputed = true;
|
|
}
|
|
|
|
void ImProcCoordinator::requestUpdateWaveform()
|
|
{
|
|
if (!hListener) {
|
|
return;
|
|
}
|
|
|
|
bool updated = updateWaveforms();
|
|
|
|
if (updated) {
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::requestUpdateHistogram()
|
|
{
|
|
if (!hListener) {
|
|
return;
|
|
}
|
|
|
|
bool updated = updateLRGBHistograms();
|
|
|
|
if (updated) {
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::requestUpdateHistogramRaw()
|
|
{
|
|
if (!hListener) {
|
|
return;
|
|
}
|
|
|
|
// Don't need to actually update histogram because it is always
|
|
// up-to-date.
|
|
if (hist_raw_dirty) {
|
|
hist_raw_dirty = false;
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::requestUpdateVectorscopeHC()
|
|
{
|
|
if (!hListener) {
|
|
return;
|
|
}
|
|
|
|
bool updated = updateVectorscopeHC();
|
|
|
|
if (updated) {
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
void ImProcCoordinator::requestUpdateVectorscopeHS()
|
|
{
|
|
if (!hListener) {
|
|
return;
|
|
}
|
|
|
|
bool updated = updateVectorscopeHS();
|
|
|
|
if (updated) {
|
|
notifyHistogramChanged();
|
|
}
|
|
}
|
|
|
|
}
|