1 #ifndef _NIFTI_IMAGE_H_ 2 #define _NIFTI_IMAGE_H_ 6 #include "niftilib/nifti1_io.h" 43 : image(image), dimension(dimension), index(index)
45 if (dimension != image->ndim)
46 throw std::runtime_error(
"Blocks must be along the last dimension in the image");
59 if (source->datatype != image->datatype)
60 throw std::runtime_error(
"New data does not have the same datatype as the target block");
64 blockSize *= image->
dim[i];
66 if (blockSize != source->nvox)
67 throw std::runtime_error(
"New data does not have the same size as the target block");
69 blockSize *= image->nbyper;
70 memcpy(static_cast<char*>(image->data) + blockSize*index, source->data, blockSize);
77 template <
typename TargetType>
78 std::vector<TargetType>
getData ()
const;
89 if (sexpType == INTSXP || sexpType == LGLSXP)
91 else if (sexpType == REALSXP)
94 throw std::runtime_error(
"Array elements must be numeric");
105 void copy (
const nifti_image *source);
124 void initFromNiftiS4 (
const Rcpp::RObject &
object,
const bool copyData =
true);
131 void initFromMriImage (
const Rcpp::RObject &
object,
const bool copyData =
true);
144 void initFromArray (
const Rcpp::RObject &
object,
const bool copyData =
true);
156 void setPixunits (
const std::vector<std::string> &pixunits);
163 : image(NULL), persistent(false) {}
170 : image(NULL), persistent(false)
174 Rprintf(
"Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
183 : image(NULL), persistent(false)
187 Rprintf(
"Creating NiftiImage with pointer %p (from Block)\n", this->image);
198 : image(NULL), persistent(false)
205 Rprintf(
"Creating NiftiImage with pointer %p (from pointer)\n", this->image);
215 NiftiImage (
const std::string &path,
const bool readData =
true)
218 this->image = nifti_image_read(path.c_str(), readData);
219 if (this->image == NULL)
220 throw std::runtime_error(
"Failed to read image from path " + path);
222 Rprintf(
"Creating NiftiImage with pointer %p (from string)\n", this->image);
231 NiftiImage (
const SEXP
object,
const bool readData =
true);
241 Rprintf(
"Freeing NiftiImage with pointer %p\n", this->image);
243 nifti_image_free(image);
250 operator const nifti_image* ()
const {
return image; }
255 operator nifti_image* () {
return image; }
275 Rprintf(
"Creating NiftiImage with pointer %p (from NiftiImage)\n", this->image);
289 Rprintf(
"Creating NiftiImage with pointer %p (from Block)\n", this->image);
303 Rprintf(
"Setting NiftiImage with pointer %p to be persistent\n", this->image);
310 bool isNull ()
const {
return (image == NULL); }
332 std::vector<int>
dim ()
const 335 return std::vector<int>();
337 return std::vector<int>(image->dim+1, image->dim+image->ndim+1);
347 return std::vector<float>();
349 return std::vector<float>(image->pixdim+1, image->pixdim+image->ndim+1);
360 int ndim = image->ndim;
361 while (image->dim[ndim] < 2)
363 image->
dim[0] = image->ndim = ndim;
371 template <
typename TargetType>
372 std::vector<TargetType>
getData ()
const;
393 template <
typename SourceType>
394 void replaceData (
const std::vector<SourceType> &data,
const short datatype = DT_NONE);
406 void rescale (
const std::vector<float> &scales);
412 void update (
const SEXP array);
419 mat44
xform (
const bool preferQuaternion =
true)
const;
429 return image->dim[image->ndim];
483 void toFile (
const std::string fileName,
const short datatype = DT_NONE)
const;
490 void toFile (
const std::string fileName,
const std::string &datatype)
const;
496 Rcpp::RObject
toArray ()
const;
503 Rcpp::RObject
toPointer (
const std::string label)
const;
511 Rcpp::RObject
toArrayOrPointer (
const bool internal,
const std::string label)
const;
521 #include "lib/NiftiImage_internal.h" 526 nifti_image_free(
image);
532 image = nifti_copy_nim_info(source);
533 if (source->data != NULL)
535 size_t dataSize = nifti_get_volsize(source);
536 image->data = calloc(1, dataSize);
537 memcpy(
image->data, source->data, dataSize);
544 const nifti_image *sourceStruct = source;
551 nifti_image_free(
image);
553 const nifti_image *sourceStruct = source.
image;
554 if (sourceStruct == NULL)
558 image = nifti_copy_nim_info(sourceStruct);
562 nifti_update_dims_from_array(
image);
564 if (sourceStruct->data != NULL)
566 size_t blockSize = nifti_get_volsize(
image);
567 image->data = calloc(1, blockSize);
568 memcpy(
image->data, static_cast<char*>(source.
image->data) + blockSize*source.
index, blockSize);
576 nifti_1_header header;
577 header.sizeof_hdr = 348;
579 const std::vector<short> dims =
object.slot(
"dim_");
580 for (
int i=0; i<8; i++)
581 header.dim[i] = dims[i];
583 header.intent_p1 =
object.slot(
"intent_p1");
584 header.intent_p2 =
object.slot(
"intent_p2");
585 header.intent_p3 =
object.slot(
"intent_p3");
586 header.intent_code =
object.slot(
"intent_code");
588 header.datatype =
object.slot(
"datatype");
589 header.bitpix =
object.slot(
"bitpix");
591 header.slice_start =
object.slot(
"slice_start");
592 header.slice_end =
object.slot(
"slice_end");
593 header.slice_code = Rcpp::as<int>(
object.slot(
"slice_code"));
594 header.slice_duration =
object.slot(
"slice_duration");
596 const std::vector<float> pixdims =
object.slot(
"pixdim");
597 for (
int i=0; i<8; i++)
598 header.pixdim[i] = pixdims[i];
599 header.xyzt_units = Rcpp::as<int>(
object.slot(
"xyzt_units"));
601 header.vox_offset =
object.slot(
"vox_offset");
603 header.scl_slope =
object.slot(
"scl_slope");
604 header.scl_inter =
object.slot(
"scl_inter");
605 header.toffset =
object.slot(
"toffset");
607 header.cal_max =
object.slot(
"cal_max");
608 header.cal_min =
object.slot(
"cal_min");
609 header.glmax = header.glmin = 0;
611 strncpy(header.descrip, Rcpp::as<std::string>(
object.slot(
"descrip")).c_str(), 79);
612 header.descrip[79] =
'\0';
613 strncpy(header.aux_file, Rcpp::as<std::string>(
object.slot(
"aux_file")).c_str(), 23);
614 header.aux_file[23] =
'\0';
615 strncpy(header.intent_name, Rcpp::as<std::string>(
object.slot(
"intent_name")).c_str(), 15);
616 header.intent_name[15] =
'\0';
617 strncpy(header.magic, Rcpp::as<std::string>(
object.slot(
"magic")).c_str(), 3);
618 header.magic[3] =
'\0';
620 header.qform_code =
object.slot(
"qform_code");
621 header.sform_code =
object.slot(
"sform_code");
623 header.quatern_b =
object.slot(
"quatern_b");
624 header.quatern_c =
object.slot(
"quatern_c");
625 header.quatern_d =
object.slot(
"quatern_d");
626 header.qoffset_x =
object.slot(
"qoffset_x");
627 header.qoffset_y =
object.slot(
"qoffset_y");
628 header.qoffset_z =
object.slot(
"qoffset_z");
630 const std::vector<float> srow_x =
object.slot(
"srow_x");
631 const std::vector<float> srow_y =
object.slot(
"srow_y");
632 const std::vector<float> srow_z =
object.slot(
"srow_z");
633 for (
int i=0; i<4; i++)
635 header.srow_x[i] = srow_x[i];
636 header.srow_y[i] = srow_y[i];
637 header.srow_z[i] = srow_z[i];
640 if (header.datatype == DT_UINT8 || header.datatype == DT_INT16 || header.datatype == DT_INT32 || header.datatype == DT_INT8 || header.datatype == DT_UINT16 || header.datatype == DT_UINT32)
641 header.datatype = DT_INT32;
642 else if (header.datatype == DT_FLOAT32 || header.datatype == DT_FLOAT64)
643 header.datatype = DT_FLOAT64;
645 throw std::runtime_error(
"Data type is not supported");
647 this->
image = nifti_convert_nhdr2nim(header, NULL);
649 const SEXP data = PROTECT(
object.slot(
".Data"));
650 if (!copyData || Rf_length(data) <= 1)
651 this->
image->data = NULL;
654 const size_t dataSize = nifti_get_volsize(this->
image);
655 this->
image->data = calloc(1, dataSize);
656 if (header.datatype == DT_INT32)
658 Rcpp::IntegerVector intData(data);
659 std::copy(intData.begin(), intData.end(),
static_cast<int32_t*
>(this->
image->data));
663 Rcpp::DoubleVector doubleData(data);
664 std::copy(doubleData.begin(), doubleData.end(),
static_cast<double*
>(this->
image->data));
672 Rcpp::Reference mriImage(
object);
673 Rcpp::Function getXform = mriImage.field(
"getXform");
674 Rcpp::NumericMatrix
xform = getXform();
678 if (Rf_length(mriImage.field(
"tags")) > 0)
681 Rcpp::RObject data = mriImage.field(
"data");
682 if (data.inherits(
"SparseArray"))
684 Rcpp::Language call(
"as.array", data);
688 const short datatype = (Rf_isNull(data) ? DT_INT32 :
sexpTypeToNiftiType(data.sexp_type()));
690 int dims[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
691 const std::vector<int> dimVector = mriImage.field(
"imageDims");
692 const int nDims = std::min(7,
int(dimVector.size()));
695 for (
int i=0; i<
nDims; i++)
697 dims[i+1] = dimVector[i];
698 nVoxels *= dimVector[i];
701 if (this->
image == NULL)
702 this->
image = nifti_make_new_nim(dims, datatype, FALSE);
705 std::copy(dims, dims+8, this->
image->
dim);
706 this->
image->datatype = datatype;
707 nifti_datatype_sizes(
image->datatype, &
image->nbyper, NULL);
710 if (copyData && !Rf_isNull(data))
713 const size_t dataSize = nVoxels *
image->nbyper;
714 this->
image->data = calloc(1, dataSize);
715 if (datatype == DT_INT32)
716 memcpy(this->
image->data, INTEGER(data), dataSize);
718 memcpy(this->
image->data, REAL(data), dataSize);
721 this->
image->data = NULL;
723 const std::vector<float> pixdimVector = mriImage.field(
"voxelDims");
724 const int pixdimLength = pixdimVector.size();
725 for (
int i=0; i<std::min(pixdimLength,nDims); i++)
726 this->
image->
pixdim[i+1] = std::abs(pixdimVector[i]);
728 const std::vector<std::string> pixunitsVector = mriImage.field(
"voxelDimUnits");
731 if (xform.rows() != 4 || xform.cols() != 4)
732 this->
image->qform_code = this->
image->sform_code = 0;
736 for (
int i=0; i<4; i++)
738 for (
int j=0; j<4; j++)
739 matrix.m[i][j] = static_cast<float>(xform(i,j));
742 this->
image->qto_xyz = matrix;
743 this->
image->qto_ijk = nifti_mat44_inverse(
image->qto_xyz);
744 nifti_mat44_to_quatern(
image->qto_xyz, &
image->quatern_b, &
image->quatern_c, &
image->quatern_d, &
image->qoffset_x, &
image->qoffset_y, &
image->qoffset_z, NULL, NULL, NULL, &
image->qfac);
746 this->
image->sto_xyz = matrix;
747 this->
image->sto_ijk = nifti_mat44_inverse(
image->sto_xyz);
749 this->
image->qform_code = this->
image->sform_code = 2;
755 Rcpp::List list(
object);
756 nifti_1_header *header = nifti_make_new_header(NULL, DT_FLOAT64);
758 const Rcpp::CharacterVector _names = list.names();
759 std::set<std::string> names;
760 for (Rcpp::CharacterVector::const_iterator it=_names.begin(); it!=_names.end(); it++)
761 names.insert(Rcpp::as<std::string>(*it));
763 internal::copyIfPresent(list, names,
"sizeof_hdr", header->sizeof_hdr);
765 internal::copyIfPresent(list, names,
"dim_info", header->dim_info);
766 if (names.count(
"dim") == 1)
768 std::vector<short>
dim = list[
"dim"];
769 for (
size_t i=0; i<std::min(dim.size(),size_t(8)); i++)
770 header->dim[i] = dim[i];
773 internal::copyIfPresent(list, names,
"intent_p1", header->intent_p1);
774 internal::copyIfPresent(list, names,
"intent_p2", header->intent_p2);
775 internal::copyIfPresent(list, names,
"intent_p3", header->intent_p3);
776 internal::copyIfPresent(list, names,
"intent_code", header->intent_code);
778 internal::copyIfPresent(list, names,
"datatype", header->datatype);
779 internal::copyIfPresent(list, names,
"bitpix", header->bitpix);
781 internal::copyIfPresent(list, names,
"slice_start", header->slice_start);
782 if (names.count(
"pixdim") == 1)
784 std::vector<float>
pixdim = list[
"pixdim"];
785 for (
size_t i=0; i<std::min(pixdim.size(),size_t(8)); i++)
786 header->pixdim[i] = pixdim[i];
788 internal::copyIfPresent(list, names,
"vox_offset", header->vox_offset);
789 internal::copyIfPresent(list, names,
"scl_slope", header->scl_slope);
790 internal::copyIfPresent(list, names,
"scl_inter", header->scl_inter);
791 internal::copyIfPresent(list, names,
"slice_end", header->slice_end);
792 internal::copyIfPresent(list, names,
"slice_code", header->slice_code);
793 internal::copyIfPresent(list, names,
"xyzt_units", header->xyzt_units);
794 internal::copyIfPresent(list, names,
"cal_max", header->cal_max);
795 internal::copyIfPresent(list, names,
"cal_min", header->cal_min);
796 internal::copyIfPresent(list, names,
"slice_duration", header->slice_duration);
797 internal::copyIfPresent(list, names,
"toffset", header->toffset);
799 if (names.count(
"descrip") == 1)
800 strcpy(header->descrip, Rcpp::as<std::string>(list[
"descrip"]).substr(0,79).c_str());
801 if (names.count(
"aux_file") == 1)
802 strcpy(header->aux_file, Rcpp::as<std::string>(list[
"aux_file"]).substr(0,23).c_str());
804 internal::copyIfPresent(list, names,
"qform_code", header->qform_code);
805 internal::copyIfPresent(list, names,
"sform_code", header->sform_code);
806 internal::copyIfPresent(list, names,
"quatern_b", header->quatern_b);
807 internal::copyIfPresent(list, names,
"quatern_c", header->quatern_c);
808 internal::copyIfPresent(list, names,
"quatern_d", header->quatern_d);
809 internal::copyIfPresent(list, names,
"qoffset_x", header->qoffset_x);
810 internal::copyIfPresent(list, names,
"qoffset_y", header->qoffset_y);
811 internal::copyIfPresent(list, names,
"qoffset_z", header->qoffset_z);
813 if (names.count(
"srow_x") == 1)
815 std::vector<float> srow_x = list[
"srow_x"];
816 for (
size_t i=0; i<std::min(srow_x.size(),size_t(4)); i++)
817 header->srow_x[i] = srow_x[i];
819 if (names.count(
"srow_y") == 1)
821 std::vector<float> srow_y = list[
"srow_y"];
822 for (
size_t i=0; i<std::min(srow_y.size(),size_t(4)); i++)
823 header->srow_y[i] = srow_y[i];
825 if (names.count(
"srow_z") == 1)
827 std::vector<float> srow_z = list[
"srow_z"];
828 for (
size_t i=0; i<std::min(srow_z.size(),size_t(4)); i++)
829 header->srow_z[i] = srow_z[i];
832 if (names.count(
"intent_name") == 1)
833 strcpy(header->intent_name, Rcpp::as<std::string>(list[
"intent_name"]).substr(0,15).c_str());
834 if (names.count(
"magic") == 1)
835 strcpy(header->magic, Rcpp::as<std::string>(list[
"magic"]).substr(0,3).c_str());
837 this->
image = nifti_convert_nhdr2nim(*header, NULL);
838 this->
image->data = NULL;
844 int dims[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
845 const std::vector<int> dimVector =
object.attr(
"dim");
847 const int nDims = std::min(7,
int(dimVector.size()));
849 for (
int i=0; i<
nDims; i++)
850 dims[i+1] = dimVector[i];
853 this->
image = nifti_make_new_nim(dims, datatype,
int(copyData));
857 const size_t dataSize = nifti_get_volsize(
image);
858 if (datatype == DT_INT32)
859 memcpy(this->
image->data, INTEGER(
object), dataSize);
861 memcpy(this->
image->data, REAL(
object), dataSize);
864 this->
image->data = NULL;
866 if (
object.hasAttribute(
"pixdim"))
868 const std::vector<float> pixdimVector =
object.attr(
"pixdim");
869 const int pixdimLength = pixdimVector.size();
870 for (
int i=0; i<std::min(pixdimLength,nDims); i++)
874 if (
object.hasAttribute(
"pixunits"))
876 const std::vector<std::string> pixunitsVector =
object.attr(
"pixunits");
884 Rcpp::RObject imageObject(
object);
885 bool resolved =
false;
887 if (imageObject.hasAttribute(
".nifti_image_ptr"))
889 Rcpp::XPtr<NiftiImage> imagePtr(SEXP(imageObject.attr(
".nifti_image_ptr")));
890 if (imagePtr.get() != NULL)
892 this->
image = imagePtr->image;
896 if (imageObject.hasAttribute(
"dim"))
899 else if (Rf_isString(
object))
900 throw std::runtime_error(
"Internal image is not valid");
902 Rf_warning(
"Ignoring invalid internal pointer");
907 if (Rf_isNull(
object))
909 else if (Rf_isString(
object))
911 const std::string path = Rcpp::as<std::string>(object);
912 this->
image = nifti_image_read(path.c_str(), readData);
913 if (this->image == NULL)
914 throw std::runtime_error(
"Failed to read image from path " + path);
916 else if (imageObject.inherits(
"nifti"))
918 else if (imageObject.inherits(
"anlz"))
919 throw std::runtime_error(
"Cannot currently convert objects of class \"anlz\"");
920 else if (imageObject.inherits(
"MriImage"))
922 else if (Rf_isVectorList(
object))
924 else if (imageObject.hasAttribute(
"dim"))
927 throw std::runtime_error(
"Cannot convert object of class \"" + Rcpp::as<std::string>(imageObject.attr(
"class")) +
"\" to a nifti_image");
930 if (this->
image != NULL)
931 nifti_update_dims_from_array(this->
image);
934 Rprintf(
"Creating NiftiImage with pointer %p (from SEXP)\n", this->
image);
941 const std::vector<float> origPixdim(
image->pixdim+1,
image->pixdim+4);
943 for (
int i=1; i<8; i++)
944 image->pixdim[i] = 0.0;
946 const int pixdimLength = pixdim.size();
947 for (
int i=0; i<std::min(pixdimLength,nDims); i++)
948 image->pixdim[i+1] = pixdim[i];
950 if (!std::equal(origPixdim.begin(), origPixdim.begin() + std::min(3,nDims), pixdim.begin()))
953 for (
int i=0; i<3; i++)
955 for (
int j=0; j<3; j++)
958 scaleMatrix.m[i][j] = 0.0;
960 scaleMatrix.m[i][j] = 1.0;
962 scaleMatrix.m[i][j] = pixdim[i] / origPixdim[i];
966 if (
image->qform_code > 0)
968 mat33 prod = nifti_mat33_mul(scaleMatrix, internal::topLeftCorner(
image->qto_xyz));
969 for (
int i=0; i<3; i++)
971 for (
int j=0; j<3; j++)
972 image->qto_xyz.m[i][j] = prod.m[i][j];
974 image->qto_ijk = nifti_mat44_inverse(
image->qto_xyz);
975 nifti_mat44_to_quatern(
image->qto_xyz, &
image->quatern_b, &
image->quatern_c, &
image->quatern_d, &
image->qoffset_x, &
image->qoffset_y, &
image->qoffset_z, NULL, NULL, NULL, &
image->qfac);
978 if (
image->sform_code > 0)
980 mat33 prod = nifti_mat33_mul(scaleMatrix, internal::topLeftCorner(
image->sto_xyz));
981 for (
int i=0; i<3; i++)
983 for (
int j=0; j<3; j++)
984 image->sto_xyz.m[i][j] = prod.m[i][j];
986 image->sto_ijk = nifti_mat44_inverse(
image->sto_xyz);
993 for (
size_t i=0; i<pixunits.size(); i++)
995 if (pixunits[i] ==
"m")
996 image->xyz_units = NIFTI_UNITS_METER;
997 else if (pixunits[i] ==
"mm")
998 image->xyz_units = NIFTI_UNITS_MM;
999 else if (pixunits[i] ==
"um")
1000 image->xyz_units = NIFTI_UNITS_MICRON;
1001 else if (pixunits[i] ==
"s")
1002 image->time_units = NIFTI_UNITS_SEC;
1003 else if (pixunits[i] ==
"ms")
1004 image->time_units = NIFTI_UNITS_MSEC;
1005 else if (pixunits[i] ==
"us")
1006 image->time_units = NIFTI_UNITS_USEC;
1007 else if (pixunits[i] ==
"Hz")
1008 image->time_units = NIFTI_UNITS_HZ;
1009 else if (pixunits[i] ==
"ppm")
1010 image->time_units = NIFTI_UNITS_PPM;
1011 else if (pixunits[i] ==
"rad/s")
1012 image->time_units = NIFTI_UNITS_RADS;
1020 for (
int i=0; i<std::min(3,
int(scales.size())); i++)
1022 if (scales[i] != 1.0)
1024 pixdim[i] /= scales[i];
1025 image->dim[i+1] =
static_cast<int>(std::floor(
image->dim[i+1] * scales[i]));
1030 nifti_update_dims_from_array(
image);
1038 Rcpp::RObject object(array);
1039 if (!
object.hasAttribute(
"dim"))
1042 for (
int i=0; i<8; i++)
1044 const std::vector<int> dimVector =
object.attr(
"dim");
1046 const int nDims = std::min(7,
int(dimVector.size()));
1048 for (
int i=0; i<
nDims; i++)
1049 image->dim[i+1] = dimVector[i];
1051 if (
object.hasAttribute(
"pixdim"))
1053 const std::vector<float> pixdimVector =
object.attr(
"pixdim");
1057 if (
object.hasAttribute(
"pixunits"))
1059 const std::vector<std::string> pixunitsVector =
object.attr(
"pixunits");
1064 nifti_update_dims_from_array(
image);
1068 nifti_datatype_sizes(
image->datatype, &
image->nbyper, NULL);
1072 const size_t dataSize = nifti_get_volsize(
image);
1073 image->data = calloc(1, dataSize);
1074 if (
image->datatype == DT_INT32)
1075 memcpy(
image->data, INTEGER(
object), dataSize);
1077 memcpy(
image->data, REAL(
object), dataSize);
1085 for (
int i=0; i<4; i++)
1087 for (
int j=0; j<4; j++)
1088 matrix.m[i][j] = 0.0;
1092 else if (
image->qform_code <= 0 &&
image->sform_code <= 0)
1096 for (
int i=0; i<4; i++)
1098 for (
int j=0; j<4; j++)
1101 matrix.m[i][j] = 0.0;
1103 matrix.m[3][3] = 1.0;
1105 matrix.m[i][j] = (
image->pixdim[i+1]==0.0 ? 1.0 :
image->pixdim[i+1]);
1110 else if ((preferQuaternion &&
image->qform_code > 0) ||
image->sform_code <= 0)
1111 return image->qto_xyz;
1113 return image->sto_xyz;
1116 template <
typename TargetType>
1120 return std::vector<TargetType>();
1122 size_t blockSize = 1;
1123 for (
int i=1; i<dimension; i++)
1124 blockSize *=
image->dim[i];
1126 std::vector<TargetType> data(blockSize);
1127 internal::convertData<TargetType>(
image->data,
image->datatype, blockSize, data.begin(), blockSize*index);
1131 template <
typename TargetType>
1135 return std::vector<TargetType>();
1137 std::vector<TargetType> data(
image->nvox);
1138 internal::convertData<TargetType>(
image->data,
image->datatype,
image->nvox, data.begin());
1144 if (this->
isNull() ||
image->datatype == datatype)
1147 if (
image->data != NULL)
1150 nifti_datatype_sizes(datatype, &bytesPerPixel, NULL);
1151 void *data = calloc(
image->nvox, bytesPerPixel);
1156 internal::convertData<uint8_t>(
image->data,
image->datatype,
image->nvox,
static_cast<uint8_t *
>(data));
1160 internal::convertData<int16_t>(
image->data,
image->datatype,
image->nvox,
static_cast<int16_t *
>(data));
1164 internal::convertData<int32_t>(
image->data,
image->datatype,
image->nvox,
static_cast<int32_t *
>(data));
1168 internal::convertData<float>(
image->data,
image->datatype,
image->nvox,
static_cast<float *
>(data));
1172 internal::convertData<double>(
image->data,
image->datatype,
image->nvox,
static_cast<double *
>(data));
1176 internal::convertData<int8_t>(
image->data,
image->datatype,
image->nvox,
static_cast<int8_t *
>(data));
1180 internal::convertData<uint16_t>(
image->data,
image->datatype,
image->nvox,
static_cast<uint16_t *
>(data));
1184 internal::convertData<uint32_t>(
image->data,
image->datatype,
image->nvox,
static_cast<uint32_t *
>(data));
1188 internal::convertData<int64_t>(
image->data,
image->datatype,
image->nvox,
static_cast<int64_t *
>(data));
1192 internal::convertData<uint64_t>(
image->data,
image->datatype,
image->nvox,
static_cast<uint64_t *
>(data));
1196 throw std::runtime_error(
"Unsupported data type (" + std::string(nifti_datatype_string(datatype)) +
")");
1199 nifti_image_unload(
image);
1203 image->datatype = datatype;
1204 nifti_datatype_sizes(datatype, &
image->nbyper, &
image->swapsize);
1212 template <
typename SourceType>
1217 else if (data.size() !=
image->nvox)
1218 throw std::runtime_error(
"New data length does not match the number of voxels in the image");
1220 if (datatype != DT_NONE)
1222 nifti_image_unload(
image);
1223 image->datatype = datatype;
1224 nifti_datatype_sizes(datatype, &
image->nbyper, &
image->swapsize);
1227 if (
image->data == NULL)
1229 internal::replaceData<SourceType>(data.begin(), data.end(),
image->data,
image->datatype);
1231 image->scl_slope = 0.0;
1232 image->scl_inter = 0.0;
1233 image->cal_min =
static_cast<float>(*std::min_element(data.begin(), data.end()));
1234 image->cal_max =
static_cast<float>(*std::max_element(data.begin(), data.end()));
1242 if (datatype == DT_NONE)
1247 const int status = nifti_set_filenames(imageToWrite, fileName.c_str(),
false,
true);
1249 throw std::runtime_error(
"Failed to set filenames for NIfTI object");
1250 nifti_image_write(imageToWrite);
1255 toFile(fileName, internal::stringToDatatype(datatype));
1260 Rcpp::RObject array;
1265 switch (
image->datatype)
1275 array = internal::imageDataToArray<INTSXP>(
image);
1280 array = internal::imageDataToArray<REALSXP>(
image);
1284 throw std::runtime_error(
"Unsupported data type (" + std::string(nifti_datatype_string(
image->datatype)) +
")");
1287 internal::addAttributes(array,
image);
1288 array.attr(
"class") = Rcpp::CharacterVector::create(
"niftiImage",
"array");
1295 return Rcpp::RObject();
1298 Rcpp::RObject
string = Rcpp::wrap(label);
1299 internal::addAttributes(
string,
image,
false);
1300 string.attr(
"class") = Rcpp::CharacterVector::create(
"internalImage",
"niftiImage");
1312 if (this->
image == NULL)
1313 return Rcpp::RObject();
1315 nifti_1_header header = nifti_convert_nim2nhdr(this->
image);
1318 result[
"sizeof_hdr"] = header.sizeof_hdr;
1320 result[
"dim_info"] = int(header.dim_info);
1321 result[
"dim"] = std::vector<short>(header.dim, header.dim+8);
1323 result[
"intent_p1"] = header.intent_p1;
1324 result[
"intent_p2"] = header.intent_p2;
1325 result[
"intent_p3"] = header.intent_p3;
1326 result[
"intent_code"] = header.intent_code;
1328 result[
"datatype"] = header.datatype;
1329 result[
"bitpix"] = header.bitpix;
1331 result[
"slice_start"] = header.slice_start;
1332 result[
"pixdim"] = std::vector<float>(header.pixdim, header.pixdim+8);
1333 result[
"vox_offset"] = header.vox_offset;
1334 result[
"scl_slope"] = header.scl_slope;
1335 result[
"scl_inter"] = header.scl_inter;
1336 result[
"slice_end"] = header.slice_end;
1337 result[
"slice_code"] = int(header.slice_code);
1338 result[
"xyzt_units"] = int(header.xyzt_units);
1339 result[
"cal_max"] = header.cal_max;
1340 result[
"cal_min"] = header.cal_min;
1341 result[
"slice_duration"] = header.slice_duration;
1342 result[
"toffset"] = header.toffset;
1343 result[
"descrip"] = std::string(header.descrip, 80);
1344 result[
"aux_file"] = std::string(header.aux_file, 24);
1346 result[
"qform_code"] = header.qform_code;
1347 result[
"sform_code"] = header.sform_code;
1348 result[
"quatern_b"] = header.quatern_b;
1349 result[
"quatern_c"] = header.quatern_c;
1350 result[
"quatern_d"] = header.quatern_d;
1351 result[
"qoffset_x"] = header.qoffset_x;
1352 result[
"qoffset_y"] = header.qoffset_y;
1353 result[
"qoffset_z"] = header.qoffset_z;
1354 result[
"srow_x"] = std::vector<float>(header.srow_x, header.srow_x+4);
1355 result[
"srow_y"] = std::vector<float>(header.srow_y, header.srow_y+4);
1356 result[
"srow_z"] = std::vector<float>(header.srow_z, header.srow_z+4);
1358 result[
"intent_name"] = std::string(header.intent_name, 16);
1359 result[
"magic"] = std::string(header.magic, 4);
1361 result.attr(
"class") = Rcpp::CharacterVector::create(
"niftiHeader");
NiftiImage()
Default constructor.
Definition: NiftiImage.h:162
void dropData()
Drop the data from the image, retaining only the metadata.
Definition: NiftiImage.h:399
const int index
The location along dimension.
Definition: NiftiImage.h:33
std::vector< int > dim() const
Return the dimensions of the image.
Definition: NiftiImage.h:332
const nifti_image * operator->() const
Allows a NiftiImage object to be treated as a pointer to a const nifti_image.
Definition: NiftiImage.h:260
Rcpp::RObject headerToList() const
Create an R list containing raw image metadata.
Definition: NiftiImage.h:1310
bool persistent
Marker of persistence, which determines whether the nifti_image should be freed on destruction...
Definition: NiftiImage.h:99
std::vector< float > pixdim() const
Return the dimensions of the pixels or voxels in the image.
Definition: NiftiImage.h:344
NiftiImage(const std::string &path, const bool readData=true)
Initialise using a path string.
Definition: NiftiImage.h:215
NiftiImage(nifti_image *const image, const bool copy=false)
Initialise using an existing nifti_image pointer.
Definition: NiftiImage.h:197
void rescale(const std::vector< float > &scales)
Rescale the image, changing its image dimensions and pixel dimensions.
Definition: NiftiImage.h:1016
Definition: NiftiImage.h:16
void initFromMriImage(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from a reference object of class "MriImage".
Definition: NiftiImage.h:670
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:57
bool isNull() const
Determine whether or not the internal pointer is NULL.
Definition: NiftiImage.h:310
Inner class referring to a subset of an image.
Definition: NiftiImage.h:29
Block slice(const int i)
Extract a slice block from a 3D image.
Definition: NiftiImage.h:462
void update(const SEXP array)
Update the image from an R array.
Definition: NiftiImage.h:1036
Rcpp::RObject toPointer(const std::string label) const
Create an internal image to pass back to R.
Definition: NiftiImage.h:1292
std::vector< TargetType > getData() const
Extract a vector of data from the image, casting it to any required element type. ...
Definition: NiftiImage.h:1132
void initFromArray(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an R array.
Definition: NiftiImage.h:842
void initFromNiftiS4(const Rcpp::RObject &object, const bool copyData=true)
Initialise the object from an S4 object of class "nifti".
Definition: NiftiImage.h:574
const Block slice(const int i) const
Extract a slice block from a 3D image.
Definition: NiftiImage.h:455
const Block volume(const int i) const
Extract a volume block from a 4D image.
Definition: NiftiImage.h:469
bool isPersistent() const
Determine whether or not the image is marked as persistent.
Definition: NiftiImage.h:315
void replaceData(const std::vector< SourceType > &data, const short datatype=DT_NONE)
Replace the pixel data in the image with the contents of a vector.
Definition: NiftiImage.h:1213
void setPixunits(const std::vector< std::string > &pixunits)
Modify the pixel dimension units.
Definition: NiftiImage.h:991
NiftiImage(const Block &source)
Initialise from a block, copying in the data.
Definition: NiftiImage.h:182
virtual ~NiftiImage()
Destructor which frees the wrapped pointer, unless the object is marked as persistent.
Definition: NiftiImage.h:236
Thin wrapper around a C-style nifti_image struct that allows C++-style destruction.
Definition: NiftiImage.h:22
void setPersistence(const bool persistent)
Marked the image as persistent, so that it can be passed back to R.
Definition: NiftiImage.h:298
NiftiImage(const NiftiImage &source)
Copy constructor.
Definition: NiftiImage.h:169
int nBlocks() const
Return the number of blocks in the image.
Definition: NiftiImage.h:424
void changeDatatype(const short datatype)
Change the datatype of the image, casting the pixel data if present.
Definition: NiftiImage.h:1142
const int dimension
The dimension along which the block applies (which should be the last)
Definition: NiftiImage.h:32
const NiftiImage & image
The parent image.
Definition: NiftiImage.h:31
void initFromList(const Rcpp::RObject &object)
Initialise the object from an R list with named elements, which can only contain metadata.
Definition: NiftiImage.h:753
void toFile(const std::string fileName, const short datatype=DT_NONE) const
Write the image to a NIfTI-1 file.
Definition: NiftiImage.h:1237
void updatePixdim(const std::vector< float > &pixdim)
Modify the pixel dimensions, and potentially the xform matrices to match.
Definition: NiftiImage.h:938
const Block block(const int i) const
Extract a block from the image.
Definition: NiftiImage.h:439
void copy(const nifti_image *source)
Copy the contents of a nifti_image to create a new image.
Definition: NiftiImage.h:523
mat44 xform(const bool preferQuaternion=true) const
Obtain an xform matrix, indicating the orientation of the image.
Definition: NiftiImage.h:1080
nifti_image * image
The wrapped nifti_image pointer.
Definition: NiftiImage.h:98
std::vector< TargetType > getData() const
Extract a vector of data from a block, casting it to any required element type.
Definition: NiftiImage.h:1117
Rcpp::RObject toArrayOrPointer(const bool internal, const std::string label) const
A conditional method that calls either toArray or toPointer.
Definition: NiftiImage.h:1305
static short sexpTypeToNiftiType(const int sexpType)
Convert between R SEXP object type and nifti_image datatype codes.
Definition: NiftiImage.h:87
int nDims() const
Return the number of dimensions in the image.
Definition: NiftiImage.h:320
Block volume(const int i)
Extract a volume block from a 4D image.
Definition: NiftiImage.h:476
NiftiImage & drop()
Drop unitary dimensions.
Definition: NiftiImage.h:358
Rcpp::RObject toArray() const
Create an R array from the image.
Definition: NiftiImage.h:1258
Block(const NiftiImage &image, const int dimension, const int index)
Standard constructor for this class.
Definition: NiftiImage.h:42
Block block(const int i)
Extract a block from the image.
Definition: NiftiImage.h:448