some enhancements of the Fast Export functionality

- remember fast export options across RT sessions

- added option to use a dedicated "Fast Export" pipeline, trading speed for
  quality (resizes early instead of at the end)
This commit is contained in:
Alberto Griggio
2017-03-08 22:55:08 +01:00
parent 93296cff17
commit 44505ccb08
10 changed files with 76 additions and 99 deletions

View File

@@ -80,6 +80,8 @@ EXPORT_BYPASS_SHARPENEDGE;Bypass Edge Sharpening
EXPORT_BYPASS_SHARPENING;Bypass Sharpening
EXPORT_BYPASS_SHARPENMICRO;Bypass Microcontrast
EXPORT_BYPASS_SH_HQ;Bypass Sharp Mask Shadows/Highlights
EXPORT_USE_FAST_PIPELINE;Enable Special "Fast-Export" Processing Pipeline
EXPORT_USE_FAST_PIPELINE_TIP;Use a dedicated processing pipeline for images in Fast Export mode, that trades speed for quality. Resizing of the image is done as early as possible, instead of doing it at the end like in the normal pipeline. The speedup can be significant, but be prepared to see artifacts and a general degradation of output quality.
EXPORT_FASTEXPORTOPTIONS;<b>Fast Export Options</b>
EXPORT_INSTRUCTIONS;Fast Export options provide overrides to bypass time and resource consuming development settings and to run queue processing using the fast export settings instead. This method is recommended for quicker generation of lower resolution images when speed is a priority or when resized output is desired for one or many images without making modifications to their saved development parameters.
EXPORT_MAXHEIGHT;Maximum height:

View File

@@ -49,6 +49,8 @@ public:
initialImage->decreaseRef();
}
}
bool fastPipeline() const { return fast; }
};
}

View File

@@ -483,6 +483,8 @@ public:
* gets invalid, you must not use it any more. Dont call this function while the job is being processed.
* @param job is the job to destroy */
static void destroy (ProcessingJob* job);
virtual bool fastPipeline() const = 0;
};
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It returns when it is ready, so it can be slow.

View File

@@ -67,16 +67,12 @@ public:
private:
Image16 *normal_pipeline()
{
if (!stage_1()) {
if (!stage_init()) {
return nullptr;
}
stage_calc_denoise();
stage_2();
stage_3();
stage_4();
stage_5();
stage_6();
return stage_7();
stage_denoise();
stage_transform();
return stage_finish();
}
Image16 *fast_pipeline()
@@ -87,26 +83,16 @@ private:
pl = nullptr;
if (!stage_1()) {
if (!stage_init()) {
return nullptr;
}
stage_calc_denoise();
printf("after calc denoise\n"); fflush(stdout);
stage_2();
stage_4();
printf("after 4\n"); fflush(stdout);
stage_transform();
stage_early_resize();
printf("after early resize\n"); fflush(stdout);
stage_3();
printf("after 3\n"); fflush(stdout);
stage_5();
printf("after 5\n"); fflush(stdout);
stage_6();
printf("after 6\n"); fflush(stdout);
return stage_7();
stage_denoise();
return stage_finish();
}
bool stage_1()
bool stage_init()
{
errorCode = 0;
@@ -230,19 +216,6 @@ private:
currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias);
}
// // AG begin
// baseImg = new Imagefloat (fw, fh);
// imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw);
// // AG end
return true;
}
void stage_calc_denoise()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
calclum = nullptr ;
params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve);
autoNR = (float) settings->nrauto;//
@@ -713,14 +686,6 @@ private:
//end evaluate noise
}
// return true;
}
void stage_2()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
baseImg = new Imagefloat (fw, fh);
imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw);
@@ -752,9 +717,11 @@ private:
imgsrc->flushRawData();
imgsrc->flushRGB();
}
return true;
}
void stage_3()
void stage_denoise()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
@@ -816,17 +783,9 @@ private:
delete [] ry;
delete [] sk;
delete [] pcsk;
// imgsrc->convertColorSpace(baseImg, params.icm, currWB);
// // perform first analysis
// hist16 (65536);
// ipf.firstAnalysis (baseImg, params, hist16);
}
void stage_4()
void stage_transform()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
@@ -848,7 +807,7 @@ private:
}
}
void stage_5()
Image16 *stage_finish()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
@@ -990,13 +949,7 @@ private:
if (pl) {
pl->setProgress (0.55);
}
}
void stage_6()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// start tile processing...???
@@ -1187,13 +1140,7 @@ private:
if (pl) {
pl->setProgress (0.60);
}
}
Image16 *stage_7()
{
procparams::ProcParams& params = job->pparams;
ImProcFunctions ipf (&params, true);
int imw, imh;
double tmpScale = ipf.resizeScale(&params, fw, fh, imw, imh);
bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0;
@@ -1392,12 +1339,10 @@ private:
int imw, imh;
double tmpScale = ipf.resizeScale(&params, fw, fh, imw, imh);
// bool resize = params.resize.enabled;
LabImage *tmplab = new LabImage(fw, fh);
ipf.rgb2lab(*baseImg, *tmplab, params.icm.working);
// crop and convert to rgb16
int cx = 0, cy = 0, cw = fw, ch = fh;
if (params.crop.enabled) {
@@ -1438,9 +1383,10 @@ private:
params.dirpyrDenoise.luma *= tmpScale;
params.dirpyrDenoise.smethod = "shal";
const double dirpyreq_scale = min(tmpScale * 1.5, 1.0);
for (int i = 0; i < 6; ++i) {
auto &n = params.dirpyrequalizer.mult[i];
n = 1.0 + (n - 1.0) * tmpScale;
n = 1.0 + (n - 1.0) * dirpyreq_scale;
}
fw = imw;

View File

@@ -35,8 +35,6 @@
#include "rtimage.h"
#include <sys/time.h>
#include "../rtengine/processingjob.h"
using namespace std;
using namespace rtengine;
@@ -245,7 +243,7 @@ bool BatchQueue::saveBatchQueue ()
<< saveFormat.pngBits << '|' << saveFormat.pngCompression << '|'
<< saveFormat.tiffBits << '|' << saveFormat.tiffUncompressed << '|'
<< saveFormat.saveParams << '|' << entry->forceFormatOpts << '|'
<< static_cast<ProcessingJobImpl *>(entry->job)->fast << '|'
<< entry->job->fastPipeline() << '|'
<< std::endl;
}
}

