Developer documentation
Version 3.0.3-105-gd3941f44
difference_robust.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_metric_difference_robust_h__
18#define __registration_metric_difference_robust_h__
19
20#include "math/math.h"
23
24namespace MR
25{
26 namespace Registration
27 {
28 namespace Metric
29 {
30 template<class Estimator = L2>
32 public:
33 DifferenceRobust () = delete;
34 DifferenceRobust (Estimator est) : estimator(est) {}
35
36 template <class Params>
37 default_type operator() (Params& params,
38 const Eigen::Vector3d im1_point,
39 const Eigen::Vector3d im2_point,
40 const Eigen::Vector3d midway_point,
41 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
42
43 assert (!this->weighted && "FIXME: set_weights not implemented for 3D metric");
44
45 typename Params::Im1ValueType im1_value;
46 typename Params::Im2ValueType im2_value;
47 Eigen::Matrix<typename Params::Im1ValueType, 1, 3> im1_grad;
48 Eigen::Matrix<typename Params::Im2ValueType, 1, 3> im2_grad;
49
50 params.im1_image_interp->value_and_gradient_wrt_scanner (im1_value, im1_grad);
51 if (std::isnan (default_type (im1_value)))
52 return 0.0;
53 params.im2_image_interp->value_and_gradient_wrt_scanner (im2_value, im2_grad);
54 if (std::isnan (default_type (im2_value)))
55 return 0.0;
56
57 default_type residual, grad;
58 estimator((default_type) im1_value - (default_type) im2_value, residual, grad);
59 const auto jacobian_vec = params.transformation.get_jacobian_vector_wrt_params (midway_point);
60 const Eigen::Vector3d g = grad * (im1_grad + im2_grad);
61 gradient.segment<4>(0) += g(0) * jacobian_vec;
62 gradient.segment<4>(4) += g(1) * jacobian_vec;
63 gradient.segment<4>(8) += g(2) * jacobian_vec;
64
65 return residual;
66 }
67
68 Estimator estimator;
69 };
70
71 template<class Im1Type, class Im2Type, class Estimator = L2>
73 public:
74 DifferenceRobust4D () = delete;
75 DifferenceRobust4D (const Im1Type& im1, const Im2Type& im2, const Estimator& est) :
76 volumes(im1.size(3)),
77 estimator(est) {
78 im1_grad.resize(volumes, 3);
79 im2_grad.resize(volumes, 3);
80 im1_values.resize(volumes, 1);
81 im2_values.resize(volumes, 1);
82 diff_values.resize(volumes, 1);
83 };
84
85
88 using requires_initialisation = int;
89
90 void init (const Im1Type& im1, const Im2Type& im2) {
91 assert (im1.ndim() == 4);
92 assert (im2.ndim() == 4);
93 assert(im1.size(3) == im2.size(3));
94 if (volumes != im1.size(3)) {
95 volumes = im1.size(3);
96 im1_grad.resize(volumes, 3);
97 im2_grad.resize(volumes, 3);
98 im1_values.resize(volumes, 1);
99 im2_values.resize(volumes, 1);
100 diff_values.resize(volumes, 1);
101 }
102 }
103
104 template <class Params>
105 default_type operator() (Params& params,
106 const Eigen::Vector3d& im1_point,
107 const Eigen::Vector3d& im2_point,
108 const Eigen::Vector3d& midway_point,
109 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
110
111 params.im1_image_interp->value_and_gradient_row_wrt_scanner (im1_values, im1_grad);
112 if (im1_values.hasNaN())
113 return 0.0;
114
115 params.im2_image_interp->value_and_gradient_row_wrt_scanner (im2_values, im2_grad);
116 if (im2_values.hasNaN())
117 return 0.0;
118
119 assert (volumes == im1_grad.rows() && "metric.init not called after image has been cropped?");
120 assert (volumes == im2_grad.rows() && "metric.init not called after image has been cropped?");
121
122 const Eigen::Matrix<default_type, 4, 1> jacobian_vec (params.transformation.get_jacobian_vector_wrt_params (midway_point));
123 diff_values = im1_values - im2_values;
124
125 if (this->weighted)
126 diff_values.array() *= this->mc_weights.array();
127
128 estimator (diff_values.template cast<default_type>(), residuals, grads);
129
130 Eigen::Matrix<default_type, 1, 3> g;
131 for (ssize_t i = 0; i < volumes; ++i) {
132 g = grads[i] * (im1_grad.row(i) + im2_grad.row(i));
133 gradient.segment<4>(0) += g(0) * jacobian_vec;
134 gradient.segment<4>(4) += g(1) * jacobian_vec;
135 gradient.segment<4>(8) += g(2) * jacobian_vec;
136 }
137
138 return residuals.sum() / (default_type)volumes;
139 }
140
141 private:
142 ssize_t volumes;
143 Estimator estimator;
144 Eigen::Matrix<default_type, Eigen::Dynamic, 1> residuals, grads;
145 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 3> im1_grad;
146 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 3> im2_grad;
147 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 1> im1_values, diff_values;
148 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 1> im2_values;
149 };
150 }
151 }
152}
153#endif
Definition: base.h:24
double default_type
the default type used throughout MRtrix
Definition: types.h:228
#define MEMALIGN(...)
Definition: types.h:185