various fixes to Fattal, and moved it later in the pipeline

This commit is contained in:
Alberto Griggio
2017-11-03 14:58:27 +01:00
parent 77b4ad497b
commit d418b9d01d
7 changed files with 108 additions and 52 deletions

View File

@@ -808,6 +808,10 @@ void Crop::update (int todo)
parent->ipf.chromiLuminanceCurve (this, 1, labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->clcurve, parent->lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy);
parent->ipf.vibrance (labnCrop);
if (params.fattal.enabled) {
parent->ipf.ToneMapFattal02(labnCrop, 3);
}
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) {
parent->ipf.EPDToneMap (labnCrop, 5, skip);
}
@@ -1077,6 +1081,11 @@ void Crop::freeAll ()
namespace
{
bool check_need_full_image(const ProcParams &params)
{
return params.fattal.enabled; // agriggio - maybe we can do this for wavelets too?
}
bool check_need_larger_crop_for_lcp_distortion (int fw, int fh, int x, int y, int w, int h, const ProcParams &params)
{
if (x == 0 && y == 0 && w == fw && h == fh) {
@@ -1139,6 +1148,14 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte
ory = by1;
orw = bw;
orh = bh;
if (check_need_full_image(parent->params)) {
orx = bx1 = 0;
ory = by1 = 0;
orw = bw = parent->fullw;
orh = bh = parent->fullh;
}
ProcParams& params = parent->params;
parent->ipf.transCoord (parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh);
@@ -1178,7 +1195,6 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte
orh = min (y2 - y1, parent->fh - ory);
}
PreviewProps cp (orx, ory, orw, orh, skip);
int orW, orH;
parent->imgsrc->getSize (cp, orW, orH);

View File

@@ -636,6 +636,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall)
ipf.chromiLuminanceCurve (nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve);
ipf.vibrance (nprevl);
if (params.fattal.enabled) {
ipf.ToneMapFattal02(nprevl, 3);
}
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) {
ipf.EPDToneMap (nprevl, 5, scale);
}

View File

@@ -3119,19 +3119,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
}
}
std::unique_ptr<Imagefloat> fattal;
if (params->fattal.enabled) {
fattal.reset(working->copy());
int detail_level = 3;
if (scale < 8) {
detail_level = 3;
} else {
detail_level = 0;
}
ToneMapFattal02(fattal.get(), detail_level);
working = fattal.get();
}
int h_th = 0, s_th = 0;
if (shmap) {

View File

@@ -347,7 +347,7 @@ public:
void Badpixelscam (CieImage * src, CieImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad);
void BadpixelsLab (LabImage * src, LabImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom);
void ToneMapFattal02(Imagefloat *rgb, int detail_level);
void ToneMapFattal02(LabImage *lab, int detail_level);
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga = nullptr);

View File

@@ -1275,6 +1275,10 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
ipf.vibrance (labView);
if (params.fattal.enabled) {
ipf.ToneMapFattal02(labView, 0);
}
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || !params.colorappearance.enabled) {
ipf.EPDToneMap (labView, 5, 6);
}

View File

@@ -1013,6 +1013,10 @@ private:
ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy);
if (params.fattal.enabled) {
ipf.ToneMapFattal02(labView, 3);
}
if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) {
ipf.EPDToneMap (labView, 5, 1);
}

View File

