17#ifndef __registration_linear_h__
18#define __registration_linear_h__
48 namespace Registration
75 std::string
info (
const bool& do_reorientation =
true) {
85 st +=
", optimiser: ";
121 stages[0].scale_factor = 0.25;
123 stages[1].scale_factor = 0.5;
125 stages[2].scale_factor = 1.0;
131 stages.resize (scalefactor.size());
132 for (
size_t level = 0; level < scalefactor.size(); ++level) {
133 if (scalefactor[level] <= 0 || scalefactor[level] > 1.0)
134 throw Exception (
"the linear registration scale factor for each multi-resolution level must be between 0 and 1");
135 stages[level].scale_factor = scalefactor[level];
141 for (
auto & stage :
stages)
142 stage.optimiser_default = type;
147 for (
auto & stage :
stages)
148 stage.optimiser_first = type;
153 for (
auto & stage :
stages)
154 stage.optimiser_last = type;
158 for (
size_t i = 0; i < it.size (); ++i)
160 throw Exception (
"the number of stage iterations must be positive");
161 if (it.size() ==
stages.size()) {
162 for (
size_t i = 0; i <
stages.size (); ++i)
163 stages[i].stage_iterations = it[i];
164 }
else if (it.size() == 1) {
165 for (
size_t i = 0; i <
stages.size (); ++i)
166 stages[i].stage_iterations = it[0];
168 throw Exception (
"the number of stage iterations must be defined for all stages (1 or " +
str(
stages.size())+
")");
169 for (
auto & stage :
stages) {
170 stage.optimisers.resize(stage.stage_iterations, stage.optimiser_default);
171 stage.optimisers[0] = stage.optimiser_first;
172 if (stage.stage_iterations > 1)
173 stage.optimisers[stage.stage_iterations - 1] = stage.optimiser_last;
178 if (maxiter.size() ==
stages.size()) {
179 for (
size_t i = 0; i <
stages.size (); ++i)
180 stages[i].gd_max_iter = maxiter[i];
181 }
else if (maxiter.size() == 1) {
182 for (
size_t i = 0; i <
stages.size (); ++i)
183 stages[i].gd_max_iter = maxiter[0];
185 throw Exception (
"the number of gradient descent iterations must be defined for all stages (1 or " +
str(
stages.size())+
")");
189 void set_directions (Eigen::MatrixXd& dir) {
195 for (
size_t i = 0; i < lmax.size (); ++i)
197 throw Exception (
"the input lmax must be even");
198 if (lmax.size() ==
stages.size()) {
199 for (
size_t i = 0; i <
stages.size (); ++i)
200 stages[i].fod_lmax = lmax[i];
201 }
else if (lmax.size() == 1) {
202 for (
size_t i = 0; i <
stages.size (); ++i)
203 stages[i].fod_lmax = lmax[0];
205 throw Exception (
"the lmax must be defined for all stages (1 or " +
str(
stages.size())+
")");
214 for (
size_t d = 0; d < loop_density_.size(); ++d)
215 if (loop_density_[d] < 0.0 or loop_density_[d] > 1.0 )
216 throw Exception (
"loop density must be between 0.0 and 1.0");
217 if (loop_density_.size() ==
stages.size()) {
218 for (
size_t i = 0; i <
stages.size (); ++i)
219 stages[i].loop_density = loop_density_[i];
220 }
else if (loop_density_.size() == 1) {
221 for (
size_t i = 0; i <
stages.size (); ++i)
222 stages[i].loop_density = loop_density_[0];
224 throw Exception (
"the lmax must be defined for all stages (1 or " +
str(
stages.size())+
")");
227 void set_diagnostics_image_prefix (
const std::basic_string<char>& diagnostics_image_prefix) {
228 for (
size_t level = 0; level <
stages.size(); ++level) {
229 auto & stage =
stages[level];
230 for (
size_t iter = 1; iter <= stage.stage_iterations; ++iter) {
231 std::ostringstream oss;
232 oss << diagnostics_image_prefix <<
"_stage-" << level + 1 <<
"_iter-" << iter <<
".mif";
234 throw Exception (
"diagnostics image file \"" + oss.str() +
"\" already exists (use -force option to force overwrite)");
235 stage.diagnostics_images.push_back(oss.str());
241 for (
size_t d = 0; d < extent.size(); ++d) {
243 throw Exception (
"the neighborhood kernel extent must be at least 1 voxel");
256 void use_robust_estimate (
bool use) {
261 void set_grad_tolerance (
const float& tolerance) {
265 void set_log_stream (std::streambuf* stream) {
269 ssize_t get_lmax () {
272 lmax = std::max(s.fod_lmax, lmax);
276 Header get_midway_header () {
280 template <
class MetricType,
class TransformType,
class Im1ImageType,
class Im2ImageType>
283 TransformType& transform,
284 Im1ImageType& im1_image,
285 Im2ImageType& im2_image) {
287 run_masked<MetricType, TransformType, Im1ImageType, Im2ImageType, BogusMaskType, BogusMaskType >
288 (metric, transform, im1_image, im2_image,
nullptr,
nullptr);
291 template <
class MetricType,
class TransformType,
class Im1ImageType,
class Im2ImageType,
class Im2MaskType>
294 TransformType& transform,
295 Im1ImageType& im1_image,
296 Im2ImageType& im2_image,
297 std::unique_ptr<Im2MaskType>& im2_mask) {
299 run_masked<MetricType, TransformType, Im1ImageType, Im2ImageType, BogusMaskType, Im2MaskType >
300 (metric, transform, im1_image, im2_image,
nullptr, im2_mask);
304 template <
class MetricType,
class TransformType,
class Im1ImageType,
class Im2ImageType,
class Im1MaskType>
307 TransformType& transform,
308 Im1ImageType& im1_image,
309 Im2ImageType& im2_image,
310 std::unique_ptr<Im1MaskType>& im1_mask) {
312 run_masked<MetricType, TransformType, Im1ImageType, Im2ImageType, Im1MaskType, BogusMaskType >
313 (metric, transform, im1_image, im2_image, im1_mask,
nullptr);
316 template <
class MetricType,
class TransformType,
class Im1ImageType,
class Im2ImageType,
class Im1MaskType,
class Im2MaskType>
319 TransformType& transform,
320 Im1ImageType& im1_image,
321 Im2ImageType& im2_image,
322 Im1MaskType& im1_mask,
323 Im2MaskType& im2_mask) {
328 throw Exception (
"the lmax needs to be defined for each registration stage");
345 INFO (
"Transformation before registration:");
346 INFO (transform.info());
348 INFO (
"Linear registration stage parameters:");
349 for (
auto & stage :
stages) {
366 using MidwayImageType =
Header;
367 using ProcessedImageType = Im1ImageType;
370#ifdef REGISTRATION_CUBIC_INTERP
386 Im1ImageInterpolatorType,
387 Im2ImageInterpolatorType,
391 ProcessedImageInterpolatorType,
395 Eigen::Matrix<typename TransformType::ParameterType, Eigen::Dynamic, 1> optimiser_weights = transform.get_optimiser_weights();
400 for (
size_t istage = 0; istage <
stages.size(); istage++) {
401 auto& stage =
stages[istage];
408 mc.lower_lmax (stage.fod_lmax);
415 DEBUG (
"before downsampling:");
419 INFO (
"smoothing image 1");
421 INFO (
"smoothing image 2");
424 DEBUG (
"after downsampling:");
430 midway_resize_filter.set_scale_factor (stage.scale_factor);
431 Header midway_resized (midway_resize_filter);
433 ParamType parameters (transform, im1_smoothed, im2_smoothed, midway_resized, im1_mask, im2_mask);
434 parameters.loop_density = stage.loop_density;
448 for (
size_t i = 0; i<3; ++i)
450 parameters.set_control_points_extent(ext);
454 Eigen::Vector3d spacing (
458 Eigen::Vector3d coherence(spacing);
459 Eigen::Vector3d stop(spacing);
464 coherence *= reg_coherence_len * 1.0 / (2.0 * stage.scale_factor);
469 stop.array() *= reg_stop_len;
470 DEBUG (
"coherence length: " +
str(coherence));
471 DEBUG (
"stop length: " +
str(stop));
472 transform.get_gradient_descent_updator()->set_control_points (parameters.control_points, coherence, stop, spacing);
475 Eigen::VectorXd slope_threshold = Eigen::VectorXd::Ones (12);
481 DEBUG (
"convergence slope threshold: " +
str(slope_threshold[0]));
487 if ( (alpha < 0.0f ) || (alpha > 1.0f) )
488 throw Exception (
"config file option RegGdConvergenceDataSmooth has to be in the range: [0...1]");
494 if ( (beta < 0.0f ) || (beta > 1.0f) )
495 throw Exception (
"config file option RegGdConvergenceSlopeSmooth has to be in the range: [0...1]");
501 transform.get_gradient_descent_updator()->set_convergence_check (slope_threshold, alpha, beta, buffer_len, min_iter);
507 INFO (
"registration stage running...");
508 for (
auto stage_iter = 1U; stage_iter <= stage.stage_iterations; ++stage_iter) {
511 optim (evaluate, *transform.get_gradient_descent_updator());
513 optim.precondition (optimiser_weights);
515 parameters.optimiser_update (optim, evaluate.overlap());
516 INFO (
" iteration: "+
str(stage_iter)+
"/"+
str(stage.stage_iterations)+
" GD iterations: "+
517 str(optim.function_evaluations())+
" cost: "+
str(optim.value())+
" overlap: "+
str(evaluate.overlap()));
518 }
else if (stage.gd_max_iter > 0) {
520 optim (evaluate, *transform.get_gradient_descent_updator());
522 optim.precondition (optimiser_weights);
524 parameters.optimiser_update (optim, evaluate.overlap());
525 INFO (
" iteration: "+
str(stage_iter)+
"/"+
str(stage.stage_iterations)+
" GD iterations: "+
526 str(optim.function_evaluations())+
" cost: "+
str(optim.value())+
" overlap: "+
str(evaluate.overlap()));
537 if (stage.diagnostics_images.size()) {
538 CONSOLE(
" creating diagnostics image: " + stage.diagnostics_images[stage_iter - 1]);
539 parameters.make_diagnostics_image (stage.diagnostics_images[stage_iter - 1],
File::Config::get_bool (
"RegLinregDiagnosticsImageMasked",
false));
545 INFO(
"linear registration done");
546 INFO (transform.info());
a class to hold a named list of Option's
static bool get_bool(const std::string &key, bool default_value)
static float get_float(const std::string &key, float default_value)
This class provides access to the voxel intensities of an Image, using nearest-neighbour interpolatio...
Computes the minimum of a function using a Barzilai Borwein gradient descent approach....
Computes the minimum of a function using a gradient descent approach.
default_type grad_tolerance
Transform::Init::InitType init_translation_type
Eigen::MatrixXd aPSF_directions
vector< MultiContrastSetting > contrasts
Header midway_image_header
vector< StageSetting > stages
const bool analyse_descent
vector< MultiContrastSetting > stage_contrasts
default_type step_tolerance
Transform::Init::InitType init_rotation_type
vector< size_t > kernel_extent
std::streambuf * log_stream
void init(int argc, const char *const *argv)
initialise MRtrix and parse command-line arguments
vector< ParsedOption > option
the list of options parsed from the command-line
bool exists(const std::string &path)
const App::OptionGroup rigid_options
const char * optim_algo_names[]
FORCE_INLINE ImageType multi_resolution_lmax(ImageType &input, const default_type scale_factor, const bool do_reorientation=false, const uint32_t lmax=0)
const App::OptionGroup adv_init_options
const App::OptionGroup lin_stage_options
void set_init_translation_model_from_option(Registration::Linear ®istration, const int &option)
void parse_general_options(Registration::Linear ®istration)
const App::OptionGroup affine_options
const App::OptionGroup fod_options
void set_init_rotation_model_from_option(Registration::Linear ®istration, const int &option)
LinearRobustMetricEstimatorType
double default_type
the default type used throughout MRtrix
std::string str(const T &value, int precision=0)
Header compute_minimum_average_header(const vector< Header > &input_headers, const vector< Eigen::Transform< default_type, 3, Eigen::Projective > > &transform_header_with, int voxel_subsampling=1, Eigen::Matrix< default_type, 4, 1 > padding=Eigen::Matrix< default_type, 4, 1 >(1.0, 1.0, 1.0, 1.0))
vector< OptimiserAlgoType > optimisers
MEMALIGN(StageSetting) StageSetting()
default_type loop_density
std::string info(const bool &do_reorientation=true)
OptimiserAlgoType optimiser_first
OptimiserAlgoType optimiser_default
vector< std::string > diagnostics_images
OptimiserAlgoType optimiser_last
default_type scale_factor