/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * 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 . * 2016 Jacques Desmis * 2016 Ingo Weyrich */ #include #include #include #include "rtengine.h" #include "improcfun.h" #include "curves.h" #include "gauss.h" #include "iccstore.h" #include "iccmatrices.h" #include "color.h" #include "rt_math.h" #ifdef _DEBUG #include "mytime.h" #endif #include "cplx_wavelet_dec.h" //#define BENCHMARK //#include "StopWatch.h" #define cliploc( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val ) #define CLIPC(a) ((a)>-42000?((a)<42000?(a):42000):-42000) // limit a and b to 130 probably enough ? #define CLIPL(x) LIM(x,0.f,40000.f) // limit L to about L=120 probably enough ? #define CLIPLOC(x) LIM(x,0.f,32767.f) #define CLIPLIG(x) LIM(x,0.f, 99.5f) #define CLIPCHRO(x) LIM(x,0.f, 140.f) #define CLIPRET(x) LIM(x,-99.5f, 99.5f) namespace rtengine { using namespace procparams; extern const Settings* settings; struct local_params { float yc, xc; float lx, ly; float lxL, lyT; float dxx, dyy; float iterat; int cir; float thr; int prox; int chro, cont, sens, sensh, senscb, sensbn, senstm; float ligh; int shamo, shdamp, shiter, senssha; double shrad; double rad; double stren; int trans; bool inv; bool curvact; bool invrad; bool invret; bool invshar; bool actsp; float str; int qualmet; int qualcurvemet; float noiself; float noiselc; float noisecf; float noisecc; float mulloc[5]; float threshol; float strengt; float gamm; float esto; float scalt; float rewe; bool colorena; bool blurena; bool tonemapena; bool retiena; bool sharpena; bool cbdlena; bool denoiena; }; static void calcLocalParams (int oW, int oH, const LocallabParams& locallab, struct local_params& lp) { int w = oW; int h = oH; int circr = locallab.circrad; float streng = ((float)locallab.stren) / 100.f; float gam = ((float)locallab.gamma) / 100.f; float est = ((float)locallab.estop) / 100.f; float scal_tm = ((float)locallab.scaltm) / 10.f; float rewe = ((float)locallab.rewei); float thre = locallab.thres / 100.f; double local_x = locallab.locX / 2000.0; double local_y = locallab.locY / 2000.0; double local_xL = locallab.locXL / 2000.0; double local_yT = locallab.locYT / 2000.0; double local_center_x = locallab.centerX / 2000.0 + 0.5; double local_center_y = locallab.centerY / 2000.0 + 0.5; double local_dxx = locallab.proxi / 8000.0;//for proxi = 2==> # 1 pixel double local_dyy = locallab.proxi / 8000.0; float iterati = (float) locallab.proxi; // double local_dyy = locallab.proxi; if (locallab.qualityMethod == "std") { lp.qualmet = 0; } else if (locallab.qualityMethod == "enh") { lp.qualmet = 1; } else if (locallab.qualityMethod == "enhden") { lp.qualmet = 2; } if (locallab.qualitycurveMethod == "none") { lp.qualcurvemet = 0; } else if (locallab.qualitycurveMethod == "std") { lp.qualcurvemet = 1; } else if (locallab.qualitycurveMethod == "enh") { lp.qualcurvemet = 2; } float local_noiself = locallab.noiselumf; float local_noiselc = locallab.noiselumc; float local_noisecf = locallab.noisechrof; float local_noisecc = locallab.noisechroc; float multi[5]; for (int y = 0; y < 5; y++) { multi[y] = ((float) locallab.mult[y]) / 100.f; } float thresho = ((float)locallab.threshold ) / 100.f; int local_chroma = locallab.chroma; int local_sensi = locallab.sensi; int local_sensibn = locallab.sensibn; int local_sensitm = locallab.sensitm; int local_sensih = locallab.sensih; int local_sensicb = locallab.sensicb; int local_contrast = locallab.contrast; float local_lightness = (float) locallab.lightness; int local_transit = locallab.transit; double radius = (double) locallab.radius; double sharradius = ((double) locallab.sharradius) / 100. ; int local_sensisha = locallab.sensisha; int local_sharamount = locallab.sharamount; int local_shardamping = locallab.shardamping; int local_shariter = locallab.shariter; bool inverse = locallab.invers; bool curvacti = locallab.curvactiv; bool acti = locallab.activlum; bool inverserad = locallab.inversrad; bool inverseret = locallab.inversret; bool inversesha = locallab.inverssha; double strength = (double) locallab.strength; float str = (float)locallab.str; lp.cir = circr; lp.actsp = acti; lp.xc = w * local_center_x; lp.yc = h * local_center_y; lp.lx = w * local_x; lp.ly = h * local_y; lp.lxL = w * local_xL; lp.lyT = h * local_yT; lp.chro = local_chroma; lp.sens = local_sensi; lp.sensh = local_sensih; lp.senscb = local_sensicb; lp.cont = local_contrast; lp.ligh = local_lightness; if (lp.ligh >= -2.f && lp.ligh <= 2.f) { lp.ligh /= 5.f; } lp.trans = local_transit; lp.rad = radius; lp.stren = strength; lp.sensbn = local_sensibn; lp.inv = inverse; lp.curvact = curvacti; lp.invrad = inverserad; lp.invret = inverseret; lp.invshar = inversesha; lp.str = str; lp.shrad = sharradius; lp.senssha = local_sensisha; lp.shamo = local_sharamount; lp.shdamp = local_shardamping; lp.shiter = local_shariter; lp.iterat = iterati; lp.dxx = w * local_dxx; lp.dyy = h * local_dyy; lp.thr = thre; lp.noiself = local_noiself; lp.noiself = local_noiself; lp.noiselc = local_noiselc; lp.noisecf = local_noisecf; lp.noisecc = local_noisecc; lp.strengt = streng; lp.gamm = gam; lp.esto = est; lp.scalt = scal_tm; lp.rewe = rewe; lp.senstm = local_sensitm; for (int y = 0; y < 5; y++) { lp.mulloc[y] = multi[y]; } lp.threshol = thresho; lp.colorena = locallab.expcolor; lp.blurena = locallab.expblur; lp.tonemapena = locallab.exptonemap; lp.retiena = locallab.expreti; lp.sharpena = locallab.expsharp; lp.cbdlena = locallab.expcbdl; lp.denoiena = locallab.expdenoi; } inline static float calcLocalFactor (const float lox, const float loy, const float lcx, const float dx, const float lcy, const float dy, const float ach) { //elipse x2/a2 + y2/b2=1 //transition elipsoidal //x==>lox y==>loy // a==> dx b==>dy float kelip = dx / dy; float belip = sqrt ((SQR ((lox - lcx) / kelip) + SQR (loy - lcy))); //determine position ellipse ==> a and b float aelip = belip * kelip; float degrad = aelip / dx; float ap = M_PI / (1.f - ach); float bp = M_PI - ap; return 0.5f * (1.f + xcosf (degrad * ap + bp)); //trigo cos transition } static void calcTransition (const float lox, const float loy, const float ach, const local_params& lp, int &zone, float &localFactor) { // returns the zone (0 = outside selection, 1 = transition zone between outside and inside selection, 2 = inside selection) // and a factor to calculate the transition in case zone == 1 zone = 0; if (lox >= lp.xc && lox < (lp.xc + lp.lx) && loy >= lp.yc && loy < lp.yc + lp.ly) { zone = ( (SQR (lox - lp.xc) / SQR (ach * lp.lx) + SQR (loy - lp.yc) / SQR (ach * lp.ly)) < 1.f) ? 2 : 0; if (!zone) { zone = (((SQR (lox - lp.xc) / SQR (ach * lp.lx) + SQR (loy - lp.yc) / SQR (ach * lp.ly)) > 1.f) && ((SQR (lox - lp.xc) / SQR (lp.lx) + SQR (loy - lp.yc) / SQR (lp.ly)) < 1.f)) ? 1 : 0; if (zone) { localFactor = calcLocalFactor (lox, loy, lp.xc, lp.lx, lp.yc, lp.ly, ach); } } } else if (lox >= lp.xc && lox < lp.xc + lp.lx && loy < lp.yc && loy > lp.yc - lp.lyT) { zone = (SQR (lox - lp.xc) / SQR (ach * lp.lx) + SQR (loy - lp.yc) / SQR (ach * lp.lyT)) < 1.f ? 2 : 0; if (!zone) { zone = (((SQR (lox - lp.xc) / SQR (ach * lp.lx) + SQR (loy - lp.yc) / SQR (ach * lp.lyT)) > 1.f) && ((SQR (lox - lp.xc) / SQR (lp.lx) + SQR (loy - lp.yc) / SQR (lp.lyT)) < 1.f)) ? 1 : 0; if (zone) { localFactor = calcLocalFactor (lox, loy, lp.xc, lp.lx, lp.yc, lp.lyT, ach); } } } else if (lox < lp.xc && lox > lp.xc - lp.lxL && loy <= lp.yc && loy > lp.yc - lp.lyT) { zone = (SQR (lox - lp.xc) / SQR (ach * lp.lxL) + SQR (loy - lp.yc) / SQR (ach * lp.lyT)) < 1.f ? 2 : 0; if (!zone) { zone = (((SQR (lox - lp.xc) / SQR (ach * lp.lxL) + SQR (loy - lp.yc) / SQR (ach * lp.lyT)) > 1.f) && ((SQR (lox - lp.xc) / SQR (lp.lxL) + SQR (loy - lp.yc) / SQR (lp.lyT)) < 1.f)) ? 1 : 0; if (zone) { localFactor = calcLocalFactor (lox, loy, lp.xc, lp.lxL, lp.yc, lp.lyT, ach); } } } else if (lox < lp.xc && lox > lp.xc - lp.lxL && loy > lp.yc && loy < lp.yc + lp.ly) { zone = (SQR (lox - lp.xc) / SQR (ach * lp.lxL) + SQR (loy - lp.yc) / SQR (ach * lp.ly)) < 1.f ? 2 : 0; if (!zone) { zone = (((SQR (lox - lp.xc) / SQR (ach * lp.lxL) + SQR (loy - lp.yc) / SQR (ach * lp.ly)) > 1.f) && ((SQR (lox - lp.xc) / SQR (lp.lxL) + SQR (loy - lp.yc) / SQR (lp.ly)) < 1.f)) ? 1 : 0; if (zone) { localFactor = calcLocalFactor (lox, loy, lp.xc, lp.lxL, lp.yc, lp.ly, ach); } } } } void ImProcFunctions::strcurv_data (std::string retistr, int *s_datc, int &siz) { 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", "&", "#", "{", "[", "]", "}", "$", "*", "?", ">", "!", ";", "<", "(", ")", "+", "-" }; int s_size; std::size_t posend = retistr.find ("@"); std::string strend = retistr.substr (posend - 1, 1); // printf("stren=%s posz=%i\n", strend.c_str(), posz); int longe; for (int sl = 0; sl < 69; sl++) { if (delim[sl] == strend) { longe = sl + 1; } } s_size = longe; // printf("sp=%i stren=%s reti=%s long=%i\n", sp, strend.c_str(), retistr[sp].c_str(), longe); int s_cur[s_size + 1]; int s_datcu[s_size + 1]; std::size_t pose[s_size + 1]; std::size_t valstr[s_size + 1]; pose[0] = -1; for (int z = 1; z < s_size + 1; z++) { pose[z] = retistr.find (delim[z - 1]); } for (int z = 1; z < s_size + 1; z++) { std::string sval = retistr.substr (pose[z - 1] + 1, (pose[z] - pose[z - 1])); s_datc[z - 1] = s_datcu[z - 1] = std::stoi (sval.c_str()); } /* //here to verify process is good std::string cur_str = ""; for(int j = 0; j < s_size; j++) { cur_str = cur_str + std::to_string(s_datcu[j]) + delim[j]; } printf("calc str=%s\n", cur_str.c_str()); */ siz = longe; } void ImProcFunctions::addGaNoise (LabImage *lab, LabImage *dst, const float mean, const float variance, const int sk) { // BENCHFUN //Box-Muller method. // add luma noise to image srand (1); const float variaFactor = SQR (variance) / sk; const float randFactor = 1.f / RAND_MAX; #ifdef _OPENMP #pragma omp parallel #endif { float z0, z1; bool generate = false; #ifdef _OPENMP #pragma omp for schedule(static) // static scheduling is important to avoid artefacts #endif for (int y = 0; y < lab->H; y++) { for (int x = 0; x < lab->W; x++) { generate = !generate; float kvar = 1.f; if (lab->L[y][x] < 12000.f) { constexpr float ah = -0.5f / 12000.f; constexpr float bh = 1.5f; kvar = ah * lab->L[y][x] + bh; //increase effect for low lights < 12000.f } else if (lab->L[y][x] > 20000.f) { constexpr float ah = -0.5f / 12768.f; constexpr float bh = 1.f - 20000.f * ah; kvar = ah * lab->L[y][x] + bh; //decrease effect for high lights > 20000.f kvar = kvar < 0.5f ? 0.5f : kvar; } float varia = SQR (kvar) * variaFactor; if (!generate) { dst->L[y][x] = LIM (lab->L[y][x] + mean + varia * z1, 0.f, 32768.f); continue; } int u1 = 0; int u2; while (u1 == 0) { u1 = rand(); u2 = rand(); } float u1f = u1 * randFactor; float u2f = u2 * randFactor; float2 sincosval = xsincosf (2.f * M_PI * u2f); float factor = sqrtf (-2.f * xlogf (u1f)); z0 = factor * sincosval.y; z1 = factor * sincosval.x; dst->L[y][x] = LIM (lab->L[y][x] + mean + varia * z0, 0.f, 32768.f); } } } } void ImProcFunctions::DeNoise_Local (int call, const struct local_params& lp, LabImage* original, LabImage* transformed, const LabImage* const tmp1, int cx, int cy) { // local denoise // BENCHFUN const float ach = (float)lp.trans / 100.f; #pragma omp parallel for schedule(dynamic,16) if (multiThread) for (int y = 0; y < transformed->H; y++) { int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; break; } case 1: { // inside transition zone float factorx = localFactor; float difL, difa, difb; if (call == 2) { //simpleprocess if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; } } else { //dcrop difL = tmp1->L[y][x] - original->L[y][x]; difa = tmp1->a[y][x] - original->a[y][x]; difb = tmp1->b[y][x] - original->b[y][x]; } difL *= factorx; difa *= factorx; difb *= factorx; transformed->L[y][x] = original->L[y][x] + difL; transformed->a[y][x] = original->a[y][x] + difa; transformed->b[y][x] = original->b[y][x] + difb; break; } case 2: { // inside selection => full effect, no transition float difL, difa, difb; if (call == 2) { //simpleprocess if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; } } else { //dcrop difL = tmp1->L[y][x] - original->L[y][x]; difa = tmp1->a[y][x] - original->a[y][x]; difb = tmp1->b[y][x] - original->b[y][x]; } transformed->L[y][x] = original->L[y][x] + difL; transformed->a[y][x] = original->a[y][x] + difa; transformed->b[y][x] = original->b[y][x] + difb; } } } } } void ImProcFunctions::cbdl_Local (int call, int sp, float ** buflight, float **loctemp, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { //local CBDL // BENCHFUN const float localtype = lumaref; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.senscb < 30.f) { reducac = 0.2f * (lp.senscb / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.senscb / 100.f) + breduc; } constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.senscb - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.senscb; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif int zone; //retrieve data float cli = 1.f; // if (lp.curvact == true) { cli = (buflight[loy - begy][lox - begx]); // } //parameters for linear interpolation in function of real hue float apluscligh = (1.f - cli) / delhu; float bpluscligh = 1.f - apluscligh * hueplus; float amoinscligh = (cli - 1.f) / delhu; float bmoinscligh = 1.f - amoinscligh * huemoins; float realcligh = 1.f; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.senscb / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.senscb / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.senscb < 40.f ) { kch = pow (kch, pa * lp.senscb + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.senscb < 100.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { khu = amo * rhue + bmo; realcligh = amoinscligh * rhue + bmoinscligh; } else { khu = 1.f; realcligh = cli; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; realcligh = amoinscligh * rhue + bmoinscligh; } else { khu = 1.f; realcligh = cli; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { realcligh = cli; khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; realcligh = amoinscligh * rhue + bmoinscligh; } else { khu = 1.f; realcligh = cli; } kzon = true; } if (deltaE < 2.8f * lp.senscb) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet == 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { /* float kcr = 8.f; if(lp.senssha > 30.f){ if (rchro < kcr) { fach *= (1.f / (kcr)) * rchro; } } */ } float fli = ((100.f + realcligh) / 100.f);//luma transition float kcr = 100.f * lp.thr; float falL = 1.f; if (rchro < kcr && chromaref > kcr) { // reduce artifacts in grey tones near hue spot and improve algorithm falL *= pow (rchro / kcr, lp.iterat / 10.f); } switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; break; } case 1: { // inside transition zone float factorx = localFactor; float difL = 0.f; difL = loctemp[loy - begy][lox - begx] * fli * falL - original->L[y][x]; //float difL = loctemp[y][x] - original->L[y][x]; difL *= factorx; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; break; } case 2: { // inside selection => full effect, no transition float difL = 0.f; difL = loctemp[loy - begy][lox - begx] * fli * falL - original->L[y][x]; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; } } } } } } } void ImProcFunctions::TM_Local (int call, int sp, LabImage * tmp1, float **buflight, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { //local TM // BENCHFUN const float localtype = lumaref; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.senstm < 30.f) { reducac = 0.2f * (lp.senstm / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.senstm / 100.f) + breduc; } constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.senstm - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.senstm; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif int zone; //retrieve data float cli = 1.f; // if (lp.curvact == true) { cli = (buflight[loy - begy][lox - begx]); // } //parameters for linear interpolation in function of real hue float apluscligh = (1.f - cli) / delhu; float bpluscligh = 1.f - apluscligh * hueplus; float amoinscligh = (cli - 1.f) / delhu; float bmoinscligh = 1.f - amoinscligh * huemoins; float realcligh = 1.f; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.senstm / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.senstm / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.senstm < 40.f ) { kch = pow (kch, pa * lp.senstm + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.senstm < 100.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { khu = 1.f; realcligh = cli; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; realcligh = amoinscligh * rhue + bmoinscligh; } else { khu = 1.f; realcligh = cli; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { khu = 1.f; realcligh = cli; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { khu = 1.f; realcligh = cli; } kzon = true; } if (deltaE < 2.8f * lp.senstm) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet == 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { } float fli = ((100.f + realcligh) / 100.f);//luma transition float kcr = 100.f * lp.thr; float falL = 1.f; if (rchro < kcr && chromaref > kcr) { // reduce artifacts in grey tones near hue spot and improve algorithm falL *= pow (rchro / kcr, lp.iterat / 10.f); } switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; break; } case 1: { // inside transition zone float factorx = localFactor; float difL, difa, difb; difL = tmp1->L[loy - begy][lox - begx] * fli * falL - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; difL *= factorx; difa *= factorx; difb *= factorx; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; transformed->a[y][x] = original->a[y][x] + difa * kch * fach;//same as Luma transformed->b[y][x] = original->b[y][x] + difb * kch * fach;//same as Luma break; } case 2: { // inside selection => full effect, no transition float difL, difa, difb; difL = tmp1->L[loy - begy][lox - begx] * fli * falL - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; transformed->a[y][x] = original->a[y][x] + difa * kch * fach;//same as Luma transformed->b[y][x] = original->b[y][x] + difb * kch * fach;//same as Luma } } } } } } } void ImProcFunctions::BlurNoise_Local (int call, int sp, LabImage * tmp1, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { //local BLUR // BENCHFUN const float localtype = lumaref; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.sensbn < 30.f) { reducac = 0.2f * (lp.sensbn / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.sensbn / 100.f) + breduc; } constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.sensbn - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.sensbn; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif int zone; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.sensbn / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.sensbn / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.sensbn < 40.f ) { kch = pow (kch, pa * lp.sensbn + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.sensbn < 20.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if (deltaE < 2.8f * lp.sensbn) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet == 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { } int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; if (!lp.actsp) { transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; } break; } case 1: { // inside transition zone float factorx = localFactor; float difL, difa, difb; if (call == 2) { if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; } } else { difL = tmp1->L[y][x] - original->L[y][x]; difa = tmp1->a[y][x] - original->a[y][x]; difb = tmp1->b[y][x] - original->b[y][x]; } difL *= factorx; difa *= factorx; difb *= factorx; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; if (!lp.actsp) { transformed->a[y][x] = original->a[y][x] + difa * kch * fach;//same as Luma transformed->b[y][x] = original->b[y][x] + difb * kch * fach;//same as Luma } break; } case 2: { // inside selection => full effect, no transition float difL, difa, difb; if (call == 2) { if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { // bufsh[loy - begy - 1][lox - begx - 1] difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; } } else { difL = tmp1->L[y][x] - original->L[y][x]; difa = tmp1->a[y][x] - original->a[y][x]; difb = tmp1->b[y][x] - original->b[y][x]; } transformed->L[y][x] = original->L[y][x] + difL * kch * fach; if (!lp.actsp) { transformed->a[y][x] = original->a[y][x] + difa * kch * fach;//same as Luma transformed->b[y][x] = original->b[y][x] + difb * kch * fach;//same as Luma } } } } } } } void ImProcFunctions::InverseReti_Local (const struct local_params & lp, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy, int chro) { // BENCHFUN //inverse local retinex float ach = (float)lp.trans / 100.f; #pragma omp parallel for schedule(dynamic,16) if (multiThread) for (int y = 0; y < transformed->H; y++) { int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); switch (zone) { case 0: { // outside selection and outside transition zone => full effect, no transition if (chro == 0) { transformed->L[y][x] = tmp1->L[y][x]; } if (chro == 1) { transformed->a[y][x] = tmp1->a[y][x]; transformed->b[y][x] = tmp1->b[y][x]; } break; } case 1: { // inside transition zone float factorx = 1.f - localFactor; if (chro == 0) { float difL = tmp1->L[y][x] - original->L[y][x]; difL *= factorx; transformed->L[y][x] = original->L[y][x] + difL; } if (chro == 1) { float difa = tmp1->a[y][x] - original->a[y][x]; float difb = tmp1->b[y][x] - original->b[y][x]; difa *= factorx; difb *= factorx; transformed->a[y][x] = original->a[y][x] + difa; transformed->b[y][x] = original->b[y][x] + difb; } break; } case 2: { // inside selection => no effect, keep original values if (chro == 0) { transformed->L[y][x] = original->L[y][x]; } if (chro == 1) { transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; } } } } } } void ImProcFunctions::Reti_Local (int call, float **buflight, float **bufchro, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const struct local_params & lp, float **deltE, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy, int chro) { //local retinex //BENCHFUN { const float ach = (float)lp.trans / 100.f; //chroma constexpr float amplchsens = 2.5f; constexpr float achsens = (amplchsens - 1.f) / (100.f - 20.f); //20. default locallab.sensih constexpr float bchsens = 1.f - 20.f * achsens; const float multchro = lp.sensh * achsens + bchsens; //luma constexpr float ampllumsens = 2.f; constexpr float alumsens = (ampllumsens - 1.f) / (100.f - 20.f); //20. default locallab.sensih constexpr float blumsens = 1.f - 20.f * alumsens; const float multlum = lp.sensh * alumsens + blumsens; //skin constexpr float amplchsensskin = 1.6f; constexpr float achsensskin = (amplchsensskin - 1.f) / (100.f - 20.f); //20. default locallab.sensih constexpr float bchsensskin = 1.f - 20.f * achsensskin; const float multchroskin = lp.sensh * achsensskin + bchsensskin; //transition = difficult to avoid artifact with scope on flat area (sky...) float strn = lp.str / 1.f; // we can chnage 1.f by 2 or...to chnage effect constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.sensh - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.sensh; const float alum = 1.f / (lp.sensh - 100.f); const float blum = 1.f - alum * lp.sensh; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif float rL = original->L[y][x] / 327.68f; float eps = 0.f; if (fabs (original->b[y][x]) < 0.001f) { eps = 0.01f; } float cli = 1.f; float clc = 1.f; // if (lp.curvact == true) { cli = (buflight[loy - begy][lox - begx]); clc = (bufchro[loy - begy][lox - begx]); // } else { // cli = lp.str; // clc = params->locallab.chrrt; // } float aplus = (1.f - cli) / delhu; float bplus = 1.f - aplus * hueplus; float amoins = (cli - 1.f) / delhu; float bmoins = 1.f - amoins * huemoins; float aplusch = (1.f - clc) / delhu; float bplusch = 1.f - aplusch * hueplus; float amoinsch = (clc - 1.f) / delhu; float bmoinsch = 1.f - amoinsch * huemoins; float kab = original->a[y][x] / (original->b[y][x] + eps); float realstr = 1.f; float realstrch = 1.f; //prepare shape detection float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //between 0 and 280 float deltaL = fabs (lumaref - rL); //between 0 and 100 float kch = 1.f; float khu = 0.f; float fach = 1.f; float falu = 1.f; if (deltachro < 160.f * SQR (lp.sensh / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.sensh / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.sensh < 40.f ) { kch = pow (kch, pa * lp.sensh + pb); //increase under 40 } bool kzon = false; //transition = difficult to avoid artifact with scope on flat area (sky...) //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu) { realstr = aplus * rhue + bplus; realstrch = aplusch * rhue + bplusch; khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { realstr = amoins * rhue + bmoins; realstrch = amoinsch * rhue + bmoinsch; khu = amo * rhue + bmo; } else { realstr = cli; khu = 1.f; realstrch = clc; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realstr = aplus * rhue + bplus; realstrch = aplusch * rhue + bplusch; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realstr = amoins * rhue + bmoins; realstrch = amoinsch * rhue + bmoinsch; khu = amo * rhue + bmo; } else { realstr = cli; khu = 1.f; realstrch = clc; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins) { if (rhue >= hueplus - delhu && rhue < hueplus) { realstr = aplus * rhue + bplus; realstrch = aplusch * rhue + bplusch; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realstr = amoins * rhue + bmoins; realstrch = amoinsch * rhue + bmoinsch; khu = amo * rhue + bmo; } else { realstr = cli; khu = 1.f; realstrch = clc; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realstr = aplus * rhue + bplus; realstrch = aplusch * rhue + bplusch; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realstr = amoins * rhue + bmoins; realstrch = amoinsch * rhue + bmoinsch; khu = amo * rhue + bmo; } else { realstr = cli; khu = 1.f; realstrch = clc; } kzon = true; } //shape detection for hue chroma and luma if (lp.sensh <= 20.f) { //to try... if (deltaE < 2.8f * lp.sensh) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet >= 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } if (deltaL < lp.sensh) { falu = 1.f; } else { falu = alum * deltaL + blum; } } // float kdiff = 0.f; // I add these functions...perhaps not good if (kzon) { if (lp.sensh < 60.f) { //arbitrary value if (hueref < -1.1f && hueref > -2.8f) { // detect blue sky if (chromaref > 0.f && chromaref < 35.f * multchro) { // detect blue sky if ( (rhue > -2.79f && rhue < -1.11f) && (rchro < 35.f * multchro)) { realstr *= 0.9f; } else { realstr = 1.f; } } } else { realstr = cli; } if (lp.sensh < 50.f) { //&& lp.chro > 0.f if (hueref > -0.1f && hueref < 1.6f) { // detect skin if (chromaref > 0.f && chromaref < 55.f * multchroskin) { // detect skin if ( (rhue > -0.09f && rhue < 1.59f) && (rchro < 55.f * multchroskin)) { realstr *= 0.7f; } else { realstr = 1.f; } } } else { realstr = cli; } } } } float kcr = 100.f * lp.thr; float falL = 1.f; if (rchro < kcr && chromaref > kcr) { // reduce artifacts in grey tones near hue spot and improve algorithm falL *= pow (rchro / kcr, lp.iterat / 10.f); } int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); if (rL > 0.1f) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values if (chro == 0) { transformed->L[y][x] = original->L[y][x]; } if (chro == 1) { transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; } break; } case 1: { // inside transition zone float factorx = localFactor; if (chro == 0) { float difL; difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difL *= factorx * (100.f + realstr * falL) / 100.f; difL *= kch * fach; transformed->L[y][x] = original->L[y][x] + difL; } if (chro == 1) { float difa, difb; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; difa *= factorx * (100.f + realstrch * falu * falL) / 100.f; difb *= factorx * (100.f + realstrch * falu * falL) / 100.f; transformed->a[y][x] = CLIPC (original->a[y][x] + difa); transformed->b[y][x] = CLIPC (original->b[y][x] + difb); } break; } case 2: { // inside selection => full effect, no transition if (chro == 0) { float difL; difL = tmp1->L[loy - begy][lox - begx] - original->L[y][x]; difL *= (100.f + realstr * falL) / 100.f; difL *= kch * fach; transformed->L[y][x] = original->L[y][x] + difL; } if (chro == 1) { float difa, difb; difa = tmp1->a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1->b[loy - begy][lox - begx] - original->b[y][x]; difa *= (100.f + realstrch * falu * falL) / 100.f; difb *= (100.f + realstrch * falu * falL) / 100.f; transformed->a[y][x] = CLIPC (original->a[y][x] + difa); transformed->b[y][x] = CLIPC (original->b[y][x] + difb); } } } } } } } } } } void ImProcFunctions::InverseBlurNoise_Local (const struct local_params & lp, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy) { // BENCHFUN //inverse local blur and noise float ach = (float)lp.trans / 100.f; #pragma omp parallel for schedule(dynamic,16) if (multiThread) for (int y = 0; y < transformed->H; y++) { int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); switch (zone) { case 0: { // outside selection and outside transition zone => full effect, no transition transformed->L[y][x] = tmp1->L[y][x]; if (!lp.actsp) { transformed->a[y][x] = tmp1->a[y][x]; transformed->b[y][x] = tmp1->b[y][x]; } break; } case 1: { // inside transition zone float difL = tmp1->L[y][x] - original->L[y][x]; float difa = tmp1->a[y][x] - original->a[y][x]; float difb = tmp1->b[y][x] - original->b[y][x]; float factorx = 1.f - localFactor; difL *= factorx; difa *= factorx; difb *= factorx; transformed->L[y][x] = original->L[y][x] + difL; if (!lp.actsp) { transformed->a[y][x] = original->a[y][x] + difa; transformed->b[y][x] = original->b[y][x] + difb; } break; } case 2: { // inside selection => no effect, keep original values transformed->L[y][x] = original->L[y][x]; if (!lp.actsp) { transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; } } } } } } struct local_contra { float alsup, blsup; float alsup2, blsup2; float alsup3, blsup3; float alinf; float aDY; float aa; float bb; float aaa, bbb; float ccc; // float DY; float dx, dy; float ah, bh; float al, bl; }; void ImProcFunctions::Contrast_Local (int call, float ave, LabImage * bufcontorig, float ** buflightc, float moy, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, float pm, struct local_contra & lco, float lumaref, float av, const struct local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { // BENCHFUN // contrast - perhaps for 4 areas if need // I tried shmap adaptaed to Lab, but no real gain and artifacts const float localtype = lumaref; // always spot area // const float localtype = ave; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.sens < 30.f) { reducac = 0.2f * (lp.sens / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.sens / 100.f) + breduc; } const float realcox = lco.dx, realcoy = lco.dy; lco.alsup = (-realcox) / (localtype / 2.f); lco.blsup = -lco.alsup * localtype; lco.alsup2 = (realcoy) / (50.f - localtype / 2.f); lco.blsup2 = -lco.alsup2 * localtype; lco.alsup3 = (realcoy) / (localtype / 2.f - 50.f); lco.blsup3 = -lco.alsup3 * 100.f; lco.aDY = realcoy; constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.sens - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.sens; lco.alinf = realcox / (localtype / 2.f); const float vi = (localtype / 2.f) / 100.f; const float vinf = (50.f + localtype / 2.f) / 100.f; ImProcFunctions::secondeg_begin (reducac, vi, lco.aa, lco.bb);//parabolic ImProcFunctions::secondeg_end (reducac, vinf, lco.aaa, lco.bbb, lco.ccc);//parabolic float maxco = -10000.f; float minco = +10000.f; if (call <= 3) { #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { //Todo optimization in this first part with something equivalent to bufcolorig and bufcoltra in colorlight_local #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float cli = 1.f; if (lp.curvact == true) { cli = (buflightc[loy - begy][lox - begx]); } //parameters for linear interpolation in function of real hue float apluscligh = (1.f - cli) / delhu; float bpluscligh = 1.f - apluscligh * hueplus; float amoinscligh = (cli - 1.f) / delhu; float bmoinscligh = 1.f - amoinscligh * huemoins; float realcligh = 1.f; float realcligh2 = cli; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 float rL = original->L[y][x] / 327.68f; //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.sens / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.sens / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.sens < 40.f ) { kch = pow (kch, pa * lp.sens + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.sens < 100.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { realcligh = cli; khu = 1.f; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { realcligh = cli; khu = 1.f; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { realcligh = cli; khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realcligh = apluscligh * rhue + bpluscligh; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realcligh = amoinscligh * rhue + bmoinscligh; khu = amo * rhue + bmo; } else { realcligh = cli; khu = 1.f; } kzon = true; } if (deltaE < 2.8f * lp.sens) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet >= 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { /* float kcr = 8.f; if(lp.sensh > 30.f){ if (rchro < kcr) { fach *= (1.f / (kcr)) * rchro; } } */ } float kcr = 100.f * lp.thr; float falL = 1.f; if (rchro < kcr && chromaref > kcr) { // reduce artifacts in grey tones near hue spot and improve algorithm falL *= pow (rchro / kcr, lp.iterat / 10.f); } int zone; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); float kdiff = 1.f; float modu = 1.f ;//realclig / cli; float localty = localtype; if (rL > 0.01f) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; break; } case 1: { // inside transition zone if (lp.curvact == false) { modu = 1.f; } else { modu = realcligh / (cli + 0.001f);//avoid divide by zero } if (original->L[y][x] < 32768.f) { float factorx = localFactor; float prov100 = original->L[y][x] / 32768.f; float prov = prov100 * 100.f; bool contin = true; if (contin) { if (prov > localty) { if (prov >= localty && prov < 50.f + localty / 2.f) { float core = (lco.alsup2 * prov + lco.blsup2) ; core *= factorx; transformed->L[y][x] = 327.68f * (prov + pm * (prov - localty) * (core) * kch * fach * falL * modu); } else { float core = lco.aDY * (lco.aaa * prov100 * prov100 + lco.bbb * prov100 + lco.ccc); core *= factorx; transformed->L[y][x] = 327.68f * (prov + pm * (prov - localty) * (core) * kch * fach * falL * modu); } } else { //inferior if (2.f * prov > localty && prov < localty) { float core = (lco.alsup * prov + lco.blsup) ; core *= factorx; transformed->L[y][x] = 327.68f * (prov - pm * (localty - prov) * core * kch * fach * falL * modu); } else if (2.f * prov <= localtype) { float core = prov * lco.alinf * (lco.aa * prov100 * prov100 + lco.bb * prov100); core *= factorx; transformed->L[y][x] = 327.68f * (prov - pm * (localty - prov) * core * kch * fach * falL * modu); } } } } else { transformed->L[y][x] = original->L[y][x]; } break; } case 2: { // inside selection => full effect, no transition if (lp.curvact == false) { modu = 1.f; } else { modu = realcligh / (cli + 0.001f); } if (original->L[y][x] < 32768.f) { float prov100 = original->L[y][x] / 32768.f; float prov = prov100 * 100.f; bool contin = true; if (contin) { if (prov > localty ) { if (prov >= localty && prov < 50.f + localty / 2.f) { float core = (lco.alsup2 * prov + lco.blsup2) ; transformed->L[y][x] = 327.68f * (prov + pm * (prov - localty) * core * kch * fach * falL * modu); } else { float core = lco.aDY * (lco.aaa * prov100 * prov100 + lco.bbb * prov100 + lco.ccc); transformed->L[y][x] = 327.68f * (prov + pm * (prov - localty) * core * kch * fach * falL * modu); } } else { //inferior if (2.f * prov > localty && prov < localty) { float core = (lco.alsup * prov + lco.blsup) ; transformed->L[y][x] = 327.68f * (prov - pm * (localty - prov) * core * kch * fach * falL * modu); } else if (2.f * prov <= localtype) { float core = prov * lco.alinf * (lco.aa * prov100 * prov100 + lco.bb * prov100); transformed->L[y][x] = 327.68f * (prov - pm * (localty - prov) * core * kch * fach * falL * modu); } } } } else { transformed->L[y][x] = original->L[y][x]; } } } } } } } } } } void ImProcFunctions::InverseContrast_Local (float ave, const local_contra & lco, const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy) { // BENCHFUN float ach = (float)lp.trans / 100.f; #pragma omp parallel for schedule(dynamic,16) if (multiThread) for (int y = 0; y < transformed->H; y++) { int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); switch (zone) { case 0: { // outside selection and outside transition zone => full effect, no transition if (original->L[y][x] < 32768.f) { float prov = original->L[y][x]; if (original->L[y][x] > ave) { float kh = lco.ah * (original->L[y][x] / 327.68f) + lco.bh; original->L[y][x] = ave + kh * (original->L[y][x] - ave); } else { float kl = lco.al * (original->L[y][x] / 327.68f) + 1.f; original->L[y][x] = ave - kl * (ave - original->L[y][x]); } float diflc = original->L[y][x] - prov; transformed->L[y][x] = prov + diflc; } else { transformed->L[y][x] = original->L[y][x]; } break; } case 1: { // inside transition zone if (original->L[y][x] < 32768.f) { float factorx = localFactor; factorx = 1.f - factorx; float prov = original->L[y][x]; if (original->L[y][x] > ave) { float kh = lco.ah * (original->L[y][x] / 327.68f) + lco.bh; original->L[y][x] = ave + kh * (original->L[y][x] - ave); } else { float kl = lco.al * (original->L[y][x] / 327.68f) + 1.f; original->L[y][x] = ave - kl * (ave - original->L[y][x]); } float diflc = original->L[y][x] - prov; diflc *= factorx; transformed->L[y][x] = prov + diflc; } else { transformed->L[y][x] = original->L[y][x]; } break; } case 2: { // inside selection => no effect, keep original values transformed->L[y][x] = original->L[y][x]; } } } } } static void calclight (float lum, float koef, float & lumnew, bool inv) //replace L-curve that does not work in local or bad { float blac = 0.3f; if (inv == false) { blac = 0.99f; } if (koef > 0.f) { lumnew = lum + 0.2f * (33000.f - lum) * koef / 100.f; } if (koef < 0.f) { lumnew = lum + blac * lum * koef / 100.f;//0.999 instead of 0.2 if (lumnew < 0.f) { float kc = lum / (lum - lumnew); lumnew = lum + kc * 0.2f * lum * koef / 100.f; } if (inv == false && koef == -100.f) { lumnew = 0.f; } } lumnew = CLIPLOC (lumnew); } void ImProcFunctions::InverseSharp_Local (int sp, float **loctemp, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { //local sharp // BENCHFUN const float localtype = lumaref; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.senssha < 30.f) { reducac = 0.2f * (lp.senssha / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.senssha / 100.f) + breduc; } constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.senssha - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.senssha; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif int zone; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.senssha / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.senssha / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.senssha < 40.f ) { kch = pow (kch, pa * lp.senssha + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.senssha < 20.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if (deltaE < 2.8f * lp.senssha) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet >= 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { /* float kcr = 8.f; if(lp.senssha > 30.f){ if (rchro < kcr) { fach *= (1.f / (kcr)) * rchro; } } */ } switch (zone) { case 0: { // outside selection and outside transition zone => full effect, no transition float difL = loctemp[y][x] - original->L[y][x]; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; break; } case 1: { // inside transition zone float difL = loctemp[y][x] - original->L[y][x]; float factorx = 1.f - localFactor; difL *= factorx; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; break; } case 2: { // inside selection => no effect, keep original values transformed->L[y][x] = original->L[y][x]; } } } } } } void ImProcFunctions::Sharp_Local (int call, int sp, float **loctemp, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, const local_params & lp, float **deltE, LabImage * original, LabImage * transformed, int cx, int cy) { // BENCHFUN const float localtype = lumaref; // always spot area const float ach = (float)lp.trans / 100.f; float reducac; //constant and variable to prepare shape detection if (lp.senssha < 30.f) { reducac = 0.2f * (lp.senssha / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.senssha / 100.f) + breduc; } //printf("call=%i\n", call); constexpr float delhu = 0.1f; //between 0.05 and 0.2 const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.senssha - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.senssha; #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif int zone; float localFactor = 1.f; calcTransition (lox, loy, ach, lp, zone, localFactor); //prepare shape detection float khu = 0.f; float kch = 1.f; bool kzon = false; float fach = 1.f; float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 //kch to modulate action with chroma if (deltachro < 160.f * SQR (lp.senssha / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.senssha / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.senssha < 40.f ) { kch = pow (kch, pa * lp.senssha + pb); //increase under 40 } // algo with detection of hue ==> artifacts for noisy images ==> denoise before if (lp.senssha < 20.f) { //to try... //hue detection if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu ) { khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins ) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { khu = amo * rhue + bmo; } else { khu = 1.f; } kzon = true; } if (deltaE < 2.8f * lp.senssha) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } if (lp.qualmet == 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //fach = khu ; } else { /* float kcr = 8.f; if(lp.senssha > 30.f){ if (rchro < kcr) { fach *= (1.f / (kcr)) * rchro; } } */ } int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; break; } case 1: { // inside transition zone float factorx = localFactor; float difL; if (call == 2) { if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { difL = loctemp[loy - begy][lox - begx] - original->L[y][x]; } } else { difL = loctemp[y][x] - original->L[y][x]; } difL *= factorx; transformed->L[y][x] = original->L[y][x] + difL * kch * fach; break; } case 2: { // inside selection => full effect, no transition float difL; if (call == 2) { if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { // bufsh[loy - begy - 1][lox - begx - 1] difL = loctemp[loy - begy][lox - begx] - original->L[y][x]; } } else { difL = loctemp[y][x] - original->L[y][x]; } transformed->L[y][x] = original->L[y][x] + difL * kch * fach; } } } } } } void ImProcFunctions::ColorLight_Local (int call, LabImage * bufcolorig, LabImage * bufcoltra, float ** buflight, float ** bufchro, float ** buflightslid, int sp, float moy, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, bool locallutili, LUTf & lllocalcurve, const LocLHCurve & loclhCurve, LUTf & cclocalcurve, float chprov, float cligh, const local_params & lp, float ** deltE, LabImage * original, LabImage * transformed, int cx, int cy) { // BENCHFUN // chroma and lightness const float ach = (float)lp.trans / 100.f; //chroma constexpr float amplchsens = 2.5f; constexpr float achsens = (amplchsens - 1.f) / (100.f - 20.f); //20. default locallab.sensi constexpr float bchsens = 1.f - 20.f * achsens; const float multchro = lp.sens * achsens + bchsens; //luma constexpr float ampllumsens = 2.f; constexpr float alumsens = (ampllumsens - 1.f) / (100.f - 20.f); //20. default locallab.sensi constexpr float blumsens = 1.f - 20.f * alumsens; const float multlum = lp.sens * alumsens + blumsens; //skin constexpr float amplchsensskin = 1.6f; constexpr float achsensskin = (amplchsensskin - 1.f) / (100.f - 20.f); //20. default locallab.sensi constexpr float bchsensskin = 1.f - 20.f * achsensskin; const float multchroskin = lp.sens * achsensskin + bchsensskin; //transition = difficult to avoid artifact with scope on flat area (sky...) constexpr float delhu = 0.1f; //between 0.05 and 0.2 ==> minima for scope //constexpr float delhu2 = 0.03f; //between 0.05 and 0.2 const float aplus = (1.f - lp.chro) / delhu; const float bplus = 1.f - aplus * hueplus; const float amoins = (lp.chro - 1.f) / delhu; const float bmoins = 1.f - amoins * huemoins; const float apl = (-1.f) / delhu; const float bpl = - apl * hueplus; const float amo = 1.f / delhu; const float bmo = - amo * huemoins; const float pb = 4.f; const float pa = (1.f - pb) / 40.f; const float ahu = 1.f / (2.8f * lp.sens - 280.f); const float bhu = 1.f - ahu * 2.8f * lp.sens; const float alum = 1.f / (lp.sens - 100.f); const float blum = 1.f - alum * lp.sens; //luma constexpr float lumdelta = 11.f; //11 float modlum = lumdelta * multlum; // constant and varaibles to prepare shape detection if (lumaref + modlum >= 100.f) { modlum = (100.f - lumaref) / 2.f; } if (lumaref - modlum <= 0.f) { modlum = (lumaref) / 2.f; } float alu = 1.f / (lumaref + modlum - 100.f); //linear float aa, bb, aaa, bbb, ccc; float reducac = settings->reduchigh;//0.85f; float reducac2 = settings->reduclow;//0.2f; float vinf = (lumaref + modlum) / 100.f; float vi = (lumaref - modlum) / 100.f; ImProcFunctions::secondeg_begin (reducac, vi, aa, bb);//parabolic ImProcFunctions::secondeg_end (reducac, vinf, aaa, bbb, ccc);//parabolic // printf("vi=%f aa=%f bb=%f vinf=%f aaa=%f bbb=%f ccc=%f\n", vi,aa,bb, vinf, aaa, bbb, ccc); float vinf2 = (lumaref + modlum) / 100.f; float vi2 = (lumaref - modlum) / 100.f; float aaaa, bbbb, cccc, aO, bO; ImProcFunctions::secondeg_end (reducac2, vinf2, aaaa, bbbb, cccc);//parabolic ImProcFunctions::secondeg_begin (reducac2, vi2, aO, bO);//parabolic if (call <= 3) { //Todo optimization in this first part with bufcolorig and bufcoltra #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); #endif float maxl = -100000.f; float maxa = -100000.f; float maxb = -100000.f; float minl = 100000.f; float mina = 100000.f; float minb = 100000.f; float maxrl = -100000.f; float minrl = 100000.f; #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; //Todo optimization in this first part with bufcolorig and bufcoltra for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (original->a[y][i]); vfloat bv = LVFU (original->b[y][i]); STVF (atan2Buffer[i], xatan2f (bv, av)); STVF (sqrtBuffer[i], _mm_sqrt_ps (SQRV (bv) + SQRV (av)) / c327d68v); } for (; i < transformed->W; i++) { atan2Buffer[i] = xatan2f (original->b[y][i], original->a[y][i]); sqrtBuffer[i] = sqrt (SQR (original->b[y][i]) + SQR (original->a[y][i])) / 327.68f; } #endif int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { #ifdef __SSE2__ float rhue = atan2Buffer[x]; float rchro = sqrtBuffer[x]; #else float rhue = xatan2f (original->b[y][x], original->a[y][x]); float rchro = sqrt (SQR (original->b[y][x]) + SQR (original->a[y][x])) / 327.68f; #endif float rL = original->L[y][x] / 327.68f; float rLL = original->L[y][x] / 327.68f; if (fabs (original->b[y][x]) < 0.01f) { original->b[y][x] = 0.01f; } float eps = 0.f; if (fabs (original->b[y][x]) < 0.001f) { eps = 0.01f; } //retriev data curve lightness float cli = (buflight[loy - begy][lox - begx]); //parameters for linear interpolation in function of real hue float apluscligh = (1.f - cli) / delhu; float bpluscligh = 1.f - apluscligh * hueplus; float amoinscligh = (cli - 1.f) / delhu; float bmoinscligh = 1.f - amoinscligh * huemoins; float cchro = (bufchro[loy - begy][lox - begx]); float apluscurv = (1.f - cchro) / delhu; float bpluscurv = 1.f - apluscurv * hueplus; float amoinscurv = (cchro - 1.f) / delhu; float bmoinscurv = 1.f - amoinscurv * huemoins; float clisl = (buflightslid[loy - begy][lox - begx]); //parameters for linear interpolation in function of real hue float aplusclighsl = (1.f - clisl) / delhu; float bplusclighsl = 1.f - aplusclighsl * hueplus; float amoinsclighsl = (clisl - 1.f) / delhu; float bmoinsclighsl = 1.f - amoinsclighsl * huemoins; float kab = (original->a[y][x] / (original->b[y][x] + eps)); //prepare shape detection // real... = coefficient to apply at lightness, chroma,... float realchro = 1.f; float realcurv = 1.f; float realcligh = 1.f; float realclighsl = 1.f; float realchrosl = 1.f; //evaluate delta Hue and delta Chro float deltachro = fabs (rchro - chromaref); float deltahue = fabs (rhue - hueref); if (deltahue > M_PI) { deltahue = - (deltahue - 2.f * M_PI); } //pseudo deltaE float deltaE = 20.f * deltahue + deltachro; //pseudo deltaE between 0 and 280 float deltaL = fabs (lumaref - rL); //between 0 and 100 float kch = 1.f; float khu = 0.f; float fach = 1.f; float falu = 1.f; //kch acts on luma if (deltachro < 160.f * SQR (lp.sens / 100.f)) { kch = 1.f; } else { float ck = 160.f * SQR (lp.sens / 100.f); float ak = 1.f / (ck - 160.f); float bk = -160.f * ak; kch = ak * deltachro + bk; } if (lp.sens < 40.f ) { kch = pow (kch, pa * lp.sens + pb); //increase under 40 } bool kzon = false; //transition = difficult to avoid artifact with scope on flat area (sky...) //hue detection //for each quart calculate realchro, realcligh,... in function of Hue pixel if ((hueref + dhue) < M_PI && rhue < hueplus && rhue > huemoins) { //transition are good if (rhue >= hueplus - delhu) { realchro = aplus * rhue + bplus; realcurv = apluscurv * rhue + bpluscurv; realcligh = apluscligh * rhue + bpluscligh; realclighsl = aplusclighsl * rhue + bplusclighsl; khu = apl * rhue + bpl; } else if (rhue < huemoins + delhu) { realchro = amoins * rhue + bmoins; realcurv = amoinscurv * rhue + bmoinscurv; realcligh = amoinscligh * rhue + bmoinscligh; realclighsl = amoinsclighsl * rhue + bmoinsclighsl; khu = amo * rhue + bmo; } else { realchro = lp.chro; realcurv = cchro; realcligh = cli; realclighsl = clisl; khu = 1.f; } kzon = true; } else if ((hueref + dhue) >= M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realchro = aplus * rhue + bplus; realcurv = apluscurv * rhue + bpluscurv; realcligh = apluscligh * rhue + bpluscligh; realclighsl = aplusclighsl * rhue + bplusclighsl; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realchro = amoins * rhue + bmoins; realcurv = amoinscurv * rhue + bmoinscurv; realcligh = amoinscligh * rhue + bmoinscligh; realclighsl = amoinsclighsl * rhue + bmoinsclighsl; khu = amo * rhue + bmo; } else { realchro = lp.chro; realcurv = cchro; realcligh = cli; realclighsl = clisl; khu = 1.f; } kzon = true; } if ((hueref - dhue) > -M_PI && rhue < hueplus && rhue > huemoins) { if (rhue >= hueplus - delhu && rhue < hueplus) { realchro = aplus * rhue + bplus; realcurv = apluscurv * rhue + bpluscurv; realcligh = apluscligh * rhue + bpluscligh; realclighsl = aplusclighsl * rhue + bplusclighsl; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realchro = amoins * rhue + bmoins; realcurv = amoinscurv * rhue + bmoinscurv; realcligh = amoinscligh * rhue + bmoinscligh; realclighsl = amoinsclighsl * rhue + bmoinsclighsl; khu = amo * rhue + bmo; } else { realchro = lp.chro; realcurv = cchro; realcligh = cli; realclighsl = clisl; khu = 1.f; } kzon = true; } else if ((hueref - dhue) <= -M_PI && (rhue > huemoins || rhue < hueplus )) { if (rhue >= hueplus - delhu && rhue < hueplus) { realchro = aplus * rhue + bplus; realcurv = apluscurv * rhue + bpluscurv; realcligh = apluscligh * rhue + bpluscligh; realclighsl = aplusclighsl * rhue + bplusclighsl; khu = apl * rhue + bpl; } else if (rhue >= huemoins && rhue < huemoins + delhu) { realchro = amoins * rhue + bmoins; realcurv = amoinscurv * rhue + bmoinscurv; realcligh = amoinscligh * rhue + bmoinscligh; realclighsl = amoinsclighsl * rhue + bmoinsclighsl; khu = amo * rhue + bmo; } else { realchro = lp.chro; realcurv = cchro; realcligh = cli; realclighsl = clisl; khu = 1.f; } kzon = true; } //detection of deltaE and deltaL if (lp.sens <= 20.f) { //to try... //fach and kch acts on luma if (deltaE < 2.8f * lp.sens) { fach = khu; } else { fach = khu * (ahu * deltaE + bhu); } float kcr = 10.f; if (rchro < kcr) { fach *= (1.f / (kcr * kcr)) * rchro * rchro; } //fach = 1.f;//to avoid artifacts in some cases //can be probably improved if (lp.qualmet >= 1) { if (deltE[y][x] > 10.f * lp.thr) { fach = 1.f; } } else { fach = 1.f; } //falu acts on chroma if (deltaL < lp.sens) { falu = 1.f; } else { falu = 1.f;// alum * deltaL + blum; } } if (kzon) { if (lp.sens < 60.f) { //arbitrary value if (hueref < -1.1f && hueref > -2.8f) { // detect blue sky if (chromaref > 0.f && chromaref < 35.f * multchro) { // detect blue sky if ( (rhue > -2.79f && rhue < -1.11f) && (rchro < 35.f * multchro)) { realchro *= 0.9f; realcurv *= 0.9f; } else { realchro = 1.f; realcurv = 1.f; } } } else { realchro = lp.chro; realcurv = cchro; } if (lp.sens < 50.f && lp.chro > 0.f) { if (hueref > -0.1f && hueref < 1.6f) { // detect skin if (chromaref > 0.f && chromaref < 55.f * multchroskin) { // detect skin if ( (rhue > -0.09f && rhue < 1.59f) && (rchro < 55.f * multchroskin)) { realchro *= 0.9f; realcurv *= 0.9f; } else { realchro = 1.f; realcurv = 1.f; } } } else { realchro = lp.chro; realcurv = cchro; } } } } float kLinf = rLL / (100.f); float kLsup = kLinf; float kdiff = 1.f; if (kzon) { ///rhue < hueplus && rhue > huemoins if ( (rLL > (lumaref - modlum) && rLL < (lumaref + modlum))) { kdiff = 1.f; } else if (rLL > 0.f && rLL <= (lumaref - modlum)) { kdiff = (aa * kLinf * kLinf + bb * kLinf); //parabolic if (kdiff < 0.01f) { kdiff = 0.01f; } } else if (rLL <= 100.f && rLL >= (lumaref + modlum)) { kdiff = (aaa * kLsup * kLsup + bbb * kLsup + ccc); //parabolic if (kdiff < 0.01f) { kdiff = 0.01f; } } //end luma } else { float ktes = 1.f; if ( (rLL > (lumaref - modlum) && rLL < (lumaref + modlum))) { kdiff = ktes; } else if (rLL > 0.f && rLL <= (lumaref - modlum)) { kdiff = (ktes * (aO * kLinf * kLinf + bO * kLinf)); //parabolic if (kdiff < 0.01f) { kdiff = 0.01f; } } else if (rLL <= 100.f && rLL >= (lumaref + modlum)) { kdiff = (ktes * (aaaa * kLsup * kLsup + bbbb * kLsup + cccc)); //parabolic if (kdiff < 0.01f) { kdiff = 0.01f; } } } float kcr = 100.f * lp.thr; float falL = 1.f; if (rchro < kcr && chromaref > kcr) { // reduce artifacts in grey tones near hue spot and improve algorithm falL *= pow (rchro / kcr, lp.iterat / 10.f); } int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); float th_r = 0.01f; if (rL > th_r) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values transformed->L[y][x] = original->L[y][x]; transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; break; } case 1: { // inside transition zone float lumnew = bufcolorig->L[loy - begy][lox - begx]; float lightcont; if (lp.qualcurvemet == 1) { if (lllocalcurve) { float lumprov = lllocalcurve[lumnew * 1.9f]; float lumred = 0.526316f * lumprov; //0.526316f lumnew = lumnew + (lumred - lumnew) / 4.f;//reduce sensibility } if (loclhCurve) { float l_r;//Luminance Lab in 0..1 l_r = lumnew / 32768.f; { float khu = 1.9f; //in reserve in case of! float valparam = float ((loclhCurve[500.f * Color::huelab_to_huehsv2 (rhue)] - 0.5f)); //get l_r=f(H) float valparamneg; valparamneg = valparam; if (valparam > 0.f) { l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR (((SQR (1.f - min (l_r, 1.0f)))))); } else //for negative { l_r *= (1.f + khu * valparamneg); } } lumnew = l_r * 32768.f; } } if (lp.ligh != 0.f && lp.curvact == false) { calclight (lumnew, lp.ligh , lumnew, true);//replace L-curve lightcont = lumnew; } else { lightcont = lumnew; } float factorx = localFactor; float fli = 1.f; float flisl = 1.f; if (lp.curvact && lp.ligh != 0.f) { flisl = ((100.f + realclighsl * falL ) / 100.f);//luma transition } if (lp.qualcurvemet == 2) { fli = ((100.f + realcligh * falL ) / 100.f);//luma transition } float flicur = 1.f; if (lp.qualcurvemet != 0) { flicur = ((100.f + realcurv * factorx * falu * falL) / 100.f); } float fac = flicur * (100.f + factorx * realchro * falu * falL) / 100.f; //chroma factor transition float diflc = lightcont * fli * flisl - original->L[y][x]; kdiff *= fach * kch; diflc *= kdiff ; diflc *= factorx; //transition lightness transformed->L[y][x] = CLIPL (1.f * (original->L[y][x] + diflc)); if (fabs (kab) > 1.f) { transformed->a[y][x] = CLIPC (original->a[y][x] * fac) ; transformed->b[y][x] = CLIPC (original->a[y][x] * fac) / kab; } else { transformed->b[y][x] = CLIPC (original->b[y][x] * fac); transformed->a[y][x] = CLIPC (original->b[y][x] * fac) * kab ; } break; } case 2: { // inside selection => full effect, no transition float lumnew = bufcolorig->L[loy - begy][lox - begx]; float lightcont; if (lp.qualcurvemet == 1) { if (lllocalcurve) { float lumprov = lllocalcurve[lumnew * 1.9f]; float lumred = 0.526316 * lumprov; // 0.526316f lumnew = lumnew + (lumred - lumnew) / 4.f;//reduce sensibility } if (loclhCurve) { float l_r;//Luminance Lab in 0..1 l_r = lumnew / 32768.f; { float khu = 1.9f; float valparam = float ((loclhCurve[500.f * Color::huelab_to_huehsv2 (rhue)] - 0.5f)); //get l_r=f(H) float valparamneg; valparamneg = valparam; if (valparam > 0.f) { l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR (((SQR (1.f - min (l_r, 1.0f)))))); } else //for negative { l_r *= (1.f + khu * valparamneg); } } lumnew = l_r * 32768.f; } } if (lp.ligh != 0.f && lp.curvact == false) { calclight (lumnew, lp.ligh , lumnew, true);//replace L-curve lightcont = lumnew; } else { lightcont = lumnew; } float fli = 1.f; float flisl = 1.f; if (lp.curvact && lp.ligh != 0.f) { flisl = ((100.f + realclighsl * falL ) / 100.f);//luma transition } if (lp.qualcurvemet == 2) { fli = ((100.f + realcligh * falL) / 100.f);//luma transition } float flicur = 1.f; if (lp.qualcurvemet != 0) { flicur = ((100.f + realcurv * falu * falL) / 100.f); } float fac = flicur * (100.f + realchro * falu * falL) / 100.f; //chroma factor transition7 float diflc = lightcont * fli * flisl - original->L[y][x]; kdiff *= fach * kch; diflc *= kdiff ; transformed->L[y][x] = CLIPL (1.f * (original->L[y][x] + diflc)); if (fabs (kab) > 1.f) { transformed->a[y][x] = CLIPC (original->a[y][x] * fac) ; transformed->b[y][x] = CLIPC (original->a[y][x] * fac) / kab; } else { transformed->b[y][x] = CLIPC (original->b[y][x] * fac); transformed->a[y][x] = CLIPC (original->b[y][x] * fac) * kab; } } } } } } } } } } void ImProcFunctions::InverseColorLight_Local (const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy) { // BENCHFUN float ach = (float)lp.trans / 100.f; const float facc = (100.f + lp.chro) / 100.f; //chroma factor transition #pragma omp parallel for schedule(dynamic,16) if (multiThread) for (int y = 0; y < transformed->H; y++) { int loy = cy + y; for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int zone; float localFactor; calcTransition (lox, loy, ach, lp, zone, localFactor); switch (zone) { case 0: { // outside selection and outside transition zone => no effect, keep original values float lumnew = original->L[y][x]; if (lp.ligh != 0.f) { calclight (original->L[y][x], lp.ligh , lumnew, false); } // float lightcont = localcurve[original->L[y][x]]; //apply lightness float lightcont = lumnew ; //original->L[y][x] + (lp.ligh /100.f)*original->L[y][x] ; //apply lightness transformed->L[y][x] = lightcont; //localcurve[original->L[y][x]]; //apply lightness transformed->a[y][x] = original->a[y][x] * facc; transformed->b[y][x] = original->b[y][x] * facc; break; } case 1: { // inside transition zone float factorx = 1.f - localFactor; float fac = (100.f + factorx * lp.chro) / 100.f; //chroma factor transition float lumnew = original->L[y][x]; if (lp.ligh != 0.f) { calclight (original->L[y][x], lp.ligh , lumnew, false); } // float lightcont = localcurve[original->L[y][x]]; //apply lightness float lightcont = lumnew ; //original->L[y][x] + (lp.ligh /100.f)*original->L[y][x] ; //apply lightness //float lightcont = localcurve[original->L[y][x]]; //apply lightness float diflc = lightcont - original->L[y][x]; diflc *= factorx; transformed->L[y][x] = original->L[y][x] + diflc; transformed->a[y][x] = original->a[y][x] * fac; transformed->b[y][x] = original->b[y][x] * fac; break; } case 2: { // inside selection => no effect, keep original values transformed->L[y][x] = original->L[y][x]; transformed->a[y][x] = original->a[y][x]; transformed->b[y][x] = original->b[y][x]; } } } } } void ImProcFunctions::Lab_Local (int call, int sp, float** shbuffer, LabImage * original, LabImage * transformed, int sx, int sy, int cx, int cy, int oW, int oH, int fw, int fh, bool locutili, int sk, const LocretigainCurve & locRETgainCcurve, bool locallutili, LUTf & lllocalcurve, const LocLHCurve & loclhCurve, LUTf & cclocalcurve, double & hueref, double & chromaref, double & lumaref) { //general call of others functions : important return hueref, chromaref, lumaref if (params->locallab.enabled) { // BENCHFUN #ifdef _DEBUG MyTime t1e, t2e; t1e.set(); // init variables to display Munsell corrections MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); #endif int del = 3; // to avoid crash with [loy - begy] and [lox - begx] and bfh bfw // with gtk2 [loy - begy-1] [lox - begx -1 ] and del = 1 int GW = transformed->W; int GH = transformed->H; float moy = 0.f; float maxmad = -10000.f; float minmad = 1000000.f; struct local_params lp; calcLocalParams (oW, oH, params->locallab, lp); const float radius = lp.rad / (sk * 1.4f); //0 to 70 ==> see skip GW = transformed->W; GH = transformed->H; float **deltE = nullptr; if (lp.qualmet >= 1) { deltE = new float*[GH]; for (int i = 0; i < GH; i++) { deltE[i] = new float[GW]; } for (int ir = 0; ir < GH; ir++) for (int jr = 0; jr < GW; jr++) { deltE[ir][jr] = 0.f; } } //begin contrast and evalue hue // double precision for large summations double ave = 0.; double aveA = 0.; double aveB = 0.; double aveL = 0.; double aveChro = 0.; // int precision for the counters int n = 0; int nab = 0; // single precision for the result float av, avA, avB, avL; //evauate mean luminance for contrast : actually one area // evaluate also hue int levred; bool noiscfactiv = false; if (lp.qualmet == 2) { //suppress artifacts with quality enhanced levred = 4; noiscfactiv = true; } else { levred = 7; noiscfactiv = false; } if ((!lp.inv && !lp.invret) && hueref == INFINITY && chromaref == INFINITY && lumaref == INFINITY) { //evaluate hue, chroma, luma in center spot int spotSize = 0.88623f * max (1, lp.cir / sk); //18 //O.88623 = sqrt(PI / 4) ==> sqare equal to circle // very small region, don't use omp here for (int y = max (cy, (int) (lp.yc - spotSize)); y < min (transformed->H + cy, (int) (lp.yc + spotSize + 1)); y++) { for (int x = max (cx, (int) (lp.xc - spotSize)); x < min (transformed->W + cx, (int) (lp.xc + spotSize + 1)); x++) { aveL += original->L[y - cy][x - cx]; aveA += original->a[y - cy][x - cx]; aveB += original->b[y - cy][x - cx]; aveChro += sqrtf (SQR (original->b[y - cy][x - cx]) + SQR (original->a[y - cy][x - cx])); nab++; } } } else if (lp.inv || lp.invret) { //exterior || lp.curvact ave = 0.f; n = 0; #pragma omp parallel for reduction(+:ave,n) for (int y = 0; y < transformed->H; y++) { for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; if (lox >= lp.xc && lox < lp.xc + lp.lx && loy >= lp.yc && loy < lp.yc + lp.ly) { } else if (lox >= lp.xc && lox < lp.xc + lp.lx && loy < lp.yc && loy > lp.yc - lp.lyT) { } else if (lox < lp.xc && lox > lp.xc - lp.lxL && loy <= lp.yc && loy > lp.yc - lp.lyT) { } else if (lox < lp.xc && lox > lp.xc - lp.lxL && loy > lp.yc && loy < lp.yc + lp.ly) { } else { ave += original->L[y][x]; n++; } } } if (n == 0) { ave = 15000.f; n = 1; } ave = ave / n; av = ave / 327.68f; } aveL = aveL / nab; aveA = aveA / nab; aveB = aveB / nab; aveChro = aveChro / nab; aveChro /= 327.68f; avA = aveA / 327.68f; avB = aveB / 327.68f; avL = aveL / 327.68f; //INFINITY to solve crop problem when Ref is outside preview if (hueref == INFINITY) { hueref = xatan2f (avB, avA); //mean hue } if (chromaref == INFINITY) { chromaref = aveChro; } if (lumaref == INFINITY) { lumaref = avL; } struct local_contra lco; // we must here detect : general case, skin, sky,...foliages ??? // delta dhue, luminance and chroma constexpr float ared = (M_PI - 0.05f) / 100.f; constexpr float bred = 0.05f; float dhue = ared * lp.sens + bred; //delta hue lght chroma float dhueret = ared * lp.sensh + bred; //delta hue retinex constexpr float maxh = 3.5f; // 3.5 amplification contrast above mean constexpr float maxl = 2.5f; // 3 reductio contrast under mean float multh = (float) fabs (lp.cont) * (maxh - 1.f) / 100.f + 1.f; float mult = (float)fabs (lp.cont) * (maxl - 1.f) / 100.f + 1.f; lco.dx = 1.f - 1.f / mult; lco.dy = 1.f - 1.f / multh; //Blur and noise if (((radius >= 1.5 * GAUSS_SKIP && lp.rad > 1.) || lp.stren > 0.1) && lp.blurena) { // radius < GAUSS_SKIP means no gauss, just copy of original image LabImage *tmp1; LabImage *bufgb; int GW = transformed->W; int GH = transformed->H; printf ("rad=%f gaus=%f call=%i skip=%i\n", radius, GAUSS_SKIP, call, sk); if (call == 2 && !lp.invrad) { //simpleprocess int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; bufgb = new LabImage (bfw, bfh); #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufgb->L[ir][jr] = 0.f; bufgb->a[ir][jr] = 0.f; bufgb->b[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufgb->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas bufgb->a[loy - begy][lox - begx] = original->a[y][x];//fill square buffer with datas bufgb->b[loy - begy][lox - begx] = original->b[y][x];//fill square buffer with datas } } tmp1 = new LabImage (bfw, bfh); #ifdef _OPENMP #pragma omp parallel #endif { gaussianBlur (bufgb->L, tmp1->L, bfw, bfh, radius); gaussianBlur (bufgb->a, tmp1->a, bfw, bfh, radius); gaussianBlur (bufgb->b, tmp1->b, bfw, bfh, radius); } } else { tmp1 = new LabImage (transformed->W, transformed->H);; #ifdef _OPENMP #pragma omp parallel #endif { gaussianBlur (original->L, tmp1->L, GW, GH, radius); gaussianBlur (original->a, tmp1->a, GW, GH, radius); gaussianBlur (original->b, tmp1->b, GW, GH, radius); } } if (lp.stren > 0.1f) { float mean = 0.f;//0 best result float variance = lp.stren ; //(double) SQR(lp.stren)/sk; addGaNoise (tmp1, tmp1, mean, variance, sk) ; } if (!lp.invrad) { //blur and noise (center) // BlurNoise_Local(call, lp, original, transformed, tmp1, cx, cy); float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } BlurNoise_Local (call, sp, tmp1, hueplus, huemoins, hueref, dhue, chromaref, lumaref, lp, deltE, original, transformed, cx, cy); } else { InverseBlurNoise_Local (lp, original, transformed, tmp1, cx, cy); } if (call == 2 && !lp.invrad) { delete bufgb; } delete tmp1; } // } //local denoise if (lp.noiself > 0.f || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f && call < 3 || noiscfactiv && lp.denoiena) { if (lp.noisecf > 0.1f || lp.noisecc > 0.1f) { noiscfactiv = false; levred = 7; } if (call == 1) { LabImage *tmp1 = new LabImage (transformed->W, transformed->H); int GW = transformed->W; int GH = transformed->H; for (int ir = 0; ir < GH; ir++) for (int jr = 0; jr < GW; jr++) { tmp1->L[ir][jr] = original->L[ir][jr]; tmp1->a[ir][jr] = original->a[ir][jr]; tmp1->b[ir][jr] = original->b[ir][jr]; } int DaubLen = 6; int wavNestedLevels = 1; int levwavL = levred; int skip = 1; wavelet_decomposition* Ldecomp = new wavelet_decomposition (tmp1->L[0], tmp1->W, tmp1->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); wavelet_decomposition* adecomp = new wavelet_decomposition (tmp1->a[0], tmp1->W, tmp1->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); wavelet_decomposition* bdecomp = new wavelet_decomposition (tmp1->b[0], tmp1->W, tmp1->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); float madL[8][3]; float madab[8][3]; int edge; if (!Ldecomp->memoryAllocationFailed) { for (int lvl = 0; lvl < levred; lvl++) { for (int dir = 1; dir < 4; dir++) { int Wlvl_L = Ldecomp->level_W (lvl); int Hlvl_L = Ldecomp->level_H (lvl); float ** WavCoeffs_L = Ldecomp->level_coeffs (lvl); madL[lvl][dir - 1] = SQR (Mad (WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); } } int ind = 0; float vari[levred]; if (levred == 7) { edge = 2; vari[0] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[1] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[2] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[3] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[4] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[5] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[6] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); } else if (levred == 4) { edge = 3; vari[0] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[1] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[2] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[3] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiselc / 25.0)); } if (( lp.noiself > 0.1f || lp.noiselc > 0.1f)) { vari[0] = max (0.0001f, vari[0]); vari[1] = max (0.0001f, vari[1]); vari[2] = max (0.0001f, vari[2]); vari[3] = max (0.0001f, vari[3]); if (levred == 7) { vari[4] = max (0.0001f, vari[4]); vari[5] = max (0.0001f, vari[5]); vari[6] = max (0.0001f, vari[6]); } float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL WaveletDenoiseAllL (*Ldecomp, noisevarlum, madL, vari, edge); } } float variC[levred]; if (!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { if (levred == 7) { edge = 2; variC[0] = SQR (lp.noisecf / 10.0); variC[1] = SQR (lp.noisecf / 10.0); variC[2] = SQR (lp.noisecf / 10.0); variC[3] = SQR (lp.noisecf / 10.0); variC[4] = SQR (lp.noisecf / 10.0); variC[5] = SQR (lp.noisecc / 10.0); variC[6] = SQR (lp.noisecc / 10.0); } else if (levred == 4) { edge = 3; variC[0] = SQR (lp.noisecf / 10.0); variC[1] = SQR (lp.noisecf / 10.0); variC[2] = SQR (lp.noisecf / 10.0); variC[3] = SQR (lp.noisecf / 10.0); } if (( lp.noisecf > 0.1f || lp.noisecc > 0.1f || noiscfactiv)) { float minic = 0.0001f; if (noiscfactiv) { minic = 0.01f;//only for artifact shape detection } variC[0] = max (minic, variC[0]); variC[1] = max (minic, variC[1]); variC[2] = max (minic, variC[2]); variC[3] = max (minic, variC[3]); if (levred == 7) { variC[4] = max (0.0001f, variC[4]); variC[5] = max (0.0001f, variC[5]); variC[6] = max (0.0001f, variC[6]); } float* noisevarchrom = new float[GH * GW]; for (int q = 0; q < GH * GW; q++) { noisevarchrom[q] = 1.f; } float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0); WaveletDenoiseAllAB (*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false); WaveletDenoiseAllAB (*Ldecomp, *bdecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false); delete[] noisevarchrom; } } if (!Ldecomp->memoryAllocationFailed) { Ldecomp->reconstruct (tmp1->L[0]); } if (!adecomp->memoryAllocationFailed) { adecomp->reconstruct (tmp1->a[0]); } if (!bdecomp->memoryAllocationFailed) { bdecomp->reconstruct (tmp1->b[0]); } DeNoise_Local (call, lp, original, transformed, tmp1, cx, cy); delete tmp1; delete Ldecomp; delete adecomp; delete bdecomp; } LabImage *bufwv; if (call == 2) { //simpleprocess int GW = transformed->W; int GH = transformed->H; int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; bufwv = new LabImage (bfw, bfh); #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufwv->L[ir][jr] = 0.f; bufwv->a[ir][jr] = 0.f; bufwv->b[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufwv->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas bufwv->a[loy - begy][lox - begx] = original->a[y][x];//fill square buffer with datas bufwv->b[loy - begy][lox - begx] = original->b[y][x];//fill square buffer with datas } } int DaubLen = 6; int wavNestedLevels = 1; int levwavL = levred; int skip = 1; wavelet_decomposition* Ldecomp = new wavelet_decomposition (bufwv->L[0], bufwv->W, bufwv->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); wavelet_decomposition* adecomp = new wavelet_decomposition (bufwv->a[0], bufwv->W, bufwv->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); wavelet_decomposition* bdecomp = new wavelet_decomposition (bufwv->b[0], bufwv->W, bufwv->H, levwavL, 1, skip, max (1, wavNestedLevels), DaubLen); float madL[8][3]; float madab[8][3]; int edge; if (!Ldecomp->memoryAllocationFailed) { for (int lvl = 0; lvl < levred; lvl++) { for (int dir = 1; dir < 4; dir++) { int Wlvl_L = Ldecomp->level_W (lvl); int Hlvl_L = Ldecomp->level_H (lvl); float ** WavCoeffs_L = Ldecomp->level_coeffs (lvl); madL[lvl][dir - 1] = SQR (Mad (WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); } } int ind = 0; float vari[levred]; if (levred == 7) { edge = 2; vari[0] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[1] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[2] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[3] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[4] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[5] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); vari[6] = 8.f * SQR ((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); } else if (levred == 4) { edge = 3; vari[0] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[1] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[2] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); vari[3] = 8.f * SQR ((lp.noiself / 125.0) * (1.0 + lp.noiselc / 25.0)); } if (( lp.noiself > 0.1f || lp.noiselc > 0.1f)) { vari[0] = max (0.0001f, vari[0]); vari[1] = max (0.0001f, vari[1]); vari[2] = max (0.0001f, vari[2]); vari[3] = max (0.0001f, vari[3]); if (levred == 7) { vari[4] = max (0.0001f, vari[4]); vari[5] = max (0.0001f, vari[5]); vari[6] = max (0.0001f, vari[6]); } float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL WaveletDenoiseAllL (*Ldecomp, noisevarlum, madL, vari, edge); } } float variC[levred]; if (!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { if (levred == 7) { edge = 2; variC[0] = SQR (lp.noisecf / 10.0); variC[1] = SQR (lp.noisecf / 10.0); variC[2] = SQR (lp.noisecf / 10.0); variC[3] = SQR (lp.noisecf / 10.0); variC[4] = SQR (lp.noisecf / 10.0); variC[5] = SQR (lp.noisecc / 10.0); variC[6] = SQR (lp.noisecc / 10.0); } else if (levred == 4) { edge = 3; variC[0] = SQR (lp.noisecf / 10.0); variC[1] = SQR (lp.noisecf / 10.0); variC[2] = SQR (lp.noisecf / 10.0); variC[3] = SQR (lp.noisecf / 10.0); } if (( lp.noisecf > 0.1f || lp.noisecc > 0.1f || noiscfactiv)) { float minic = 0.0001f; if (noiscfactiv) { minic = 0.01f;//only for artifact shape detection } variC[0] = max (minic, variC[0]); variC[1] = max (minic, variC[1]); variC[2] = max (minic, variC[2]); variC[3] = max (minic, variC[3]); if (levred == 7) { variC[4] = max (0.0001f, variC[4]); variC[5] = max (0.0001f, variC[5]); variC[6] = max (0.0001f, variC[6]); } float* noisevarchrom = new float[bfh * bfw]; for (int q = 0; q < bfh * bfw; q++) { noisevarchrom[q] = 1.f; } float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0); WaveletDenoiseAllAB (*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false); WaveletDenoiseAllAB (*Ldecomp, *bdecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false); delete[] noisevarchrom; } } if (!Ldecomp->memoryAllocationFailed) { Ldecomp->reconstruct (bufwv->L[0]); } if (!adecomp->memoryAllocationFailed) { adecomp->reconstruct (bufwv->a[0]); } if (!bdecomp->memoryAllocationFailed) { bdecomp->reconstruct (bufwv->b[0]); } DeNoise_Local (call, lp, original, transformed, bufwv, cx, cy); delete bufwv; delete Ldecomp; delete adecomp; delete bdecomp; bufwv = nullptr; Ldecomp = nullptr; adecomp = nullptr; bdecomp = nullptr; } } //local color and light if (!lp.inv && (lp.chro != 0 || lp.ligh != 0.f || lp.qualcurvemet != 0) && lp.colorena) { // || lllocalcurve)) { //interior ellipse renforced lightness and chroma //locallutili float maxhur = -10.f; float minhur = 10.f; float hueplus = hueref + dhue; float huemoins = hueref - dhue; //printf("hueplus=%f huemoins=%f dhu=%f\n", hueplus, huemoins, dhue); if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } LabImage *bufcolorig; float chprov = 1.f; float chpro = 1.f; float chp = 1.f; float cligh = 1.f; float clighL = 1.f; float clighmax ; float clighmin ; LabImage *bufcoltra; float **buflight; float **bufchro; float **buflightslid; int bfh, bfw; float adjustr = 1.0f; float compadjustr = 1.0f; //adapt chroma to working profile if (params->icm.working == "ProPhoto") { adjustr = 1.2f; // 1.2 instead 1.0 because it's very rare to have C>170.. } else if (params->icm.working == "Adobe RGB") { adjustr = 1.8f; } else if (params->icm.working == "sRGB") { adjustr = 2.0f; } else if (params->icm.working == "WideGamut") { adjustr = 1.2f; } else if (params->icm.working == "Beta RGB") { adjustr = 1.4f; } else if (params->icm.working == "BestRGB") { adjustr = 1.4f; } else if (params->icm.working == "BruceRGB") { adjustr = 1.8f; } if (call <= 3) { //simpleprocess, dcrop, improccoordinator int GW = transformed->W; int GH = transformed->H; bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone bfw = int (lp.lx + lp.lxL) + del; bufcolorig = new LabImage (bfw, bfh);//buffer for data in zone limit // bufcoltra = new LabImage (bfw, bfh);//not used buflight = new float*[bfh];//for lightness curve for (int i = 0; i < bfh; i++) { buflight[i] = new float[bfw]; } bufchro = new float*[bfh];//for chroma curve for (int i = 0; i < bfh; i++) { bufchro[i] = new float[bfw]; } buflightslid = new float*[bfh];//for chroma curve for (int i = 0; i < bfh; i++) { buflightslid[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufcolorig->L[ir][jr] = 0.f; bufcolorig->a[ir][jr] = 0.f; bufcolorig->b[ir][jr] = 0.f; } clighmax = 0.f; clighmin = 100000.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufcolorig->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas bufcolorig->a[loy - begy][lox - begx] = original->a[y][x];//fill square buffer with datas bufcolorig->b[loy - begy][lox - begx] = original->b[y][x];//fill square buffer with datas chprov = 0.f; chpro = 0.f; //Chroma curve if (cclocalcurve && lp.qualcurvemet != 0) { // C=f(C) curve float chromat = sqrt (SQR (bufcolorig->a[loy - begy][lox - begx]) + SQR (bufcolorig->b[loy - begy][lox - begx])); float ch; float ampli = 25.f; ch = (cclocalcurve[chromat * adjustr ]) / ((chromat + 0.00001f) * adjustr); //ch between 0 and 0 50 or more if (ch <= 1.f) {//convert data curve near values of slider -100 + 100, to be used after to detection shape chpro = 99.f * ch - 99.f; } else { chpro = CLIPCHRO (ampli * ch - ampli); //ampli = 25.f arbitrary empirical coefficient between 5 and 50 } bufchro[loy - begy][lox - begx] = chpro; } //slider lightness clighL = 0.f; if (lp.ligh != 0.f && lp.curvact) { float lL; float lighLnew; float amplil = 140.f; float lighL = bufcolorig->L[loy - begy][lox - begx]; calclight (lighL, lp.ligh , lighLnew, true);//replace L-curve lL = lighLnew / lighL; if (lL <= 1.f) {//convert data curve near values of slider -100 + 100, to be used after to detection shape clighL = 99.f * lL - 99.f; } else { clighL = CLIPLIG (amplil * lL - amplil); //ampli = 25.f arbitrary empirical coefficient between 5 and 150 } buflightslid[loy - begy][lox - begx] = clighL; } cligh = 0.f; //luma curve if (lllocalcurve && lp.qualcurvemet == 2) {// L=f(L) curve enhanced float lh; float amplil = 25.f; float lighn = bufcolorig->L[loy - begy][lox - begx]; lh = (lllocalcurve[lighn * 1.9f]) / ((lighn + 0.00001f) * 1.9f) ; // / ((lighn) / 1.9f) / 3.61f; //lh between 0 and 0 50 or more if (lh <= 1.f) {//convert data curve near values of slider -100 + 100, to be used after to detection shape cligh = 0.3f * (100.f * lh - 100.f);//0.3 reduce sensibility } else { cligh = CLIPLIG (amplil * lh - amplil); } buflight[loy - begy][lox - begx] = cligh; } } } } ColorLight_Local (call, bufcolorig, bufcoltra, buflight, bufchro, buflightslid, sp, moy, hueplus, huemoins, hueref, dhue, chromaref, lumaref, locallutili, lllocalcurve, loclhCurve, cclocalcurve, chprov, clighmax, lp, deltE, original, transformed, cx, cy); if (call <= 3) { delete bufcolorig; // delete bufcoltra; for (int i = 0; i < bfh; i++) { delete [] buflight[i]; } delete [] buflight; for (int i = 0; i < bfh; i++) { delete [] bufchro[i]; } delete [] bufchro; for (int i = 0; i < bfh; i++) { delete [] buflightslid[i]; } delete [] buflightslid; } } //inverse else if (lp.inv && (lp.chro != 0 || lp.ligh != 0.f) && lp.colorena) { InverseColorLight_Local (lp, original, transformed, cx, cy); } if (!lp.inv && lp.cont != 0 && lp.colorena) { //contrast interior ellipse const float pm = lp.cont < 0.f ? -1.f : 1.f; float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } LabImage *bufcontorig; float **buflightc; int bfh, bfw; float clighc = 0.f; const float localtype = lumaref; // const float localtype = ave; float reducac; float corered; if (lp.sens < 30.f) { reducac = 0.2f * (lp.sens / 100.f); } else { float areduc = 0.6285714f; //0.44f/0.7f; float breduc = 0.5f - areduc; reducac = areduc * (lp.sens / 100.f) + breduc; } const float realcox = lco.dx, realcoy = lco.dy; lco.alsup = (-realcox) / (localtype / 2.f); lco.blsup = -lco.alsup * localtype; lco.alsup2 = (realcoy) / (50.f - localtype / 2.f); lco.blsup2 = -lco.alsup2 * localtype; lco.alsup3 = (realcoy) / (localtype / 2.f - 50.f); lco.blsup3 = -lco.alsup3 * 100.f; lco.aDY = realcoy; lco.alinf = realcox / (localtype / 2.f); const float vi = (localtype / 2.f) / 100.f; const float vinf = (50.f + localtype / 2.f) / 100.f; ImProcFunctions::secondeg_begin (reducac, vi, lco.aa, lco.bb);//parabolic ImProcFunctions::secondeg_end (reducac, vinf, lco.aaa, lco.bbb, lco.ccc);//parabolic if (call <= 3) { //simpleprocess, dcrop, improccoordinator int GW = transformed->W; int GH = transformed->H; bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone bfw = int (lp.lx + lp.lxL) + del; bufcontorig = new LabImage (bfw, bfh);//buffer for data in zone limit buflightc = new float*[bfh];//for lightness curve for (int i = 0; i < bfh; i++) { buflightc[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufcontorig->L[ir][jr] = 0.f; // bufcontorig->a[ir][jr] = 0.f; // bufcontorig->b[ir][jr] = 0.f; } float maxc = -10000.f; float minc = +10000.f; float localty; localty = localtype; #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufcontorig->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas //slider contrast clighc = 1.f; corered = 0.f; if (lp.cont != 0.f && lp.curvact) { float cL; float amplil = 150.f; float prov100 = bufcontorig->L[loy - begy][lox - begx] / 32768.f; float prov = prov100 * 100.f; cL = 1.f; if (prov > localty) { if (prov >= localty && prov < 50.f + localty / 2.f) { float core = (lco.alsup2 * prov + lco.blsup2) ; corered = prov + pm * (prov - localty) * (core); } else { float core = lco.aDY * (lco.aaa * prov100 * prov100 + lco.bbb * prov100 + lco.ccc); corered = prov + pm * (prov - localty) * (core); } } else { if (2.f * prov > localty && prov < localty) { float core = (lco.alsup * prov + lco.blsup) ; corered = prov - pm * (localty - prov) * core; } else if (2.f * prov <= localty) { float core = prov * lco.alinf * (lco.aa * prov100 * prov100 + lco.bb * prov100); corered = prov - pm * (localty - prov) * core; } } cL = corered / prov; if (cL <= 1.f) {//convert data curve near values of slider -100 + 100, to be used after to detection shape clighc = 99.f * cL - 99.f; } else { clighc = CLIPLIG (amplil * cL - amplil); //arbitrary empirical coefficient between 5 and 150 } /* if (clighc > maxc) { maxc = clighc; } if (clighc < minc) { minc = clighc; } */ buflightc[loy - begy][lox - begx] = clighc; } } } // printf ("min=%2.2f max=%2.2f", minc, maxc); } Contrast_Local (call, ave, bufcontorig, buflightc, moy, hueplus, huemoins, hueref, dhue, chromaref, pm, lco, lumaref, av, lp, deltE, original, transformed, cx, cy); if (call <= 3) { delete bufcontorig; for (int i = 0; i < bfh; i++) { delete [] buflightc[i]; } delete [] buflightc; } } else if (lp.inv && lp.cont != 0 && lp.colorena) { float multL = (float)lp.cont * (maxl - 1.f) / 100.f + 1.f; float multH = (float) lp.cont * (maxh - 1.f) / 100.f + 1.f; lco.ah = (multH - 1.f) / (av - 100.f); //av ==> lumaref lco.bh = 1.f - 100.f * lco.ah; lco.al = (multL - 1.f) / av; lco.bl = 1.f; InverseContrast_Local (ave, lco, lp, original, transformed, cx, cy); } // end contrast interior and exterior //Tone mapping //&& lp.tonemapena if (lp.strengt != 0.f && lp.tonemapena) { LabImage *tmp1; LabImage *tmp; float **buflight; LabImage *bufgb; int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; int GW = transformed->W; int GH = transformed->H; int Hd = bfh; int Wd = bfw; if (call <= 3) { //simpleprocess dcrop improcc bufgb = new LabImage (bfw, bfh); buflight = new float*[bfh];//for lightness reti for (int i = 0; i < bfh; i++) { buflight[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufgb->L[ir][jr] = 0.f; bufgb->a[ir][jr] = 0.f; bufgb->b[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufgb->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas bufgb->a[loy - begy][lox - begx] = original->a[y][x];//fill square buffer with datas bufgb->b[loy - begy][lox - begx] = original->b[y][x];//fill square buffer with datas } } tmp1 = new LabImage (bfw, bfh); ImProcFunctions::EPDToneMaplocal (bufgb, tmp1, 5 , 1); } /*else { //stay here in case of tmp = new LabImage (transformed->W, transformed->H); tmp->CopyFrom (original); tmp1 = new LabImage (transformed->W, transformed->H); ImProcFunctions::EPDToneMaplocal (tmp, tmp1, 5 , sk); delete tmp; } */ float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } float maxc = -10000.f; float minc = +10000.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { float rL; rL = CLIPRET ((tmp1->L[loy - begy][lox - begx] - original->L[y][x]) / 400.f); /* if (rL > maxc) { maxc = rL; } if (rL < minc) { minc = rL; } */ buflight[loy - begy][lox - begx] = rL; } } // printf ("min=%2.2f max=%2.2f", minc, maxc); TM_Local (call, sp, tmp1, buflight, hueplus, huemoins, hueref, dhue, chromaref, lumaref, lp, deltE, original, transformed, cx, cy); if (call <= 3) { delete bufgb; for (int i = 0; i < bfh; i++) { delete [] buflight[i]; } delete [] buflight; } delete tmp1; } //begin cbdl if (lp.mulloc[0] != 1.f || lp.mulloc[1] != 1.f || lp.mulloc[2] != 1.f || lp.mulloc[3] != 1.f || lp.mulloc[4] != 1.f && lp.cbdlena) { int GW = original->W; int GH = original->H; float **bufsh;//buffer por square zone float **loctemp; float **hbuffer; int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; float b_l = -5.f; float t_l = 25.f; float t_r = 120.f; float b_r = 170.f; double skinprot = 0.; int choice = 0; float **buflight; if (call <= 3) { //call from simpleprocess dcrop improcc bufsh = new float*[bfh]; for (int i = 0; i < bfh; i++) { bufsh[i] = new float[bfw]; } buflight = new float*[bfh];//for lightness reti for (int i = 0; i < bfh; i++) { buflight[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufsh[ir][jr] = 0.f; buflight[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufsh[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas } } loctemp = new float*[bfh];//allocate temp for (int i = 0; i < bfh; i++) { loctemp[i] = new float[bfw]; } hbuffer = new float*[bfh];//allocate buffer for sharp for (int i = 0; i < bfh; i++) { hbuffer[i] = new float[bfw]; } ImProcFunctions::cbdl_local_temp (bufsh, bufsh, loctemp, bfw, bfh, lp.mulloc, lp.threshol, skinprot, false, b_l, t_l, t_r, b_r, choice, sk); float maxc = -10000.f; float minc = +10000.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { float rL; rL = CLIPRET ((loctemp[loy - begy][lox - begx] - original->L[y][x]) / 330.f); /* if (rL > maxc) { maxc = rL; } if (rL < minc) { minc = rL; } */ buflight[loy - begy][lox - begx] = rL; } } // printf ("min=%2.2f max=%2.2f", minc, maxc); } /* else { //call from dcrop.cc loctemp = new float*[GH];//allocate temp for (int i = 0; i < GH; i++) { loctemp[i] = new float[GW]; } ImProcFunctions::cbdl_local_temp (original->L, original->L, loctemp, GW, GH, lp.mulloc, lp.threshol, skinprot, false, b_l, t_l, t_r, b_r, choice, sk); } */ // I initialize these variable in case of ! float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } cbdl_Local (call, sp, buflight, loctemp, hueplus, huemoins, hueref, dhue, chromaref, lumaref, lp, deltE, original, transformed, cx, cy); if (call <= 3) { for (int i = 0; i < bfh; i++) { delete [] loctemp[i]; } delete [] loctemp; for (int i = 0; i < bfh; i++) { delete [] bufsh[i]; } delete [] bufsh; for (int i = 0; i < bfh; i++) { delete [] hbuffer[i]; } delete [] hbuffer; for (int i = 0; i < bfh; i++) { delete [] buflight[i]; } delete [] buflight; } /* else { for (int i = 0; i < GH; i++) { delete [] loctemp[i]; } delete [] loctemp; } */ } // } //end cbdl if (!lp.invshar && lp.shrad > 0.42 && call < 3 && lp.sharpena) { //interior ellipse for sharpening, call = 1 and 2 only with Dcrop and simpleprocess int GW = original->W; int GH = original->H; float **bufsh;//buffer por square zone float **loctemp; float **hbuffer; int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; if (call == 2) { //call from simpleprocess bufsh = new float*[bfh]; for (int i = 0; i < bfh; i++) { bufsh[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufsh[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufsh[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas } } loctemp = new float*[bfh];//allocate temp for (int i = 0; i < bfh; i++) { loctemp[i] = new float[bfw]; } hbuffer = new float*[bfh];//allocate buffer for sharp for (int i = 0; i < bfh; i++) { hbuffer[i] = new float[bfw]; } //sharpen only square area instaed of all image ImProcFunctions::deconvsharpeningloc (bufsh, hbuffer, bfw, bfh, loctemp, params->locallab.shardamping, (double)params->locallab.sharradius / 100., params->locallab.shariter, params->locallab.sharamount); } else { //call from dcrop.cc loctemp = new float*[GH];//allocate temp for (int i = 0; i < GH; i++) { loctemp[i] = new float[GW]; } ImProcFunctions::deconvsharpeningloc (original->L, shbuffer, GW, GH, loctemp, params->locallab.shardamping, (double)params->locallab.sharradius / 100., params->locallab.shariter, params->locallab.sharamount); } float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } //sharpen ellipse and transition Sharp_Local (call, sp, loctemp, hueplus, huemoins, hueref, dhue, chromaref, lumaref, lp, deltE, original, transformed, cx, cy); //cleann all if (call == 2 && !lp.invshar) { for (int i = 0; i < bfh; i++) { delete [] loctemp[i]; } delete [] loctemp; for (int i = 0; i < bfh; i++) { delete [] bufsh[i]; } delete [] bufsh; for (int i = 0; i < bfh; i++) { delete [] hbuffer[i]; } delete [] hbuffer; } else { for (int i = 0; i < GH; i++) { delete [] loctemp[i]; } delete [] loctemp; } /* for (int i = 0; i < GH; i++) { delete [] hbuffer[i]; } delete [] hbuffer; */ } else if (lp.invshar && lp.shrad > 0.42 && call < 3 && lp.sharpena) { int GW = original->W; int GH = original->H; float **loctemp = new float*[GH]; for (int i = 0; i < GH; i++) { loctemp[i] = new float[GW]; } ImProcFunctions::deconvsharpeningloc (original->L, shbuffer, GW, GH, loctemp, params->locallab.shardamping, (double)params->locallab.sharradius / 100., params->locallab.shariter, params->locallab.sharamount); float hueplus = hueref + dhue; float huemoins = hueref - dhue; if (hueplus > M_PI) { hueplus = hueref + dhue - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhue + 2.f * M_PI; } InverseSharp_Local (sp, loctemp, hueplus, huemoins, hueref, dhue, chromaref, lumaref, lp, deltE, original, transformed, cx, cy); for (int i = 0; i < GH; i++) { delete [] loctemp[i]; } delete [] loctemp; } // } //&& lp.retiena if (lp.str > 0.f && lp.retiena) { int GW = transformed->W; int GH = transformed->H; LabImage *bufreti; float **buflight; float **bufchro; float clighL; float clighc; float **loctemp; float **hbuffer; int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone int bfw = int (lp.lx + lp.lxL) + del; float hueplus = hueref + dhueret; float huemoins = hueref - dhueret; if (hueplus > M_PI) { hueplus = hueref + dhueret - 2.f * M_PI; } if (huemoins < -M_PI) { huemoins = hueref - dhueret + 2.f * M_PI; } int Hd, Wd; Hd = GH; Wd = GW; if (!lp.invret && call <= 3) { Hd = bfh; Wd = bfw; bufreti = new LabImage (bfw, bfh); buflight = new float*[bfh];//for lightness reti for (int i = 0; i < bfh; i++) { buflight[i] = new float[bfw]; } bufchro = new float*[bfh];//for chroma reti for (int i = 0; i < bfh; i++) { bufchro[i] = new float[bfw]; } #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < bfh; ir++) //fill with 0 for (int jr = 0; jr < bfw; jr++) { bufreti->L[ir][jr] = 0.f; bufreti->a[ir][jr] = 0.f; bufreti->b[ir][jr] = 0.f; } #ifdef _OPENMP #pragma omp parallel for #endif for (int y = 0; y < transformed->H ; y++) //{ for (int x = 0; x < transformed->W; x++) { int lox = cx + x; int loy = cy + y; int begx = int (lp.xc - lp.lxL); int begy = int (lp.yc - lp.lyT); if (lox >= (lp.xc - lp.lxL) && lox < (lp.xc + lp.lx) && loy >= (lp.yc - lp.lyT) && loy < (lp.yc + lp.ly)) { bufreti->L[loy - begy][lox - begx] = original->L[y][x];//fill square buffer with datas bufreti->a[loy - begy][lox - begx] = original->a[y][x];//fill square buffer with datas bufreti->b[loy - begy][lox - begx] = original->b[y][x];//fill square buffer with datas } } } float *orig[Hd] ALIGNED16; float *origBuffer = new float[Hd * Wd]; for (int i = 0; i < Hd; i++) { orig[i] = &origBuffer[i * Wd]; } float *orig1[Hd] ALIGNED16; float *origBuffer1 = new float[Hd * Wd]; for (int i = 0; i < Hd; i++) { orig1[i] = &origBuffer1[i * Wd]; } LabImage *tmpl; if (!lp.invret && call <= 3) { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { orig[ir][jr] = bufreti->L[ir][jr]; orig1[ir][jr] = bufreti->L[ir][jr]; } tmpl = new LabImage (Wd, Hd); } /* else { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { orig[ir][jr] = original->L[ir][jr]; orig1[ir][jr] = transformed->L[ir][jr]; } tmpl = new LabImage (transformed->W, transformed->H); } */ float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; ImProcFunctions::MSRLocal (orig, tmpl->L, orig1, Wd, Hd, params->locallab, sk, locRETgainCcurve, 0, 4, 0.8f, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); float maxc = -10000000.f; float minc = +10000.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { tmpl->L[ir][jr] = orig[ir][jr]; clighL = 0.f; float amplil = 1.f; if (!lp.invret) { float rL; rL = CLIPRET ((tmpl->L[ir][jr] - bufreti->L[ir][jr]) / 328.f); /* if (rL > maxc) { maxc = rL; } if (rL < minc) { minc = rL; } */ buflight[ir][jr] = rL; } } // printf ("min=%2.2f max=%2.2f", minc, maxc); //new shape detection if (!lp.invret) { Reti_Local (call, buflight, bufchro, hueplus, huemoins, hueref, dhueret, chromaref, lumaref, lp, deltE, original, transformed, tmpl, cx, cy, 0); } else { InverseReti_Local (lp, original, transformed, tmpl, cx, cy, 0); } if (params->locallab.chrrt > 0) { if (!lp.invret && call <= 3) { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { orig[ir][jr] = sqrt (SQR (bufreti->a[ir][jr]) + SQR (bufreti->b[ir][jr])); orig1[ir][jr] = sqrt (SQR (bufreti->a[ir][jr]) + SQR (bufreti->b[ir][jr])); } } /* else { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int ir = 0; ir < GH; ir += 1) for (int jr = 0; jr < GW; jr += 1) { orig[ir][jr] = sqrt (SQR (original->a[ir][jr]) + SQR (original->b[ir][jr])); orig1[ir][jr] = sqrt (SQR (transformed->a[ir][jr]) + SQR (transformed->b[ir][jr])); } } */ ImProcFunctions::MSRLocal (orig, tmpl->L, orig1, Wd, Hd, params->locallab, sk, locRETgainCcurve, 1, 4, 0.8f, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); if (!lp.invret && call <= 3) { float maxch = -10000000.f; float minch = +10000.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { float Chprov = orig1[ir][jr]; float2 sincosval; sincosval.y = Chprov == 0.0f ? 1.f : bufreti->a[ir][jr] / Chprov; sincosval.x = Chprov == 0.0f ? 0.f : bufreti->b[ir][jr] / Chprov; tmpl->a[ir][jr] = orig[ir][jr] * sincosval.y; tmpl->b[ir][jr] = orig[ir][jr] * sincosval.x; clighc = 0.f; float amplil = 1.f; if (!lp.invret) { float ra; ra = CLIPRET ((sqrt (SQR (tmpl->a[ir][jr]) + SQR (tmpl->b[ir][jr])) - Chprov) / 300.f); /* if (ra > maxch) { maxch = ra; } if (ra < minch) { minch = ra; } */ bufchro[ir][jr] = ra; } } // printf ("minch=%2.2f maxch=%2.2f", minch, maxch); } /* else { #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int ir = 0; ir < Hd; ir += 1) for (int jr = 0; jr < Wd; jr += 1) { float Chprov = orig1[ir][jr]; float2 sincosval; sincosval.y = Chprov == 0.0f ? 1.f : transformed->a[ir][jr] / Chprov; sincosval.x = Chprov == 0.0f ? 0.f : transformed->b[ir][jr] / Chprov; tmpl->a[ir][jr] = orig[ir][jr] * sincosval.y; tmpl->b[ir][jr] = orig[ir][jr] * sincosval.x; } } */ if (!lp.invret) { Reti_Local (call, buflight, bufchro, hueplus, huemoins, hueref, dhueret, chromaref, lumaref, lp, deltE, original, transformed, tmpl, cx, cy, 1); } else { InverseReti_Local (lp, original, transformed, tmpl, cx, cy, 1); } } delete tmpl; delete [] origBuffer; delete [] origBuffer1; if (!lp.invret && call <= 3) { delete bufreti; for (int i = 0; i < bfh; i++) { delete [] buflight[i]; } delete [] buflight; for (int i = 0; i < bfh; i++) { delete [] bufchro[i]; } delete [] bufchro; } } // Gamut and Munsell control - very important do not desactivated to avoid crash if (params->locallab.avoid) { TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); float wip[3][3] = { {static_cast (wiprof[0][0]), static_cast (wiprof[0][1]), static_cast (wiprof[0][2])}, {static_cast (wiprof[1][0]), static_cast (wiprof[1][1]), static_cast (wiprof[1][2])}, {static_cast (wiprof[2][0]), static_cast (wiprof[2][1]), static_cast (wiprof[2][2])} }; const bool highlight = params->toneCurve.hrenabled; const bool needHH = (lp.chro != 0.f); #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif { #ifdef __SSE2__ float atan2Buffer[transformed->W] ALIGNED16; float sqrtBuffer[transformed->W] ALIGNED16; float sincosyBuffer[transformed->W] ALIGNED16; float sincosxBuffer[transformed->W] ALIGNED16; vfloat c327d68v = F2V (327.68f); vfloat onev = F2V (1.f); #endif #ifdef _OPENMP #ifdef _DEBUG #pragma omp for schedule(dynamic,16) firstprivate(MunsDebugInfo) #else #pragma omp for schedule(dynamic,16) #endif #endif for (int y = 0; y < transformed->H; y++) { #ifdef __SSE2__ int i = 0; for (; i < transformed->W - 3; i += 4) { vfloat av = LVFU (transformed->a[y][i]); vfloat bv = LVFU (transformed->b[y][i]); if (needHH) { // only do expensive atan2 calculation if needed STVF (atan2Buffer[i], xatan2f (bv, av)); } vfloat Chprov1v = vsqrtf (SQRV (bv) + SQRV (av)); STVF (sqrtBuffer[i], Chprov1v / c327d68v); vfloat sincosyv = av / Chprov1v; vfloat sincosxv = bv / Chprov1v; vmask selmask = vmaskf_eq (Chprov1v, ZEROV); sincosyv = vself (selmask, onev, sincosyv); sincosxv = vselfnotzero (selmask, sincosxv); STVF (sincosyBuffer[i], sincosyv); STVF (sincosxBuffer[i], sincosxv); } for (; i < transformed->W; i++) { float aa = transformed->a[y][i]; float bb = transformed->b[y][i]; if (needHH) { // only do expensive atan2 calculation if needed atan2Buffer[i] = xatan2f (bb, aa); } float Chprov1 = sqrtf (SQR (bb) + SQR (aa)); sqrtBuffer[i] = Chprov1 / 327.68f; if (Chprov1 == 0.0f) { sincosyBuffer[i] = 1.f; sincosxBuffer[i] = 0.0f; } else { sincosyBuffer[i] = aa / Chprov1; sincosxBuffer[i] = bb / Chprov1; } } #endif for (int x = 0; x < transformed->W; x++) { float Lprov1 = transformed->L[y][x] / 327.68f; float2 sincosval; #ifdef __SSE2__ float HH = atan2Buffer[x]; // reading HH from line buffer even if line buffer is not filled is faster than branching float Chprov1 = sqrtBuffer[x]; sincosval.y = sincosyBuffer[x]; sincosval.x = sincosxBuffer[x]; float chr; #else float aa = transformed->a[y][x]; float bb = transformed->b[y][x]; float HH, chr; if (needHH) { // only do expensive atan2 calculation if needed HH = xatan2f (bb, aa); } float Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; if (Chprov1 == 0.0f) { sincosval.y = 1.f; sincosval.x = 0.0f; } else { sincosval.y = aa / (Chprov1 * 327.68f); sincosval.x = bb / (Chprov1 * 327.68f); } #endif #ifdef _DEBUG bool neg = false; bool more_rgb = false; // Color::pregamutlab (Lprov1, HH, chr); Chprov1 = min (Chprov1, chr); Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.92f, neg, more_rgb); #else Color::pregamutlab (Lprov1, HH, chr); Chprov1 = min (Chprov1, chr); Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.92f); #endif transformed->L[y][x] = Lprov1 * 327.68f; transformed->a[y][x] = 327.68f * Chprov1 * sincosval.y; transformed->b[y][x] = 327.68f * Chprov1 * sincosval.x; if (needHH) { float Lprov2 = original->L[y][x] / 327.68f; float correctionHue = 0.f; // Munsell's correction float correctlum = 0.f; float memChprov = sqrtf (SQR (original->a[y][x]) + SQR (original->b[y][x])) / 327.68f; float Chprov = sqrtf (SQR (transformed->a[y][x]) + SQR (transformed->b[y][x])) / 327.68f; #ifdef _DEBUG Color::AllMunsellLch (true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum, MunsDebugInfo); #else Color::AllMunsellLch (true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum); #endif if (fabs (correctionHue) < 0.015f) { HH += correctlum; // correct only if correct Munsell chroma very little. } float2 sincosval = xsincosf (HH + correctionHue); transformed->a[y][x] = 327.68f * Chprov * sincosval.y; // apply Munsell transformed->b[y][x] = 327.68f * Chprov * sincosval.x; } } } } } if (deltE) { for (int i = 0; i < GH; i++) { delete [] deltE[i]; } delete [] deltE; } #ifdef _DEBUG if (settings->verbose) { t2e.set(); printf ("Color::AllMunsellLch (correction performed in %d usec):\n", t2e.etime (t1e)); // printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); // printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhuelum[0], MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } delete MunsDebugInfo; #endif } } }