View File

@@ -39,6 +39,8 @@ ExportPanel::ExportPanel () : listener (nullptr)
pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4);
bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL")));
use_fast_pipeline = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_USE_FAST_PIPELINE")));
use_fast_pipeline->set_tooltip_text(M("EXPORT_USE_FAST_PIPELINE_TIP"));
bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING")));
bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE")));
bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO")));
@@ -96,6 +98,7 @@ ExportPanel::ExportPanel () : listener (nullptr)
// ----------------------------------------------------------------
// start global packing
pack_start(*use_fast_pipeline , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4);
pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4);
pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4);
@@ -224,40 +227,48 @@ void ExportPanel::FastExportPressed ()
void ExportPanel::SaveSettingsAsDefault()
{
bool changed = false;
#define FE_OPT_STORE_(n, v) \
do { \
if (n != v) { \
n = v; \
changed = true; \
} \
} while (false)
// Save fast export settings to options
options.fastexport_bypass_sharpening = bypass_sharpening->get_active ();
options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active ();
options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active ();
FE_OPT_STORE_(options.fastexport_bypass_sharpening, bypass_sharpening->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_sharpenEdge, bypass_sharpenEdge->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_sharpenMicro, bypass_sharpenMicro->get_active ());
//options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active ();
//options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active ();
options.fastexport_bypass_defringe = bypass_defringe->get_active ();
options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active ();
options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active ();
options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active ();
options.fastexport_bypass_wavelet = bypass_wavelet->get_active ();
FE_OPT_STORE_(options.fastexport_bypass_defringe, bypass_defringe->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_dirpyrDenoise, bypass_dirpyrDenoise->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_sh_hq, bypass_sh_hq->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_dirpyrequalizer, bypass_dirpyrequalizer->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_wavelet, bypass_wavelet->get_active ());
//options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active ();
options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active ();
options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active ();
options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active();
options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active ();
options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active ();
options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active ();
options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active ();
options.fastexport_bypass_raw_df = bypass_raw_df->get_active ();
options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active ();
FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_iterations, bypass_raw_bayer_dcb_iterations->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_enhance, bypass_raw_bayer_dcb_enhance->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_lmmse_iterations, bypass_raw_bayer_lmmse_iterations->get_active());
FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_linenoise, bypass_raw_bayer_linenoise->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_greenthresh, bypass_raw_bayer_greenthresh->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_ccSteps, bypass_raw_ccSteps->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_ca, bypass_raw_ca->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_df, bypass_raw_df->get_active ());
FE_OPT_STORE_(options.fastexport_bypass_raw_ff, bypass_raw_ff->get_active ());
//saving Bayer demosaic_method
int currentRow = raw_bayer_method->get_active_row_number();
if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) {
options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow];
FE_OPT_STORE_(options.fastexport_raw_bayer_method, procparams::RAWParams::BayerSensor::methodstring[currentRow]);
}
//saving X-Trans demosaic_method
currentRow = raw_xtrans_method->get_active_row_number();
if( currentRow >= 0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) {
options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow];
FE_OPT_STORE_(options.fastexport_raw_xtrans_method, procparams::RAWParams::XTransSensor::methodstring[currentRow]);
}
// options.fastexport_icm_input = icm_input ;
@@ -269,9 +280,16 @@ void ExportPanel::SaveSettingsAsDefault()
// options.fastexport_resize_appliesTo = resize_appliesTo;
// options.fastexport_resize_dataspec = resize_dataspec ;
options.fastexport_resize_method = "Lanczos";
options.fastexport_resize_width = MaxWidth->get_value_as_int ();
options.fastexport_resize_height = MaxHeight->get_value_as_int ();
FE_OPT_STORE_(options.fastexport_resize_method, "Lanczos");
FE_OPT_STORE_(options.fastexport_resize_width, MaxWidth->get_value_as_int ());
FE_OPT_STORE_(options.fastexport_resize_height, MaxHeight->get_value_as_int ());
FE_OPT_STORE_(options.fastexport_use_fast_pipeline, use_fast_pipeline->get_active());
#undef FE_OPT_STORE_
if (changed) {
Options::save();
}
}
void ExportPanel::LoadDefaultSettings()
@@ -327,6 +345,8 @@ void ExportPanel::LoadDefaultSettings()
MaxWidth->set_value(options.fastexport_resize_width);
MaxHeight->set_value(options.fastexport_resize_height);
use_fast_pipeline->set_active(options.fastexport_use_fast_pipeline);
}
void ExportPanel::LoadSettings()

