Solving issue 2023: "Pseudo memory leak with Detail window + memory handling optimization"

The Detail window buffers are now freed up when the it is closed. The CIECAM buffers are allocated only if necessary now, and if the single block allocation fails, it will try to allocate it in several blocks.
This commit is contained in:
Hombre
2013-11-06 00:19:06 +01:00
parent 91c45758c4
commit b7e0b0ebab
10 changed files with 599 additions and 504 deletions

View File

@@ -155,7 +155,7 @@ namespace rtengine {
//srand((unsigned)time(0));//test with random data
const float gain = pow (2.0f, expcomp);
const float gain = pow (2.0f, float(expcomp));
float incr=1.f;
float noisevar_Ldetail = SQR((SQR(100.f-dnparams.Ldetail) + 50.f*(100.f-dnparams.Ldetail)) * TS * 0.5f * incr);

View File

@@ -10,49 +10,90 @@ CieImage::CieImage (int w, int h) : fromImage(false), W(w), H(h) {
sh_p = new float*[H];
// ch_p = new float*[H];
h_p = new float*[H];
data = new float [W*H*6];
float * index = data;
for (int i=0; i<H; i++)
J_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
Q_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
M_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
C_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
sh_p[i] = index + i*W;
index+=W*H;
// for (int i=0; i<H; i++)
// ch_p[i] = index + i*W;
// index+=W*H;
for (int i=0; i<H; i++)
h_p[i] = index + i*W;
// Initialize the pointers to zero
for (unsigned int c=0; c<6; ++c)
data[c] = NULL;
// Trying to allocate all in one block
data[0] = new (std::nothrow) float [W*H*6];
if (data[0]) {
float * index = data[0];
for (int i=0; i<H; i++)
J_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
Q_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
M_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
C_p[i] = index + i*W;
index+=W*H;
for (int i=0; i<H; i++)
sh_p[i] = index + i*W;
index+=W*H;
// for (int i=0; i<H; i++)
// ch_p[i] = index + i*W;
// index+=W*H;
for (int i=0; i<H; i++)
h_p[i] = index + i*W;
}
else {
// Allocating each plane separately
for (unsigned int c=0; c<6; ++c)
data[c] = new float [W*H];
unsigned int c = 0;
for (int i=0; i<H; i++)
J_p[i] = data[c] + i*W;
++c;
for (int i=0; i<H; i++)
Q_p[i] = data[c] + i*W;
++c;
for (int i=0; i<H; i++)
M_p[i] = data[c] + i*W;
++c;
for (int i=0; i<H; i++)
C_p[i] = data[c] + i*W;
++c;
for (int i=0; i<H; i++)
sh_p[i] = data[c] + i*W;
++c;
// for (int i=0; i<H; i++)
// ch_p[i] = data[c] + i*W;
// ++c;
for (int i=0; i<H; i++)
h_p[i] = data[c] + i*W;
}
}
CieImage::~CieImage () {
if (!fromImage) {
delete [] J_p;
delete [] Q_p;
delete [] J_p;
delete [] Q_p;
delete [] M_p;
delete [] C_p;
delete [] sh_p;
// delete [] ch_p;
// delete [] ch_p;
delete [] h_p;
delete [] data;
for (unsigned int c=0; c<6; ++c)
if (data[c]) delete [] data[c];
}
}
void CieImage::CopyFrom(CieImage *Img){
memcpy(data, Img->data, W*H*6*sizeof(float));
if (!data [1])
// Only one allocated block
memcpy(data, Img->data, W*H*6*sizeof(float));
else
// Separate allocation
for (unsigned int c=0; c<6; ++c)
memcpy(data[c], Img->data[c], W*H*sizeof(float));
}
}

View File

@@ -29,7 +29,7 @@ private:
public:
int W, H;
float * data;
float * data[6];
float** J_p;
float** Q_p;
float** M_p;

View File

