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:
@@ -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);
|
||||
|
||||
|
||||
@@ -11,8 +11,15 @@ CieImage::CieImage (int w, int h) : fromImage(false), W(w), H(h) {
|
||||
// ch_p = new float*[H];
|
||||
h_p = new float*[H];
|
||||
|
||||
data = new float [W*H*6];
|
||||
float * index = data;
|
||||
// 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;
|
||||
@@ -34,6 +41,34 @@ CieImage::CieImage (int w, int h) : fromImage(false), W(w), H(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 () {
|
||||
|
||||
@@ -46,13 +81,19 @@ CieImage::~CieImage () {
|
||||
// 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){
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ private:
|
||||
|
||||
public:
|
||||
int W, H;
|
||||
float * data;
|
||||
float * data[6];
|
||||
float** J_p;
|
||||
float** Q_p;
|
||||
float** M_p;
|
||||
|
||||
@@ -30,9 +30,15 @@ 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),
|
||||
: 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);
|
||||
@@ -40,15 +46,19 @@ Crop::Crop (ImProcCoordinator* parent)
|
||||
|
||||
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();
|
||||
|
||||
@@ -107,26 +117,28 @@ void Crop::update (int todo) {
|
||||
//parent->imgsrc->convertColorSpace(origCrop, params.icm);
|
||||
|
||||
if (todo & M_LINDENOISE) {
|
||||
if (skip==1 && params.dirpyrDenoise.enabled) {
|
||||
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;
|
||||
transCrop = NULL;
|
||||
}
|
||||
if (needstransform && !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;
|
||||
}
|
||||
|
||||
// blurmap for shadow & highlights
|
||||
if ((todo & M_BLURMAP) && params.sh.enabled) {
|
||||
@@ -205,31 +217,39 @@ void Crop::update (int todo) {
|
||||
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
|
||||
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 {
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
|
||||
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 {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);}
|
||||
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
|
||||
@@ -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");
|
||||
@@ -392,20 +409,16 @@ if (settings->verbose) printf ("setcropsizes before lock\n");
|
||||
trafh = orH;
|
||||
|
||||
origCrop = new Imagefloat (trafw, trafh);
|
||||
//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;
|
||||
|
||||
resizeCrop = NULL;
|
||||
transCrop = NULL;
|
||||
cshmap = new SHMap (cropw, croph, true);
|
||||
|
||||
cropAllocated = true;
|
||||
|
||||
@@ -425,20 +438,31 @@ 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;
|
||||
bool needsNewThread = true;
|
||||
|
||||
// If there are more update request, the following WHILE will collect it
|
||||
if (updating) {
|
||||
needsNext = true;
|
||||
needsFullUpdate = false;
|
||||
} else updating = true;
|
||||
// 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 needsFullUpdate;
|
||||
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 ();
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
// --- 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;
|
||||
float * cbuf_real;
|
||||
SHMap* cshmap;
|
||||
|
||||
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;}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -106,11 +107,12 @@ 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
|
||||
@@ -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,7 +217,10 @@ 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) ;
|
||||
|
||||
@@ -223,10 +228,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
|
||||
if (todo & M_LINDENOISE) {
|
||||
//printf("denoising!\n");
|
||||
if (scale==1 && params.dirpyrDenoise.enabled) {
|
||||
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);
|
||||
|
||||
ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma());
|
||||
@@ -254,7 +258,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
double shradius = params.sh.radius;
|
||||
if (!params.sh.hq) shradius *= radius / 1800.0;
|
||||
shmap->update (oprevi, shradius, ipf.lumimul, params.sh.hq, scale);
|
||||
|
||||
}
|
||||
readyphase++;
|
||||
|
||||
@@ -316,13 +319,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
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);
|
||||
@@ -330,7 +331,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
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);
|
||||
@@ -379,8 +379,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
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
|
||||
int x1, y1, x2, y2, pos, posc;
|
||||
@@ -406,25 +406,22 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
customColCurve1,
|
||||
customColCurve2,
|
||||
customColCurve3,
|
||||
scale==1 ? 1 : 1);
|
||||
int Iterates=0;
|
||||
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
|
||||
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
|
||||
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 {
|
||||
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;
|
||||
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;
|
||||
@@ -436,20 +433,31 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
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, ¶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);
|
||||
|
||||
if(!ncie)
|
||||
ncie = new CieImage (pW, pH);
|
||||
|
||||
if(settings->ciecamfloat){
|
||||
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; 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++)
|
||||
@@ -458,7 +466,7 @@ 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);
|
||||
@@ -468,11 +476,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
|
||||
catch(char * str)
|
||||
{
|
||||
progress ("Error converting file...",0);
|
||||
previmg->getMutex().unlock();
|
||||
mProcessing.unlock ();
|
||||
return;
|
||||
}
|
||||
previmg->getMutex().unlock();
|
||||
}
|
||||
if (!resultValid) {
|
||||
resultValid = true;
|
||||
@@ -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,11 +503,12 @@ 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);
|
||||
@@ -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");
|
||||
@@ -549,7 +559,7 @@ if (settings->verbose) printf ("setscale before lock\n");
|
||||
oprevi = orig_prev;
|
||||
oprevl = new LabImage (pW, pH);
|
||||
nprevl = new LabImage (pW, pH);
|
||||
ncie = new CieImage (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);
|
||||
shmap = new SHMap (pW, pH, true);
|
||||
@@ -598,7 +608,6 @@ void ImProcCoordinator::updateLRGBHistograms () {
|
||||
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++) {
|
||||
@@ -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,12 +682,12 @@ 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 ();
|
||||
@@ -688,7 +700,7 @@ void ImProcCoordinator::getSpotWB (int x, int y, int rect, double& temp, double&
|
||||
|
||||
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) {
|
||||
@@ -712,14 +724,12 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &
|
||||
}
|
||||
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 () {
|
||||
|
||||
@@ -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;
|
||||
@@ -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 ();
|
||||
|
||||
@@ -252,10 +252,11 @@ namespace rtengine {
|
||||
|
||||
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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user