Skip to content

Commit

Permalink
Upgrade RNifti and dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
onurulgen committed Feb 16, 2024
1 parent a74e436 commit 193ef44
Show file tree
Hide file tree
Showing 14 changed files with 750 additions and 387 deletions.
2 changes: 1 addition & 1 deletion niftyreg_build_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
406
407
2 changes: 1 addition & 1 deletion reg-io/RNifti.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

// Defined since RNifti v0.10.0, and equal to 100 * (major version) + (minor version). May not
// change if the API does not change, and in particular never changes with patch level
#define RNIFTI_VERSION 104
#define RNIFTI_VERSION 106

// Versions 1 and 2 of the NIfTI reference library are mutually incompatible, but RNifti does some
// work to get them to play nicely:
Expand Down
114 changes: 83 additions & 31 deletions reg-io/RNifti/NiftiImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class NiftiImageData
double getDouble (void *ptr) const { return static_cast<double>(getNative(ptr).real()); }
int getInt (void *ptr) const { return static_cast<int>(getNative(ptr).real()); }
void setComplex (void *ptr, const complex128_t value) const { setNative(ptr, std::complex<ElementType>(value)); }
void setDouble (void *ptr, const double value) const { setNative(ptr, std::complex<ElementType>(static_cast<ElementType>(value), 0.0)); }
void setDouble (void *ptr, const double value) const { setNative(ptr, std::complex<ElementType>(value, 0.0)); }
void setInt (void *ptr, const int value) const { setNative(ptr, std::complex<ElementType>(static_cast<ElementType>(value), 0.0)); }
void minmax (void *ptr, const size_t length, double *min, double *max) const;
};
Expand Down Expand Up @@ -329,7 +329,9 @@ class NiftiImageData
operator Rcomplex() const
{
const complex128_t value = parent.handler->getComplex(ptr);
Rcomplex rValue = { value.real(), value.imag() };
Rcomplex rValue;
rValue.r = value.real();
rValue.i = value.imag();
if (parent.isScaled())
{
rValue.r = rValue.r * parent.slope + parent.intercept;
Expand All @@ -351,7 +353,9 @@ class NiftiImageData
class Iterator
{
private:
const NiftiImageData &parent;
// NB: "parent" cannot be a reference because reference members are immutable. That renders
// the class non-copy-assignable, which is a requirement for iterators (issue #31)
const NiftiImageData *parent;
void *ptr;
size_t step;

Expand All @@ -365,16 +369,17 @@ class NiftiImageData

/**
* Primary constructor
* @param parent A reference to the parent object
* @param ptr An opaque pointer to the memory underpinning the iterator
* @param parent A pointer to the parent object
* @param ptr An opaque pointer to the memory underpinning the iterator. The default,
* \c nullptr, corresponds to the start of the parent object's data blob.
* @param step The increment between elements within the blob, in bytes. If zero, the
* default, the width associated with the stored datatype will be used.
**/
Iterator (const NiftiImageData &parent, void *ptr = nullptr, const size_t step = 0)
Iterator (const NiftiImageData *parent = nullptr, void *ptr = nullptr, const size_t step = 0)
: parent(parent)
{
this->ptr = (ptr == nullptr ? parent.dataPtr : ptr);
this->step = (step == 0 ? parent.handler->size() : step);
this->ptr = (ptr == nullptr ? parent->dataPtr : ptr);
this->step = (step == 0 ? parent->handler->size() : step);
}

/**
Expand All @@ -387,7 +392,7 @@ class NiftiImageData
/**
* Reset the iterator to point to the start of the data blob
**/
void reset () { ptr = parent.dataPtr; }
void reset () { ptr = parent->dataPtr; }

Iterator & operator++ () { ptr = static_cast<char*>(ptr) + step; return *this; }
Iterator operator++ (int) { Iterator copy(*this); ptr = static_cast<char*>(ptr) + step; return copy; }
Expand Down Expand Up @@ -415,10 +420,10 @@ class NiftiImageData
bool operator> (const Iterator &other) const { return (ptr > other.ptr); }
bool operator< (const Iterator &other) const { return (ptr < other.ptr); }

const Element operator* () const { return Element(parent, ptr); }
Element operator* () { return Element(parent, ptr); }
const Element operator[] (const size_t i) const { return Element(parent, static_cast<char*>(ptr) + (i * step)); }
Element operator[] (const size_t i) { return Element(parent, static_cast<char*>(ptr) + (i * step)); }
const Element operator* () const { return Element(*parent, ptr); }
Element operator* () { return Element(*parent, ptr); }
const Element operator[] (const size_t i) const { return Element(*parent, static_cast<char*>(ptr) + (i * step)); }
Element operator[] (const size_t i) { return Element(*parent, static_cast<char*>(ptr) + (i * step)); }
};

/**
Expand Down Expand Up @@ -479,8 +484,7 @@ class NiftiImageData
else
{
calibrateFrom(source);
for (size_t i = 0; i < source.length(); ++i)
(*this)[i] = source[i];
std::copy(source.begin(), source.end(), this->begin());
}
}

Expand Down Expand Up @@ -591,16 +595,16 @@ class NiftiImageData
NiftiImageData & disown () { this->owner = false; return *this; }

/** Obtain a constant iterator corresponding to the start of the blob */
const Iterator begin () const { return Iterator(*this); }
const Iterator begin () const { return Iterator(this); }

/** Obtain a constant iterator corresponding to the end of the blob */
const Iterator end () const { return Iterator(*this, static_cast<char*>(dataPtr) + totalBytes()); }
const Iterator end () const { return Iterator(this, static_cast<char*>(dataPtr) + totalBytes()); }

/** Obtain a mutable iterator corresponding to the start of the blob */
Iterator begin () { return Iterator(*this); }
Iterator begin () { return Iterator(this); }

/** Obtain a mutable iterator corresponding to the end of the blob */
Iterator end () { return Iterator(*this, static_cast<char*>(dataPtr) + totalBytes()); }
Iterator end () { return Iterator(this, static_cast<char*>(dataPtr) + totalBytes()); }

/**
* Indexing operator, returning a constant element
Expand Down Expand Up @@ -1305,6 +1309,16 @@ class NiftiImage
**/
void acquire (nifti_image * const image);

/**
* Acquire the same pointer as another \c NiftiImage, incrementing the shared reference count
* @param source A reference to a \c NiftiImage
**/
void acquire (const NiftiImage &source)
{
refCount = source.refCount;
acquire(source.image);
}

/**
* Release the currently wrapped pointer, if it is not \c nullptr, decrementing the reference
* count and releasing memory if there are no remaining references to the pointer
Expand All @@ -1318,6 +1332,12 @@ class NiftiImage
**/
void copy (const nifti_image *source, const Copy copy);

/**
* Copy the contents of another \c NiftiImage to create a new image, acquiring a new pointer
* @param source A reference to a \c NiftiImage
**/
void copy (const NiftiImage &source);

/**
* Copy the contents of a \ref Block to create a new image, acquiring a new pointer
* @param source A reference to a \ref Block
Expand Down Expand Up @@ -1408,8 +1428,7 @@ class NiftiImage
if (copy != Copy::None) {
this->copy(source, copy);
} else {
refCount = source.refCount;
acquire(source.image);
acquire(source);
}
RN_DEBUG("Creating NiftiImage (v%d) with pointer %p (from NiftiImage)", RNIFTI_NIFTILIB_VERSION, this->image);
}
Expand Down Expand Up @@ -1451,6 +1470,34 @@ class NiftiImage
RN_DEBUG("Creating NiftiImage (v%d) with pointer %p (from pointer)", RNIFTI_NIFTILIB_VERSION, this->image);
}

/**
* Initialise using a NIfTI-1 header
* @param header A reference to a NIfTI-1 header struct
**/
NiftiImage (const nifti_1_header &header)
: NiftiImage()
{
#if RNIFTI_NIFTILIB_VERSION == 1
acquire(nifti_convert_nhdr2nim(header, nullptr));
#elif RNIFTI_NIFTILIB_VERSION == 2
acquire(nifti_convert_n1hdr2nim(header, nullptr));
#endif
RN_DEBUG("Creating NiftiImage (v%d) with pointer %p (from header)", RNIFTI_NIFTILIB_VERSION, this->image);
}

#if RNIFTI_NIFTILIB_VERSION == 2
/**
* Initialise using a NIfTI-2 header
* @param header A reference to a NIfTI-2 header struct
**/
NiftiImage (const nifti_2_header &header)
: NiftiImage()
{
acquire(nifti_convert_n2hdr2nim(header, nullptr));
RN_DEBUG("Creating NiftiImage (v%d) with pointer %p (from header)", RNIFTI_NIFTILIB_VERSION, this->image);
}
#endif

/**
* Initialise from basic metadata, allocating and zeroing pixel data
* @param dim A vector of image dimensions
Expand Down Expand Up @@ -2021,11 +2068,12 @@ class NiftiImage
* @param dimCount Number of dimensions to consider
* @return The number of voxels in the image
*/
static size_t calcVoxelNumber(const nifti_image *image, const int dimCount) {
static size_t calcVoxelNumber (const nifti_image *image, const int dimCount) {
if (image == nullptr)
return 0;
size_t voxelNumber = 1;
for (int i = 1; i <= dimCount; i++) {
for (int i = 1; i <= dimCount; i++)
{
const size_t dim = static_cast<size_t>(std::abs(image->dim[i]));
voxelNumber *= dim > 0 ? dim : 1;
}
Expand All @@ -2035,7 +2083,7 @@ class NiftiImage
/**
* Recalculate the number of voxels in the image and update the nvox field
*/
void recalcVoxelNumber() {
void recalcVoxelNumber () {
if (image != nullptr)
image->nvox = calcVoxelNumber(image, image->ndim);
}
Expand All @@ -2061,7 +2109,7 @@ class NiftiImage
/**
* Return the total size of the image data in bytes
*/
size_t totalBytes() const
size_t totalBytes () const
{
#if RNIFTI_NIFTILIB_VERSION == 1
return nifti_get_volsize(image);
Expand Down Expand Up @@ -2120,7 +2168,7 @@ class NiftiImage
* @param A list of \ref Extension objects
* @return Self, with the new extensions attached
**/
NiftiImage & replaceExtensions (const std::list<Extension> extensions)
NiftiImage & replaceExtensions (const std::list<Extension> &extensions)
{
dropExtensions();
for (std::list<Extension>::const_iterator it=extensions.begin(); it!=extensions.end(); ++it)
Expand All @@ -2147,7 +2195,7 @@ class NiftiImage
* Set the intent name of the image
* @param name A string giving the new intent name
**/
void setIntentName(const std::string& name) {
void setIntentName (const std::string &name) {
if (image != nullptr)
{
constexpr size_t intentNameLength = sizeof(image->intent_name) / sizeof(*image->intent_name);
Expand All @@ -2162,19 +2210,23 @@ class NiftiImage
* @param datatype The datatype to use when writing the file
* @param filetype The file type to create: a \c NIFTI_FTYPE constant or -1. In the latter case
* the file name is used to determine the file type
* @param compression The \c zlib compression level to use, if appropriate. Valid values are
* between 0 and 9
* @return A pair of strings, giving the final header and image paths in that order
**/
std::pair<std::string,std::string> toFile (const std::string fileName, const int datatype = DT_NONE, const int filetype = -1) const;
std::pair<std::string,std::string> toFile (const std::string &fileName, const int datatype = DT_NONE, const int filetype = -1, const int compression = 6) const;

/**
* Write the image to a NIfTI-1 file
* @param fileName The file name to write to, with appropriate suffix (e.g. ".nii.gz")
* @param datatype The datatype to use when writing the file, or "auto"
* @param filetype The file type to create: a \c NIFTI_FTYPE constant or -1. In the latter case
* the file name is used to determine the file type
* @param compression The \c zlib compression level to use, if appropriate. Valid values are
* between 0 and 9
* @return A pair of strings, giving the final header and image paths in that order
**/
std::pair<std::string,std::string> toFile (const std::string fileName, const std::string &datatype, const int filetype = -1) const;
std::pair<std::string,std::string> toFile (const std::string &fileName, const std::string &datatype, const int filetype = -1, const int compression = 6) const;

#ifdef USING_R

Expand All @@ -2189,15 +2241,15 @@ class NiftiImage
* @param label A string labelling the image
* @return An R character string with additional attributes
**/
Rcpp::RObject toPointer (const std::string label) const;
Rcpp::RObject toPointer (const std::string &label) const;

/**
* A conditional method that calls either \ref toArray or \ref toPointer
* @param internal If \c true, \ref toPointer will be called; otherwise \ref toArray
* @param label A string labelling the image
* @return An R object
**/
Rcpp::RObject toArrayOrPointer (const bool internal, const std::string label) const;
Rcpp::RObject toArrayOrPointer (const bool internal, const std::string &label) const;

#endif

Expand Down
Loading

0 comments on commit 193ef44

Please sign in to comment.