Speedup for high quality S/H.

This commit is contained in:
Emil Martinec
2011-04-09 08:25:02 -05:00
parent 04b4745718
commit 31791b268f
9 changed files with 157 additions and 28 deletions

View File

@@ -131,8 +131,9 @@ void Crop::update (int todo) {
// blurmap for shadow & highlights // blurmap for shadow & highlights
if ((todo & M_BLURMAP) && params.sh.enabled) { 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 radius = sqrt (double(SKIPS(parent->fw,skip)*SKIPS(parent->fw,skip)+SKIPS(parent->fh,skip)*SKIPS(parent->fh,skip))) / 2.0;
double shradius = radius / 1800.0 * params.sh.radius; double shradius = params.sh.radius;
cshmap->update (baseCrop, (float**)cbuffer, shradius, parent->ipf.lumimul, params.sh.hq); if (!params.sh.hq) shradius *= radius / 1800.0;
cshmap->update (baseCrop, cbuffer, shradius, parent->ipf.lumimul, params.sh.hq, skip);
cshmap->forceStat (parent->shmap->max, parent->shmap->min, parent->shmap->avg); cshmap->forceStat (parent->shmap->max, parent->shmap->min, parent->shmap->avg);
} }
@@ -348,8 +349,8 @@ if (settings->verbose) printf ("setcropsizes before lock\n");
cshmap = new SHMap (cropw, croph, true); cshmap = new SHMap (cropw, croph, true);
cbuffer = new int*[croph]; cbuffer = new float*[croph];
cbuf_real= new int[(croph+2)*cropw]; cbuf_real= new float[(croph+2)*cropw];
for (int i=0; i<croph; i++) for (int i=0; i<croph; i++)
cbuffer[i] = cbuf_real+cropw*i+cropw; cbuffer[i] = cbuf_real+cropw*i+cropw;

View File

@@ -43,8 +43,8 @@ class Crop : public DetailedCrop {
Image8 *cropImgtrue; Image8 *cropImgtrue;
int** cbuffer; float** cbuffer;
int * cbuf_real; float * cbuf_real;
SHMap* cshmap; SHMap* cshmap;
bool updating, needsNext; bool updating, needsNext;

View File

@@ -164,8 +164,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
progress ("Preparing shadow/highlight map...",100*readyphase/numofphases); progress ("Preparing shadow/highlight map...",100*readyphase/numofphases);
if ((todo & M_BLURMAP) && params.sh.enabled) { if ((todo & M_BLURMAP) && params.sh.enabled) {
double radius = sqrt (double(pW*pW+pH*pH)) / 2.0; double radius = sqrt (double(pW*pW+pH*pH)) / 2.0;
double shradius = radius / 1800.0 * params.sh.radius; double shradius = params.sh.radius;
shmap->update (oprevi, (float**)buffer, shradius, ipf.lumimul, params.sh.hq); if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (oprevi, buffer, shradius, ipf.lumimul, params.sh.hq, scale);
} }
readyphase++; readyphase++;
@@ -341,9 +343,9 @@ if (settings->verbose) printf ("setscale before lock\n");
workimg = new Image8 (pW, pH); workimg = new Image8 (pW, pH);
shmap = new SHMap (pW, pH, true); shmap = new SHMap (pW, pH, true);
buffer = new int*[pH]; buffer = new float*[pH];
for (int i=0; i<pH; i++) for (int i=0; i<pH; i++)
buffer[i] = new int[pW]; buffer[i] = new float[pW];
allocated = true; allocated = true;
} }

View File

@@ -50,7 +50,7 @@ class ImProcCoordinator : public StagedImageProcessor {
ImageSource* imgsrc; ImageSource* imgsrc;
int** buffer; float** buffer;
SHMap* shmap; SHMap* shmap;

View File

@@ -303,7 +303,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone
} }
if (processSH || processLCE) { if (processSH || processLCE) {
double mapval = shmap->map[i][j]; double mapval = 1.0 + shmap->map[i][j];
double factor = 1.0; double factor = 1.0;
if (processSH) { if (processSH) {
@@ -314,14 +314,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone
} }
if (processLCE) { if (processLCE) {
double sub = lceamount*(mapval-factor*(r*lumimul[0] + g*lumimul[1] + b*lumimul[2])); double sub = lceamount*(mapval-factor*(r*lumimul[0] + g*lumimul[1] + b*lumimul[2]));
r = (factor*r-sub); r = CLIP(factor*r-sub);
g = (factor*g-sub); g = CLIP(factor*g-sub);
b = (factor*b-sub); b = CLIP(factor*b-sub);
} }
else { else {
r = (factor*r); r = CLIP(factor*r);
g = (factor*g); g = CLIP(factor*g);
b = (factor*b); b = CLIP(factor*b);
} }
} }

View File

