diff --git a/CMakeLists.txt b/CMakeLists.txt index f7124c95..69f6f233 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ endif() # libconfig -set(LIBCONFIG_MINIMUM_VERSION_REQUIRED "1.5") +set(LIBCONFIG_MINIMUM_VERSION_REQUIRED "1.7") find_package(libconfig) if( LIBCONFIG_FOUND AND (LIBCONFIG_VERSION VERSION_GREATER ${LIBCONFIG_MINIMUM_VERSION_REQUIRED}) OR (LIBCONFIG_VERSION VERSION_EQUAL ${LIBCONFIG_MINIMUM_VERSION_REQUIRED})) message(STATUS "libconfig ${LIBCONFIG_VERSION} found") diff --git a/README.md b/README.md index 3910a362..4977ae62 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ OpenCV >= 4.2 TBB -libconfig >= 1.5 +libconfig >= 1.7 libtiff -libraw +libraw >= 0.20 (https://www.libraw.org) -libopenraw-0.3 +libopenraw-0.3 (https://libopenraw.freedesktop.org) cfitsio diff --git a/core/improc/c_smap_routine.cc b/core/improc/c_smap_routine.cc index 5e2af243..0631299f 100644 --- a/core/improc/c_smap_routine.cc +++ b/core/improc/c_smap_routine.cc @@ -19,38 +19,52 @@ c_smap_routine::ptr c_smap_routine::create(bool enabled) return ptr (new this_class(enabled)); } -c_smap_routine::ptr c_smap_routine::create(double minv, double scale, bool enabled) +c_smap_routine::ptr c_smap_routine::create(int lksize, int scale_size, double minv, bool enabled) { ptr obj(new this_class(enabled)); + obj->set_lksize(lksize); + obj->set_scale_size(scale_size); obj->set_minv(minv); - obj->set_scale(scale); return obj; } -void c_smap_routine::set_minv(double v) + +void c_smap_routine::set_lksize(int v) { - minv_ = v; + lksize_ = v; } -double c_smap_routine::minv() const +int c_smap_routine::lksize() const { - return minv_; + return lksize_; +} + + +void c_smap_routine::set_scale_size(int v) +{ + scale_size_ = v; } -void c_smap_routine::set_scale(double v) +int c_smap_routine::scale_size() const { - scale_ = v; + return scale_size_; } -double c_smap_routine::scale() const +void c_smap_routine::set_minv(double v) { - return scale_; + minv_ = v; } +double c_smap_routine::minv() const +{ + return minv_; +} + + bool c_smap_routine::process(cv::InputOutputArray image, cv::InputOutputArray mask) { cv::Mat1f smap; - compute_smap(image, smap, minv_, scale_); + compute_smap(image, smap, lksize_, scale_size_, minv_); image.move(smap); return true; } @@ -61,8 +75,9 @@ bool c_smap_routine::deserialize(c_config_setting settings) return false; } + settings.get("lksize", &lksize_); + settings.get("scale_size", &scale_size_); settings.get("minv", &minv_); - settings.get("scale", &scale_); return true; } @@ -73,8 +88,10 @@ bool c_smap_routine::serialize(c_config_setting settings) const return false; } + + settings.set("lksize", lksize_); + settings.set("scale_size", scale_size_); settings.set("minv", minv_); - settings.set("scale", scale_); return true; } diff --git a/core/improc/c_smap_routine.h b/core/improc/c_smap_routine.h index e4a11d08..563bbc7d 100644 --- a/core/improc/c_smap_routine.h +++ b/core/improc/c_smap_routine.h @@ -28,20 +28,24 @@ class c_smap_routine c_smap_routine(bool enabled = true); static ptr create(bool enabled = true); - static ptr create(double minv, double scale = 1.0 / 16, bool enabled = true); + static ptr create(int lksize, int scale_size, double minv, bool enabled = true); bool deserialize(c_config_setting settings) override; bool serialize(c_config_setting settings) const override; bool process(cv::InputOutputArray image, cv::InputOutputArray mask = cv::noArray()) override; - void set_minv(double v); - double minv() const; + void set_lksize(int ); + int lksize() const; + + void set_scale_size(int); + int scale_size() const; - void set_scale(double v); - double scale() const; + void set_minv(double); + double minv() const; protected: - double minv_ = 0; - double scale_ = 1.0/16; + int lksize_ = 7; + int scale_size_ = 6; + double minv_ = 1; }; diff --git a/core/io/c_raw_file.cc b/core/io/c_raw_file.cc index 4bf3a1b3..d74e9515 100644 --- a/core/io/c_raw_file.cc +++ b/core/io/c_raw_file.cc @@ -77,7 +77,7 @@ int c_raw_file_reader::raw2mat(cv::Mat & output_image) colorid_ = COLORID_UNKNOWN; - bpc_ = raw.imgdata.color.raw_bps; + bpc_ = 16; // fixme: raw.imgdata.color.raw_bps; black_level_ = raw.imgdata.color.black; if ( !output_image.empty() && !output_image.isContinuous() ) { diff --git a/core/pipeline/c_image_stacking_pipeline.cc b/core/pipeline/c_image_stacking_pipeline.cc index e3f79b43..2aa8facf 100644 --- a/core/pipeline/c_image_stacking_pipeline.cc +++ b/core/pipeline/c_image_stacking_pipeline.cc @@ -973,6 +973,7 @@ bool c_image_stacking_pipeline::initialize(const c_image_stacking_options::ptr & output_directory_.clear(); missing_pixel_mask_.release(); + reference_weights_.release(); external_master_frame_ = false; master_frame_index_ = -1; @@ -1251,15 +1252,32 @@ bool c_image_stacking_pipeline::actual_run() reference_mask.depth(), reference_mask.channels()); + + if ( weights_required() ) { + compute_weights(reference_frame, reference_mask, reference_weights_); + } + if ( !(frame_registration_ = options_->create_frame_registration()) ) { CF_FATAL("options_->create_frame_registration() fails"); return false; } - if ( options_->upscale_options().need_upscale_before_align() ) { + if( upscale_required(frame_upscale_before_align) ) { + upscale_image(options_->upscale_options().upscale_option, reference_frame, reference_mask, reference_frame, reference_mask); + + if( !reference_weights_.empty() ) { + upscale_image(options_->upscale_options().upscale_option, + reference_weights_, cv::noArray(), + reference_weights_, cv::noArray()); + + CF_DEBUG("Reference weights: %dx%d depth=%d channels=%d", + reference_weights_.cols, reference_weights_.rows, + reference_weights_.depth(), + reference_weights_.channels()); + } } if ( output_options.debug_frame_registration ) { @@ -1273,6 +1291,19 @@ bool c_image_stacking_pipeline::actual_run() return false; } + + if( upscale_required(frame_upscale_after_align) ) { + + upscale_image(options_->upscale_options().upscale_option, + reference_weights_, cv::noArray(), + reference_weights_, cv::noArray()); + + CF_DEBUG("Reference weights: %dx%d depth=%d channels=%d", + reference_weights_.cols, reference_weights_.rows, + reference_weights_.depth(), + reference_weights_.channels()); + } + if ( output_options.debug_frame_registration && frame_registration_->enable_eccflow() ) { const c_ecch_flow & eccflow = @@ -1326,9 +1357,18 @@ bool c_image_stacking_pipeline::actual_run() set_status_msg("RUNNING ..."); - master_frame_generation_ = false; - if ( !(fOk = process_input_sequence(input_sequence_, 0, input_sequence_->size())) ) { + + const int start_pos = + std::max(input_options.start_frame_index, 0); + + const int end_pos = + input_options.max_input_frames < 1 ? + input_sequence_->size() : + std::min(input_sequence_->size(), + input_options.start_frame_index + input_options.max_input_frames); + + if ( !(fOk = process_input_sequence(input_sequence_, start_pos, end_pos)) ) { CF_ERROR("process_input_sequence() fails"); return false; } @@ -1565,6 +1605,7 @@ bool c_image_stacking_pipeline::create_reference_frame(const c_input_sequence::p const c_master_frame_options & master_options = options_->master_frame_options(); + master_frame_generation_ = true; if ( !input_sequence->seek(master_frame_index) ) { CF_ERROR("ERROR: input_sequence->seek(master_frame_index=%d) fails", master_frame_index); @@ -1659,6 +1700,10 @@ bool c_image_stacking_pipeline::create_reference_frame(const c_input_sequence::p return false; } + if ( weights_required() ) { + compute_weights(reference_frame, reference_mask, reference_weights_); + } + if ( true ) { lock_guard lock(accumulator_lock_); @@ -1680,7 +1725,6 @@ bool c_image_stacking_pipeline::create_reference_frame(const c_input_sequence::p const int startpos = std::max(0, master_frame_index - max_frames_to_stack / 2); const int endpos = startpos + max_frames_to_stack; - master_frame_generation_ = true; if ( !process_input_sequence(input_sequence, startpos, endpos) ) { CF_ERROR("process_input_sequence() fails"); return false; @@ -1761,41 +1805,7 @@ bool c_image_stacking_pipeline::create_reference_frame(const c_input_sequence::p } } } -// if ( master_options.master_sharpen_factor > 0 && frame_accumulation_->accumulated_frames() > 1 ) { -// -// if ( options_->output_options().dump_reference_data_for_debug ) { -// -// save_image(reference_frame, -// ssprintf("%s/%s-initial_reference_frame.tiff", -// output_directory_.c_str(), -// options_->cname())); -// } -// -// double fftscale = master_options.master_sharpen_factor * CV_PI * sqrt(frame_accumulation_->accumulated_frames()); -// CF_DEBUG("fftscale = %g accumulated_frames=%d", fftscale, frame_accumulation_->accumulated_frames()); -// -// fftSharpenR2(reference_frame, reference_frame, fftscale); -// -// -// //cv::max(reference_frame, 0, reference_frame); -// -// static const thread_local cv::Mat G = -// cv::getGaussianKernel(3, 0.5, CV_32F); -// -// cv::sepFilter2D(reference_frame, reference_frame, -1, G, G); -// -// -// if ( options_->output_options().dump_reference_data_for_debug ) { -// if ( !master_options.save_master_frame ) { -// -// save_image(reference_frame, ssprintf("%s/%s-reference_frame_after_sharpenning.tiff", -// output_directory_.c_str(), -// options_->cname())); -// -// } -// } -// -// } + } if ( canceled() ) { @@ -1812,6 +1822,7 @@ bool c_image_stacking_pipeline::create_reference_frame(const c_input_sequence::p frame_registration_.reset(); } + master_frame_generation_ = false; return true; } @@ -1820,6 +1831,7 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p { cv::Mat current_frame, current_mask; cv::Mat2f current_remap; + cv::Mat1f current_weights; c_video_writer output_preprocessed_frames_writer; c_video_writer output_aligned_frames_writer; @@ -1929,6 +1941,13 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p } } + if( weights_required() ) { + compute_weights(current_frame, current_mask, current_weights); + if ( canceled() ) { + break; + } + } + if ( upscale_required(frame_upscale_before_align) ) { upscale_image(upscale_options.upscale_option, @@ -1938,6 +1957,16 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p if ( canceled() ) { break; } + + if( !current_weights.empty() ) { + upscale_image(options_->upscale_options().upscale_option, + current_weights, cv::noArray(), + current_weights, cv::noArray()); + } + + if ( canceled() ) { + break; + } } @@ -1988,6 +2017,9 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p } + if( canceled() ) { + break; + } } @@ -1996,6 +2028,10 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p continue; } + if( canceled() ) { + break; + } + if ( flow_accumulation_ ) { const cv::Mat2f turbulence = compute_turbulent_flow( @@ -2011,6 +2047,10 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p flow_accumulation_->add(turbulence/*, current_mask_*/); } + + if( canceled() ) { + break; + } } if ( !upscale_required(frame_upscale_after_align) ) { @@ -2031,6 +2071,24 @@ bool c_image_stacking_pipeline::process_input_sequence(const c_input_sequence::p master_frame_generation_ ? ECC_BORDER_REFLECT101 : registration_options.base_options.border_mode, registration_options.base_options.border_value); + + if( !current_weights.empty() ) { + + frame_registration_->custom_remap(current_remap, + current_weights, current_weights, + cv::noArray(), cv::noArray(), + registration_options.base_options.interpolation, + ECC_BORDER_CONSTANT); + + cv::divide(current_weights, reference_weights_, + current_weights); + + cv::multiply(current_mask, current_weights, current_weights, + current_mask.depth() == CV_8U ? 1./255 : 1, + CV_32F); + + current_mask = current_weights; + } } @@ -2412,9 +2470,21 @@ void c_image_stacking_pipeline::upscale_image(enum frame_upscale_option scale, } -void c_image_stacking_pipeline::compute_weights(const cv::Mat & src, const cv::Mat & srcmask, cv::Mat & dst) +bool c_image_stacking_pipeline::weights_required() const +{ + return options_->accumulation_options().accumulation_method == frame_accumulation_weighted_average && + options_->accumulation_options().lksize > 0; +} + +void c_image_stacking_pipeline::compute_weights(const cv::Mat & src, const cv::Mat & srcmask, cv::Mat & dst) const { - compute_smap(src, dst, 0.01, 0); + const c_frame_accumulation_options & acc_options = + options_->accumulation_options(); + + compute_smap(src, dst, + acc_options.lksize, + acc_options.scale_size, + acc_options.minv); } void c_image_stacking_pipeline::compute_relative_weights(const cv::Mat & wc, const cv::Mat & mc, const cv::Mat & wref, cv::Mat & wrel) diff --git a/core/pipeline/c_image_stacking_pipeline.h b/core/pipeline/c_image_stacking_pipeline.h index 3be781bc..10a6a444 100644 --- a/core/pipeline/c_image_stacking_pipeline.h +++ b/core/pipeline/c_image_stacking_pipeline.h @@ -119,9 +119,11 @@ struct c_input_options { enum anscombe_method anscombe = anscombe_none; double hot_pixels_variation_threshold = 6; + int start_frame_index = 0; + int max_input_frames = 0; + bool serialize(c_config_setting settings) const; bool deserialize(c_config_setting settings); - }; struct c_roi_selection_options { @@ -138,7 +140,7 @@ struct c_master_frame_options { int master_frame_index = 0; // relative, in master source bool apply_input_frame_processor = true; bool generate_master_frame = true; - int max_input_frames_to_generate_master_frame = 500; + int max_input_frames_to_generate_master_frame = 2500; int eccflow_scale = 0; double master_sharpen_factor = 0.5; double accumulated_sharpen_factor = 1; @@ -183,9 +185,14 @@ struct c_frame_upscale_options { }; struct c_frame_accumulation_options { + enum frame_accumulation_method accumulation_method = frame_accumulation_weighted_average; + int lksize = 0; + int scale_size = 6; + double minv = 1e-5; + bool serialize(c_config_setting settings) const; bool deserialize(c_config_setting settings); }; @@ -450,7 +457,8 @@ class c_image_stacking_pipeline cv::InputArray srcmap, cv::OutputArray dstmap); - static void compute_weights(const cv::Mat & src, const cv::Mat & srcmask, cv::Mat & dst); + bool weights_required() const; + void compute_weights(const cv::Mat & src, const cv::Mat & srcmask, cv::Mat & dst) const; static void compute_relative_weights(const cv::Mat & wc, const cv::Mat & mc, const cv::Mat & wref, cv::Mat & wrel); static double compute_image_noise(const cv::Mat & image, const cv::Mat & mask, color_channel_type channel); @@ -481,6 +489,7 @@ class c_image_stacking_pipeline int processed_frames_ = 0; cv::Mat missing_pixel_mask_; + cv::Mat1f reference_weights_; std::string statusmsg_; mutable std::mutex status_lock_; diff --git a/core/pipeline/c_image_stacking_pipeline_load_save.cc b/core/pipeline/c_image_stacking_pipeline_load_save.cc index 152c4319..536e6ed8 100644 --- a/core/pipeline/c_image_stacking_pipeline_load_save.cc +++ b/core/pipeline/c_image_stacking_pipeline_load_save.cc @@ -316,6 +316,9 @@ bool c_input_options::serialize(c_config_setting settings) const settings.set("bad_pixels_variation_threshold", hot_pixels_variation_threshold); settings.set("enable_color_maxtrix", enable_color_maxtrix ); settings.set("anscombe", anscombe); + settings.set("start_frame_index", start_frame_index); + settings.set("max_input_frames", max_input_frames); + if ( input_frame_processor ) { settings.set("input_frame_processor", input_frame_processor->name()); @@ -339,6 +342,8 @@ bool c_input_options::deserialize(c_config_setting settings) settings.get("bad_pixels_variation_threshold", &hot_pixels_variation_threshold); settings.get("enable_color_maxtrix", &enable_color_maxtrix ); settings.get("anscombe", &anscombe); + settings.get("start_frame_index", &start_frame_index); + settings.get("max_input_frames", &max_input_frames); if ( settings.get("input_frame_processor", &s) && !s.empty() ) { input_frame_processor = c_image_processor_collection::default_instance()->get(s); @@ -432,6 +437,10 @@ bool c_master_frame_options::deserialize(c_config_setting settings) bool c_frame_accumulation_options::serialize(c_config_setting settings) const { save_settings(settings, "accumulation_method", accumulation_method ); + save_settings(settings, "lksize", lksize ); + save_settings(settings, "scale_size", scale_size); + save_settings(settings, "minv", minv); + return true; } @@ -442,6 +451,9 @@ bool c_frame_accumulation_options::deserialize(c_config_setting settings) } load_settings(settings, "accumulation_method", &accumulation_method ); + load_settings(settings, "lksize", &lksize ); + load_settings(settings, "scale_size", &scale_size); + load_settings(settings, "minv", &minv); return true; } diff --git a/core/proc/smap.cc b/core/proc/smap.cc index 0cc20a41..1ab3278c 100644 --- a/core/proc/smap.cc +++ b/core/proc/smap.cc @@ -7,9 +7,76 @@ #include "smap.h" #include +#include +#include +#if 1 +bool compute_smap(cv::InputArray src, cv::Mat & dst, + int lksize, int scale_size, double minv) +{ + cv::Mat gs; + //double noise; + double mscale = 1.0; + switch ( src.depth() ) { + case CV_8U : + case CV_8S : + mscale = 1. / UINT8_MAX; + break; + case CV_16U : + case CV_16S : + mscale = 1. / UINT16_MAX; + break; + case CV_32S : + mscale = 1. / UINT32_MAX; + break; + case CV_32F : + case CV_64F : + break; + } + + if ( src.channels() == 1 ) { + src.getMat().convertTo(gs, CV_32F, mscale); + } + else { + cv::cvtColor(src, gs, cv::COLOR_BGR2GRAY); + gs.convertTo(gs, CV_32F, mscale); + } + + + if ( lksize < 1 ) { + lksize = 7; + } + + if ( 1 ) { + cv::Laplacian(gs, gs, CV_32F, lksize); + cv::multiply(gs, gs, gs); + } + else { + cv::Mat gx, gy; + cv::pyrDown(gs, gs); + ecc_differentiate(gs, gx, gy, CV_32F); + cv::magnitude(gx, gy, gs); + cv::pyrUp(gs, gs, src.size()); + } + + if ( scale_size > 1 ) { + ecc_downscale(gs, gs, scale_size, cv::BORDER_REPLICATE); + ecc_upscale(gs, src.size()); + } + + if ( minv > 0 ) { + cv::add(gs, minv, dst); + } + else { + dst = std::move(gs); + } + + return true; +} + +#else bool compute_smap(cv::InputArray src, cv::Mat & dst, double minv, double scale) { @@ -76,3 +143,5 @@ bool compute_smap(cv::InputArray src, cv::Mat & dst, return true; } +#endif + diff --git a/core/proc/smap.h b/core/proc/smap.h index 528f0bf3..fd150f1a 100644 --- a/core/proc/smap.h +++ b/core/proc/smap.h @@ -12,7 +12,7 @@ #include bool compute_smap(cv::InputArray src, cv::Mat & dst, - double minv = -1, double scale = 1./16); + int lksize, int scale_size, double minv); #endif /* __smap_h__ */ diff --git a/core/registration/c_frame_registration.h b/core/registration/c_frame_registration.h index dac93dc6..cf704dd7 100644 --- a/core/registration/c_frame_registration.h +++ b/core/registration/c_frame_registration.h @@ -42,7 +42,7 @@ struct c_frame_registration_base_options { enum ECC_BORDER_MODE border_mode = ECC_BORDER_REFLECT101; cv::Scalar border_value = cv::Scalar(0, 0, 0); - double feature_scale = 1.; + double feature_scale = 0.5; bool enable_ecc = true; bool enable_eccflow = false; diff --git a/gui/qimproc/QSmapSettings.cc b/gui/qimproc/QSmapSettings.cc index 3d95369f..42565973 100644 --- a/gui/qimproc/QSmapSettings.cc +++ b/gui/qimproc/QSmapSettings.cc @@ -12,13 +12,18 @@ const QSmapSettings::ClassFactory QSmapSettings::classFactory; QSmapSettings::QSmapSettings(const c_smap_routine::ptr & routine, QWidget * parent) : Base(&classFactory, routine, parent) { + lksize_ctl = add_numeric_box("lksize:", + &c_smap_routine::lksize, + &c_smap_routine::set_lksize); + + scale_size_ctl = add_numeric_box("Scale:", + &c_smap_routine::scale_size, + &c_smap_routine::set_scale_size); + minv_ctl = add_numeric_box("Minv:", &c_smap_routine::minv, &c_smap_routine::set_minv); - scale_ctl = add_numeric_box("Scale:", - &c_smap_routine::scale, - &c_smap_routine::set_scale); updateControls(); } @@ -29,8 +34,9 @@ void QSmapSettings::onupdatecontrols() setEnabled(false); } else { + lksize_ctl->setValue(routine_->lksize()); + scale_size_ctl->setValue(routine_->scale_size()); minv_ctl->setValue(routine_->minv()); - scale_ctl->setValue(routine_->scale()); setEnabled(true); } Base::onupdatecontrols(); diff --git a/gui/qimproc/QSmapSettings.h b/gui/qimproc/QSmapSettings.h index 3b201f2b..b6eb5f4c 100644 --- a/gui/qimproc/QSmapSettings.h +++ b/gui/qimproc/QSmapSettings.h @@ -36,8 +36,9 @@ class QSmapSettings void onupdatecontrols() override; protected: + QNumberEditBox * lksize_ctl = Q_NULLPTR; + QNumberEditBox * scale_size_ctl = Q_NULLPTR; QNumberEditBox * minv_ctl = Q_NULLPTR; - QNumberEditBox * scale_ctl = Q_NULLPTR; }; diff --git a/gui/qstackingoptions/QFrameAccumulationOptions.cc b/gui/qstackingoptions/QFrameAccumulationOptions.cc index c159ea87..719f0bf0 100644 --- a/gui/qstackingoptions/QFrameAccumulationOptions.cc +++ b/gui/qstackingoptions/QFrameAccumulationOptions.cc @@ -47,6 +47,33 @@ QFrameAccumulationOptions::QFrameAccumulationOptions(QWidget * parent) : } }); + lksize_ctl = + add_numeric_box("lksize:", + [this](int v) { + if ( options_ && v != options_->lksize ) { + options_->lksize = v; + emit parameterChanged(); + } + }); + + scale_size_ctl = + add_numeric_box("scale:", + [this](int v) { + if ( options_ && v != options_->scale_size ) { + options_->scale_size = v; + emit parameterChanged(); + } + }); + + minv_ctl = + add_numeric_box("miv:", + [this](double v) { + if ( options_ && v != options_->minv ) { + options_->minv = v; + emit parameterChanged(); + } + }); + applyToAll_ctl = new QToolButton(this); applyToAll_ctl->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); applyToAll_ctl->setIconSize(QSize(16,16)); @@ -85,6 +112,9 @@ void QFrameAccumulationOptions::onupdatecontrols() else { accumulation_method_ctl->setCurrentItem(options_->accumulation_method); + lksize_ctl->setValue(options_->lksize); + scale_size_ctl->setValue(options_->scale_size); + minv_ctl->setValue(options_->minv); setEnabled(true); } diff --git a/gui/qstackingoptions/QFrameAccumulationOptions.h b/gui/qstackingoptions/QFrameAccumulationOptions.h index 8ea1e4d5..5b71e0ad 100644 --- a/gui/qstackingoptions/QFrameAccumulationOptions.h +++ b/gui/qstackingoptions/QFrameAccumulationOptions.h @@ -56,6 +56,9 @@ class QFrameAccumulationOptions : protected: c_frame_accumulation_options * options_ = Q_NULLPTR; QFrameAccumulationMethodCombo * accumulation_method_ctl = Q_NULLPTR; + QNumberEditBox * lksize_ctl = Q_NULLPTR; + QNumberEditBox * scale_size_ctl = Q_NULLPTR; + QNumberEditBox * minv_ctl = Q_NULLPTR; QToolButton * applyToAll_ctl = Q_NULLPTR; }; diff --git a/gui/qstackingoptions/QImageStackingInputOptions.cc b/gui/qstackingoptions/QImageStackingInputOptions.cc index 0c6e05c3..96911733 100644 --- a/gui/qstackingoptions/QImageStackingInputOptions.cc +++ b/gui/qstackingoptions/QImageStackingInputOptions.cc @@ -24,17 +24,36 @@ static QIcon getIcon(const QString & name) QImageStackingInputOptions::QImageStackingInputOptions(QWidget * parent) : Base("QImageStackingInputOptions", parent) { + start_frame_index_ctl = + add_numeric_box("Start frame index:", + [this](int v) { + if ( options_ && options_->start_frame_index != v ) { + options_->start_frame_index = v; + emit parameterChanged(); + } + }); - enable_remove_bad_pixels_ctl = add_checkbox("Detect Bad Pixels", - [this](int state) { - if ( options_ ) { - bool checked = state == Qt::Checked; - if ( checked != options_->filter_hot_pixels ) { - options_->filter_hot_pixels = checked; - emit parameterChanged(); - } - } - }); + + max_input_frames_ctl = + add_numeric_box("Max frames:", + [this](int v) { + if ( options_ && options_->max_input_frames != v ) { + options_->max_input_frames = v; + emit parameterChanged(); + } + }); + + enable_remove_bad_pixels_ctl = + add_checkbox("Detect Bad Pixels", + [this](int state) { + if ( options_ ) { + bool checked = state == Qt::Checked; + if ( checked != options_->filter_hot_pixels ) { + options_->filter_hot_pixels = checked; + emit parameterChanged(); + } + } + }); bad_pixels_variation_threshold_ctl = add_numeric_box("Bad Pixels Variation Threshold", @@ -46,46 +65,51 @@ QImageStackingInputOptions::QImageStackingInputOptions(QWidget * parent) }); - inpaint_missing_pixels_ctl = add_checkbox("Inpaint missing pixels with feasible values", - [this](int state) { - if ( options_ ) { - bool checked = state == Qt::Checked; - if ( checked != options_->inpaint_missing_pixels ) { - options_->inpaint_missing_pixels = checked; - emit parameterChanged(); - } - } - });; + inpaint_missing_pixels_ctl = + add_checkbox("Inpaint missing pixels with feasible values", + [this](int state) { + if ( options_ ) { + bool checked = state == Qt::Checked; + if ( checked != options_->inpaint_missing_pixels ) { + options_->inpaint_missing_pixels = checked; + emit parameterChanged(); + } + } + }); - enable_color_maxtrix_ctl = add_checkbox("Apply color matrix if available", - [this](int state) { - if ( options_ ) { - bool checked = state == Qt::Checked; - if ( checked != options_->enable_color_maxtrix ) { - options_->enable_color_maxtrix = checked; - emit parameterChanged(); - } - } - }); + enable_color_maxtrix_ctl = + add_checkbox("Apply color matrix if available", + [this](int state) { + if ( options_ ) { + bool checked = state == Qt::Checked; + if ( checked != options_->enable_color_maxtrix ) { + options_->enable_color_maxtrix = checked; + emit parameterChanged(); + } + } + }); - anscombe_ctl = add_enum_combobox( - "Anscombe Transform:", - [this](anscombe_method v) { - if ( options_ && v != options_->anscombe ) { - options_->anscombe = v; - emit parameterChanged(); - } - }); + anscombe_ctl = + add_enum_combobox( + "Anscombe Transform:", + [this](anscombe_method v) { + if ( options_ && v != options_->anscombe ) { + options_->anscombe = v; + emit parameterChanged(); + } + }); - processor_selector_ctl = add_combobox( - "Process input frames:", - [this](int currentIndex) { - if ( options_ ) { - options_->input_frame_processor = + + processor_selector_ctl = + add_combobox( + "Process input frames:", + [this](int currentIndex) { + if ( options_ ) { + options_->input_frame_processor = processor_selector_ctl->processor(currentIndex); - }}); + }}); form->addRow(missing_pixel_mask_filename_ctl = @@ -93,6 +117,7 @@ QImageStackingInputOptions::QImageStackingInputOptions(QWidget * parent) QFileDialog::ExistingFile, this)); + connect(missing_pixel_mask_filename_ctl, &QBrowsePathCombo::pathChanged, [this] () { if ( options_ && !updatingControls() ) { @@ -102,18 +127,18 @@ QImageStackingInputOptions::QImageStackingInputOptions(QWidget * parent) } }); - missing_pixels_marked_black_ctl = add_checkbox("Missing pixels marked as black", - [this](int state) { - if ( options_ ) { - bool checked = state == Qt::Checked; - if ( checked != options_->missing_pixels_marked_black ) { - options_->missing_pixels_marked_black = checked; - emit parameterChanged(); - } - } - });; - + missing_pixels_marked_black_ctl = + add_checkbox("Missing pixels marked as black", + [this](int state) { + if ( options_ ) { + bool checked = state == Qt::Checked; + if ( checked != options_->missing_pixels_marked_black ) { + options_->missing_pixels_marked_black = checked; + emit parameterChanged(); + } + } + }); applyToAll_ctl = new QToolButton(this); @@ -130,7 +155,6 @@ QImageStackingInputOptions::QImageStackingInputOptions(QWidget * parent) }); form->addRow(applyToAll_ctl); - } void QImageStackingInputOptions::set_input_options(c_input_options * options) @@ -160,6 +184,9 @@ void QImageStackingInputOptions::onupdatecontrols() missing_pixels_marked_black_ctl->setChecked(options_->missing_pixels_marked_black); inpaint_missing_pixels_ctl->setChecked(options_->inpaint_missing_pixels); + start_frame_index_ctl->setValue(options_->start_frame_index); + max_input_frames_ctl->setValue(options_->max_input_frames); + if ( !processor_selector_ctl->setCurrentProcessor(options_->input_frame_processor) ) { options_->input_frame_processor.reset(); } diff --git a/gui/qstackingoptions/QImageStackingInputOptions.h b/gui/qstackingoptions/QImageStackingInputOptions.h index 636630dc..663468a2 100644 --- a/gui/qstackingoptions/QImageStackingInputOptions.h +++ b/gui/qstackingoptions/QImageStackingInputOptions.h @@ -62,7 +62,10 @@ class QImageStackingInputOptions : QBrowsePathCombo * missing_pixel_mask_filename_ctl = Q_NULLPTR; QCheckBox * missing_pixels_marked_black_ctl = Q_NULLPTR; - QCheckBox * inpaint_missing_pixels_ctl = Q_NULLPTR; + QCheckBox * inpaint_missing_pixels_ctl = Q_NULLPTR; + + QNumberEditBox * start_frame_index_ctl = Q_NULLPTR; + QNumberEditBox * max_input_frames_ctl = Q_NULLPTR; QImageProcessorSelectionCombo * processor_selector_ctl = Q_NULLPTR;