Developer documentation
Version 3.0.3-105-gd3941f44
params.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_params_h__
18#define __registration_metric_params_h__
19
20#include "image.h"
21#include "interp/linear.h"
22#include "interp/nearest.h"
23#include "adapter/reslice.h"
25
26namespace MR
27{
28 namespace Registration
29 {
30 namespace Metric
31 {
32
33 template <class TransformType,
34 class Im1ImageType,
35 class Im2ImageType,
36 class MidwayImageType,
37 class Im1MaskType,
38 class Im2MaskType,
39 class Im1ImageInterpType,
40 class Im2ImageInterpType,
41 class Im1MaskInterpolatorType,
42 class Im2MaskInterpolatorType,
43 class ProcImageType = Image<default_type>,
44 class ProcImageInterpolatorType = Interp::Linear<Image<default_type>>,
45 class ProcMaskType = Image<bool>,
46 class ProcessedMaskInterpolatorType = Interp::Nearest<Image<bool>>>
47 class Params {
48 MEMALIGN (Params<TransformType,Im1ImageType,Im2ImageType,MidwayImageType,
49 Im1MaskType,Im2MaskType,Im1ImageInterpType,Im2ImageInterpType,
50 Im1MaskInterpolatorType,Im2MaskInterpolatorType,ProcImageType,ProcImageInterpolatorType,
51 ProcMaskType,ProcessedMaskInterpolatorType>)
52 public:
53
54 using TransformParamType = typename TransformType::ParameterType;
55 using Im1ValueType = typename Im1ImageInterpType::value_type;
56 using Im2ValueType = typename Im2ImageInterpType::value_type;
57 using Im1InterpType = Im1ImageInterpType;
58 using Im2InterpType = Im2ImageInterpType;
59 using Mask1InterpolatorType = Im1MaskInterpolatorType;
60 using Mask2InterpolatorType = Im2MaskInterpolatorType;
61 using ProcessedValueType = typename ProcImageInterpolatorType::value_type;
62 using ProcessedImageType = ProcImageType;
63 using ProcessedMaskType = ProcMaskType;
64 using ProcessedImageInterpType = ProcImageInterpolatorType;
65 using ProcessedMaskInterpType = ProcessedMaskInterpolatorType;
66
67 Params (TransformType& transform,
68 Im1ImageType& im1_image,
69 Im2ImageType& im2_image,
70 MidwayImageType& midway_image,
71 Im1MaskType& im1_mask,
72 Im2MaskType& im2_mask) :
73 transformation (transform),
74 im1_image (im1_image),
75 im2_image (im2_image),
76 midway_image (midway_image),
77 im1_mask (im1_mask),
78 im2_mask (im2_mask),
79 loop_density (1.0),
80 control_point_exent (10.0, 10.0, 10.0),
81 robust_estimate_subset (false),
82 robust_estimate_use_score (false) {
83 im1_image_interp.reset (new Im1ImageInterpType (im1_image));
84 im2_image_interp.reset (new Im2ImageInterpType (im2_image));
85 if (im1_mask.valid())
86 im1_mask_interp.reset (new Im1MaskInterpolatorType (im1_mask));
87 if (im2_mask.valid())
88 im2_mask_interp.reset (new Im2MaskInterpolatorType (im2_mask));
89 update_control_points();
90 }
91
92 void set_extent (vector<size_t> extent_vector) { extent=std::move(extent_vector); }
93
94 void set_mc_settings (const vector<MultiContrastSetting>& mc_vector) {
95 mc_settings = mc_vector;
96
97 // set multi contrast weights
98 size_t nvols (0);
99 for (const auto& mc : mc_settings)
100 nvols += mc.nvols;
101
102 if (nvols == 1) {
103 mc_weights = Eigen::Matrix<default_type, Eigen::Dynamic, 1>();
104 return;
105 }
106
107 mc_weights.resize (nvols);
108 for (const auto& mc : mc_settings) {
109 mc_weights.segment(mc.start,mc.nvols).fill(mc.weight);
110 }
111
112 if ((mc_weights.array() == 1.0).all())
113 mc_weights = Eigen::Matrix<default_type, Eigen::Dynamic, 1>();
114 }
115
116 Eigen::VectorXd get_weights () const {
117 return mc_weights;
118 }
119
120 template <class VectorType>
121 void set_control_points_extent(const VectorType& extent) {
122 control_point_exent = extent;
123 update_control_points();
124 }
125
126 void set_im1_iterpolator (Im1ImageType& im1_image) {
127 im1_image_interp.reset (new Im1ImageInterpType (im1_image));
128 }
129 void set_im2_iterpolator (Im1ImageType& im2_image) {
130 im2_image_interp.reset (new Im2ImageInterpType (im2_image));
131 }
132
133 void update_control_points () {
134 const Eigen::Vector3d centre = transformation.get_centre();
135 control_points.resize(4, 4);
136 // tetrahedron centred at centre of midspace scaled by control_point_exent
137 control_points << 1.0, -1.0, -1.0, 1.0,
138 1.0, 1.0, -1.0, -1.0,
139 1.0, -1.0, 1.0, -1.0,
140 1.0, 1.0, 1.0, 1.0;
141 for (size_t i = 0; i < 3; ++i)
142 control_points.row(i) *= control_point_exent[i];
143 control_points.block<3,4>(0,0).colwise() += centre;
144 }
145
146 const vector<size_t>& get_extent() const { return extent; }
147
148 template <class OptimiserType>
149 void optimiser_update (OptimiserType& optim, const ssize_t overlap_count) {
150 DEBUG ("gradient descent ran using " + str(optim.function_evaluations()) + " cost function evaluations.");
151 if (!is_finite(optim.state())) {
152 CONSOLE ("last valid transformation:");
153 transformation.debug();
154 CONSOLE ("last optimisation step ran using " + str(optim.function_evaluations()) + " cost function evaluations.");
155 if (overlap_count == 0)
156 WARN ("linear registration failed because (masked) images do not overlap.");
157 throw Exception ("Linear registration failed, transformation parameters are NaN.");
158 }
159 transformation.set_parameter_vector (optim.state());
160 update_control_points();
161 }
162
163 void make_diagnostics_image (const std::basic_string<char>& image_path, bool masked = true) {
164 Header header (midway_image);
165 header.datatype() = DataType::Float64;
166 header.ndim() = 4;
167 header.size(3) = 3; // + processed_image.valid();
168 // auto check = Image<float>::scratch (header);
169 auto trafo1 = transformation.get_transform_half();
170 auto trafo2 = transformation.get_transform_half_inverse();
171
172 header.keyval()["control_points"] = str(control_points);
173 header.keyval()["trafo1"] = str(trafo1.matrix());
174 header.keyval()["trafo2"] = str(trafo2.matrix());
175 auto check = Image<default_type>::create (image_path, header);
176
177 vector<uint32_t> no_oversampling (3,1);
179 im1_image, midway_image, trafo1, no_oversampling, NAN);
181 im2_image, midway_image, trafo2, no_oversampling, NAN);
182
183 auto T = MR::Transform(midway_image).voxel2scanner;
184 Eigen::Vector3d midway_point, voxel_pos, im1_point, im2_point;
185
186 for (auto i = Loop (midway_image) (check, im1_reslicer, im2_reslicer); i; ++i) {
187 voxel_pos = Eigen::Vector3d ((default_type)check.index(0), (default_type)check.index(1), (default_type)check.index(2));
188 midway_point = T * voxel_pos;
189
190 check.index(3) = 0;
191 check.value() = im1_reslicer.value();
192 if (masked and im1_mask_interp) {
193 transformation.transform_half (im1_point, midway_point);
194 im1_mask_interp->scanner (im1_point);
195 if (im1_mask_interp->value() < 0.5)
196 check.value() = NAN;
197 }
198
199 check.index(3) = 1;
200 check.value() = im2_reslicer.value();
201 if (masked and im2_mask_interp) {
202 transformation.transform_half_inverse (im2_point, midway_point);
203 im2_mask_interp->scanner (im2_point);
204 if (im2_mask_interp->value() < 0.5)
205 check.value() = NAN;
206 }
207 if (robust_estimate_score1_interp) {
208 check.index(3) = 2;
209 transformation.transform_half (im1_point, midway_point);
210 robust_estimate_score1_interp->scanner (im1_point);
211 transformation.transform_half_inverse (im2_point, midway_point);
212 robust_estimate_score2_interp->scanner (im2_point);
213 if (robust_estimate_score1_interp->value() >= 0.5 && robust_estimate_score2_interp->value() >= 0.5)
214 check.value() = 0.0; // 0.5 * (robust_estimate_score2_interp->value() + robust_estimate_score1_interp->value());
215 else
216 check.value() = NaN;
217 }
218 // if (processed_image.valid()) {
219 // assign_pos_of(voxel_pos, 0, 3).to(processed_image);
220 // check.index(3) = 3;
221 // check.value() = processed_image.value();
222 // }
223 check.index(3) = 0;
224 }
225 INFO("diagnostics image written");
226 // display (check);
227 }
228
229 TransformType& transformation;
230 Im1ImageType im1_image;
231 Im2ImageType im2_image;
232 MidwayImageType midway_image;
233 MR::copy_ptr<Im1ImageInterpType> im1_image_interp;
234 MR::copy_ptr<Im2ImageInterpType> im2_image_interp;
235 Im1MaskType im1_mask;
236 Im2MaskType im2_mask;
239 default_type loop_density;
240 Eigen::Vector3d control_point_exent;
241
242 bool robust_estimate_subset;
243 bool robust_estimate_use_score;
244 MR::vector<int> robust_estimate_subset_from;
245 MR::vector<int> robust_estimate_subset_size;
246 Image<float> robust_estimate_score1, robust_estimate_score2;
247 MR::copy_ptr<Interp::Linear<Image<float>>> robust_estimate_score1_interp;
248 MR::copy_ptr<Interp::Linear<Image<float>>> robust_estimate_score2_interp;
249
250 Eigen::Matrix<default_type, Eigen::Dynamic, Eigen::Dynamic> control_points;
251 vector<size_t> extent;
253
254 ProcImageType processed_image;
255 MR::copy_ptr<ProcImageInterpolatorType> processed_image_interp;
256 ProcMaskType processed_mask;
258
259
260 private:
261 Eigen::Matrix<default_type, Eigen::Dynamic, 1> mc_weights;
262 };
263 }
264 }
265}
266
267#endif
an Image providing interpolated values from another Image
Definition: reslice.h:112
static constexpr uint8_t Float64
Definition: datatype.h:148
static Image create(const std::string &image_name, const Header &template_header, bool add_to_command_history=true)
Definition: image.h:192
const transform_type voxel2scanner
Definition: transform.h:43
#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
bool is_finite(const Eigen::MatrixBase< Derived > &x)
check if all elements of an Eigen MatrixBase object are finite
Definition: math.h:98
FORCE_INLINE LoopAlongAxes Loop()
Definition: loop.h:419
bool check(int VERSION, Header &H, const size_t num_axes, const vector< std::string > &suffixes)
MR::default_type value_type
Definition: typedefs.h:33
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
constexpr default_type NaN
Definition: types.h:230
#define MEMALIGN(...)
Definition: types.h:185