Developer documentation
Version 3.0.3-105-gd3941f44
writer.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_writer_h__
18#define __dwi_tractography_mapping_writer_h__
19
20#include "memory.h"
21#include "file/path.h"
22#include "file/utils.h"
23#include "image.h"
24#include "algo/loop.h"
25#include "thread_queue.h"
26
30
31
32
33#include <typeinfo>
34
35
36namespace MR {
37 namespace DWI {
38 namespace Tractography {
39 namespace Mapping {
40
41
42
44 extern const char* writer_dims[];
45
46
47
49 { MEMALIGN(MapWriterBase)
50
51 public:
52 MapWriterBase (const Header& header, const std::string& name, const vox_stat_t s = V_SUM, const writer_dim t = GREYSCALE) :
53 H (header),
56 type (t) {
57 assert (type != UNDEFINED);
58 }
59
60 MapWriterBase (const MapWriterBase&) = delete;
61
62 virtual ~MapWriterBase () { }
63
64 // can't do this in destructor since it could potentially throw,
65 // and throwing in destructor is most uncool (invokes
66 // std::terminate() with no further ado).
67 virtual void finalise() { }
68
69
70
71 virtual bool operator() (const SetVoxel&) { return false; }
72 virtual bool operator() (const SetVoxelDEC&) { return false; }
73 virtual bool operator() (const SetDixel&) { return false; }
74 virtual bool operator() (const SetVoxelTOD&) { return false; }
75
76 virtual bool operator() (const Gaussian::SetVoxel&) { return false; }
77 virtual bool operator() (const Gaussian::SetVoxelDEC&) { return false; }
78 virtual bool operator() (const Gaussian::SetDixel&) { return false; }
79 virtual bool operator() (const Gaussian::SetVoxelTOD&) { return false; }
80
81
82 protected:
83 const Header& H;
84 const std::string output_image_name;
87
88 // This gets used with mean voxel statistic for some (but not all) writers,
89 // or if the output is a voxel_summed DEC image.
90 // counts needs to be floating-point to cover possibility of weighted streamlines
91 // It's also hijacked to store per-voxel min/max factors in the case of TOD
92 std::unique_ptr<Image<float>> counts;
93
94 };
95
96
97
98
99
100
101 template <typename value_type>
103 { MEMALIGN(MapWriter<value_type>)
104
105 public:
106 MapWriter (const Header& header, const std::string& name, const vox_stat_t voxel_statistic = V_SUM, const writer_dim type = GREYSCALE) :
108 buffer (Image<value_type>::scratch (header, "TWI " + str(writer_dims[type]) + " buffer"))
109 {
110 auto loop = Loop (buffer);
111 if (type == DEC || type == TOD) {
112
113 if (voxel_statistic == V_MIN) {
114 for (auto l = loop (buffer); l; ++l )
115 buffer.value() = std::numeric_limits<value_type>::max();
116 }
117/* shouldn't be needed: scratch IO class memset to zero already:
118 else {
119 buffer.zero();
120 } */
121
122 } else { // Greyscale and dixel
123
124 if (voxel_statistic == V_MIN) {
125 for (auto l = loop (buffer); l; ++l )
126 buffer.value() = std::numeric_limits<value_type>::max();
127 } else if (voxel_statistic == V_MAX) {
128 for (auto l = loop (buffer); l; ++l )
129 buffer.value() = std::numeric_limits<value_type>::lowest();
130 }
131/* shouldn't be needed: scratch IO class memset to zero already:
132 else {
133 buffer.zero();
134 }*/
135
136 }
137
138 // With TOD, hijack the counts buffer in voxel statistic min/max mode
139 // (use to store maximum / minimum factors and hence decide when to update the TOD)
140 if ((type != DEC && voxel_statistic == V_MEAN) ||
141 (type == TOD && (voxel_statistic == V_MIN || voxel_statistic == V_MAX)) ||
142 (type == DEC && voxel_statistic == V_SUM))
143 {
144 Header H_counts (header);
145 if (type == DEC || type == TOD)
146 H_counts.ndim() = 3;
147 counts.reset (new Image<float> (Image<float>::scratch (H_counts, "TWI streamline count buffer")));
148 }
149 }
150
151 MapWriter (const MapWriter&) = delete;
152
153 void finalise () override {
154
155 auto loop = Loop (buffer, 0, 3);
156 switch (voxel_statistic) {
157
158 case V_SUM:
159 if (type == DEC) {
160 assert (counts);
161 for (auto l = loop (buffer, *counts); l; ++l) {
162 const float total_weight = counts->value();
163 if (total_weight) {
164 auto value = get_dec();
165 const default_type norm = value.norm();
166 if (norm)
167 value *= total_weight / norm;
168 set_dec (value);
169 }
170 }
171 }
172 break;
173
174 case V_MIN:
175 for (auto l = loop (buffer); l; ++l ) {
176 if (buffer.value() == std::numeric_limits<value_type>::max())
177 buffer.value() = value_type(0);
178 }
179 break;
180
181 case V_MEAN:
182 if (type == GREYSCALE) {
183 assert (counts);
184 for (auto l = loop (buffer, *counts); l; ++l) {
185 if (counts->value())
186 buffer.value() /= value_type(counts->value());
187 }
188 }
189 else if (type == DEC) {
190 for (auto l = loop (buffer); l; ++l) {
191 auto value = get_dec();
192 if (value.squaredNorm())
193 set_dec (value.normalized());
194 }
195 }
196 else if (type == TOD) {
197 assert (counts);
198 for (auto l = loop (buffer, *counts); l; ++l) {
199 if (counts->value()) {
201 get_tod (value);
202 value *= (1.0 / counts->value());
203 set_tod (value);
204 }
205 }
206 } else { // Dixel
207 assert (counts);
208 // TODO For dixels, should this be a voxel mean i.e. normalise each non-zero voxel to unit density,
209 // rather than a per-dixel mean?
210 for (auto l = Loop (buffer) (buffer, *counts); l; ++l) {
211 if (counts->value())
212 buffer.value() /= default_type(counts->value());
213 }
214 }
215 break;
216
217 case V_MAX:
218 if (type == GREYSCALE) {
219 for (auto l = loop (buffer); l; ++l) {
220 if (buffer.value() == -std::numeric_limits<value_type>::max())
221 buffer.value() = value_type(0);
222 }
223 } else if (type == DIXEL) {
224 for (auto l = Loop (buffer) (buffer); l; ++l) {
225 if (buffer.value() == -std::numeric_limits<value_type>::max())
226 buffer.value() = value_type(0);
227 }
228 }
229 break;
230
231 default:
232 throw Exception ("Unknown / unhandled voxel statistic in MapWriter::finalise()");
233
234 }
235
236 save (buffer, output_image_name);
237 }
238
239
240 bool operator() (const SetVoxel& in) override { receive_greyscale (in); return true; }
241 bool operator() (const SetVoxelDEC& in) override { receive_dec (in); return true; }
242 bool operator() (const SetDixel& in) override { receive_dixel (in); return true; }
243 bool operator() (const SetVoxelTOD& in) override { receive_tod (in); return true; }
244
245 bool operator() (const Gaussian::SetVoxel& in) override { receive_greyscale (in); return true; }
246 bool operator() (const Gaussian::SetVoxelDEC& in) override { receive_dec (in); return true; }
247 bool operator() (const Gaussian::SetDixel& in) override { receive_dixel (in); return true; }
248 bool operator() (const Gaussian::SetVoxelTOD& in) override { receive_tod (in); return true; }
249
250
251 private:
252 Image<value_type> buffer;
253
254 // Template functions used so that the functors don't have to be written twice
255 // (once for standard TWI and one for Gaussian track-wise statistic)
256 template <class Cont> void receive_greyscale (const Cont&);
257 template <class Cont> void receive_dec (const Cont&);
258 template <class Cont> void receive_dixel (const Cont&);
259 template <class Cont> void receive_tod (const Cont&);
260
261 // Partially specialized template function to shut up modern compilers
262 // regarding using multiplication in a boolean context
263 inline void add (const default_type, const default_type);
264
265 // These acquire the TWI factor at any point along the streamline;
266 // For the standard SetVoxel classes, this is a single value 'factor' for the set as
267 // stored in SetVoxelExtras
268 // For the Gaussian SetVoxel classes, there is a factor per mapped element
269 default_type get_factor (const Voxel& element, const SetVoxel& set) const { return set.factor; }
270 default_type get_factor (const VoxelDEC& element, const SetVoxelDEC& set) const { return set.factor; }
271 default_type get_factor (const Dixel& element, const SetDixel& set) const { return set.factor; }
272 default_type get_factor (const VoxelTOD& element, const SetVoxelTOD& set) const { return set.factor; }
273 default_type get_factor (const Gaussian::Voxel& element, const Gaussian::SetVoxel& set) const { return element.get_factor(); }
274 default_type get_factor (const Gaussian::VoxelDEC& element, const Gaussian::SetVoxelDEC& set) const { return element.get_factor(); }
275 default_type get_factor (const Gaussian::Dixel& element, const Gaussian::SetDixel& set) const { return element.get_factor(); }
276 default_type get_factor (const Gaussian::VoxelTOD& element, const Gaussian::SetVoxelTOD& set) const { return element.get_factor(); }
277
278
279 // Convenience functions for Directionally-Encoded Colour processing
280 Eigen::Vector3d get_dec ();
281 void set_dec (const Eigen::Vector3d&);
282
283 // Convenience functions for Track Orientation Distribution processing
284 void get_tod ( VoxelTOD::vector_type&);
285 void set_tod (const VoxelTOD::vector_type&);
286
287 };
288
289
290
291
292
293
294
295 template <typename value_type>
296 template <class Cont>
297 void MapWriter<value_type>::receive_greyscale (const Cont& in)
298 {
299 assert (MapWriterBase::type == GREYSCALE);
300 for (const auto& i : in) {
301 assign_pos_of (i).to (buffer);
302 const default_type factor = get_factor (i, in);
303 const default_type weight = in.weight * i.get_length();
304 switch (voxel_statistic) {
305 case V_SUM: add (weight, factor); break;
306 case V_MIN: buffer.value() = std::min (default_type (buffer.value()), factor); break;
307 case V_MAX: buffer.value() = std::max (default_type (buffer.value()), factor); break;
308 case V_MEAN:
309 add (weight, factor);
310 assert (counts);
311 assign_pos_of (i).to (*counts);
312 counts->value() += weight;
313 break;
314 default:
315 throw Exception ("Unknown / unhandled voxel statistic in MapWriter::receive_greyscale()");
316 }
317 }
318 }
319
320
321
322 template <typename value_type>
323 template <class Cont>
324 void MapWriter<value_type>::receive_dec (const Cont& in)
325 {
326 assert (type == DEC);
327 for (const auto& i : in) {
328 assign_pos_of (i).to (buffer);
329 const default_type factor = get_factor (i, in);
330 const default_type weight = in.weight * i.get_length();
331 auto scaled_colour = i.get_colour();
332 scaled_colour *= factor;
333 const auto current_value = get_dec();
334 switch (voxel_statistic) {
335 case V_SUM:
336 set_dec (current_value + (scaled_colour * weight));
337 assert (counts);
338 assign_pos_of (i).to (*counts);
339 counts->value() += weight;
340 break;
341 case V_MIN:
342 if (scaled_colour.squaredNorm() < current_value.squaredNorm())
343 set_dec (scaled_colour);
344 break;
345 case V_MEAN:
346 set_dec (current_value + (scaled_colour * weight));
347 break;
348 case V_MAX:
349 if (scaled_colour.squaredNorm() > current_value.squaredNorm())
350 set_dec (scaled_colour);
351 break;
352 default:
353 throw Exception ("Unknown / unhandled voxel statistic in MapWriter::receive_dec()");
354 }
355 }
356 }
357
358
359
360 template <typename value_type>
361 template <class Cont>
362 void MapWriter<value_type>::receive_dixel (const Cont& in)
363 {
364 assert (type == DIXEL);
365 for (const auto& i : in) {
366 assign_pos_of (i, 0, 3).to (buffer);
367 buffer.index(3) = i.get_dir();
368 const default_type factor = get_factor (i, in);
369 const default_type weight = in.weight * i.get_length();
370 switch (voxel_statistic) {
371 case V_SUM: add (weight, factor); break;
372 case V_MIN: buffer.value() = std::min (default_type (buffer.value()), factor); break;
373 case V_MAX: buffer.value() = std::max (default_type (buffer.value()), factor); break;
374 case V_MEAN:
375 add (weight, factor);
376 assert (counts);
377 assign_pos_of (i, 0, 3).to (*counts);
378 counts->index(3) = i.get_dir();
379 counts->value() += weight;
380 break;
381 default:
382 throw Exception ("Unknown / unhandled voxel statistic in MapWriter::receive_dixel()");
383 }
384 }
385 }
386
387
388
389 template <typename value_type>
390 template <class Cont>
391 void MapWriter<value_type>::receive_tod (const Cont& in)
392 {
393 assert (type == TOD);
394 VoxelTOD::vector_type sh_coefs;
395 for (const auto& i : in) {
396 assign_pos_of (i, 0, 3).to (buffer);
397 const default_type factor = get_factor (i, in);
398 const default_type weight = in.weight * i.get_length();
399 get_tod (sh_coefs);
400 if (counts)
401 assign_pos_of (i, 0, 3).to (*counts);
402 switch (voxel_statistic) {
403 case V_SUM:
404 for (ssize_t index = 0; index != sh_coefs.size(); ++index)
405 sh_coefs[index] += i.get_tod()[index] * weight * factor;
406 set_tod (sh_coefs);
407 break;
408 // For TOD, need to store min/max factors - counts buffer is hijacked to do this
409 case V_MIN:
410 assert (counts);
411 if (factor < counts->value()) {
412 counts->value() = factor;
413 auto tod = i.get_tod();
414 tod *= factor;
415 set_tod (tod);
416 }
417 break;
418 case V_MAX:
419 assert (counts);
420 if (factor > counts->value()) {
421 counts->value() = factor;
422 auto tod = i.get_tod();
423 tod *= factor;
424 set_tod (tod);
425 }
426 break;
427 case V_MEAN:
428 assert (counts);
429 for (ssize_t index = 0; index != sh_coefs.size(); ++index)
430 sh_coefs[index] += i.get_tod()[index] * weight * factor;
431 set_tod (sh_coefs);
432 counts->value() += weight;
433 break;
434 default:
435 throw Exception ("Unknown / unhandled voxel statistic in MapWriter::receive_tod()");
436 }
437 }
438 }
439
440
441
442
443 template <>
444 inline void MapWriter<bool>::add (const default_type weight, const default_type factor)
445 {
446 if (weight && factor)
447 buffer.value() = true;
448 }
449
450 template <typename value_type>
451 inline void MapWriter<value_type>::add (const default_type weight, const default_type factor)
452 {
453 buffer.value() += weight * factor;
454 }
455
456
457
458
459
460 template <typename value_type>
461 Eigen::Vector3d MapWriter<value_type>::get_dec ()
462 {
463 assert (type == DEC);
464 Eigen::Vector3d value;
465 buffer.index(3) = 0; value[0] = buffer.value();
466 buffer.index(3)++; value[1] = buffer.value();
467 buffer.index(3)++; value[2] = buffer.value();
468 return value;
469 }
470
471 template <typename value_type>
472 void MapWriter<value_type>::set_dec (const Eigen::Vector3d& value)
473 {
474 assert (type == DEC);
475 buffer.index(3) = 0; buffer.value() = value[0];
476 buffer.index(3)++; buffer.value() = value[1];
477 buffer.index(3)++; buffer.value() = value[2];
478 }
479
480
481
482
483
484 template <typename value_type>
485 void MapWriter<value_type>::get_tod (VoxelTOD::vector_type& sh_coefs)
486 {
487 assert (type == TOD);
488 sh_coefs.resize (buffer.size(3));
489 for (auto l = Loop (3) (buffer); l; ++l)
490 sh_coefs[buffer.index(3)] = buffer.value();
491 }
492
493 template <typename value_type>
494 void MapWriter<value_type>::set_tod (const VoxelTOD::vector_type& sh_coefs)
495 {
496 assert (type == TOD);
497 assert (sh_coefs.size() == buffer.size(3));
498 for (auto l = Loop (3) (buffer); l; ++l)
499 buffer.value() = sh_coefs[buffer.index(3)];
500 }
501
502
503
504
505
506 }
507 }
508 }
509}
510
511#endif
512
513
514
std::unique_ptr< Image< float > > counts
Definition: writer.h:92
functions and classes related to image data input/output
Definition: image.h:41
FORCE_INLINE LoopAlongAxes Loop()
Definition: loop.h:419
VectorType::Scalar value(const VectorType &coefs, typename VectorType::Scalar cos_elevation, typename VectorType::Scalar cos_azimuth, typename VectorType::Scalar sin_azimuth, int lmax)
Definition: SH.h:233
MR::default_type value_type
Definition: typedefs.h:33
Eigen::Array< value_type, Eigen::Dynamic, 1 > vector_type
Definition: typedefs.h:35
void set(HeaderType &header, const List &stride)
set the strides of header from a vector<ssize_t>
Definition: stride.h:135
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
std::enable_if< is_adapter_type< typenamestd::remove_reference< ImageType >::type >::value, std::string >::type save(ImageType &&x, const std::string &filename, bool use_multi_threading=true)
save contents of an existing image to file (for debugging only)
Definition: image.h:523
size_t index
const std::string name
Definition: thread.h:108