17#ifndef __registration_metric_mean_squared_h__
18#define __registration_metric_mean_squared_h__
26 namespace Registration
33 template <
class Params>
35 const Eigen::Vector3d& im1_point,
36 const Eigen::Vector3d& im2_point,
37 const Eigen::Vector3d& midway_point,
38 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
40 assert (!this->
weighted &&
"FIXME: set_weights not implemented for 3D metric");
42 typename Params::Im1ValueType im1_value;
43 typename Params::Im2ValueType im2_value;
44 Eigen::Matrix<typename Params::Im1ValueType, 1, 3> im1_grad;
45 Eigen::Matrix<typename Params::Im2ValueType, 1, 3> im2_grad;
47 params.im1_image_interp->value_and_gradient_wrt_scanner (im1_value, im1_grad);
50 params.im2_image_interp->value_and_gradient_wrt_scanner (im2_value, im2_grad);
56 const auto jacobian_vec = params.transformation.get_jacobian_vector_wrt_params (midway_point);
57 const Eigen::Vector3d g = diff * (im1_grad + im2_grad);
58 gradient.segment<4>(0) += g(0) * jacobian_vec;
59 gradient.segment<4>(4) += g(1) * jacobian_vec;
60 gradient.segment<4>(8) += g(2) * jacobian_vec;
68 template <
class Params>
70 const Eigen::Vector3d& im1_point,
71 const Eigen::Vector3d& im2_point,
72 const Eigen::Vector3d& midway_point,
73 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
75 assert (!this->
weighted &&
"FIXME: set_weights not implemented for 3D metric");
77 typename Params::Im1ValueType im1_value;
78 typename Params::Im2ValueType im2_value;
80 im1_value = params.im1_image_interp->value ();
83 im2_value = params.im2_image_interp->value ();
98 using is_asymmetric_type = int;
100 template <
class Params>
102 const Eigen::Vector3d& im1_point,
103 const Eigen::Vector3d& im2_point,
104 const Eigen::Vector3d& midway_point,
105 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
107 assert (!this->
weighted &&
"FIXME: set_weights not implemented for 3D metric");
109 typename Params::Im1ValueType im1_value;
111 Eigen::Matrix<typename Params::Im1ValueType, 1, 3> im1_grad;
113 params.im1_image_interp->value_and_gradient_wrt_scanner (im1_value, im1_grad);
120 im2_value = params.im2_image.value();
122 if (std::isnan (im2_value))
127 const auto jacobian_vec = params.transformation.get_jacobian_vector_wrt_params (im2_point);
128 const Eigen::Vector3d g = 2.0 * diff * im1_grad;
129 gradient.segment<4>(0) += g(0) * jacobian_vec;
130 gradient.segment<4>(4) += g(1) * jacobian_vec;
131 gradient.segment<4>(8) += g(2) * jacobian_vec;
137 template <
class Im1Type,
class Im2Type>
140 template <
class Params>
142 const Eigen::Vector3d& im1_point,
143 const Eigen::Vector3d& im2_point,
144 const Eigen::Vector3d& midway_point,
145 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
147 const ssize_t volumes = params.im1_image_interp->size(3);
149 if (im1_values.rows() != volumes) {
150 im1_values.resize (volumes);
151 im1_grad.resize (volumes, 3);
152 diff_values.resize (volumes);
153 im2_values.resize (volumes);
154 im2_grad.resize (volumes, 3);
157 params.im1_image_interp->value_and_gradient_row_wrt_scanner (im1_values, im1_grad);
158 if (im1_values.hasNaN())
161 params.im2_image_interp->value_and_gradient_row_wrt_scanner (im2_values, im2_grad);
162 if (im2_values.hasNaN())
165 const Eigen::Matrix<default_type, 4, 1> jacobian_vec = params.transformation.get_jacobian_vector_wrt_params (midway_point);
166 diff_values = im1_values - im2_values;
169 diff_values.array() *= this->
mc_weights.array();
171 for (ssize_t i = 0; i < volumes; ++i) {
172 const Eigen::Vector3d g = diff_values[i] * (im1_grad.row(i) + im2_grad.row(i));
173 gradient.segment<4>(0) += g(0) * jacobian_vec;
174 gradient.segment<4>(4) += g(1) * jacobian_vec;
175 gradient.segment<4>(8) += g(2) * jacobian_vec;
178 return diff_values.squaredNorm() / volumes;
181 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 1> im1_values;
182 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 1> im2_values;
183 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 3> im1_grad;
184 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 3> im2_grad;
185 Eigen::VectorXd diff_values;
188 template <
class Im1Type,
class Im2Type>
193 template <
class Params>
195 const Eigen::Vector3d& im1_point,
196 const Eigen::Vector3d& im2_point,
197 const Eigen::Vector3d& midway_point,
198 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
199 const ssize_t volumes = params.im1_image_interp->size(3);
201 if (im1_values.rows() != volumes) {
202 im1_values.resize (volumes);
203 im2_values.resize (volumes);
204 diff_values.resize (volumes);
207 params.im1_image_interp->row (im1_values);
208 if (im1_values.hasNaN())
211 params.im2_image_interp->row (im2_values);
212 if (im2_values.hasNaN())
215 diff_values = im1_values - im2_values;
217 diff_values.array() *= this->
mc_weights.array();
219 return diff_values.squaredNorm() / volumes;
222 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 1> im1_values;
223 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 1> im2_values;
224 Eigen::VectorXd diff_values;
227 template <
class Im1Type,
class Im2Type>
230 template <
class Params>
232 const Eigen::Vector3d& im1_point,
233 const Eigen::Vector3d& im2_point,
234 const Eigen::Vector3d& midway_point,
235 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
237 const ssize_t volumes = params.im1_image_interp->size(3);
239 if (im1_values.rows() != volumes) {
240 im1_values.resize (volumes);
241 im1_grad.resize (volumes, 3);
242 diff_values.resize (volumes);
243 im2_values.resize (volumes);
244 im2_grad.resize (volumes, 3);
247 params.im1_image_interp->value_and_gradient_row_wrt_scanner (im1_values, im1_grad);
248 if (im1_values.hasNaN())
251 params.im2_image_interp->value_and_gradient_row_wrt_scanner (im2_values, im2_grad);
252 if (im2_values.hasNaN())
258 im2_values = params.im2_image.row(3);
260 if (im2_values.hasNaN())
263 const Eigen::Matrix<default_type, 4, 1> jacobian_vec = params.transformation.get_jacobian_vector_wrt_params (im2_point);
264 diff_values = im1_values - im2_values;
267 diff_values.array() *= this->
mc_weights.array();
269 for (ssize_t i = 0; i < volumes; ++i) {
270 const Eigen::Vector3d g = 2.0 * diff_values[i] * im1_grad.row(i);
271 gradient.segment<4>(0) += g(0) * jacobian_vec;
272 gradient.segment<4>(4) += g(1) * jacobian_vec;
273 gradient.segment<4>(8) += g(2) * jacobian_vec;
276 return diff_values.squaredNorm() / volumes;
279 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 1> im1_values;
280 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 1> im2_values;
281 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 3> im1_grad;
282 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 3> im2_grad;
283 Eigen::VectorXd diff_values;
286 template <
class Im1Type,
class Im2Type>
291 volumes ( (im1.ndim() == 3) ? 1 : im1.size(3) ) {
292 assert (im1.ndim() == 4);
293 assert (im1.ndim() == im2.ndim());
294 assert (im1.size(3) == im2.size(3));
295 diff_values.resize (volumes);
296 im1_values.resize (volumes);
297 im2_values.resize (volumes);
301 using is_vector_type = int;
303 template <
class Params>
304 Eigen::Matrix<default_type, Eigen::Dynamic, 1> operator() (
Params& params,
305 const Eigen::Vector3d& im1_point,
306 const Eigen::Vector3d& im2_point,
307 const Eigen::Vector3d& midway_point,
308 Eigen::Matrix<default_type, Eigen::Dynamic, 1>& gradient) {
310 assert (volumes == params.im1_image_interp->size(3));
312 im1_values = params.im1_image_interp->row (3);
313 if (im1_values.hasNaN()) {
314 diff_values.setZero();
318 im2_values = params.im2_image_interp->row (3);
319 if (im2_values.hasNaN()) {
320 diff_values.setZero();
324 diff_values = im1_values - im2_values;
326 diff_values.array() *= this->
mc_weights.array();
328 return diff_values.array().square();
332 Eigen::Matrix<typename Im1Type::value_type, Eigen::Dynamic, 1> im1_values;
333 Eigen::Matrix<typename Im2Type::value_type, Eigen::Dynamic, 1> im2_values;
334 Eigen::VectorXd diff_values;
Eigen::VectorXd mc_weights
constexpr I round(const T x)
double default_type
the default type used throughout MRtrix