rawTherapee/rtengine/ipwavelet.cc

2882 lines
104 KiB
C++

////////////////////////////////////////////////////////////////
//
//
//
//
// code dated: December , 2014
//
// Ipwaveletcc 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
// * 2014 Jacques Desmis <jdesmis@gmail.com>
// * 2014 Ingo Weyrich <heckflosse@i-weyrich.de>
//
////////////////////////////////////////////////////////////////
#include <math.h>
#include "../rtgui/threadutils.h"
#include "rtengine.h"
#include "improcfun.h"
#include "LUT.h"
#include "array2D.h"
#include "boxblur.h"
#include "rt_math.h"
#include "mytime.h"
#include "sleef.c"
#include "opthelper.h"
#include "StopWatch.h"
#include "EdgePreservingDecomposition.h"
#ifdef _OPENMP
#include <omp.h>
#endif
#include "cplx_wavelet_dec.h"
#define TS 64 // Tile size
#define offset 25 // shift between tiles
#define fTS ((TS/2+1)) // second dimension of Fourier tiles
#define blkrad 1 // radius of block averaging
#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} }
#define med3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \
pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; \
PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \
PIX_SORT(pp[0],pp[1]); PIX_SORT(pp[3],pp[4]); PIX_SORT(pp[6],pp[7]); \
PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \
PIX_SORT(pp[0],pp[3]); PIX_SORT(pp[5],pp[8]); PIX_SORT(pp[4],pp[7]); \
PIX_SORT(pp[3],pp[6]); PIX_SORT(pp[1],pp[4]); PIX_SORT(pp[2],pp[5]); \
PIX_SORT(pp[4],pp[7]); PIX_SORT(pp[4],pp[2]); PIX_SORT(pp[6],pp[4]); \
PIX_SORT(pp[4],pp[2]); median=pp[4];} //pp4 = median
#define med2(a0,a1,a2,a3,a4,median) { \
pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; \
PIX_SORT(pp[0],pp[1]) ; PIX_SORT(pp[3],pp[4]) ; PIX_SORT(pp[0],pp[3]) ;\
PIX_SORT(pp[1],pp[4]) ; PIX_SORT(pp[1],pp[2]) ; PIX_SORT(pp[2],pp[3]) ;\
PIX_SORT(pp[1],pp[2]) ; median=pp[2] ;}
#define epsilon 0.001f/(TS*TS) //tolerance
namespace rtengine {
extern const Settings* settings;
struct cont_params {
float mul[10];
int chrom;
int chro;
int contrast;
float th;
float thH;
float conres;
float conresH;
float chrores;
float hueres;
float sky;
float b_l,t_l,b_r,t_r;
float b_ly,t_ly,b_ry,t_ry;
float b_lsl,t_lsl,b_rsl,t_rsl;
float b_lhl,t_lhl,b_rhl,t_rhl;
float edg_low, edg_mean, edg_sd, edg_max;
float lev0s, lev0n, lev1s, lev1n, lev2s, lev2n;
float b_lpast,t_lpast,b_rpast,t_rpast;
float b_lsat,t_lsat,b_rsat,t_rsat;
int rad;
int val;
int til;
int numlevH, numlevS;
float mulC[9];
float mulopaRG[9];
float mulopaBY[9];
bool curv;
bool opaBY;
bool opaRG;
bool edgcurv;
bool diagcurv;
int CHmet;
int CHSLmet;
int EDmet;
bool HSmet;
bool avoi;
float strength;
int reinforce;
bool detectedge;
int backm;
float eddet;
float eddetthr;
bool lips;
float eddetthrHi;
bool link;
bool lip3;
bool tonemap;
bool diag;
int TMmeth;
float tmstrength;
float balan;
int ite;
int contmet;
bool opaW;
int BAmet;
bool bam;
float blhigh;
float grhigh;
float blmed;
float grmed;
float bllow;
float grlow;
bool cbena;
};
int wavNestedLevels = 1;
SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, LUTf &wavclCurve, bool wavcontlutili, int skip)
{
MyTime t1e,t2e ;
t1e.set();
#ifdef _DEBUG
// init variables to display Munsell corrections
MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo();
#endif
TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working);
double wip[3][3] = {
{wiprof[0][0],wiprof[0][1],wiprof[0][2]},
{wiprof[1][0],wiprof[1][1],wiprof[1][2]},
{wiprof[2][0],wiprof[2][1],wiprof[2][2]}
};
const short int imheight=lab->H, imwidth=lab->W;
struct cont_params cp;
cp.avoi = params->wavelet.avoid;
if(params->wavelet.Medgreinf=="more") cp.reinforce = 1;
if(params->wavelet.Medgreinf=="none") cp.reinforce = 2;
if(params->wavelet.Medgreinf=="less") cp.reinforce = 3;
cp.lip3 = params->wavelet.lipst;
cp.diag = params->wavelet.tmr;
cp.balan = (float)params->wavelet.balance;
cp.ite = params->wavelet.iter;
cp.tonemap=false;
cp.bam=false;
if(params->wavelet.tmrs==0) cp.tonemap=false;
else cp.tonemap=true;
/*else if(params->wavelet.TMmethod=="std") {cp.TMmeth=1;cp.tonemap=true;}
else if(params->wavelet.TMmethod=="high") {cp.TMmeth=2;cp.tonemap=true;}
else if(params->wavelet.TMmethod=="lowhigh") {cp.TMmeth=3;cp.tonemap=true;}
*/
if(params->wavelet.TMmethod=="cont") cp.contmet=1;
else if(params->wavelet.TMmethod=="tm") cp.contmet=2;
if(params->wavelet.BAmethod!="none") cp.bam=true;
if(params->wavelet.BAmethod=="sli") cp.BAmet=1;
if(params->wavelet.BAmethod=="cur") cp.BAmet=2;
cp.tmstrength=params->wavelet.tmrs;
//cp.tonemap = params->wavelet.tmr;
if(params->wavelet.Backmethod=="black") cp.backm= 0;
if(params->wavelet.Backmethod=="grey") cp.backm = 1;
if(params->wavelet.Backmethod=="resid") cp.backm = 2;
cp.link=params->wavelet.linkedg;
cp.eddet=(float) params->wavelet.edgedetect;
cp.eddetthr=(float) params->wavelet.edgedetectthr;
cp.eddetthrHi=(float) params->wavelet.edgedetectthr2;
int N=imheight*imwidth;
int maxmul=params->wavelet.thres;
static const float scales[10] = {1.f,2.f,4.f,8.f,16.f,32.f,64.f,128.f,256.f,512.f};
float scaleskip[10];
for(int sc=0;sc<10;sc++)
scaleskip[sc]=scales[sc]/skip;
float atten0 = 0.40f;
float atten123=0.90f;
//int DaubLen = settings->daubech ? 8 : 6;
int DaubLen;
if(params->wavelet.daubcoeffmethod=="2_") DaubLen=4;
if(params->wavelet.daubcoeffmethod=="4_") DaubLen=6;
if(params->wavelet.daubcoeffmethod=="6_") DaubLen=8;
if(params->wavelet.daubcoeffmethod=="10_") DaubLen=12;
if(params->wavelet.daubcoeffmethod=="14_") DaubLen=16;
cp.CHSLmet=1;
// if(params->wavelet.CHSLmethod=="SL") cp.CHSLmet=1;
// if(params->wavelet.CHSLmethod=="CU") cp.CHSLmet=2;
cp.EDmet=1;
if(params->wavelet.EDmethod=="SL") cp.EDmet=1;
if(params->wavelet.EDmethod=="CU") cp.EDmet=2;
cp.cbena= params->wavelet.cbenab;
cp.blhigh=(float)params->wavelet.bluehigh;
cp.grhigh=(float)params->wavelet.greenhigh;
cp.blmed=(float)params->wavelet.bluemed;
cp.grmed=(float)params->wavelet.greenmed;
cp.bllow=(float)params->wavelet.bluelow;
cp.grlow=(float)params->wavelet.greenlow;
cp.curv=false;
cp.edgcurv=false;
cp.diagcurv=false;
cp.opaRG=false;
cp.opaBY=false;
cp.opaW=false;
cp.CHmet=0;
cp.HSmet=false;
if(params->wavelet.CHmethod=="with") cp.CHmet=1;
if(params->wavelet.CHmethod=="link") cp.CHmet=2;
if(params->wavelet.HSmethod=="with") cp.HSmet=true;
cp.strength = min(1.f,max(0.f,((float)params->wavelet.strength / 100.f)));
for(int m=0;m<maxmul;m++)
cp.mulC[m]=waparams.ch[m];
if(waOpacityCurveRG) cp.opaRG=true;
if(cp.opaRG) {
cp.mulopaRG[0]=200.f*(waOpacityCurveRG[0]-0.5f);
cp.mulopaRG[1]=200.f*(waOpacityCurveRG[62]-0.5f);
cp.mulopaRG[2]=200.f*(waOpacityCurveRG[125]-0.5f);
cp.mulopaRG[3]=200.f*(waOpacityCurveRG[187]-0.5f);
cp.mulopaRG[4]=200.f*(waOpacityCurveRG[250]-0.5f);
cp.mulopaRG[5]=200.f*(waOpacityCurveRG[312]-0.5f);
cp.mulopaRG[6]=200.f*(waOpacityCurveRG[375]-0.5f);
cp.mulopaRG[7]=200.f*(waOpacityCurveRG[438]-0.5f);
cp.mulopaRG[8]=200.f*(waOpacityCurveRG[500]-0.5f);
}
else {
for(int level=0;level<9;level++)
cp.mulopaRG[level] = 0.f;
}
if(waOpacityCurveBY) cp.opaBY=true;
if(cp.opaBY) {
cp.mulopaBY[0]=200.f*(waOpacityCurveBY[0]-0.5f);
cp.mulopaBY[1]=200.f*(waOpacityCurveBY[62]-0.5f);
cp.mulopaBY[2]=200.f*(waOpacityCurveBY[125]-0.5f);
cp.mulopaBY[3]=200.f*(waOpacityCurveBY[187]-0.5f);
cp.mulopaBY[4]=200.f*(waOpacityCurveBY[250]-0.5f);
cp.mulopaBY[5]=200.f*(waOpacityCurveBY[312]-0.5f);
cp.mulopaBY[6]=200.f*(waOpacityCurveBY[375]-0.5f);
cp.mulopaBY[7]=200.f*(waOpacityCurveBY[438]-0.5f);
cp.mulopaBY[8]=200.f*(waOpacityCurveBY[500]-0.5f);
}
else {
for(int level=0;level<9;level++)
cp.mulopaBY[level] = 0.f;
}
if(wavCLVCcurve) cp.edgcurv=true;
if(waOpacityCurveWL) cp.diagcurv=true;
for(int m=0;m<maxmul;m++)
cp.mul[m]=waparams.c[m];
cp.mul[9]=(float) waparams.sup;
for(int sc=0;sc<10;sc++) {//reduce strength if zoom < 100% for contrast
if(sc==0) {if(scaleskip[sc] < 1.f) cp.mul[sc]*=(atten0*scaleskip[sc]);}
else {if(scaleskip[sc] < 1.f) cp.mul[sc]*=(atten123*scaleskip[sc]);}
}
// if(settings->verbose) printf("Wav mul 0=%f 1=%f 2=%f 3=%f 4=%f 5=%f 6=%f 7=%f 8=%f 9=%f\n",cp.mul[0],cp.mul[1],cp.mul[2],cp.mul[3],cp.mul[4],cp.mul[5],cp.mul[6],cp.mul[7],cp.mul[8],cp.mul[9]);
for(int sc=0;sc<9;sc++) {//reduce strength if zoom < 100% for chroma and tuning
if(sc==0) {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten0*scaleskip[sc]);cp.mulopaRG[sc]*=(atten0*scaleskip[sc]);cp.mulopaBY[sc]*=(atten0*scaleskip[sc]);}}
else {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten123*scaleskip[sc]);cp.mulopaRG[sc]*=(atten123*scaleskip[sc]);cp.mulopaBY[sc]*=(atten123*scaleskip[sc]);}}
}
cp.chro=waparams.chro;
cp.chrom=waparams.chroma;
cp.contrast=waparams.contrast;
cp.rad=waparams.edgrad;
cp.val=waparams.edgval;
cp.til=waparams.edgthresh;
cp.conres=waparams.rescon;
cp.conresH=waparams.resconH;
cp.chrores=waparams.reschro;
//cp.hueres=waparams.reshue;
cp.hueres=2.f;
cp.th=float(waparams.thr);
cp.thH=float(waparams.thrH);
cp.sky=waparams.sky;
//skin
cp.b_l = static_cast<float>(params->wavelet.hueskin.value[0]) / 100.0f;
cp.t_l = static_cast<float>(params->wavelet.hueskin.value[1]) / 100.0f;
cp.b_r = static_cast<float>(params->wavelet.hueskin.value[2]) / 100.0f;
cp.t_r = static_cast<float>(params->wavelet.hueskin.value[3]) / 100.0f;
cp.b_ly = static_cast<float>(params->wavelet.hueskin2.value[0]) / 100.0f;
cp.t_ly = static_cast<float>(params->wavelet.hueskin2.value[1]) / 100.0f;
cp.b_ry = static_cast<float>(params->wavelet.hueskin2.value[2]) / 100.0f;
cp.t_ry = static_cast<float>(params->wavelet.hueskin2.value[3]) / 100.0f;
cp.numlevH=params->wavelet.threshold;
//shadows
cp.b_lsl = static_cast<float>(params->wavelet.bllev.value[0]);
cp.t_lsl = static_cast<float>(params->wavelet.bllev.value[1]);
cp.b_rsl = static_cast<float>(params->wavelet.bllev.value[2]);
cp.t_rsl = static_cast<float>(params->wavelet.bllev.value[3]);
cp.numlevS=params->wavelet.threshold2;
int maxlevS=9-cp.numlevH;
cp.numlevS = MIN(cp.numlevS,maxlevS);
//printf("levHigh=%d levShad=%d\n",cp.numlevH,cp.numlevS);
//highlight
cp.b_lhl = static_cast<float>(params->wavelet.hllev.value[0]);
cp.t_lhl = static_cast<float>(params->wavelet.hllev.value[1]);
cp.b_rhl = static_cast<float>(params->wavelet.hllev.value[2]);
cp.t_rhl = static_cast<float>(params->wavelet.hllev.value[3]);
//printf("BL=%f TL=%f BR=%f TR=%f\n",cp.b_lhl,cp.t_lhl,cp.b_rhl,cp.t_rhl);
//pastel
cp.b_lpast = static_cast<float>(params->wavelet.pastlev.value[0]);
cp.t_lpast = static_cast<float>(params->wavelet.pastlev.value[1]);
cp.b_rpast = static_cast<float>(params->wavelet.pastlev.value[2]);
cp.t_rpast = static_cast<float>(params->wavelet.pastlev.value[3]);
//saturated
cp.b_lsat = static_cast<float>(params->wavelet.satlev.value[0]);
cp.t_lsat = static_cast<float>(params->wavelet.satlev.value[1]);
cp.b_rsat = static_cast<float>(params->wavelet.satlev.value[2]);
cp.t_rsat = static_cast<float>(params->wavelet.satlev.value[3]);
//edge local contrast
cp.edg_low = static_cast<float>(params->wavelet.edgcont.value[0]);
cp.edg_mean = static_cast<float>(params->wavelet.edgcont.value[1]);
cp.edg_max = static_cast<float>(params->wavelet.edgcont.value[2]);
cp.edg_sd = static_cast<float>(params->wavelet.edgcont.value[3]);
//level noise
cp.lev0s =static_cast<float>(params->wavelet.level0noise.value[0]);
cp.lev0n =static_cast<float>(params->wavelet.level0noise.value[1]);
cp.lev1s =static_cast<float>(params->wavelet.level1noise.value[0]);
cp.lev1n =static_cast<float>(params->wavelet.level1noise.value[1]);
cp.lev2s =static_cast<float>(params->wavelet.level2noise.value[0]);
cp.lev2n =static_cast<float>(params->wavelet.level2noise.value[1]);
cp.detectedge = false;
cp.detectedge = params->wavelet.medianlev;
//printf("low=%f mean=%f sd=%f max=%f\n",cp.edg_low,cp.edg_mean,cp.edg_sd,cp.edg_max);
int minwin=min(imwidth,imheight);
int maxlevelcrop=9;
if(cp.mul[9]!=0)
maxlevelcrop=10;
// adap maximum level wavelet to size of crop
if(minwin*skip < 1024) maxlevelcrop = 9;//sampling wavelet 512
if(minwin*skip < 512) maxlevelcrop = 8;//sampling wavelet 256
if(minwin*skip < 256) maxlevelcrop = 7;//sampling 128
if(minwin*skip < 128) maxlevelcrop = 6;
if(minwin < 64) maxlevelcrop = 5;
// printf("minwin=%d maxcrop=%d\n",minwin, maxlevelcrop);
int levwav=params->wavelet.thres;
if(levwav==9 && cp.mul[9]!=0) levwav=10;
levwav=min(maxlevelcrop,levwav);
// determine number of levels to process.
// for(levwav=min(maxlevelcrop,levwav);levwav>0;levwav--)
// if(cp.mul[levwav-1]!=0.f || cp.curv)
// if(cp.mul[levwav-1]!=0.f)
// break;
// I suppress this fonctionality ==> crash for level < 3
if(levwav<1)
return; // nothing to do
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// begin tile processing of image
//output buffer
int realtile;
if(params->wavelet.Tilesmethod=="big") realtile=22;
if(params->wavelet.Tilesmethod=="lit") realtile=12;
int tilesize;
int overlap;
tilesize = 1024;
overlap = 128;
//tilesize=128*params->wavelet.tiles;
tilesize=128*realtile;
//overlap=(int) tilesize*params->wavelet.overl;
overlap=(int) tilesize*0.125f;
// printf("overl=%d\n",overlap);
int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip;
if(params->wavelet.Tilesmethod=="full") kall=0;
Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip);
const int numtiles = numtiles_W*numtiles_H;
LabImage * dsttmp;
if(numtiles == 1) {
dsttmp = dst;
} else {
dsttmp = new LabImage(imwidth,imheight);
for (int n=0; n<3*imwidth*imheight; n++) dsttmp->data[n] = 0;
}
//now we have tile dimensions, overlaps
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
int minsizetile=min(tilewidth, tileheight);
int maxlev2=10;
if(minsizetile < 1024 && levwav==10) maxlev2 = 9;
if(minsizetile < 512) maxlev2 = 8;
if(minsizetile < 256) maxlev2 = 7;
if(minsizetile < 128) maxlev2 = 6;
levwav=min(maxlev2,levwav);
//printf("levwav = %d\n",levwav);
int numthreads = 1;
int maxnumberofthreadsforwavelet =0;
//reduce memory for big tile size
if(kall!=0) {
if(realtile <= 22) maxnumberofthreadsforwavelet=2;
if(realtile <= 20) maxnumberofthreadsforwavelet=3;
if(realtile <= 18) maxnumberofthreadsforwavelet=4;
if(realtile <= 16) maxnumberofthreadsforwavelet=6;
if(realtile <= 14) maxnumberofthreadsforwavelet=8;
//printf("maxNRT=%d\n",maxnumberofthreadsforwavelet);
if((maxnumberofthreadsforwavelet==6 || maxnumberofthreadsforwavelet==8) && levwav==10) maxnumberofthreadsforwavelet-=2;
if(levwav <=7 && maxnumberofthreadsforwavelet ==8) maxnumberofthreadsforwavelet=0;
}
//printf("maxthre=%d\n",maxnumberofthreadsforwavelet);
#ifdef _OPENMP
// Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles
if( options.rgbDenoiseThreadLimit>0)
maxnumberofthreadsforwavelet = min(max(options.rgbDenoiseThreadLimit / 2, 1), maxnumberofthreadsforwavelet);
numthreads = MIN(numtiles,omp_get_max_threads());
if(maxnumberofthreadsforwavelet > 0)
numthreads = MIN(numthreads,maxnumberofthreadsforwavelet);
#ifdef _RT_NESTED_OPENMP
wavNestedLevels = omp_get_max_threads() / numthreads;
bool oldNested = omp_get_nested();
if(wavNestedLevels < 2)
wavNestedLevels = 1;
else
omp_set_nested(true);
if(maxnumberofthreadsforwavelet > 0)
while(wavNestedLevels*numthreads > maxnumberofthreadsforwavelet)
wavNestedLevels--;
#endif
if(settings->verbose)
printf("Ip Wavelet uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,wavNestedLevels);
#endif
#ifdef _OPENMP
#pragma omp parallel num_threads(numthreads)
#endif
{
float *mean = new float [9];
float *meanN = new float [9];
float *sigma = new float [9];
float *sigmaN = new float [9];
float *MaxP = new float [9];
float *MaxN = new float [9];
float** varhue = new float*[tileheight];
for (int i=0; i<tileheight; i++)
varhue[i] = new float[tilewidth];
float** varchro = new float*[tileheight];
for (int i=0; i<tileheight; i++)
varchro[i] = new float[tilewidth];
#ifdef _OPENMP
#pragma omp for schedule(dynamic) collapse(2)
#endif
for (int tiletop=0; tiletop<imheight; tiletop+=tileHskip) {
for (int tileleft=0; tileleft<imwidth ; tileleft+=tileWskip) {
int tileright = MIN(imwidth,tileleft+tilewidth);
int tilebottom = MIN(imheight,tiletop+tileheight);
int width = tileright-tileleft;
int height = tilebottom-tiletop;
LabImage * labco;
float **Lold;
float *LoldBuffer = NULL;
if(numtiles == 1) { // untiled processing => we can use output buffer for labco
labco = dst;
if(cp.avoi) { // we need a buffer to hold a copy of the L channel
Lold = new float*[tileheight];
LoldBuffer = new float[tilewidth*tileheight];
memcpy(LoldBuffer, lab->L[0], tilewidth*tileheight*sizeof(float));
for (int i=0; i<tileheight; i++)
Lold[i] = LoldBuffer + i*tilewidth;
}
} else {
labco = new LabImage(width,height);
Lold = lab->L;
}
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for (int i=tiletop; i<tilebottom; i++) {
int i1 = i - tiletop;
int j;
#ifdef __SSE2__
__m128 c327d68v = _mm_set1_ps(327.68f);
__m128 av, bv, huev, chrov;
for (j=tileleft; j<tileright-3; j+=4) {
int j1 = j - tileleft;
av = LVFU(lab->a[i][j]);
bv = LVFU(lab->b[i][j]);
huev = xatan2f(bv,av);
chrov = _mm_sqrt_ps(SQRV(av)+SQRV(bv)) / c327d68v;
_mm_storeu_ps(&varhue[i1][j1],huev);
_mm_storeu_ps(&varchro[i1][j1], chrov);
if(labco != lab) {
_mm_storeu_ps(&(labco->L[i1][j1]),LVFU(lab->L[i][j]));
_mm_storeu_ps(&(labco->a[i1][j1]),av);
_mm_storeu_ps(&(labco->b[i1][j1]),bv);
}
}
#else
j=tileleft;
#endif
for (; j<tileright; j++) {
int j1 = j - tileleft;
float a=lab->a[i][j];
float b=lab->b[i][j];
varhue[i1][j1]=xatan2f(b,a);
varchro[i1][j1]=(sqrtf(a*a+b*b))/327.68f;
if(labco != lab) {
labco->L[i1][j1] = lab->L[i][j];
labco->a[i1][j1] = a;
labco->b[i1][j1] = b;
}
}
}
//to avoid artifacts in blue sky
if(params->wavelet.median) {
float** tmL;
int wid=labco->W;
int hei=labco->H;
int borderL = 1;
tmL = new float*[hei];
for (int i=0; i<hei; i++)
tmL[i] = new float[wid];
for(int i = borderL; i < hei-borderL; i++ ) {
for(int j = borderL; j < wid-borderL; j++) {
tmL[i][j] = labco->L[i][j];
}
}
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for (int i=1; i<hei-1; i++) {
float pp[9],temp;
for (int j=1; j<wid-1; j++) {
if((varhue[i][j] < -1.3f && varhue[i][j] > - 2.5f) && (varchro[i][j] > 15.f && varchro[i][j] < 55.f) && labco->L[i][j] > 6000.f) //blue sky + med3x3 ==> after for more effect use denoise
med3(labco->L[i][j] ,labco->L[i-1][j], labco->L[i+1][j] ,labco->L[i][j+1],labco->L[i][j-1], labco->L[i-1][j-1],labco->L[i-1][j+1],labco->L[i+1][j-1],labco->L[i+1][j+1],tmL[i][j]);//3x3
}
}
for(int i = borderL; i < hei-borderL; i++ ) {
for(int j = borderL; j < wid-borderL; j++) {
labco->L[i][j] = tmL[i][j];
}
}
for (int i=0; i<hei; i++)
delete [] tmL[i];
delete [] tmL;
// end blue sky
}
if(numtiles == 1) {
// reduce the varhue array to get faster access in following processing and reduce peak memory usage
float temphue[(tilewidth+1)/2] ALIGNED64;
for (int i=0; i<(tileheight+1)/2; i++) {
for (int j=0; j<(tilewidth+1)/2; j++) {
temphue[j]=varhue[i*2][j*2];
}
delete [] varhue[i];
varhue[i] = new float[(tilewidth+1)/2];
memcpy(varhue[i],temphue, ((tilewidth+1)/2) * sizeof(float));
}
for(int i=(tileheight+1)/2;i<tileheight;i++) {
delete [] varhue[i];
varhue[i] = NULL;
}
} else { // reduce the varhue array to get faster access in following processing
for (int i=0; i<(tileheight+1)/2; i++) {
for (int j=0; j<(tilewidth+1)/2; j++) {
varhue[i][j]=varhue[i*2][j*2];
}
}
}
int datalen = labco->W * labco->H;
int levwavL = levwav;
bool ref0=false;
if(cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f) ref0=true;
// printf("LevwavL before: %d\n",levwavL);
if(cp.contrast == 0.f && cp.tonemap==false && cp.conres == 0.f && cp.conresH == 0.f && cp.val ==0 && !ref0 && params->wavelet.CLmethod=="all") { // no processing of residual L or edge=> we probably can reduce the number of levels
while(levwavL > 0 && cp.mul[levwavL-1] == 0.f) // cp.mul[level] == 0.f means no changes to level
levwavL--;
}
// printf("LevwavL after: %d\n",levwavL);
if(levwavL < 3) levwavL=3;//to allow edge => I always allocate 3 levels..because if user select wavelet it is to do something !!
if(levwavL > 0) {
wavelet_decomposition* Ldecomp = new wavelet_decomposition (labco->data, labco->W, labco->H, levwavL, 1, skip, max(1,wavNestedLevels), DaubLen );
if(!Ldecomp->memoryAllocationFailed) {
float madL[8][3];
bool memoryAllocationFailed = false;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for (int lvl=0; lvl<3; 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;
bool ref=false;
if(cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f) ref=true;
bool contr=false;
for(int f=0;f<levwavL;f++) {
if(cp.mul[f]!=0.f) contr=true;
}
if(cp.val > 0 || ref || contr) {//edge
Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL);
}
//init for edge and denoise
float vari[3];
vari[0]=8.f*SQR((cp.lev0n/125.0)*(1.0+ cp.lev0n/25.0));
vari[1]=8.f*SQR((cp.lev1n/125.0)*(1.0+ cp.lev1n/25.0));
vari[2]=8.f*SQR((cp.lev2n/125.0)*(1.0+ cp.lev2n/25.0));
int edge=1;
if(cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f) {
vari[0] = max(0.0001f,vari[0]);
vari[1] = max(0.0001f,vari[1]);
vari[2] = max(0.0001f,vari[2]);
float* noisevarlum = NULL; // we need a dummy to pass it to WaveletDenoiseAllL
if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge))//
memoryAllocationFailed = true;
}
ind=1;
//Flat curve for Contrast=f(H) in levels
FlatCurve* ChCurve = NULL;//curve C=f(H)
bool Chutili = false;
ChCurve = new FlatCurve(params->wavelet.Chcurve);
if (!ChCurve || ChCurve->isIdentity()) {
if (ChCurve) {
delete ChCurve;
ChCurve = NULL;
}
} else
Chutili = true;
WaveletcontAllL(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, waOpacityCurveWL, ChCurve, Chutili);
if(cp.val > 0 || ref || contr || cp.diagcurv) {//edge
Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL);
}
WaveletcontAllLfinal(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveWL, ChCurve, Chutili);
//Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL);
Ldecomp->reconstruct(labco->data, cp.strength);
}
delete Ldecomp;
}
//Flat curve for H=f(H) in residual image
FlatCurve* hhCurve = NULL;//curve H=f(H)
bool hhutili = false;
hhCurve = new FlatCurve(params->wavelet.hhcurve);
if (!hhCurve || hhCurve->isIdentity()) {
if (hhCurve) {
delete hhCurve;
hhCurve = NULL;
}
} else
hhutili = true;
if(!hhutili) {//always a or b
int levwava = levwav;
// printf("Levwava before: %d\n",levwava);
if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels
while(levwava > 0 && !cp.diag &&(((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwava-1] == 0.f )) || (cp.CHmet!=2 && (levwava == 10 || (!cp.curv || (cp.curv && cp.mulC[levwava-1] == 0.f)))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava-1] == 0.f)) && ((levwava == 10 ||(cp.CHSLmet==1 && cp.mulC[levwava-1] == 0.f)))) {
levwava--;
}
}
//printf("Levwava after: %d\n",levwava);
if(levwava > 0) {
wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwava, 1, skip, max(1,wavNestedLevels), DaubLen );
if(!adecomp->memoryAllocationFailed) {
WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true);
adecomp->reconstruct(labco->data+datalen, cp.strength);
}
delete adecomp;
}
int levwavb = levwav;
//printf("Levwavb before: %d\n",levwavb);
if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels
while(levwavb > 0 && !cp.diag && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavb-1] == 0.f )) || (cp.CHmet!=2 && (levwavb == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavb-1] == 0.f)))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb-1] == 0.f)) && ((levwavb == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavb-1] == 0.f)))) {
levwavb--;
}
}
// printf("Levwavb after: %d\n",levwavb);
if(levwavb > 0) {
wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavb, 1, skip, max(1,wavNestedLevels), DaubLen );
if(!bdecomp->memoryAllocationFailed) {
WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false);
bdecomp->reconstruct(labco->data+2*datalen, cp.strength);
}
delete bdecomp;
}
} else {// a and b
int levwavab = levwav;
// printf("Levwavab before: %d\n",levwavab);
if(cp.chrores == 0.f && !hhutili && params->wavelet.CLmethod=="all") { // no processing of residual ab => we probably can reduce the number of levels
while(levwavab > 0 && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavab-1] == 0.f )) || (cp.CHmet!=2 && (levwavab == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavab-1] == 0.f)))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab-1] == 0.f)) && ((levwavab == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavab-1] == 0.f)))) {
levwavab--;
}
}
// printf("Levwavab after: %d\n",levwavab);
if(levwavab > 0) {
wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwavab, 1, skip, max(1,wavNestedLevels), DaubLen );
wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavab, 1, skip, max(1,wavNestedLevels), DaubLen );
if(!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) {
WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true);
WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false);
WaveletAandBAllAB(labco, varhue, varchro, *adecomp, *bdecomp, cp, waOpacityCurveW, hhCurve, hhutili );
adecomp->reconstruct(labco->data+datalen, cp.strength);
bdecomp->reconstruct(labco->data+2*datalen, cp.strength);
}
delete adecomp;
delete bdecomp;
}
}
if (hhCurve)
delete hhCurve;
if(numtiles > 1 || (numtiles == 1 /*&& cp.avoi*/)) {//in all case since I add contrast curve
//calculate mask for feathering output tile overlaps
float Vmask[height+overlap] ALIGNED16;
float Hmask[width+overlap] ALIGNED16;
if(numtiles > 1) {
for (int i=0; i<height; i++) {
Vmask[i] = 1;
}
for (int j=0; j<width; j++) {
Hmask[j] = 1;
}
for (int i=0; i<overlap; i++) {
float mask = SQR(sin((M_PI*i)/(2*overlap)));
if (tiletop>0) Vmask[i] = mask;
if (tilebottom<imheight) Vmask[height-i] = mask;
if (tileleft>0) Hmask[i] = mask;
if (tileright<imwidth) Hmask[width-i] = mask;
}
}
bool highlight = params->toneCurve.hrenabled;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for schedule(dynamic,16) num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for (int i=tiletop; i<tilebottom; i++){
int i1 = i-tiletop;
float L,a,b;
#ifdef __SSE2__
int rowWidth = tileright - tileleft;
float atan2Buffer[rowWidth] ALIGNED64;
float chprovBuffer[rowWidth] ALIGNED64;
float xBuffer[rowWidth] ALIGNED64;
float yBuffer[rowWidth] ALIGNED64;
if(cp.avoi) {
int col;
__m128 av,bv;
__m128 cv,yv,xv;
__m128 zerov = _mm_setzero_ps();
__m128 onev = _mm_set1_ps(1.f);
__m128 c327d68v = _mm_set1_ps(327.68f);
vmask xyMask;
for(col = 0;col<rowWidth-3;col+=4) {
av = LVFU(labco->a[i1][col]);
bv = LVFU(labco->b[i1][col]);
_mm_store_ps(&atan2Buffer[col],xatan2f(bv,av));
cv = _mm_sqrt_ps(SQRV(av)+SQRV(bv));
yv = av / cv;
xv = bv / cv;
xyMask = vmaskf_eq(zerov, cv);
yv = vself(xyMask, onev, yv);
xv = vself(xyMask, zerov, xv);
_mm_store_ps(&yBuffer[col],yv);
_mm_store_ps(&xBuffer[col],xv);
_mm_store_ps(&chprovBuffer[col], cv / c327d68v);
}
for(;col<rowWidth;col++) {
float a = labco->a[i1][col];
float b = labco->b[i1][col];
atan2Buffer[col] = xatan2f(b,a);
float Chprov1=sqrtf(SQR(a) + SQR(b));
yBuffer[col] = (Chprov1 == 0.f) ? 1.f : a/Chprov1;
xBuffer[col] = (Chprov1 == 0.f) ? 0.f : b/Chprov1;
chprovBuffer[col] = Chprov1/327.68;
}
}
#endif
for (int j=tileleft; j<tileright; j++) {
int j1=j-tileleft;
if(cp.avoi){//Gamut and Munsell
#ifdef __SSE2__
float HH = atan2Buffer[j1];
float Chprov1 = chprovBuffer[j1];
float2 sincosv;
sincosv.y = yBuffer[j1];
sincosv.x = xBuffer[j1];
#else
a = labco->a[i1][j1];
b = labco->b[i1][j1];
float HH=xatan2f(b,a);
float Chprov1=sqrtf(SQR(a) + SQR(b));
float2 sincosv;
sincosv.y = (Chprov1==0.0f) ? 1.f : a/(Chprov1);
sincosv.x = (Chprov1==0.0f) ? 0.f : b/(Chprov1);
Chprov1 /= 327.68f;
#endif
L = labco->L[i1][j1];
const float Lin=labco->L[i1][j1];
if(wavclCurve) {labco->L[i1][j1] =(0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve
L = labco->L[i1][j1];
float Lprov1=L/327.68f;
float Lprov2 = Lold[i][j]/327.68f;
float memChprov=varchro[i1][j1];
float R,G,B;
#ifdef _DEBUG
bool neg=false;
bool more_rgb=false;
Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb);
#else
Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f);
#endif
L=Lprov1*327.68f;
a=327.68f*Chprov1*sincosv.y;//gamut
b=327.68f*Chprov1*sincosv.x;//gamut
float correctionHue=0.0f; // Munsell's correction
float correctlum=0.0f;
Lprov1=L/327.68f;
float Chprov=sqrtf(SQR(a)+ SQR(b))/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(correctionHue!=0.f || correctlum!=0.f) { // only calculate sin and cos if HH changed
if(fabs(correctionHue) < 0.015f)
HH+=correctlum; // correct only if correct Munsell chroma very little.
sincosv = xsincosf(HH+correctionHue);
}
a=327.68f*Chprov*sincosv.y;// apply Munsell
b=327.68f*Chprov*sincosv.x;//aply Munsell
} else {//general case
L = labco->L[i1][j1];
const float Lin=labco->L[i1][j1];
if(wavclCurve) {labco->L[i1][j1] = (0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve
L = labco->L[i1][j1];
a = labco->a[i1][j1];
b = labco->b[i1][j1];
}
if(numtiles > 1) {
float factor = Vmask[i1]*Hmask[j1];
dsttmp->L[i][j]+= factor*L;
dsttmp->a[i][j]+= factor*a;
dsttmp->b[i][j]+= factor*b;
} else {
dsttmp->L[i][j] = L;
dsttmp->a[i][j] = a;
dsttmp->b[i][j] = b;
}
}
}
}
if(LoldBuffer != NULL) {
delete [] LoldBuffer;
delete [] Lold;
}
if(numtiles>1)
delete labco;
}
}
for (int i=0; i<tileheight; i++)
if(varhue[i] != NULL)
delete [] varhue[i];
delete [] varhue;
for (int i=0; i<tileheight; i++)
delete [] varchro[i];
delete [] varchro;
delete [] mean;
delete [] meanN;
delete [] sigma;
delete [] sigmaN;
}
#ifdef _RT_NESTED_OPENMP
omp_set_nested(oldNested);
#endif
if(numtiles > 1) {
dst->CopyFrom(dsttmp);
delete dsttmp;
}
if (settings->verbose) {
t2e.set();
printf("Wavelet performed in %d usec:\n", t2e.etime(t1e));
}
}//end o
#undef TS
#undef fTS
#undef offset
#undef epsilon
void ImProcFunctions::Aver( float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) {
//find absolute mean
int countP = 0, countN = 0;
float averaP = 0.f, averaN = 0.f;
float thres = 5.f;//different fom zero to take into account only data large enough
max=0.f;
min=0.f;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
{
float lmax = 0.f, lmin = 0.f;
#ifdef _RT_NESTED_OPENMP
#pragma omp for reduction(+:averaP,averaN,countP,countN) nowait
#endif
for(int i=0;i<datalen;i++) {
if(DataList[i] >= thres) {
averaP += DataList[i];
if(DataList[i]> lmax)
lmax = DataList[i];
countP++;
}
else if(DataList[i] < -thres) {
averaN += DataList[i];
if(DataList[i] < lmin)
lmin = DataList[i];
countN++;
}
}
#ifdef _RT_NESTED_OPENMP
#pragma omp critical
#endif
{
max = max > lmax ? max : lmax;
min = min < lmin ? min : lmin;
}
}
averagePlus=averaP/countP;
averageNeg=averaN/countN;
}
void ImProcFunctions::Sigma( float * RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg) {
int countP = 0, countN = 0;
float variP = 0.f, variN = 0.f;
float thres = 5.f;//different fom zero to take into account only data large enough
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for reduction(+:variP,variN,countP,countN) num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for(int i=0;i<datalen;i++) {
if(DataList[i] >= thres) {
variP += SQR(DataList[i] - averagePlus);
countP++;
}
else if(DataList[i] <= -thres) {
variN += SQR(DataList[i] - averageNeg);
countN++;
}
}
sigmaPlus=sqrt(variP/countP);
sigmaNeg=sqrt(variN/countN);
}
void ImProcFunctions::Evaluate2(wavelet_decomposition &WaveletCoeffs_L,
struct cont_params cp, int ind, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, float madL[8][3]){
//StopWatch Stop1("Evaluate2");
int maxlvl = WaveletCoeffs_L.maxlevel();
for (int lvl=0; lvl<maxlvl; lvl++) {
int Wlvl_L = WaveletCoeffs_L.level_W(lvl);
int Hlvl_L = WaveletCoeffs_L.level_H(lvl);
int skip_L = WaveletCoeffs_L.level_stride(lvl);
float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl);
Eval2 (WavCoeffs_L, lvl, cp, Wlvl_L, Hlvl_L, skip_L, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL[lvl]);
}
}
void ImProcFunctions::Eval2 (float ** WavCoeffs_L, int level,struct cont_params cp,
int W_L, int H_L, int skip_L, int ind, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, float *madL)
{
const float eps = 0.01f;
float ava[4], avb[4], avLP[4], avLN[4];
float maxL[4], minL[4], maxa[4], maxb[4];
float sigP[4], sigN[4];
float AvL,AvN,SL,SN, maxLP, maxLN,MADL;
float madLlev[10];
float thr= params->wavelet.thres;
for (int dir=1; dir<4; dir++) {
Aver(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir]);
Sigma(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], sigP[dir], sigN[dir]);
// printf("dir=%d level=%d avLP=%f max=%f avLN=%f min=%f sigP=%f sigN=%f\n",dir,level,avLP[dir] ,maxL[dir], avLN[dir] ,minL[dir], sigP[dir], sigN[dir]);
}
AvL=0.f;AvN=0.f;SL=0.f;SN=0.f;maxLP=0.f;maxLN=0.f;MADL=0.f;
for (int dir=1; dir<4; dir++) {
AvL +=avLP[dir];
AvN +=avLN[dir];
SL +=sigP[dir];
SN +=sigN[dir];
maxLP += maxL[dir];
maxLN += minL[dir];
MADL += madL[dir];
}
AvL/=3;
AvN/=3;
SL/=3;
SN/=3;
maxLP/=3;
maxLN/=3;
MADL/=3;
if(level < 3) MADL=sqrt(MADL);else MADL=0.f;
mean[level]=AvL;
meanN[level]=AvN;
sigma[level]=SL;
sigmaN[level]=SN;
MaxP[level]=maxLP;
MaxN[level]=maxLN;
// if(params->wavelet.CLmethod!="all") {//display only if user choose different from all
// printf("Ind=%d Level=%d MadL=%f AvL=%f AvN=%f SL=%f SN=%f maxP=%f maxN=%f\n",ind, level,MADL,mean[level],meanN[level],sigma[level],sigmaN[level],MaxP[level],MaxN[level]);
// }
}
float *ImProcFunctions::ContrastDR(float *Source, int skip, struct cont_params cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Contrast){
int n=W_L*H_L;
if(Contrast == NULL) Contrast = new float[n];
memcpy(Contrast, Source, n*sizeof(float));
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for
#endif
for (int i=0; i<W_L*H_L; i++) {//contrast
/*
//source between 0 and 1
if(Source[i] < 1.f) {
float prov;
if( 32768.f*Source[i]> ave) {
float kh = ah*(Source[i]*100.f)+bh;
prov=32768.f*Source[i];
Contrast[i]=ave+kh*(Source[i]*32768.f-ave);
} else {
float kl = al*(Source[i]*100.f)+bl;
prov=32768.f*Source[i];
Contrast[i]=ave-kl*(ave-Source[i]*32768.f);
}
float diflc=Contrast[i]-prov;
diflc*=factorx;
Contrast[i] = (prov + diflc)/32768.f;
//contrast between 0 and 1
}
*/
Contrast[i] = Source[i] ;
}
return Contrast;
}
SSEFUNCTION float *ImProcFunctions::CompressDR(float *Source, int skip, struct cont_params cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Compressed){
const float eps = 0.000001f;
int n=W_L*H_L;
#ifdef __SSE2__
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel
#endif
{
__m128 epsv = _mm_set1_ps( eps );
#ifdef _RT_NESTED_OPENMP
#pragma omp for
#endif
for(int ii = 0; ii < n-3; ii+=4)
_mm_storeu_ps( &Source[ii], xlogf(LVFU(Source[ii]) + epsv));
}
for(int ii = n-(n%4); ii < n; ii++)
Source[ii] = xlogf(Source[ii] + eps);
#else
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for
#endif
for(int ii = 0; ii < n; ii++)
Source[ii] = xlogf(Source[ii] + eps);
#endif
float *ucr =ContrastDR(Source, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx);
if(Compressed == NULL) Compressed = ucr;
float temp;
if(DetailBoost>0.f && DetailBoost < 0.05f ) {
float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2)
temp = 1.2f*xlogf( -betemp);
temp /= 20.f;
}
else if(DetailBoost>=0.05f && DetailBoost < 0.25f ) {
float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2)
temp = 1.2f*xlogf( -betemp);
temp /= (-75.f*DetailBoost+23.75f);
}
else if(DetailBoost>=0.25f) {
float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2)
temp = 1.2f*xlogf( -betemp);
temp /= (-2.f*DetailBoost + 5.5f);
}
else temp= (Compression - 1.0f)/20.f;
// printf("temp=%f \n", temp);
#ifdef __SSE2__
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel
#endif
{
__m128 cev, uev, sourcev;
__m128 epsv = _mm_set1_ps( eps );
__m128 DetailBoostv = _mm_set1_ps( DetailBoost );
__m128 tempv = _mm_set1_ps( temp );
#ifdef _RT_NESTED_OPENMP
#pragma omp for
#endif
for(int i = 0; i < n-3; i+=4){
cev = xexpf(LVFU(Source[i]) + LVFU(ucr[i])*(tempv)) - epsv;
uev = xexpf(LVFU(ucr[i])) - epsv;
sourcev = xexpf(LVFU(Source[i])) - epsv;
_mm_storeu_ps( &Source[i], sourcev);
_mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) );
}
}
for(int i=n-(n%4); i < n; i++){
float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps;
float ue = xexpf(ucr[i]) - eps;
Source[i] = xexpf(Source[i]) - eps;
Compressed[i] = ce + DetailBoost*(Source[i] - ue);
}
#else
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for
#endif
for(int i = 0; i < n; i++){
float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps;
float ue = xexpf(ucr[i]) - eps;
Source[i] = xexpf(Source[i]) - eps;
Compressed[i] = ce + DetailBoost*(Source[i] - ue);
}
#endif
if(Compressed != ucr) delete[] ucr;
return Compressed;
}
void ImProcFunctions::ContrastResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params cp, int W_L, int H_L, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx) {
float stren=cp.tmstrength;
float gamm=params->wavelet.gamma;
cp.TMmeth=2;//default after testing
if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;}
else if (cp.TMmeth ==2) {min0 = 0.0f;}
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for
#endif
for(int i = 0; i < W_L*H_L; i++)
{ WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0;
WavCoeffs_L0[i]*=gamm;
}
float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents.
float DetailBoost = stren;
if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing.
CompressDR(WavCoeffs_L0, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx, WavCoeffs_L0);
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for // removed schedule(dynamic,10)
#endif
for(int ii = 0; ii < W_L*H_L; ii++)
WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0;
}
void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params cp, int W_L, int H_L, float max0, float min0) {
float stren=cp.tmstrength;
float edgest=params->epd.edgeStopping;
float sca=params->epd.scale;
float gamm=params->wavelet.gamma;
float rew=params->epd.reweightingIterates;
EdgePreservingDecomposition epd = EdgePreservingDecomposition(W_L, H_L);
cp.TMmeth=2;//default after testing
if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;}
else if (cp.TMmeth ==2) {min0 = 0.0f;}
// max0=32768.f;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for
#endif
for(int i = 0; i < W_L*H_L; i++)
{ WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0;
WavCoeffs_L0[i]*=gamm;
}
float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents.
float DetailBoost = stren;
if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing.
//Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur.
if(Iterates == 0) Iterates = (unsigned int)(edgest*15.0f);
epd.CompressDynamicRange(WavCoeffs_L0, sca/float(skip), edgest, Compression, DetailBoost, Iterates, rew, WavCoeffs_L0);
//Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping.
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for // removed schedule(dynamic,10)
#endif
for(int ii = 0; ii < W_L*H_L; ii++)
WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0;
}
void ImProcFunctions::WaveletcontAllLfinal(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L,
struct cont_params cp, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili){
int maxlvl = WaveletCoeffs_L.maxlevel();
int W_L = WaveletCoeffs_L.level_W(0);
int H_L = WaveletCoeffs_L.level_H(0);
float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0;
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic) collapse(2)
#endif
for (int dir=1; dir<4; dir++) {
for (int lvl=0; lvl<maxlvl; lvl++) {
int Wlvl_L = WaveletCoeffs_L.level_W(lvl);
int Hlvl_L = WaveletCoeffs_L.level_H(lvl);
float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl);
finalContAllL (maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveWL, ChCurve, Chutili);
}
}
}
void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L,
struct cont_params cp, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili){
//StopWatch Stop1("WaveletcontAllL");
int maxlvl = WaveletCoeffs_L.maxlevel();
int W_L = WaveletCoeffs_L.level_W(0);
int H_L = WaveletCoeffs_L.level_H(0);
float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0;
float maxh=2.5f;//amplification contrast above mean
float maxl=2.5f; //reduction contrast under mean
float contrast=cp.contrast;
float multL=(float)contrast*(maxl-1.f)/100.f + 1.f;
float multH=(float) contrast*(maxh-1.f)/100.f + 1.f;
double avedbl=0.f; // use double precision for big summations
float max0 = 0.f;
float min0 = FLT_MAX;
if(contrast != 0.f || cp.tonemap) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel for reduction(+:avedbl) num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
for (int i=0; i<W_L*H_L; i++) {
avedbl += WavCoeffs_L0[i];
}
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
{
float lminL = FLT_MAX;
float lmaxL = 0.f;
#ifdef _RT_NESTED_OPENMP
#pragma omp for
#endif
for(int i = 0; i < W_L*H_L; i++) {
if(WavCoeffs_L0[i] < lminL) lminL = WavCoeffs_L0[i];
if(WavCoeffs_L0[i] > lmaxL) lmaxL = WavCoeffs_L0[i];
}
#ifdef _RT_NESTED_OPENMP
#pragma omp critical
#endif
{ if(lminL < min0) min0 = lminL;
if(lmaxL > max0) max0 = lmaxL;
}
}
}
// printf("MAXmax0=%f MINmin0=%f\n",max0,min0);
//tone mapping
if(cp.tonemap && cp.contmet==2) {
//iterate = 5
EPDToneMapResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, max0, min0);
}
//end tonemapping
max0/=327.68f;
min0/=327.68f;
float ave = avedbl / (double)(W_L*H_L);
float av=ave/327.68f;
float ah=(multH-1.f)/(av-max0);//
float bh=1.f-max0*ah;
float al=(multL-1.f)/(av-min0);
float bl=1.f-min0*al;
float factorx=1.f;
float *koeLi[9];
float maxkoeLi[9];
float *koeLibuffer = NULL;
bool lipschitz =false;
lipschitz=true;
if(lipschitz==true) {
for(int y=0;y<9;y++) maxkoeLi[y]=0.f;
koeLibuffer = new float[9*H_L*W_L];
for (int i=0; i<9; i++) {
koeLi[i] = &koeLibuffer[i*W_L*H_L];
}
for(int j=0;j<9;j++)
for (int i=0; i<W_L*H_L; i++)
koeLi[j][i]=0.f;
}
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
{
if(contrast != 0.f) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step
{
#ifdef _RT_NESTED_OPENMP
#pragma omp for
#endif
for (int i=0; i<W_L*H_L; i++) {//contrast
if(WavCoeffs_L0[i] < 32768.f) {
float prov;
if( WavCoeffs_L0[i]> ave) {
float kh = ah*(WavCoeffs_L0[i]/327.68f)+bh;
prov=WavCoeffs_L0[i];
WavCoeffs_L0[i]=ave+kh*(WavCoeffs_L0[i]-ave);
} else {
float kl = al*(WavCoeffs_L0[i]/327.68f)+bl;
prov=WavCoeffs_L0[i];
WavCoeffs_L0[i]=ave-kl*(ave-WavCoeffs_L0[i]);
}
float diflc=WavCoeffs_L0[i]-prov;
diflc*=factorx;
WavCoeffs_L0[i] = prov + diflc;
}
}
}
}
if(cp.tonemap && cp.contmet==1) {
float maxp=max0*256.f;
float minp=min0*256.f;
#ifdef _RT_NESTED_OPENMP
#pragma omp single
#endif
ContrastResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, maxp, minp, ave, ah, bh, al, bl, factorx );
}
#ifdef _RT_NESTED_OPENMP
#pragma omp barrier
#endif
if(cp.conres != 0.f || cp.conresH != 0.f) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
#ifdef _RT_NESTED_OPENMP
#pragma omp for nowait
#endif
for (int i=0; i<W_L*H_L; i++) {
float LL=WavCoeffs_L0[i];
float LL100 = LL/327.68f;
float tran = 5.f;//transition
//shadow
float alp=3.f;//increase contrast sahdow in lowlights between 1 and ??
if(cp.th > (100.f-tran))
tran=100.f-cp.th;
if(LL100 < cp.th){
float aalp=(1.f-alp)/cp.th;//no changes for LL100 = cp.th
float kk=aalp*LL100+alp;
WavCoeffs_L0[i] *= (1.f+kk*cp.conres/200.f);
}
else if(LL100 < cp.th + tran) {
float ath = -cp.conres/tran;
float bth = cp.conres-ath*cp.th;
WavCoeffs_L0[i] *= (1.f+(LL100*ath+bth)/200.f);
}
//highlight
tran=5.f;
if(cp.thH < (tran))
tran = cp.thH;
if(LL100 > cp.thH)
WavCoeffs_L0[i] *= (1.f+cp.conresH/200.f);
else if(LL100 > (cp.thH - tran)) {
float athH = cp.conresH/tran;
float bthH = cp.conresH-athH*cp.thH;
WavCoeffs_L0[i] *= (1.f+(LL100*athH+bthH)/200.f);
}
}
}
//enabled Lipschitz..replace simple by complex edge detection
// I found this concept on the web (doctoral thesis on medical Imaging)
// I was inspired by the principle of Canny and Lipschitz (continuity and derivability)
// I adapted the principle but have profoundly changed the algorithm
// One can 1) change all parameters and found good parameters;
//one can also chnage in calckoe
float edd=settings->ed_detec;
float eddlow=settings->ed_low;
float eddlipinfl=settings->ed_lipinfl;
float eddlipampl=settings->ed_lipampl;
if(cp.detectedge && lipschitz==true) { //enabled Lipschitz control...more memory..more time...
float *tmCBuffer = new float[H_L*W_L];
float *tmC[H_L];
for (int i=0; i<H_L; i++){
tmC[i] = &tmCBuffer[i*W_L];
}
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic) collapse(2)
#endif
for (int lvl=0; lvl<3; lvl++) {
for (int dir=1; dir<4; dir++) {
int W_L = WaveletCoeffs_L.level_W(lvl);
int H_L = WaveletCoeffs_L.level_H(lvl);
float ** WavCoeffs_LL = WaveletCoeffs_L.level_coeffs(lvl);
calckoe(WavCoeffs_LL, cp, koeLi,lvl , dir, W_L, H_L, edd, maxkoeLi, tmC);
// return convolution KoeLi and maxkoeLi of level 0 1 2 3 and Dir Horiz, Vert, Diag
}
}
delete [] tmCBuffer;
float aamp=1.f+cp.eddetthrHi/100.f;
for (int lvl=0; lvl<3; lvl++) {
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic,16)
#endif
for (int i=1; i<H_L-1; i++) {
for (int j=1; j<W_L-1; j++) {
//treatment of koeLi and maxkoeLi
float interm = 0.f;
for (int dir=1; dir<4; dir++) {
//here I evaluate combinaison of vert / diag / horiz...we are with multiplicators of the signal
interm += SQR(koeLi[lvl*3 + dir-1][i*W_L + j]);
}
interm = sqrt(interm);
// interm /= 1.732f;//interm = pseudo variance koeLi
interm *= 0.57736721f;
float kampli = 1.f;
// I think this double ratio (alph, beta) is better than arctg
float alph = koeLi[lvl*3][i*W_L + j] / koeLi[lvl*3 + 1][i*W_L + j];//ratio between horizontal and vertical
float beta = koeLi[lvl*3+2][i*W_L + j] / koeLi[lvl*3 + 1][i*W_L + j];//ratio between diagonal and horizontal
float alipinfl=(eddlipampl-1.f)/(1.f-eddlipinfl);
float blipinfl=eddlipampl-alipinfl;
//alph evaluate the direction of the gradient regularity Lipschitz
// if = 1 we are on an edge
// if 0 we are not
// we can change and use log..or Arctg but why ?? we can change if need ...
//Liamp=1 for eddlipinfl
//liamp > 1 for alp >eddlipinfl and alph < 1
//Liamp < 1 for alp < eddlipinfl and alph > 0
if(alph > 1.f) {alph = 1.f/ alph;}
if(beta > 1.f) {beta=1.f/beta;}
//take into account diagonal
//if in same value OK
//if not no edge or reduction
float bet=1.f;
//if(cp.lip3) {//enhance algorithm
if(alph > eddlipinfl && beta < 0.85f*eddlipinfl) {//0.85 arbitrary value ==> eliminate from edge if H V D too different
bet=beta;
}
//}
float AmpLip=1.f;
if(alph > eddlipinfl) {AmpLip=alipinfl*alph+blipinfl;kampli=SQR(bet)*AmpLip*aamp;}//If beta low reduce kampli
else {AmpLip=(1.f/eddlipinfl)*SQR(SQR(alph*bet));kampli=AmpLip/aamp;}//Strong Reduce if beta low
// comparaison betwwen pixel and neighbours to do ==> I think 3 dir above is better
//koeLi[lvl*3][i*W_L + j] koeLi[lvl*3][(i-1)*W_L + j] koeLi[lvl*3][(i+1)*W_L + j]
// koeLi[lvl*3][i*W_L + j+1] koeLi[lvl*3][i*W_L + j-1]) koeLi[lvl*3][(i-1)*W_L + j-1]
// koeLi[lvl*3][(i-1)*W_L + j+1] koeLi[lvl*3][(i+1)*W_L + j-1] koeLi[lvl*3][(i+1)*W_L + j+1])
// apply to each direction Wavelet level : horizontal / vertiacle / diagonal
interm*=kampli;
if(interm < cp.eddetthr/eddlow) interm = 0.01f;//eliminate too low values
//we can change this part of algo==> not equal but ponderate
koeLi[lvl*3][i*W_L + j]=koeLi[lvl*3 + 1][i*W_L + j]=koeLi[lvl*3 + 2][i*W_L + j]=interm;//new value
//here KoeLi contains values where gradient is high and coef high, and eliminate low values...
}
}
}
// end
}
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic) collapse(2)
#endif
for (int dir=1; dir<4; dir++) {
for (int lvl=0; lvl<maxlvl; lvl++) {
int Wlvl_L = WaveletCoeffs_L.level_W(lvl);
int Hlvl_L = WaveletCoeffs_L.level_H(lvl);
float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl);
ContAllL (koeLi, maxkoeLi, lipschitz, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili);
}
}
}
//delete edge detection
if(koeLibuffer) {
delete [] koeLibuffer;
}
}
void ImProcFunctions::WaveletAandBAllAB(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_a, wavelet_decomposition &WaveletCoeffs_b,
struct cont_params cp, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* hhCurve, bool hhutili){
// StopWatch Stop1("WaveletAandBAllAB");
if (hhutili) { // H=f(H)
int W_L = WaveletCoeffs_a.level_W(0);
int H_L = WaveletCoeffs_a.level_H(0);
float * WavCoeffs_a0 = WaveletCoeffs_a.coeff0;
float * WavCoeffs_b0 = WaveletCoeffs_b.coeff0;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
{
#ifdef __SSE2__
float huebuffer[W_L] ALIGNED64;
float chrbuffer[W_L] ALIGNED64;
#endif // __SSE2__
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic,16)
#endif
for (int i=0; i<H_L; i++) {
#ifdef __SSE2__
// precalculate hue and chr
int k;
for (k=0; k<W_L-3; k+=4) {
__m128 av = LVFU(WavCoeffs_a0[i*W_L+k]);
__m128 bv = LVFU(WavCoeffs_b0[i*W_L+k]);
__m128 huev = xatan2f(bv,av);
__m128 chrv = _mm_sqrt_ps(SQRV(av)+SQRV(bv));
STVF(huebuffer[k],huev);
STVF(chrbuffer[k],chrv);
}
for(;k<W_L;k++) {
huebuffer[k] = xatan2f(WavCoeffs_b0[i*W_L+k],WavCoeffs_a0[i*W_L+k]);
chrbuffer[k] = sqrtf(SQR(WavCoeffs_b0[i*W_L+k])+SQR(WavCoeffs_a0[i*W_L+k]))/327.68f;
}
#endif // __SSE2__
for (int j=0; j<W_L; j++) {
#ifdef __SSE2__
float hueR = huebuffer[j];
float chR = chrbuffer[j];
#else
float hueR=xatan2f(WavCoeffs_b0[i*W_L+j],WavCoeffs_a0[i*W_L+j]);
float chR = sqrtf(SQR(WavCoeffs_b0[i*W_L+j])+SQR(WavCoeffs_a0[i*W_L+j]));
#endif
/* if (editID == EUID_WW_HHCurve) {//H pipette
float valpar =Color::huelab_to_huehsv2(hueR);
editWhatever->v(i,j) = valpar;
}
*/
float valparam = float((hhCurve->getVal(Color::huelab_to_huehsv2(hueR))-0.5f) * 1.7f) +hueR;//get H=f(H) 1.7 optimisation !
float2 sincosval = xsincosf(valparam);
WavCoeffs_a0[i*W_L+j]=chR*sincosval.y;
WavCoeffs_b0[i*W_L+j]=chR*sincosval.x;
}
}
}
}
}
void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_ab,const WavOpacityCurveW & waOpacityCurveW,
struct cont_params cp, const bool useChannelA){
int maxlvl = WaveletCoeffs_ab.maxlevel();
int W_L = WaveletCoeffs_ab.level_W(0);
int H_L = WaveletCoeffs_ab.level_H(0);
float * WavCoeffs_ab0 = WaveletCoeffs_ab.coeff0;
#ifdef _RT_NESTED_OPENMP
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
#endif
{
if(cp.chrores != 0.f) { // cp.chrores == 0.f means all will be multiplied by 1.f, so we can skip the processing of residual
#ifdef _RT_NESTED_OPENMP
#pragma omp for nowait
#endif
for (int i=0; i<W_L*H_L; i++) {
const float skyprot = cp.sky;
//chroma
int ii = i/W_L;
int jj = i-ii*W_L;
float modhue = varhue[ii][jj];
float scale=1.f;
if(skyprot > 0.f){
if((modhue < cp.t_ry && modhue > cp.t_ly)) {
scale=(100.f-cp.sky)/100.1f;
} else if((modhue >= cp.t_ry && modhue < cp.b_ry)) {
scale=(100.f-cp.sky)/100.1f;
float ar=(scale-1.f)/(cp.t_ry- cp.b_ry);
float br=scale-cp.t_ry*ar;
scale=ar*modhue+br;
} else if((modhue > cp.b_ly && modhue < cp.t_ly)) {
scale=(100.f-cp.sky)/100.1f;
float al=(scale-1.f)/(-cp.b_ly + cp.t_ly);
float bl=scale-cp.t_ly*al;
scale=al*modhue+bl;
}
} else if(skyprot < 0.f){
if((modhue > cp.t_ry || modhue < cp.t_ly)){
scale=(100.f+cp.sky)/100.1f;
}
/* else if((modhue >= cp.t_ry && modhue < cp.b_ry)) {
scale=(100.f+cp.sky)/100.1f;
float ar=(scale-1.f)/(cp.t_ry- cp.b_ry);
float br=scale-cp.t_ry*ar;
scale=ar*modhue+br;
}
else if((modhue > cp.b_ly && modhue < cp.t_ly)) {
scale=(100.f+cp.sky)/100.1f;
float al=(scale-1.f)/(-cp.b_ly + cp.t_ly);
float bl=scale-cp.t_ly*al;
scale=al*modhue+bl;
}
*/
}
WavCoeffs_ab0[i]*=(1.f+cp.chrores*(scale)/100.f);
}
}
if(cp.cbena) {//if user select Toning and color balance
#ifdef _RT_NESTED_OPENMP
#pragma omp for nowait
#endif
for (int i=0; i<W_L*H_L; i++) {
int ii = i/W_L;
int jj = i-ii*W_L;
float LL = (labco->L[ii*2][jj*2])/327.68f;//I use labco but I can use also WavCoeffs_L0 (more exact but more memory)
float sca=1.f;//amplifer - reducter...about 1, but perhaps 0.6 or 1.3
if(useChannelA) {//green red (little magenta)
//transition to avoid artifacts with 6 between 30 to 36 and 63 to 69
float aa=(cp.grmed-cp.grlow)/6.f;
float bb= cp.grlow-30.f*aa;
float aaa=(cp.grhigh-cp.grmed)/6.f;
float bbb= cp.grmed-63.f*aaa;
if(LL < 30.f)//shadows
WavCoeffs_ab0[i]+=cp.grlow*(sca)*300.f;
else if(LL >= 30.f && LL < 36.f) {//transition
float tr=aa*LL+bb;
WavCoeffs_ab0[i]+= tr*(sca)*300.f;
}
else if(LL >= 36.f && LL < 63.f)//midtones
WavCoeffs_ab0[i]+=cp.grmed*(sca)*300.f;
else if(LL >= 63.f && LL < 69.f) {//transition
float trh=aaa*LL+bbb;
WavCoeffs_ab0[i]+=trh*(sca)*300.f;
}
else if(LL >= 69.f)//highlights
WavCoeffs_ab0[i]+=cp.grhigh*(sca)*300.f;
}
else {//blue yellow
//transition with 6 between 30 to 36 and 63 to 69
float aa1=(cp.blmed-cp.bllow)/6.f;
float bb1= cp.bllow-30.f*aa1;
float aaa1=(cp.blhigh-cp.blmed)/6.f;
float bbb1= cp.blmed-63.f*aaa1;
if(LL < 30.f)
WavCoeffs_ab0[i]+=cp.bllow*(sca)*300.f;
else if(LL >= 30.f && LL < 36.f) {
float tr1=aa1*LL+bb1;
WavCoeffs_ab0[i]+=tr1*(sca)*300.f;
}
else if(LL >= 36.f && LL < 63.f)
WavCoeffs_ab0[i]+=cp.blmed*(sca)*300.f;
else if(LL >= 63.f && LL < 69.f) {
float trh1=aaa1*LL+bbb1;
WavCoeffs_ab0[i]+=trh1*(sca)*300.f;
}
else if(LL >= 69.f)
WavCoeffs_ab0[i]+=cp.blhigh*(sca)*300.f;
}
}
}
#ifdef _RT_NESTED_OPENMP
#pragma omp for schedule(dynamic) collapse(2)
#endif
for (int dir=1; dir<4; dir++) {
for (int lvl=0; lvl<maxlvl; lvl++) {
int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl);
int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl);
int skip_ab = WaveletCoeffs_ab.level_stride(lvl);
//printf("lev=%d skipL=%d skipab=%d\n",lvl, skip_L,skip_ab);
float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl);
ContAllAB (labco, maxlvl, varhue, varchrom, WavCoeffs_ab, WavCoeffs_ab0, lvl, dir, waOpacityCurveW, cp, Wlvl_ab, Hlvl_ab, useChannelA);
}
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void ImProcFunctions::calckoe(float ** WavCoeffs_LL, struct cont_params cp, float *koeLi[9], int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC){
int borderL = 2;
// printf("cpedth=%f\n",cp.eddetthr);
if(cp.eddetthr < 30.f) {
borderL = 1;
// I calculate coefficients with r size matrix 3x3 r=1 ; 5x5 r=2; 7x7 r=3
/*
float k[2*r][2*r];
for(int i=1;i<=(2*r+1);i++) {
for(int j=1;j<=(2*r+1);j++) {
k[i][j]=(1.f/6.283*sigma*sigma)*exp(-SQR(i-r-1)+SQR(j-r-1)/2.f*SQR(sigma));
}
}
//I could also use Gauss.h for 3x3
// If necessary I can put a 7x7 matrix
*/
for (int i=1; i<H_L-1; i++) {//sigma=0.55
for (int j=1; j<W_L-1; j++) {
tmC[i][j]=(8.94f*WavCoeffs_LL[dir][i*W_L + j] + 1.71f*(WavCoeffs_LL[dir][(i-1)*W_L + j] + 1.71f*WavCoeffs_LL[dir][(i+1)*W_L + j]
+ 1.71f*WavCoeffs_LL[dir][i*W_L + j+1] + 1.71f*WavCoeffs_LL[dir][i*W_L + j-1]) + 0.33f*WavCoeffs_LL[dir][(i-1)*W_L + j-1]
+0.33f*WavCoeffs_LL[dir][(i-1)*W_L + j+1]+0.33f*WavCoeffs_LL[dir][(i+1)*W_L + j-1]+0.33f*WavCoeffs_LL[dir][(i+1)*W_L + j+1]) * 0.0584795f;
// apply to each direction Wavelet level : horizontal / vertiacle / diagonal
}
}
}
else if(cp.eddetthr >= 30.f && cp.eddetthr < 50.f) {
borderL = 1;
for (int i=1; i<H_L-1; i++) {//sigma=0.85
for (int j=1; j<W_L-1; j++) {
tmC[i][j]=(4.0091f*WavCoeffs_LL[dir][i*W_L + j] + 2.0068f*(WavCoeffs_LL[dir][(i-1)*W_L + j] + 2.0068f*WavCoeffs_LL[dir][(i+1)*W_L + j]
+ 2.0068f*WavCoeffs_LL[dir][i*W_L + j+1] + 2.0068f*WavCoeffs_LL[dir][i*W_L + j-1]) + 1.0045f*WavCoeffs_LL[dir][(i-1)*W_L + j-1]
+1.0045f*WavCoeffs_LL[dir][(i-1)*W_L + j+1]+1.0045f*WavCoeffs_LL[dir][(i+1)*W_L + j-1]+1.0045f*WavCoeffs_LL[dir][(i+1)*W_L + j+1]) * 0.062288f;
// apply to each direction Wavelet level : horizontal / vertiacle / diagonal
}
}
}
else if(cp.eddetthr >= 50.f && cp.eddetthr < 75.f) {
borderL = 1;
for (int i=1; i<H_L-1; i++) {
for (int j=1; j<W_L-1; j++) {//sigma=1.1
tmC[i][j]=(3.025f*WavCoeffs_LL[dir][i*W_L + j] + 2.001f*(WavCoeffs_LL[dir][(i-1)*W_L + j] + 2.001f*WavCoeffs_LL[dir][(i+1)*W_L + j]
+ 2.001f*WavCoeffs_LL[dir][i*W_L + j+1] + 2.001f*WavCoeffs_LL[dir][i*W_L + j-1]) + 1.323f*WavCoeffs_LL[dir][(i-1)*W_L + j-1]
+1.323f*WavCoeffs_LL[dir][(i-1)*W_L + j+1]+1.323f*WavCoeffs_LL[dir][(i+1)*W_L + j-1]+1.323f*WavCoeffs_LL[dir][(i+1)*W_L + j+1]) * 0.06127f;
}
}
}
else if(cp.eddetthr >= 75.f) {
borderL = 2;
for (int i=2; i<H_L-2; i++) {
for (int j=2; j<W_L-2; j++) {
// Gaussian 1.1
// 0.5 2 3 2 0.5
// 2 7 10 7 2
// 3 10 15 10 3
// 2 7 10 7 2
// 0.5 2 3 2 0.5
// divi 113
//Gaussian 1.4
// 2 4 5 4 2
// 4 9 12 9 4
// 5 12 15 12 5
// 4 9 12 9 4
// 2 4 5 4 2
// divi 159
if(cp.eddetthr < 85.f){//sigma=1.1
tmC[i][j]=(15.f*WavCoeffs_LL[dir][i*W_L + j] + 10.f*WavCoeffs_LL[dir][(i-1)*W_L + j] + 10.f*WavCoeffs_LL[dir][(i+1)*W_L + j]
+ 10.f*WavCoeffs_LL[dir][i*W_L + j+1] + 10.f*WavCoeffs_LL[dir][i*W_L + j-1] + 7.f*WavCoeffs_LL[dir][(i-1)*W_L + j-1]
+7.f*WavCoeffs_LL[dir][(i-1)*W_L + j+1]+7.f*WavCoeffs_LL[dir][(i+1)*W_L + j-1]+7.f*WavCoeffs_LL[dir][(i+1)*W_L + j+1]
+3.f*WavCoeffs_LL[dir][(i-2)*W_L + j]+3.f*WavCoeffs_LL[dir][(i+2)*W_L + j]+3.f*WavCoeffs_LL[dir][i*W_L + j-2]+3.f*WavCoeffs_LL[dir][i*W_L + j+2]
+2.f*WavCoeffs_LL[dir][(i-2)*W_L + j-1]+2.f*WavCoeffs_LL[dir][(i-2)*W_L + j+1]+2.f*WavCoeffs_LL[dir][(i+2)*W_L + j+1]+2.f*WavCoeffs_LL[dir][(i+2)*W_L + j-1]
+2.f*WavCoeffs_LL[dir][(i-1)*W_L + j-2]+2.f*WavCoeffs_LL[dir][(i-1)*W_L + j+2]+2.f*WavCoeffs_LL[dir][(i+1)*W_L + j+2]+2.f*WavCoeffs_LL[dir][(i+1)*W_L + j-2]
+0.5f*WavCoeffs_LL[dir][(i-2)*W_L + j-2]+0.5f*WavCoeffs_LL[dir][(i-2)*W_L + j+2]+0.5f*WavCoeffs_LL[dir][(i+2)*W_L + j-2]+0.5f*WavCoeffs_LL[dir][(i+2)*W_L + j+2]
)*0.0088495f;
}
else {//sigma=1.4
tmC[i][j]=(15.f*WavCoeffs_LL[dir][i*W_L + j] + 12.f*WavCoeffs_LL[dir][(i-1)*W_L + j] + 12.f*WavCoeffs_LL[dir][(i+1)*W_L + j]
+ 12.f*WavCoeffs_LL[dir][i*W_L + j+1] + 12.f*WavCoeffs_LL[dir][i*W_L + j-1] + 9.f*WavCoeffs_LL[dir][(i-1)*W_L + j-1]
+9.f*WavCoeffs_LL[dir][(i-1)*W_L + j+1]+9.f*WavCoeffs_LL[dir][(i+1)*W_L + j-1]+9.f*WavCoeffs_LL[dir][(i+1)*W_L + j+1]
+5.f*WavCoeffs_LL[dir][(i-2)*W_L + j]+5.f*WavCoeffs_LL[dir][(i+2)*W_L + j]+5.f*WavCoeffs_LL[dir][i*W_L + j-2]+5.f*WavCoeffs_LL[dir][i*W_L + j+2]
+4.f*WavCoeffs_LL[dir][(i-2)*W_L + j-1]+4.f*WavCoeffs_LL[dir][(i-2)*W_L + j+1]+4.f*WavCoeffs_LL[dir][(i+2)*W_L + j+1]+4.f*WavCoeffs_LL[dir][(i+2)*W_L + j-1]
+4.f*WavCoeffs_LL[dir][(i-1)*W_L + j-2]+4.f*WavCoeffs_LL[dir][(i-1)*W_L + j+2]+4.f*WavCoeffs_LL[dir][(i+1)*W_L + j+2]+4.f*WavCoeffs_LL[dir][(i+1)*W_L + j-2]
+2.f*WavCoeffs_LL[dir][(i-2)*W_L + j-2]+2.f*WavCoeffs_LL[dir][(i-2)*W_L + j+2]+2.f*WavCoeffs_LL[dir][(i+2)*W_L + j-2]+2.f*WavCoeffs_LL[dir][(i+2)*W_L + j+2]
)*0.0062893f;
}
// apply to each direction Wavelet level : horizontal / vertiacle / diagonal
}
}
}
/*
// I suppress these 2 convolutions ==> lees good results==> probably because structure data different and also I compare to original value which have + and -
for(int i = borderL; i < H_L-borderL; i++ ) {//[-1 0 1] x==>j
for(int j = borderL; j < W_L-borderL; j++) {
tmC[i][j]=- WavCoeffs_LL[dir][(i)*W_L + j-1] + WavCoeffs_LL[dir][(i)*W_L + j+1];
}
}
for(int i = borderL; i < H_L-borderL; i++ ) {//[1 0 -1] y==>i
for(int j = borderL; j < W_L-borderL; j++) {
tmC[i][j]= - WavCoeffs_LL[dir][(i-1)*W_L + j] + WavCoeffs_LL[dir][(i+1)*W_L + j];
}
}
*/
float thr=40.f;//avoid artifact eg. noise...to test
float thr2=1.5f*edd;//edd can be modified in option ed_detect
thr2+=cp.eddet/30.f;//to test
float diffFactor = (cp.eddet/100.f);
for(int i = 0; i < H_L; i++ ) {
for(int j = 0; j < W_L; j++) {
koeLi[level*3 + dir-1][i*W_L + j]=1.f;
}
}
for(int i = borderL; i < H_L-borderL; i++ ) {
for(int j = borderL; j < W_L-borderL; j++) {
// my own algo : probably a little false, but simpler as Lipschitz !
// Thr2 = maximum of the function ==> Lipsitch says = probably edge
// float temp = WavCoeffs_LL[dir][i*W_L + j];
// if(temp>=0.f && temp < thr) temp = thr;
// if(temp < 0.f && temp > -thr) temp = -thr;
float temp = max(fabsf(WavCoeffs_LL[dir][i*W_L + j]), thr );
koeLi[level*3 + dir-1][i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp));// limit maxi
//it will be more complicated to calculate both Wh and Wv, but we have also Wd==> pseudo Lipschitz
if(koeLi[level*3+ dir-1][i*W_L + j] > maxkoeLi[level*3+ dir-1])
maxkoeLi[level*3+ dir-1] = koeLi[level*3 + dir-1][i*W_L + j];
float diff = maxkoeLi[level*3+ dir-1] - koeLi[level*3 + dir-1][i*W_L + j];
diff *= diffFactor;
koeLi[level*3 + dir-1][i*W_L + j] = maxkoeLi[level*3 + dir-1] - diff;
}
}
}
void ImProcFunctions::finalContAllL (int maxlvl, LabImage * labco, float ** varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params cp,
int W_L, int H_L, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili)
{
bool lipschitz=true;
float edge=1.f;
bool curvdiag=true;
if(curvdiag) {//curve
float insigma=0.666f;//SD
float logmax=log(MaxP[level]);//log Max
float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max
float inx=log(insigma);
float iny=log(rapX);
float rap=inx/iny;//koef
float asig=0.166f/sigma[level];
float bsig=0.5f-asig*mean[level];
float amean=0.5f/mean[level];
float absciss;
float kinterm;
float kmul;
for (int i=0; i<W_L*H_L; i++) {
edge=1.f;
kinterm=1.f;
if(cp.diagcurv) {
if(fabs(WavCoeffs_L[dir][i])>= (mean[level]+sigma[level])){//for max
float valcour=log(fabs(WavCoeffs_L[dir][i]));
float valc=valcour-logmax;
float vald=valc*rap;
absciss=exp(vald);
}
else if(fabs(WavCoeffs_L[dir][i])>=mean[level] && fabs(WavCoeffs_L[dir][i]) < (mean[level]+sigma[level])){
absciss=asig*fabs(WavCoeffs_L[dir][i])+bsig;
}
else if(fabs(WavCoeffs_L[dir][i]) < mean[level]){
absciss=amean*fabs(WavCoeffs_L[dir][i]);
}
kinterm=1.f;
kmul=1.f;
float kc = kmul*(waOpacityCurveWL[absciss*500.f]-0.5f);
float reduceeffect=1.5f;
if(kc <=0.f) reduceeffect=1.f;
kinterm = 1.f + reduceeffect*kmul*(waOpacityCurveWL[absciss*500.f]-0.5f);
if(kinterm<0.f) kinterm=0.01f;
}
WavCoeffs_L[dir][i] *= kinterm;
}
}
int choicelevel = atoi(params->wavelet.Lmethod.data())-1;
choicelevel = choicelevel == -1 ? 4 : choicelevel;
int choiceClevel=0;
if(params->wavelet.CLmethod=="one") choiceClevel=0;
else if(params->wavelet.CLmethod=="inf") choiceClevel=1;
else if(params->wavelet.CLmethod=="sup") choiceClevel=2;
else if(params->wavelet.CLmethod=="all") choiceClevel=3;
int choiceDir=0;
if(params->wavelet.Dirmethod=="one") choiceDir=1;
else if(params->wavelet.Dirmethod=="two") choiceDir=2;
else if(params->wavelet.Dirmethod=="thr") choiceDir=3;
else if(params->wavelet.Dirmethod=="all") choiceDir=0;
int dir1 = (choiceDir == 2) ? 1 : 2;
int dir2 = (choiceDir == 3) ? 1 : 3;
if(choiceClevel<3) { // not all levels visible, paint residual
if(level == 0) {
if(cp.backm!=2) { // nothing to change when residual is used as background
float backGroundColor = (cp.backm==1) ? 12000.f : 0.f;
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L0[i] = backGroundColor;
}
}
}
}
if(choiceClevel==0) { // Only one level
if(level != choicelevel){ // zero all for the levels != choicelevel
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir][i] = 0.f;
}
}
} else { // zero the unwanted directions for level == choicelevel
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir1][i] = WavCoeffs_L[dir2][i] = 0.f;
}
}
} else if(choiceClevel==1) { // Only below level
if(choiceDir==0) { // All directions
if(level >= choicelevel) {
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir][i] =0.f;
}
}
}
} else { // zero the unwanted directions for level >= choicelevel
if(level >= choicelevel) {
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir1][i] = WavCoeffs_L[dir2][i] = 0.f;
}
}
}
} else if(choiceClevel==2) { // Only above level
if(choiceDir==0) { // All directions
if(level <= choicelevel) {
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir][i] =0.f;
}
}
}
} else { // zero the unwanted directions for level >= choicelevel
if(level <= choicelevel) {
for (int i=0; i<W_L*H_L; i++) {
WavCoeffs_L[dir1][i] = WavCoeffs_L[dir2][i] = 0.f;
}
}
}
}
}
void ImProcFunctions::ContAllL (float *koeLi[9], float *maxkoeLi, bool lipschitz, int maxlvl, LabImage * labco, float ** varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params cp,
int W_L, int H_L, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili)
{
static const float scales[10] = {1.f,2.f,4.f,8.f,16.f,32.f,64.f,128.f,256.f,512.f};
float scaleskip[10];
for(int sc=0;sc<10;sc++)
scaleskip[sc]=scales[sc]/skip;
float atten01234 = 0.80f;
float t_r=settings->top_right;
float t_l=settings->top_left;
float b_r=settings->bot_right;
float b_l=settings->bot_left;
float edd=settings->ed_detec;
float eddlow=settings->ed_low;
float eddstrength=settings->ed_detecStr;
float aedstr=(eddstrength-1.f)/90.f;
float bedstr=1.f-10.f*aedstr;
bool refi=false;
// if(cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f) refi=true;
// if(cp.val > 0 || refi) {//edge
if(cp.val > 0) {//edge
float * koe;
float maxkoe=0.f;
if(lipschitz==false) {
koe = new float [H_L*W_L];
for (int i=0; i<W_L*H_L; i++) koe[i]=0.f;
maxkoe=0.f;
if(cp.detectedge) {//
float** tmC;
int borderL = 1;
tmC = new float*[H_L];
for (int i=0; i<H_L; i++){
tmC[i] = new float[W_L];
}
{
for (int i=1; i<H_L-1; i++) {
for (int j=1; j<W_L-1; j++) {
//edge detection wavelet TMC Canny
// also possible to detect noise with 5x5 instead of 3x3
tmC[i][j]=(4.f*WavCoeffs_L[dir][i*W_L + j] + 2.f*WavCoeffs_L[dir][(i-1)*W_L + j] + 2.f*WavCoeffs_L[dir][(i+1)*W_L + j]
+ 2.f*WavCoeffs_L[dir][i*W_L + j+1] + 2.f*WavCoeffs_L[dir][i*W_L + j-1] + WavCoeffs_L[dir][(i-1)*W_L + j-1]
+WavCoeffs_L[dir][(i-1)*W_L + j+1]+WavCoeffs_L[dir][(i+1)*W_L + j-1]+WavCoeffs_L[dir][(i+1)*W_L + j+1])/16.f;
// apply to each direction Wavelet level : horizontal / vertiacle / diagonal
}
}
}
for(int i = borderL; i < H_L-borderL; i++ ) {
for(int j = borderL; j < W_L-borderL; j++) {
// my own algo : probably a little false, but simpler as Lipschitz !
float thr=40.f;//avoid artifact eg. noise...to test
float thr2=edd;//edd can be modified in option ed_detect
thr2+=cp.eddet/30.f;//to test
float temp = WavCoeffs_L[dir][i*W_L + j];
if(temp>=0.f && temp < thr) temp= thr;
if(temp < 0.f && temp > -thr) temp= -thr;
koe[i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp));
if(koe[i*W_L + j] > maxkoe) maxkoe=koe[i*W_L + j];
float diff=maxkoe-koe[i*W_L + j];
diff *=(cp.eddet/100.f);
float interm=maxkoe-diff;
if(interm < cp.eddetthr/30.f) interm = 0.01f;
koe[i*W_L + j]=interm;
}
}
//printf("maxkoe=%f \n",maxkoe);
for (int i=0; i<H_L; i++){
delete [] tmC[i];
}
delete [] tmC;
}
}
//end detect edge
float rad = ((float)cp.rad)/60.f;//radius ==> not too high value to avoid artifacts
float value = ((float)cp.val)/8.f;//strength
if (scaleskip[1] < 1.f) value *= (atten01234*scaleskip[1]);//for zoom < 100% reduce strength...I choose level 1...but!!
float edge=1.f;
float lim0=20.f;//arbitrary limit for low radius and level between 2 or 3 to 30 maxi
float lev = float (level);
float repart=(float)cp.til;
float brepart;
if(cp.reinforce==1) brepart=3.f;
if(cp.reinforce==3) brepart=0.5f; //arbitrary value to increase / decrease repart, between 1 and 0
float arepart=-(brepart-1.f)/(lim0/60.f);
if (cp.reinforce !=2) {if(rad < lim0/60.f) repart *= (arepart*rad + brepart);}//linear repartition of repart
float al0 = 1.f + (repart)/50.f;
float al10 =1.0f;//arbitrary value ==> less = take into account high levels
// float ak =-(al0-al10)/10.f;//10 = maximum levels
float ak =-(al0-al10)/10.f;//10 = maximum levels
float bk =al0;
float koef = ak*level+bk;//modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels
float expkoef= -pow(fabs(rad - lev),koef);//reduce effect for high levels
if (cp.reinforce==3) {if(rad < lim0/60.f && level==0) expkoef *= repart;}//reduce effect for low values of rad and level=0==> quasi only level 1 is effective
if (cp.reinforce==1) {if(rad < lim0/60.f && level==1) expkoef /= repart;}//increase effect for low values of rad and level=1==> quasi only level 0 is effective
float coefsd=0.85f;//arbitray value to reduce effect after sigma in all case
float coefmean=0.85f;//arbitray value to reduce effect after sigma in all case
// edge = 1.f + value * exp (expkoef);//estimate edge "pseudo variance"
//take into account local contrast
float refin= value * exp (expkoef);
if(cp.link==true){//combi
{
if(level==0) refin *= (1.f + cp.lev0s/50.f);// we can change this sensibility!
if(level==1) refin *= (1.f + cp.lev1s/50.f);
if(level==2) refin *= (1.f + cp.lev2s/50.f);
}
}
float edgePrecalc = 1.f + refin; //estimate edge "pseudo variance"
//bool exa=false;
if(cp.EDmet==2) {//curve
// if(exa) {//curve
float insigma=0.666f;//SD
float logmax=log(MaxP[level]);//log Max
float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max
float inx=log(insigma);
float iny=log(rapX);
float rap=inx/iny;//koef
float asig=0.166f/sigma[level];
float bsig=0.5f-asig*mean[level];
float amean=0.5f/mean[level];
float absciss;
float kinterm;
float kmul;
for (int i=0; i<W_L*H_L; i++) {
if(cp.detectedge) {
if(lipschitz==false) {
if(cp.eddet > 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[i]))/(1.f+0.9f*maxkoe);
else edge=(edgePrecalc*(1.f+koe[i]))/(1.f+0.9f*maxkoe);
}
if(lipschitz==true) {
if(level < 3) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][i])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]);
else edge = edgePrecalc;
}
}
else edge = edgePrecalc;
if(cp.edgcurv) {
if(fabs(WavCoeffs_L[dir][i])>= (mean[level]+sigma[level])){//for max
float valcour=log(fabs(WavCoeffs_L[dir][i]));
float valc=valcour-logmax;
float vald=valc*rap;
absciss=exp(vald);
}
else if(fabs(WavCoeffs_L[dir][i])>=mean[level] && fabs(WavCoeffs_L[dir][i]) < (mean[level]+sigma[level])){
absciss=asig*fabs(WavCoeffs_L[dir][i])+bsig;
}
else if(fabs(WavCoeffs_L[dir][i]) < mean[level]){
absciss=amean*fabs(WavCoeffs_L[dir][i]);
}
// Threshold adjuster settings==> approximative for curve
//kmul about average cbrt(3--40 / 10)==>1.5 to 2.5
//kmul about SD 10--60 / 35 ==> 2
// kmul about low cbrt((5.f+cp.edg_low)/5.f);==> 1.5
// kmul about max ==> 9
// we can change these values
// result is different not best or bad than threshold slider...but similar
float abssd=4.f;//amplification reference
float bbssd=2.f;//mini ampli
float maxamp=2.5f;//maxi ampli at end
float maxampd=10.f;//maxi ampli at end
float a_abssd=(maxamp - abssd)/0.333f;
float b_abssd=maxamp-a_abssd;
float da_abssd=(maxampd - abssd)/0.333f;
float db_abssd=maxampd-da_abssd;
float am=(abssd-bbssd)/0.666f;
float kmuld=0.f;
if(absciss>0.666f && absciss < 1.f) {kmul=a_abssd*absciss + b_abssd;kmuld=da_abssd*absciss + db_abssd;}//about max ==> kinterm
else kmul = kmuld = absciss*am+bbssd;
kinterm=1.f;
float kc= kmul*(wavCLVCcurve[absciss*500.f]-0.5f);
float kcd= kmuld*(wavCLVCcurve[absciss*500.f]-0.5f);
float reduceeffect=0.6f;
if(kc >=0.f)
kinterm = 1.f + reduceeffect*kmul*(wavCLVCcurve[absciss*500.f]-0.5f);//about 1 to 3 general and big amplification for max (under 0)
else
kinterm = 1.f - (SQR(kcd))/10.f;
if(kinterm<0.f) kinterm=0.01f;
edge *= kinterm;
if(edge < 1.f)
edge=1.f;
}
WavCoeffs_L[dir][i] *= edge;
}
}
else if(cp.EDmet==1) {//threshold adjuster
float MaxPCompare = MaxP[level]*SQR(cp.edg_max/100.f);//100 instead of b_r...case if b_r < 100
float MaxNCompare = MaxN[level]*SQR(cp.edg_max/100.f);//always rduce a little edge for near max values
float edgeSdCompare = (mean[level]+1.5f*sigma[level])*SQR(cp.edg_sd/t_r);// 1.5 standard deviation #80% range between mean 50% and 80%
float edgeMeanCompare = mean[level]*SQR(cp.edg_mean/t_l);
float edgeLowCompare = (5.f+SQR(cp.edg_low));
float edgeMeanFactor = cbrt(cp.edg_mean/t_l);
float interm;
if(cp.edg_low < 10.f) interm= cbrt((5.f+cp.edg_low)/5.f);
else interm=1.437f;//cbrt(3);
float edgeLowFactor = interm;
float edgeSdFactor = cp.edg_sd/t_r;
float edgeMaxFactor = SQR(cp.edg_max/b_r);
float edgMaxFsup=(cp.edg_max/b_r);//reduce increase of effect for high values contrast..if slider > b_r
for (int i=0; i<W_L*H_L; i++) {
if(cp.detectedge) {
if(lipschitz==false) {
if(cp.eddet > 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[i]))/(1.f+0.9f*maxkoe);
else edge=(edgePrecalc*(1.f+koe[i]))/(1.f+0.9f*maxkoe);
}
if(lipschitz==true) {
if(level < 3) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][i])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]);
else edge = edgePrecalc;
}
}
else edge = edgePrecalc;
//algorithm that take into account local contrast
// I use a thresholdadjuster with
// Bottom left ==> minimal low value for local contrast (not 0, but 5...we can change)
// 0 10*10 35*35 100*100 substantially correspond to the true distribution of low value, mean, standard-deviation and max (ed 5, 50, 400, 4000
// Top left ==> mean reference value (for each level), we can change cbrt(cp.edg_mean/10.f)
// Top Right==> standard deviation (for each level) we can change (cp.edg_sd/35.f)
// bottom right ==> Max for positif and negatif contrast we can change cp.edg_max/100.f
// If we move sliders to the left, local contrast is reduced
// if we move sliders to the right local contrast is increased
// MaxP, MaxN, mean, sigma are calculated if necessary (val > 0) by evaluate2(), eval2(), aver() , sigma()
if(b_r < 100.f && cp.edg_max/b_r > 1.f) {//in case of b_r < 100 and slider move to right
if (WavCoeffs_L[dir][i] > MaxPCompare*cp.edg_max/b_r) {
edge *= edgMaxFsup;
if(edge < 1.f)
edge=1.f;
}
else if (WavCoeffs_L[dir][i] < MaxNCompare*cp.edg_max/b_r) {
edge *= edgMaxFsup;
if(edge < 1.f)
edge=1.f;
}
}
if (WavCoeffs_L[dir][i] > MaxPCompare) {
edge *= edgeMaxFactor;
if(edge < 1.f)
edge=1.f;
}//reduce edge if > new max
else if (WavCoeffs_L[dir][i] < MaxNCompare) {
edge *= edgeMaxFactor;
if(edge < 1.f)
edge=1.f;
}
if (fabs(WavCoeffs_L[dir][i]) >= edgeMeanCompare && fabs(WavCoeffs_L[dir][i]) < edgeSdCompare) {
//if (fabs(WavCoeffs_L[dir][i]) > edgeSdCompare) {
edge *= edgeSdFactor;
if(edge < 1.f)
edge=1.f;
}//mofify effect if sd change
if (fabs(WavCoeffs_L[dir][i]) < edgeMeanCompare) {
edge *= edgeMeanFactor;
if(edge < 1.f)
edge=1.f;
} // modify effect if mean change
if (fabs(WavCoeffs_L[dir][i]) < edgeLowCompare) {
edge *= edgeLowFactor;
if(edge < 1.f)
edge=1.f;
}
WavCoeffs_L[dir][i] *= edge;
}
}
if(lipschitz==false) {
delete [] koe;
}
}
if(cp.link==false) { //used both with denoise 1 2 3
float refine=0.f;
for (int i=0; i<W_L*H_L; i++) {
if(level==0) refine = cp.lev0s/40.f;
if(level==1) refine = cp.lev1s/40.f;
if(level==2) refine = cp.lev2s/40.f;
WavCoeffs_L[dir][i]*=(1.f + refine);
}
}
float cpMul = cp.mul[level];
if(cpMul != 0.f) { // cpMul == 0.f means all will be multiplied by 1.f, so we can skip this
const float skinprot = params->wavelet.skinprotect;
const float skinprotneg = -skinprot;
const float factorHard = (1.f - skinprotneg/100.f);
//to adjust increase contrast with local contrast
//for each pixel and each level
float beta;
float mea[9];
mea[0]=mean[level]/6.f;
mea[1]=mean[level]/2.f;
mea[2]=mean[level];// 50% data
mea[3]=mean[level] + sigma[level]/2.f;
mea[4]=mean[level] + sigma[level];//66%
mea[5]=mean[level] + 1.2f*sigma[level];
mea[6]=mean[level] + 1.5f*sigma[level];//
mea[7]=mean[level] + 2.f*sigma[level];//95%
mea[8]=mean[level] + 2.5f*sigma[level];//99%
bool skinControl = (skinprot != 0.f);
bool useChromAndHue = (skinprot != 0.f || cp.HSmet);
float modchro, kLlev;
for (int i=0; i<W_L*H_L; i++) {
kLlev=1.f;
if(cpMul<0.f) {
beta=1.f;// disabled for negatives values "less contrast"
} else {
float WavCL = fabsf(WavCoeffs_L[dir][i]);
//reduction amplification: max action between mean / 2 and mean + sigma
// arbitrary coefficient, we can add a slider !!
if(WavCL < mea[0]) beta=0.6f;//preserve very low contrast (sky...)
else if(WavCL < mea[1]) beta=0.8f;
else if(WavCL < mea[2]) beta=1.f;//standard
else if(WavCL < mea[3]) beta=1.f;
else if(WavCL < mea[4]) beta=0.8f;//+sigma
else if(WavCL < mea[5]) beta=0.6f;
else if(WavCL < mea[6]) beta=0.4f;
else if(WavCL < mea[7]) beta=0.2f;// + 2 sigma
else if(WavCL < mea[8]) beta=0.1f;
else beta =0.0f;
}
float scale = 1.f;
float scale2=1.f;
float LL100, LL100res, LL100init, kH[maxlvl];
if(useChromAndHue) {
int ii=i/W_L;
int jj=i-ii*W_L;
float LL = labco->L[ii*2][jj*2];
LL100=LL100init=LL/327.68f;
LL100res=WavCoeffs_L0[i]/327.68f;
float delta=fabs(LL100init-LL100res)/(maxlvl/2);
for(int ml=0;ml<maxlvl;ml++) {
if(ml < maxlvl/2) kH[ml]=(LL100res+ml*delta)/LL100res;// fixed a priori max to level middle
else kH[ml]=(LL100init-ml*delta)/LL100res;
}
float modhue = varhue[ii][jj];
modchro = varchrom[ii*2][jj*2];
// hue chroma skin with initial lab datas
scale=1.f;
if(skinprot > 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand
} else if(skinprot < 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0);
if (scale == 1.f)
scale=factorHard;
else
scale=1.f;
}
}
if(Chutili){
int i_i=i/W_L;
int j_j=i-i_i*W_L;
double lr;
float modhue2 = varhue[i_i][j_j];
float valparam = float((ChCurve->getVal(lr=Color::huelab_to_huehsv2(modhue2))-0.5f));//get valparam=f(H)
if(valparam > 0.f) scale2=1.f + 3.f* valparam;//arbitrary value
else scale2 = 1.f + 1.9f*valparam;//near 0 but not zero if curve # 0
//curve Contrast / hue
}
//
//linear transition HL
float diagacc=1.f;
/*
if(cp.diag) {
if(dir <=2) diagacc=0.75f;
if(dir ==3) diagacc=1.5f;
}
*/
float alpha = (1024.f + 15.f *(float) cpMul*scale*scale2*beta*diagacc)/1024.f ;
if(cp.HSmet){
float aaal=(1.f-alpha)/((cp.b_lhl-cp.t_lhl)*kH[level]);
float bbal=1.f-aaal*cp.b_lhl*kH[level];
float aaar=(alpha-1.f)/(cp.t_rhl-cp.b_rhl)*kH[level];
float bbbr=1.f-cp.b_rhl*aaar*kH[level];
//linear transition Shadows
float aaalS=(1.f-alpha)/(cp.b_lsl-cp.t_lsl);
float bbalS=1.f-aaalS*cp.b_lsl;
float aaarS=(alpha-1.f)/(cp.t_rsl-cp.b_rsl);
float bbbrS=1.f-cp.b_rsl*aaarS;
if(level <=cp.numlevH) {//in function of levels
if((LL100 > cp.t_lhl*kH[level] && LL100 < cp.t_rhl*kH[level])) {kLlev=alpha;}
else if((LL100 > cp.b_lhl*kH[level] && LL100 <= cp.t_lhl*kH[level])) kLlev=aaal*LL100+bbal;
else if((LL100 > cp.t_rhl*kH[level] && LL100 <= cp.b_rhl*kH[level])) kLlev=aaar*LL100+bbbr;
else kLlev=1.f;
}
if(level >=(9-cp.numlevS)) {
if((LL100 > cp.t_lsl && LL100 < cp.t_rsl)) kLlev=alpha;
else if((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) kLlev=aaalS*LL100+bbalS;
else if((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) kLlev=aaarS*LL100+bbbrS;
else kLlev=1.f;
}
}
else kLlev=alpha;
WavCoeffs_L[dir][i]*=(kLlev);
}
}
if(waOpacityCurveW) cp.opaW=true;
if(cp.bam) {
if(cp.opaW && cp.BAmet==2){
int iteration = cp.ite;
int itplus=7+iteration;
int itmoins= 7-iteration;
int med = maxlvl/2;
int it;
if(level < med) {it=itmoins; }
else if(level == med) it=7;
else if(level > med) it=itplus;
for(int j=0; j < it; j++) {
//float bal = cp.balan;//-100 +100
float kba=1.f;
float k1;
float k2;
// if(dir <3) kba= 1.f + bal/600.f;
// if(dir==3) kba = 1.f - bal/300.f;
for (int i=0; i<W_L*H_L; i++) {
int ii=i/W_L;
int jj=i-ii*W_L;
float LL100 = labco->L[ii*2][jj*2]/327.68f;
k1=600.f;
k2=300.f;
k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16
k2=k1*2.f;
if(dir <3) kba= 1.f + k1;
if(dir==3) kba = 1.f - k2;
WavCoeffs_L[dir][i] *=(kba);
}
}
}
if(cp.BAmet==1){
int iteration = cp.ite;
int itplus=7+iteration;
int itmoins= 7-iteration;
int med = maxlvl/2;
int it;
if(level < med) {it=itmoins; }
else if(level == med) it=7;
else if(level > med) it=itplus;
for(int j=0; j < it; j++) {
float bal = cp.balan;//-100 +100
float kba=1.f;
float k1;
float k2;
// if(dir <3) kba= 1.f + bal/600.f;
// if(dir==3) kba = 1.f - bal/300.f;
for (int i=0; i<W_L*H_L; i++) {
int ii=i/W_L;
int jj=i-ii*W_L;
k1=600.f;
k2=300.f;
float LL100 = labco->L[ii*2][jj*2]/327.68f;
float aa=4970.f;
float bb=-397000.f;
float b0=100000.f;
float a0=-4970.f;
if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;}
if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;}
//k1=600.f;
//k2=300.f;
//k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16
//k2=k1*2.f;
if(dir <3) kba= 1.f + bal/k1;
if(dir==3) kba = 1.f - bal/k2;
WavCoeffs_L[dir][i] *=(kba);
}
}
}
}
// to see each level of wavelet ...level from 0 to 8
int choicelevel = atoi(params->wavelet.Lmethod.data())-1;
choicelevel = choicelevel == -1 ? 4 : choicelevel;
}
void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue, float **varchrom, float ** WavCoeffs_ab, float * WavCoeffs_ab0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params cp,
int W_ab, int H_ab, const bool useChannelA)
{
float cpMul = cp.mul[level];
if(cpMul != 0.f && cp.CHmet==2 && cp.chro != 0.f) { // cpMul == 0.f or cp.chro = 0.f means all will be multiplied by 1.f, so we can skip this
const float skinprot = params->wavelet.skinprotect;
const float skinprotneg = -skinprot;
const float factorHard = (1.f - skinprotneg/100.f);
const float cpChrom = cp.chro;
//to adjust increase contrast with local contrast
bool useSkinControl = (skinprot != 0.f);
float alphaC =(1024.f + 15.f *cpMul*cpChrom/50.f)/1024.f ;
for (int i=0; i<W_ab*H_ab; i++) {
if(useSkinControl) {
int ii=i/W_ab;
int jj=i-ii*W_ab;
float LL100 = labco->L[ii*2][jj*2]/327.68f;
float modhue = varhue[ii][jj];
float modchro = varchrom[ii*2][jj*2];
// hue chroma skin with initial lab datas
float scale=1.f;
if(skinprot > 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand
} else if(skinprot < 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0);
scale = (scale == 1.f) ? factorHard : 1.f;
}
alphaC =(1024.f + 15.f *cpMul*cpChrom*scale/50.f)/1024.f ;
}
WavCoeffs_ab[dir][i] *= alphaC;
}
}
//Curve chro
float cpMulC = cp.mulC[level];
// if( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip
if( cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip
float modchro, modhue, kClev;
const float skinprot = params->wavelet.skinprotect;
const float skinprotneg = -skinprot;
const float factorHard = (1.f - skinprotneg/100.f);
bool useSkinControl = (skinprot != 0.f);
for (int i=0; i<W_ab*H_ab; i++) {
int ii=i/W_ab;
int jj=i-ii*W_ab;
//WL and W_ab are identical
float LL = labco->L[ii*2][jj*2];
float LL100=LL/327.68f;
float scale=1.f;
modchro = varchrom[ii*2][jj*2];
if(useSkinControl) {
// hue chroma skin with initial lab datas
modhue = varhue[ii][jj];
scale=1.f;
if(skinprot > 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); //1 for curve
}
else if(skinprot < 0.f){
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1);
scale = (scale == 1.f) ? factorHard : 1.f;
}
}
float beta = (1024.f + 20.f * cpMulC * scale)/1024.f ;
if(beta < 0.02f)
beta=0.02f;
kClev = beta;
if(cp.CHmet==1){
if(level < cp.chrom) {
//linear for saturated
if((modchro > cp.t_lsat && modchro < cp.t_rsat))
kClev=beta;
else if((modchro > cp.b_lsat && modchro <= cp.t_lsat)) {
float aaal=(1.f-beta)/(cp.b_lsat-cp.t_lsat);
float bbal=1.f-aaal*cp.b_lsat;
kClev=aaal*modchro+bbal;
} else if((modchro > cp.t_rsat && modchro <= cp.b_rsat)) {
float aaar=(beta-1.f)/(cp.t_rsat-cp.b_rsat);
float bbbr=1.f-cp.b_rsat*aaar;
kClev=aaar*modchro+bbbr;
} else
kClev=1.f;
} else {
//linear for pastel
if((modchro > cp.t_lpast && modchro < cp.t_rpast))
kClev=beta;
else if((modchro > cp.b_lpast && modchro <= cp.t_lpast)) {
float aaalS=(1.f-beta)/(cp.b_lpast-cp.t_lpast);
float bbalS=1.f-aaalS*cp.b_lpast;
kClev=aaalS*modchro+bbalS;
} else if((modchro > cp.t_rpast && modchro <= cp.b_rpast)) {
float aaarS=(beta-1.f)/(cp.t_rpast-cp.b_rpast);
float bbbrS=1.f-cp.b_rpast*aaarS;
kClev=aaarS*modchro+bbbrS;
} else
kClev=1.f;
}
}
else if(cp.CHmet==0)
kClev=beta;
WavCoeffs_ab[dir][i] *= kClev;
}
}
bool useOpacity;
float mulOpacity;
if(useChannelA) {
useOpacity = cp.opaRG;
mulOpacity = cp.mulopaRG[level];
}
else {
useOpacity = cp.opaBY;
mulOpacity = cp.mulopaBY[level];
}
if(useOpacity && level < 9 && mulOpacity != 0.f) { //toning
float beta = (1024.f + 20.f * mulOpacity)/1024.f ;
//float beta = (1000.f * mulOpacity);
for (int i=0; i<W_ab*H_ab; i++)
WavCoeffs_ab[dir][i] *= beta;
// WavCoeffs_ab[dir][i] += beta;
}
if(waOpacityCurveW) cp.opaW=true;
if(cp.bam && cp.diag) {
//printf("OK Chroma\n");
if(cp.opaW && cp.BAmet==2){
int iteration = cp.ite;
int itplus=7+iteration;
int itmoins= 7-iteration;
int med = maxlvl/2;
int it;
if(level < med) {it=itmoins; }
else if(level == med) it=7;
else if(level > med) it=itplus;
for(int j=0; j < it; j++) {
//float bal = cp.balan;//-100 +100
float kba=1.f;
float k1;
float k2;
// if(dir <3) kba= 1.f + bal/600.f;
// if(dir==3) kba = 1.f - bal/300.f;
for (int i=0; i<W_ab*H_ab; i++) {
int ii=i/W_ab;
int jj=i-ii*W_ab;
float LL100 = labco->L[ii*2][jj*2]/327.68f;
k1=600.f;
k2=300.f;
k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16
k2=k1*2.f;
if(dir <3) kba= 1.f + k1;
if(dir==3) kba = 1.f - k2;
WavCoeffs_ab[dir][i] *=(kba);
}
}
}
if(cp.BAmet==1){
int iteration = cp.ite;
int itplus=7+iteration;
int itmoins= 7-iteration;
int med = maxlvl/2;
int it;
if(level < med) {it=itmoins; }
else if(level == med) it=7;
else if(level > med) it=itplus;
for(int j=0; j < it; j++) {
float bal = cp.balan;//-100 +100
float kba=1.f;
float k1;
float k2;
// if(dir <3) kba= 1.f + bal/600.f;
// if(dir==3) kba = 1.f - bal/300.f;
for (int i=0; i<W_ab*H_ab; i++) {
int ii=i/W_ab;
int jj=i-ii*W_ab;
k1=600.f;
k2=300.f;
float LL100 = labco->L[ii*2][jj*2]/327.68f;
float aa=4970.f;
float bb=-397000.f;
float b0=100000.f;
float a0=-4970.f;
if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;}
if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;}
//k1=600.f;
//k2=300.f;
//k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16
//k2=k1*2.f;
if(dir <3) kba= 1.f + bal/k1;
if(dir==3) kba = 1.f - bal/k2;
WavCoeffs_ab[dir][i] *=(kba);
}
}
}
}
// to see each level of wavelet ...level from 0 to 8
int choicelevel = atoi(params->wavelet.Lmethod.data())-1;
choicelevel = choicelevel == -1 ? 4 : choicelevel;
int choiceClevel=0;
if(params->wavelet.CLmethod=="one") choiceClevel=0;
else if(params->wavelet.CLmethod=="inf") choiceClevel=1;
else if(params->wavelet.CLmethod=="sup") choiceClevel=2;
else if(params->wavelet.CLmethod=="all") choiceClevel=3;
int choiceDir=0;
if(params->wavelet.Dirmethod=="one") choiceDir=1;
else if(params->wavelet.Dirmethod=="two") choiceDir=2;
else if(params->wavelet.Dirmethod=="thr") choiceDir=3;
else if(params->wavelet.Dirmethod=="all") choiceDir=0;
int dir1 = (choiceDir == 2) ? 1 : 2;
int dir2 = (choiceDir == 3) ? 1 : 3;
if(choiceClevel<3) { // not all levels visible, paint residual
if(level == 0) {
if(cp.backm!=2) { // nothing to change when residual is used as background
float backGroundChroma = (cp.backm==1) ? 0.f : 0.f;//we can change first to colorized...
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab0[i] = backGroundChroma;
}
}
}
}
if(choiceClevel==0) { // Only one level
if(level != choicelevel){ // zero all for the levels != choicelevel
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir][i] = 0.f;
}
}
} else { // zero the unwanted directions for level == choicelevel
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir1][i] = WavCoeffs_ab[dir2][i] = 0.f;
}
}
} else if(choiceClevel==1) { // Only below level
if(choiceDir==0) { // All directions
if(level >= choicelevel) {
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir][i] =0.f;
}
}
}
} else { // zero the unwanted directions for level >= choicelevel
if(level >= choicelevel) {
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir1][i] = WavCoeffs_ab[dir2][i] = 0.f;
}
}
}
} else if(choiceClevel==2) { // Only above level
if(choiceDir==0) { // All directions
if(level <= choicelevel) {
for (int dir=1; dir<4; dir++) {
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir][i] =0.f;
}
}
}
} else { // zero the unwanted directions for level >= choicelevel
if(level <= choicelevel) {
for (int i=0; i<W_ab*H_ab; i++) {
WavCoeffs_ab[dir1][i] = WavCoeffs_ab[dir2][i] = 0.f;
}
}
}
}
}
}