1 #ifndef _NIFTI_IMAGE_H_ 2 #define _NIFTI_IMAGE_H_ 11 #define MAYBE_SHARED(x) (NAMED(x) > 1) 16 #define R_NegInf -INFINITY 34 #include "niftilib/nifti1_io.h" 46 typedef std::complex<float> complex64_t;
47 typedef std::complex<double> complex128_t;
59 unsigned char bytes[4];
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; }
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; }
101 template <
typename Type,
bool alpha = false>
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 111 *(static_cast<Type*>(ptr)) = Type(value.real());
112 *(static_cast<Type*>(ptr) + 1) = Type(0);
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;
119 template <
typename ElementType>
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 126 const ElementType real = *static_cast<ElementType*>(ptr);
127 const ElementType imag = *(static_cast<ElementType*>(ptr) + 1);
128 return std::complex<ElementType>(real, imag);
130 void setNative (
void *ptr,
const std::complex<ElementType> native)
const 132 *(static_cast<ElementType*>(ptr)) = native.real();
133 *(static_cast<ElementType*>(ptr) + 1) = native.imag();
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;
144 template <
bool alpha>
147 size_t size ()
const {
return alpha ? 4 : 3; }
148 int getInt (
void *ptr)
const {
return getRgb(ptr).value.packed; }
152 unsigned char *source = static_cast<unsigned char *>(ptr);
153 std::copy(source, source + (alpha ? 4 : 3), value.value.bytes);
156 void setInt (
void *ptr,
const int value)
const 159 native.value.packed = value;
162 void setRgb (
void *ptr,
const rgba32_t value)
const 164 unsigned char *target = static_cast<unsigned char *>(ptr);
165 std::copy(value.value.bytes, value.value.bytes + (alpha ? 4 : 3), target);
167 void minmax (
void *ptr,
const size_t length,
double *min,
double *max)
const { *min = 0.0; *max = 255.0; }
198 throw std::runtime_error(
"Unsupported data type (" + std::string(nifti_datatype_string(
_datatype)) +
")");
229 else if (alloc && data == NULL)
251 double dataMin, dataMax, typeMin, typeMax;
252 data.
minmax(&dataMin, &dataMax);
253 handler->minmax(NULL, 0, &typeMin, &typeMax);
256 if (dataMin < typeMin || dataMax > typeMax)
258 slope = (dataMax - dataMin) / (typeMax - typeMin);
284 this->ptr = (ptr == NULL ? parent.
dataPtr : ptr);
294 template <
typename SourceType>
307 template <
typename TargetType>
308 operator TargetType()
const 312 else if (std::numeric_limits<TargetType>::is_integer)
313 return TargetType(parent.
handler->getInt(ptr));
315 return TargetType(parent.
handler->getDouble(ptr));
318 template <
typename ElementType>
319 operator std::complex<ElementType>()
const 324 return std::complex<ElementType>(parent.
handler->getComplex(ptr));
331 operator Rcomplex()
const 333 const complex128_t value = parent.
handler->getComplex(ptr);
334 Rcomplex rValue = { value.real(), value.imag() };
346 return parent.
handler->getRgb(ptr);
353 class Iterator :
public std::iterator<std::random_access_iterator_tag, Element>
371 this->ptr = (ptr == NULL ? parent.
dataPtr : ptr);
372 this->step = (step == 0 ? parent.
handler->size() : step);
380 : parent(other.parent), ptr(other.ptr), step(other.step) {}
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 386 void *newptr = static_cast<char*>(ptr) + (n * step);
387 return Iterator(parent, newptr, step);
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 393 void *newptr = static_cast<char*>(ptr) - (n * step);
394 return Iterator(parent, newptr, step);
397 ptrdiff_t operator- (
const Iterator &other)
const 399 const ptrdiff_t difference = static_cast<char*>(ptr) - static_cast<char*>(other.ptr);
400 return difference / step;
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); }
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)); }
441 init(NULL, 0, DT_NONE, 0.0, 0.0,
false);
443 init(image->data, image->nvox, image->datatype, static_cast<double>(image->scl_slope), static_cast<double>(image->scl_inter),
false);
472 template <
class InputIterator>
475 const size_t length = static_cast<size_t>(std::distance(from, to));
477 std::copy(from, to, this->
begin());
602 void minmax (
double *min,
double *max)
const 618 inline bool NiftiImageData::ConcreteTypeHandler<int>::hasNaN ()
const {
return true; }
652 throw std::runtime_error(
"Blocks must be along the last dimension in the image");
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");
670 size_t blockSize = 1;
674 if (blockSize != source->nvox)
675 throw std::runtime_error(
"New data does not have the same size as the target block");
677 blockSize *=
image->nbyper;
692 size_t blockSize = 1;
706 template <
typename TargetType>
707 std::vector<TargetType>
getData (
const bool useSlope =
true)
const;
719 if (sexpType == INTSXP || sexpType == LGLSXP)
721 else if (sexpType == REALSXP)
723 else if (sexpType == CPLXSXP)
724 return DT_COMPLEX128;
726 throw std::runtime_error(
"Array elements must be numeric");
785 void copy (
const nifti_image *source);
797 void copy (
const Block &source);
807 void initFromNiftiS4 (
const Rcpp::RObject &
object,
const bool copyData =
true);
814 void initFromMriImage (
const Rcpp::RObject &
object,
const bool copyData =
true);
827 void initFromArray (
const Rcpp::RObject &
object,
const bool copyData =
true);
848 void setPixunits (
const std::vector<std::string> &pixunits);
871 Rc_printf(
"Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
884 Rc_printf(
"Creating NiftiImage with pointer %p (from Block)\n", this->image);
902 Rc_printf(
"Creating NiftiImage with pointer %p (from pointer)\n", this->image);
911 NiftiImage (
const std::vector<int> &
dim,
const int datatype);
918 NiftiImage (
const std::vector<int> &
dim,
const std::string &datatype);
926 NiftiImage (
const std::string &path,
const bool readData =
true);
934 NiftiImage (
const std::string &path,
const std::vector<int> &volumes);
947 NiftiImage (
const SEXP
object,
const bool readData =
true,
const bool readOnly =
false);
959 operator const nifti_image* ()
const {
return image; }
964 operator nifti_image* () {
return image; }
984 Rc_printf(
"Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
998 Rc_printf(
"Creating NiftiImage with pointer %p (from Block)\n", this->image);
1058 return std::vector<int>();
1070 return std::vector<float>();
1072 return std::vector<float>(
image->pixdim+1,
image->pixdim+
image->ndim+1);
1083 int ndim =
image->ndim;
1084 while (
image->dim[ndim] < 2)
1112 template <
typename TargetType>
1113 std::vector<TargetType>
getData (
const bool useSlope =
true)
const;
1141 template <
typename SourceType>
1158 nifti_image_unload(
image);
1204 mat44
xform (
const bool preferQuaternion =
true)
const;
1269 switch (
image->datatype)
1271 case DT_NONE:
return 0;
1272 case DT_RGB24:
return 3;
1273 case DT_RGBA32:
return 4;
1291 std::pair<std::string,std::string>
toFile (
const std::string fileName,
const int datatype = DT_NONE)
const;
1299 std::pair<std::string,std::string>
toFile (
const std::string fileName,
const std::string &datatype)
const;
1307 Rcpp::RObject
toArray ()
const;
1314 Rcpp::RObject
toPointer (
const std::string label)
const;
1322 Rcpp::RObject
toArrayOrPointer (
const bool internal,
const std::string label)
const;
1335 #include "RNifti/NiftiImage_impl.h" 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