/* Templated image storage class Mark Jenkinson, FMRIB Image Analysis Group Copyright (C) 2000 University of Oxford */ /* Part of FSL - FMRIB's Software Library http://www.fmrib.ox.ac.uk/fsl fsl@fmrib.ox.ac.uk Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance Imaging of the Brain), Department of Clinical Neurology, Oxford University, Oxford, UK LICENCE FMRIB Software Library, Release 5.0 (c) 2012, The University of Oxford (the "Software") The Software remains the property of the University of Oxford ("the University"). The Software is distributed "AS IS" under this Licence solely for non-commercial use in the hope that it will be useful, but in order that the University as a charitable foundation protects its assets for the benefit of its educational and research purposes, the University makes clear that no condition is made or to be implied, nor is any warranty given or to be implied, as to the accuracy of the Software, or that it will be suitable for any particular purpose or for use under any specific conditions. Furthermore, the University disclaims all responsibility for the use which is made of the Software. It further disclaims any liability for the outcomes arising from using the Software. The Licensee agrees to indemnify the University and hold the University harmless from and against any and all claims, damages and liabilities asserted by third parties (including claims for negligence) which arise directly or indirectly from the use of the Software or the sale of any products based on the Software. No part of the Software may be reproduced, modified, transmitted or transferred in any form or by any means, electronic or mechanical, without the express permission of the University. The permission of the University is not required if the said reproduction, modification, transmission or transference is done without financial return, the conditions of this Licence are imposed upon the receiver of the product, and all original and amended source code is included in any transmitted product. You may be held legally responsible for any copyright infringement that is caused or encouraged by your failure to abide by these terms and conditions. You are not permitted under this Licence to use this Software commercially. Use for which any financial return is received shall be defined as commercial use, and includes (1) integration of all or part of the source code or the Software into a product for sale or license by or on behalf of Licensee to third parties or (2) use of the Software or any derivative of it for research with the final aim of developing software products for sale or license to a third party or (3) use of the Software or any derivative of it for research with the final aim of developing non-software products for sale or license to a third party, or (4) use of the Software to provide any service to an external organisation for which payment is received. If you are interested in using the Software commercially, please contact Isis Innovation Limited ("Isis"), the technology transfer company of the University, to negotiate a licence. Contact details are: innovation@isis.ox.ac.uk quoting reference DE/9564. */ #if !defined(__newimage_h) #define __newimage_h #include #include #include #include #include #include "newmatap.h" #include "lazy.h" #include "lazyiterators.h" #include "positerators.h" #include "miscmaths/miscmaths.h" #include "miscmaths/kernel.h" #include "niftiio/nifti1.h" #include "miscmaths/splinterpolator.h" using namespace NEWMAT; using namespace LAZY; using namespace MISCMATHS; using namespace std; namespace NEWIMAGE { const bool USEASSERT=false; // used inside imthrow to determine type of action void imthrow(const string& msg, int nierrnum); enum extrapolation { zeropad, constpad, extraslice, mirror, periodic, boundsassert, boundsexception, userextrapolation }; enum interpolation { nearestneighbour, trilinear, sinc, userkernel, userinterpolation, spline }; enum threshtype { inclusive , exclusive }; template class minmaxstuff { public: P min; P max; int minx; int miny; int minz; int mint; int maxx; int maxy; int maxz; int maxt; } ; #pragma interface template class volume : public lazymanager { private: T* Data; bool data_owner; int SizeBound; int SliceOffset; int SlicesZ; int RowsY; int ColumnsX; float Xdim; float Ydim; float Zdim; // the following matrices map voxel coords to mm coords (nifti conventions) mutable Matrix StandardSpaceCoordMat; mutable Matrix RigidBodyCoordMat; mutable int StandardSpaceTypeCode; mutable int RigidBodyTypeCode; mutable int IntentCode; mutable float IntentParam1; mutable float IntentParam2; mutable float IntentParam3; mutable int SliceOrderingCode; mutable std::vector ROIbox; mutable bool activeROI; mutable std::vector Limits; mutable unsigned long int no_voxels; lazy, volume > minmax; lazy, volume > sums; lazy, volume > robustlimits; lazy > principleaxes; lazy, volume > percentiles; mutable std::vector percentilepvals; lazy > l_histogram; mutable int HISTbins; mutable T HISTmin; mutable T HISTmax; lazy, volume > splint; mutable kernel interpkernel; mutable extrapolation p_extrapmethod; mutable interpolation p_interpmethod; mutable unsigned int splineorder; mutable T (*p_userextrap)(const volume& , int, int, int); mutable float (*p_userinterp)(const volume& , float, float, float); mutable T padvalue; mutable T extrapval; // the reference target for all extrapolations mutable std::vector ep_valid; // Indicates if extrapolation can produce "valid" values. mutable float displayMaximum; mutable float displayMinimum; char auxFile[24]; // Internal functions inline T* basicptr(int x, int y, int z) { return (Data + (z*RowsY + y)*ColumnsX + x); } inline T* basicptr(int x, int y, int z) const { return (Data + (z*RowsY + y)*ColumnsX + x); } int initialize(int xsize, int ysize, int zsize, T *d, bool d_owner); void setdefaultproperties(); void setupsizeproperties() const; void setdefaultlimits() const; void enforcelimits(std::vector& lims) const; void calc_no_voxels() const; const T& extrapolate(int x, int y, int z) const; float kernelinterpolation(const float x, const float y, const float z) const; float splineinterpolate(float x, float y, float z) const; float spline_interp1partial(float x, float y, float z, int dir, float *deriv) const; float spline_interp3partial(float x, float y, float z, float *dfdx, float *dfdy, float *dfdz) const; typedef T* nonsafe_fast_iterator; inline nonsafe_fast_iterator nsfbegin() { set_whole_cache_validity(false); return Data; } inline nonsafe_fast_iterator nsfend() { return Data+SizeBound; } template friend void copybasicproperties(const volume& source, volume& dest); void basic_swapdimensions(int dim1, int dim2, int dim3, bool keepLRorder); lazy > lazycog; // in voxel coordinates #ifdef EXPOSE_TREACHEROUS public: #endif // sampling_mat should now be avoided - use newimagevox2mm_mat instead bool RadiologicalFile; Matrix sampling_mat() const; void set_sform(int sform_code, const Matrix& snewmat) const; void set_qform(int qform_code, const Matrix& qnewmat) const; int left_right_order() const; // see also newimagevox2mm_mat() void swapLRorder(); void setLRorder(int LRorder); void makeradiological(); void makeneurological(); Matrix sform_mat() const { return StandardSpaceCoordMat; } int sform_code() const { return StandardSpaceTypeCode; } Matrix qform_mat() const { return RigidBodyCoordMat; } int qform_code() const { return RigidBodyTypeCode; } public: // CONSTRUCTORS AND DESTRUCTORS (including copy, = and reinitialize) volume(); volume(const volume& source); volume(int xsize, int ysize, int zsize); volume(int xsize, int ysize, int zsize, T *d, bool d_owner); ~volume(); void destroy(); const volume& operator=(const volume& source); int reinitialize(const volume& source); int reinitialize(int xsize, int ysize, int zsize); int reinitialize(int xsize, int ysize, int zsize, T *d, bool d_owner); int copyproperties(const volume& source); int copydata(const volume& source); // BASIC PROPERTIES inline int xsize() const { return ColumnsX; } inline int ysize() const { return RowsY; } inline int zsize() const { return SlicesZ; } inline float xdim() const { return Xdim; } inline float ydim() const { return Ydim; } inline float zdim() const { return Zdim; } inline float getDisplayMaximum() const { return displayMaximum; } inline float getDisplayMinimum() const { return displayMinimum; } inline string getAuxFile() const { return string(auxFile); } void setxdim(float x) { Xdim = fabs(x); } void setydim(float y) { Ydim = fabs(y); } void setzdim(float z) { Zdim = fabs(z); } void setdims(float x, float y, float z) { setxdim(x); setydim(y); setzdim(z); } void setDisplayMaximumMinimum(const float maximum, const float minimum) const { displayMaximum=maximum; displayMinimum=minimum; } void setDisplayMaximum(const float maximum) const { setDisplayMaximumMinimum(maximum,displayMinimum); } void setDisplayMinimum(const float minimum) const { setDisplayMaximumMinimum(displayMaximum,minimum); } void setAuxFile(const string fileName) { strncpy(auxFile,fileName.c_str(),24); } unsigned long int nvoxels() const { return no_voxels; } // ROI FUNCTIONS inline const std::vector& limits() const { return Limits; } inline int limits(int n) const { return Limits[n]; } inline int minx() const { return Limits[0]; } inline int maxx() const { return Limits[3]; } inline int miny() const { return Limits[1]; } inline int maxy() const { return Limits[4]; } inline int minz() const { return Limits[2]; } inline int maxz() const { return Limits[5]; } inline const std::vector& ROIlimits() const { return ROIbox; } inline int ROIlimits(int n) const { return ROIbox[n]; } inline bool usingROI() const { return activeROI; } void setROIlimits(int x0, int y0, int z0, int x1, int y1, int z1) const; void setROIlimits(const std::vector& lims) const; void activateROI() const; void deactivateROI() const; volume ROI() const; // returns a new volume = ROI int copyROIonly(const volume& source); // Volume<->ColumnVector conversion ReturnMatrix vec(const volume& mask) const; ReturnMatrix vec() const; void insert_vec(const ColumnVector& pvec, const volume& pmask); void insert_vec(const ColumnVector& pvec); vector labelToCoord(const long label) const; // SECONDARY PROPERTIES // maps *NEWIMAGE* voxel coordinates to mm (consistent with FSLView mm) // NB: do not try to determine left-right order from this matrix // sampling_mat should now be avoided - use newimagevox2mm_mat instead Matrix newimagevox2mm_mat() const; Matrix niftivox2newimagevox_mat() const; int intent_code() const { return IntentCode; } float intent_param(int n) const; void set_intent(int intent_code, float p1, float p2, float p3) const; T min() const { return minmax().min; } T max() const { return minmax().max; } int mincoordx() const { return minmax().minx; } int mincoordy() const { return minmax().miny; } int mincoordz() const { return minmax().minz; } int maxcoordx() const { return minmax().maxx; } int maxcoordy() const { return minmax().maxy; } int maxcoordz() const { return minmax().maxz; } double sum() const { return sums()[0]; } double sumsquares() const { return sums()[1]; } double mean() const { return sum()/((double) no_voxels); } double variance() const { double n=(double) no_voxels; return (n/(n-1))*(sumsquares()/n - mean()*mean()); } double stddev() const { return sqrt(variance()); } T robustmin() const { return robustlimits()[0]; } T robustmax() const { return robustlimits()[1]; } ColumnVector principleaxis(int n) const; Matrix principleaxes_mat() const; T percentile(float pvalue) const; // argument in range [0.0 , 1.0] std::vector percentilepvalues() const { return percentilepvals; } ColumnVector histogram(int nbins) const; ColumnVector histogram(int nbins, T minval, T maxval) const; int histbins() const { return HISTbins; } T histmin() const { return HISTmin; } T histmax() const { return HISTmax; } lazy > backgroundval; ColumnVector cog(const string& coordtype="voxel") const; // SECONDARY PROPERTIES (using mask) T min(const volume& mask) const; T max(const volume& mask) const; int mincoordx(const volume& mask) const; int mincoordy(const volume& mask) const; int mincoordz(const volume& mask) const; int maxcoordx(const volume& mask) const; int maxcoordy(const volume& mask) const; int maxcoordz(const volume& mask) const; double sum(const volume& mask) const; double sumsquares(const volume& mask) const; double mean(const volume& mask) const; double variance(const volume& mask) const; double stddev(const volume& mask) const { return sqrt(variance(mask)); } T robustmin(const volume& mask) const; T robustmax(const volume& mask) const; T percentile(float pvalue, const volume& mask) const; // arg in [0,1] ColumnVector histogram(int nbins, const volume& mask) const; ColumnVector histogram(int nbins, T minval, T maxval, const volume& mask) const; // DATA ACCESS FUNCTIONS (iterators) typedef const T* fast_const_iterator; inline fast_const_iterator fbegin() const { return Data; } inline fast_const_iterator fend() const { return Data+SizeBound; } // BASIC DATA ACCESS FUNCTIONS inline bool in_bounds(int x, int y, int z) const { return ( (x>=0) && (y>=0) && (z>=0) && (x=0) && (iy>=0) && (iz>=0) && ((ix+1)=-1) && (iy>=-1) && (iz>=-1) && (ix=0 && x=0 && y=0 && z= 0.0 && x <= ColumnsX-1+tol)) && (ep_valid[1] || (y+tol >= 0.0 && y <= RowsY-1+tol)) && (ep_valid[2] || (z+tol >= 0.0 && z <= SlicesZ-1+tol))); // return((ep_valid[0] || (ix>=0 && (ix+1)=0 && (iy+1)=0 && (iz+1) (extrapolate(x,y,z)); } inline const T& operator()(int x, int y, int z) const { if (in_bounds(x,y,z)) return *(basicptr(x,y,z)); else return extrapolate(x,y,z); } float interpolate(float x, float y, float z) const; float interpolate(float x, float y, float z, bool *ep) const; float interp1partial(// Input float x, float y, float z, // Co-ordinates to get value for int dir, // Direction for partial, 0->x, 1->y, 2->z // Output float *pderiv // Derivative returned here ) const; float interp3partial(// Input float x, float y, float z, // Co-ordinate to get value for // Output float *dfdx, float *dfdy, float *dfdz // Partials ) const; inline T& value(int x, int y, int z) { set_whole_cache_validity(false); return *(basicptr(x,y,z)); } inline const T& value(int x, int y, int z) const { return *(basicptr(x,y,z)); } float interpolatevalue(float x, float y, float z) const; ColumnVector ExtractRow(int j, int k) const; ColumnVector ExtractColumn(int i, int k) const; void SetRow(int j, int k, const ColumnVector& row); void SetColumn(int j, int k, const ColumnVector& col); // SECONDARY FUNCTIONS void setextrapolationmethod(extrapolation extrapmethod) const { p_extrapmethod = extrapmethod; } extrapolation getextrapolationmethod() const { return(p_extrapmethod); } void setpadvalue(T padval) const { padvalue = padval; } T getpadvalue() const { return padvalue; } void defineuserextrapolation(T (*extrap)( const volume& , int, int, int)) const; void setinterpolationmethod(interpolation interpmethod) const; interpolation getinterpolationmethod() const { return p_interpmethod; } void setsplineorder(unsigned int order) const; unsigned int getsplineorder() const { return(splineorder); } void forcesplinecoefcalculation() const { splint(); } void setextrapolationvalidity(bool xv, bool yv, bool zv) const { ep_valid[0]=xv; ep_valid[1]=yv; ep_valid[2]=zv; } std::vector getextrapolationvalidity() const { return(ep_valid); } void defineuserinterpolation(float (*interp)( const volume& , float, float, float)) const; void definekernelinterpolation(const ColumnVector& kx, const ColumnVector& ky, const ColumnVector& kz, int wx, int wy, int wz) const; // full-width void definekernelinterpolation(const volume& vol) const; void definesincinterpolation(const string& sincwindowtype, int w, int nstore=1201) const; // full-width void definesincinterpolation(const string& sincwindowtype, int wx, int wy, int wz, int nstore=1201) const; // full-width inline void getneighbours(int x, int y, int z, T &v000, T &v001, T &v010, T &v011, T &v100, T &v101, T &v110, T &v111) const; inline void getneighbours(int x, int y, int z, T &v000, T &v010, T &v100, T &v110) const; // ARITHMETIC FUNCTIONS T operator=(T val); const volume& operator+=(T val); const volume& operator-=(T val); const volume& operator*=(T val); const volume& operator/=(T val); const volume& operator+=(const volume& source); const volume& operator-=(const volume& source); const volume& operator*=(const volume& source); const volume& operator/=(const volume& source); volume operator+(T num) const; volume operator-(T num) const; volume operator*(T num) const; volume operator/(T num) const; volume operator+(const volume& vol2) const; volume operator-(const volume& vol2) const; volume operator*(const volume& vol2) const; volume operator/(const volume& vol2) const; template friend volume operator+(S num, const volume& vol); template friend volume operator-(S num, const volume& vol); template friend volume operator*(S num, const volume& vol); template friend volume operator/(S num, const volume& vol); template friend volume operator-(const volume& vol); // Comparisons. These are used for "spatial" purposes // so that if data is identical and all the "spatial // fields of the header are identical then the volumes // are considered identical. template friend bool operator==(const volume& v1, const volume& v2); template friend bool operator!=(const volume& v1, const volume& v2); // { return(!(v1==v2)); } // GENERAL MANIPULATION void binarise(T lowerth, T upperth, threshtype tt=inclusive); void binarise(T thresh) { this->binarise(thresh,this->max(),inclusive); } void threshold(T lowerth, T upperth, threshtype tt=inclusive); void threshold(T thresh) { this->threshold(thresh,this->max(),inclusive); } // valid entries for dims are +/- 1, 2, 3 (and for newx, etc they are x, -x, y, -y, z, -z) void swapdimensions(int dim1, int dim2, int dim3); void swapdimensions(const string& newx, const string& newy, const string& newz); Matrix swapmat(int dim1, int dim2, int dim3) const; Matrix swapmat(const string& newx, const string& newy, const string& newz) const; // CONVERSION FUNCTIONS template friend void copyconvert(const volume& source, volume& dest); }; // HELPER FUNCTIONS template long int no_mask_voxels(const volume& mask); template void convertbuffer(const S* source, D* dest, int len); template void convertbuffer(const S* source, D* dest, int len, float slope, float intercept); template bool samesize(const volume& vol1, const volume& vol2, bool checkdim=false); template bool sameabssize(const volume& vol1, const volume& vol2, bool checkdim=false); template bool samedim(const volume& vol1, const volume& vol2); //////////////////////// VOLUME4D CLASS ///////////////////////////// template class volume4D : public lazymanager { private: std::vector > vols; float p_TR; int dim5; mutable std::vector ROIbox; mutable bool activeROI; mutable std::vector Limits; mutable extrapolation p_extrapmethod; mutable interpolation p_interpmethod; mutable T (*p_userextrap)(const volume& , int, int, int); mutable float (*p_userinterp)(const volume& , float, float, float); mutable T p_padval; lazy, volume4D > tsminmax; lazy, volume4D > sums; lazy, volume4D > robustlimits; lazy, volume4D > percentiles; mutable std::vector percentilepvals; lazy > l_histogram; mutable int HISTbins; mutable T HISTmin; mutable T HISTmax; // Internal functions int initialize(int xsize, int ysize, int zsize, int tsize, T *d=0); void setdefaultproperties(); void setdefaultlimits() const; void enforcelimits(std::vector& lims) const; template friend void copybasicproperties(const volume& source, volume4D& dest); template friend void copybasicproperties(const volume4D& source, volume& dest); template friend void copybasicproperties(const volume4D& source, volume4D& dest); #ifdef EXPOSE_TREACHEROUS public: #endif // sampling_mat should now be avoided - use newimagevox2mm_mat instead Matrix sampling_mat() const; void set_sform(int sform_code, const Matrix& snewmat) const; void set_qform(int qform_code, const Matrix& qnewmat) const; int left_right_order() const; void swapLRorder(); void setLRorder(int LRorder); void makeradiological(); void makeneurological(); Matrix sform_mat() const; int sform_code() const; Matrix qform_mat() const; int qform_code() const; public: // CONSTRUCTORS AND DESTRUCTORS (including copy, = and reinitialize) volume4D(); volume4D(const volume4D& source); volume4D(int xsize, int ysize, int zsize, int tsize, T *d=0); ~volume4D(); void destroy(); const volume4D& operator=(const volume4D& source); const volume4D& operator=(const volume& source); int reinitialize(const volume4D& source); int reinitialize(int xsize, int ysize, int zsize, int tsize, T *d=0); int copyproperties(const volume4D& source); int copyproperties(const volume& source); int copyvolumes(const volume4D& source); // DATA ACCESS inline bool in_bounds(int x, int y, int z) const { return ( (vols.size()>0) && vols[0].in_bounds(x,y,z) ); } bool in_bounds(float x, float y, float z) const { return ( (vols.size()>0) && vols[0].in_bounds(x,y,z) ); } inline bool in_bounds(int t) const { return ( (t>=0) && (ttsize()) ); } inline bool in_bounds(int x, int y, int z, int t) const { return ( (t>=0) && (ttsize()) && vols[Limits[3]].in_bounds(x,y,z) ); } bool in_bounds(float x, float y, float z, int t) const { return ( (t>=0) && (ttsize()) && vols[Limits[3]].in_bounds(x,y,z) ); } bool valid(int x, int y, int z) const {return(vols.size()>0 && vols[0].valid(x,y,z));} bool valid(float x, float y, float z) const {return(vols.size()>0 && vols[0].valid(x,y,z));} inline T& operator()(int x, int y, int z, int t) { set_whole_cache_validity(false); if (!in_bounds(t)) imthrow("Out of Bounds (time index)",5); return vols[t](x,y,z); } inline const T& operator()(int x, int y, int z, int t) const { if (!in_bounds(t)) imthrow("Out of Bounds (time index)",5); return vols[t](x,y,z); } inline T& value(int x, int y, int z, int t) { set_whole_cache_validity(false); return vols[t].value(x,y,z); } inline const T& value(int x, int y, int z, int t) const { return vols[t].value(x,y,z); } inline volume& operator[](int t) { set_whole_cache_validity(false); if (!in_bounds(t)) imthrow("Out of Bounds (time index)",5); return vols[t]; } inline const volume& operator[](int t) const { if (!in_bounds(t)) imthrow("Out of Bounds (time index)",5); return vols[t]; } // SINGLE VOXEL TIME-SERIES ACCESS ReturnMatrix voxelts(int x, int y, int z) const; void setvoxelts(const ColumnVector& ts, int x, int y, int z); // WHOLE VOLUME MODIFIERS void addvolume(const volume& source); void addvolume(const volume4D& source); void insertvolume(const volume& source, int t); void deletevolume(int t); void clear(); // deletes all volumes // MATRIX <-> VOLUME4D CONVERSIONS ReturnMatrix matrix(const volume& mask) const; ReturnMatrix matrix(const volume& mask, vector& voxelLabels) const; ReturnMatrix matrix() const; void setmatrix(const Matrix& newmatrix, const volume& mask, const T pad=0); void setmatrix(const Matrix& newmatrix); volume vol2matrixkey(const volume& mask); //returns a volume with numbers in relating to matrix colnumbers ReturnMatrix matrix2volkey(volume& mask); // SIZE AND DIMENSIONS inline int xsize() const { if (vols.size()>0) return vols[0].xsize(); else return 0; } inline int ysize() const { if (vols.size()>0) return vols[0].ysize(); else return 0; } inline int zsize() const { if (vols.size()>0) return vols[0].zsize(); else return 0; } inline int tsize() const { return (int) vols.size(); } inline int size5() const { return dim5; } void setsize5(int d5) { if (d5>=1) dim5 = d5; else dim5=1; } inline float xdim() const { if (vols.size()>0) return vols[0].xdim(); else return 1.0; } inline float ydim() const { if (vols.size()>0) return vols[0].ydim(); else return 1.0; } inline float zdim() const { if (vols.size()>0) return vols[0].zdim(); else return 1.0; } inline float tdim() const { return p_TR; } inline float TR() const { return p_TR; } inline float getDisplayMaximum() const { if (vols.size()>0) return vols[0].getDisplayMaximum(); else return 0; } inline float getDisplayMinimum() const { if (vols.size()>0) return vols[0].getDisplayMinimum(); else return 0; } inline string getAuxFile() const { if (vols.size()>0) return vols[0].getAuxFile(); else return string(""); } void setxdim(float x); void setydim(float y); void setzdim(float z); void settdim(float tr) { p_TR = fabs(tr); } void setTR(float tr) { settdim(tr); } void setdims(float x, float y, float z, float tr) { setxdim(x); setydim(y); setzdim(z); settdim(tr); } unsigned long int nvoxels() const { if (vols.size()>0) return vols[0].nvoxels(); else return 0; } int ntimepoints() const { return this->tsize(); } void setDisplayMaximumMinimum(const float maximum, const float minimum) const; void setDisplayMaximum(const float maximum) const { setDisplayMaximumMinimum(maximum,vols[0].getDisplayMinimum()); } void setDisplayMinimum(const float minimum) const { setDisplayMaximumMinimum(vols[0].getDisplayMaximum(),minimum); } void setAuxFile(const string fileName); void setinterpolationmethod(interpolation interpmethod) const; interpolation getinterpolationmethod() const; void setsplineorder(unsigned int order) const; unsigned int getsplineorder() const; void setextrapolationvalidity(bool xv, bool yv, bool zv) const; std::vector getextrapolationvalidity() const; void setextrapolationmethod(extrapolation extrapmethod) const; extrapolation getextrapolationmethod() const; void setpadvalue(T padval) const; T getpadvalue() const; void defineuserinterpolation(float (*interp)( const volume& , float, float, float)) const; void defineuserextrapolation(T (*extrap)( const volume& , int, int, int)) const; void definekernelinterpolation(const ColumnVector& kx, const ColumnVector& ky, const ColumnVector& kz, int wx, int wy, int wz) const; void definekernelinterpolation(const volume4D& vol) const; void definekernelinterpolation(const volume& vol) const; void definesincinterpolation(const string& sincwindowtype, int w, int nstore=1201) const; void definesincinterpolation(const string& sincwindowtype, int wx, int wy, int wz, int nstore=1201) const; // ROI FUNCTIONS inline const std::vector& limits() const { return Limits; } inline int limits(int n) const { return Limits[n]; } inline int minx() const { return Limits[0]; } inline int maxx() const { return Limits[4]; } inline int miny() const { return Limits[1]; } inline int maxy() const { return Limits[5]; } inline int minz() const { return Limits[2]; } inline int maxz() const { return Limits[6]; } inline int mint() const { return Limits[3]; } inline int maxt() const { return Limits[7]; } inline const std::vector& ROIlimits() const { return ROIbox; } inline int ROIlimits(int n) const { return ROIbox[n]; } inline bool usingROI() const { return activeROI; } void setROIlimits(int x0, int y0, int z0, int t0, int x1, int y1, int z1, int t1) const; void setROIlimits(int t0, int t1) const; void setROIlimits(int x0, int y0, int z0, int x1, int y1, int z1) const; void setROIlimits(const std::vector& lims) const; void activateROI() const; void deactivateROI() const; volume4D ROI() const; // returns a new volume = ROI int copyROIonly(const volume4D& source); // SECONDARY PROPERTIES // maps *NEWIMAGE* voxel coordinates to mm (consistent with FSLView mm) // NB: do not try to determine left-right order from this matrix // sampling_mat should now be avoided - use newimagevox2mm_mat instead Matrix newimagevox2mm_mat() const; Matrix niftivox2newimagevox_mat() const; int intent_code() const; float intent_param(int n) const; void set_intent(int intent_code, float p1, float p2, float p3) const; T min() const { return tsminmax().min; } T max() const { return tsminmax().max; } int mincoordx() const { return tsminmax().minx; } int mincoordy() const { return tsminmax().miny; } int mincoordz() const { return tsminmax().minz; } int mincoordt() const { return tsminmax().mint; } int maxcoordx() const { return tsminmax().maxx; } int maxcoordy() const { return tsminmax().maxy; } int maxcoordz() const { return tsminmax().maxz; } int maxcoordt() const { return tsminmax().maxt; } double sum() const { return sums()[0]; } double sumsquares() const { return sums()[1]; } double mean() const { return sum()/(Max(1.0,(double) nvoxels()*ntimepoints()));} double variance() const { double n=(double) nvoxels() * ntimepoints(); return (n/(n-1))*(sumsquares()/n - mean()*mean()); } double stddev() const { return sqrt(variance()); } T robustmin() const { return robustlimits()[0]; } T robustmax() const { return robustlimits()[1]; } Matrix principleaxes_mat() const; T percentile(float pvalue) const; // argument in range [0.0 , 1.0] std::vector percentilepvalues() const { return percentilepvals; } ColumnVector histogram(int nbins) const; ColumnVector histogram(int nbins, T minval, T maxval) const; int histbins() const { return HISTbins; } T histmin() const { return HISTmin; } T histmax() const { return HISTmax; } // SECONDARY PROPERTIES (using a 3D mask) T min(const volume& mask) const; T max(const volume& mask) const; int mincoordx(const volume& mask) const; int mincoordy(const volume& mask) const; int mincoordz(const volume& mask) const; int maxcoordx(const volume& mask) const; int maxcoordy(const volume& mask) const; int maxcoordz(const volume& mask) const; double sum(const volume& mask) const; double sumsquares(const volume& mask) const; double mean(const volume& mask) const; double variance(const volume& mask) const; double stddev(const volume& mask) const { return sqrt(variance(mask)); } T percentile(float pvalue, const volume& mask) const; // arg in [0,1] T robustmin(const volume& mask) const; T robustmax(const volume& mask) const; ColumnVector histogram(int nbins, const volume& mask) const; ColumnVector histogram(int nbins, T minval, T maxval, const volume& mask) const; // SECONDARY PROPERTIES (using a 4D mask) T min(const volume4D& mask) const; T max(const volume4D& mask) const; int mincoordx(const volume4D& mask) const; int mincoordy(const volume4D& mask) const; int mincoordz(const volume4D& mask) const; int maxcoordx(const volume4D& mask) const; int maxcoordy(const volume4D& mask) const; int maxcoordz(const volume4D& mask) const; double sum(const volume4D& mask) const; double sumsquares(const volume4D& mask) const; double mean(const volume4D& mask) const; double variance(const volume4D& mask) const; double stddev(const volume4D& mask) const { return sqrt(variance(mask));} T percentile(float pvalue, const volume4D& mask) const; // arg in [0,1] T robustmin(const volume4D& mask) const; T robustmax(const volume4D& mask) const; ColumnVector histogram(int nbins, const volume4D& mask) const; ColumnVector histogram(int nbins, T minval, T maxval, const volume4D& mask) const; // GENERAL MANIPULATION void binarise(T lowerth, T upperth, threshtype tt=inclusive); void binarise(T thresh) { this->binarise(thresh,this->max(),inclusive); } void threshold(T lowerth, T upperth, threshtype tt=inclusive); void threshold(T thresh) { this->threshold(thresh,this->max(),inclusive); } // valid entries for dims are +/- 1, 2, 3 (and for newx, etc they are x, -x, y, -y, z, -z) void swapdimensions(int dim1, int dim2, int dim3); void swapdimensions(const string& newx, const string& newy, const string& newz); Matrix swapmat(int dim1, int dim2, int dim3) const; Matrix swapmat(const string& newx, const string& newy, const string& newz) const; // ARITHMETIC FUNCTIONS T operator=(T val); const volume4D& operator+=(T val); const volume4D& operator-=(T val); const volume4D& operator*=(T val); const volume4D& operator/=(T val); const volume4D& operator+=(const volume& source); const volume4D& operator-=(const volume& source); const volume4D& operator*=(const volume& source); const volume4D& operator/=(const volume& source); const volume4D& operator+=(const volume4D& source); const volume4D& operator-=(const volume4D& source); const volume4D& operator*=(const volume4D& source); const volume4D& operator/=(const volume4D& source); volume4D operator+(T num) const; volume4D operator-(T num) const; volume4D operator*(T num) const; volume4D operator/(T num) const; volume4D operator+(const volume& vol2) const; volume4D operator-(const volume& vol2) const; volume4D operator*(const volume& vol2) const; volume4D operator/(const volume& vol2) const; volume4D operator+(const volume4D& vol2) const; volume4D operator-(const volume4D& vol2) const; volume4D operator*(const volume4D& vol2) const; volume4D operator/(const volume4D& vol2) const; template friend volume4D operator+(S num, const volume4D& vol); template friend volume4D operator-(S num, const volume4D& vol); template friend volume4D operator*(S num, const volume4D& vol); template friend volume4D operator/(S num, const volume4D& vol); template friend volume4D operator-(const volume4D& vol); template friend volume4D operator+(const volume& v1, const volume4D& v2); template friend volume4D operator-(const volume& v1, const volume4D& v2); template friend volume4D operator*(const volume& v1, const volume4D& v2); // CONVERSION FUNCTIONS template friend void copyconvert(const volume4D& source, volume4D& dest); }; // HELPER FUNCTIONS template bool samesize(const volume4D& vol1, const volume4D& vol2, bool checkdim=false); template bool sameabssize(const volume4D& vol1, const volume4D& vol2, bool checkdim=false); template bool samedim(const volume4D& vol1, const volume4D& vol2); //////////////////////////////////////////////////////////////////////// ///////////////////////// DEBUGGING FUNCTIONS ////////////////////////// //////////////////////////////////////////////////////////////////////// template void print_info(const volume& source, const string& name) { cout << name << ":: Size = (" << source.xsize() << "," << source.ysize() << "," << source.zsize() << ")" << endl; cout << name << ":: ROI Size = (" << source.maxx() - source.minx() + 1 << "," << source.maxy() - source.miny() + 1 << "," << source.maxz() - source.minz() + 1 << ")" << endl; cout << name << ":: Dims = (" << source.xdim() << "," << source.ydim() << "," << source.zdim() << ")" << endl; cout << name << ":: Minimum and maximum intensities are: " << source.min() << " and " << source.max() << endl; } template void print_info(const volume4D& source, const string& name) { cout << name << ":: Size = (" << source.xsize() << "," << source.ysize() << "," << source.zsize() << "," << source.tsize() << ")" << endl; cout << name << ":: ROI Size = (" << source.maxx() - source.minx() + 1 << "," << source.maxy() - source.miny() + 1 << "," << source.maxz() - source.minz() + 1 << "," << source.maxt() - source.mint() + 1 << ")" << endl; cout << name << ":: Dims = (" << source.xdim() << "," << source.ydim() << "," << source.zdim() << "," << source.tdim() << ")" << endl; cout << name << ":: Minimum and maximum intensities are: " << source.min() << " and " << source.max() << endl; } //////////////////////////////////////////////////////////////////////// ///////////////////////// INLINE DEFINITIONS /////////////////////////// //////////////////////////////////////////////////////////////////////// template inline void volume::getneighbours(int x, int y, int z, T &v000, T &v001, T &v010, T &v011, T &v100, T &v101, T &v110, T &v111) const { T *ptr = basicptr(x,y,z); v000 = *ptr; ptr++; v100 = *ptr; ptr+= ColumnsX; v110 = *ptr; ptr--; v010 = *ptr; ptr += SliceOffset; v011 = *ptr; ptr++; v111 = *ptr; ptr-= ColumnsX; v101 = *ptr; ptr--; v001 = *ptr; } template inline void volume::getneighbours(int x, int y, int z, T &v000, T &v010, T &v100, T &v110) const { T *ptr = basicptr(x,y,z); v000 = *ptr; ptr++; v100 = *ptr; ptr+= ColumnsX; v110 = *ptr; ptr--; v010 = *ptr; } // template // inline volume::iterator volume::begin() // { return volume::iterator(basicptr(Limits[0],Limits[1],Limits[2]), // (lazymanager*) this, // Limits[0],Limits[1],Limits[2], // Limits[0],Limits[1],Limits[2], // Limits[3],Limits[4],Limits[5], // ColumnsX,SliceOffset); } // template // inline volume::iterator volume::end() // { volume::iterator tmp(basicptr(Limits[3],Limits[4],Limits[5]), // (lazymanager*) this, // Limits[3],Limits[4],Limits[5], // Limits[0],Limits[1],Limits[2], // Limits[3],Limits[4],Limits[5], // ColumnsX,SliceOffset); // return ++tmp; } // template // inline volume::const_iterator volume::begin() const // { return // volume::const_iterator(basicptr(Limits[0],Limits[1],Limits[2]), // Limits[0],Limits[1],Limits[2], // Limits[0],Limits[1],Limits[2], // Limits[3],Limits[4],Limits[5], // ColumnsX,SliceOffset); } // template // inline volume::const_iterator volume::end() const // { volume::const_iterator tmp(basicptr(Limits[3],Limits[4],Limits[5]), // Limits[3],Limits[4],Limits[5], // Limits[0],Limits[1],Limits[2], // Limits[3],Limits[4],Limits[5], // ColumnsX,SliceOffset); // return ++tmp; } //////////////////////////////////////////////////////////////////////// /////////////////////////// HELPER FUNCTIONS /////////////////////////// //////////////////////////////////////////////////////////////////////// template long int no_mask_voxels(const volume& mask) { long int n=0; for (int z=mask.minz(); z<=mask.maxz(); z++) { for (int y=mask.miny(); y<=mask.maxy(); y++) { for (int x=mask.minx(); x<=mask.maxx(); x++) { if (mask.value(x,y,z)>(T) 0.5) n++; } } } return n; } template long int no_mask_voxels(const volume4D& mask) { long int n=0; for (int t=mask.mint(); t<=mask.maxt(); t++) { for (int z=mask.minz(); z<=mask.maxz(); z++) { for (int y=mask.miny(); y<=mask.maxy(); y++) { for (int x=mask.minx(); x<=mask.maxx(); x++) { if (mask.value(x,y,z,t)>(T) 0.5) n++; } } } } return n; } template long int no_timepoints(const volume4D& vol) { return (vol.maxt()-vol.mint()+1); } template void convertbuffer(const S* source, D* dest, int len) { D* dptr=dest; for (const S* sptr=source; sptr<(source+len); sptr++) { *dptr = (D) *sptr; dptr++; } } template void convertbuffer(const S* source, D* dest, int len, float slope, float intercept) { D* dptr=dest; for (const S* sptr=source; sptr<(source+len); sptr++) { *dptr = (D) ((*sptr) * slope + intercept); dptr++; } } template bool samesize(const volume& vol1, const volume& vol2, bool checkdim) { bool same = ( ( (vol1.maxx()-vol1.minx())==(vol2.maxx()-vol2.minx()) ) && ( (vol1.maxy()-vol1.miny())==(vol2.maxy()-vol2.miny()) ) && ( (vol1.maxz()-vol1.minz())==(vol2.maxz()-vol2.minz()) ) ); if (checkdim) same = same && samedim(vol1,vol2); return(same); } template bool samesize(const volume4D& vol1, const volume4D& vol2, bool checkdim) { bool same = ( ( (vol1.maxt()-vol1.mint())==(vol2.maxt()-vol2.mint()) ) && ( (vol1.tsize()<=0) || (vol2.tsize()<=0) || samesize(vol1[0],vol2[0]) ) ); if (checkdim) same = same && samedim(vol1,vol2); return(same); } template bool sameabssize(const volume& vol1, const volume& vol2, bool checkdim) { bool same = ( ( (vol1.xsize())==(vol2.xsize()) ) && ( (vol1.ysize())==(vol2.ysize()) ) && ( (vol1.zsize())==(vol2.zsize()) ) ); if (checkdim) same = same && samedim(vol1,vol2); return(same); } template bool sameabssize(const volume4D& vol1, const volume4D& vol2, bool checkdim) { bool same = ( ( (vol1.tsize())==(vol2.tsize()) ) && ( (vol1.tsize()==0) || samesize(vol1[0],vol2[0]) ) ); if (checkdim) same = same && samedim(vol1,vol2); return(same); } template bool samedim(const volume& vol1, const volume& vol2) { return(std::abs(vol1.xdim()-vol2.xdim())<1e-6 && std::abs(vol1.ydim()-vol2.ydim())<1e-6 && std::abs(vol1.zdim()-vol2.zdim())<1e-6); } template bool samedim(const volume4D& vol1, const volume4D& vol2) { return(std::abs(vol1.tdim()-vol2.tdim())<1e-6 && samedim(vol1[0],vol2[0])); } //////////////////////////////////////////////////////////////////////// /////////////////////////// FRIEND FUNCTIONS /////////////////////////// //////////////////////////////////////////////////////////////////////// template void copybasicproperties(const volume& source, volume& dest) { // set up properties (except lazy ones) dest.Xdim = source.Xdim; dest.Ydim = source.Ydim; dest.Zdim = source.Zdim; dest.StandardSpaceCoordMat = source.StandardSpaceCoordMat; dest.RigidBodyCoordMat = source.RigidBodyCoordMat; dest.StandardSpaceTypeCode = source.StandardSpaceTypeCode; dest.RigidBodyTypeCode = source.RigidBodyTypeCode; dest.RadiologicalFile = source.RadiologicalFile; dest.IntentCode = source.IntentCode; dest.IntentParam1 = source.IntentParam1; dest.IntentParam2 = source.IntentParam2; dest.IntentParam3 = source.IntentParam3; dest.SliceOrderingCode = source.SliceOrderingCode; dest.ROIbox = source.ROIbox; dest.enforcelimits(dest.ROIbox); dest.activeROI = source.activeROI; if (dest.activeROI) { dest.Limits = source.Limits; dest.enforcelimits(dest.Limits); } else { dest.setdefaultlimits(); } dest.calc_no_voxels(); dest.interpkernel = source.interpkernel; dest.p_interpmethod = source.p_interpmethod; dest.p_extrapmethod = source.p_extrapmethod; dest.padvalue = (D) source.padvalue; dest.splineorder = source.splineorder; dest.ep_valid = source.ep_valid; dest.displayMaximum=source.displayMaximum; dest.displayMinimum=source.displayMinimum; dest.setAuxFile(source.getAuxFile()); } template void copyconvert(const volume& source, volume& dest) { // set up basic size and data storage dest.reinitialize(source.xsize(),source.ysize(),source.zsize()); // set up properties (except lazy ones) copybasicproperties(source,dest); // now copy across the data convertbuffer(source.Data,dest.Data,source.SizeBound); // doubly ensure that lazy properties are not valid dest.set_whole_cache_validity(false); } template void copybasicproperties(const volume4D& source, volume4D& dest) { // set up properties (except lazy ones) dest.p_TR = source.p_TR; dest.dim5 = source.dim5; dest.ROIbox = source.ROIbox; dest.enforcelimits(dest.ROIbox); dest.activeROI = source.activeROI; if ((dest.activeROI) && (sameabssize(source,dest))) { dest.Limits = source.Limits; dest.enforcelimits(dest.Limits); } else { dest.setdefaultlimits(); } dest.p_interpmethod = source.p_interpmethod; dest.p_extrapmethod = source.p_extrapmethod; // Cannot convert the following between different types //dest.p_userextrap = source.p_userextrap; //dest.p_userinterp = source.p_userinterp; dest.p_padval = (D) source.p_padval; int toffset = dest.mint() - source.mint(); for (int t=source.mint(); t<=source.maxt(); t++) { copybasicproperties(source[t],dest[Min(t + toffset,dest.maxt())]); } } template void copybasicproperties(const volume4D& source, volume& dest) { copybasicproperties(source[0],dest); } template void copybasicproperties(const volume& source, volume4D& dest) { // set up properties (except lazy ones) dest.setdefaultproperties(); dest.setROIlimits(source.ROIlimits(0),source.ROIlimits(1), source.ROIlimits(2),dest.ROIlimits(3), source.ROIlimits(4),source.ROIlimits(5), source.ROIlimits(6),dest.ROIlimits(7)); if (source.usingROI()) dest.activateROI(); else dest.deactivateROI(); if ((dest.usingROI()) && (dest.tsize()>=1) && (sameabssize(source,dest[0]))) { dest.setROIlimits(source.limits()); } else { dest.setdefaultlimits(); } dest.setinterpolationmethod(source.getinterpolationmethod()); dest.setextrapolationmethod(source.getextrapolationmethod()); // Cannot convert the following between different types //dest.p_userextrap = source.p_userextrap; //dest.p_userinterp = source.p_userinterp; dest.setpadvalue((D) source.getpadvalue()); for (int t=dest.mint(); t<=dest.maxt(); t++) { copybasicproperties(source,dest[t]); } } template void copyconvert(const volume4D& source, volume4D& dest) { // set up basic size and data storage dest.reinitialize(source.xsize(),source.ysize(),source.zsize(), source.tsize()); copybasicproperties(source,dest); for (int t=0; t volume operator+(S num, const volume& vol) { return (vol + num); } template volume operator-(S num, const volume& vol) { volume tmp = vol; tmp=num; tmp-=vol; return tmp; } template volume operator*(S num, const volume& vol) { return (vol * num); } template volume operator/(S num, const volume& vol) { volume tmp = vol; tmp=num; tmp/=vol; return tmp; } template volume operator-(const volume& vol) { return(vol * (static_cast(-1))); } template bool operator==(const volume& v1, const volume& v2) { // Check relevant parts of header if (!samesize(v1,v2,true)) return(false); if (v1.sform_code() != v2.sform_code()) return(false); if (v1.sform_mat() != v2.sform_mat()) return(false); if (v1.qform_code() != v2.qform_code()) return(false); if (v1.qform_mat() != v2.qform_mat()) return(false); // Check data for (typename volume::fast_const_iterator it1=v1.fbegin(), it_end=v1.fend(), it2=v2.fbegin(); it1 != it_end; ++it1, ++it2) { if ((*it1) != (*it2)) return(false); } return(true); } template bool operator!=(const volume& v1, const volume& v2) {return(!(v1==v2));} template volume4D operator+(S num, const volume4D& vol) { return (vol + num); } template volume4D operator-(S num, const volume4D& vol) { volume4D tmp = vol; tmp=num; tmp-=vol; return tmp; } template volume4D operator*(S num, const volume4D& vol) { return (vol * num); } template volume4D operator/(S num, const volume4D& vol) { volume4D tmp = vol; tmp=num; tmp/=vol; return tmp; } template volume4D operator-(const volume4D& vol) { return(vol * (static_cast(-1))); } template volume4D operator+(const volume& v1, const volume4D& v2) { return (v2 + v1); } template volume4D operator-(const volume& v1, const volume4D& v2) { return (v2*(-1.0) + v1); } template volume4D operator*(const volume& v1, const volume4D& v2) { return (v2 * v1); } } // end namespace #endif