@@ -697,8 +697,9 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
} }
shmap = new SHMap (fw, fh, false); shmap = new SHMap (fw, fh, false);
double radius = sqrt (double(fw*fw+fh*fh)) / 2.0; double radius = sqrt (double(fw*fw+fh*fh)) / 2.0;
double shradius = radius / 1800.0 * params.sh.radius; double shradius = params.sh.radius;
shmap->update (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq); if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq, 16);
if (buffer) { if (buffer) {
for (int i=0; i<fh; i++) for (int i=0; i<fh; i++)
delete [] buffer[i]; delete [] buffer[i];

View File

@@ -21,9 +21,22 @@
#include <bilateral2.h> #include <bilateral2.h>
#include <rtengine.h> #include <rtengine.h>
#include <rawimagesource.h>//for dirpyr
#undef MAXVAL
#undef CLIP
#undef MAX
#undef MIN
#undef SQR
#undef THREAD_PRIORITY_NORMAL #undef THREAD_PRIORITY_NORMAL
#define MAXVAL 0xffff #define MAXVAL 0xffff
#define CLIP(a) ((a)>0?((a)<MAXVAL?(a):MAXVAL):0) #define CLIP(a) ((a)>0?((a)<MAXVAL?(a):MAXVAL):0)
#define SQR(x) ((x)*(x))
#define MAX(a,b) ((a)<(b)?(b):(a))
#define MIN(a,b) ((a)>(b)?(b):(a))
namespace rtengine { namespace rtengine {
@@ -43,7 +56,7 @@ SHMap::~SHMap () {
delete [] map; delete [] map;
} }
void SHMap::update (Imagefloat* img, float** buffer, double radius, double lumi[3], bool hq) { void SHMap::update (Imagefloat* img, float** buffer, double radius, double lumi[3], bool hq, int skip) {
// fill with luminance // fill with luminance
for (int i=0; i<H; i++) for (int i=0; i<H; i++)
@@ -63,6 +76,7 @@ void SHMap::update (Imagefloat* img, float** buffer, double radius, double lumi[
delete buffer; delete buffer;
} }
else { else {
/*
#if 0 #if 0
// the new OpenMP method does not need thread number specific code. // the new OpenMP method does not need thread number specific code.
// #ifdef _OPENMP // #ifdef _OPENMP
@@ -80,6 +94,57 @@ void SHMap::update (Imagefloat* img, float** buffer, double radius, double lumi[
#else #else
bilateral<float> (map, buffer, W, H, 8000, radius, 0, H); bilateral<float> (map, buffer, W, H, 8000, radius, 0, H);
#endif #endif
*/
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//experimental dirpyr shmap
float thresh = 100*radius;//1000;
LUTf rangefn(0x10000);
float ** dirpyrlo[2];
int intfactor = 1024;//16384;
//set up range functions
for (int i=0; i<0x10000; i++) {
//rangefn[i] = (int)(((thresh)/((double)(i) + (thresh)))*intfactor);
rangefn[i] = (int)(exp(-(MIN(10,((float)i*i) / (thresh*thresh))))*intfactor);
//if (rangefn[i]<0 || rangefn[i]>intfactor)
//printf("i=%d rangefn=%d arg=%f \n",i,rangefn[i], float(i*i) / (thresh*thresh));
}
dirpyrlo[0] = allocArray<float> (W, H);
dirpyrlo[1] = allocArray<float> (W, H);
int scale=1;
int level=0;
int indx=0;
dirpyr_shmap(map, dirpyrlo[indx], W, H, rangefn, 0, scale );
scale *= 2;
level += 1;
indx = 1-indx;
while (skip*scale<16) {
dirpyr_shmap(dirpyrlo[1-indx], dirpyrlo[indx], W, H, rangefn, level, scale );
scale *= 2;
level += 1;
indx = 1-indx;
}
/*dirpyr_shmap(dirpyrlo[0], dirpyrlo[1], W, H, rangefn, 1, scale );
scale = 4;
dirpyr_shmap(dirpyrlo[1], dirpyrlo[0], W, H, rangefn, 2, scale );
scale = 8;
dirpyr_shmap(dirpyrlo[0], dirpyrlo[1], W, H, rangefn, 3, scale );
scale = 16;
dirpyr_shmap(dirpyrlo[1], map, W, H, rangefn, 3, scale );*/
dirpyr_shmap(dirpyrlo[1-indx], map, W, H, rangefn, level, scale );
freeArray<float>(dirpyrlo[0], H);
freeArray<float>(dirpyrlo[1], H);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
// anti-alias filtering the result // anti-alias filtering the result
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp for #pragma omp for
@@ -90,6 +155,8 @@ void SHMap::update (Imagefloat* img, float** buffer, double radius, double lumi[
map[i][j] = (buffer[i-1][j-1]+buffer[i-1][j]+buffer[i-1][j+1]+buffer[i][j-1]+buffer[i][j]+buffer[i][j+1]+buffer[i+1][j-1]+buffer[i+1][j]+buffer[i+1][j+1])/9; map[i][j] = (buffer[i-1][j-1]+buffer[i-1][j]+buffer[i-1][j+1]+buffer[i][j-1]+buffer[i][j]+buffer[i][j+1]+buffer[i+1][j-1]+buffer[i+1][j]+buffer[i+1][j+1])/9;
else else
map[i][j] = buffer[i][j]; map[i][j] = buffer[i][j];
*/
} }
} // end parallel enclosure } // end parallel enclosure
// update average, minimum, maximum // update average, minimum, maximum
@@ -115,5 +182,60 @@ void SHMap::forceStat (float max_, float min_, float avg_) {
max = max_; max = max_;
min = min_; min = min_;
avg = avg_; avg = avg_;
}} }
void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale)
{
//scale is spacing of directional averaging weights
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// calculate weights, compute directionally weighted average
int halfwin=2;
int domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,2,2,1},{1,2,2,2,1},{1,1,1,1,1}};
//generate domain kernel
if (level<2) {
halfwin = 1;
domker[1][1]=domker[1][2]=domker[2][1]=domker[2][2]=1;
}
int scalewin = halfwin*scale;
#ifdef _OPENMP
#pragma omp parallel for
#endif
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++)
{
float val=0;
float norm=0;
for(int inbr=(i-scalewin); inbr<=(i+scalewin); inbr+=scale) {
if (inbr<0 || inbr>height-1) continue;
for (int jnbr=(j-scalewin); jnbr<=(j+scalewin); jnbr+=scale) {
if (jnbr<0 || jnbr>width-1) continue;
float dirwt = ( domker[(inbr-i)/scale+halfwin][(jnbr-j)/scale+halfwin] * rangefn[abs(data_fine[inbr][jnbr]-data_fine[i][j])] );
val += dirwt*data_fine[inbr][jnbr];
norm += dirwt;
/*if (val<0 || norm<0) {
printf("val=%f norm=%f \n",val,norm);
printf("i=%d j=%d inbr=%d jnbr=%d domker=%d val=%d nbrval=%d rangefn=%d \n",i,j,inbr,jnbr, \
domker[(inbr-i)/scale+halfwin][(jnbr-j)/scale+halfwin], \
data_fine[i][j], data_fine[inbr][jnbr], \
rangefn[abs(data_fine[inbr][jnbr]-data_fine[i][j])]);
}*/
}
}
data_coarse[i][j]=CLIP((int)(val/norm));//low pass filter
if (val<=0 || norm<=0)
printf("val=%f norm=%f \n",val,norm);
}
}
}
}//end of SHMap

