Developer documentation
Version 3.0.3-105-gd3941f44
image_helpers.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 __image_helpers_h__
18#define __image_helpers_h__
19
20#include "datatype.h"
21#include "apply.h"
22#include "debug.h"
23
24namespace MR
25{
26
27
29 namespace {
30
31 template <class AxesType>
32 FORCE_INLINE auto __ndim (const AxesType& axes) -> decltype (axes.size(), size_t()) { return axes.size(); }
33
34 template <class AxesType>
35 FORCE_INLINE auto __ndim (const AxesType& axes) -> decltype (axes.ndim(), size_t()) { return axes.ndim(); }
36
37 template <class AxesType>
38 FORCE_INLINE auto __get_index (const AxesType& axes, size_t axis) -> decltype (axes.size(), ssize_t())
39 { return axes[axis]; }
40
41 template <class AxesType>
42 FORCE_INLINE auto __get_index (const AxesType& axes, size_t axis) -> decltype (axes.ndim(), ssize_t())
43 { return axes.index(axis); }
44
45 template <class AxesType>
46 FORCE_INLINE auto __set_index (AxesType& axes, size_t axis, ssize_t index) -> decltype (axes.size(), void())
47 { axes[axis] = index; }
48
49 template <class AxesType>
50 FORCE_INLINE auto __set_index (AxesType& axes, size_t axis, ssize_t index) -> decltype (axes.ndim(), void())
51 { axes.index(axis) = index; }
52
53
54 template <class... DestImageType>
55 struct __assign { NOMEMALIGN
56 __assign (size_t axis, ssize_t index) : axis (axis), index (index) { }
57 const size_t axis;
58 const ssize_t index;
59 template <class ImageType>
60 FORCE_INLINE void operator() (ImageType& x) { __set_index (x, axis, index); }
61 };
62
63 template <class... DestImageType>
64 struct __assign<std::tuple<DestImageType...>> { NOMEMALIGN
65 __assign (size_t axis, ssize_t index) : axis (axis), index (index) { }
66 const size_t axis;
67 const ssize_t index;
68 template <class ImageType>
69 FORCE_INLINE void operator() (ImageType& x) { apply (__assign<DestImageType...> (axis, index), x); }
70 };
71
72 template <class... DestImageType>
73 struct __max_axis { NOMEMALIGN
74 __max_axis (size_t& axis) : axis (axis) { }
75 size_t& axis;
76 template <class ImageType>
77 FORCE_INLINE void operator() (ImageType& x) { if (axis > __ndim(x)) axis = __ndim(x); }
78 };
79
80 template <class... DestImageType>
81 struct __max_axis<std::tuple<DestImageType...>> { NOMEMALIGN
82 __max_axis (size_t& axis) : axis (axis) { }
83 size_t& axis;
84 template <class ImageType>
85 FORCE_INLINE void operator() (ImageType& x) { apply (__max_axis<DestImageType...> (axis), x); }
86 };
87
88 template <class ImageType>
89 struct __assign_pos_axis_range { NOMEMALIGN
90 template <class... DestImageType>
91 FORCE_INLINE void to (DestImageType&... dest) const {
92 size_t last_axis = to_axis;
93 apply (__max_axis<DestImageType...> (last_axis), std::tie (ref, dest...));
94 for (size_t n = from_axis; n < last_axis; ++n)
95 apply (__assign<DestImageType...> (n, __get_index (ref, n)), std::tie (dest...));
96 }
97 const ImageType& ref;
98 const size_t from_axis, to_axis;
99 };
100
101
102 template <class ImageType, typename IntType>
103 struct __assign_pos_axes { NOMEMALIGN
104 template <class... DestImageType>
105 FORCE_INLINE void to (DestImageType&... dest) const {
106 for (auto a : axes)
107 apply (__assign<DestImageType...> (a, __get_index (ref, a)), std::tie (dest...));
108 }
109 const ImageType& ref;
110 const vector<IntType> axes;
111 };
112 }
113
114 template <typename ValueType> class Image;
116
117
119 template <class HeaderType, typename ReturnType>
120 struct enable_if_header_type { NOMEMALIGN
121 typedef decltype ((void) (
122 std::declval<HeaderType>().ndim() +
123 std::declval<HeaderType>().size(0) +
124 std::declval<HeaderType>().name().size()
125 ), std::declval<ReturnType>()) type;
126 };
127
129 template<typename HeaderType>
130 class is_header_type { NOMEMALIGN
131 typedef char yes[1], no[2];
132 template<typename C> static yes& test(typename enable_if_header_type<HeaderType,int>::type);
133 template<typename C> static no& test(...);
134 public:
135 static bool const value = sizeof(test<HeaderType>(0)) == sizeof(yes);
136 };
137
138
139
140
142 template <class ImageType, typename ReturnType>
143 struct enable_if_image_type { NOMEMALIGN
144 typedef decltype ((void) (
145 std::declval<ImageType>().ndim() +
146 std::declval<ImageType>().size(0) +
147 std::declval<ImageType>().name().size() +
148 std::declval<ImageType>().value() +
149 std::declval<ImageType>().index(0)
150 ), std::declval<ReturnType>()) type;
151 };
152
153
155 template<typename ImageType>
156 class is_image_type { NOMEMALIGN
157 typedef char yes[1], no[2];
158 template<typename C> static yes& test(typename enable_if_image_type<ImageType,int>::type);
159 template<typename C> static no& test(...);
160 public:
161 static bool const value = sizeof(test<ImageType>(0)) == sizeof(yes);
162 };
163
164
165
166
167
168
170 template<class ImageType>
171 struct is_pure_image { NOMEMALIGN
172 static bool const value = std::is_same<ImageType, ::MR::Image<typename ImageType::value_type>>::value;
173 };
174
176 template<class ImageType>
177 struct is_adapter_type { NOMEMALIGN
179 };
180
181
182
183
185
193 template <class ImageType>
194 FORCE_INLINE __assign_pos_axis_range<ImageType>
195 assign_pos_of (const ImageType& reference, size_t from_axis = 0, size_t to_axis = std::numeric_limits<size_t>::max())
196 {
197 return { reference, from_axis, to_axis };
198 }
199
201
210 template <class ImageType, typename IntType>
211 FORCE_INLINE __assign_pos_axes<ImageType, IntType>
212 assign_pos_of (const ImageType& reference, const vector<IntType>& axes)
213 {
214 return { reference, axes };
215 }
216
217 template <class ImageType, typename IntType>
218 FORCE_INLINE __assign_pos_axes<ImageType, IntType>
219 assign_pos_of (const ImageType& reference, const vector<IntType>&& axes)
220 {
221 return assign_pos_of (reference, axes);
222 }
223
224
225
226 template <class ImageType>
227 FORCE_INLINE bool is_out_of_bounds (const ImageType& image,
228 size_t from_axis = 0, size_t to_axis = std::numeric_limits<size_t>::max())
229 {
230 for (size_t n = from_axis; n < std::min<size_t> (to_axis, image.ndim()); ++n)
231 if (image.index(n) < 0 || image.index(n) >= image.size(n))
232 return true;
233 return false;
234 }
235
236 template <class HeaderType, class VectorType>
237 FORCE_INLINE typename std::enable_if<!std::is_arithmetic<VectorType>::value, bool>::type is_out_of_bounds (const HeaderType& header, const VectorType& pos,
238 size_t from_axis = 0, size_t to_axis = std::numeric_limits<size_t>::max())
239 {
240 for (size_t n = from_axis; n < std::min<size_t> (to_axis, header.ndim()); ++n)
241 if (pos[n] < 0 || pos[n] >= header.size(n))
242 return true;
243 return false;
244 }
245
248 template <class HeaderType>
249 FORCE_INLINE void check_3D_nonunity (const HeaderType& in)
250 {
251 if (in.ndim() < 3)
252 throw Exception ("Image \"" + in.name() + "\" does not represent spatial data (less than 3 dimensions)");
253 if (std::min ({ in.size(0), in.size(1), in.size(2) }) == 1)
254 throw Exception ("Image \"" + in.name() + "\" does not represent spatial data (has axis with size 1)");
255 }
256
260 template <class HeaderType>
261 FORCE_INLINE void check_effective_dimensionality (const HeaderType& in, size_t N)
262 {
263 if (in.ndim() < N)
264 throw Exception ("Image \"" + in.name() + "\" does not represent " + str(N) + "D data (too few dimensions)");
265 for (size_t i = N; i < in.ndim(); ++i)
266 if (in.size(i) != 1)
267 throw Exception ("Image \"" + in.name() + "\" does not represent " + str(N) + "D data (axis " + str(i) + " has size " + str(in.size(i)) + ")");
268 }
269
271 template <class HeaderType>
272 inline size_t voxel_count (const HeaderType& in, size_t from_axis = 0, size_t to_axis = std::numeric_limits<size_t>::max())
273 {
274 if (to_axis > in.ndim()) to_axis = in.ndim();
275 assert (from_axis < to_axis);
276 size_t fp = 1;
277 for (size_t n = from_axis; n < to_axis; ++n)
278 fp *= in.size (n);
279 return fp;
280 }
281
283 template <class HeaderType>
284 inline size_t voxel_count (const HeaderType& in, const char* specifier)
285 {
286 size_t fp = 1;
287 for (size_t n = 0; n < in.ndim(); ++n)
288 if (specifier[n] != ' ') fp *= in.size (n);
289 return fp;
290 }
291
293 template <class HeaderType>
294 inline size_t voxel_count (const HeaderType& in, const std::initializer_list<size_t> axes)
295 {
296 size_t fp = 1;
297 for (auto n : axes)
298 fp *= in.size (n);
299 return fp;
300 }
301
303 template <class HeaderType>
304 inline int64_t voxel_count (const HeaderType& in, const vector<size_t>& axes)
305 {
306 int64_t fp = 1;
307 for (size_t n = 0; n < axes.size(); ++n) {
308 assert (axes[n] < in.ndim());
309 fp *= in.size (axes[n]);
310 }
311 return fp;
312 }
313
314 template <typename ValueType>
315 inline int64_t footprint (int64_t count) {
316 return count * sizeof(ValueType);
317 }
318
319 template <>
320 inline int64_t footprint<bool> (int64_t count) {
321 return (count+7)/8;
322 }
323
324 inline int64_t footprint (int64_t count, DataType dtype) {
325 return dtype == DataType::Bit ? (count+7)/8 : count*dtype.bytes();
326 }
327
329 template <class HeaderType>
330 inline typename std::enable_if<std::is_class<HeaderType>::value, int64_t>::type footprint (const HeaderType& in, size_t from_dim = 0, size_t up_to_dim = std::numeric_limits<size_t>::max()) {
331 return footprint (voxel_count (in, from_dim, up_to_dim), in.datatype());
332 }
333
335 template <class HeaderType>
336 inline typename std::enable_if<std::is_class<HeaderType>::value, int64_t>::type footprint (const HeaderType& in, const char* specifier) {
337 return footprint (voxel_count (in, specifier), in.datatype());
338 }
339
340
341
342 template <class HeaderType1, class HeaderType2>
343 inline bool spacings_match (const HeaderType1& in1, const HeaderType2& in2, const double tol=0.0)
344 {
345 if (in1.ndim() != in2.ndim()) return false;
346 for (size_t n = 0; n < in1.ndim(); ++n)
347 if (abs(in1.spacing (n) - in2.spacing (n)) > tol * 0.5 * (in1.spacing (n) + in2.spacing (n))) return false;
348 return true;
349 }
350
351 template <class HeaderType1, class HeaderType2>
352 inline bool spacings_match (const HeaderType1& in1, const HeaderType2& in2, size_t from_axis, size_t to_axis, const double tol=0.0)
353 {
354 assert (from_axis < to_axis);
355 if (to_axis > in1.ndim() || to_axis > in2.ndim()) return false;
356 for (size_t n = from_axis; n < to_axis; ++n)
357 if (abs(in1.spacing (n) - in2.spacing (n)) > tol * 0.5 * (in1.spacing (n) + in2.spacing (n))) return false;
358 return true;
359 }
360
361 template <class HeaderType1, class HeaderType2>
362 inline bool spacings_match (const HeaderType1& in1, const HeaderType2& in2, const vector<size_t>& axes, const double tol=0.0)
363 {
364 for (size_t n = 0; n < axes.size(); ++n) {
365 if (in1.ndim() <= axes[n] || in2.ndim() <= axes[n]) return false;
366 if (abs(in1.spacing (axes[n]) - in2.spacing(axes[n])) > tol * 0.5 * (in1.spacing (axes[n]) + in2.spacing(axes[n]))) return false;
367 }
368 return true;
369 }
370
371
372
373 template <class HeaderType1, class HeaderType2>
374 inline bool dimensions_match (const HeaderType1& in1, const HeaderType2& in2)
375 {
376 if (in1.ndim() != in2.ndim()) return false;
377 for (size_t n = 0; n < in1.ndim(); ++n)
378 if (in1.size (n) != in2.size (n)) return false;
379 return true;
380 }
381
382 template <class HeaderType1, class HeaderType2>
383 inline bool dimensions_match (const HeaderType1& in1, const HeaderType2& in2, size_t from_axis, size_t to_axis)
384 {
385 assert (from_axis < to_axis);
386 if (to_axis > in1.ndim() || to_axis > in2.ndim()) return false;
387 for (size_t n = from_axis; n < to_axis; ++n)
388 if (in1.size (n) != in2.size (n)) return false;
389 return true;
390 }
391
392 template <class HeaderType1, class HeaderType2>
393 inline bool dimensions_match (const HeaderType1& in1, const HeaderType2& in2, const vector<size_t>& axes)
394 {
395 for (size_t n = 0; n < axes.size(); ++n) {
396 if (in1.ndim() <= axes[n] || in2.ndim() <= axes[n]) return false;
397 if (in1.size (axes[n]) != in2.size (axes[n])) return false;
398 }
399 return true;
400 }
401
402 namespace
403 {
404 template <class HeaderType>
405 std::string dim2str (const HeaderType& in)
406 {
407 std::string msg = str(in.size(0));
408 for (size_t axis = 1; axis != in.ndim(); ++axis)
409 msg += "," + str(in.size(axis));
410 return msg;
411 }
412 }
413
414 template <class HeaderType1, class HeaderType2>
415 inline void check_dimensions (const HeaderType1& in1, const HeaderType2& in2)
416 {
417 if (!dimensions_match (in1, in2))
418 throw Exception ("dimension mismatch between \"" + in1.name() + "\" and \"" + in2.name() + "\"" +
419 " (" + dim2str(in1) + " vs. " + dim2str(in2) + ")");
420 }
421
422 template <class HeaderType1, class HeaderType2>
423 inline void check_dimensions (const HeaderType1& in1, const HeaderType2& in2, size_t from_axis, size_t to_axis)
424 {
425 if (!dimensions_match (in1, in2, from_axis, to_axis))
426 throw Exception ("dimension mismatch between \"" + in1.name() + "\" and \"" + in2.name() + "\" between axes " + str(from_axis) + " and " + str(to_axis-1) +
427 " (" + dim2str(in1) + " vs. " + dim2str(in2) + ")");
428 }
429
430 template <class HeaderType1, class HeaderType2>
431 inline void check_dimensions (const HeaderType1& in1, const HeaderType2& in2, const vector<size_t>& axes)
432 {
433 if (!dimensions_match (in1, in2, axes))
434 throw Exception ("dimension mismatch between \"" + in1.name() + "\" and \"" + in2.name() + "\" for axes [" + join(axes, ",") + "]" +
435 " (" + dim2str(in1) + " vs. " + dim2str(in2) + ")");
436 }
437
438 template <class HeaderType1, class HeaderType2>
439 inline void check_voxel_grids_match_in_scanner_space (const HeaderType1& in1, const HeaderType2& in2, const double tol = 1.0e-3) {
440 Eigen::IOFormat FullPrecFmt(Eigen::FullPrecision, 0, ", ", "\n", "[", "]");
441 if (!voxel_grids_match_in_scanner_space (in1, in2, tol))
442 throw Exception ("images \"" + in1.name() + "\" and \"" + in2.name() + "\" do not have matching header transforms "
443 + "\n" + str(in1.transform().matrix().format(FullPrecFmt))
444 + "\nvs\n" + str(in2.transform().matrix().format(FullPrecFmt)) + ")");
445 }
446
449 template <class HeaderType1, class HeaderType2>
450 inline bool voxel_grids_match_in_scanner_space (const HeaderType1 in1, const HeaderType2 in2,
451 const double tol = 1.0e-3) {
452 if (!dimensions_match(in1, in2, 0, 3))
453 return false;
454
455 const Eigen::Vector3d vs1 (in1.spacing(0), in1.spacing(1), in1.spacing(2));
456 const Eigen::Vector3d vs2 (in2.spacing(0), in2.spacing(1), in2.spacing(2));
457
458 Eigen::MatrixXd voxel_coord = Eigen::MatrixXd::Zero(4,4);
459 voxel_coord.row(3).fill(1.0);
460 voxel_coord(0,1) = voxel_coord(0,2) = 0.5 * (in1.size(0) + in2.size(0));
461 voxel_coord(1,1) = voxel_coord(1,3) = 0.5 * (in1.size(1) + in2.size(1));
462 voxel_coord(2,2) = voxel_coord(2,3) = 0.5 * (in1.size(2) + in2.size(2));
463
464 double diff_in_scannercoord = std::sqrt((vs1.asDiagonal() * in1.transform().matrix() * voxel_coord -
465 vs2.asDiagonal() * in2.transform().matrix() * voxel_coord).colwise().squaredNorm().maxCoeff());
466 DEBUG ("transforms_match: FOV difference in scanner coordinates: "+str(diff_in_scannercoord));
467 return diff_in_scannercoord < (0.5*(vs1+vs2)).minCoeff() * tol;
468 }
469
470 template <class HeaderType>
471 inline void squeeze_dim (HeaderType& in, size_t from_axis = 3)
472 {
473 size_t n = in.ndim();
474 while (in.size(n-1) <= 1 && n > from_axis) --n;
475 in.ndim() = n;
476 }
477
478
479
480 namespace Helper
481 {
482
483 template <class ImageType>
484 class Index { NOMEMALIGN
485 public:
486 FORCE_INLINE Index (ImageType& image, size_t axis) : image (image), axis (axis) { assert (axis < image.ndim()); }
487 Index () = delete;
488 Index (const Index&) = delete;
489 FORCE_INLINE Index (Index&&) = default;
490
491 FORCE_INLINE operator ssize_t () const { return get (); }
492 FORCE_INLINE ssize_t operator++ () { move( 1); return get(); }
493 FORCE_INLINE ssize_t operator-- () { move(-1); return get(); }
494 FORCE_INLINE ssize_t operator++ (int) { auto p = get(); move( 1); return p; }
495 FORCE_INLINE ssize_t operator-- (int) { auto p = get(); move(-1); return p; }
496 FORCE_INLINE ssize_t operator+= (ssize_t increment) { move( increment); return get(); }
497 FORCE_INLINE ssize_t operator-= (ssize_t increment) { move(-increment); return get(); }
498 FORCE_INLINE ssize_t operator= (ssize_t position) { return ( *this += position - get() ); }
499 FORCE_INLINE ssize_t operator= (Index&& position) { return ( *this = position.get() ); }
500 friend std::ostream& operator<< (std::ostream& stream, const Index& p) { stream << p.get(); return stream; }
501 protected:
502 ImageType& image;
503 const size_t axis;
504 FORCE_INLINE ssize_t get () const { return image.get_index (axis); }
505 FORCE_INLINE void move (ssize_t amount) { image.move_index (axis, amount); }
506 };
507
508
509 template <class ImageType>
510 class Value { NOMEMALIGN
511 public:
512 using value_type = typename ImageType::value_type;
513 Value () = delete;
514 Value (const Value&) = delete;
515 FORCE_INLINE Value (Value&&) = default;
516
517 FORCE_INLINE Value (ImageType& parent) : image (parent) { }
518 FORCE_INLINE operator value_type () const { return get(); }
520 template <typename OtherType>
521 FORCE_INLINE value_type operator= (Value<OtherType>&& V) { return set (typename OtherType::value_type (V)); }
524 FORCE_INLINE value_type operator*= (value_type value) { return set (get() * value); }
525 FORCE_INLINE value_type operator/= (value_type value) { return set (get() / value); }
526 friend std::ostream& operator<< (std::ostream& stream, const Value& V) { stream << V.get(); return stream; }
527 private:
528 ImageType& image;
529 FORCE_INLINE value_type get () const { return image.get_value(); }
530 FORCE_INLINE value_type set (value_type value) { image.set_value (value); return value; }
531 };
532
533
534 template <class ImageType>
535 class ConstRow { NOMEMALIGN
536 public:
537 ConstRow (ImageType& image, size_t axis) : axis (axis), image (image) { assert (axis >= 0 && axis < image.ndim()); }
538 ssize_t size () const { return image.size (axis); }
539 typename ImageType::value_type operator[] (ssize_t n) const { image.index (axis) = n; return image.value(); }
540 const size_t axis;
541 protected:
542 ImageType& image;
543 template <typename, int, int, int, int, int> friend class Eigen::Matrix;
544 template <class Derived> friend class Eigen::MatrixBase;
545 template <class OtherImageType> friend class Row;
546 };
547
548
549 template <class ImageType>
550 class Row :
551 public ConstRow<ImageType>
552 { NOMEMALIGN
553 public:
554
555 using value_type = typename ImageType::value_type;
556
557 Row (ImageType& image, size_t axis) : ConstRow<ImageType> (image, axis) { }
558
559 template <class OtherImageType>
560 Row (ConstRow<OtherImageType>&& other) {
561 assert (image.size(axis) == other.image.size(other.axis));
562 for (image.index(axis) = 0, other.image.index(other.axis);
563 image.index(axis) < image.size(axis);
564 ++image.index(axis), ++other.image.index(other.axis))
565 image.value() = typename OtherImageType::value_type (other.image.value());
566 }
567
568 using ConstRow<ImageType>::image;
570
571#define MRTRIX_OP(ARG) \
572 template <class Derived> \
573 FORCE_INLINE void operator ARG (const Eigen::MatrixBase<Derived>& vec) { \
574 assert (vec.rows() == image.size(axis)); \
575 assert (vec.cols() == 1); \
576 for (image.index(axis) = 0; image.index(axis) < image.size(axis); ++image.index(axis)) \
577 image.value() ARG vec[image.index(axis)]; \
578 }
579 MRTRIX_OP(=);
580 MRTRIX_OP(+=);
581 MRTRIX_OP(-=);
582#undef MRTRIX_OP
583
584#define MRTRIX_OP(ARG) \
585 FORCE_INLINE void operator ARG (value_type val) { \
586 for (image.index(axis) = 0; image.index(axis) < image.size(axis); ++image.index(axis)) \
587 image.value() ARG val; \
588 }
589 MRTRIX_OP(=);
590 MRTRIX_OP(+=);
591 MRTRIX_OP(-=);
592 MRTRIX_OP(*=);
593 MRTRIX_OP(/=);
594#undef MRTRIX_OP
595
596 FORCE_INLINE void operator= (Row&& other) {
597 assert (image.size(axis) == other.image.size(other.axis));
598 for (image.index(axis) = 0, other.image.index(other.axis) = 0;
599 image.index(axis) < image.size(axis);
600 ++image.index(axis), ++other.image.index(other.axis))
601 image.value() = other.image.value();
602 }
603
604#define MRTRIX_OP(ARG) \
605 template <class OtherImageType> \
606 FORCE_INLINE void operator ARG (ConstRow<OtherImageType>&& other) { \
607 assert (image.size(axis) == other.image.size(other.axis)); \
608 for (image.index(axis) = 0, other.image.index(other.axis) = 0; \
609 image.index(axis) < image.size(axis); \
610 ++image.index(axis), ++other.image.index(other.axis)) \
611 image.value() ARG typename OtherImageType::value_type (other.image.value()); \
612 }
613 MRTRIX_OP(=);
614 MRTRIX_OP(+=);
615 MRTRIX_OP(-=);
616#undef MRTRIX_OP
617
618 };
619
620
621
622 }
623
624
625 template <class Derived, typename ValueType>
626 class ImageBase
627 { MEMALIGN (ImageBase<Derived,ValueType>)
628 public:
629 using value_type = ValueType;
630
631 FORCE_INLINE Helper::Index<Derived> index (size_t axis) { return { static_cast<Derived&> (*this), axis }; }
632 FORCE_INLINE ssize_t index (size_t axis) const { return static_cast<const Derived*>(this)->get_index (axis); }
633
634 FORCE_INLINE Helper::Value<Derived> value () { return { static_cast<Derived&> (*this) }; }
635 FORCE_INLINE ValueType value () const { return static_cast<const Derived*>(this)->get_value(); }
636
638
651 FORCE_INLINE Helper::ConstRow<Derived> row (size_t axis) const { return { static_cast<Derived&> (*this), axis }; }
652 FORCE_INLINE Helper::Row<Derived> row (size_t axis) { return { static_cast<Derived&> (*this), axis }; }
653 };
654
655
656
657}
658
659#endif
660
661
662
663
664
Array & operator=(const MR::Helper::ConstRow< ImageType > &row)
Definition: array.h:25
static constexpr uint8_t Bit
Definition: datatype.h:142
Matrix(const MR::Helper::ConstRow< ImageType > &row)
Definition: matrix.h:17
Derived & operator-=(const MR::Helper::ConstRow< ImageType > &row)
Definition: dense_base.h:29
Derived & operator+=(const MR::Helper::ConstRow< ImageType > &row)
Definition: dense_base.h:28
#define DEBUG(msg)
Definition: exception.h:75
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
#define MRTRIX_OP(ARG)
#define NOMEMALIGN
Definition: memory.h:22
std::ostream & operator<<(std::ostream &stream, const App::ParsedArgument &arg)
Definition: app.h:482
@ Value
Definition: linear.h:87
MR::default_type value_type
Definition: typedefs.h:33
void set(HeaderType &header, const List &stride)
set the strides of header from a vector<ssize_t>
Definition: stride.h:135
List get(const HeaderType &header)
return the strides of header as a vector<ssize_t>
Definition: stride.h:125
Definition: base.h:24
void apply(F &&f, T &&t)
invoke f(x) for each entry in t
Definition: apply.h:82
std::string join(const vector< std::string > &V, const std::string &delimiter)
Definition: mrtrix.h:498
constexpr std::enable_if< std::is_arithmetic< X >::value &&std::is_unsigned< X >::value, X >::type abs(X x)
Definition: types.h:297
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
T to(const std::string &string)
Definition: mrtrix.h:260
Definition: types.h:303
int axis
size_t index
#define MEMALIGN(...)
Definition: types.h:185
#define FORCE_INLINE
Definition: types.h:156