From b7e0b0ebabb6a78823ab768427ffd68e5610e3e7 Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 6 Nov 2013 00:19:06 +0100 Subject: [PATCH] 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. --- rtengine/FTblockDN.cc | 2 +- rtengine/cieimage.cc | 101 +++++--- rtengine/cieimage.h | 2 +- rtengine/dcrop.cc | 425 ++++++++++++++++-------------- rtengine/dcrop.h | 36 ++- rtengine/improccoordinator.cc | 473 +++++++++++++++++----------------- rtengine/improccoordinator.h | 41 +-- rtengine/rtengine.h | 13 +- rtgui/crophandler.cc | 4 +- rtgui/imagearea.cc | 6 +- 10 files changed, 599 insertions(+), 504 deletions(-) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 39f542d0c..fef2d047a 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -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); diff --git a/rtengine/cieimage.cc b/rtengine/cieimage.cc index 2ae1bd9c8..ae66f92b8 100644 --- a/rtengine/cieimage.cc +++ b/rtengine/cieimage.cc @@ -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; idata, 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)); } } diff --git a/rtengine/cieimage.h b/rtengine/cieimage.h index ca6e5785c..0688ad053 100644 --- a/rtengine/cieimage.h +++ b/rtengine/cieimage.h @@ -29,7 +29,7 @@ private: public: int W, H; - float * data; + float * data[6]; float** J_p; float** Q_p; float** M_p; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index a923d7479..7a4b97cb2 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -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::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, ¶ms) ; - //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, ¶ms,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, ¶ms,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, ¶ms, 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, ¶ms, 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; idata + 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; iverbose) 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; iverbose) 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); diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index b5881546c..52b6f9fe3 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -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;} }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 0495261e5..f39dedad2 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -29,8 +29,9 @@ namespace rtengine { extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () - : workimg(NULL), lastAwbEqual(0.), ipf(¶ms, 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(¶ms, 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; iget_skip() == 1 ) { // skip=1 -> full resolution - highDetailNeeded=true; - break; - } + for (size_t i=0; iget_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, ¶ms) ; - //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; xL[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; xL[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=x1 && xgetMetaData()->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; iciecamfloat){ipf.ciecam_02float (ncie, adap, begh, endh, pW, 2, nprevl, ¶ms, 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, ¶ms, 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; igetMetaData()->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; iciecamfloat){ + ipf.ciecam_02float (ncie, float(adap), begh, endh, pW, 2, nprevl, ¶ms, 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, ¶ms, 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; ihasListener () && 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; idata[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; ia[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 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 () { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 3d2798210..dfc50ece9 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -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; } }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 85cbafb39..33c478969 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -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. */ diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index 4f612ccd0..4efcaa466 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -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; diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index de95e526a..c6e17f8e7 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -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_) {