Developer documentation
Version 3.0.3-105-gd3941f44
mapper.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 __dwi_tractography_mapping_gaussian_mapper_h__
18#define __dwi_tractography_mapping_gaussian_mapper_h__
19
20
21#include "image.h"
22
26
27
28
29namespace MR {
30 namespace DWI {
31 namespace Tractography {
32 namespace Mapping {
33 namespace Gaussian {
34
35
36
37
39 { MEMALIGN(TrackMapper)
40
41 using BaseMapper = Mapping::TrackMapperTWI;
42
43 public:
44 template <class HeaderType>
45 TrackMapper (const HeaderType& template_image, const contrast_t c) :
46 BaseMapper (template_image, c, GAUSSIAN),
48 assert (c == SCALAR_MAP || c == SCALAR_MAP_COUNT || c == FOD_AMP || c == CURVATURE);
49 }
50
51 TrackMapper (const TrackMapper&) = default;
53
54
56 {
58 throw Exception ("Cannot set Gaussian FWHM unless the track statistic is Gaussian");
59 const default_type theta = FWHM / (2.0 * std::sqrt (2.0 * std::log (2.0)));
60 gaussian_denominator = 2.0 * Math::pow2 (theta);
61 }
62
63
64 // Have to re-define the functor here, so that the alternative voxelise() methods can be called
65 // (Can't define these virtual because they're templated)
66 // Also means that the call to run_queue() must cast to Gaussian::TrackMapper rather than using base class
67 template <class Cont>
68 bool operator() (Streamline<>& in, Cont& out) const
69 {
70 out.clear();
71 out.index = in.get_index();
72 out.weight = in.weight;
73 if (in.empty())
74 return true;
75 if (preprocess (in, out) || map_zero) {
76 Streamline<> temp;
77 upsampler (in, temp);
78 if (precise)
79 voxelise_precise (temp, out);
80 else if (ends_only)
81 voxelise_ends (temp, out);
82 else
83 voxelise (temp, out);
84 postprocess (temp, out);
85 }
86 return true;
87 }
88
89
90
91
92 protected:
95
96 // Overload corresponding functions in TrackMapperTWI
97 void set_factor (const Streamline<>& tck, SetVoxelExtras& out) const;
98 bool preprocess (const Streamline<>& tck, SetVoxelExtras& out) const { set_factor (tck, out); return true; }
99
100 // Three versions of voxelise() function, just as in base class: difference is that here the
101 // corresponding TWI factor for each voxel mapping must be determined and passed to add_to_set()
102 template <class Cont> void voxelise (const Streamline<>&, Cont&) const;
103 template <class Cont> void voxelise_precise (const Streamline<>&, Cont&) const;
104 template <class Cont> void voxelise_ends (const Streamline<>&, Cont&) const;
105
106 inline void add_to_set (SetVoxel& , const Eigen::Vector3i&, const Eigen::Vector3d&, const default_type, const default_type) const;
107 inline void add_to_set (SetVoxelDEC&, const Eigen::Vector3i&, const Eigen::Vector3d&, const default_type, const default_type) const;
108 inline void add_to_set (SetDixel& , const Eigen::Vector3i&, const Eigen::Vector3d&, const default_type, const default_type) const;
109 inline void add_to_set (SetVoxelTOD&, const Eigen::Vector3i&, const Eigen::Vector3d&, const default_type, const default_type) const;
110
111 // Convenience function to convert from streamline position index to a linear-interpolated
112 // factor value (TrackMapperTWI member field factors[] only contains one entry per pre-upsampled point)
113 inline default_type tck_index_to_factor (const size_t) const;
114
115
116 };
117
118
119
120 template <class Cont>
121 void TrackMapper::voxelise (const Streamline<>& tck, Cont& output) const
122 {
123
124 size_t prev = 0;
125 const size_t last = tck.size() - 1;
126
127 Eigen::Vector3i vox;
128 for (size_t i = 0; i != last; ++i) {
129 vox = round (scanner2voxel * tck[i]);
130 if (check (vox, info)) {
131 const Eigen::Vector3d dir ((tck[i+1] - tck[prev]).cast<default_type>().normalized());
132 const default_type factor = tck_index_to_factor (i);
133 add_to_set (output, vox, dir, 1.0, factor);
134 }
135 prev = i;
136 }
137
138 vox = round (scanner2voxel * tck[last]);
139 if (check (vox, info)) {
140 const Eigen::Vector3d dir ((tck[last] - tck[prev]).cast<default_type>().normalized());
141 const default_type factor = tck_index_to_factor (last);
142 add_to_set (output, vox, dir, 1.0f, factor);
143 }
144
145 for (auto& i : output)
146 i.normalize();
147
148 }
149
150
151
152
153
154
155 template <class Cont>
156 void TrackMapper::voxelise_precise (const Streamline<>& tck, Cont& out) const
157 {
158
160 using value_type = Streamline<>::value_type;
161
162
163 static const default_type accuracy = Math::pow2 (0.005 * std::min (info.spacing (0), std::min (info.spacing (1), info.spacing (2))));
164
165 if (tck.size() < 2)
166 return;
167
168 Math::Hermite<value_type> hermite (0.1);
169
170 const point_type tck_proj_front = (tck[ 0 ] * 2.0) - tck[ 1 ];
171 const point_type tck_proj_back = (tck[tck.size()-1] * 2.0) - tck[tck.size()-2];
172
173 unsigned int p = 0;
174 point_type p_voxel_exit = tck.front();
175 default_type mu = 0.0;
176 bool end_track = false;
177 Eigen::Vector3i next_voxel (round (scanner2voxel * tck.front()));
178
179 do {
180
181 const point_type p_voxel_entry (p_voxel_exit);
182 point_type p_prev (p_voxel_entry);
183 default_type length = 0.0;
184 const default_type index_voxel_entry = default_type(p) + mu;
185 const Eigen::Vector3i this_voxel = next_voxel;
186
187 while ((p != tck.size()) && ((next_voxel = round (scanner2voxel * tck[p])) == this_voxel)) {
188 length += (p_prev - tck[p]).norm();
189 p_prev = tck[p];
190 ++p;
191 mu = 0.0;
192 }
193
194 if (p == tck.size()) {
195 p_voxel_exit = tck.back();
196 end_track = true;
197 } else {
198
199 default_type mu_min = mu;
200 default_type mu_max = 1.0;
201
202 const point_type* p_one = (p == 1) ? &tck_proj_front : &tck[p - 2];
203 const point_type* p_four = (p == tck.size() - 1) ? &tck_proj_back : &tck[p + 1];
204
205 point_type p_min = p_prev;
206 point_type p_max = tck[p];
207
208 while ((p_min - p_max).squaredNorm() > accuracy) {
209
210 mu = 0.5 * (mu_min + mu_max);
211 hermite.set (mu);
212 const point_type p_mu = hermite.value (*p_one, tck[p - 1], tck[p], *p_four);
213 const Eigen::Vector3i mu_voxel = round (scanner2voxel * p_mu);
214
215 if (mu_voxel == this_voxel) {
216 mu_min = mu;
217 p_min = p_mu;
218 } else {
219 mu_max = mu;
220 p_max = p_mu;
221 next_voxel = mu_voxel;
222 }
223
224 }
225 p_voxel_exit = p_max;
226
227 }
228
229 length += (p_prev - p_voxel_exit).norm();
230 Eigen::Vector3d traversal_vector = (p_voxel_exit - p_voxel_entry).cast<default_type>().normalized();
231 if (traversal_vector.allFinite() && check (this_voxel, info)) {
232 const default_type index_voxel_exit = default_type(p) + mu;
233 const size_t mean_tck_index = std::round (0.5 * (index_voxel_entry + index_voxel_exit));
234 const default_type factor = tck_index_to_factor (mean_tck_index);
235 add_to_set (out, this_voxel, traversal_vector, length, factor);
236 }
237
238 } while (!end_track);
239
240 }
241
242
243
244 template <class Cont>
245 void TrackMapper::voxelise_ends (const Streamline<>& tck, Cont& out) const
246 {
247 for (size_t end = 0; end != 2; ++end) {
248 const Eigen::Vector3i vox = round (scanner2voxel * (end ? tck.back() : tck.front()));
249 if (check (vox, info)) {
250 const Eigen::Vector3d dir = (end ? (tck[tck.size()-1] - tck[tck.size()-2]) : (tck[0] - tck[1])).cast<default_type>().normalized();
251 const default_type factor = (end ? factors.back() : factors.front());
252 add_to_set (out, vox, dir, 1.0, factor);
253 }
254 }
255 }
256
257
258
259 inline void TrackMapper::add_to_set (SetVoxel& out, const Eigen::Vector3i& v, const Eigen::Vector3d& d, const default_type l, const default_type f) const
260 {
261 out.insert (v, l, f);
262 }
263 inline void TrackMapper::add_to_set (SetVoxelDEC& out, const Eigen::Vector3i& v, const Eigen::Vector3d& d, const default_type l, const default_type f) const
264 {
265 out.insert (v, d, l, f);
266 }
267 inline void TrackMapper::add_to_set (SetDixel& out, const Eigen::Vector3i& v, const Eigen::Vector3d& d, const default_type l, const default_type f) const
268 {
269 assert (dixel_plugin);
270 const size_t bin = (*dixel_plugin) (d);
271 out.insert (v, bin, l, f);
272 }
273 inline void TrackMapper::add_to_set (SetVoxelTOD& out, const Eigen::Vector3i& v, const Eigen::Vector3d& d, const default_type l, const default_type f) const
274 {
275 assert (tod_plugin);
277 (*tod_plugin) (sh, d);
278 out.insert (v, sh, l, f);
279 }
280
281
282
283
284
285 inline default_type TrackMapper::tck_index_to_factor (const size_t i) const
286 {
287 const default_type ideal_index = default_type(i) / default_type(upsampler.get_ratio());
288 const size_t lower_index = std::max (size_t(std::floor (ideal_index)), size_t(0));
289 const size_t upper_index = std::min (size_t(std::ceil (ideal_index)), size_t(factors.size() - 1));
290 const default_type mu = ideal_index - default_type(lower_index);
291 return ((mu * factors[upper_index]) + ((1.0-mu) * factors[lower_index]));
292 }
293
294
295
296
297
298 }
299 }
300 }
301 }
302}
303
304#endif
305
306
307
bool operator()(Streamline<> &in, Cont &out) const
Definition: mapper.h:68
void voxelise_precise(const Streamline<> &, Cont &) const
Definition: mapper.h:156
bool preprocess(const Streamline<> &tck, SetVoxelExtras &out) const
Definition: mapper.h:98
void set_gaussian_FWHM(const default_type FWHM)
Definition: mapper.h:55
default_type tck_index_to_factor(const size_t) const
Definition: mapper.h:285
void set_factor(const Streamline<> &tck, SetVoxelExtras &out) const
void voxelise(const Streamline<> &, Cont &) const
Definition: mapper.h:121
TrackMapper(const HeaderType &template_image, const contrast_t c)
Definition: mapper.h:45
void voxelise_ends(const Streamline<> &, Cont &) const
Definition: mapper.h:245
void add_to_set(SetVoxel &, const Eigen::Vector3i &, const Eigen::Vector3d &, const default_type, const default_type) const
Definition: mapper.h:259
void gaussian_smooth_factors(const Streamline<> &) const
Eigen::Matrix< default_type, Eigen::Dynamic, 1 > vector_type
Definition: voxel.h:131
const Eigen::Transform< float, 3, Eigen::AffineCompact > scanner2voxel
Definition: mapper.h:137
DWI::Tractography::Resampling::Upsampler upsampler
Definition: mapper.h:169
std::shared_ptr< TODMappingPlugin > tod_plugin
Definition: mapper.h:143
std::shared_ptr< DixelMappingPlugin > dixel_plugin
Definition: mapper.h:142
virtual void postprocess(const Streamline<> &tck, SetVoxelExtras &out) const
Definition: mapper.h:160
void set(value_type position)
Definition: hermite.h:36
S value(const S *vals) const
Definition: hermite.h:50
constexpr T pow2(const T &v)
Definition: math.h:53
constexpr I ceil(const T x)
template function with cast to different type
Definition: math.h:86
constexpr I floor(const T x)
template function with cast to different type
Definition: math.h:75
constexpr I round(const T x)
Definition: math.h:64
Eigen::Vector3i round(const Eigen::Matrix< T, 3, 1 > &p)
Definition: voxel.h:38
bool check(const Eigen::Vector3i &V, const HeaderType &H)
Definition: voxel.h:45
typename Streamline<>::point_type point_type
Definition: resampling.h:40
PointType::Scalar length(const vector< PointType > &tck)
Definition: streamline.h:134
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