@@ -68,6 +68,8 @@
#include "array2D.h"
#include "improcfun.h"
#include "settings.h"
#include "iccstore.h"
namespace rtengine {
@@ -155,6 +157,15 @@ void gaussianBlur(const Array2Df& I, Array2Df& L)
Array2Df T(width,height);
if (width < 3 || height < 3) {
if (&I != &L) {
for (int i = 0, n = width*height; i < n; ++i) {
L(i) = I(i);
}
}
return;
}
//--- X blur
//#pragma omp parallel for shared(I, T)
for ( int y=0 ; y<height ; y++ )
@@ -202,10 +213,20 @@ void createGaussianPyramids( Array2Df* H, Array2Df** pyramids, int nlevels)
for ( int k=1 ; k<nlevels ; k++ )
{
if (width > 2 && height > 2) {
width /= 2;
height /= 2;
pyramids[k] = new Array2Df(width,height);
downSample(*L, *pyramids[k]);
} else {
// RT - now nlevels is fixed in tmo_fattal02 (see the comment in
// there), so it might happen that we have to add some padding to
// the gaussian pyramids
pyramids[k] = new Array2Df(width,height);
for (int j = 0, n = width*height; j < n; ++j) {
(*pyramids[k])(j) = (*L)(j);
}
}
delete L;
L = new Array2Df(width,height);
@@ -379,7 +400,7 @@ void findMaxMinPercentile(const Array2Df& I,
maxLum = vI.at( int(maxPrct*vI.size()) );
}
void solve_pde_fft(Array2Df *F, Array2Df *U);
void solve_pde_fft(Array2Df *F, Array2Df *U, bool multithread);
void tmo_fattal02(size_t width,
size_t height,
@@ -388,7 +409,8 @@ void tmo_fattal02(size_t width,
float alfa,
float beta,
float noise,
int detail_level)
int detail_level,
bool multithread)
{
// #ifdef TIMER_PROFILING
// msec_timer stop_watch;
@@ -404,15 +426,21 @@ void tmo_fattal02(size_t width,
// ph.setValue(2);
// if (ph.canceled()) return;
int MSIZE = 32; // minimum size of gaussian pyramid
// I believe a smaller value than 32 results in slightly better overall
// quality but I'm only applying this if the newly implemented fft solver
// is used in order not to change behaviour of the old version
// TODO: best let the user decide this value
// if (fftsolver)
{
MSIZE = 8;
}
/* RT -- we use a hardcoded value of 8 for nlevels, to limit the
* dependency of the result on the image size. When using an auto computed
* nlevels value, you would get vastly different results with different
* image sizes, making it essentially impossible to preview the tool
* inside RT. With a hardcoded value, the results for the preview are much
* closer to those for the final image */
// int MSIZE = 32; // minimum size of gaussian pyramid
// // I believe a smaller value than 32 results in slightly better overall
// // quality but I'm only applying this if the newly implemented fft solver
// // is used in order not to change behaviour of the old version
// // TODO: best let the user decide this value
// // if (fftsolver)
// {
// MSIZE = 8;
// }
int size = width*height;
// unsigned int x,y;
@@ -435,16 +463,17 @@ void tmo_fattal02(size_t width,
// ph.setValue(4);
// create gaussian pyramids
int mins = (width<height) ? width : height; // smaller dimension
int nlevels = 0;
while ( mins >= MSIZE )
{
nlevels++;
mins /= 2;
}
// std::cout << "DEBUG: nlevels = " << nlevels << ", mins = " << mins << std::endl;
// The following lines solves a bug with images particularly small
if (nlevels == 0) nlevels = 1;
// int mins = (width<height) ? width : height; // smaller dimension
// int nlevels = 0;
// while ( mins >= MSIZE )
// {
// nlevels++;
// mins /= 2;
// }
// // std::cout << "DEBUG: nlevels = " << nlevels << ", mins = " << mins << std::endl;
// // The following lines solves a bug with images particularly small
// if (nlevels == 0) nlevels = 1;
const int nlevels = 7; // RT -- see above
Array2Df** pyramids = new Array2Df*[nlevels];
createGaussianPyramids(H, pyramids, nlevels);
@@ -551,7 +580,7 @@ void tmo_fattal02(size_t width,
Array2Df U(width, height);
// if (fftsolver)
{
solve_pde_fft(&DivG, &U);//, ph);
solve_pde_fft(&DivG, &U, multithread);//, ph);
}
// else
// {
@@ -798,7 +827,7 @@ std::vector<double> get_lambda(int n)
// not modified and the equation might not have a solution but an
// approximate solution with a minimum error is then calculated
// double precision version
void solve_pde_fft(Array2Df *F, Array2Df *U)/*, pfs::Progress &ph,
void solve_pde_fft(Array2Df *F, Array2Df *U, bool multithread)/*, pfs::Progress &ph,
bool adjust_bound)*/
{
// ph.setValue(20);
@@ -809,8 +838,10 @@ void solve_pde_fft(Array2Df *F, Array2Df *U)/*, pfs::Progress &ph,
// activate parallel execution of fft routines
#ifdef RT_FFTW3F_OMP
if (multithread) {
fftwf_init_threads();
fftwf_plan_with_nthreads( omp_get_max_threads() );
}
// #else
// fftwf_plan_with_nthreads( 2 );
#endif
@@ -883,7 +914,9 @@ void solve_pde_fft(Array2Df *F, Array2Df *U)/*, pfs::Progress &ph,
// fft parallel threads cleanup, better handled outside this function?
#ifdef RT_FFTW3F_OMP
if (multithread) {
fftwf_cleanup_threads();
}
#endif
// ph.setValue(90);
@@ -916,10 +949,7 @@ void solve_pde_fft(Array2Df *F, Array2Df *U)/*, pfs::Progress &ph,
// }
} // namespace
void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, int detail_level)
void tmo_fattal02_RT(Imagefloat *rgb, float alpha, float beta, int detail_level, bool multiThread)
{
int w = rgb->getWidth();
int h = rgb->getHeight();
@@ -936,8 +966,8 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, int detail_level)
}
}
float alpha = params->fattal.alpha;
float beta = params->fattal.beta;
// float alpha = params->fattal.alpha;
// float beta = params->fattal.beta;
float noise = alpha * 0.01f;
if (settings->verbose) {
@@ -945,7 +975,7 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, int detail_level)
<< ", detail_level = " << detail_level << std::endl;
}
tmo_fattal02(w, h, Yr, L, alpha, beta, noise, detail_level);
tmo_fattal02(w, h, Yr, L, alpha, beta, noise, detail_level, multiThread);
const float epsilon = 1e-4f;
for (int y = 0; y < h; y++) {
@@ -961,4 +991,15 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, int detail_level)
rgb->normalizeFloatTo65535();
}
} // namespace
void ImProcFunctions::ToneMapFattal02(LabImage *lab, int detail_level)
{
Imagefloat tmp(lab->W, lab->H);
lab2rgb(*lab, tmp, params->icm.working);
tmo_fattal02_RT(&tmp, params->fattal.alpha, params->fattal.beta, detail_level, multiThread);
rgb2lab(tmp, *lab, params->icm.working);
}
} // namespace rtengine