View File

@@ -38,6 +38,7 @@ protected:
//Gtk::CheckButton* enabled;
Gtk::CheckButton* bypass_ALL;
Gtk::CheckButton* use_fast_pipeline;
Gtk::CheckButton* bypass_sharpenEdge;
Gtk::CheckButton* bypass_sharpenMicro;
Gtk::CheckButton* bypass_sharpening;

View File

@@ -1094,7 +1094,7 @@ void FileCatalog::developRequested (std::vector<FileBrowserEntry*> tbe, bool fas
// controlling time and resource consuming tasks
// and also those which effect is not pronounced after reducing the image size
// TODO!!! could expose selections below via preferences
if (fastmode && false) {
if (fastmode) {
if (options.fastexport_bypass_sharpening ) {
params.sharpening.enabled = false;
}
@@ -1183,11 +1183,11 @@ void FileCatalog::developRequested (std::vector<FileBrowserEntry*> tbe, bool fas
params.resize.appliesTo = options.fastexport_resize_appliesTo ;
params.resize.method = options.fastexport_resize_method ;
params.resize.dataspec = options.fastexport_resize_dataspec ;
params.resize.width = options.fastexport_resize_width ;
params.resize.height = options.fastexport_resize_height ;
params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ;
params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ;
}
rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode);
rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline);
int pw;
int ph = BatchQueue::calcMaxThumbnailHeight();

View File

@@ -480,6 +480,7 @@ void Options::setDefaults ()
fastexport_resize_dataspec = 3;
fastexport_resize_width = 900;
fastexport_resize_height = 900;
fastexport_use_fast_pipeline = false;
clutsDir = "./cluts";
@@ -1784,6 +1785,9 @@ int Options::readFromFile (Glib::ustring fname)
if (keyFile.has_key ("Fast Export", "fastexport_resize_height" )) {
fastexport_resize_height = keyFile.get_integer ("Fast Export", "fastexport_resize_height" );
}
if (keyFile.has_key ("Fast Export", "fastexport_use_fast_pipeline" )) {
fastexport_use_fast_pipeline = keyFile.get_integer ("Fast Export", "fastexport_use_fast_pipeline" );
}
}
if (keyFile.has_group ("Dialogs")) {
@@ -2142,6 +2146,7 @@ int Options::saveToFile (Glib::ustring fname)
keyFile.set_integer ("Fast Export", "fastexport_resize_dataspec", fastexport_resize_dataspec );
keyFile.set_integer ("Fast Export", "fastexport_resize_width", fastexport_resize_width );
keyFile.set_integer ("Fast Export", "fastexport_resize_height", fastexport_resize_height );
keyFile.set_integer ("Fast Export", "fastexport_use_fast_pipeline", fastexport_use_fast_pipeline );
keyFile.set_string ("Dialogs", "LastIccDir", lastIccDir);
keyFile.set_string ("Dialogs", "LastDarkframeDir", lastDarkframeDir);

View File

@@ -279,6 +279,7 @@ public:
int fastexport_resize_dataspec;
int fastexport_resize_width;
int fastexport_resize_height;
bool fastexport_use_fast_pipeline;
// Dialog settings
Glib::ustring lastIccDir;