View File

@@ -35,8 +35,10 @@ class SHMap {
SHMap (int w, int h, bool multiThread); SHMap (int w, int h, bool multiThread);
~SHMap (); ~SHMap ();
void update (Imagefloat* img, float** buffer, double radius, double lumi[3], bool hq); void update (Imagefloat* img, float** buffer, double radius, double lumi[3], bool hq, int skip);
void forceStat (float max_, float min_, float avg_); void forceStat (float max_, float min_, float avg_);
void dirpyr_shmap (float ** data_fine, float ** data_coarse,
int width, int height, LUTf & rangefn, int level, int scale);
}; };
}; };
#endif #endif

View File

@@ -122,16 +122,17 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
} }
// update blurmap // update blurmap
int** buffer = new int*[fh]; float** buffer = new float*[fh];
for (int i=0; i<fh; i++) for (int i=0; i<fh; i++)
buffer[i] = new int[fw]; buffer[i] = new float[fw];
SHMap* shmap = NULL; SHMap* shmap = NULL;
if (params.sh.enabled) { if (params.sh.enabled) {
shmap = new SHMap (fw, fh, true); shmap = new SHMap (fw, fh, true);
double radius = sqrt (double(fw*fw+fh*fh)) / 2.0; double radius = sqrt (double(fw*fw+fh*fh)) / 2.0;
double shradius = radius / 1800.0 * params.sh.radius; double shradius = params.sh.radius;
shmap->update (baseImg, (float**)buffer, shradius, ipf.lumimul, params.sh.hq); if (!params.sh.hq) shradius *= radius / 1800.0;
shmap->update (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq, 1);
} }
// RGB processing // RGB processing
//!!!// auto exposure!!! //!!!// auto exposure!!!
@@ -190,7 +191,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
//ipf.waveletEqualizer (labView, true, true); //ipf.waveletEqualizer (labView, true, true);
// directional pyramid equalizer // directional pyramid equalizer
ipf.dirpyrequalizer (labView); ipf.dirpyrequalizer (labView);//TODO: this is the luminance tonecurve, not the RGB one
for (int i=0; i<fh; i++) for (int i=0; i<fh; i++)
delete [] buffer[i]; delete [] buffer[i];