2769 lines
102 KiB
C++
2769 lines
102 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "rtengine.h"
|
|
#include "colortemp.h"
|
|
#include "imagesource.h"
|
|
#include "improcfun.h"
|
|
#include "curves.h"
|
|
#include "iccstore.h"
|
|
#include "clutstore.h"
|
|
#include "processingjob.h"
|
|
#include <glibmm.h>
|
|
#include "../rtgui/options.h"
|
|
#include "rawimagesource.h"
|
|
#include "../rtgui/multilangmgr.h"
|
|
#include "mytime.h"
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include "../rtgui/md5helper.h"
|
|
#include "../rtgui/thresholdselector.h"
|
|
|
|
|
|
#undef THREAD_PRIORITY_NORMAL
|
|
|
|
namespace rtengine
|
|
{
|
|
extern const Settings* settings;
|
|
|
|
namespace
|
|
{
|
|
|
|
template <typename T>
|
|
void adjust_radius(const T &default_param, double scale_factor, T ¶m)
|
|
{
|
|
const double delta = (param - default_param) * scale_factor;
|
|
param = default_param + delta;
|
|
}
|
|
|
|
|
|
class ImageProcessor
|
|
{
|
|
public:
|
|
ImageProcessor(ProcessingJob* pjob, int& errorCode,
|
|
ProgressListener* pl, bool tunnelMetaData, bool flush):
|
|
job(static_cast<ProcessingJobImpl*>(pjob)),
|
|
errorCode(errorCode),
|
|
pl(pl),
|
|
tunnelMetaData(tunnelMetaData),
|
|
flush(flush),
|
|
// internal state
|
|
ipf_p(nullptr),
|
|
ii(nullptr),
|
|
imgsrc(nullptr),
|
|
fw(-1),
|
|
fh(-1),
|
|
pp(0, 0, 0, 0, 0)
|
|
{
|
|
}
|
|
|
|
Image16 *operator()()
|
|
{
|
|
if (!job->fast) {
|
|
return normal_pipeline();
|
|
} else {
|
|
return fast_pipeline();
|
|
}
|
|
}
|
|
|
|
private:
|
|
Image16 *normal_pipeline()
|
|
{
|
|
if (!stage_init()) {
|
|
return nullptr;
|
|
}
|
|
|
|
stage_denoise();
|
|
stage_transform();
|
|
return stage_finish();
|
|
}
|
|
|
|
Image16 *fast_pipeline()
|
|
{
|
|
if (!job->pparams.resize.enabled) {
|
|
return normal_pipeline();
|
|
}
|
|
|
|
pl = nullptr;
|
|
|
|
if (!stage_init()) {
|
|
return nullptr;
|
|
}
|
|
|
|
stage_transform();
|
|
stage_early_resize();
|
|
stage_denoise();
|
|
return stage_finish();
|
|
}
|
|
|
|
bool stage_init()
|
|
{
|
|
errorCode = 0;
|
|
|
|
if (pl) {
|
|
pl->setProgressStr("PROGRESSBAR_PROCESSING");
|
|
pl->setProgress(0.0);
|
|
}
|
|
|
|
ii = job->initialImage;
|
|
|
|
if (!ii) {
|
|
ii = InitialImage::load(job->fname, job->isRaw, &errorCode);
|
|
|
|
if (errorCode) {
|
|
delete job;
|
|
return false; //return nullptr;
|
|
}
|
|
}
|
|
|
|
procparams::ProcParams& params = job->pparams;
|
|
|
|
// acquire image from imagesource
|
|
imgsrc = ii->getImageSource();
|
|
|
|
tr = getCoarseBitMask(params.coarse);
|
|
imgsrc->getFullSize(fw, fh, tr);
|
|
|
|
// check the crop params
|
|
if (params.crop.x > fw || params.crop.y > fh) {
|
|
// the crop is completely out of the image, so we disable the crop
|
|
params.crop.enabled = false;
|
|
// and we set the values to the defaults
|
|
params.crop.x = 0;
|
|
params.crop.y = 0;
|
|
params.crop.w = fw;
|
|
params.crop.h = fh;
|
|
} else {
|
|
if (params.crop.x < 0) {
|
|
params.crop.x = 0;
|
|
}
|
|
|
|
if (params.crop.y < 0) {
|
|
params.crop.y = 0;
|
|
}
|
|
|
|
if ((params.crop.x + params.crop.w) > fw) {
|
|
// crop overflow in the width dimension ; we trim it
|
|
params.crop.w = fw - params.crop.x;
|
|
}
|
|
|
|
if ((params.crop.y + params.crop.h) > fh) {
|
|
// crop overflow in the height dimension ; we trim it
|
|
params.crop.h = fh - params.crop.y;
|
|
}
|
|
}
|
|
|
|
// MyTime t1,t2;
|
|
// t1.set();
|
|
|
|
ipf_p.reset(new ImProcFunctions(¶ms, true));
|
|
ImProcFunctions &ipf = * (ipf_p.get());
|
|
|
|
pp = PreviewProps(0, 0, fw, fh, 1);
|
|
imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum);
|
|
imgsrc->preprocess(params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled);
|
|
|
|
if (params.toneCurve.autoexp) {// this enabled HLRecovery
|
|
LUTu histRedRaw(256), histGreenRaw(256), histBlueRaw(256);
|
|
imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw);
|
|
|
|
if (ToneCurveParams::HLReconstructionNecessary(histRedRaw, histGreenRaw, histBlueRaw) && !params.toneCurve.hrenabled) {
|
|
params.toneCurve.hrenabled = true;
|
|
// WARNING: Highlight Reconstruction is being forced 'on', should we force a method here too?
|
|
}
|
|
}
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.20);
|
|
}
|
|
|
|
imgsrc->demosaic(params.raw);
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.30);
|
|
}
|
|
|
|
if (params.retinex.enabled) { //enabled Retinex
|
|
LUTf cdcurve(65536, 0);
|
|
LUTf mapcurve(65536, 0);
|
|
LUTu dummy;
|
|
RetinextransmissionCurve dehatransmissionCurve;
|
|
RetinexgaintransmissionCurve dehagaintransmissionCurve;
|
|
bool dehacontlutili = false;
|
|
bool mapcontlutili = false;
|
|
bool useHsl = false;
|
|
// multi_array2D<float, 3> conversionBuffer(1, 1);
|
|
multi_array2D<float, 4> conversionBuffer(1, 1);
|
|
imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy);
|
|
imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy);
|
|
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, dummy);
|
|
}
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.40);
|
|
}
|
|
|
|
imgsrc->HLRecovery_Global(params.toneCurve);
|
|
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.45);
|
|
}
|
|
|
|
// set the color temperature
|
|
currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method);
|
|
|
|
if (!params.wb.enabled) {
|
|
currWB = ColorTemp();
|
|
} else if (params.wb.method == "Camera") {
|
|
currWB = imgsrc->getWB();
|
|
} else if (params.wb.method == "Auto") {
|
|
double rm, gm, bm;
|
|
imgsrc->getAutoWBMultipliers(rm, gm, bm);
|
|
currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias);
|
|
}
|
|
|
|
calclum = nullptr ;
|
|
params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve);
|
|
autoNR = (float) settings->nrauto;//
|
|
autoNRmax = (float) settings->nrautomax;//
|
|
|
|
if (settings->leveldnti == 0) {
|
|
tilesize = 1024;
|
|
overlap = 128;
|
|
}
|
|
|
|
if (settings->leveldnti == 1) {
|
|
tilesize = 768;
|
|
overlap = 96;
|
|
}
|
|
|
|
// const int tilesize = 768;
|
|
// const int overlap = 96;
|
|
int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip;
|
|
ipf.Tile_calc(tilesize, overlap, 2, fw, fh, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip);
|
|
int nbtl = numtiles_W * numtiles_H;
|
|
|
|
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) {
|
|
nbtl = 9;
|
|
}
|
|
|
|
ch_M = new float [nbtl];//allocate memory
|
|
max_r = new float [nbtl];
|
|
max_b = new float [nbtl];
|
|
min_b = new float [9];
|
|
min_r = new float [9];
|
|
lumL = new float [nbtl];
|
|
chromC = new float [nbtl];
|
|
ry = new float [nbtl];
|
|
sk = new float [nbtl];
|
|
pcsk = new float [nbtl];
|
|
|
|
// printf("expert=%d\n",settings->leveldnautsimpl);
|
|
if (settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PON") {
|
|
MyTime t1pone, t2pone;
|
|
t1pone.set();
|
|
int crW = 100; // settings->leveldnv == 0
|
|
int crH = 100; // settings->leveldnv == 0
|
|
|
|
if (settings->leveldnv == 1) {
|
|
crW = 250;
|
|
crH = 250;
|
|
}
|
|
|
|
if (settings->leveldnv == 2) {
|
|
crW = int (tileWskip / 2);
|
|
crH = int (tileHskip / 2);
|
|
}
|
|
|
|
// if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview
|
|
if (settings->leveldnv == 3) {
|
|
crW = tileWskip - 10;
|
|
crH = tileHskip - 10;
|
|
}
|
|
|
|
float lowdenoise = 1.f;
|
|
int levaut = settings->leveldnaut;
|
|
|
|
if (levaut == 1) { //Standard
|
|
lowdenoise = 0.7f;
|
|
}
|
|
|
|
// int crW=tileWskip-10;//crop noise width
|
|
// int crH=tileHskip-10;//crop noise height
|
|
// Imagefloat *origCropPart;//init auto noise
|
|
// origCropPart = new Imagefloat (crW, crH);//allocate memory
|
|
if (params.dirpyrDenoise.enabled) {//evaluate Noise
|
|
LUTf gamcurve(65536, 0);
|
|
float gam, gamthresh, gamslope;
|
|
ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
|
|
#pragma omp parallel
|
|
{
|
|
Imagefloat *origCropPart;//init auto noise
|
|
origCropPart = new Imagefloat(crW, crH); //allocate memory
|
|
Imagefloat *provicalc = new Imagefloat((crW + 1) / 2, (crH + 1) / 2); //for denoise curves
|
|
int skipP = 1;
|
|
#pragma omp for schedule(dynamic) collapse(2) nowait
|
|
|
|
for (int wcr = 0; wcr < numtiles_W; wcr++) {
|
|
for (int hcr = 0; hcr < numtiles_H; hcr++) {
|
|
int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f;
|
|
int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f;
|
|
PreviewProps ppP(beg_tileW, beg_tileH, crW, crH, skipP);
|
|
imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
|
|
//baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve);
|
|
|
|
// we only need image reduced to 1/4 here
|
|
for (int ii = 0; ii < crH; ii += 2) {
|
|
for (int jj = 0; jj < crW; jj += 2) {
|
|
provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj);
|
|
provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj);
|
|
provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
imgsrc->convertColorSpace(provicalc, params.icm, currWB); //for denoise luminance curve
|
|
float maxr = 0.f;
|
|
float maxb = 0.f;
|
|
float pondcorrec = 1.0f;
|
|
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
|
int Nb;
|
|
chaut = 0.f;
|
|
redaut = 0.f;
|
|
blueaut = 0.f;
|
|
maxredaut = 0.f;
|
|
maxblueaut = 0.f;
|
|
chromina = 0.f;
|
|
sigma = 0.f;
|
|
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
|
float multip = 1.f;
|
|
float adjustr = 1.f;
|
|
|
|
if (params.icm.working == "ProPhoto") {
|
|
adjustr = 1.f; //
|
|
} else if (params.icm.working == "Adobe RGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.working == "sRGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.working == "WideGamut") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.working == "Rec2020") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.working == "Beta RGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.working == "BestRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.working == "BruceRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
}
|
|
|
|
if (!imgsrc->isRAW()) {
|
|
multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1
|
|
}
|
|
|
|
float maxmax = max(maxredaut, maxblueaut);
|
|
float delta;
|
|
int mode = 2;
|
|
int lissage = settings->leveldnliss;
|
|
ipf.calcautodn_info(chaut, delta, Nb, levaut, maxmax, lumema, chromina, mode, lissage, redyel, skinc, nsknc);
|
|
|
|
// printf("PROCESS cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f sigL=%f\n",chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema, sigma_L);
|
|
if (maxredaut > maxblueaut) {
|
|
maxr = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
|
|
if (minblueaut <= minredaut && minblueaut < chaut) {
|
|
maxb = (-chaut + minblueaut) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
}
|
|
} else {
|
|
maxb = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
|
|
if (minredaut <= minblueaut && minredaut < chaut) {
|
|
maxr = (-chaut + minredaut) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
}
|
|
}//maxb mxr - empirical evaluation red / blue
|
|
|
|
ch_M[hcr * numtiles_W + wcr] = pondcorrec * chaut / (autoNR * multip * adjustr * lowdenoise);
|
|
max_r[hcr * numtiles_W + wcr] = pondcorrec * maxr;
|
|
max_b[hcr * numtiles_W + wcr] = pondcorrec * maxb;
|
|
lumL[hcr * numtiles_W + wcr] = lumema;
|
|
chromC[hcr * numtiles_W + wcr] = chromina;
|
|
ry[hcr * numtiles_W + wcr] = redyel;
|
|
sk[hcr * numtiles_W + wcr] = skinc;
|
|
pcsk[hcr * numtiles_W + wcr] = nsknc;
|
|
|
|
}
|
|
}
|
|
|
|
delete provicalc;
|
|
delete origCropPart;
|
|
}
|
|
|
|
int liss = settings->leveldnliss; //smooth result around mean
|
|
|
|
if (liss == 2 || liss == 3) {
|
|
// I smooth only mean and not delta (max)
|
|
float nchm = 0.f;
|
|
float koef = 0.4f; //between 0.1 to 0.9
|
|
|
|
if (liss == 3) {
|
|
koef = 0.0f; //quasi auto for mean Ch
|
|
}
|
|
|
|
for (int wcr = 0; wcr < numtiles_W; wcr++) {
|
|
for (int hcr = 0; hcr < numtiles_H; hcr++) {
|
|
nchm += ch_M[hcr * numtiles_W + wcr];
|
|
}
|
|
}
|
|
|
|
nchm /= (numtiles_H * numtiles_W);
|
|
|
|
for (int wcr = 0; wcr < numtiles_W; wcr++) {
|
|
for (int hcr = 0; hcr < numtiles_H; hcr++) {
|
|
ch_M[hcr * numtiles_W + wcr] = nchm + (ch_M[hcr * numtiles_W + wcr] - nchm) * koef;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (liss == 3) { //same as auto but with much cells
|
|
float MaxR = 0.f;
|
|
float MaxB = 0.f;
|
|
float MaxRMoy = 0.f;
|
|
float MaxBMoy = 0.f;
|
|
|
|
for (int k = 0; k < nbtl; k++) {
|
|
MaxBMoy += max_b[k];
|
|
MaxRMoy += max_r[k];
|
|
|
|
if (max_r[k] > MaxR) {
|
|
MaxR = max_r[k];
|
|
}
|
|
|
|
if (max_b[k] > MaxB) {
|
|
MaxB = max_b[k];
|
|
}
|
|
|
|
}
|
|
|
|
MaxBMoy /= nbtl;
|
|
MaxRMoy /= nbtl;
|
|
|
|
for (int k = 0; k < nbtl; k++) {
|
|
if (MaxR > MaxB) {
|
|
max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev
|
|
//max_b[k]=MinB;
|
|
max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f;
|
|
|
|
} else {
|
|
max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f;
|
|
//max_r[k]=MinR;
|
|
max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (settings->verbose) {
|
|
t2pone.set();
|
|
printf("Info denoise ponderated performed in %d usec:\n", t2pone.etime(t1pone));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) {
|
|
MyTime t1aue, t2aue;
|
|
t1aue.set();
|
|
int crW, crH;
|
|
|
|
if (settings->leveldnv == 0) {
|
|
crW = 100;
|
|
crH = 100;
|
|
}
|
|
|
|
if (settings->leveldnv == 1) {
|
|
crW = 250;
|
|
crH = 250;
|
|
}
|
|
|
|
if (settings->leveldnv == 2) {
|
|
crW = int (tileWskip / 2);
|
|
crH = int (tileHskip / 2);
|
|
}
|
|
|
|
// if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview
|
|
if (settings->leveldnv == 3) {
|
|
crW = tileWskip - 10;
|
|
crH = tileHskip - 10;
|
|
}
|
|
|
|
float lowdenoise = 1.f;
|
|
int levaut = settings->leveldnaut;
|
|
|
|
if (levaut == 1) { //Standard
|
|
lowdenoise = 0.7f;
|
|
}
|
|
|
|
if (params.dirpyrDenoise.enabled) {//evaluate Noise
|
|
LUTf gamcurve(65536, 0);
|
|
float gam, gamthresh, gamslope;
|
|
ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
|
|
int Nb[9];
|
|
int coordW[3];//coordonate of part of image to mesure noise
|
|
int coordH[3];
|
|
int begW = 50;
|
|
int begH = 50;
|
|
coordW[0] = begW;
|
|
coordW[1] = fw / 2 - crW / 2;
|
|
coordW[2] = fw - crW - begW;
|
|
coordH[0] = begH;
|
|
coordH[1] = fh / 2 - crH / 2;
|
|
coordH[2] = fh - crH - begH;
|
|
#pragma omp parallel
|
|
{
|
|
Imagefloat *origCropPart;//init auto noise
|
|
origCropPart = new Imagefloat(crW, crH); //allocate memory
|
|
Imagefloat *provicalc = new Imagefloat((crW + 1) / 2, (crH + 1) / 2); //for denoise curves
|
|
|
|
#pragma omp for schedule(dynamic) collapse(2) nowait
|
|
|
|
for (int wcr = 0; wcr <= 2; wcr++) {
|
|
for (int hcr = 0; hcr <= 2; hcr++) {
|
|
PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1);
|
|
imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
|
|
//baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve);
|
|
|
|
|
|
// we only need image reduced to 1/4 here
|
|
for (int ii = 0; ii < crH; ii += 2) {
|
|
for (int jj = 0; jj < crW; jj += 2) {
|
|
provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj);
|
|
provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj);
|
|
provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
imgsrc->convertColorSpace(provicalc, params.icm, currWB); //for denoise luminance curve
|
|
int nb = 0;
|
|
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
|
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
|
Nb[hcr * 3 + wcr] = nb;
|
|
ch_M[hcr * 3 + wcr] = chaut;
|
|
max_r[hcr * 3 + wcr] = maxredaut;
|
|
max_b[hcr * 3 + wcr] = maxblueaut;
|
|
min_r[hcr * 3 + wcr] = minredaut;
|
|
min_b[hcr * 3 + wcr] = minblueaut;
|
|
lumL[hcr * 3 + wcr] = lumema;
|
|
chromC[hcr * 3 + wcr] = chromina;
|
|
ry[hcr * 3 + wcr] = redyel;
|
|
sk[hcr * 3 + wcr] = skinc;
|
|
pcsk[hcr * 3 + wcr] = nsknc;
|
|
}
|
|
}
|
|
|
|
delete provicalc;
|
|
delete origCropPart;
|
|
}
|
|
float chM = 0.f;
|
|
float MaxR = 0.f;
|
|
float MaxB = 0.f;
|
|
float MinR = 100000000.f;
|
|
float MinB = 100000000.f;
|
|
float maxr = 0.f;
|
|
float maxb = 0.f;
|
|
float multip = 1.f;
|
|
float adjustr = 1.f;
|
|
float Max_R[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
|
float Max_B[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
|
float Min_R[9];
|
|
float Min_B[9];
|
|
float MaxRMoy = 0.f;
|
|
float MaxBMoy = 0.f;
|
|
float MinRMoy = 0.f;
|
|
float MinBMoy = 0.f;
|
|
|
|
if (params.icm.working == "ProPhoto") {
|
|
adjustr = 1.f;
|
|
} else if (params.icm.working == "Adobe RGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.working == "sRGB") {
|
|
adjustr = 1.f / 1.3f;
|
|
} else if (params.icm.working == "WideGamut") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.working == "Rec2020") {
|
|
adjustr = 1.f / 1.1f;
|
|
} else if (params.icm.working == "Beta RGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.working == "BestRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
} else if (params.icm.working == "BruceRGB") {
|
|
adjustr = 1.f / 1.2f;
|
|
}
|
|
|
|
if (!imgsrc->isRAW()) {
|
|
multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1
|
|
}
|
|
|
|
float delta[9];
|
|
int mode = 1;
|
|
int lissage = settings->leveldnliss;
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
float maxmax = max(max_r[k], max_b[k]);
|
|
ipf.calcautodn_info(ch_M[k], delta[k], Nb[k], levaut, maxmax, lumL[k], chromC[k], mode, lissage, ry[k], sk[k], pcsk[k]);
|
|
// printf("ch_M=%f delta=%f\n",ch_M[k], delta[k]);
|
|
}
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
if (max_r[k] > max_b[k]) {
|
|
//printf("R delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise);
|
|
Max_R[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
Min_B[k] = - (ch_M[k] - min_b[k]) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
Max_B[k] = 0.f;
|
|
Min_R[k] = 0.f;
|
|
} else {
|
|
//printf("B delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise);
|
|
Max_B[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f);
|
|
Min_R[k] = - (ch_M[k] - min_r[k]) / (autoNRmax * multip * adjustr * lowdenoise);
|
|
Min_B[k] = 0.f;
|
|
Max_R[k] = 0.f;
|
|
}
|
|
}
|
|
|
|
for (int k = 0; k < 9; k++) {
|
|
// printf("ch_M= %f Max_R=%f Max_B=%f min_r=%f min_b=%f\n",ch_M[k],Max_R[k], Max_B[k],Min_R[k], Min_B[k]);
|
|
chM += ch_M[k];
|
|
MaxBMoy += Max_B[k];
|
|
MaxRMoy += Max_R[k];
|
|
MinRMoy += Min_R[k];
|
|
MinBMoy += Min_B[k];
|
|
|
|
if (Max_R[k] > MaxR) {
|
|
MaxR = Max_R[k];
|
|
}
|
|
|
|
if (Max_B[k] > MaxB) {
|
|
MaxB = Max_B[k];
|
|
}
|
|
|
|
if (Min_R[k] < MinR) {
|
|
MinR = Min_R[k];
|
|
}
|
|
|
|
if (Min_B[k] < MinB) {
|
|
MinB = Min_B[k];
|
|
}
|
|
|
|
}
|
|
|
|
chM /= 9;
|
|
MaxBMoy /= 9;
|
|
MaxRMoy /= 9;
|
|
MinBMoy /= 9;
|
|
MinRMoy /= 9;
|
|
|
|
if (MaxR > MaxB) {
|
|
maxr = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev
|
|
// maxb=MinB;
|
|
maxb = MinBMoy + (MinB - MinBMoy) * 0.66f;
|
|
|
|
} else {
|
|
maxb = MaxBMoy + (MaxB - MaxBMoy) * 0.66f;
|
|
// maxr=MinR;
|
|
maxr = MinRMoy + (MinR - MinRMoy) * 0.66f;
|
|
|
|
}
|
|
|
|
// printf("SIMPL cha=%f red=%f bl=%f \n",chM,maxr,maxb);
|
|
|
|
params.dirpyrDenoise.chroma = chM / (autoNR * multip * adjustr);
|
|
params.dirpyrDenoise.redchro = maxr;
|
|
params.dirpyrDenoise.bluechro = maxb;
|
|
}
|
|
|
|
if (settings->verbose) {
|
|
t2aue.set();
|
|
printf("Info denoise auto performed in %d usec:\n", t2aue.etime(t1aue));
|
|
}
|
|
|
|
//end evaluate noise
|
|
}
|
|
|
|
baseImg = new Imagefloat(fw, fh);
|
|
imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw);
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.50);
|
|
}
|
|
|
|
// LUTf Noisecurve (65536,0);
|
|
//!!!// auto exposure!!!
|
|
expcomp = params.toneCurve.expcomp;
|
|
bright = params.toneCurve.brightness;
|
|
contr = params.toneCurve.contrast;
|
|
black = params.toneCurve.black;
|
|
hlcompr = params.toneCurve.hlcompr;
|
|
hlcomprthresh = params.toneCurve.hlcomprthresh;
|
|
|
|
|
|
if (params.toneCurve.autoexp) {
|
|
LUTu aehist;
|
|
int aehistcompr;
|
|
imgsrc->getAutoExpHistogram(aehist, aehistcompr);
|
|
ipf.getAutoExp(aehist, aehistcompr, params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh);
|
|
}
|
|
|
|
// at this stage, we can flush the raw data to free up quite an important amount of memory
|
|
// commented out because it makes the application crash when batch processing...
|
|
// TODO: find a better place to flush rawData and rawRGB
|
|
if (flush) {
|
|
imgsrc->flushRawData();
|
|
imgsrc->flushRGB();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void stage_denoise()
|
|
{
|
|
procparams::ProcParams& params = job->pparams;
|
|
//ImProcFunctions ipf (¶ms, true);
|
|
ImProcFunctions &ipf = * (ipf_p.get());
|
|
|
|
// perform luma/chroma denoise
|
|
// CieImage *cieView;
|
|
// NoisCurve noiseLCurve;
|
|
// bool lldenoiseutili=false;
|
|
// Imagefloat *calclum ;
|
|
// params.dirpyrDenoise.getCurves(noiseLCurve, lldenoiseutili);
|
|
// if (params.dirpyrDenoise.enabled && lldenoiseutili) {
|
|
|
|
DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; // make a copy because we cheat here
|
|
|
|
if (denoiseParams.Lmethod == "CUR") {
|
|
if (noiseLCurve) {
|
|
denoiseParams.luma = 0.5f;
|
|
} else {
|
|
denoiseParams.luma = 0.0f;
|
|
}
|
|
} else if (denoiseParams.Lmethod == "SLI") {
|
|
noiseLCurve.Reset();
|
|
}
|
|
|
|
if (denoiseParams.enabled && (noiseLCurve || noiseCCurve)) {
|
|
// we only need image reduced to 1/4 here
|
|
calclum = new Imagefloat((fw + 1) / 2, (fh + 1) / 2); //for luminance denoise curve
|
|
#pragma omp parallel for
|
|
|
|
for (int ii = 0; ii < fh; ii += 2) {
|
|
for (int jj = 0; jj < fw; jj += 2) {
|
|
calclum->r(ii >> 1, jj >> 1) = baseImg->r(ii, jj);
|
|
calclum->g(ii >> 1, jj >> 1) = baseImg->g(ii, jj);
|
|
calclum->b(ii >> 1, jj >> 1) = baseImg->b(ii, jj);
|
|
}
|
|
}
|
|
|
|
imgsrc->convertColorSpace(calclum, params.icm, currWB);
|
|
}
|
|
|
|
if (denoiseParams.enabled) {
|
|
// CurveFactory::denoiseLL(lldenoiseutili, denoiseParams.lcurve, Noisecurve,1);
|
|
//denoiseParams.getCurves(noiseLCurve);
|
|
// ipf.RGB_denoise(baseImg, baseImg, calclum, imgsrc->isRAW(), denoiseParams, params.defringe, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, lldenoiseutili);
|
|
float nresi, highresi;
|
|
int kall = 2;
|
|
ipf.RGB_denoise(kall, baseImg, baseImg, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, nresi, highresi);
|
|
|
|
}
|
|
|
|
// delete calclum;
|
|
delete [] ch_M;
|
|
delete [] max_r;
|
|
delete [] max_b;
|
|
delete [] min_r;
|
|
delete [] min_b;
|
|
delete [] lumL;
|
|
delete [] chromC;
|
|
delete [] ry;
|
|
delete [] sk;
|
|
delete [] pcsk;
|
|
}
|
|
|
|
void stage_transform()
|
|
{
|
|
procparams::ProcParams& params = job->pparams;
|
|
//ImProcFunctions ipf (¶ms, true);
|
|
ImProcFunctions &ipf = * (ipf_p.get());
|
|
|
|
imgsrc->convertColorSpace(baseImg, params.icm, currWB);
|
|
|
|
// perform first analysis
|
|
hist16(65536);
|
|
|
|
ipf.firstAnalysis(baseImg, params, hist16);
|
|
|
|
if (params.fattal.enabled) {
|
|
ipf.ToneMapFattal02(baseImg);
|
|
}
|
|
|
|
// perform transform (excepted resizing)
|
|
if (ipf.needsTransform()) {
|
|
Imagefloat* trImg = nullptr;
|
|
|
|
if (ipf.needsLuminanceOnly()) {
|
|
trImg = baseImg;
|
|
} else {
|
|
trImg = new Imagefloat(fw, fh);
|
|
}
|
|
|
|
ipf.transform(baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh,
|
|
imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
|
|
|
|
if (trImg != baseImg) {
|
|
delete baseImg;
|
|
baseImg = trImg;
|
|
}
|
|
}
|
|
}
|
|
|
|
Image16 *stage_finish()
|
|
{
|
|
procparams::ProcParams& params = job->pparams;
|
|
//ImProcFunctions ipf (¶ms, true);
|
|
ImProcFunctions &ipf = * (ipf_p.get());
|
|
|
|
if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) {
|
|
const int W = baseImg->getWidth();
|
|
const int H = baseImg->getHeight();
|
|
LabImage labcbdl(W, H);
|
|
ipf.rgb2lab(*baseImg, labcbdl, params.icm.working);
|
|
ipf.dirpyrequalizer(&labcbdl, 1);
|
|
ipf.lab2rgb(labcbdl, *baseImg, params.icm.working);
|
|
}
|
|
|
|
// update blurmap
|
|
SHMap* shmap = nullptr;
|
|
|
|
if (params.sh.enabled) {
|
|
shmap = new SHMap(fw, fh, true);
|
|
double radius = sqrt(double (fw * fw + fh * fh)) / 2.0;
|
|
double shradius = params.sh.radius;
|
|
|
|
if (!params.sh.hq) {
|
|
shradius *= radius / 1800.0;
|
|
}
|
|
|
|
shmap->update(baseImg, shradius, ipf.lumimul, params.sh.hq, 1);
|
|
}
|
|
|
|
// RGB processing
|
|
|
|
curve1(65536);
|
|
curve2(65536);
|
|
curve(65536, 0);
|
|
satcurve(65536, 0);
|
|
lhskcurve(65536, 0);
|
|
lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation
|
|
clcurve(65536, 0);
|
|
wavclCurve(65536, 0);
|
|
|
|
//if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
|
|
|
|
CurveFactory::complexCurve(expcomp, black / 65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr,
|
|
params.toneCurve.curve, params.toneCurve.curve2,
|
|
hist16, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2);
|
|
|
|
CurveFactory::RGBCurve(params.rgbCurves.rcurve, rCurve, 1);
|
|
CurveFactory::RGBCurve(params.rgbCurves.gcurve, gCurve, 1);
|
|
CurveFactory::RGBCurve(params.rgbCurves.bcurve, bCurve, 1);
|
|
|
|
bool opautili = false;
|
|
|
|
if (params.colorToning.enabled) {
|
|
TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.working);
|
|
double wp[3][3] = {
|
|
{wprof[0][0], wprof[0][1], wprof[0][2]},
|
|
{wprof[1][0], wprof[1][1], wprof[1][2]},
|
|
{wprof[2][0], wprof[2][1], wprof[2][2]}
|
|
};
|
|
params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili);
|
|
clToningcurve(65536, 0);
|
|
CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, 1);
|
|
cl2Toningcurve(65536, 0);
|
|
CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, 1);
|
|
}
|
|
|
|
labView = new LabImage(fw, fh);
|
|
reservView = new LabImage(fw, fh);
|
|
|
|
if (params.blackwhite.enabled) {
|
|
CurveFactory::curveBW(params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1);
|
|
}
|
|
|
|
double rrm, ggm, bbm;
|
|
float autor, autog, autob;
|
|
float satLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f;
|
|
float satLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f);
|
|
|
|
if (params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings
|
|
float moyS = 0.f;
|
|
float eqty = 0.f;
|
|
ipf.moyeqt(baseImg, moyS, eqty); //return image : mean saturation and standard dev of saturation
|
|
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
|
|
}
|
|
|
|
satLimit = 100.f * satp;
|
|
|
|
satLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation
|
|
}
|
|
|
|
autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000)
|
|
DCPProfile::ApplyState as;
|
|
DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as);
|
|
|
|
LUTu histToneCurve;
|
|
|
|
ipf.rgbProc(baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve);
|
|
|
|
if (settings->verbose) {
|
|
printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob);
|
|
}
|
|
|
|
// if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS)
|
|
if (params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) {
|
|
CLUTStore::getInstance().clearCache();
|
|
}
|
|
|
|
// freeing up some memory
|
|
customToneCurve1.Reset();
|
|
customToneCurve2.Reset();
|
|
ctColorCurve.Reset();
|
|
ctOpacityCurve.Reset();
|
|
noiseLCurve.Reset();
|
|
noiseCCurve.Reset();
|
|
customToneCurvebw1.Reset();
|
|
customToneCurvebw2.Reset();
|
|
|
|
// Freeing baseImg because not used anymore
|
|
delete baseImg;
|
|
baseImg = nullptr;
|
|
|
|
if (shmap) {
|
|
delete shmap;
|
|
}
|
|
|
|
shmap = nullptr;
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.55);
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
// start tile processing...???
|
|
|
|
|
|
if (params.labCurve.contrast != 0) { //only use hist16 for contrast
|
|
hist16.clear();
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel
|
|
#endif
|
|
{
|
|
LUTu hist16thr(hist16.getSize()); // one temporary lookup table per thread
|
|
hist16thr.clear();
|
|
#ifdef _OPENMP
|
|
#pragma omp for schedule(static) nowait
|
|
#endif
|
|
|
|
for (int i = 0; i < fh; i++)
|
|
for (int j = 0; j < fw; j++) {
|
|
hist16thr[(int)((labView->L[i][j]))]++;
|
|
}
|
|
|
|
#pragma omp critical
|
|
{
|
|
hist16 += hist16thr;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool utili;
|
|
CurveFactory::complexLCurve(params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili);
|
|
|
|
bool clcutili;
|
|
CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1);
|
|
|
|
bool ccutili, cclutili;
|
|
CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve,
|
|
params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1);
|
|
|
|
|
|
// bool locallutili = false;
|
|
// bool localcutili = false;
|
|
reservView->CopyFrom(labView);
|
|
|
|
if (params.locallab.enabled) {
|
|
MyTime t1, t2;
|
|
t1.set();
|
|
|
|
std::string mdfive = getMD5(imgsrc->getFileName());
|
|
|
|
Glib::ustring pop = options.cacheBaseDir + "/mip/";
|
|
|
|
Glib::ustring datalab;
|
|
|
|
if (options.mip == MI_opt) {
|
|
datalab = pop + Glib::path_get_basename(imgsrc->getFileName() + "." + mdfive + ".mip");
|
|
}
|
|
|
|
if (options.mip == MI_prev) {
|
|
datalab = imgsrc->getFileName() + ".mip";
|
|
}
|
|
|
|
|
|
LocretigainCurve locRETgainCurve;
|
|
LocLHCurve loclhCurve;
|
|
LocHHCurve lochhCurve;
|
|
|
|
LocretigainCurverab locRETgainCurverab;
|
|
LUTf lllocalcurve(65536, 0);
|
|
LUTf cclocalcurve(65536, 0);
|
|
LUTf sklocalcurve(65536, 0);
|
|
LUTf hltonecurveloc(32768, 0);
|
|
LUTf shtonecurveloc(32768, 0);
|
|
LUTf tonecurveloc(32768, 0);
|
|
LUTf exlocalcurve(32768, 0);
|
|
// int realspot = params.locallab.nbspot;
|
|
int maxspot = settings->nspot + 1;
|
|
ifstream fic0(datalab, ios::in);
|
|
float** shbuffer = nullptr;
|
|
int versionmip = 0;
|
|
std::string delim[69] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
|
"&", "#", "{", "[", "]", "}", "$", "*", "?", ">", "!", ";", "<"",(", ")", "+", "-"
|
|
};
|
|
|
|
if (params.locallab.inverssha) {
|
|
shbuffer = new float*[fh];
|
|
|
|
for (int i = 0; i < fh; i++) {
|
|
shbuffer[i] = new float[fw];
|
|
}
|
|
}
|
|
|
|
if (fic0) {//normally we don't use here but ??
|
|
//find the version mip
|
|
string line;
|
|
string spotline;
|
|
// int cont = 0;
|
|
|
|
while (getline(fic0, line)) {
|
|
spotline = line;
|
|
std::size_t pos = spotline.find("=");
|
|
std::size_t posend = spotline.find("@"); //in case of for futur use
|
|
|
|
if (spotline.substr(0, pos) == "Mipversion") {
|
|
string strversion = spotline.substr(pos + 1, (posend - pos));
|
|
versionmip = std::stoi(strversion.c_str());
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "Spot") {
|
|
// cont = 0;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
fic0.close();
|
|
}
|
|
|
|
ifstream fich(datalab, ios::in);
|
|
int maxdata = 99; // 91 10021 //88 10019 //87 10018//86 10017//85 10016 //82;//78;//73 10011
|
|
|
|
if (fich && versionmip != 0) {
|
|
std::string inser;
|
|
|
|
int **dataspots;
|
|
dataspots = new int*[maxdata];
|
|
|
|
for (int i = 0; i < maxdata; i++) {
|
|
dataspots[i] = new int[maxspot];
|
|
}
|
|
|
|
|
|
std::string *retistrs;
|
|
retistrs = new std::string[maxspot];
|
|
std::string *llstrs;
|
|
|
|
llstrs = new std::string[maxspot];
|
|
|
|
std::string *lhstrs;
|
|
lhstrs = new std::string[maxspot];
|
|
|
|
std::string *ccstrs;
|
|
ccstrs = new std::string[maxspot];
|
|
|
|
std::string *hhstrs;
|
|
hhstrs = new std::string[maxspot];
|
|
|
|
std::string *skinstrs;
|
|
skinstrs = new std::string[maxspot];
|
|
|
|
std::string *pthstrs;
|
|
pthstrs = new std::string[maxspot];
|
|
|
|
std::string *exstrs;
|
|
exstrs = new std::string[maxspot];
|
|
|
|
{
|
|
dataspots[2][0] = params.locallab.circrad;
|
|
dataspots[3][0] = params.locallab.locX;
|
|
dataspots[4][0] = params.locallab.locY;
|
|
dataspots[5][0] = params.locallab.locYT;
|
|
dataspots[6][0] = params.locallab.locXL;
|
|
dataspots[7][0] = params.locallab.centerX;
|
|
dataspots[8][0] = params.locallab.centerY;
|
|
dataspots[9][0] = params.locallab.lightness;
|
|
dataspots[10][0] = params.locallab.contrast;
|
|
dataspots[11][0] = params.locallab.chroma;
|
|
dataspots[12][0] = params.locallab.sensi;
|
|
dataspots[13][0] = params.locallab.transit;
|
|
|
|
if (!params.locallab.invers) {
|
|
dataspots[14][0] = 0;
|
|
} else {
|
|
dataspots[14][0] = 1;
|
|
}
|
|
|
|
if (params.locallab.Smethod == "IND") {
|
|
dataspots[15][0] = 0;
|
|
} else if (params.locallab.Smethod == "SYM") {
|
|
dataspots[15][0] = 1;
|
|
} else if (params.locallab.Smethod == "INDSL") {
|
|
dataspots[15][0] = 2;
|
|
} else if (params.locallab.Smethod == "SYMSL") {
|
|
dataspots[15][0] = 3;
|
|
}
|
|
|
|
dataspots[17][0] = params.locallab.radius;
|
|
dataspots[18][0] = params.locallab.strength;
|
|
dataspots[19][0] = params.locallab.sensibn;
|
|
|
|
if (!params.locallab.inversrad) {
|
|
dataspots[20][0] = 0;
|
|
} else {
|
|
dataspots[20][0] = 1;
|
|
}
|
|
|
|
dataspots[21][0] = params.locallab.str;
|
|
dataspots[22][0] = params.locallab.chrrt;
|
|
dataspots[23][0] = params.locallab.neigh;
|
|
dataspots[24][0] = params.locallab.vart;
|
|
dataspots[25][0] = params.locallab.sensih;
|
|
|
|
if (!params.locallab.inversret) {
|
|
dataspots[26][0] = 0;
|
|
} else {
|
|
dataspots[26][0] = 1;
|
|
}
|
|
|
|
if (params.locallab.retinexMethod == "low") {
|
|
dataspots[27][0] = 0;
|
|
} else if (params.locallab.retinexMethod == "uni") {
|
|
dataspots[27][0] = 1;
|
|
} else if (params.locallab.retinexMethod == "high") {
|
|
dataspots[27][0] = 2;
|
|
}
|
|
|
|
|
|
dataspots[28][0] = params.locallab.sharradius;
|
|
dataspots[29][0] = params.locallab.sharamount;
|
|
dataspots[30][0] = params.locallab.shardamping;
|
|
dataspots[31][0] = params.locallab.shariter;
|
|
dataspots[32][0] = params.locallab.sensisha;
|
|
|
|
if (!params.locallab.inverssha) {
|
|
dataspots[33][0] = 0;
|
|
} else {
|
|
dataspots[33][0] = 1;
|
|
}
|
|
|
|
if (params.locallab.qualityMethod == "std") {
|
|
dataspots[34][0] = 0;
|
|
} else if (params.locallab.qualityMethod == "enh") {
|
|
dataspots[34][0] = 1;
|
|
} else if (params.locallab.qualityMethod == "enhden") {
|
|
dataspots[34][0] = 2;
|
|
}
|
|
|
|
dataspots[35][0] = params.locallab.thres;
|
|
dataspots[36][0] = params.locallab.proxi;
|
|
|
|
dataspots[37][0] = params.locallab.noiselumf;
|
|
dataspots[38][0] = params.locallab.noiselumc;
|
|
dataspots[39][0] = params.locallab.noisechrof;
|
|
dataspots[40][0] = params.locallab.noisechroc;
|
|
|
|
dataspots[41][0] = params.locallab.mult[0];
|
|
dataspots[42][0] = params.locallab.mult[1];
|
|
dataspots[43][0] = params.locallab.mult[2];
|
|
dataspots[44][0] = params.locallab.mult[3];
|
|
dataspots[45][0] = params.locallab.mult[4];
|
|
dataspots[46][0] = params.locallab.threshold;
|
|
dataspots[47][0] = params.locallab.sensicb;
|
|
|
|
if (!params.locallab.activlum) {
|
|
dataspots[48][0] = 0;
|
|
} else {
|
|
dataspots[48][0] = 1;
|
|
}
|
|
|
|
dataspots[49][0] = params.locallab.stren;
|
|
dataspots[50][0] = params.locallab.gamma;
|
|
dataspots[51][0] = params.locallab.estop;
|
|
dataspots[52][0] = params.locallab.scaltm;
|
|
dataspots[53][0] = params.locallab.rewei;
|
|
dataspots[54][0] = params.locallab.sensitm;
|
|
dataspots[55][0] = params.locallab.retrab;
|
|
|
|
if (!params.locallab.curvactiv) {
|
|
dataspots[56][0] = 0;
|
|
} else {
|
|
dataspots[56][0] = 1;
|
|
}
|
|
|
|
if (params.locallab.qualitycurveMethod == "none") {
|
|
dataspots[57][0] = 0;
|
|
} else if (params.locallab.qualitycurveMethod == "std") {
|
|
dataspots[57][0] = 1;
|
|
} else if (params.locallab.qualitycurveMethod == "enh") {
|
|
dataspots[57][0] = 2;
|
|
}
|
|
|
|
dataspots[58][0] = params.locallab.sensiv;
|
|
dataspots[59][0] = params.locallab.pastels;
|
|
dataspots[60][0] = params.locallab.saturated;
|
|
|
|
if (!params.locallab.protectskins) {
|
|
dataspots[61][0] = 0;
|
|
} else {
|
|
dataspots[61][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.avoidcolorshift) {
|
|
dataspots[62][0] = 0;
|
|
} else {
|
|
dataspots[62][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.pastsattog) {
|
|
dataspots[63][0] = 0;
|
|
} else {
|
|
dataspots[63][0] = 1;
|
|
}
|
|
|
|
dataspots[64][0] = params.locallab.expcomp;
|
|
dataspots[65][0] = params.locallab.black;
|
|
dataspots[66][0] = params.locallab.hlcompr;
|
|
dataspots[67][0] = params.locallab.hlcomprthresh;
|
|
dataspots[68][0] = params.locallab.shcompr;
|
|
dataspots[69][0] = params.locallab.sensiex;
|
|
|
|
dataspots[70][0] = params.locallab.centerXbuf;
|
|
dataspots[71][0] = params.locallab.centerYbuf;
|
|
dataspots[72][0] = params.locallab.adjblur;
|
|
|
|
if (!params.locallab.cutpast) {
|
|
dataspots[73][0] = 0;
|
|
} else {
|
|
dataspots[73][0] = 1;
|
|
}
|
|
|
|
dataspots[74][0] = params.locallab.chromacbdl;
|
|
|
|
if (!params.locallab.lastdust) {
|
|
dataspots[75][0] = 0;
|
|
} else {
|
|
dataspots[75][0] = 1;
|
|
}
|
|
|
|
if (params.locallab.blurMethod == "norm") {
|
|
dataspots[76][0] = 0;
|
|
} else if (params.locallab.blurMethod == "inv") {
|
|
dataspots[76][0] = 1;
|
|
} else if (params.locallab.blurMethod == "sym") {
|
|
dataspots[76][0] = 2;
|
|
}
|
|
|
|
if (params.locallab.dustMethod == "cop") {
|
|
dataspots[77][0] = 0;
|
|
} else if (params.locallab.dustMethod == "mov") {
|
|
dataspots[77][0] = 1;
|
|
} else if (params.locallab.dustMethod == "pas") {
|
|
dataspots[77][0] = 2;
|
|
}
|
|
|
|
|
|
if (params.locallab.Exclumethod == "norm") {
|
|
dataspots[78][0] = 0;
|
|
} else if (params.locallab.Exclumethod == "exc") {
|
|
dataspots[78][0] = 1;
|
|
}
|
|
|
|
dataspots[79][0] = params.locallab.sensiexclu;
|
|
dataspots[80][0] = params.locallab.struc;
|
|
dataspots[81][0] = params.locallab.warm;
|
|
dataspots[82][0] = params.locallab.noiselumdetail;
|
|
dataspots[83][0] = params.locallab.noisechrodetail;
|
|
dataspots[84][0] = params.locallab.sensiden;
|
|
|
|
if (!params.locallab.expdenoi) {
|
|
dataspots[85][0] = 0;
|
|
} else {
|
|
dataspots[85][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expcolor) {
|
|
dataspots[86][0] = 0;
|
|
} else {
|
|
dataspots[86][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expvibrance) {
|
|
dataspots[87][0] = 0;
|
|
} else {
|
|
dataspots[87][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expblur) {
|
|
dataspots[88][0] = 0;
|
|
} else {
|
|
dataspots[88][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.exptonemap) {
|
|
dataspots[89][0] = 0;
|
|
} else {
|
|
dataspots[89][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expreti) {
|
|
dataspots[90][0] = 0;
|
|
} else {
|
|
dataspots[90][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expsharp) {
|
|
dataspots[91][0] = 0;
|
|
} else {
|
|
dataspots[91][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expcbdl) {
|
|
dataspots[92][0] = 0;
|
|
} else {
|
|
dataspots[92][0] = 1;
|
|
}
|
|
|
|
if (!params.locallab.expexpose) {
|
|
dataspots[93][0] = 0;
|
|
} else {
|
|
dataspots[93][0] = 1;
|
|
}
|
|
|
|
dataspots[maxdata - 5][0] = 100.f * params.locallab.huerefblur;
|
|
dataspots[maxdata - 4][0] = 100.f * params.locallab.hueref;
|
|
dataspots[maxdata - 3][0] = params.locallab.chromaref;
|
|
dataspots[maxdata - 2][0] = params.locallab.lumaref;
|
|
dataspots[maxdata - 1][0] = params.locallab.sobelref;
|
|
|
|
//curve Reti local
|
|
int siz = params.locallab.localTgaincurve.size();
|
|
|
|
if (siz > 69) {
|
|
siz = 69;//avoid crash
|
|
}
|
|
|
|
// int s_cur[siz + 1];
|
|
int s_datcur[siz + 1];
|
|
|
|
for (int j = 0; j < siz; j++) {
|
|
s_datcur[j] = (int)(1000. * params.locallab.localTgaincurve[j]);
|
|
}
|
|
|
|
std::string cur_str = "";
|
|
|
|
for (int j = 0; j < siz; j++) {
|
|
cur_str = cur_str + std::to_string(s_datcur[j]) + delim[j];
|
|
}
|
|
|
|
inser = retistrs[0] = cur_str + "@";
|
|
|
|
int sizl = params.locallab.llcurve.size();
|
|
|
|
if (sizl > 69) {
|
|
sizl = 69;
|
|
}
|
|
|
|
// int s_curl[sizl + 1];
|
|
int s_datcurl[sizl + 1];
|
|
|
|
for (int j = 0; j < sizl; j++) {
|
|
s_datcurl[j] = (int)(1000. * params.locallab.llcurve[j]);
|
|
}
|
|
|
|
std::string ll_str = "";
|
|
|
|
for (int j = 0; j < sizl; j++) {
|
|
ll_str = ll_str + std::to_string(s_datcurl[j]) + delim[j];
|
|
}
|
|
|
|
llstrs[0] = ll_str + "@";
|
|
|
|
|
|
int sizc = params.locallab.cccurve.size();
|
|
|
|
if (sizc > 69) {
|
|
sizc = 69;
|
|
}
|
|
|
|
// int s_curc[sizc + 1];
|
|
int s_datcurc[sizc + 1];
|
|
|
|
for (int j = 0; j < sizc; j++) {
|
|
s_datcurc[j] = (int)(1000. * params.locallab.cccurve[j]);
|
|
}
|
|
|
|
std::string cc_str = "";
|
|
|
|
for (int j = 0; j < sizc; j++) {
|
|
cc_str = cc_str + std::to_string(s_datcurc[j]) + delim[j];
|
|
}
|
|
|
|
ccstrs[0] = cc_str + "@";
|
|
|
|
//
|
|
|
|
int sizh = params.locallab.LHcurve.size();
|
|
|
|
if (sizh > 69) {
|
|
sizh = 69;
|
|
}
|
|
|
|
// int s_curh[sizh + 1];
|
|
int s_datcurh[sizh + 1];
|
|
|
|
for (int j = 0; j < sizh; j++) {
|
|
s_datcurh[j] = (int)(1000. * params.locallab.LHcurve[j]);
|
|
}
|
|
|
|
std::string lh_str = "";
|
|
|
|
for (int j = 0; j < sizh; j++) {
|
|
lh_str = lh_str + std::to_string(s_datcurh[j]) + delim[j];
|
|
}
|
|
|
|
lhstrs[0] = lh_str + "@";
|
|
|
|
int sizhh = params.locallab.HHcurve.size();
|
|
|
|
if (sizhh > 69) {
|
|
sizhh = 69;
|
|
}
|
|
|
|
// int s_curh[sizh + 1];
|
|
int s_datcurhh[sizhh + 1];
|
|
|
|
for (int j = 0; j < sizhh; j++) {
|
|
s_datcurhh[j] = (int)(1000. * params.locallab.HHcurve[j]);
|
|
}
|
|
|
|
std::string hh_str = "";
|
|
|
|
for (int j = 0; j < sizhh; j++) {
|
|
hh_str = hh_str + std::to_string(s_datcurhh[j]) + delim[j];
|
|
}
|
|
|
|
hhstrs[0] = hh_str + "@";
|
|
|
|
//Skin curve
|
|
int sizsk = params.locallab.skintonescurve.size();
|
|
|
|
if (sizsk > 69) {
|
|
sizsk = 69;//to avoid crash
|
|
}
|
|
|
|
|
|
int s_datcursk[sizsk + 1];
|
|
|
|
for (int j = 0; j < sizsk; j++) {
|
|
s_datcursk[j] = (int)(1000. * params.locallab.skintonescurve[j]);
|
|
}
|
|
|
|
std::string sk_str = "";
|
|
|
|
for (int j = 0; j < sizsk; j++) {
|
|
sk_str = sk_str + std::to_string(s_datcursk[j]) + delim[j];
|
|
}
|
|
|
|
skinstrs[0] = sk_str + "@";
|
|
|
|
//end local skin
|
|
//PSThreshold
|
|
int sizps = 2;
|
|
int s_datps[sizps + 1];
|
|
s_datps[1] = static_cast<int>(params.locallab.psthreshold.getTopLeft());
|
|
|
|
s_datps[0] = static_cast<int>(params.locallab.psthreshold.getBottomLeft());
|
|
|
|
std::string ps_str = "";
|
|
|
|
for (int j = 0; j < sizps; j++) {
|
|
ps_str = ps_str + std::to_string(s_datps[j]) + delim[j];
|
|
}
|
|
|
|
pthstrs[0] = ps_str + "@";
|
|
|
|
//end local ps
|
|
|
|
//expos
|
|
//Skin curve
|
|
int sizex = params.locallab.excurve.size();
|
|
|
|
if (sizex > 69) {
|
|
sizex = 69;//to avoid crash
|
|
}
|
|
|
|
|
|
int s_datcurex[sizsk + 1];
|
|
|
|
for (int j = 0; j < sizex; j++) {
|
|
s_datcurex[j] = (int)(1000. * params.locallab.excurve[j]);
|
|
}
|
|
|
|
std::string ex_str = "";
|
|
|
|
for (int j = 0; j < sizex; j++) {
|
|
ex_str = ex_str + std::to_string(s_datcurex[j]) + delim[j];
|
|
}
|
|
|
|
exstrs[0] = ex_str + "@";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
int ns = 0;
|
|
|
|
if (fich) {
|
|
|
|
std::string line;
|
|
std::string spotline;
|
|
int cont = 0;
|
|
|
|
while (getline(fich, line)) {
|
|
spotline = line;
|
|
std::size_t pos = spotline.find("=");
|
|
std::size_t posend = spotline.find("@"); //in case of for futur use
|
|
|
|
if (spotline.substr(0, pos) == "Mipversion") {
|
|
std::string strversion = spotline.substr(pos + 1, (posend - pos));
|
|
versionmip = std::stoi(strversion.c_str());
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "Spot") {
|
|
cont = 0;
|
|
}
|
|
|
|
cont++;
|
|
std::string str3 = spotline.substr(pos + 1, (posend - pos));
|
|
|
|
if (cont == 1) {
|
|
ns = std::stoi(str3.c_str());
|
|
}
|
|
|
|
if (cont >= 2 && cont < 16) {
|
|
dataspots[cont][ns] = std::stoi(str3.c_str());
|
|
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "Currentspot") {
|
|
dataspots[16][0] = std::stoi(str3.c_str());
|
|
}
|
|
|
|
if (cont > 16 && cont < maxdata) {
|
|
dataspots[cont][ns] = std::stoi(str3.c_str());
|
|
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveReti") {
|
|
retistrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveLL") {
|
|
llstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveLH") {
|
|
lhstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveHH") {
|
|
hhstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveCC") {
|
|
ccstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveskin") {
|
|
skinstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "pthres") {
|
|
pthstrs[ns] = str3;
|
|
}
|
|
|
|
if (spotline.substr(0, pos) == "curveex") {
|
|
exstrs[ns] = str3;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
fich.close();
|
|
}
|
|
|
|
|
|
for (int sp = 1; sp < maxspot; sp++) { //spots default
|
|
params.locallab.huerefblur = INFINITY;
|
|
params.locallab.hueref = INFINITY;
|
|
params.locallab.chromaref = INFINITY;
|
|
params.locallab.lumaref = INFINITY;
|
|
params.locallab.sobelref = INFINITY;
|
|
|
|
params.locallab.circrad = dataspots[2][sp];
|
|
params.locallab.locX = dataspots[3][sp];
|
|
params.locallab.locY = dataspots[4][sp];
|
|
params.locallab.locYT = dataspots[5][sp];
|
|
params.locallab.locXL = dataspots[6][sp];
|
|
params.locallab.centerX = dataspots[7][sp];
|
|
params.locallab.centerY = dataspots[8][sp];
|
|
params.locallab.lightness = dataspots[9][sp];
|
|
params.locallab.contrast = dataspots[10][sp];
|
|
params.locallab.chroma = dataspots[11][sp];
|
|
params.locallab.sensi = dataspots[12][sp];
|
|
params.locallab.transit = dataspots[13][sp];
|
|
|
|
if (dataspots[14][sp] == 0) {
|
|
params.locallab.invers = false;
|
|
} else {
|
|
params.locallab.invers = true;
|
|
}
|
|
|
|
if (dataspots[15][sp] == 0) {
|
|
params.locallab.Smethod = "IND" ;
|
|
} else if (dataspots[15][sp] == 1) {
|
|
params.locallab.Smethod = "SYM" ;
|
|
} else if (dataspots[15][sp] == 2) {
|
|
params.locallab.Smethod = "INDSL";
|
|
} else if (dataspots[15][sp] == 3) {
|
|
params.locallab.Smethod = "SYMSL";
|
|
}
|
|
|
|
params.locallab.radius = dataspots[17][sp];
|
|
params.locallab.strength = dataspots[18][sp];
|
|
params.locallab.sensibn = dataspots[19][sp];
|
|
|
|
if (dataspots[20][sp] == 0) {
|
|
params.locallab.inversrad = false;
|
|
} else {
|
|
params.locallab.inversrad = true;
|
|
}
|
|
|
|
params.locallab.str = dataspots[21][sp];
|
|
params.locallab.chrrt = dataspots[22][sp];
|
|
params.locallab.neigh = dataspots[23][sp];
|
|
params.locallab.vart = dataspots[24][sp];
|
|
params.locallab.sensih = dataspots[25][sp];
|
|
|
|
if (dataspots[26][sp] == 0) {
|
|
params.locallab.inversret = false;
|
|
} else {
|
|
params.locallab.inversret = true;
|
|
}
|
|
|
|
if (dataspots[27][sp] == 0) {
|
|
params.locallab.retinexMethod = "low" ;
|
|
} else if (dataspots[27][sp] == 1) {
|
|
params.locallab.retinexMethod = "uni" ;
|
|
} else if (dataspots[27][sp] == 2) {
|
|
params.locallab.retinexMethod = "high";
|
|
}
|
|
|
|
params.locallab.sharradius = dataspots[28][sp];
|
|
params.locallab.sharamount = dataspots[29][sp];
|
|
params.locallab.shardamping = dataspots[30][sp];
|
|
params.locallab.shariter = dataspots[31][sp];
|
|
params.locallab.sensisha = dataspots[32][sp];
|
|
|
|
if (dataspots[33][sp] == 0) {
|
|
params.locallab.inverssha = false;
|
|
} else {
|
|
params.locallab.inverssha = true;
|
|
}
|
|
|
|
if (dataspots[34][sp] == 0) {
|
|
params.locallab.qualityMethod = "std" ;
|
|
} else if (dataspots[34][sp] == 1) {
|
|
params.locallab.qualityMethod = "enh" ;
|
|
} else if (dataspots[34][sp] == 2) {
|
|
params.locallab.qualityMethod = "enhden" ;
|
|
}
|
|
|
|
params.locallab.thres = dataspots[35][sp];
|
|
params.locallab.proxi = dataspots[36][sp];
|
|
|
|
params.locallab.noiselumf = dataspots[37][sp];
|
|
params.locallab.noiselumc = dataspots[38][sp];
|
|
params.locallab.noisechrof = dataspots[39][sp];
|
|
params.locallab.noisechroc = dataspots[40][sp];
|
|
|
|
params.locallab.mult[0] = dataspots[41][sp];
|
|
params.locallab.mult[1] = dataspots[42][sp];
|
|
params.locallab.mult[2] = dataspots[43][sp];
|
|
params.locallab.mult[3] = dataspots[44][sp];
|
|
params.locallab.mult[4] = dataspots[45][sp];
|
|
params.locallab.threshold = dataspots[46][sp];
|
|
params.locallab.sensicb = dataspots[47][sp];
|
|
|
|
if (dataspots[48][sp] == 0) {
|
|
params.locallab.activlum = false;
|
|
} else {
|
|
params.locallab.activlum = true;
|
|
}
|
|
|
|
params.locallab.stren = dataspots[49][sp];
|
|
params.locallab.gamma = dataspots[50][sp];
|
|
params.locallab.estop = dataspots[51][sp];
|
|
params.locallab.scaltm = dataspots[52][sp];
|
|
params.locallab.rewei = dataspots[53][sp];
|
|
params.locallab.sensitm = dataspots[54][sp];
|
|
params.locallab.retrab = dataspots[55][sp];
|
|
|
|
if (dataspots[56][sp] == 0) {
|
|
params.locallab.curvactiv = false;
|
|
} else {
|
|
params.locallab.curvactiv = true;
|
|
}
|
|
|
|
if (dataspots[57][sp] == 0) {
|
|
params.locallab.qualitycurveMethod = "none" ;
|
|
} else if (dataspots[57][sp] == 1) {
|
|
params.locallab.qualitycurveMethod = "std" ;
|
|
} else if (dataspots[57][sp] == 2) {
|
|
params.locallab.qualitycurveMethod = "enh" ;
|
|
}
|
|
|
|
|
|
params.locallab.sensiv = dataspots[58][sp];
|
|
params.locallab.pastels = dataspots[59][sp];
|
|
params.locallab.saturated = dataspots[60][sp];
|
|
|
|
if (dataspots[61][sp] == 0) {
|
|
params.locallab.protectskins = false;
|
|
} else {
|
|
params.locallab.protectskins = true;
|
|
}
|
|
|
|
if (dataspots[62][sp] == 0) {
|
|
params.locallab.avoidcolorshift = false;
|
|
} else {
|
|
params.locallab.avoidcolorshift = true;
|
|
}
|
|
|
|
if (dataspots[63][sp] == 0) {
|
|
params.locallab.pastsattog = false;
|
|
} else {
|
|
params.locallab.pastsattog = true;
|
|
}
|
|
|
|
params.locallab.expcomp = dataspots[64][sp];
|
|
params.locallab.black = dataspots[65][sp];
|
|
params.locallab.hlcompr = dataspots[66][sp];
|
|
params.locallab.hlcomprthresh = dataspots[67][sp];
|
|
params.locallab.shcompr = dataspots[68][sp];
|
|
params.locallab.sensiex = dataspots[69][sp];
|
|
|
|
params.locallab.centerXbuf = dataspots[70][sp];
|
|
params.locallab.centerYbuf = dataspots[71][sp];
|
|
params.locallab.adjblur = dataspots[72][sp];
|
|
|
|
if (dataspots[73][sp] == 0) {
|
|
params.locallab.cutpast = false;
|
|
} else {
|
|
params.locallab.cutpast = true;
|
|
}
|
|
|
|
params.locallab.chromacbdl = dataspots[74][sp];
|
|
|
|
if (dataspots[75][sp] == 0) {
|
|
params.locallab.lastdust = false;
|
|
} else {
|
|
params.locallab.lastdust = true;
|
|
}
|
|
|
|
if (dataspots[76][sp] == 0) {
|
|
params.locallab.blurMethod = "norm" ;
|
|
} else if (dataspots[76][sp] == 1) {
|
|
params.locallab.blurMethod = "inv" ;
|
|
} else if (dataspots[76][sp] == 2) {
|
|
params.locallab.blurMethod = "sym" ;
|
|
}
|
|
|
|
if (dataspots[77][sp] == 0) {
|
|
params.locallab.dustMethod = "cop" ;
|
|
} else if (dataspots[77][sp] == 1) {
|
|
params.locallab.dustMethod = "mov" ;
|
|
} else if (dataspots[77][sp] == 2) {
|
|
params.locallab.dustMethod = "pas" ;
|
|
}
|
|
|
|
|
|
if (dataspots[78][sp] == 0) {
|
|
params.locallab.Exclumethod = "norm" ;
|
|
} else if (dataspots[78][sp] == 1) {
|
|
params.locallab.Exclumethod = "exc" ;
|
|
}
|
|
|
|
params.locallab.sensiexclu = dataspots[79][sp];
|
|
params.locallab.struc = dataspots[80][sp];
|
|
params.locallab.warm = dataspots[81][sp];
|
|
params.locallab.noiselumdetail = dataspots[82][sp];
|
|
params.locallab.noisechrodetail = dataspots[83][sp];
|
|
params.locallab.sensiden = dataspots[84][sp];
|
|
|
|
if (dataspots[85][sp] == 0) {
|
|
params.locallab.expdenoi = false;
|
|
} else {
|
|
params.locallab.expdenoi = true;
|
|
}
|
|
|
|
if (dataspots[86][sp] == 0) {
|
|
params.locallab.expcolor = false;
|
|
} else {
|
|
params.locallab.expcolor = true;
|
|
}
|
|
|
|
if (dataspots[87][sp] == 0) {
|
|
params.locallab.expvibrance = false;
|
|
} else {
|
|
params.locallab.expvibrance = true;
|
|
}
|
|
|
|
if (dataspots[88][sp] == 0) {
|
|
params.locallab.expblur = false;
|
|
} else {
|
|
params.locallab.expblur = true;
|
|
}
|
|
|
|
if (dataspots[89][sp] == 0) {
|
|
params.locallab.exptonemap = false;
|
|
} else {
|
|
params.locallab.exptonemap = true;
|
|
}
|
|
|
|
if (dataspots[90][sp] == 0) {
|
|
params.locallab.expreti = false;
|
|
} else {
|
|
params.locallab.expreti = true;
|
|
}
|
|
|
|
if (dataspots[91][sp] == 0) {
|
|
params.locallab.expsharp = false;
|
|
} else {
|
|
params.locallab.expsharp = true;
|
|
}
|
|
|
|
if (dataspots[92][sp] == 0) {
|
|
params.locallab.expcbdl = false;
|
|
} else {
|
|
params.locallab.expcbdl = true;
|
|
}
|
|
|
|
if (dataspots[93][sp] == 0) {
|
|
params.locallab.expexpose = false;
|
|
} else {
|
|
params.locallab.expexpose = true;
|
|
}
|
|
|
|
|
|
|
|
params.locallab.huerefblur = ((float) dataspots[maxdata - 5][sp]) / 100.f;
|
|
params.locallab.hueref = ((float) dataspots[maxdata - 4][sp]) / 100.f;
|
|
params.locallab.chromaref = dataspots[maxdata - 3][sp];
|
|
params.locallab.lumaref = dataspots[maxdata - 2][sp];
|
|
params.locallab.sobelref = dataspots[maxdata - 1][sp];
|
|
|
|
|
|
int *s_datc;
|
|
s_datc = new int[70];
|
|
int siz;
|
|
|
|
ipf.strcurv_data(retistrs[sp], s_datc, siz);
|
|
std::vector<double> cretiend;
|
|
|
|
for (int j = 0; j < siz; j++) {
|
|
cretiend.push_back((double)(s_datc[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datc;
|
|
|
|
int *s_datcl;
|
|
s_datcl = new int[70];
|
|
int sizl;
|
|
|
|
ipf.strcurv_data(llstrs[sp], s_datcl, sizl);
|
|
|
|
|
|
std::vector<double> cllend;
|
|
|
|
for (int j = 0; j < sizl; j++) {
|
|
cllend.push_back((double)(s_datcl[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datcl;
|
|
|
|
int *s_datcc;
|
|
s_datcc = new int[70];
|
|
int sizc;
|
|
|
|
ipf.strcurv_data(ccstrs[sp], s_datcc, sizc);
|
|
|
|
|
|
std::vector<double> cccend;
|
|
|
|
for (int j = 0; j < sizc; j++) {
|
|
cccend.push_back((double)(s_datcc[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datcc;
|
|
|
|
int *s_datch;
|
|
s_datch = new int[70];
|
|
int sizh;
|
|
|
|
ipf.strcurv_data(lhstrs[sp], s_datch, sizh);
|
|
|
|
|
|
std::vector<double> clhend;
|
|
|
|
for (int j = 0; j < sizh; j++) {
|
|
clhend.push_back((double)(s_datch[j]) / 1000.);
|
|
}
|
|
|
|
int *s_datchh;
|
|
s_datchh = new int[70];
|
|
int sizhh;
|
|
|
|
ipf.strcurv_data(hhstrs[sp], s_datchh, sizhh);
|
|
|
|
|
|
std::vector<double> chhend;
|
|
|
|
for (int j = 0; j < sizhh; j++) {
|
|
chhend.push_back((double)(s_datchh[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datchh;
|
|
|
|
int *s_datcsk;
|
|
s_datcsk = new int[70];
|
|
int sizsk;
|
|
|
|
ipf.strcurv_data(skinstrs[sp], s_datcsk, sizsk);
|
|
|
|
|
|
std::vector<double> cskend;
|
|
|
|
for (int j = 0; j < sizsk; j++) {
|
|
cskend.push_back((double)(s_datcsk[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datcsk;
|
|
|
|
//PSThreshold + 1
|
|
int sizps = 2;
|
|
int s_datcps[sizps + 1];
|
|
ipf.strcurv_data(pthstrs[sp], s_datcps, sizps);
|
|
|
|
params.locallab.psthreshold.setValues(s_datcps[0], s_datcps[1]);
|
|
|
|
//expos
|
|
int *s_datcex;
|
|
s_datcex = new int[70];
|
|
int sizex;
|
|
|
|
ipf.strcurv_data(exstrs[sp], s_datcex, sizex);
|
|
|
|
|
|
std::vector<double> cexend;
|
|
|
|
for (int j = 0; j < sizex; j++) {
|
|
cexend.push_back((double)(s_datcex[j]) / 1000.);
|
|
}
|
|
|
|
delete [] s_datcex;
|
|
|
|
params.locallab.localTgaincurve.clear();
|
|
params.locallab.llcurve.clear();
|
|
params.locallab.LHcurve.clear();
|
|
params.locallab.cccurve.clear();
|
|
params.locallab.HHcurve.clear();
|
|
params.locallab.skintonescurve.clear();
|
|
params.locallab.excurve.clear();
|
|
|
|
params.locallab.localTgaincurve = cretiend;
|
|
params.locallab.llcurve = cllend;
|
|
params.locallab.LHcurve = clhend;
|
|
params.locallab.cccurve = cccend;
|
|
params.locallab.HHcurve = chhend;
|
|
params.locallab.skintonescurve = cskend;
|
|
params.locallab.excurve = cexend;
|
|
|
|
bool LHutili = false;
|
|
bool HHutili = false;
|
|
std::string t_curvhhref = "1000A0B500C350D350E166F500G350H350I333J500K350L350M500N500O350P350Q666R500S350T350U833V500W350X350Y@";
|
|
|
|
if (lhstrs[sp].c_str() != t_curvhhref) {
|
|
LHutili = true;
|
|
}
|
|
|
|
if (hhstrs[sp].c_str() != t_curvhhref) {
|
|
HHutili = true;
|
|
}
|
|
|
|
|
|
params.locallab.getCurves(locRETgainCurve, locRETgainCurverab, loclhCurve, lochhCurve, LHutili, HHutili);
|
|
bool locallutili = false;
|
|
bool localcutili = false;
|
|
bool localskutili = false;
|
|
bool localexutili = false;
|
|
std::string t_curvskinref = "3000A0B0C1000D1000E@";
|
|
std::string t_none = "0A@";
|
|
|
|
if (skinstrs[sp].c_str() != t_curvskinref && skinstrs[sp].c_str() != t_none) {
|
|
localskutili = true;
|
|
}
|
|
|
|
std::string t_curvexref = "3000A0B0C1000D1000E@";
|
|
|
|
if (exstrs[sp].c_str() != t_curvexref && exstrs[sp].c_str() != t_none) {
|
|
localexutili = true;
|
|
}
|
|
|
|
CurveFactory::curveLocal(locallutili, params.locallab.llcurve, lllocalcurve, 1);
|
|
CurveFactory::curveCCLocal(localcutili, params.locallab.cccurve, cclocalcurve, 1);
|
|
CurveFactory::curveskLocal(localskutili, params.locallab.skintonescurve, sklocalcurve, 1);
|
|
|
|
CurveFactory::curveexLocal(localexutili, params.locallab.excurve, exlocalcurve, 1);
|
|
//provisory
|
|
double br = 0.;
|
|
double contr = 0.;
|
|
double ecomp = params.locallab.expcomp;
|
|
double black = params.locallab.black;
|
|
double hlcompr = params.locallab.hlcompr;
|
|
double hlcomprthresh = params.locallab.hlcomprthresh;
|
|
double shcompr = params.locallab.shcompr;
|
|
|
|
CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, contr,
|
|
hist16, hltonecurveloc, shtonecurveloc, tonecurveloc,
|
|
1);
|
|
|
|
double huere, chromare, lumare, huerefblu;
|
|
double sobelre;
|
|
|
|
ipf.calc_ref(labView, labView, 0, 0, fw, fh, 1, huerefblu, huere, chromare, lumare, sobelre);
|
|
|
|
params.locallab.huerefblur = huerefblu;
|
|
params.locallab.hueref = huere;
|
|
params.locallab.chromaref = chromare;
|
|
params.locallab.lumaref = lumare;
|
|
params.locallab.sobelref = sobelre;
|
|
|
|
ipf.Lab_Local(2, (float**)shbuffer, labView, labView, reservView, 0, 0, fw, fh, 1, locRETgainCurve, lllocalcurve, loclhCurve, lochhCurve,
|
|
LHutili, HHutili, cclocalcurve, localskutili, sklocalcurve, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, params.locallab.huerefblur, params.locallab.hueref, params.locallab.chromaref, params.locallab.lumaref, params.locallab.sobelref);
|
|
lllocalcurve.clear();
|
|
cclocalcurve.clear();
|
|
sklocalcurve.clear();
|
|
exlocalcurve.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < maxdata; i++) {
|
|
delete [] dataspots[i];
|
|
}
|
|
|
|
delete [] dataspots;
|
|
|
|
|
|
|
|
|
|
delete [] retistrs;
|
|
delete [] llstrs;
|
|
delete [] lhstrs;
|
|
delete [] ccstrs;
|
|
delete [] hhstrs;
|
|
delete [] skinstrs;
|
|
delete [] exstrs;
|
|
|
|
if (params.locallab.inverssha) {
|
|
|
|
for (int i = 0; i < fh; i++) {
|
|
delete [] shbuffer[i];
|
|
}
|
|
|
|
delete [] shbuffer;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
t2.set();
|
|
|
|
if (settings->verbose) {
|
|
printf("Total local:- %d usec\n", t2.etime(t1));
|
|
}
|
|
|
|
}
|
|
|
|
delete reservView;
|
|
reservView = nullptr;
|
|
|
|
ipf.chromiLuminanceCurve(nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy);
|
|
|
|
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) {
|
|
ipf.EPDToneMap(labView, 5, 1);
|
|
}
|
|
|
|
|
|
ipf.vibrance(labView);
|
|
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
|
|
ipf.impulsedenoise(labView);
|
|
}
|
|
|
|
// for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled
|
|
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
|
|
ipf.defringe(labView);
|
|
}
|
|
|
|
if (params.sharpenEdge.enabled) {
|
|
ipf.MLsharpen(labView);
|
|
}
|
|
|
|
if (params.sharpenMicro.enabled) {
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
|
|
ipf.MLmicrocontrast(labView); //!params.colorappearance.sharpcie
|
|
}
|
|
}
|
|
|
|
if (((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) {
|
|
|
|
float **buffer = new float*[fh];
|
|
|
|
for (int i = 0; i < fh; i++) {
|
|
buffer[i] = new float[fw];
|
|
}
|
|
|
|
ipf.sharpening(labView, (float**)buffer, params.sharpening);
|
|
|
|
for (int i = 0; i < fh; i++) {
|
|
delete [] buffer[i];
|
|
}
|
|
|
|
delete [] buffer;
|
|
}
|
|
|
|
WaveletParams WaveParams = params.wavelet;
|
|
WavCurve wavCLVCurve;
|
|
WavOpacityCurveRG waOpacityCurveRG;
|
|
WavOpacityCurveBY waOpacityCurveBY;
|
|
WavOpacityCurveW waOpacityCurveW;
|
|
WavOpacityCurveWL waOpacityCurveWL;
|
|
|
|
params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL);
|
|
|
|
|
|
// directional pyramid wavelet
|
|
if (params.dirpyrequalizer.cbdlMethod == "aft") {
|
|
if ((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) {
|
|
ipf.dirpyrequalizer(labView, 1); //TODO: this is the luminance tonecurve, not the RGB one
|
|
}
|
|
}
|
|
|
|
bool wavcontlutili = false;
|
|
|
|
CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1);
|
|
|
|
if (params.wavelet.enabled) {
|
|
ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1);
|
|
}
|
|
|
|
wavCLVCurve.Reset();
|
|
|
|
//Colorappearance and tone-mapping associated
|
|
|
|
int f_w = 1, f_h = 1;
|
|
|
|
if (params.colorappearance.tonecie || params.colorappearance.enabled) {
|
|
f_w = fw;
|
|
f_h = fh;
|
|
}
|
|
|
|
CieImage *cieView = new CieImage(f_w, (f_h));
|
|
|
|
CurveFactory::curveLightBrightColor(
|
|
params.colorappearance.curve,
|
|
params.colorappearance.curve2,
|
|
params.colorappearance.curve3,
|
|
hist16, dummy,
|
|
dummy, dummy,
|
|
customColCurve1,
|
|
customColCurve2,
|
|
customColCurve3,
|
|
1);
|
|
|
|
if (params.colorappearance.enabled) {
|
|
double adap;
|
|
int imgNum = 0;
|
|
|
|
if (imgsrc->getSensorType() == ST_BAYER) {
|
|
imgNum = params.raw.bayersensor.imageNum;
|
|
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
|
|
//imgNum = params.raw.xtranssensor.imageNum;
|
|
}
|
|
|
|
float fnum = imgsrc->getMetaData()->getFNumber(imgNum); // F number
|
|
float fiso = imgsrc->getMetaData()->getISOSpeed(imgNum) ; // ISO
|
|
float fspeed = imgsrc->getMetaData()->getShutterSpeed(imgNum) ; //speed
|
|
float fcomp = imgsrc->getMetaData()->getExpComp(imgNum); //compensation + -
|
|
|
|
if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {
|
|
adap = 2000.;
|
|
}//if no exif data or wrong
|
|
else {
|
|
float E_V = fcomp + log2((fnum * fnum) / fspeed / (fiso / 100.f));
|
|
E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
|
|
E_V += log2(params.raw.expos); // exposure raw white point ; log2 ==> linear to EV
|
|
adap = powf(2.f, E_V - 3.f); //cd / m2
|
|
}
|
|
|
|
LUTf CAMBrightCurveJ;
|
|
LUTf CAMBrightCurveQ;
|
|
float CAMMean = NAN;
|
|
|
|
if (params.sharpening.enabled) {
|
|
if (settings->ciecamfloat) {
|
|
float d, dj, yb;
|
|
ipf.ciecam_02float(cieView, float (adap), 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, dj, yb, 1);
|
|
} else {
|
|
double dd, dj;
|
|
ipf.ciecam_02(cieView, adap, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, dj, 1);
|
|
}
|
|
} else {
|
|
if (settings->ciecamfloat) {
|
|
float d, dj, yb;
|
|
ipf.ciecam_02float(cieView, float (adap), 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, dj, yb, 1);
|
|
} else {
|
|
double dd, dj;
|
|
ipf.ciecam_02(cieView, adap, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, dj, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete cieView;
|
|
cieView = nullptr;
|
|
|
|
|
|
|
|
|
|
// end tile processing...???
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.60);
|
|
}
|
|
|
|
int imw, imh;
|
|
double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh);
|
|
bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0;
|
|
LabImage *tmplab;
|
|
|
|
// crop and convert to rgb16
|
|
int cx = 0, cy = 0, cw = labView->W, ch = labView->H;
|
|
|
|
if (params.crop.enabled) {
|
|
cx = params.crop.x;
|
|
cy = params.crop.y;
|
|
cw = params.crop.w;
|
|
ch = params.crop.h;
|
|
|
|
if (labResize) { // crop lab data
|
|
tmplab = new LabImage(cw, ch);
|
|
|
|
for (int row = 0; row < ch; row++) {
|
|
for (int col = 0; col < cw; col++) {
|
|
tmplab->L[row][col] = labView->L[row + cy][col + cx];
|
|
tmplab->a[row][col] = labView->a[row + cy][col + cx];
|
|
tmplab->b[row][col] = labView->b[row + cy][col + cx];
|
|
}
|
|
}
|
|
|
|
delete labView;
|
|
labView = tmplab;
|
|
cx = 0;
|
|
cy = 0;
|
|
}
|
|
}
|
|
|
|
if (labResize) { // resize lab data
|
|
// resize image
|
|
tmplab = new LabImage(imw, imh);
|
|
ipf.Lanczos(labView, tmplab, tmpScale);
|
|
delete labView;
|
|
labView = tmplab;
|
|
cw = labView->W;
|
|
ch = labView->H;
|
|
|
|
if (params.prsharpening.enabled) {
|
|
for (int i = 0; i < ch; i++)
|
|
for (int j = 0; j < cw; j++) {
|
|
labView->L[i][j] = labView->L[i][j] < 0.f ? 0.f : labView->L[i][j];
|
|
}
|
|
|
|
float **buffer = new float*[ch];
|
|
|
|
for (int i = 0; i < ch; i++) {
|
|
buffer[i] = new float[cw];
|
|
}
|
|
|
|
ipf.sharpening(labView, (float**)buffer, params.prsharpening);
|
|
|
|
for (int i = 0; i < ch; i++) {
|
|
delete [] buffer[i];
|
|
}
|
|
|
|
delete [] buffer;
|
|
}
|
|
}
|
|
|
|
Image16* readyImg = nullptr;
|
|
cmsHPROFILE jprof = nullptr;
|
|
bool customGamma = false;
|
|
bool useLCMS = false;
|
|
bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled && !autili && !butili ;
|
|
|
|
if (params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8
|
|
|
|
GammaValues ga;
|
|
// if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
|
|
readyImg = ipf.lab2rgb16(labView, cx, cy, cw, ch, params.icm, &ga);
|
|
customGamma = true;
|
|
|
|
//or selected Free gamma
|
|
useLCMS = false;
|
|
|
|
if ((jprof = ICCStore::getInstance()->createCustomGammaOutputProfile(params.icm, ga)) == nullptr) {
|
|
useLCMS = true;
|
|
}
|
|
|
|
} else {
|
|
// if Default gamma mode: we use the profile selected in the "Output profile" combobox;
|
|
// gamma come from the selected profile, otherwise it comes from "Free gamma" tool
|
|
|
|
readyImg = ipf.lab2rgb16(labView, cx, cy, cw, ch, params.icm);
|
|
|
|
if (settings->verbose) {
|
|
printf("Output profile_: \"%s\"\n", params.icm.output.c_str());
|
|
}
|
|
}
|
|
|
|
delete labView;
|
|
labView = nullptr;
|
|
|
|
// delete reservView;
|
|
// reservView = nullptr;
|
|
|
|
|
|
if (bwonly) { //force BW r=g=b
|
|
if (settings->verbose) {
|
|
printf("Force BW\n");
|
|
}
|
|
|
|
for (int ccw = 0; ccw < cw; ccw++) {
|
|
for (int cch = 0; cch < ch; cch++) {
|
|
readyImg->r(cch, ccw) = readyImg->g(cch, ccw);
|
|
readyImg->b(cch, ccw) = readyImg->g(cch, ccw);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.70);
|
|
}
|
|
|
|
if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied)
|
|
Image16* tempImage = new Image16(imw, imh);
|
|
ipf.resize(readyImg, tempImage, tmpScale);
|
|
delete readyImg;
|
|
readyImg = tempImage;
|
|
}
|
|
|
|
if (tunnelMetaData) {
|
|
// Sending back the whole first root, which won't necessarily be the selected frame number
|
|
// and may contain subframe depending on initial raw's hierarchy
|
|
readyImg->setMetadata(ii->getMetaData()->getRootExifData());
|
|
} else {
|
|
// ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy
|
|
readyImg->setMetadata(ii->getMetaData()->getBestExifData(imgsrc, ¶ms.raw), params.exif, params.iptc);
|
|
}
|
|
|
|
|
|
// Setting the output curve to readyImg
|
|
if (customGamma) {
|
|
if (!useLCMS) {
|
|
// use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma
|
|
ProfileContent pc(jprof);
|
|
readyImg->setOutputProfile(pc.getData().c_str(), pc.getData().size());
|
|
}
|
|
} else {
|
|
// use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma
|
|
|
|
if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) {
|
|
|
|
// if ICCStore::getInstance()->getProfile send back an object, then ICCStore::getInstance()->getContent will do too
|
|
cmsHPROFILE jprof = ICCStore::getInstance()->getProfile(params.icm.output); //get outProfile
|
|
|
|
if (jprof == nullptr) {
|
|
if (settings->verbose) {
|
|
printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", params.icm.output.c_str());
|
|
}
|
|
} else {
|
|
if (settings->verbose) {
|
|
printf("Using \"%s\" output profile\n", params.icm.output.c_str());
|
|
}
|
|
|
|
ProfileContent pc = ICCStore::getInstance()->getContent(params.icm.output);
|
|
readyImg->setOutputProfile(pc.getData().c_str(), pc.getData().size());
|
|
}
|
|
} else {
|
|
// No ICM
|
|
readyImg->setOutputProfile(nullptr, 0);
|
|
}
|
|
}
|
|
|
|
// t2.set();
|
|
// if( settings->verbose )
|
|
// printf("Total:- %d usec\n", t2.etime(t1));
|
|
|
|
if (!job->initialImage) {
|
|
ii->decreaseRef();
|
|
}
|
|
|
|
delete job;
|
|
|
|
if (pl) {
|
|
pl->setProgress(0.75);
|
|
}
|
|
|
|
/* curve1.reset();curve2.reset();
|
|
curve.reset();
|
|
satcurve.reset();
|
|
lhskcurve.reset();
|
|
|
|
rCurve.reset();
|
|
gCurve.reset();
|
|
bCurve.reset();
|
|
hist16.reset();
|
|
hist16C.reset();
|
|
*/
|
|
return readyImg;
|
|
}
|
|
|
|
void stage_early_resize()
|
|
{
|
|
procparams::ProcParams& params = job->pparams;
|
|
//ImProcFunctions ipf (¶ms, true);
|
|
ImProcFunctions &ipf = * (ipf_p.get());
|
|
|
|
int imw, imh;
|
|
double scale_factor = ipf.resizeScale(¶ms, fw, fh, imw, imh);
|
|
|
|
std::unique_ptr<LabImage> tmplab(new LabImage(fw, fh));
|
|
ipf.rgb2lab(*baseImg, *tmplab, params.icm.working);
|
|
|
|
if (params.crop.enabled) {
|
|
int cx = params.crop.x;
|
|
int cy = params.crop.y;
|
|
int cw = params.crop.w;
|
|
int ch = params.crop.h;
|
|
|
|
std::unique_ptr<LabImage> cropped(new LabImage(cw, ch));
|
|
|
|
for (int row = 0; row < ch; row++) {
|
|
for (int col = 0; col < cw; col++) {
|
|
cropped->L[row][col] = tmplab->L[row + cy][col + cx];
|
|
cropped->a[row][col] = tmplab->a[row + cy][col + cx];
|
|
cropped->b[row][col] = tmplab->b[row + cy][col + cx];
|
|
}
|
|
}
|
|
|
|
tmplab = std::move(cropped);
|
|
}
|
|
|
|
assert(params.resize.enabled);
|
|
|
|
// resize image
|
|
{
|
|
std::unique_ptr<LabImage> resized(new LabImage(imw, imh));
|
|
ipf.Lanczos(tmplab.get(), resized.get(), scale_factor);
|
|
tmplab = std::move(resized);
|
|
}
|
|
|
|
adjust_procparams(scale_factor);
|
|
|
|
fw = imw;
|
|
fh = imh;
|
|
|
|
delete baseImg;
|
|
baseImg = new Imagefloat(fw, fh);
|
|
ipf.lab2rgb(*tmplab, *baseImg, params.icm.working);
|
|
}
|
|
|
|
void adjust_procparams(double scale_factor)
|
|
{
|
|
procparams::ProcParams ¶ms = job->pparams;
|
|
procparams::ProcParams defaultparams;
|
|
|
|
params.resize.enabled = false;
|
|
params.crop.enabled = false;
|
|
|
|
if (params.prsharpening.enabled) {
|
|
params.sharpening = params.prsharpening;
|
|
} else {
|
|
adjust_radius(defaultparams.sharpening.radius, scale_factor,
|
|
params.sharpening.radius);
|
|
}
|
|
|
|
params.impulseDenoise.thresh *= scale_factor;
|
|
|
|
if (scale_factor < 0.5) {
|
|
params.impulseDenoise.enabled = false;
|
|
}
|
|
|
|
params.wavelet.strength *= scale_factor;
|
|
params.dirpyrDenoise.luma *= scale_factor;
|
|
//params.dirpyrDenoise.Ldetail += (100 - params.dirpyrDenoise.Ldetail) * scale_factor;
|
|
auto &lcurve = params.dirpyrDenoise.lcurve;
|
|
|
|
for (size_t i = 2; i < lcurve.size(); i += 4) {
|
|
lcurve[i] *= min(scale_factor * 2, 1.0);
|
|
}
|
|
|
|
noiseLCurve.Set(lcurve);
|
|
const char *medmethods[] = { "soft", "33", "55soft", "55", "77", "99" };
|
|
|
|
if (params.dirpyrDenoise.median) {
|
|
auto &key = params.dirpyrDenoise.methodmed == "RGB" ? params.dirpyrDenoise.rgbmethod : params.dirpyrDenoise.medmethod;
|
|
|
|
for (int i = 1; i < int (sizeof(medmethods) / sizeof(const char *)); ++i) {
|
|
if (key == medmethods[i]) {
|
|
int j = i - int (1.0 / scale_factor);
|
|
|
|
if (j < 0) {
|
|
params.dirpyrDenoise.median = false;
|
|
} else {
|
|
key = medmethods[j];
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
params.epd.scale *= scale_factor;
|
|
//params.epd.edgeStopping *= scale_factor;
|
|
|
|
const double dirpyreq_scale = min(scale_factor * 1.5, 1.0);
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
adjust_radius(defaultparams.dirpyrequalizer.mult[i], dirpyreq_scale,
|
|
params.dirpyrequalizer.mult[i]);
|
|
}
|
|
|
|
params.dirpyrequalizer.threshold *= scale_factor;
|
|
|
|
adjust_radius(defaultparams.defringe.radius, scale_factor,
|
|
params.defringe.radius);
|
|
adjust_radius(defaultparams.sh.radius, scale_factor, params.sh.radius);
|
|
|
|
if (params.raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::THREE_PASS)) {
|
|
params.raw.xtranssensor.method = procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::ONE_PASS);
|
|
}
|
|
|
|
if (params.raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) {
|
|
params.raw.bayersensor.method = procparams::RAWParams::BayerSensor::getMethodString(params.raw.bayersensor.pixelShiftLmmse ? procparams::RAWParams::BayerSensor::Method::LMMSE : procparams::RAWParams::BayerSensor::Method::AMAZE);
|
|
}
|
|
}
|
|
|
|
private:
|
|
ProcessingJobImpl* job;
|
|
int& errorCode;
|
|
ProgressListener* pl;
|
|
bool tunnelMetaData;
|
|
bool flush;
|
|
|
|
// internal state
|
|
std::unique_ptr<ImProcFunctions> ipf_p;
|
|
InitialImage *ii;
|
|
ImageSource *imgsrc;
|
|
int fw;
|
|
int fh;
|
|
|
|
int tr;
|
|
PreviewProps pp;
|
|
|
|
NoiseCurve noiseLCurve;
|
|
NoiseCurve noiseCCurve;
|
|
Imagefloat *calclum;
|
|
float autoNR;
|
|
float autoNRmax;
|
|
int tilesize;
|
|
int overlap;
|
|
|
|
float *ch_M;
|
|
float *max_r;
|
|
float *max_b;
|
|
float *min_b;
|
|
float *min_r;
|
|
float *lumL;
|
|
float *chromC;
|
|
float *ry;
|
|
float *sk;
|
|
float *pcsk;
|
|
|
|
double expcomp;
|
|
int bright;
|
|
int contr;
|
|
int black;
|
|
int hlcompr;
|
|
int hlcomprthresh;
|
|
|
|
ColorTemp currWB;
|
|
Imagefloat *baseImg;
|
|
LabImage* labView;
|
|
LabImage* reservView;
|
|
|
|
LUTu hist16;
|
|
|
|
LUTf curve1;
|
|
LUTf curve2;
|
|
LUTf curve;
|
|
LUTf satcurve;
|
|
LUTf lhskcurve;
|
|
LUTf lumacurve;
|
|
LUTf clcurve;
|
|
LUTf clToningcurve;
|
|
LUTf cl2Toningcurve;
|
|
LUTf wavclCurve;
|
|
|
|
LUTf rCurve;
|
|
LUTf gCurve;
|
|
LUTf bCurve;
|
|
LUTu dummy;
|
|
|
|
ToneCurve customToneCurve1, customToneCurve2;
|
|
ColorGradientCurve ctColorCurve;
|
|
OpacityCurve ctOpacityCurve;
|
|
ColorAppearance customColCurve1, customColCurve2, customColCurve3 ;
|
|
ToneCurve customToneCurvebw1;
|
|
ToneCurve customToneCurvebw2;
|
|
|
|
bool autili, butili;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
IImage16* processImage(ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush)
|
|
{
|
|
ImageProcessor proc(pjob, errorCode, pl, tunnelMetaData, flush);
|
|
return proc();
|
|
}
|
|
|
|
void batchProcessingThread(ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData)
|
|
{
|
|
|
|
ProcessingJob* currentJob = job;
|
|
|
|
while (currentJob) {
|
|
int errorCode;
|
|
IImage16* img = processImage(currentJob, errorCode, bpl, tunnelMetaData, true);
|
|
|
|
if (errorCode) {
|
|
bpl->error(M("MAIN_MSG_CANNOTLOAD"));
|
|
currentJob = nullptr;
|
|
} else {
|
|
try {
|
|
currentJob = bpl->imageReady(img);
|
|
} catch (Glib::Exception& ex) {
|
|
bpl->error(ex.what());
|
|
currentJob = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void startBatchProcessing(ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData)
|
|
{
|
|
|
|
if (bpl) {
|
|
Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl, tunnelMetaData), 0, true, true, Glib::THREAD_PRIORITY_LOW);
|
|
}
|
|
|
|
}
|
|
|
|
}
|