RNifti Fast R and C++ Access to NIfTI Images

NiftiImage.h
1 #ifndef _NIFTI_IMAGE_H_
2 #define _NIFTI_IMAGE_H_
3
4
5 #ifdef USING_R
6
7 #include <Rcpp.h>
8
9 // Defined since R 3.1.0, according to Tomas Kalibera, but there's no reason to break compatibility with 3.0.x
10 #ifndef MAYBE_SHARED
11 #define MAYBE_SHARED(x) (NAMED(x) > 1)
12 #endif
13
14 #else
15
16 #define R_NegInf -INFINITY
17
18 #include <stdint.h>
19 #include <cstddef>
20 #include <cmath>
21 #include <string>
22 #include <sstream>
23 #include <vector>
24 #include <complex>
25 #include <stdexcept>
26 #include <algorithm>
27 #include <map>
28 #include <locale>
29 #include <limits>
30
31 #endif
32
33
34 #include "niftilib/nifti1_io.h"
35
44 namespace RNifti {
45
46 typedef std::complex<float> complex64_t;
47 typedef std::complex<double> complex128_t;
48
55 struct rgba32_t
56 {
57 union ValueType {
58 int packed;
59 unsigned char bytes[4];
60 };
61 ValueType value;
62 rgba32_t () { value.packed = 0; }
63 };
64
72 class NiftiImageData
73 {
74 public:
75 double slope;
76 double intercept;
78 protected:
82 struct TypeHandler
83 {
84 virtual ~TypeHandler() {}
85 virtual size_t size () const { return 0; }
86 virtual bool hasNaN () const { return false; }
87 virtual complex128_t getComplex (void *ptr) const { return complex128_t(0.0, 0.0); }
88 virtual double getDouble (void *ptr) const { return 0.0; }
89 virtual int getInt (void *ptr) const { return 0; }
90 virtual rgba32_t getRgb (void *ptr) const { return rgba32_t(); }
91 virtual void setComplex (void *ptr, const complex128_t value) const {}
92 virtual void setDouble (void *ptr, const double value) const {}
93 virtual void setInt (void *ptr, const int value) const {}
94 virtual void setRgb (void *ptr, const rgba32_t value) const {}
95 virtual void minmax (void *ptr, const size_t length, double *min, double *max) const { *min = 0.0; *max = 0.0; }
96 };
97
101 template <typename Type, bool alpha = false>
102 struct ConcreteTypeHandler : public TypeHandler
103 {
104 size_t size () const { return (sizeof(Type)); }
105 bool hasNaN () const { return std::numeric_limits<Type>::has_quiet_NaN; }
106 complex128_t getComplex (void *ptr) const { return complex128_t(static_cast<double>(*static_cast<Type*>(ptr)), 0.0); }
107 double getDouble (void *ptr) const { return static_cast<double>(*static_cast<Type*>(ptr)); }
108 int getInt (void *ptr) const { return static_cast<int>(*static_cast<Type*>(ptr)); }
109 void setComplex (void *ptr, const complex128_t value) const
110 {
111 *(static_cast<Type*>(ptr)) = Type(value.real());
112 *(static_cast<Type*>(ptr) + 1) = Type(0);
113 }
114 void setDouble (void *ptr, const double value) const { *(static_cast<Type*>(ptr)) = Type(value); }
115 void setInt (void *ptr, const int value) const { *(static_cast<Type*>(ptr)) = Type(value); }
116 void minmax (void *ptr, const size_t length, double *min, double *max) const;
117 };
118
119 template <typename ElementType>
120 struct ConcreteTypeHandler<std::complex<ElementType>,false> : public TypeHandler
121 {
122 size_t size () const { return (sizeof(ElementType) * 2); }
123 bool hasNaN () const { return std::numeric_limits<ElementType>::has_quiet_NaN; }
124 std::complex<ElementType> getNative (void *ptr) const
125 {
126 const ElementType real = *static_cast<ElementType*>(ptr);
127 const ElementType imag = *(static_cast<ElementType*>(ptr) + 1);
128 return std::complex<ElementType>(real, imag);
129 }
130 void setNative (void *ptr, const std::complex<ElementType> native) const
131 {
132 *(static_cast<ElementType*>(ptr)) = native.real();
133 *(static_cast<ElementType*>(ptr) + 1) = native.imag();
134 }
135 complex128_t getComplex (void *ptr) const { return complex128_t(getNative(ptr)); }
136 double getDouble (void *ptr) const { return static_cast<double>(getNative(ptr).real()); }
137 int getInt (void *ptr) const { return static_cast<int>(getNative(ptr).real()); }
138 void setComplex (void *ptr, const complex128_t value) const { setNative(ptr, std::complex<ElementType>(value)); }
139 void setDouble (void *ptr, const double value) const { setNative(ptr, std::complex<ElementType>(value, 0.0)); }
140 void setInt (void *ptr, const int value) const { setNative(ptr, std::complex<ElementType>(static_cast<ElementType>(value), 0.0)); }
141 void minmax (void *ptr, const size_t length, double *min, double *max) const;
142 };
143
144 template <bool alpha>
145 struct ConcreteTypeHandler<rgba32_t,alpha> : public TypeHandler
146 {
147 size_t size () const { return alpha ? 4 : 3; }
148 int getInt (void *ptr) const { return getRgb(ptr).value.packed; }
149 rgba32_t getRgb (void *ptr) const
150 {
151 rgba32_t value;
152 unsigned char *source = static_cast<unsigned char *>(ptr);
153 std::copy(source, source + (alpha ? 4 : 3), value.value.bytes);
154 return value;
155 }
156 void setInt (void *ptr, const int value) const
157 {
158 rgba32_t native;
159 native.value.packed = value;
160 setRgb(ptr, native);
161 }
162 void setRgb (void *ptr, const rgba32_t value) const
163 {
164 unsigned char *target = static_cast<unsigned char *>(ptr);
165 std::copy(value.value.bytes, value.value.bytes + (alpha ? 4 : 3), target);
166 }
167 void minmax (void *ptr, const size_t length, double *min, double *max) const { *min = 0.0; *max = 255.0; }
168 };
169
175 TypeHandler * createHandler ()
176 {
177 if (_datatype == DT_NONE)
178 return NULL;
179
180 switch (_datatype)
181 {
182 case DT_UINT8: return new ConcreteTypeHandler<uint8_t>(); break;
183 case DT_INT16: return new ConcreteTypeHandler<int16_t>(); break;
184 case DT_INT32: return new ConcreteTypeHandler<int32_t>(); break;
185 case DT_FLOAT32: return new ConcreteTypeHandler<float>(); break;
186 case DT_FLOAT64: return new ConcreteTypeHandler<double>(); break;
187 case DT_INT8: return new ConcreteTypeHandler<int8_t>(); break;
188 case DT_UINT16: return new ConcreteTypeHandler<uint16_t>(); break;
189 case DT_UINT32: return new ConcreteTypeHandler<uint32_t>(); break;
190 case DT_INT64: return new ConcreteTypeHandler<int64_t>(); break;
191 case DT_UINT64: return new ConcreteTypeHandler<uint64_t>(); break;
192 case DT_COMPLEX64: return new ConcreteTypeHandler<complex64_t>(); break;
193 case DT_COMPLEX128: return new ConcreteTypeHandler<complex128_t>(); break;
194 case DT_RGB24: return new ConcreteTypeHandler<rgba32_t,false>(); break;
195 case DT_RGBA32: return new ConcreteTypeHandler<rgba32_t,true>(); break;
196
197 default:
198 throw std::runtime_error("Unsupported data type (" + std::string(nifti_datatype_string(_datatype)) + ")");
199 }
200 }
201
202 void *dataPtr;
203 int _datatype;
204 TypeHandler *handler;
205 size_t _length;
206 bool owner;
218 void init (void *data, const size_t length, const int datatype, const double slope, const double intercept, const bool alloc = true)
219 {
220 this->_length = length;
221 this->_datatype = datatype;
222 this->slope = slope;
223 this->intercept = intercept;
224
225 owner = false;
226 handler = createHandler();
227 if (handler == NULL)
228 dataPtr = NULL;
229 else if (alloc && data == NULL)
230 {
231 dataPtr = calloc(length, handler->size());
232 owner = true;
233 }
234 else
235 dataPtr = data;
236 }
237
244 void calibrateFrom (const NiftiImageData &data)
245 {
246 slope = 1.0;
247 intercept = 0.0;
248
249 if (this->isInteger())
250 {
251 double dataMin, dataMax, typeMin, typeMax;
252 data.minmax(&dataMin, &dataMax);
253 handler->minmax(NULL, 0, &typeMin, &typeMax);
254
255 // If the source type is floating-point but values are in range, we will just round them
256 if (dataMin < typeMin || dataMax > typeMax)
257 {
258 slope = (dataMax - dataMin) / (typeMax - typeMin);
259 intercept = dataMin - (slope) * typeMin;
260 }
261 }
262 }
263
264 public:
268 struct Element
269 {
270 private:
271 const NiftiImageData &parent;
272 void *ptr;
273
274 public:
281 Element (const NiftiImageData &parent, void *ptr = NULL)
282 : parent(parent)
283 {
284 this->ptr = (ptr == NULL ? parent.dataPtr : ptr);
285 }
286
294 template <typename SourceType>
295 Element & operator= (const SourceType &value);
296
302 Element & operator= (const Element &other);
303
307 template <typename TargetType>
308 operator TargetType() const
309 {
310 if (parent.isScaled())
311 return TargetType(parent.handler->getDouble(ptr) * parent.slope + parent.intercept);
312 else if (std::numeric_limits<TargetType>::is_integer)
313 return TargetType(parent.handler->getInt(ptr));
314 else
315 return TargetType(parent.handler->getDouble(ptr));
316 }
317
318 template <typename ElementType>
319 operator std::complex<ElementType>() const
320 {
321 if (parent.isScaled())
322 return std::complex<ElementType>(parent.handler->getComplex(ptr) * parent.slope + complex128_t(parent.intercept, parent.intercept));
323 else
324 return std::complex<ElementType>(parent.handler->getComplex(ptr));
325 }
326
327 #ifdef USING_R
328
331 operator Rcomplex() const
332 {
333 const complex128_t value = parent.handler->getComplex(ptr);
334 Rcomplex rValue = { value.real(), value.imag() };
335 if (parent.isScaled())
336 {
337 rValue.r = rValue.r * parent.slope + parent.intercept;
338 rValue.i = rValue.i * parent.slope + parent.intercept;
339 }
340 return rValue;
341 }
342 #endif
343
344 operator rgba32_t() const
345 {
346 return parent.handler->getRgb(ptr);
347 }
348 };
349
353 class Iterator : public std::iterator<std::random_access_iterator_tag, Element>
354 {
355 private:
356 const NiftiImageData &parent;
357 void *ptr;
358 size_t step;
359
360 public:
368 Iterator (const NiftiImageData &parent, void *ptr = NULL, const size_t step = 0)
369 : parent(parent)
370 {
371 this->ptr = (ptr == NULL ? parent.dataPtr : ptr);
372 this->step = (step == 0 ? parent.handler->size() : step);
373 }
374
379 Iterator (const Iterator &other)
380 : parent(other.parent), ptr(other.ptr), step(other.step) {}
381
382 Iterator & operator++ () { ptr = static_cast<char*>(ptr) + step; return *this; }
383 Iterator operator++ (int) { Iterator copy(*this); ptr = static_cast<char*>(ptr) + step; return copy; }
384 Iterator operator+ (ptrdiff_t n) const
385 {
386 void *newptr = static_cast<char*>(ptr) + (n * step);
387 return Iterator(parent, newptr, step);
388 }
389 Iterator & operator-- () { ptr = static_cast<char*>(ptr) - step; return *this; }
390 Iterator operator-- (int) { Iterator copy(*this); ptr = static_cast<char*>(ptr) - step; return copy; }
391 Iterator operator- (ptrdiff_t n) const
392 {
393 void *newptr = static_cast<char*>(ptr) - (n * step);
394 return Iterator(parent, newptr, step);
395 }
396
397 ptrdiff_t operator- (const Iterator &other) const
398 {
399 const ptrdiff_t difference = static_cast<char*>(ptr) - static_cast<char*>(other.ptr);
400 return difference / step;
401 }
402
403 bool operator== (const Iterator &other) const { return (ptr==other.ptr && step==other.step); }
404 bool operator!= (const Iterator &other) const { return (ptr!=other.ptr || step!=other.step); }
405 bool operator> (const Iterator &other) const { return (ptr > other.ptr); }
406 bool operator< (const Iterator &other) const { return (ptr < other.ptr); }
407
408 const Element operator* () const { return Element(parent, ptr); }
409 Element operator* () { return Element(parent, ptr); }
410 const Element operator[] (const size_t i) const { return Element(parent, static_cast<char*>(ptr) + (i * step)); }
411 Element operator[] (const size_t i) { return Element(parent, static_cast<char*>(ptr) + (i * step)); }
412 };
413
417 NiftiImageData ()
418 : slope(1.0), intercept(0.0), dataPtr(NULL), _datatype(DT_NONE), handler(NULL), _length(0), owner(false) {}
419
429 NiftiImageData (void *data, const size_t length, const int datatype, const double slope = 1.0, const double intercept = 0.0)
430 {
431 init(data, length, datatype, slope, intercept);
432 }
433
438 NiftiImageData (nifti_image *image)
439 {
440 if (image == NULL)
441 init(NULL, 0, DT_NONE, 0.0, 0.0, false);
442 else
443 init(image->data, image->nvox, image->datatype, static_cast<double>(image->scl_slope), static_cast<double>(image->scl_inter), false);
444 }
445
453 NiftiImageData (const NiftiImageData &source, const int datatype = DT_NONE)
454 {
455 init(NULL, source.length(), datatype == DT_NONE ? source.datatype() : datatype, source.slope, source.intercept);
456
457 if (datatype == DT_NONE || datatype == source.datatype())
458 memcpy(dataPtr, source.dataPtr, source.totalBytes());
459 else
460 {
461 calibrateFrom(source);
462 std::copy(source.begin(), source.end(), this->begin());
463 }
464 }
465
472 template <class InputIterator>
473 NiftiImageData (InputIterator from, InputIterator to, const int datatype)
474 {
475 const size_t length = static_cast<size_t>(std::distance(from, to));
476 init(NULL, length, datatype, 1.0, 0.0);
477 std::copy(from, to, this->begin());
478 }
479
483 virtual ~NiftiImageData ()
484 {
485 delete handler;
486 if (owner)
487 free(dataPtr);
488 }
489
495 NiftiImageData & operator= (const NiftiImageData &source)
496 {
497 if (source.dataPtr != NULL)
498 {
499 // Free the old data, if we allocated it
500 if (owner)
501 free(dataPtr);
502 init(NULL, source.length(), source.datatype(), source.slope, source.intercept);
503 memcpy(dataPtr, source.dataPtr, source.totalBytes());
504 }
505 return *this;
506 }
507
508 void * blob () const { return dataPtr; }
509 int datatype () const { return _datatype; }
510 size_t length () const { return _length; }
511 size_t size () const { return _length; }
514 size_t bytesPerPixel () const { return (handler == NULL ? 0 : handler->size()); }
515
517 size_t totalBytes () const { return _length * bytesPerPixel(); }
518
523 bool isEmpty () const { return (dataPtr == NULL); }
524
530 bool isScaled () const { return (slope != 0.0 && (slope != 1.0 || intercept != 0.0)); }
531
536 bool isComplex () const { return (_datatype == DT_COMPLEX64 || _datatype == DT_COMPLEX128); }
537
543 bool isFloatingPoint () const { return (_datatype == DT_FLOAT32 || _datatype == DT_FLOAT64); }
544
549 bool isInteger () const { return nifti_is_inttype(_datatype); }
550
555 bool isRgb () const { return (_datatype == DT_RGB24 || _datatype == DT_RGBA32); }
556
561 NiftiImageData unscaled () const { return NiftiImageData(dataPtr, _length, _datatype); }
562
567 NiftiImageData & disown () { this->owner = false; return *this; }
568
570 const Iterator begin () const { return Iterator(*this); }
571
573 const Iterator end () const { return Iterator(*this, static_cast<char*>(dataPtr) + totalBytes()); }
574
576 Iterator begin () { return Iterator(*this); }
577
579 Iterator end () { return Iterator(*this, static_cast<char*>(dataPtr) + totalBytes()); }
580
586 const Element operator[] (const size_t i) const { return Element(*this, static_cast<char*>(dataPtr) + (i * bytesPerPixel())); }
587
593 Element operator[] (const size_t i) { return Element(*this, static_cast<char*>(dataPtr) + (i * bytesPerPixel())); }
594
602 void minmax (double *min, double *max) const
603 {
604 if (handler == NULL)
605 {
606 *min = 0.0;
607 *max = 0.0;
608 }
609 else
610 handler->minmax(dataPtr, _length, min, max);
611 }
612 };
613
614
615 // R provides an NaN (NA) value for integers
616 #ifdef USING_R
617 template <>
618 inline bool NiftiImageData::ConcreteTypeHandler<int>::hasNaN () const { return true; }
619 #endif
620
621
628 class NiftiImage
629 {
630 public:
635 struct Block
636 {
637 const NiftiImage &image;
638 const int dimension;
639 const int index;
648 Block (const NiftiImage &image, const int dimension, const int index)
649 : image(image), dimension(dimension), index(index)
650 {
651 if (dimension != image->ndim)
652 throw std::runtime_error("Blocks must be along the last dimension in the image");
653 }
654
663 Block & operator= (const NiftiImage &source)
664 {
665 if (source->datatype != image->datatype)
666 throw std::runtime_error("New data does not have the same datatype as the target block");
667 if (source->scl_slope != image->scl_slope || source->scl_inter != image->scl_inter)
668 throw std::runtime_error("New data does not have the same scale parameters as the target block");
669
670 size_t blockSize = 1;
671 for (int i=1; i<dimension; i++)
672 blockSize *= image->dim[i];
673
674 if (blockSize != source->nvox)
675 throw std::runtime_error("New data does not have the same size as the target block");
676
677 blockSize *= image->nbyper;
678 memcpy(static_cast<char*>(image->data) + blockSize*index, source->data, blockSize);
679 return *this;
680 }
681
686 NiftiImageData data () const
687 {
688 if (image.isNull())
689 return NiftiImageData();
690 else
691 {
692 size_t blockSize = 1;
693 for (int i=1; i<dimension; i++)
694 blockSize *= image->dim[i];
695 return NiftiImageData(static_cast<char*>(image->data) + blockSize * index * image->nbyper, blockSize, image->datatype, static_cast<double>(image->scl_slope), static_cast<double>(image->scl_inter));
696 }
697 }
698
706 template <typename TargetType>
707 std::vector<TargetType> getData (const bool useSlope = true) const;
708 };
709
710 #ifdef USING_R
711
717 static int sexpTypeToNiftiType (const int sexpType)
718 {
719 if (sexpType == INTSXP || sexpType == LGLSXP)
720 return DT_INT32;
721 else if (sexpType == REALSXP)
722 return DT_FLOAT64;
723 else if (sexpType == CPLXSXP)
724 return DT_COMPLEX128;
725 else
726 throw std::runtime_error("Array elements must be numeric");
727 }
728 #endif
729
735 static mat33 xformToRotation (const mat44 matrix);
736
742 static std::string xformToString (const mat44 matrix);
743
750 static int fileVersion (const std::string &path);
751
752
753 protected:
754 nifti_image *image;
755 int *refCount;
763 void acquire (nifti_image * const image);
764
769 void acquire (const NiftiImage &source)
770 {
771 refCount = source.refCount;
772 acquire(source.image);
773 }
774
779 void release ();
780
785 void copy (const nifti_image *source);
786
791 void copy (const NiftiImage &source);
792
797 void copy (const Block &source);
798
799
800 #ifdef USING_R
801
807 void initFromNiftiS4 (const Rcpp::RObject &object, const bool copyData = true);
808
814 void initFromMriImage (const Rcpp::RObject &object, const bool copyData = true);
815
820 void initFromList (const Rcpp::RObject &object);
821
827 void initFromArray (const Rcpp::RObject &object, const bool copyData = true);
828
829 #endif
830
836 void initFromDims (const std::vector<int> &dim, const int datatype);
837
842 void updatePixdim (const std::vector<float> &pixdim);
843
848 void setPixunits (const std::vector<std::string> &pixunits);
849
850 public:
854 NiftiImage ()
855 : image(NULL), refCount(NULL) {}
856
863 NiftiImage (const NiftiImage &source, const bool copy = true)
864 : image(NULL), refCount(NULL)
865 {
866 if (copy)
867 this->copy(source);
868 else
869 acquire(source);
870 #ifndef NDEBUG
871 Rc_printf("Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
872 #endif
873 }
874
879 NiftiImage (const Block &source)
880 : image(NULL), refCount(NULL)
881 {
882 this->copy(source);
883 #ifndef NDEBUG
884 Rc_printf("Creating NiftiImage with pointer %p (from Block)\n", this->image);
885 #endif
886 }
887
894 NiftiImage (nifti_image * const image, const bool copy = false)
895 : image(NULL), refCount(NULL)
896 {
897 if (copy)
898 this->copy(image);
899 else
900 acquire(image);
901 #ifndef NDEBUG
902 Rc_printf("Creating NiftiImage with pointer %p (from pointer)\n", this->image);
903 #endif
904 }
905
911 NiftiImage (const std::vector<int> &dim, const int datatype);
912
918 NiftiImage (const std::vector<int> &dim, const std::string &datatype);
919
926 NiftiImage (const std::string &path, const bool readData = true);
927
934 NiftiImage (const std::string &path, const std::vector<int> &volumes);
935
936 #ifdef USING_R
937
947 NiftiImage (const SEXP object, const bool readData = true, const bool readOnly = false);
948 #endif
949
954 virtual ~NiftiImage () { release(); }
955
959 operator const nifti_image* () const { return image; }
960
964 operator nifti_image* () { return image; }
965
969 const nifti_image * operator-> () const { return image; }
970
974 nifti_image * operator-> () { return image; }
975
980 NiftiImage & operator= (const NiftiImage &source)
981 {
982 copy(source);
983 #ifndef NDEBUG
984 Rc_printf("Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
985 #endif
986 return *this;
987 }
988
994 NiftiImage & operator= (const Block &source)
995 {
996 copy(source);
997 #ifndef NDEBUG
998 Rc_printf("Creating NiftiImage with pointer %p (from Block)\n", this->image);
999 #endif
1000 return *this;
1001 }
1002
1010 NiftiImage & setPersistence (const bool persistent) { return *this; }
1011
1016 bool isNull () const { return (image == NULL); }
1017
1022 bool isShared () const { return (refCount != NULL && *refCount > 1); }
1023
1030 bool isPersistent () const { return false; }
1031
1037 bool isDataScaled () const { return (image != NULL && image->scl_slope != 0.0 && (image->scl_slope != 1.0 || image->scl_inter != 0.0)); }
1038
1043 int nDims () const
1044 {
1045 if (image == NULL)
1046 return 0;
1047 else
1048 return image->ndim;
1049 }
1050
1055 std::vector<int> dim () const
1056 {
1057 if (image == NULL)
1058 return std::vector<int>();
1059 else
1060 return std::vector<int>(image->dim+1, image->dim+image->ndim+1);
1061 }
1062
1067 std::vector<float> pixdim () const
1068 {
1069 if (image == NULL)
1070 return std::vector<float>();
1071 else
1072 return std::vector<float>(image->pixdim+1, image->pixdim+image->ndim+1);
1073 }
1074
1081 NiftiImage & drop ()
1082 {
1083 int ndim = image->ndim;
1084 while (image->dim[ndim] < 2)
1085 ndim--;
1086 image->dim[0] = image->ndim = ndim;
1087
1088 return *this;
1089 }
1090
1095 const NiftiImageData data () const { return NiftiImageData(image); }
1096
1101 NiftiImageData data () { return NiftiImageData(image); }
1102
1112 template <typename TargetType>
1113 std::vector<TargetType> getData (const bool useSlope = true) const;
1114
1122 NiftiImage & changeDatatype (const int datatype, const bool useSlope = false);
1123
1131 NiftiImage & changeDatatype (const std::string &datatype, const bool useSlope = false);
1132
1141 template <typename SourceType>
1142 NiftiImage & replaceData (const std::vector<SourceType> &data, const int datatype = DT_NONE);
1143
1150 NiftiImage & replaceData (const NiftiImageData &data);
1151
1156 NiftiImage & dropData ()
1157 {
1158 nifti_image_unload(image);
1159 return *this;
1160 }
1161
1168 NiftiImage & rescale (const std::vector<float> &scales);
1169
1178 NiftiImage & reorient (const int i, const int j, const int k);
1179
1188 NiftiImage & reorient (const std::string &orientation);
1189
1190 #ifdef USING_R
1191
1196 NiftiImage & update (const Rcpp::RObject &object);
1197 #endif
1198
1204 mat44 xform (const bool preferQuaternion = true) const;
1205
1210 int nBlocks () const { return (image == NULL ? 0 : image->dim[image->ndim]); }
1211
1219 const Block block (const int i) const { return Block(*this, nDims(), i); }
1220
1228 Block block (const int i) { return Block(*this, nDims(), i); }
1229
1235 const Block slice (const int i) const { return Block(*this, 3, i); }
1236
1242 Block slice (const int i) { return Block(*this, 3, i); }
1243
1249 const Block volume (const int i) const { return Block(*this, 4, i); }
1250
1256 Block volume (const int i) { return Block(*this, 4, i); }
1257
1263 int nChannels () const
1264 {
1265 if (image == NULL)
1266 return 0;
1267 else
1268 {
1269 switch (image->datatype)
1270 {
1271 case DT_NONE: return 0;
1272 case DT_RGB24: return 3;
1273 case DT_RGBA32: return 4;
1274 default: return 1;
1275 }
1276 }
1277 }
1278
1283 size_t nVoxels () const { return (image == NULL ? 0 : image->nvox); }
1284
1291 std::pair<std::string,std::string> toFile (const std::string fileName, const int datatype = DT_NONE) const;
1292
1299 std::pair<std::string,std::string> toFile (const std::string fileName, const std::string &datatype) const;
1300
1301 #ifdef USING_R
1302
1307 Rcpp::RObject toArray () const;
1308
1314 Rcpp::RObject toPointer (const std::string label) const;
1315
1322 Rcpp::RObject toArrayOrPointer (const bool internal, const std::string label) const;
1323
1328 Rcpp::RObject headerToList () const;
1329
1330 #endif
1331
1332 };
1333
1334 // Include implementations
1335 #include "RNifti/NiftiImage_impl.h"
1336
1337 } // main namespace
1338
1339 #endif
RNifti::NiftiImage::Block::data
NiftiImageData data() const
Obtain the data within the block.
Definition: NiftiImage.h:686
RNifti::NiftiImageData::TypeHandler
Abstract inner class defining the type-specific functions required in concrete subclasses.
Definition: NiftiImage.h:82
RNifti::NiftiImage::initFromArray
void initFromArray(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an R array.
RNifti::NiftiImage::xformToString
static std::string xformToString(const mat44 matrix)
Convert a 4x4 xform matrix to a string describing its canonical axes.
RNifti::NiftiImageData::_datatype
int _datatype
Datatype code indicating the actual type of the elements.
Definition: NiftiImage.h:203
RNifti::rgba32_t
Simple RGB(A) type encapsulating an 8-bit colour value with optional opacity, which can also be set o...
Definition: NiftiImage.h:55
RNifti::NiftiImage::fileVersion
static int fileVersion(const std::string &path)
Get the NIfTI format version used by the file at the specified path.
RNifti::NiftiImageData::_length
size_t _length
The number of data elements in the blob.
Definition: NiftiImage.h:205
RNifti::NiftiImage::headerToList
Rcpp::RObject headerToList() const
Create an R list containing raw image metadata.
RNifti::NiftiImageData::slope
double slope
The slope term used to scale data values.
Definition: NiftiImage.h:75
RNifti::NiftiImage::xform
mat44 xform(const bool preferQuaternion=true) const
Obtain an xform matrix, indicating the orientation of the image.
RNifti::NiftiImageData::operator[]
const Element operator[](const size_t i) const
Indexing operator, returning a constant element.
Definition: NiftiImage.h:586
RNifti::NiftiImageData::Iterator
Iterator type for NiftiImageData, with Element as its value type.
Definition: NiftiImage.h:353
RNifti::NiftiImageData::datatype
int datatype() const
Return stored datatype code.
Definition: NiftiImage.h:509
RNifti::NiftiImage::Block::index
const int index
The location along dimension.
Definition: NiftiImage.h:639
RNifti::NiftiImage::image
nifti_image * image
The wrapped nifti_image pointer.
Definition: NiftiImage.h:754
RNifti::NiftiImage::Block::operator=
Block & operator=(const NiftiImage &source)
Copy assignment operator, which allows a block in one image to be replaced with the contents of anoth...
Definition: NiftiImage.h:663
RNifti::NiftiImage::drop
NiftiImage & drop()
Drop unitary dimensions.
Definition: NiftiImage.h:1081
RNifti::NiftiImageData::NiftiImageData
NiftiImageData(void *data, const size_t length, const int datatype, const double slope=1.0, const double intercept=0.0)
Primary constructor.
Definition: NiftiImage.h:429
RNifti::NiftiImage::Block::Block
Block(const NiftiImage &image, const int dimension, const int index)
Standard constructor for this class.
Definition: NiftiImage.h:648
RNifti::NiftiImage::slice
const Block slice(const int i) const
Extract a slice block from a 3D image.
Definition: NiftiImage.h:1235
RNifti::NiftiImageData::calibrateFrom
void calibrateFrom(const NiftiImageData &data)
Update the slope and intercept to cover the range of another data object.
Definition: NiftiImage.h:244
RNifti::NiftiImage::Block::getData
std::vector< TargetType > getData(const bool useSlope=true) const
Extract a vector of data from a block, casting it to any required element type.
RNifti::NiftiImageData::isFloatingPoint
bool isFloatingPoint() const
Determine whether the datatype is floating point.
Definition: NiftiImage.h:543
RNifti::NiftiImage::slice
Block slice(const int i)
Extract a slice block from a 3D image.
Definition: NiftiImage.h:1242
RNifti::NiftiImage::nDims
int nDims() const
Return the number of dimensions in the image.
Definition: NiftiImage.h:1043
RNifti::NiftiImageData::size
size_t size() const
Return the number of elements in the data.
Definition: NiftiImage.h:511
RNifti::NiftiImageData::createHandler
TypeHandler * createHandler()
Create a concrete type handler appropriate to the datatype code stored with the data.
Definition: NiftiImage.h:175
RNifti::NiftiImage::Block
Inner class referring to a subset of an image.
Definition: NiftiImage.h:635
RNifti::NiftiImageData::NiftiImageData
NiftiImageData(InputIterator from, InputIterator to, const int datatype)
Iterator-based constructor.
Definition: NiftiImage.h:473
RNifti::NiftiImage::setPixunits
void setPixunits(const std::vector< std::string > &pixunits)
Modify the pixel dimension units.
RNifti::NiftiImageData::NiftiImageData
NiftiImageData(const NiftiImageData &source, const int datatype=DT_NONE)
Copy constructor with optional type conversion.
Definition: NiftiImage.h:453
RNifti::NiftiImageData
Wrapper class encapsulating a NIfTI data blob, with responsibility for handling data scaling and poly...
Definition: NiftiImage.h:72
RNifti::NiftiImage::NiftiImage
NiftiImage(const Block &source)
Initialise from a block, copying in the data.
Definition: NiftiImage.h:879
RNifti::NiftiImage::data
const NiftiImageData data() const
Obtain the pixel data within the image.
Definition: NiftiImage.h:1095
RNifti::NiftiImageData::isInteger
bool isInteger() const
Determine whether the datatype is an integer type.
Definition: NiftiImage.h:549
RNifti::NiftiImage::initFromList
void initFromList(const Rcpp::RObject &object)
Initialise the object from an R list with named elements, which can only contain metadata.
RNifti::NiftiImage::data
NiftiImageData data()
Obtain the pixel data within the image.
Definition: NiftiImage.h:1101
RNifti::NiftiImage::NiftiImage
NiftiImage(nifti_image *const image, const bool copy=false)
Initialise using an existing nifti_image pointer.
Definition: NiftiImage.h:894
RNifti::NiftiImageData::unscaled
NiftiImageData unscaled() const
Return a similar object to the callee, but with the slope and intercept values reset.
Definition: NiftiImage.h:561
RNifti::NiftiImage::initFromNiftiS4
void initFromNiftiS4(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an S4 object of class "nifti".
RNifti::NiftiImageData::length
size_t length() const
Return the number of elements in the data.
Definition: NiftiImage.h:510
RNifti::NiftiImage::~NiftiImage
virtual ~NiftiImage()
Destructor which decrements the reference counter, and releases the wrapped pointer if the counter dr...
Definition: NiftiImage.h:954
RNifti::NiftiImage::replaceData
NiftiImage & replaceData(const std::vector< SourceType > &data, const int datatype=DT_NONE)
Replace the pixel data in the image with the contents of a vector.
RNifti::NiftiImage::sexpTypeToNiftiType
static int sexpTypeToNiftiType(const int sexpType)
Convert between R SEXP object type and nifti_image datatype codes.
Definition: NiftiImage.h:717
RNifti::NiftiImageData::~NiftiImageData
virtual ~NiftiImageData()
Destructor which frees the type handler, and the data blob if it is owned by this object.
Definition: NiftiImage.h:483
RNifti::NiftiImageData::intercept
double intercept
The intercept term used to scale data values.
Definition: NiftiImage.h:76
RNifti::NiftiImageData::Element
Inner class representing a single element in the data blob.
Definition: NiftiImage.h:268
RNifti::NiftiImage::nBlocks
int nBlocks() const
Return the number of blocks in the image.
Definition: NiftiImage.h:1210
RNifti::NiftiImageData::end
Iterator end()
Obtain a mutable iterator corresponding to the end of the blob.
Definition: NiftiImage.h:579
RNifti::NiftiImageData::ConcreteTypeHandler
Concrete inner class template defining behaviour specific to individual data types.
Definition: NiftiImage.h:102
RNifti::NiftiImage::volume
Block volume(const int i)
Extract a volume block from a 4D image.
Definition: NiftiImage.h:1256
RNifti::NiftiImage::nChannels
int nChannels() const
Return the number of colour channels used by the image.
Definition: NiftiImage.h:1263
RNifti::rgba32_t::ValueType
Definition: NiftiImage.h:57
RNifti::NiftiImage::toFile
std::pair< std::string, std::string > toFile(const std::string fileName, const int datatype=DT_NONE) const
Write the image to a NIfTI-1 file.
RNifti::NiftiImage::initFromDims
void initFromDims(const std::vector< int > &dim, const int datatype)
Initialise an empty object from basic metadata.
RNifti::NiftiImageData::begin
Iterator begin()
Obtain a mutable iterator corresponding to the start of the blob.
Definition: NiftiImage.h:576
RNifti::NiftiImage::toArrayOrPointer
Rcpp::RObject toArrayOrPointer(const bool internal, const std::string label) const
A conditional method that calls either toArray or toPointer.
RNifti::NiftiImageData::isScaled
bool isScaled() const
Determine whether the object uses data scaling.
Definition: NiftiImage.h:530
RNifti::NiftiImage::Block::dimension
const int dimension
The dimension along which the block applies (which should be the last)
Definition: NiftiImage.h:638
RNifti::NiftiImage::acquire
void acquire(nifti_image *const image)
Acquire the specified pointer to a nifti_image struct, taking (possibly shared) responsibility for fr...
RNifti::NiftiImage
Thin wrapper around a C-style nifti_image struct that allows C++-style destruction.
Definition: NiftiImage.h:628
RNifti::NiftiImage::toPointer
Rcpp::RObject toPointer(const std::string label) const
Create an internal image to pass back to R.
RNifti::NiftiImage::refCount
int * refCount
A reference counter, shared with other objects wrapping the same pointer.
Definition: NiftiImage.h:755
RNifti::NiftiImage::reorient
NiftiImage & reorient(const int i, const int j, const int k)
Reorient the image by permuting dimensions and potentially reversing some.
RNifti::NiftiImage::update
NiftiImage & update(const Rcpp::RObject &object)
Update the image from an R array.
RNifti::NiftiImageData::dataPtr
void * dataPtr
Opaque pointer to the underlying data blob.
Definition: NiftiImage.h:202
RNifti::NiftiImageData::owner
bool owner
An indicator of whether this object is responsible for cleaning up the data.
Definition: NiftiImage.h:206
RNifti::NiftiImage::isNull
bool isNull() const
Determine whether or not the wrapped pointer is NULL.
Definition: NiftiImage.h:1016
RNifti::NiftiImage::NiftiImage
NiftiImage(const NiftiImage &source, const bool copy=true)
Copy constructor.
Definition: NiftiImage.h:863
RNifti::NiftiImageData::isEmpty
bool isEmpty() const
Determine whether or not the object is empty.
Definition: NiftiImage.h:523
RNifti::NiftiImageData::handler
TypeHandler * handler
Type handler, which is created to match the datatype.
Definition: NiftiImage.h:204
RNifti::NiftiImage::pixdim
std::vector< float > pixdim() const
Return the dimensions of the pixels or voxels in the image.
Definition: NiftiImage.h:1067
RNifti::NiftiImageData::Element::Element
Element(const NiftiImageData &parent, void *ptr=NULL)
Primary constructor.
Definition: NiftiImage.h:281
RNifti::NiftiImageData::totalBytes
size_t totalBytes() const
Return the total size of the data blob, in bytes.
Definition: NiftiImage.h:517
RNifti::NiftiImage::volume
const Block volume(const int i) const
Extract a volume block from a 4D image.
Definition: NiftiImage.h:1249
RNifti::NiftiImageData::Iterator::Iterator
Iterator(const NiftiImageData &parent, void *ptr=NULL, const size_t step=0)
Primary constructor.
Definition: NiftiImage.h:368
RNifti::NiftiImageData::bytesPerPixel
size_t bytesPerPixel() const
Return the number of bytes used per element, or zero if the datatype is undefined or the blob is NULL...
Definition: NiftiImage.h:514
RNifti::NiftiImage::dim
std::vector< int > dim() const
Return the dimensions of the image.
Definition: NiftiImage.h:1055
RNifti::NiftiImageData::Iterator::Iterator
Iterator(const Iterator &other)
Copy constructor.
Definition: NiftiImage.h:379
RNifti::NiftiImage::block
const Block block(const int i) const
Extract a block from the image.
Definition: NiftiImage.h:1219
RNifti::NiftiImage::rescale
NiftiImage & rescale(const std::vector< float > &scales)
Rescale the image, changing its image dimensions and pixel dimensions.
RNifti::NiftiImageData::NiftiImageData
NiftiImageData(nifti_image *image)
Convenience constructor for a nifti_image.
Definition: NiftiImage.h:438
RNifti::NiftiImageData::isComplex
bool isComplex() const
Determine whether the datatype is complex.
Definition: NiftiImage.h:536
RNifti::NiftiImageData::isRgb
bool isRgb() const
Determine whether the datatype corresponds to an RGB type.
Definition: NiftiImage.h:555
RNifti::NiftiImage::toArray
Rcpp::RObject toArray() const
Create an R array from the image.
RNifti::NiftiImageData::disown
NiftiImageData & disown()
Disown the data blob, removing responsibility for freeing it upon destruction.
Definition: NiftiImage.h:567
RNifti::NiftiImage::initFromMriImage
void initFromMriImage(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from a reference object of class "MriImage".
RNifti::NiftiImage::operator->
const nifti_image * operator->() const
Allows a NiftiImage object to be treated as a pointer to a const nifti_image.
Definition: NiftiImage.h:969
RNifti::NiftiImageData::end
const Iterator end() const
Obtain a constant iterator corresponding to the end of the blob.
Definition: NiftiImage.h:573
RNifti::NiftiImage::nVoxels
size_t nVoxels() const
Return the number of voxels in the image.
Definition: NiftiImage.h:1283
RNifti::NiftiImageData::minmax
void minmax(double *min, double *max) const
Calculate the minimum and maximum values in the blob, as doubles.
Definition: NiftiImage.h:602
RNifti::NiftiImage::setPersistence
NiftiImage & setPersistence(const bool persistent)
Mark the image as persistent, so that it can be passed back to R.
Definition: NiftiImage.h:1010
RNifti::NiftiImage::isDataScaled
bool isDataScaled() const
Determine whether nontrivial scale and slope parameters are set.
Definition: NiftiImage.h:1037
RNifti::NiftiImage::acquire
void acquire(const NiftiImage &source)
Acquire the same pointer as another NiftiImage, incrementing the shared reference count.
Definition: NiftiImage.h:769
RNifti::NiftiImageData::init
void init(void *data, const size_t length, const int datatype, const double slope, const double intercept, const bool alloc=true)
Initialiser method, used by constructors.
Definition: NiftiImage.h:218
RNifti::NiftiImage::isPersistent
bool isPersistent() const
Determine whether or not the image is marked as persistent.
Definition: NiftiImage.h:1030
RNifti::NiftiImage::dropData
NiftiImage & dropData()
Drop the data from the image, retaining only the metadata.
Definition: NiftiImage.h:1156
RNifti::NiftiImage::xformToRotation
static mat33 xformToRotation(const mat44 matrix)
Extract the pure rotation part of a 4x4 xform matrix.
RNifti::NiftiImage::operator=
NiftiImage & operator=(const NiftiImage &source)
Copy assignment operator, which copies from its argument.
Definition: NiftiImage.h:980
RNifti::NiftiImageData::begin
const Iterator begin() const
Obtain a constant iterator corresponding to the start of the blob.
Definition: NiftiImage.h:570
RNifti::NiftiImage::release
void release()
Release the currently wrapped pointer, if it is not NULL, decrementing the reference count and releas...
RNifti::NiftiImage::changeDatatype
NiftiImage & changeDatatype(const int datatype, const bool useSlope=false)
Change the datatype of the image, casting the pixel data if present.
RNifti::NiftiImageData::blob
void * blob() const
Return an opaque pointer to the blob.
Definition: NiftiImage.h:508
RNifti::NiftiImage::isShared
bool isShared() const
Determine whether the wrapped pointer is shared with another NiftiImage.
Definition: NiftiImage.h:1022
RNifti::NiftiImage::Block::image
const NiftiImage & image
The parent image.
Definition: NiftiImage.h:637
RNifti::NiftiImage::getData
std::vector< TargetType > getData(const bool useSlope=true) const
Extract a vector of data from the image, casting it to any required element type.
RNifti::NiftiImage::block
Block block(const int i)
Extract a block from the image.
Definition: NiftiImage.h:1228
RNifti::NiftiImage::copy
void copy(const nifti_image *source)
Copy the contents of a nifti_image to create a new image, acquiring the new pointer.
RNifti::NiftiImageData::Element::operator=
Element & operator=(const SourceType &value)
Copy assignment operator.
RNifti::NiftiImage::NiftiImage
NiftiImage()
Default constructor.
Definition: NiftiImage.h:854
RNifti::NiftiImageData::operator=
NiftiImageData & operator=(const NiftiImageData &source)
Copy assignment operator.
Definition: NiftiImage.h:495
RNifti::NiftiImage::updatePixdim
void updatePixdim(const std::vector< float > &pixdim)
Modify the pixel dimensions, and potentially the xform matrices to match.
RNifti::NiftiImageData::NiftiImageData
NiftiImageData()
Default constructor, creating an empty data object.
Definition: NiftiImage.h:417