@@ -30,25 +30,35 @@ namespace rtengine {
extern const Settings* settings;
Crop::Crop (ImProcCoordinator* parent)
: resizeCrop(NULL), transCrop(NULL), updating(false),
skip(10),cropw(-1), croph(-1), trafw(-1), trafh(-1),
borderRequested(32), cropAllocated(false),
cropImageListener(NULL), parent(parent)
: origCrop(NULL), transCrop(NULL), laboCrop(NULL), labnCrop(NULL),
cropImg(NULL), cieCrop(NULL), cbuf_real(NULL), cshmap(NULL),
cbuffer(NULL), updating(false), newUpdatePending(false),
skip(10),
cropx(0), cropy(0), cropw(-1), croph(-1),
trafx(0), trafy(0), trafw(-1), trafh(-1),
rqcropx(0), rqcropy(0), rqcropw(-1), rqcroph(-1),
borderRequested(32), upperBorder(0), leftBorder(0),
cropAllocated(false),
cropImageListener(NULL), parent(parent)
{
parent->crops.push_back (this);
}
Crop::~Crop () {
cropMutex.lock ();
parent->mProcessing.lock ();
MyMutex::MyLock cropLock(cropMutex);
MyMutex::MyLock processingLock(parent->mProcessing);
std::vector<Crop*>::iterator i = std::find (parent->crops.begin(), parent->crops.end(), this);
if (i!=parent->crops.end ())
parent->crops.erase (i);
freeAll ();
parent->mProcessing.unlock ();
cropMutex.unlock ();
}
void Crop::destroy () {
MyMutex::MyLock lock(cropMutex);
MyMutex::MyLock processingLock(parent->mProcessing); ///////// RETESTER MAINTENANT QUE CE VERROU EST AJOUTE!!!
freeAll();
}
void Crop::setListener (DetailedCropListener* il) {
@@ -80,10 +90,10 @@ void Crop::update (int todo) {
if (needsinitupdate || (todo & M_HIGHQUAL))
todo = ALL;
// set improcfuncions' scale now that skip has been updated
// Tells to the ImProcFunctions' tool what is the preview scale, which may lead to some simplifications
parent->ipf.setScale (skip);
baseCrop = origCrop;
Imagefloat* baseCrop = origCrop;
bool needstransform = parent->ipf.needsTransform();
@@ -104,171 +114,181 @@ void Crop::update (int todo) {
parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.hlrecovery, params.icm, params.raw );
//ColorTemp::CAT02 (origCrop, &params) ;
//parent->imgsrc->convertColorSpace(origCrop, params.icm);
//parent->imgsrc->convertColorSpace(origCrop, params.icm);
if (todo & M_LINDENOISE) {
if (skip==1 && params.dirpyrDenoise.enabled) {
parent->ipf.RGB_denoise(origCrop, origCrop, parent->imgsrc->isRAW(), /*Roffset,*/ params.dirpyrDenoise, params.defringe, parent->imgsrc->getDirPyrDenoiseExpComp());
}
if (skip==1 && params.dirpyrDenoise.enabled)
parent->ipf.RGB_denoise(origCrop, origCrop, parent->imgsrc->isRAW(), /*Roffset,*/ params.dirpyrDenoise, params.defringe, parent->imgsrc->getDirPyrDenoiseExpComp());
}
parent->imgsrc->convertColorSpace(origCrop, params.icm, params.raw);
}
}
// transform
if ((!needstransform && transCrop) || (transCrop && (transCrop->width!=cropw || transCrop->height!=croph))) {
delete transCrop;
if (needstransform) {
if (!transCrop)
transCrop = new Imagefloat (cropw, croph);
if ((todo & M_TRANSFORM) && needstransform)
parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip),
parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getMetaData()->getFocalLen35mm(),
parent->imgsrc->getMetaData()->getFocusDist(), parent->imgsrc->getRotateDegree(), false);
if (transCrop)
baseCrop = transCrop;
}
else {
if (transCrop) delete transCrop;
transCrop = NULL;
}
if (needstransform && !transCrop)
transCrop = new Imagefloat (cropw, croph);
if ((todo & M_TRANSFORM) && needstransform)
parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip),
parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getMetaData()->getFocalLen35mm(),
parent->imgsrc->getMetaData()->getFocusDist(), parent->imgsrc->getRotateDegree(), false);
if (transCrop)
baseCrop = transCrop;
// blurmap for shadow & highlights
if ((todo & M_BLURMAP) && params.sh.enabled) {
double radius = sqrt (double(SKIPS(parent->fw,skip)*SKIPS(parent->fw,skip)+SKIPS(parent->fh,skip)*SKIPS(parent->fh,skip))) / 2.0;
double shradius = params.sh.radius;
if (!params.sh.hq) shradius *= radius / 1800.0;
cshmap->update (baseCrop, shradius, parent->ipf.lumimul, params.sh.hq, skip);
double shradius = params.sh.radius;
if (!params.sh.hq) shradius *= radius / 1800.0;
cshmap->update (baseCrop, shradius, parent->ipf.lumimul, params.sh.hq, skip);
cshmap->forceStat (parent->shmap->max_f, parent->shmap->min_f, parent->shmap->avg);
}
// shadows & highlights & tone curve & convert to cielab
/*int xref,yref;
xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
if (settings->verbose) printf("before rgbProc RGB Xr%i Yr%i Skip=%d R=%f G=%f B=%f gamma=%f \n",xref,yref,skip,
baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256,
parent->imgsrc->getGamma());
}*/
/*int xref,yref;
xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
if (settings->verbose) printf("before rgbProc RGB Xr%i Yr%i Skip=%d R=%f G=%f B=%f gamma=%f \n",xref,yref,skip,
baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256,
parent->imgsrc->getGamma());
}*/
if (todo & M_RGBCURVE)
parent->ipf.rgbProc (baseCrop, laboCrop, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap,
params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->customToneCurve1, parent->customToneCurve2 );
params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->customToneCurve1, parent->customToneCurve2 );
/*xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
if (settings->verbose) {
/*xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
if (settings->verbose) {
printf("after rgbProc RGB Xr%i Yr%i Skip=%d R=%f G=%f B=%f \n",xref,yref,skip,
baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256);
printf("after rgbProc Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip,
laboCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,
laboCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,
laboCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327);
baseCrop->r[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->g[(int)(xref/skip)][(int)(yref/skip)]/256,
baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256);
printf("after rgbProc Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip,
laboCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,
laboCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,
laboCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327);
}
}*/
// apply luminance operations
if (todo & (M_LUMINANCE+M_COLOR)) {
//I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here.
labnCrop->CopyFrom(laboCrop);
}*/
// apply luminance operations
if (todo & (M_LUMINANCE+M_COLOR)) {
//I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here.
labnCrop->CopyFrom(laboCrop);
// parent->ipf.luminanceCurve (labnCrop, labnCrop, parent->lumacurve);
bool utili=true;
bool autili=true;
bool butili=true;
bool ccutili=true;
bool cclutili=true;
//parent->ipf.luminanceCurve (labnCrop, labnCrop, parent->lumacurve);
bool utili=true;
bool autili=true;
bool butili=true;
bool ccutili=true;
bool cclutili=true;
LUTu dummy;
parent->ipf.chromiLuminanceCurve (1,labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->lumacurve, utili, autili, butili, ccutili,cclutili, dummy);
parent->ipf.vibrance (labnCrop);
if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) parent->ipf.EPDToneMap(labnCrop,5,1);
// parent->ipf.EPDToneMap(labnCrop, 5, 1); //Go with much fewer than normal iterates for fast redisplay.
// for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled
if (skip==1) {
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
parent->ipf.impulsedenoise (labnCrop);}
if((params.colorappearance.enabled && !settings->autocielab) ||(!params.colorappearance.enabled) ) {parent->ipf.defringe (labnCrop);}
parent->ipf.MLsharpen (labnCrop);
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
parent->ipf.MLmicrocontrast (labnCrop);
parent->ipf.sharpening (labnCrop, (float**)cbuffer);
parent->ipf.dirpyrequalizer (labnCrop);
}
}
if(params.colorappearance.enabled){
float fnum = parent->imgsrc->getMetaData()->getFNumber ();// F number
float fiso = parent->imgsrc->getMetaData()->getISOSpeed () ;// ISO
float fspeed = parent->imgsrc->getMetaData()->getShutterSpeed () ;//speed
float fcomp = parent->imgsrc->getMetaData()->getExpComp ();//compensation + -
float adap2,adap;
double ada, ada2;
if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {adap=adap=2000.f;ada=ada2=2000.;}//if no exif data or wrong
else {
float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f));
float expo2= params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
E_V += expo2;
float expo1;//exposure raw white point
expo1=log2(params.raw.expos);//log2 ==>linear to EV
E_V += expo1;
adap2 = adap= powf(2.f, E_V-3.f);//cd / m2
ada=ada2=(double) adap;
//end calculation adaptation scene luminosity
}
int begh = 0, endh = labnCrop->H;
bool execsharp=false;
float d;
double dd;
if(skip==1) execsharp=true;
if(settings->ciecamfloat) {parent->ipf.ciecam_02float (cieCrop, adap, begh, endh, 1, 2,labnCrop, &params,parent->customColCurve1,parent->customColCurve2,parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, d);
}
else {parent->ipf.ciecam_02 (cieCrop,ada, begh, endh, 1, 2, labnCrop, &params,parent->customColCurve1,parent->customColCurve2,parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, dd);}
}
}
LUTu dummy;
parent->ipf.chromiLuminanceCurve (1,labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->lumacurve, utili, autili, butili, ccutili,cclutili, dummy);
parent->ipf.vibrance (labnCrop);
if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) parent->ipf.EPDToneMap(labnCrop,5,1);
//parent->ipf.EPDToneMap(labnCrop, 5, 1); //Go with much fewer than normal iterates for fast redisplay.
// for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled
if (skip==1) {
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
parent->ipf.impulsedenoise (labnCrop);}
if((params.colorappearance.enabled && !settings->autocielab) ||(!params.colorappearance.enabled) ) {parent->ipf.defringe (labnCrop);}
parent->ipf.MLsharpen (labnCrop);
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) {
parent->ipf.MLmicrocontrast (labnCrop);
parent->ipf.sharpening (labnCrop, (float**)cbuffer);
parent->ipf.dirpyrequalizer (labnCrop);
}
}
if(params.colorappearance.enabled){
float fnum = parent->imgsrc->getMetaData()->getFNumber (); // F number
float fiso = parent->imgsrc->getMetaData()->getISOSpeed () ; // ISO
float fspeed = parent->imgsrc->getMetaData()->getShutterSpeed () ; // Speed
double fcomp = parent->imgsrc->getMetaData()->getExpComp (); // Compensation +/-
double adap; // Scene's luminosity adaptation factor
if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong
adap=2000.;
}
else {
double E_V = fcomp + log2 (double((fnum*fnum) / fspeed / (fiso/100.f)));
E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
E_V += log2(params.raw.expos);// exposure raw white point ; log2 ==> linear to EV
adap= pow(2., E_V-3.);// cd / m2
// end calculation adaptation scene luminosity
}
int begh = 0, endh = labnCrop->H;
bool execsharp=false;
if(skip==1) execsharp=true;
if (!cieCrop)
cieCrop = new CieImage (cropw, croph);
if(settings->ciecamfloat) {
float d; // not used after this block
parent->ipf.ciecam_02float (cieCrop, float(adap), begh, endh, 1, 2, labnCrop, &params, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, d);
}
else {
double dd; // not used after this block
parent->ipf.ciecam_02 (cieCrop,adap, begh, endh, 1, 2, labnCrop, &params, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, dd);
}
}
else {
// CIECAM is disbaled, we free up its image buffer to save some space
if (cieCrop) delete cieCrop; cieCrop=NULL;
}
}
// switch back to rgb
parent->ipf.lab2monitorRgb (labnCrop, cropImg);
//parent->ipf.lab2monitorRgb (laboCrop, cropImg);
//cropImg = baseCrop->to8();
/*
// int xref,yref;
xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
int rlin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))]/255.0) * 255.0);
int glin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1]/255.0) * 255.0);
int blin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2]/255.0) * 255.0);
printf("after lab2rgb RGB lab2 Xr%i Yr%i Skip=%d R=%d G=%d B=%d \n",xref,yref,skip,
rlin,glin,blin);
//cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))],
//cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1)],
//cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2)]);
//printf("after lab2rgb Lab lab2 Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327);
printf("after lab2rgb Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip,
labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,
labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,
labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327)q;
}
*/
/*
if (colortest && cropImg->height>115 && cropImg->width>115) {//for testing
xref=000;yref=000;
printf("dcrop final R= %d G= %d B= %d \n",
cropImg->data[3*xref/(skip)*(cropImg->width+1)],
cropImg->data[3*xref/(skip)*(cropImg->width+1)+1],
cropImg->data[3*xref/(skip)*(cropImg->width+1)+2]);
}
*/
//parent->ipf.lab2monitorRgb (laboCrop, cropImg);
//cropImg = baseCrop->to8();
/*
// int xref,yref;
xref=000;yref=000;
if (colortest && cropw>115 && croph>115)
for(int j=1;j<5;j++){
xref+=j*30;yref+=j*30;
int rlin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))]/255.0) * 255.0);
int glin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1]/255.0) * 255.0);
int blin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2]/255.0) * 255.0);
printf("after lab2rgb RGB lab2 Xr%i Yr%i Skip=%d R=%d G=%d B=%d \n",xref,yref,skip,
rlin,glin,blin);
//cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))],
//cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1)],
//cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2)]);
//printf("after lab2rgb Lab lab2 Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327);
printf("after lab2rgb Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip,
labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,
labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,
labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327)q;
}
*/
/*
if (colortest && cropImg->height>115 && cropImg->width>115) {//for testing
xref=000;yref=000;
printf("dcrop final R= %d G= %d B= %d \n",
cropImg->data[3*xref/(skip)*(cropImg->width+1)],
cropImg->data[3*xref/(skip)*(cropImg->width+1)+1],
cropImg->data[3*xref/(skip)*(cropImg->width+1)+2]);
}
*/
if (cropImageListener) {
// this in output space held in parallel to allow analysis like shadow/highlight
Glib::ustring outProfile=params.icm.output;
@@ -281,16 +301,16 @@ void Crop::update (int todo) {
int finalH = rqcroph;
if (cropImg->getHeight()-upperBorder < finalH)
finalH = cropImg->getHeight()-upperBorder;
Image8* final = new Image8 (finalW, finalH);
Image8* finaltrue = new Image8 (finalW, finalH);
Image8* finaltrue = new Image8 (finalW, finalH);
for (int i=0; i<finalH; i++) {
memcpy (final->data + 3*i*finalW, cropImg->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW);
memcpy (finaltrue->data + 3*i*finalW, cropImgtrue->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW);
}
memcpy (finaltrue->data + 3*i*finalW, cropImgtrue->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW);
}
cropImageListener->setDetailedCrop (final, finaltrue, params.icm, params.crop, rqcropx, rqcropy, rqcropw, rqcroph, skip);
delete final;
delete finaltrue;
delete finaltrue;
delete cropImgtrue;
}
}
@@ -300,26 +320,23 @@ void Crop::freeAll () {
if (settings->verbose) printf ("freeallcrop starts %d\n", (int)cropAllocated);
if (cropAllocated) {
delete origCrop;
if (transCrop)
delete transCrop;
transCrop = NULL;
if (resizeCrop)
delete resizeCrop;
resizeCrop = NULL;
delete laboCrop;
delete cieCrop;
delete labnCrop;
delete cropImg;
delete cshmap;
// for (int i=0; i<croph; i++)
// delete [] cbuffer[i];
delete [] cbuf_real;
delete [] cbuffer;
if (origCrop ) { delete origCrop; origCrop=NULL; }
if (transCrop) { delete transCrop; transCrop=NULL; }
if (laboCrop ) { delete laboCrop; laboCrop=NULL; }
if (labnCrop ) { delete labnCrop; labnCrop=NULL; }
if (cropImg ) { delete cropImg; cropImg=NULL; }
if (cieCrop ) { delete cieCrop; cieCrop=NULL; }
if (cbuf_real) { delete [] cbuf_real; cbuf_real=NULL; }
if (cbuffer ) { delete [] cbuffer; cbuffer=NULL; }
if (cshmap ) { delete cshmap; cshmap=NULL; }
}
cropAllocated = false;
}
/** @brief Handles crop's image buffer reallocation and trigger sizeChanged of SizeListener[s]
* If the scale changes, this method will free all buffers and reallocate ones of the new size.
* It will then tell to the SizeListener that size has changed (sizeChanged)
*/
bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool internal) {
if (settings->verbose) printf ("setcropsizes before lock\n");
@@ -379,8 +396,8 @@ if (settings->verbose) printf ("setcropsizes before lock\n");
leftBorder = SKIPS(rqx1-bx1,skip);
upperBorder = SKIPS(rqy1-by1,skip);
if (settings->verbose)
printf ("setsizes starts (%d, %d, %d, %d, %d, %d)\n", orW, orH, trafw, trafh,cw,ch);
if (settings->verbose)
printf ("setsizes starts (%d, %d, %d, %d, %d, %d)\n", orW, orH, trafw, trafh,cw,ch);
if (cw!=cropw || ch!=croph || orW!=trafw || orH!=trafh) {
@@ -392,26 +409,22 @@ if (settings->verbose) printf ("setcropsizes before lock\n");
trafh = orH;
origCrop = new Imagefloat (trafw, trafh);
laboCrop = new LabImage (cropw, croph);
labnCrop = new LabImage (cropw, croph);
//transCrop will be allocated later, if necessary
laboCrop = new LabImage (cropw, croph);
labnCrop = new LabImage (cropw, croph);
cropImg = new Image8 (cropw, croph);
cieCrop = new CieImage (cropw, croph);
cshmap = new SHMap (cropw, croph, true);
//cieCrop is only used in Crop::update, it will be allocated on first use and deleted if not used anymore
cbuffer = new float*[croph];
cbuf_real= new float[(croph+2)*cropw];
for (int i=0; i<croph; i++)
cbuffer[i] = cbuf_real+cropw*i+cropw;
cshmap = new SHMap (cropw, croph, true);
resizeCrop = NULL;
transCrop = NULL;
cropAllocated = true;
changed = true;
}
cropx = bx1;
cropy = by1;
trafx = orx;
@@ -424,27 +437,38 @@ if (settings->verbose) printf ("setcropsizes before lock\n");
return changed;
}
// Try a simple, threadless update flag first
/** @brief Look out if a new thread has to be started to process the update
*
* @return If true, a new updating thread has to be created. If false, the current updating thread will be used
*/
bool Crop::tryUpdate() {
bool needsFullUpdate = true;
// If there are more update request, the following WHILE will collect it
if (updating) {
needsNext = true;
needsFullUpdate = false;
} else updating = true;
return needsFullUpdate;
bool needsNewThread = true;
if (updating) {
// tells to the updater thread that a new update is pending
newUpdatePending = true;
// no need for a new thread, the current one will do the job
needsNewThread = false;
}
else
// the crop is now being updated ...well, when fullUpdate will be called
updating = true;
return needsNewThread;
}
// Full update, should be called via thread
/* @brief Handles Crop updating in its own thread
*
* This method will cycle updates ss long as Crop::newUpdatePending will be true. During the processing,
* intermediary update will be automatically flushed by Crop::tryUpdate.
*/
void Crop::fullUpdate () {
parent->updaterThreadStart.lock ();
if (parent->updaterRunning && parent->thread) {
// Do NOT reset changes here, since in a long chain of events it will lead to chroma_scale not being updated,
// causing Color::lab2rgb to return a black image on some opens
// Do NOT reset changes here, since in a long chain of events it will lead to chroma_scale not being updated,
// causing Color::lab2rgb to return a black image on some opens
//parent->changeSinceLast = 0;
parent->thread->join ();
}
@@ -453,12 +477,13 @@ void Crop::fullUpdate () {
if (parent->plistener)
parent->plistener->setProgressState (true);
needsNext = true;
while (needsNext) {
needsNext = false;
// If there are more update request, the following WHILE will collect it
newUpdatePending = true;
while (newUpdatePending) {
newUpdatePending = false;
update (ALL);
}
updating = false;
updating = false; // end of crop update
if (parent->plistener)
parent->plistener->setProgressState (false);

View File

@@ -37,20 +37,24 @@ class ImProcCoordinator;
class Crop : public DetailedCrop {
protected:
Imagefloat* origCrop, *baseCrop;
Imagefloat* *resizeCrop, *transCrop;
LabImage *laboCrop, *labnCrop;
Image8 *cropImg; // permanently allocated in RAM and only renewed on size changes
CieImage *cieCrop;
float** cbuffer;
float * cbuf_real;
SHMap* cshmap;
// --- permanently allocated in RAM and only renewed on size changes
Imagefloat* origCrop; // "one chunk" allocation
Imagefloat* transCrop; // "one chunk" allocation, allocated if necessary
LabImage* laboCrop; // "one chunk" allocation
LabImage* labnCrop; // "one chunk" allocation
Image8* cropImg; // "one chunk" allocation
CieImage* cieCrop; // allocating 6 images, each in "one chunk" allocation
float * cbuf_real; // "one chunk" allocation
SHMap* cshmap; // per line allocation
// -----------------------------------------------------------------
float** cbuffer;
bool updating, needsNext;
bool updating; /// Flag telling if an updater thread is currently processing
bool newUpdatePending; /// Flag telling the updater thread that a new update is pending
int skip;
int cropx, cropy, cropw, croph; // size of the detail crop image ('skip' taken into account), with border
int trafx, trafy, trafw, trafh; // the size and position to get from the imagesource that is transformed to the requested crop area
int rqcropx, rqcropy, rqcropw, rqcroph; // size of the requested detail crop image (the image might be smaller) (without border)
int cropx, cropy, cropw, croph; /// size of the detail crop image ('skip' taken into account), with border
int trafx, trafy, trafw, trafh; /// the size and position to get from the imagesource that is transformed to the requested crop area
int rqcropx, rqcropy, rqcropw, rqcroph; /// size of the requested detail crop image (the image might be smaller) (without border)
int borderRequested, upperBorder, leftBorder;
bool cropAllocated;
@@ -70,11 +74,15 @@ class Crop : public DetailedCrop {
void update (int todo);
void setWindow (int cx, int cy, int cw, int ch, int skip) { setCropSizes (cx, cy, cw, ch, skip, false); }
bool tryUpdate (); // First try, only make fullUpdate if this returns false
/** @brief Synchronously look out if a full update is necessary
* First try, only make fullUpdate if this returns false
*/
bool tryUpdate ();
/** @brief Asynchronously reprocess the detailed crop */
void fullUpdate (); // called via thread
void setListener (DetailedCropListener* il);
void destroy () {}
void destroy ();
int get_skip () { return skip;}
};
}

View File

@@ -29,8 +29,9 @@ namespace rtengine {
extern const Settings* settings;
ImProcCoordinator::ImProcCoordinator ()
: workimg(NULL), lastAwbEqual(0.), ipf(&params, true), scale(10), highDetailPreprocessComputed(false),
highDetailRawComputed(false), allocated(false),
: orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL),
ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(&params, true), scale(10),
highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false),
hltonecurve(65536,0),
shtonecurve(65536,2),//clip above
@@ -46,9 +47,9 @@ ImProcCoordinator::ImProcCoordinator ()
lhist16(65536), lhist16Cropped(65536),
lhist16CAM(65536), lhist16CroppedCAM(65536),
lhist16CCAM(65536), lhist16CroppedCCAM(65536),
lhist16CCAMAF(65536), lhist16ClabAF(65536),
lhist16CCAMAF(65536), lhist16ClabAF(65536),
histCropped(65536),
lhist16Clad(65536),lhist16CroppedClad(65536),
lhist16Clad(65536),lhist16CroppedClad(65536),
histRed(256), histRedRaw(256),
histGreen(256), histGreenRaw(256),
@@ -57,9 +58,9 @@ ImProcCoordinator::ImProcCoordinator ()
histToneCurve(256),
histLCurve(256),
histCCurve(256),
histLCAM(256),
histCCAM(256),
histClad(256),
histLCAM(256),
histCCAM(256),
histClad(256),
bcabhist(256),
rCurve(),
@@ -106,45 +107,46 @@ DetailedCrop* ImProcCoordinator::createCrop () {
// cropCall: calling crop, used to prevent self-updates
void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
mProcessing.lock ();
MyMutex::MyLock processingLock(mProcessing);
int numofphases = 14;
int readyphase = 0;
// Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications
ipf.setScale (scale);
// Check if any detail crops need high detail. If not, take a fast path short cut
// Check if any detail crops need high detail. If not, take a fast path short cut
bool highDetailNeeded = (todo & M_HIGHQUAL);
if (!highDetailNeeded) {
for (size_t i=0; i<crops.size(); i++)
if (crops[i]->get_skip() == 1 ) { // skip=1 -> full resolution
highDetailNeeded=true;
break;
}
for (size_t i=0; i<crops.size(); i++)
if (crops[i]->get_skip() == 1 ) { // skip=1 -> full resolution
highDetailNeeded=true;
break;
}
}
RAWParams rp = params.raw;
if( !highDetailNeeded ){
RAWParams rp = params.raw;
if( !highDetailNeeded ){
// if below 100% magnification, take a fast path
rp.dmethod = RAWParams::methodstring[RAWParams::fast];
rp.ca_autocorrect = false;
rp.hotdeadpix_filt = false;
rp.ccSteps = 0;
//rp.all_enhance = false;
}
rp.dmethod = RAWParams::methodstring[RAWParams::fast];
rp.ca_autocorrect = false;
rp.hotdeadpix_filt = false;
rp.ccSteps = 0;
//rp.all_enhance = false;
}
progress ("Applying white balance, color correction & sRGB conversion...",100*readyphase/numofphases);
// raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed
if ( (todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) {
imgsrc->preprocess( rp, params.lensProf, params.coarse );
imgsrc->preprocess( rp, params.lensProf, params.coarse );
imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw );
if (highDetailNeeded)
highDetailPreprocessComputed = true;
highDetailPreprocessComputed = true;
else
highDetailPreprocessComputed = false;
highDetailPreprocessComputed = false;
}
/*
/*
Demosaic is kicked off only when
Detail considerations:
accurate detail is not displayed yet needed based on preview specifics (driven via highDetailNeeded flag)
@@ -177,7 +179,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
if (todo & (M_INIT|M_LINDENOISE)) {
MyMutex::MyLock lock(minit); // Also used in crop window
MyMutex::MyLock initLock(minit); // Also used in crop window
imgsrc->HLRecovery_Global( params.hlrecovery ); // this handles Color HLRecovery
@@ -215,17 +217,19 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
imgsrc->getFullSize (fw, fh, tr);
PreviewProps pp (0, 0, fw, fh, scale);
// Will (re)allocate the preview's buffers
setScale (scale);
imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw);
//ColorTemp::CAT02 (orig_prev, &params) ;
//imgsrc->convertColorSpace(orig_prev, params.icm, params.raw);
//imgsrc->convertColorSpace(orig_prev, params.icm, params.raw);
if (todo & M_LINDENOISE) {
//printf("denoising!\n");
if (scale==1 && params.dirpyrDenoise.enabled) {
ipf.RGB_denoise(orig_prev, orig_prev, imgsrc->isRAW(), params.dirpyrDenoise, params.defringe, imgsrc->getDirPyrDenoiseExpComp());
}
//printf("denoising!\n");
if (scale==1 && params.dirpyrDenoise.enabled)
ipf.RGB_denoise(orig_prev, orig_prev, imgsrc->isRAW(), params.dirpyrDenoise, params.defringe, imgsrc->getDirPyrDenoiseExpComp());
}
imgsrc->convertColorSpace(orig_prev, params.icm, params.raw);
@@ -243,30 +247,29 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
if (needstransform && orig_prev==oprevi)
oprevi = new Imagefloat (pW, pH);
if ((todo & M_TRANSFORM) && needstransform)
ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, imgsrc->getMetaData()->getFocalLen(),
imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), false);
ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, imgsrc->getMetaData()->getFocalLen(),
imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), false);
readyphase++;
progress ("Preparing shadow/highlight map...",100*readyphase/numofphases);
if ((todo & M_BLURMAP) && params.sh.enabled) {
double radius = sqrt (double(pW*pW+pH*pH)) / 2.0;
double shradius = params.sh.radius;
if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (oprevi, shradius, ipf.lumimul, params.sh.hq, scale);
double shradius = params.sh.radius;
if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (oprevi, shradius, ipf.lumimul, params.sh.hq, scale);
}
readyphase++;
if (todo & M_AUTOEXP) {
if (params.toneCurve.autoexp) {
LUTu aehist; int aehistcompr;
imgsrc->getAutoExpHistogram (aehist, aehistcompr);
ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp,
params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh);
if (aeListener)
aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast,
params.toneCurve.black, params.toneCurve.hlcompr,params.toneCurve.hlcomprthresh);
LUTu aehist; int aehistcompr;
imgsrc->getAutoExpHistogram (aehist, aehistcompr);
ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp,
params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh);
if (aeListener)
aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast,
params.toneCurve.black, params.toneCurve.hlcompr,params.toneCurve.hlcomprthresh);
}
}
@@ -278,10 +281,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
ipf.g = imgsrc->getGamma();
ipf.iGamma = true;
CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0,
params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh,
params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast,
ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2,
vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale==1 ? 1 : 1);
params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh,
params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast,
ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2,
vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale==1 ? 1 : 1);
CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale==1 ? 1 : 1);
CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale==1 ? 1 : 1);
@@ -297,8 +300,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
int x1, y1, x2, y2, pos, poscc;
params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
lhist16.clear(); lhist16Cropped.clear();
lhist16Clad.clear(); lhist16CroppedClad.clear();
lhist16ClabAF.clear();
lhist16Clad.clear(); lhist16CroppedClad.clear();
lhist16ClabAF.clear();
for (int x=0; x<pH; x++)
for (int y=0; y<pW; y++) {
pos=CLIP((int)(oprevl->L[x][y]));
@@ -308,58 +311,55 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
}
readyphase++;
utili=false;
autili=false;
butili=false;
ccutili=false;
cclutili=false;
utili=false;
autili=false;
butili=false;
ccutili=false;
cclutili=false;
if ((todo & M_LUMACURVE) || todo==CROP) {
CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lhist16Cropped,
lumacurve, histLCurve, scale==1 ? 1 : 16, utili);
}
}
if (todo & M_LUMACURVE) {
CurveFactory::complexsgnCurve (autili, butili,ccutili,cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection,
params.labCurve.acurve, params.labCurve.bcurve,params.labCurve.cccurve,params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve,lhskcurve,
lhist16Clad,lhist16CroppedClad, histCCurve, scale==1 ? 1 : 16);
}
if (todo & (M_LUMINANCE+M_COLOR) ) {
nprevl->CopyFrom(oprevl);
progress ("Applying Color Boost...",100*readyphase/numofphases);
int poscc;
ipf.chromiLuminanceCurve (pW,nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili, histCCurve);
ipf.vibrance(nprevl);
if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) ipf.EPDToneMap(nprevl,5,1);
// for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled
readyphase++;
if (scale==1) {
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Denoising luminance impulse...",100*readyphase/numofphases);
ipf.impulsedenoise (nprevl);
readyphase++;
}
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Defringing...",100*readyphase/numofphases);
ipf.defringe (nprevl);
readyphase++;
}
if (params.sharpenEdge.enabled) {
CurveFactory::complexsgnCurve (autili, butili,ccutili,cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection,
params.labCurve.acurve, params.labCurve.bcurve,params.labCurve.cccurve,params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve,lhskcurve,
lhist16Clad,lhist16CroppedClad, histCCurve, scale==1 ? 1 : 16);
}
if (todo & (M_LUMINANCE+M_COLOR) ) {
nprevl->CopyFrom(oprevl);
progress ("Applying Color Boost...",100*readyphase/numofphases);
int poscc;
ipf.chromiLuminanceCurve (pW,nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili, histCCurve);
ipf.vibrance(nprevl);
if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) ipf.EPDToneMap(nprevl,5,1);
// for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled
readyphase++;
if (scale==1) {
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Denoising luminance impulse...",100*readyphase/numofphases);
ipf.impulsedenoise (nprevl);
readyphase++;
}
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Defringing...",100*readyphase/numofphases);
ipf.defringe (nprevl);
readyphase++;
}
if (params.sharpenEdge.enabled) {
progress ("Edge sharpening...",100*readyphase/numofphases);
ipf.MLsharpen (nprevl);
readyphase++;
}
if (params.sharpenMicro.enabled) {
if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Microcontrast...",100*readyphase/numofphases);
ipf.MLmicrocontrast (nprevl);
readyphase++;
}
}
if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) {
ipf.MLsharpen (nprevl);
readyphase++;
}
if (params.sharpenMicro.enabled) {
if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
progress ("Microcontrast...",100*readyphase/numofphases);
ipf.MLmicrocontrast (nprevl);
readyphase++;
}
}
if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) {
progress ("Sharpening...",100*readyphase/numofphases);
float **buffer = new float*[pH];
@@ -373,84 +373,92 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
delete [] buffer;
readyphase++;
}
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
// if(params.colorappearance.enabled && !params.colorappearance.sharpcie){
progress ("Pyramid equalizer...",100*readyphase/numofphases);
ipf.dirpyrequalizer (nprevl);
readyphase++;
}
if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){
//if(params.colorappearance.enabled && !params.colorappearance.sharpcie){
progress ("Pyramid equalizer...",100*readyphase/numofphases);
ipf.dirpyrequalizer (nprevl);
readyphase++;
}
}
//L histo and Chroma histo for ciecam
// histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C
//L histo and Chroma histo for ciecam
// histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C
int x1, y1, x2, y2, pos, posc;
params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
lhist16CAM.clear(); lhist16CroppedCAM.clear();
lhist16CCAM.clear(); lhist16CroppedCCAM.clear();
lhist16CCAMAF.clear();
params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
lhist16CAM.clear(); lhist16CroppedCAM.clear();
lhist16CCAM.clear(); lhist16CroppedCCAM.clear();
lhist16CCAMAF.clear();
for (int x=0; x<pH; x++)
for (int y=0; y<pW; y++) {
pos=CLIP((int)(nprevl->L[x][y]));
posc=CLIP((int)sqrt(nprevl->a[x][y]*nprevl->a[x][y] + nprevl->b[x][y]*nprevl->b[x][y]));
if(!params.colorappearance.datacie) lhist16CCAM[posc]++;
if(!params.colorappearance.datacie)lhist16CAM[pos]++;
if(!params.colorappearance.datacie) lhist16CCAM[posc]++;
if(!params.colorappearance.datacie)lhist16CAM[pos]++;
if (y>=y1 && y<y2 && x>=x1 && x<x2) {lhist16CroppedCAM[pos]++;lhist16CroppedCCAM[posc]++;}
}
LUTu dummy;
CurveFactory::curveLightBrightColor (
params.colorappearance.curveMode, params.colorappearance.curve,
params.colorappearance.curveMode2, params.colorappearance.curve2,
params.colorappearance.curveMode3, params.colorappearance.curve3,
lhist16CAM, lhist16CroppedCAM,histLCAM,
lhist16CCAM, lhist16CroppedCCAM,histCCAM,
customColCurve1,
customColCurve2,
customColCurve3,
scale==1 ? 1 : 1);
int Iterates=0;
if(params.colorappearance.enabled){
float fnum = imgsrc->getMetaData()->getFNumber ();// F number
float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed
float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + -
float adap2,adap;
double ada, ada2;
if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {adap=adap=2000.f;ada=2000.;}//if no exif data or wrong
else {
float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f));
float expo2= params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
E_V += expo2;
float expo1;//exposure raw white point
expo1=log2(params.raw.expos);//log2 ==>linear to EV
E_V += expo1;
adap2 = adap= powf(2.f, E_V-3.f);//cd / m2
ada=ada2=(double) adap;
//end calculation adaptation scene luminosity
}
int begh=0;
int endh=pH;
float d;
double dd;
float **buffer = new float*[pH];
for (int i=0; i<pH; i++)
buffer[i] = new float[pW];
bool execsharp=false;
if(scale==1) execsharp=true;
if(settings->ciecamfloat){ipf.ciecam_02float (ncie, adap, begh, endh, pW, 2, nprevl, &params, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, d);
if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*(double)d);
if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap2);//real value of adapt scene luminosity
}
else {ipf.ciecam_02 (ncie, ada, begh, endh, pW, 2, nprevl, &params, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, dd);
if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*dd);
if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(ada);
}
for (int i=0; i<pH; i++)
delete [] buffer[i];
delete [] buffer;
readyphase++;
}
}
LUTu dummy;
CurveFactory::curveLightBrightColor (
params.colorappearance.curveMode, params.colorappearance.curve,
params.colorappearance.curveMode2, params.colorappearance.curve2,
params.colorappearance.curveMode3, params.colorappearance.curve3,
lhist16CAM, lhist16CroppedCAM,histLCAM,
lhist16CCAM, lhist16CroppedCCAM,histCCAM,
customColCurve1,
customColCurve2,
customColCurve3,
scale==1 ? 1 : 1
);
if(params.colorappearance.enabled){
float fnum = imgsrc->getMetaData()->getFNumber (); // F number
float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; // Speed
double fcomp = imgsrc->getMetaData()->getExpComp (); // Compensation +/-
double adap;
if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong
adap=2000.;
}
else {
double E_V = fcomp + log2 (double((fnum*fnum) / fspeed / (fiso/100.f)));
E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV
E_V += log2(params.raw.expos);// exposure raw white point ; log2 ==> linear to EV
adap= powf(2.f, E_V-3.f);// cd / m2
// end calculation adaptation scene luminosity
}
int begh=0;
int endh=pH;
float d;
double dd;
float **buffer = new float*[pH];
for (int i=0; i<pH; i++)
buffer[i] = new float[pW];
bool execsharp=false;
if(scale==1) execsharp=true;
if(!ncie)
ncie = new CieImage (pW, pH);
if(settings->ciecamfloat){
ipf.ciecam_02float (ncie, float(adap), begh, endh, pW, 2, nprevl, &params, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, d);
if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*(double)d);
if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap);//real value of adapt scene luminosity
}
else {
ipf.ciecam_02 (ncie, adap, begh, endh, pW, 2, nprevl, &params, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, dd);
if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*dd);
if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap);
}
for (int i=0; i<pH; i++)
delete [] buffer[i];
delete [] buffer;
readyphase++;
}
else {
// CIECAM is disbaled, we free up its image buffer to save some space
if (ncie)
delete ncie; ncie=NULL;
}
}
// process crop, if needed
for (size_t i=0; i<crops.size(); i++)
if (crops[i]->hasListener () && cropCall != crops[i] )
@@ -458,29 +466,26 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
progress ("Conversion to RGB...",100*readyphase/numofphases);
if (todo!=CROP) {
previmg->getMutex().lock();
MyMutex::MyLock prevImgLock(previmg->getMutex());
try
{
ipf.lab2monitorRgb (nprevl, previmg);
delete workimg;
workimg = ipf.lab2rgb (nprevl, 0,0,pW,pH, params.icm.working);
workimg = ipf.lab2rgb (nprevl, 0,0,pW,pH, params.icm.working);
}
catch(char * str)
{
progress ("Error converting file...",0);
previmg->getMutex().unlock();
mProcessing.unlock ();
return;
}
previmg->getMutex().unlock();
}
}
if (!resultValid) {
resultValid = true;
if (imageListener)
imageListener->setImage (previmg, scale, params.crop);
}
if (imageListener)
// TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values
// TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values
imageListener->imageReady (params.crop);
readyphase++;
@@ -489,8 +494,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
updateLRGBHistograms ();
hListener->histogramChanged (histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve,histCCurve, histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma);
}
mProcessing.unlock ();
}
@@ -500,18 +503,19 @@ void ImProcCoordinator::freeAll () {
if (allocated) {
if (orig_prev!=oprevi)
delete oprevi;
delete orig_prev;
delete oprevl;
delete nprevl;
delete ncie;
delete oprevi; oprevi = NULL;
delete orig_prev; orig_prev = NULL;
delete oprevl; oprevl = NULL;
delete nprevl; nprevl = NULL;
if (ncie)
delete ncie; ncie = NULL;
if (imageListener) {
imageListener->delImage (previmg);
}
else
delete previmg;
delete workimg;
delete shmap;
@@ -519,6 +523,12 @@ void ImProcCoordinator::freeAll () {
allocated = false;
}
/** @brief Handles image buffer (re)allocation and trigger sizeChanged of SizeListener[s]
* If the scale change, this method will free all buffers and reallocate ones of the new size.
* It will then tell to the SizeListener that size has changed (sizeChanged)
*
* @param prevscale New Preview's scale.
*/
void ImProcCoordinator::setScale (int prevscale) {
if (settings->verbose) printf ("setscale before lock\n");
@@ -529,7 +539,7 @@ if (settings->verbose) printf ("setscale before lock\n");
if (params.coarse.rotate==270) tr |= TR_R270;
if (params.coarse.hflip) tr |= TR_HFLIP;
if (params.coarse.vflip) tr |= TR_VFLIP;
int nW, nH;
imgsrc->getFullSize (fw, fh, tr);
@@ -541,22 +551,22 @@ if (settings->verbose) printf ("setscale before lock\n");
if (nW!=pW || nH!=pH) {
freeAll ();
pW = nW;
pH = nH;
orig_prev = new Imagefloat (pW, pH);
oprevi = orig_prev;
oprevl = new LabImage (pW, pH);
nprevl = new LabImage (pW, pH);
ncie = new CieImage (pW, pH);
oprevl = new LabImage (pW, pH);
nprevl = new LabImage (pW, pH);
//ncie is only used in ImProcCoordinator::updatePreviewImage, it will be allocated on first use and deleted if not used anymore
previmg = new Image8 (pW, pH);
workimg = new Image8 (pW, pH);
workimg = new Image8 (pW, pH);
shmap = new SHMap (pW, pH, true);
allocated = true;
}
scale = prevscale;
resultValid = false;
fullw = fw;
@@ -578,13 +588,13 @@ void ImProcCoordinator::updateLRGBHistograms () {
histRed.clear();
histGreen.clear();
histBlue.clear();
for (int i=y1; i<y2; i++) {
int ofs = (i*pW + x1)*3;
for (int j=x1; j<x2; j++) {
int r=workimg->data[ofs++];
int g=workimg->data[ofs++];
int b=workimg->data[ofs++];
int r=workimg->data[ofs++];
int g=workimg->data[ofs++];
int b=workimg->data[ofs++];
histRed[r]++;
histGreen[g]++;
@@ -592,23 +602,22 @@ void ImProcCoordinator::updateLRGBHistograms () {
}
}
histLuma.clear();
histChroma.clear();
histLuma.clear();
histChroma.clear();
for (int i=y1; i<y2; i++)
for (int j=x1; j<x2; j++) {
histChroma[(int)(sqrt(nprevl->a[i][j]*nprevl->a[i][j] + nprevl->b[i][j]*nprevl->b[i][j]))/188]++;//188 = 48000/256
histLuma[(int)(nprevl->L[i][j]/128)]++;
}
/*for (int i=0; i<256; i++) {
Lhist[i] = (int)(256*sqrt(Lhist[i]));
rhist[i] = (int)(256*sqrt(rhist[i]));
ghist[i] = (int)(256*sqrt(ghist[i]));
bhist[i] = (int)(256*sqrt(bhist[i]));
bcrgbhist[i] = (int)(256*sqrt(bcrgbhist[i]));
bcLhist[i] = (int)(256*sqrt(bcLhist[i]));
}*/
histChroma[(int)(sqrt(nprevl->a[i][j]*nprevl->a[i][j] + nprevl->b[i][j]*nprevl->b[i][j]))/188]++;//188 = 48000/256
histLuma[(int)(nprevl->L[i][j]/128)]++;
}
/*for (int i=0; i<256; i++) {
Lhist[i] = (int)(256*sqrt(Lhist[i]));
rhist[i] = (int)(256*sqrt(rhist[i]));
ghist[i] = (int)(256*sqrt(ghist[i]));
bhist[i] = (int)(256*sqrt(bhist[i]));
bcrgbhist[i] = (int)(256*sqrt(bcrgbhist[i]));
bcLhist[i] = (int)(256*sqrt(bcLhist[i]));
}*/
}
void ImProcCoordinator::progress (Glib::ustring str, int pr) {
@@ -657,7 +666,10 @@ void ImProcCoordinator::getCamWB (double& temp, double& green) {
void ImProcCoordinator::getSpotWB (int x, int y, int rect, double& temp, double& tgreen) {
mProcessing.lock ();
ColorTemp ret;
{
MyMutex::MyLock lock(mProcessing);
std::vector<Coord2D> points, red, green, blue;
for (int i=y-rect; i<=y+rect; i++)
for (int j=x-rect; j<=x+rect; j++)
@@ -670,25 +682,25 @@ void ImProcCoordinator::getSpotWB (int x, int y, int rect, double& temp, double&
if (params.coarse.rotate==270) tr |= TR_R270;
if (params.coarse.hflip) tr |= TR_HFLIP;
if (params.coarse.vflip) tr |= TR_VFLIP;
ColorTemp ret = imgsrc->getSpotWB (red, green, blue, tr, params.wb.equal);
ret = imgsrc->getSpotWB (red, green, blue, tr, params.wb.equal);
currWB = ColorTemp (params.wb.temperature, params.wb.green,params.wb.equal, params.wb.method);
//double rr,gg,bb;
//currWB.getMultipliers(rr,gg,bb);
mProcessing.unlock ();
} // end of mutex lockong
if (ret.getTemp() > 0) {
temp = ret.getTemp ();
tgreen = ret.getGreen ();
} else {
temp = currWB.getTemp ();
tgreen = currWB.getGreen ();
}
if (ret.getTemp() > 0) {
temp = ret.getTemp ();
tgreen = ret.getGreen ();
} else {
temp = currWB.getTemp ();
tgreen = currWB.getGreen ();
}
}
void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &h) {
mProcessing.lock ();
MyMutex::MyLock lock(mProcessing);
LCPMapper *pLCPMap=NULL;
if (params.lensProf.lcpFile.length() && imgsrc->getMetaData()->getFocalLen()>0) {
@@ -700,26 +712,24 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &
double fillscale = ipf.getTransformAutoFill (fullw, fullh, pLCPMap);
if (ratio>0) {
w = fullw * fillscale;
h = w / ratio;
if (h > fullh * fillscale) {
h = fullh * fillscale;
w = h * ratio;
}
h = w / ratio;
if (h > fullh * fillscale) {
h = fullh * fillscale;
w = h * ratio;
}
}
else {
w = fullw * fillscale;
h = fullh * fillscale;
h = fullh * fillscale;
}
x = (fullw - w) / 2;
y = (fullh - h) / 2;
mProcessing.unlock ();
}
void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) {
mProcessing.lock ();
MyMutex::MyLock lock(mProcessing);
int fW, fH;
imgsrc->getFullSize (fW, fH, 0);
@@ -758,7 +768,6 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) {
im16->saveTIFF (fname,16,true);
delete im16;
//im->saveJPEG (fname, 85);
mProcessing.unlock ();
}
void ImProcCoordinator::stopProcessing () {

View File

@@ -35,8 +35,17 @@ using namespace procparams;
class Crop;
// Manages the image processing, espc. of the preview windows
// There is one ImProcCoordinator per edit panel
/** @brief Manages the image processing, espc. of the preview windows
*
* There is one ImProcCoordinator per edit panel.
*
* The ImProcCoordinator handle an sized down image representation of the full image, that is used when paning
* and in the Navigator object.
*
* Each ImProcCoordinator handles an rtengine::Crop list, which process images too with their own pipeline,
* but using this class' LUT and other precomputed parameters. The main preview area is displaying a non framed Crop object,
* while detail windows are framed Crop objects.
*/
class ImProcCoordinator : public StagedImageProcessor {
friend class Crop;
@@ -44,11 +53,11 @@ class ImProcCoordinator : public StagedImageProcessor {
protected:
Imagefloat *orig_prev;
Imagefloat *oprevi;
LabImage *oprevl;
LabImage *nprevl;
LabImage *oprevl;
LabImage *nprevl;
Image8 *previmg;
Image8 *workimg;
CieImage *ncie;
CieImage *ncie;
ImageSource* imgsrc;
@@ -82,10 +91,10 @@ class ImProcCoordinator : public StagedImageProcessor {
LUTu lhist16,lhist16Cropped;
LUTu lhist16CAM,lhist16CroppedCAM;
LUTu lhist16CCAM,lhist16CroppedCCAM;
LUTu lhist16CCAMAF;
LUTu lhist16ClabAF;
LUTu histCropped;
LUTu lhist16Clad,lhist16CroppedClad;
LUTu lhist16CCAMAF;
LUTu lhist16ClabAF;
LUTu histCropped;
LUTu lhist16Clad,lhist16CroppedClad;
LUTu histRed, histRedRaw;
LUTu histGreen, histGreenRaw;
LUTu histBlue, histBlueRaw;
@@ -94,11 +103,11 @@ class ImProcCoordinator : public StagedImageProcessor {
LUTf rCurve;
LUTf gCurve;
LUTf bCurve;
bool utili;
bool autili;
bool butili;
bool ccutili;
bool cclutili;
bool utili;
bool autili;
bool butili;
bool ccutili;
bool cclutili;
ToneCurve customToneCurve1;
ToneCurve customToneCurve2;
@@ -124,7 +133,7 @@ class ImProcCoordinator : public StagedImageProcessor {
bool resultValid;
MyMutex minit;
MyMutex minit; // to gain mutually exclusive access to ... to what exactly?
void progress (Glib::ustring str, int pr);
void reallocAll ();
@@ -189,7 +198,7 @@ class ImProcCoordinator : public StagedImageProcessor {
void setAutoCamListener (AutoCamListener* acl) {acListener = acl; }
void saveInputICCReference (const Glib::ustring& fname);
InitialImage* getInitialImage () { return imgsrc; }
};
}

View File

@@ -250,12 +250,13 @@ namespace rtengine {
virtual void autoExpChanged (double brightness, int bright, int contrast, int black, int hlcompr, int hlcomprthresh) {}
};
class AutoCamListener {
public :
virtual void autoCamChanged (double ccam) {}
virtual void adapCamChanged (double cadap) {}
};
class AutoCamListener {
public :
virtual ~AutoCamListener() {}
virtual void autoCamChanged (double ccam) {}
virtual void adapCamChanged (double cadap) {}
};
/** This class represents a detailed part of the image (looking through a kind of window).
* It can be created and destroyed with the appropriate members of StagedImageProcessor.
* Several crops can be assigned to the same image. */

View File

@@ -42,8 +42,10 @@ CropHandler::~CropHandler () {
ipc->delSizeListener (this);
setEnabled (false);
if (crop)
if (crop) {
crop->destroy ();
crop = NULL;
}
cimg.lock ();
if (chi->pending)
chi->destroyed = true;

View File

@@ -82,15 +82,15 @@ void ImageArea::on_resized (Gtk::Allocation& req) {
mainCropWindow->addCropWindowListener (this);
mainCropWindow->setCropGUIListener (cropgl);
mainCropWindow->setPointerMotionListener (pmlistener);
mainCropWindow->setPointerMotionHListener (pmhlistener);
mainCropWindow->setPointerMotionHListener (pmhlistener);
mainCropWindow->setPosition (0, 0);
mainCropWindow->setSize (get_width(), get_height(), false); // this execute the refresh itself
}
else {
mainCropWindow->setSize (get_width(), get_height());
}
parent->syncBeforeAfterViews();
}
parent->syncBeforeAfterViews();
}
}
void ImageArea::setImProcCoordinator (rtengine::StagedImageProcessor* ipc_) {