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 
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>
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 
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;
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;
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 
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 
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 
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 
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)
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 
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:
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 
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 
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 
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 
1151 
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
bool isInteger() const
Determine whether the datatype is an integer type.
Definition: NiftiImage.h:549
NiftiImage()
Default constructor.
Definition: NiftiImage.h:854
size_t nVoxels() const
Return the number of voxels in the image.
Definition: NiftiImage.h:1283
const int index
The location along dimension.
Definition: NiftiImage.h:639
static std::string xformToString(const mat44 matrix)
Convert a 4x4 xform matrix to a string describing its canonical axes.
std::vector< int > dim() const
Return the dimensions of the image.
Definition: NiftiImage.h:1055
const nifti_image * operator->() const
Allows a NiftiImage object to be treated as a pointer to a const nifti_image.
Definition: NiftiImage.h:969
static int sexpTypeToNiftiType(const int sexpType)
Convert between R SEXP object type and nifti_image datatype codes.
Definition: NiftiImage.h:717
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
int datatype() const
Return stored datatype code.
Definition: NiftiImage.h:509
Rcpp::RObject headerToList() const
Create an R list containing raw image metadata.
const Iterator begin() const
Obtain a constant iterator corresponding to the start of the blob.
Definition: NiftiImage.h:570
bool isComplex() const
Determine whether the datatype is complex.
Definition: NiftiImage.h:536
NiftiImage & rescale(const std::vector< float > &scales)
Rescale the image, changing its image dimensions and pixel dimensions.
bool isRgb() const
Determine whether the datatype corresponds to an RGB type.
Definition: NiftiImage.h:555
int * refCount
A reference counter, shared with other objects wrapping the same pointer.
Definition: NiftiImage.h:755
Abstract inner class defining the type-specific functions required in concrete subclasses.
Definition: NiftiImage.h:82
const Element operator[](const size_t i) const
Indexing operator, returning a constant element.
Definition: NiftiImage.h:586
Iterator end()
Obtain a mutable iterator corresponding to the end of the blob.
Definition: NiftiImage.h:579
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.
std::vector< float > pixdim() const
Return the dimensions of the pixels or voxels in the image.
Definition: NiftiImage.h:1067
void minmax(double *min, double *max) const
Calculate the minimum and maximum values in the blob, as doubles.
Definition: NiftiImage.h:602
Concrete inner class template defining behaviour specific to individual data types.
Definition: NiftiImage.h:102
size_t size() const
Return the number of elements in the data.
Definition: NiftiImage.h:511
Iterator type for NiftiImageData, with Element as its value type.
Definition: NiftiImage.h:353
double slope
The slope term used to scale data values.
Definition: NiftiImage.h:75
NiftiImage(nifti_image *const image, const bool copy=false)
Initialise using an existing nifti_image pointer.
Definition: NiftiImage.h:894
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
void initFromMriImage(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from a reference object of class "MriImage".
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
int nChannels() const
Return the number of colour channels used by the image.
Definition: NiftiImage.h:1263
bool isNull() const
Determine whether or not the wrapped pointer is NULL.
Definition: NiftiImage.h:1016
Inner class referring to a subset of an image.
Definition: NiftiImage.h:635
Block slice(const int i)
Extract a slice block from a 3D image.
Definition: NiftiImage.h:1242
const NiftiImageData data() const
Obtain the pixel data within the image.
Definition: NiftiImage.h:1095
Rcpp::RObject toPointer(const std::string label) const
Create an internal image to pass back to R.
bool isShared() const
Determine whether the wrapped pointer is shared with another NiftiImage.
Definition: NiftiImage.h:1022
void acquire(const NiftiImage &source)
Acquire the same pointer as another NiftiImage, incrementing the shared reference count.
Definition: NiftiImage.h:769
NiftiImageData()
Default constructor, creating an empty data object.
Definition: NiftiImage.h:417
Iterator(const NiftiImageData &parent, void *ptr=NULL, const size_t step=0)
Primary constructor.
Definition: NiftiImage.h:368
void acquire(nifti_image *const image)
Acquire the specified pointer to a nifti_image struct, taking (possibly shared) responsibility for fr...
void initFromArray(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an R array.
bool isDataScaled() const
Determine whether nontrivial scale and slope parameters are set.
Definition: NiftiImage.h:1037
void initFromNiftiS4(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an S4 object of class "nifti".
const Block slice(const int i) const
Extract a slice block from a 3D image.
Definition: NiftiImage.h:1235
NiftiImageData data() const
Obtain the data within the block.
Definition: NiftiImage.h:686
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.
const Block volume(const int i) const
Extract a volume block from a 4D image.
Definition: NiftiImage.h:1249
bool owner
An indicator of whether this object is responsible for cleaning up the data.
Definition: NiftiImage.h:206
bool isPersistent() const
Determine whether or not the image is marked as persistent.
Definition: NiftiImage.h:1030
size_t totalBytes() const
Return the total size of the data blob, in bytes.
Definition: NiftiImage.h:517
std::vector< TargetType > getData(const bool useSlope=true) const
Extract a vector of data from a block, casting it to any required element type.
NiftiImage & update(const Rcpp::RObject &object)
Update the image from an R array.
void setPixunits(const std::vector< std::string > &pixunits)
Modify the pixel dimension units.
Element & operator=(const SourceType &value)
Copy assignment operator.
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
void * blob() const
Return an opaque pointer to the blob.
Definition: NiftiImage.h:508
NiftiImage(const Block &source)
Initialise from a block, copying in the data.
Definition: NiftiImage.h:879
virtual ~NiftiImage()
Destructor which decrements the reference counter, and releases the wrapped pointer if the counter dr...
Definition: NiftiImage.h:954
Thin wrapper around a C-style nifti_image struct that allows C++-style destruction.
Definition: NiftiImage.h:628
virtual ~NiftiImageData()
Destructor which frees the type handler, and the data blob if it is owned by this object.
Definition: NiftiImage.h:483
int _datatype
Datatype code indicating the actual type of the elements.
Definition: NiftiImage.h:203
NiftiImage(const NiftiImage &source, const bool copy=true)
Copy constructor.
Definition: NiftiImage.h:863
NiftiImageData & operator=(const NiftiImageData &source)
Copy assignment operator.
Definition: NiftiImage.h:495
TypeHandler * handler
Type handler, which is created to match the datatype.
Definition: NiftiImage.h:204
int nBlocks() const
Return the number of blocks in the image.
Definition: NiftiImage.h:1210
Inner class representing a single element in the data blob.
Definition: NiftiImage.h:268
void release()
Release the currently wrapped pointer, if it is not NULL, decrementing the reference count and releas...
void calibrateFrom(const NiftiImageData &data)
Update the slope and intercept to cover the range of another data object.
Definition: NiftiImage.h:244
const int dimension
The dimension along which the block applies (which should be the last)
Definition: NiftiImage.h:638
const NiftiImage & image
The parent image.
Definition: NiftiImage.h:637
void initFromList(const Rcpp::RObject &object)
Initialise the object from an R list with named elements, which can only contain metadata.
NiftiImage & operator=(const NiftiImage &source)
Copy assignment operator, which copies from its argument.
Definition: NiftiImage.h:980
NiftiImage & changeDatatype(const int datatype, const bool useSlope=false)
Change the datatype of the image, casting the pixel data if present.
NiftiImageData unscaled() const
Return a similar object to the callee, but with the slope and intercept values reset.
Definition: NiftiImage.h:561
static int fileVersion(const std::string &path)
Get the NIfTI format version used by the file at the specified path.
static mat33 xformToRotation(const mat44 matrix)
Extract the pure rotation part of a 4x4 xform matrix.
void updatePixdim(const std::vector< float > &pixdim)
Modify the pixel dimensions, and potentially the xform matrices to match.
const Block block(const int i) const
Extract a block from the image.
Definition: NiftiImage.h:1219
NiftiImageData(const NiftiImageData &source, const int datatype=DT_NONE)
Copy constructor with optional type conversion.
Definition: NiftiImage.h:453
Element(const NiftiImageData &parent, void *ptr=NULL)
Primary constructor.
Definition: NiftiImage.h:281
bool isScaled() const
Determine whether the object uses data scaling.
Definition: NiftiImage.h:530
NiftiImageData data()
Obtain the pixel data within the image.
Definition: NiftiImage.h:1101
NiftiImage & setPersistence(const bool persistent)
Mark the image as persistent, so that it can be passed back to R.
Definition: NiftiImage.h:1010
std::vector< TargetType > getData(const bool useSlope=true) const
Extract a vector of data from the image, casting it to any required element type.
Iterator(const Iterator &other)
Copy constructor.
Definition: NiftiImage.h:379
void copy(const nifti_image *source)
Copy the contents of a nifti_image to create a new image, acquiring the new pointer.
mat44 xform(const bool preferQuaternion=true) const
Obtain an xform matrix, indicating the orientation of the image.
nifti_image * image
The wrapped nifti_image pointer.
Definition: NiftiImage.h:754
Definition: NiftiImage.h:57
double intercept
The intercept term used to scale data values.
Definition: NiftiImage.h:76
Rcpp::RObject toArrayOrPointer(const bool internal, const std::string label) const
A conditional method that calls either toArray or toPointer.
int nDims() const
Return the number of dimensions in the image.
Definition: NiftiImage.h:1043
void * dataPtr
Opaque pointer to the underlying data blob.
Definition: NiftiImage.h:202
TypeHandler * createHandler()
Create a concrete type handler appropriate to the datatype code stored with the data.
Definition: NiftiImage.h:175
size_t _length
The number of data elements in the blob.
Definition: NiftiImage.h:205
Iterator begin()
Obtain a mutable iterator corresponding to the start of the blob.
Definition: NiftiImage.h:576
void initFromDims(const std::vector< int > &dim, const int datatype)
Initialise an empty object from basic metadata.
Block volume(const int i)
Extract a volume block from a 4D image.
Definition: NiftiImage.h:1256
size_t length() const
Return the number of elements in the data.
Definition: NiftiImage.h:510
Wrapper class encapsulating a NIfTI data blob, with responsibility for handling data scaling and poly...
Definition: NiftiImage.h:72
NiftiImage & drop()
Drop unitary dimensions.
Definition: NiftiImage.h:1081
NiftiImageData & disown()
Disown the data blob, removing responsibility for freeing it upon destruction.
Definition: NiftiImage.h:567
Rcpp::RObject toArray() const
Create an R array from the image.
NiftiImage & reorient(const int i, const int j, const int k)
Reorient the image by permuting dimensions and potentially reversing some.
Simple RGB(A) type encapsulating an 8-bit colour value with optional opacity, which can also be set o...
Definition: NiftiImage.h:55
Block(const NiftiImage &image, const int dimension, const int index)
Standard constructor for this class.
Definition: NiftiImage.h:648
bool isFloatingPoint() const
Determine whether the datatype is floating point.
Definition: NiftiImage.h:543
NiftiImageData(nifti_image *image)
Convenience constructor for a nifti_image.
Definition: NiftiImage.h:438
const Iterator end() const
Obtain a constant iterator corresponding to the end of the blob.
Definition: NiftiImage.h:573
bool isEmpty() const
Determine whether or not the object is empty.
Definition: NiftiImage.h:523
NiftiImageData(InputIterator from, InputIterator to, const int datatype)
Iterator-based constructor.
Definition: NiftiImage.h:473
NiftiImage & dropData()
Drop the data from the image, retaining only the metadata.
Definition: NiftiImage.h:1156
Block block(const int i)
Extract a block from the image.
Definition: NiftiImage.h:1228