Developer documentation
Version 3.0.3-105-gd3941f44
nonlinear.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __registration_nonlinear_h__
18#define __registration_nonlinear_h__
19
20#include "image.h"
21#include "types.h"
22
23#include "filter/warp.h"
24#include "filter/resize.h"
36#include "math/average_space.h"
38
39namespace MR
40{
41 namespace Registration
42 {
43
44 extern const App::OptionGroup nonlinear_options;
45
46
48 { MEMALIGN(NonLinear)
49
50 public:
51
52 NonLinear ():
53 is_initialised (false),
54 max_iter (1, 50),
55 scale_factor (3),
56 update_smoothing (2.0),
57 disp_smoothing (1.0),
58 gradient_step (0.5),
59 do_reorientation (false),
60 fod_lmax (3),
61 use_cc (false),
63 scale_factor[0] = 0.25;
64 scale_factor[1] = 0.5;
65 scale_factor[2] = 1.0;
66 fod_lmax[0] = 0;
67 fod_lmax[1] = 2;
68 fod_lmax[2] = 4;
69 }
70
71
72 template <class TransformType, class Im1ImageType, class Im2ImageType, class Im1MaskType, class Im2MaskType>
73 void run (TransformType linear_transform,
74 Im1ImageType& im1_image,
75 Im2ImageType& im2_image,
76 Im1MaskType& im1_mask,
77 Im2MaskType& im2_mask) {
78
79 if (!is_initialised) {
80 im1_to_mid_linear = linear_transform.get_transform_half();
81 im2_to_mid_linear = linear_transform.get_transform_half_inverse();
82
83 INFO ("Estimating halfway space");
85 // define transfomations that will be applied to the image header when the common space is calculated
86 midway_image_header = compute_minimum_average_header (im1_image, im2_image, linear_transform.get_transform_half_inverse(), linear_transform.get_transform_half());
87 } else {
88 // if initialising only perform optimisation at the full resolution level
89 scale_factor.resize (1);
90 scale_factor[0] = 1.0;
91 }
92
93 if (max_iter.size() == 1)
94 max_iter.resize (scale_factor.size(), max_iter[0]);
95 else if (max_iter.size() != scale_factor.size())
96 throw Exception ("the max number of non-linear iterations needs to be defined for each multi-resolution level (scale_factor)");
97
98 if (do_reorientation and (fod_lmax.size() != scale_factor.size()))
99 throw Exception ("the lmax needs to be defined for each multi-resolution level (scale factor)");
100 else
101 fod_lmax.resize (scale_factor.size(), 0);
102
103 for (size_t level = 0; level < scale_factor.size(); level++) {
104 if (is_initialised) {
105 if (do_reorientation) {
106 CONSOLE ("scale factor (init warp resolution), lmax " + str(fod_lmax[level]));
107 } else {
108 CONSOLE ("scale factor (init warp resolution)");
109 }
110 } else {
111 if (do_reorientation) {
112 CONSOLE ("nonlinear stage " + str(level + 1) + ", scale factor " + str(scale_factor[level]) + ", lmax " + str(fod_lmax[level]));
113 } else {
114 CONSOLE ("nonlinear stage " + str(level + 1) + ", scale factor " + str(scale_factor[level]));
115 }
116 }
117
118 DEBUG ("Resizing midway image based on multi-resolution level");
119
120 Filter::Resize resize_filter (midway_image_header);
121 resize_filter.set_scale_factor (scale_factor[level]);
122 resize_filter.set_interp_type (1);
123 resize_filter.datatype() = DataType::Float64; // for saving debug output with save()
124
125 Header midway_image_header_resized = resize_filter;
126 midway_image_header_resized.ndim() = 3;
127
128 default_type update_smoothing_mm = update_smoothing * ((midway_image_header_resized.spacing(0)
129 + midway_image_header_resized.spacing(1)
130 + midway_image_header_resized.spacing(2)) / 3.0);
131 default_type disp_smoothing_mm = disp_smoothing * ((midway_image_header_resized.spacing(0)
132 + midway_image_header_resized.spacing(1)
133 + midway_image_header_resized.spacing(2)) / 3.0);
134
135
136 // define or adjust tissue contrast lmax, nvols for this stage
138 if (stage_contrasts.size()) {
139 for (auto & mc : stage_contrasts)
140 mc.lower_lmax (fod_lmax[level]);
141 } else {
142 MultiContrastSetting mc (im1_image.ndim()<4? 1:im1_image.size(3), do_reorientation, fod_lmax[level]);
143 stage_contrasts.push_back(mc);
144 }
145
146 for (const auto & mc : stage_contrasts)
147 DEBUG (str(mc));
148
151
152 for (const auto & mc : stage_contrasts)
153 INFO (str(mc));
154
155 DEBUG ("Initialising scratch images");
156 Header warped_header (midway_image_header_resized);
157 if (im1_image.ndim() == 4) {
158 warped_header.ndim() = 4;
159 warped_header.size(3) = im1_smoothed.size(3);
160 }
161 auto im1_warped = Image<default_type>::scratch (warped_header);
162 auto im2_warped = Image<default_type>::scratch (warped_header);
163
164 Image<default_type> im_cca, im_ccc, im_ccb, im_cc1, im_cc2;
165 if (use_cc) {
166 DEBUG ("Initialising CC images");
167 im_cca = Image<default_type>::scratch(warped_header);
168 im_ccb = Image<default_type>::scratch(warped_header);
169 im_ccc = Image<default_type>::scratch(warped_header);
170 im_cc1 = Image<default_type>::scratch(warped_header);
171 im_cc2 = Image<default_type>::scratch(warped_header);
172 }
173
174 Header field_header (midway_image_header_resized);
175 field_header.ndim() = 4;
176 field_header.size(3) = 3;
177
178 im1_to_mid_new = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
179 im2_to_mid_new = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
180 im1_update = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
181 im2_update = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
182 im1_update_new = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
183 im2_update_new = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
184
185 if (!is_initialised) {
186 if (level == 0) {
187 im1_to_mid = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
188 im2_to_mid = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
189 mid_to_im1 = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
190 mid_to_im2 = make_shared<Image<default_type>>(Image<default_type>::scratch (field_header));
191 } else {
192 DEBUG ("Upsampling fields");
193 {
194 LogLevelLatch level(0);
195 im1_to_mid = reslice (*im1_to_mid, field_header);
196 im2_to_mid = reslice (*im2_to_mid, field_header);
197 mid_to_im1 = reslice (*mid_to_im1, field_header);
198 mid_to_im2 = reslice (*mid_to_im2, field_header);
199 }
200 }
201 }
202
203 ssize_t iteration = 1;
204 default_type grad_step_altered = gradient_step * (field_header.spacing(0) + field_header.spacing(1) + field_header.spacing(2)) / 3.0;
205 default_type cost = std::numeric_limits<default_type>::max();
206 bool converged = false;
207
208 while (!converged) {
209 if (iteration > 1) {
210 DEBUG ("smoothing update fields");
211 Filter::Smooth smooth_filter (*im1_update);
212 smooth_filter.set_stdev (update_smoothing_mm);
213 smooth_filter (*im1_update);
214 smooth_filter (*im2_update);
215 }
216
217 Image<default_type> im1_deform_field = Image<default_type>::scratch (field_header);
218 Image<default_type> im2_deform_field = Image<default_type>::scratch (field_header);
219
220 if (iteration > 1) {
221 DEBUG ("updating displacement field");
224
225 DEBUG ("smoothing displacement field");
226 Filter::Smooth smooth_filter (*im1_to_mid_new);
227 smooth_filter.set_stdev (disp_smoothing_mm);
228 smooth_filter.set_zero_boundary (true);
229 smooth_filter (*im1_to_mid_new);
230 smooth_filter (*im2_to_mid_new);
231
234 } else {
237 }
238
239 DEBUG ("warping input images");
240 {
241 LogLevelLatch level (0);
242 Filter::warp<Interp::Linear> (im1_smoothed, im1_warped, im1_deform_field, 0.0);
243 Filter::warp<Interp::Linear> (im2_smoothed, im2_warped, im2_deform_field, 0.0);
244 }
245
246 if (do_reorientation && fod_lmax[level]) {
247 DEBUG ("Reorienting FODs");
248 Registration::Transform::reorient_warp (im1_warped, im1_deform_field, aPSF_directions, false, stage_contrasts);
249 Registration::Transform::reorient_warp (im2_warped, im2_deform_field, aPSF_directions, false, stage_contrasts);
250 }
251
252 DEBUG ("warping mask images");
253 Im1MaskType im1_mask_warped;
254 if (im1_mask.valid()) {
255 im1_mask_warped = Im1MaskType::scratch (midway_image_header_resized);
256 LogLevelLatch level (0);
257 Filter::warp<Interp::Linear> (im1_mask, im1_mask_warped, im1_deform_field, 0.0);
258 }
259 Im1MaskType im2_mask_warped;
260 if (im2_mask.valid()) {
261 im2_mask_warped = Im1MaskType::scratch (midway_image_header_resized);
262 LogLevelLatch level (0);
263 Filter::warp<Interp::Linear> (im2_mask, im2_mask_warped, im2_deform_field, 0.0);
264 }
265
266 DEBUG ("evaluating metric and computing update field");
267 default_type cost_new = 0.0;
268 size_t voxel_count = 0;
269
270 if (use_cc) {
271 Metric::cc_precompute (im1_warped, im2_warped, im1_mask_warped, im2_mask_warped, im_cca, im_ccb, im_ccc, im_cc1, im_cc2, cc_extent);
272 // display<Image<default_type>>(im_cca);
273 // display<Image<default_type>>(im_ccb);
274 // display<Image<default_type>>(im_ccc);
275 // display<Image<default_type>>(im_cc1);
276 // display<Image<default_type>>(im_cc2);
277 }
278
279 if (im1_image.ndim() == 4) {
280 assert (!use_cc && "TODO");
282 cost_new, voxel_count, im1_warped, im2_warped, im1_mask_warped, im2_mask_warped, &stage_contrasts);
283 ThreadedLoop (im1_warped, 0, 3).run (metric, im1_warped, im2_warped, *im1_update_new, *im2_update_new);
284 } else {
285 if (use_cc) {
287 cost_new, voxel_count, im_cc1, im_cc2, im1_mask_warped, im2_mask_warped);
288 ThreadedLoop (im_cc1, 0, 3).run (metric, im_cc1, im_cc2, im_cca, im_ccb, im_ccc, *im1_update_new, *im2_update_new);
289 } else {
291 cost_new, voxel_count, im1_warped, im2_warped, im1_mask_warped, im2_mask_warped);
292 ThreadedLoop (im1_warped, 0, 3).run (metric, im1_warped, im2_warped, *im1_update_new, *im2_update_new);
293 }
294 }
295
296 if (App::log_level >= 3)
297 display<Image<default_type>>(*im1_update_new);
298
299 cost_new /= static_cast<default_type>(voxel_count);
300
301 // If cost is lower then keep new displacement fields and gradients
302 if (cost_new < cost) {
303 cost = cost_new;
304 if (iteration > 1) {
307 }
310
311 DEBUG ("inverting displacement field");
312 {
313 LogLevelLatch level (0);
316 }
317
318
319 } else {
320 converged = true;
321 INFO (" converged. cost: " + str(cost) + " voxel count: " + str(voxel_count));
322 }
323
324 if (!converged)
325 INFO (" iteration: " + str(iteration) + " cost: " + str(cost));
326
327 if (++iteration > max_iter[level])
328 converged = true;
329
330 // write debug image
331 if (converged && diagnostics_image_prefix.size()) {
332 std::ostringstream oss;
333 oss << diagnostics_image_prefix << "_stage-" << level + 1 << ".mif";
334 // if (Path::exists(oss.str()) && !App::overwrite_files)
335 // throw Exception ("diagnostics image file \"" + oss.str() + "\" already exists (use -force option to force overwrite)");
336 Header hc (warped_header);
337 hc.ndim() = 4;
338 hc.size(3) = 3;
339 INFO("writing debug image: "+oss.str());
340 auto check = Image<default_type>::create (oss.str(), hc);
341 for (auto i = Loop(check, 0, 3) (check, im1_warped, im2_warped ); i; ++i) {
342 check.value() = im1_warped.value();
343 check.index(3) = 1;
344 check.value() = im2_warped.value();
345 check.index(3) = 0;
346 }
347 }
348 }
349 }
350 // Convert all warps to deformation field format for output
357 WARN ("final warp computed is not diffeomorphic (negative jacobian determinants detected). Try increasing -nl_disp_smooth or -nl_update_smooth regularisation.");
358 }
359
360 template <class InputWarpType>
361 void initialise (InputWarpType& input_warps) {
362 assert (input_warps.ndim() == 5);
363
364 DEBUG ("reading linear transform from init warp field header");
367
368 DEBUG ("loading initial warp fields");
369 midway_image_header = input_warps;
370 midway_image_header.ndim() = 3;
371 Header field_header (input_warps);
372 field_header.ndim() = 4;
373 field_header.size(3) = 3;
374
375 im1_to_mid = make_shared<Image<default_type>> (Image<default_type>::scratch (field_header));
376 input_warps.index(4) = 0;
377 threaded_copy (input_warps, *im1_to_mid, 0, 4);
379
380 mid_to_im1 = make_shared<Image<default_type>> (Image<default_type>::scratch (field_header));
381 input_warps.index(4) = 1;
382 threaded_copy (input_warps, *mid_to_im1, 0, 4);
384
385 im2_to_mid = make_shared<Image<default_type>> (Image<default_type>::scratch (field_header));
386 input_warps.index(4) = 2;
387 threaded_copy (input_warps, *im2_to_mid, 0, 4);
389
390 mid_to_im2 = make_shared<Image<default_type>> (Image<default_type>::scratch (field_header));
391 input_warps.index(4) = 3;
392 threaded_copy (input_warps, *mid_to_im2, 0, 4);
394 is_initialised = true;
395 }
396
397 void set_max_iter (const vector<uint32_t>& maxiter) {
398 max_iter = maxiter;
399 }
400
401
402 void set_scale_factor (const vector<default_type>& scalefactor) {
403 for (size_t level = 0; level < scalefactor.size(); ++level) {
404 if (scalefactor[level] <= 0 || scalefactor[level] > 1)
405 throw Exception ("the non-linear registration scale factor for each multi-resolution level must be between 0 and 1");
406 }
407 scale_factor = scalefactor;
408 }
409
410 vector<default_type> get_scale_factor () const {
411 return scale_factor;
412 }
413
414 void set_init_grad_step (const default_type step) {
415 gradient_step = step;
416 }
417
418 void set_aPSF_directions (const Eigen::MatrixXd& dir) {
419 aPSF_directions = dir;
420 do_reorientation = true;
421 }
422
423 void set_update_smoothing (const default_type voxel_fwhm) {
424 update_smoothing = voxel_fwhm;
425 }
426
427 void set_disp_smoothing (const default_type voxel_fwhm) {
428 disp_smoothing = voxel_fwhm;
429 }
430
431 void set_lmax (const vector<uint32_t>& lmax) {
432 for (size_t i = 0; i < lmax.size (); ++i)
433 if (lmax[i] % 2)
434 throw Exception ("the input nonlinear lmax must be even");
435 fod_lmax = lmax;
436 }
437
438 // needs to be set after set_lmax
439 void set_mc_parameters (const vector<MultiContrastSetting>& mcs) {
440 contrasts = mcs;
441 }
442
443 ssize_t get_lmax () {
444 return (ssize_t) *std::max_element(fod_lmax.begin(), fod_lmax.end());
445 }
446
447 std::shared_ptr<Image<default_type> > get_im1_to_mid() {
448 return im1_to_mid;
449 }
450
451 std::shared_ptr<Image<default_type> > get_im2_to_mid() {
452 return im2_to_mid;
453 }
454
455 std::shared_ptr<Image<default_type> > get_mid_to_im1() {
456 return mid_to_im1;
457 }
458
459 std::shared_ptr<Image<default_type> > get_mid_to_im2() {
460 return mid_to_im2;
461 }
462
463 transform_type get_im1_to_mid_linear() const {
464 return im1_to_mid_linear;
465 }
466
467 transform_type get_im2_to_mid_linear() const {
468 return im2_to_mid_linear;
469 }
470
471 Header get_output_warps_header () const {
472 Header output_header (*im1_to_mid);
473 output_header.ndim() = 5;
474 output_header.size(3) = 3;
475 output_header.size(4) = 4;
476 output_header.stride(0) = 1;
477 output_header.stride(1) = 2;
478 output_header.stride(2) = 3;
479 output_header.stride(3) = 4;
480 output_header.stride(4) = 5;
481 return output_header;
482 }
483
484 void write_linear_to_header (Header& output_header) const {
485 output_header.keyval()["linear1"] = str(im1_to_mid_linear.matrix());
486 output_header.keyval()["linear2"] = str(im2_to_mid_linear.matrix());
487 }
488
489 void write_params_to_header (Header& output_header) const {
490 output_header.keyval()["nl_scale"] = str(scale_factor);
491 output_header.keyval()["nl_niter"] = str(max_iter);
492 output_header.keyval()["nl_update_smooth"] = str(update_smoothing);
493 output_header.keyval()["nl_disp_smooth"] = str(disp_smoothing);
494 output_header.keyval()["nl_gradient_step"] = str(gradient_step);
495 output_header.keyval()["fod_reorientation"] = str(do_reorientation);
497 output_header.keyval()["nl_lmax"] = str(fod_lmax);
498 }
499
500 template <class OutputType>
501 void get_output_warps (OutputType& output_warps) {
502 assert (output_warps.ndim() == 5);
503 output_warps.index(4) = 0;
504 threaded_copy (*im1_to_mid, output_warps, 0, 4);
505 output_warps.index(4) = 1;
506 threaded_copy (*mid_to_im1, output_warps, 0, 4);
507 output_warps.index(4) = 2;
508 threaded_copy (*im2_to_mid, output_warps, 0, 4);
509 output_warps.index(4) = 3;
510 threaded_copy (*mid_to_im2, output_warps, 0, 4);
511 }
512
513 Header get_midway_header () {
514 return midway_image_header;
515 }
516
517 void metric_cc (int radius) {
518 if (radius < 1)
519 throw Exception ("CC radius needs to be larger than 1");
520 use_cc = true;
521 INFO("Cross correlation radius: " + str(radius));
522 cc_extent = vector<size_t>(3, radius * 2 + 1);
523 }
524
525 void set_diagnostics_image (const std::basic_string<char>& path) {
527 }
528
529
530 protected:
531
532 std::shared_ptr<Image<default_type> > reslice (Image<default_type>& image, Header& header) {
533 std::shared_ptr<Image<default_type> > temp = make_shared<Image<default_type> > (Image<default_type>::scratch (header));
534 Filter::reslice<Interp::Linear> (image, *temp);
535 return temp;
536 }
537
539 Adapter::Jacobian<Image<default_type> > jacobian (field);
540 for (auto i = Loop (0,3) (jacobian); i; ++i) {
541 if (jacobian.value().determinant() < 0.0)
542 return true;
543 }
544 return false;
545 }
546
547
548
555 Eigen::MatrixXd aPSF_directions;
558 bool use_cc;
559 std::basic_string<char> diagnostics_image_prefix;
560
562
566
568
569 // Internally the warp is stored as a displacement field to enable easy smoothing near the boundaries
570 std::shared_ptr<Image<default_type> > im1_to_mid_new;
571 std::shared_ptr<Image<default_type> > im2_to_mid_new;
572 std::shared_ptr<Image<default_type> > im1_to_mid;
573 std::shared_ptr<Image<default_type> > im2_to_mid;
574 std::shared_ptr<Image<default_type> > mid_to_im1;
575 std::shared_ptr<Image<default_type> > mid_to_im2;
576
577 std::shared_ptr<Image<default_type> > im1_update;
578 std::shared_ptr<Image<default_type> > im2_update;
579 std::shared_ptr<Image<default_type> > im1_update_new;
580 std::shared_ptr<Image<default_type> > im2_update_new;
581
582 };
583 }
584}
585
586#endif
static constexpr uint8_t Float64
Definition: datatype.h:148
static Image scratch(const Header &template_header, const std::string &label="scratch image")
Definition: image.h:195
static Image create(const std::string &image_name, const Header &template_header, bool add_to_command_history=true)
Definition: image.h:192
std::basic_string< char > diagnostics_image_prefix
Definition: nonlinear.h:559
std::shared_ptr< Image< default_type > > im1_update
Definition: nonlinear.h:577
vector< MultiContrastSetting > stage_contrasts
Definition: nonlinear.h:567
std::shared_ptr< Image< default_type > > mid_to_im2
Definition: nonlinear.h:575
Eigen::MatrixXd aPSF_directions
Definition: nonlinear.h:555
std::shared_ptr< Image< default_type > > im1_update_new
Definition: nonlinear.h:579
std::shared_ptr< Image< default_type > > im2_update_new
Definition: nonlinear.h:580
vector< size_t > cc_extent
Definition: nonlinear.h:561
std::shared_ptr< Image< default_type > > im1_to_mid_new
Definition: nonlinear.h:570
std::shared_ptr< Image< default_type > > im2_to_mid
Definition: nonlinear.h:573
vector< uint32_t > fod_lmax
Definition: nonlinear.h:557
transform_type im1_to_mid_linear
Definition: nonlinear.h:563
bool has_negative_jacobians(Image< default_type > &field)
Definition: nonlinear.h:538
vector< MultiContrastSetting > contrasts
Definition: nonlinear.h:567
vector< default_type > scale_factor
Definition: nonlinear.h:551
default_type update_smoothing
Definition: nonlinear.h:552
default_type gradient_step
Definition: nonlinear.h:554
std::shared_ptr< Image< default_type > > reslice(Image< default_type > &image, Header &header)
Definition: nonlinear.h:532
vector< uint32_t > max_iter
Definition: nonlinear.h:550
default_type disp_smoothing
Definition: nonlinear.h:553
std::shared_ptr< Image< default_type > > mid_to_im1
Definition: nonlinear.h:574
std::shared_ptr< Image< default_type > > im2_to_mid_new
Definition: nonlinear.h:571
transform_type im2_to_mid_linear
Definition: nonlinear.h:564
std::shared_ptr< Image< default_type > > im1_to_mid
Definition: nonlinear.h:572
std::shared_ptr< Image< default_type > > im2_update
Definition: nonlinear.h:578
#define WARN(msg)
Definition: exception.h:73
#define INFO(msg)
Definition: exception.h:74
#define DEBUG(msg)
Definition: exception.h:75
#define CONSOLE(msg)
Definition: exception.h:71
FORCE_INLINE void invert_displacement(Image< default_type > &disp_field, Image< default_type > &inv_disp_field, size_t max_iter=50, default_type error_tolerance=0.0001)
Definition: invert.h:158
FORCE_INLINE LoopAlongAxes Loop()
Definition: loop.h:419
int log_level
Definition: exception.h:34
std::enable_if< std::is_fundamental< ValueType >::value &&sizeof(ValueType)==1, ValueType >::type swap(ValueType v)
Definition: raw.h:49
bool check(int VERSION, Header &H, const size_t num_axes, const vector< std::string > &suffixes)
void cc_precompute(Im1ImageType &im1_image, Im2ImageType &im2_image, Im1MaskType &im1_mask, Im2MaskType &im2_mask, DerivedImageType &A, DerivedImageType &B, DerivedImageType &C, DerivedImageType &im1_meansubtr, DerivedImageType &im2_meansubtr, const vector< size_t > &extent)
Definition: cc_helper.h:34
void reorient_warp(const std::string progress_message, FODImageType &fod_image, Image< default_type > &warp, const Eigen::MatrixXd &directions, const bool modulate=false, vector< MultiContrastSetting > multi_contrast_settings=vector< MultiContrastSetting >())
Definition: reorient.h:340
FORCE_INLINE void update_displacement_scaling_and_squaring(Image< default_type > &input, Image< default_type > &update, Image< default_type > &output, const default_type step=1.0)
Definition: compose.h:159
FORCE_INLINE void compose_linear_displacement(const transform_type &transform, DisplacementFieldType &disp_in, DeformationFieldType &deform_out)
Definition: compose.h:137
transform_type parse_linear_transform(InputWarpType &input_warps, std::string name)
Definition: helpers.h:49
void deformation2displacement(ImageType &input, ImageType &output)
Definition: convert.h:44
void displacement2deformation(ImageType &input, ImageType &output)
Definition: convert.h:34
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 nonlinear_options
Definition: base.h:24
double default_type
the default type used throughout MRtrix
Definition: types.h:228
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
Eigen::Transform< default_type, 3, Eigen::AffineCompact > transform_type
the type for the affine transform of an image:
Definition: types.h:234
ThreadedLoopRunOuter< decltype(Loop(vector< size_t >()))> ThreadedLoop(const HeaderType &source, const vector< size_t > &outer_axes, const vector< size_t > &inner_axes)
Multi-threaded loop object.
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))
void threaded_copy(InputImageType &source, OutputImageType &destination, const vector< size_t > &axes, size_t num_axes_in_thread=1)
Definition: threaded_copy.h:43