/* newimagefns.cc 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. */ // General image processing functions #include "newimagefns.h" using namespace MISCMATHS; namespace NEWIMAGE { /////////////////////////////////////////////////////////////////////////// // BASIC IMAGE SUPPORT FUNCTIONS template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz) { // Note: the voxel at (offsetx,offsety,offsetz) in PADDEDVOL // will be the same as (0,0,0) in VOL std::vector roilim = paddedvol.ROIlimits(); paddedvol.copyproperties(vol); paddedvol.setROIlimits(roilim); // keep the old ROI (can be deactive) extrapolation oldex = vol.getextrapolationmethod(); if ((oldex==boundsassert) || (oldex==boundsexception)) { vol.setextrapolationmethod(constpad); } for (int z=paddedvol.minz(); z<=paddedvol.maxz(); z++) { for (int y=paddedvol.miny(); y<=paddedvol.maxy(); y++) { for (int x=paddedvol.minx(); x<=paddedvol.maxx(); x++) { paddedvol(x,y,z) = vol(x-offsetx,y-offsety,z-offsetz); } } } // set the sform and qform appropriately (currently equal to vol's) Matrix pad2vol(4,4); pad2vol = IdentityMatrix(4); pad2vol(1,4) = -offsetx; pad2vol(2,4) = -offsety; pad2vol(3,4) = -offsetz; if (paddedvol.sform_code()!=NIFTI_XFORM_UNKNOWN) { paddedvol.set_sform(paddedvol.sform_code(), paddedvol.sform_mat() * pad2vol); } if (paddedvol.qform_code()!=NIFTI_XFORM_UNKNOWN) { paddedvol.set_qform(paddedvol.qform_code(), paddedvol.qform_mat() * pad2vol); } vol.setextrapolationmethod(oldex); } template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz); template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz); template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz); template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz); template void pad(const volume& vol, volume& paddedvol, int offsetx, int offsety, int offsetz); template void raw_affine_transform(const volume& vin, volume& vout, const Matrix& aff) { // NB: the size of vout MUST BE SET BEFORE IT IS PASSED IN! // takes the volume (vin) and applies a spatial transform, given // by the 4x4 matrix (aff) in WORLD COORDINATES // the result is a new volume (vout) // Do everything in practice via the inverse transformation // That is, for every point in vout, calculate the pre-image in // vin to which it corresponds, and interpolate vin to get the // value there. // Also, the sampling transformations must be accounted for: // T_vox1->vox2 = (T_samp2)^-1 * T_world * T_samp1 // The sform/qform is unchanged if it is set in the output // The qform and sform are made equal if one is unset in the output // If both are unset in the output, then the sform is set to a // transformed input sform (or qform if sform is unset) and the // output qform is made equal to the output sform if (vout.nvoxels() <= 0) { imthrow("Attempted to use affine transform with no voxels in vout",8); } extrapolation oldex = vin.getextrapolationmethod(); if ((oldex==boundsassert) || (oldex==boundsexception)) { vin.setextrapolationmethod(constpad); } // iaffbig goes from output mm coords to input (reference) mm coords Matrix iaffbig = aff.i(); // check the left-right data orientations of the images and modify // the transformation matrix to flip to radiological coords if necessary if (vin.left_right_order()==FSL_NEUROLOGICAL) { iaffbig = vin.swapmat(-1,2,3) * iaffbig; } if (vout.left_right_order()==FSL_NEUROLOGICAL) { iaffbig = iaffbig * vout.swapmat(-1,2,3); } // convert iaffbig to go from output voxel coords to input (reference) voxel coords iaffbig = vin.sampling_mat().i() * iaffbig * vout.sampling_mat(); Matrix iaff=iaffbig.SubMatrix(1,3,1,3); float a11=iaff(1,1), a12=iaff(1,2), a13=iaff(1,3), a14=iaffbig(1,4), a21=iaff(2,1), a22=iaff(2,2), a23=iaff(2,3), a24=iaffbig(2,4), a31=iaff(3,1), a32=iaff(3,2), a33=iaff(3,3), a34=iaffbig(3,4), o1,o2,o3; // The matrix algebra below has been hand-optimized from // [o1 o2 o3] = a * [x y z] at each iteration for (int z=0; z& vin, volume& vout, const Matrix& aff); template void raw_affine_transform(const volume& vin, volume& vout, const Matrix& aff); template void raw_affine_transform(const volume& vin, volume& vout, const Matrix& aff); template void raw_affine_transform(const volume& vin, volume& vout, const Matrix& aff); template void raw_affine_transform(const volume& vin, volume& vout, const Matrix& aff); template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const T padval) { // padding is in voxels, not mm if (vout.nvoxels() <= 0) { imthrow("Attempted to use affine transform with no voxels in vout",8); } Matrix iaffbig = vin.sampling_mat().i() * aff.i() * vout.sampling_mat(); Matrix iaff=iaffbig.SubMatrix(1,3,1,3); float a11=iaff(1,1), a12=iaff(1,2), a13=iaff(1,3), a14=iaffbig(1,4), a21=iaff(2,1), a22=iaff(2,2), a23=iaff(2,3), a24=iaffbig(2,4), a31=iaff(3,1), a32=iaff(3,2), a33=iaff(3,3), a34=iaffbig(3,4), o1,o2,o3; int xb=vin.xsize()-1, yb=vin.ysize()-1, zb=vin.zsize()-1; float xb0=-padding, yb0=-padding, zb0=-padding; float xb1=xb+padding, yb1=yb+padding, zb1=zb+padding; // The matrix algebra below has been hand-optimized from // [o1 o2 o3] = a * [x y z] at each iteration for (int z=0; z=xb0) && (o2>=yb0) && (o3>=zb0) && (o1<=xb1) && (o2<=yb1) && (o3<=zb1) ) { // do nothing } else { vout(x,y,z) = padval; } o1 += a12; o2 += a22; o3 += a32; } } } } template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const char padval); template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const short int padval); template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const int padval); template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const float padval); template void affine_transform_mask(const volume& vin, volume& vout, const Matrix& aff, float padding, const double padval); template volume isotropic_resample(const volume& aniso, float scale) { // takes the anisotropic volume, with given sampling and resamples // to an isotropic scale given by scale if (scale<0.0) { cerr << "WARNING:: Negative scale in isotropic_resample - using abs value" << endl; scale = fabs(scale); } extrapolation oldex = aniso.getextrapolationmethod(); if ((oldex==boundsassert) || (oldex==boundsexception)) { aniso.setextrapolationmethod(constpad); } float stepx, stepy, stepz; stepx = scale / aniso.xdim(); stepy = scale / aniso.ydim(); stepz = scale / aniso.zdim(); int sx, sy, sz; sz = (int) Max(1.0, ( ((float) (aniso.maxz() - aniso.minz() + 1.0)) / stepz)); sy = (int) Max(1.0, ( ((float) (aniso.maxy() - aniso.miny() + 1.0)) / stepy)); sx = (int) Max(1.0, ( ((float) (aniso.maxx() - aniso.minx() + 1.0)) / stepx)); volume iso(sx,sy,sz); float fx, fy, fz; int x, y, z; for (fz=0.0, z=0; z isotropic_resample(const volume& aniso, float scale); template volume isotropic_resample(const volume& aniso, float scale); template volume isotropic_resample(const volume& aniso, float scale); template volume isotropic_resample(const volume& aniso, float scale); template volumeisotropic_resample(const volume& aniso, float scale); template int upsample_by_2(volume& highresvol, const volume& lowresvol, bool centred) { // upsamples a volume (lowresvol) to give a new volume (highresvol) // note that this uses the highresvol size if it is OK but will // throw away any data previous contained therein int sx, sy, sz; sz=lowresvol.zsize(); sy=lowresvol.ysize(); sx=lowresvol.xsize(); extrapolation oldex = lowresvol.getextrapolationmethod(); if ((oldex==boundsassert) || (oldex==boundsexception)) { lowresvol.setextrapolationmethod(constpad); } if (highresvol.nvoxels()<1) { highresvol.reinitialize(sx*2+1,sy*2+1,sz*2+1); } highresvol.copyproperties(lowresvol); highresvol = lowresvol.backgroundval(); highresvol.setdims(lowresvol.xdim() / 2.0, lowresvol.ydim() / 2.0, lowresvol.zdim() / 2.0); // set sform and qform appropriately (if set) // voxel 2 voxel mapping of subsampled vol -> original vol Matrix sub2mat(4,4); sub2mat = IdentityMatrix(4); sub2mat(1,1) = 2.0; sub2mat(2,2) = 2.0; sub2mat(3,3) = 2.0; if (!centred) { sub2mat(1,4) = 0.5; sub2mat(2,4) = 0.5; sub2mat(3,4) = 0.5; } if (lowresvol.sform_code()!=NIFTI_XFORM_UNKNOWN) { highresvol.set_sform(lowresvol.sform_code(),lowresvol.sform_mat() * sub2mat.i()); } if (lowresvol.qform_code()!=NIFTI_XFORM_UNKNOWN) { highresvol.set_qform(lowresvol.qform_code(),lowresvol.qform_mat() * sub2mat.i()); } highresvol.setROIlimits(lowresvol.minx()*2,lowresvol.miny()*2, lowresvol.minz()*2, lowresvol.maxx()*2,lowresvol.maxy()*2, lowresvol.maxz()*2); Matrix high2lowresvox(4,4); high2lowresvox = sub2mat.i(); for (int z=0; z& highresvol, const volume& lowresvol, bool centred); template int upsample_by_2(volume& highresvol, const volume& lowresvol, bool centred); template int upsample_by_2(volume& highresvol, const volume& lowresvol, bool centred); template int upsample_by_2(volume& highresvol, const volume& lowresvol, bool centred); template int upsample_by_2(volume& highresvol, const volume& lowresvol, bool centred); template volume subsample_by_2(const volume& refvol, bool centred) { // subsamples a volume (refvol) by blurring and subsampling to give // a new volume // note that this creates the new volume, throwing away any data // previous contained therein int sx, sy, sz; sz=refvol.zsize(); sy=refvol.ysize(); sx=refvol.xsize(); extrapolation oldex = refvol.getextrapolationmethod(); if ((oldex==boundsassert) || (oldex==boundsexception)) { refvol.setextrapolationmethod(constpad); } volume halfvol((sx+1)/2,(sy+1)/2,(sz+1)/2); halfvol.copyproperties(refvol); halfvol = refvol.backgroundval(); halfvol.setdims(refvol.xdim() * 2.0, refvol.ydim() * 2.0, refvol.zdim() * 2.0); // set sform and qform appropriately (if set) // voxel 2 voxel mapping of subsampled vol -> original vol Matrix sub2mat(4,4); sub2mat = IdentityMatrix(4); sub2mat(1,1) = 2.0; sub2mat(2,2) = 2.0; sub2mat(3,3) = 2.0; if (!centred) { sub2mat(1,4) = 0.5; sub2mat(2,4) = 0.5; sub2mat(3,4) = 0.5; } if (refvol.sform_code()!=NIFTI_XFORM_UNKNOWN) { halfvol.set_sform(refvol.sform_code(),refvol.sform_mat() * sub2mat); } if (refvol.qform_code()!=NIFTI_XFORM_UNKNOWN) { halfvol.set_qform(refvol.qform_code(),refvol.qform_mat() * sub2mat); } halfvol.setROIlimits(refvol.minx()/2,refvol.miny()/2,refvol.minz()/2, refvol.maxx()/2,refvol.maxy()/2,refvol.maxz()/2); for (int z=0, bz=0; z subsample_by_2(const volume& refvol, bool centred); template volume subsample_by_2(const volume& refvol, bool centred); template volume subsample_by_2(const volume& refvol, bool centred); template volume subsample_by_2(const volume& refvol, bool centred); template volumesubsample_by_2(const volume& refvol, bool centred); template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode) { MISCMATHS::get_axis_orientations(inp1.sform_mat(),inp1.sform_code(), inp1.qform_mat(),inp1.qform_code(), icode, jcode, kcode); } template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode); template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode); template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode); template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode); template void get_axis_orientations(const volume& inp1, int& icode, int& jcode, int& kcode); volume4D sqrt(const volume4D& vol4) { volume4D retvol; retvol=sqrt_float(vol4); return retvol; } volume4D sqrt(const volume4D& vol4) { volume4D retvol; retvol=sqrt_float(vol4); return retvol; } volume4D sqrt(const volume4D& vol4) { volume4D retvol; retvol=sqrt_float(vol4); return retvol; } volume4D sqrt(const volume4D& vol4) { volume4D retvol; retvol=sqrt_float(vol4); return retvol; } volume4D sqrt(const volume4D& vol4) { if (vol4.mint()<0) { volume4D newvol; return newvol; } volume4D retvol; copyconvert(vol4,retvol); for (int t=vol4.mint(); t<=vol4.maxt(); t++) { for (int z=vol4.minz(); z<=vol4.maxz(); z++) { for (int y=vol4.miny(); y<=vol4.maxy(); y++) { for (int x=vol4.minx(); x<=vol4.maxx(); x++) { if (vol4(x,y,z,t)>0) { retvol(x,y,z,t) = sqrt((double) vol4(x,y,z,t)); } else { retvol(x,y,z,t) = 0; } } } } } return retvol; } volume sqrt(const volume& vol) { volume retvol; retvol=sqrt_float(vol); return retvol; } volume sqrt(const volume& vol) { volume retvol; retvol=sqrt_float(vol); return retvol; } volume sqrt(const volume& vol) { volume retvol; retvol=sqrt_float(vol); return retvol; } volume sqrt(const volume& vol) { volume retvol; retvol=sqrt_float(vol); return retvol; } volume sqrt(const volume& vol) { volume retvol; copyconvert(vol,retvol); for (int z=vol.minz(); z<=vol.maxz(); z++) { for (int y=vol.miny(); y<=vol.maxy(); y++) { for (int x=vol.minx(); x<=vol.maxx(); x++) { if (vol(x,y,z)>0) { retvol(x,y,z) = sqrt((double) vol(x,y,z)); } else { retvol(x,y,z) = 0; } } } } return retvol; } float length(float x, float y) { return sqrt(x*x + y*y); } volume abs(const volume& realvol, const volume& imagvol) { volume absmap; absmap = realvol; for (int z=realvol.minz(); z<=realvol.maxz(); z++) { for (int y=realvol.miny(); y<=realvol.maxy(); y++) { for (int x=realvol.minx(); x<=realvol.maxx(); x++) { absmap(x,y,z) = length(imagvol(x,y,z),realvol(x,y,z)); } } } return absmap; } volume phase(const volume& realvol, const volume& imagvol) { volume phasemap; phasemap = realvol; for (int z=realvol.minz(); z<=realvol.maxz(); z++) { for (int y=realvol.miny(); y<=realvol.maxy(); y++) { for (int x=realvol.minx(); x<=realvol.maxx(); x++) { phasemap(x,y,z) = atan2(imagvol(x,y,z),realvol(x,y,z)); } } } return phasemap; } volume real(const volume& absvol, const volume& phasevol) { volume realmap; realmap = absvol; for (int z=absvol.minz(); z<=absvol.maxz(); z++) { for (int y=absvol.miny(); y<=absvol.maxy(); y++) { for (int x=absvol.minx(); x<=absvol.maxx(); x++) { realmap(x,y,z) = absvol(x,y,z) * cos(phasevol(x,y,z)); } } } return realmap; } volume imag(const volume& absvol, const volume& phasevol) { volume imagmap; imagmap = absvol; for (int z=absvol.minz(); z<=absvol.maxz(); z++) { for (int y=absvol.miny(); y<=absvol.maxy(); y++) { for (int x=absvol.minx(); x<=absvol.maxx(); x++) { imagmap(x,y,z) = absvol(x,y,z) * sin(phasevol(x,y,z)); } } } return imagmap; } /////////////////////////////////////////////////////////////////////////// // IMAGE PROCESSING ROUTINES void make_grad_masks(volume& maskx, volume& masky, volume& maskz) { maskx.reinitialize(3,3,3); masky.reinitialize(3,3,3); maskz.reinitialize(3,3,3); for (int z=0; z<3; z++) { for (int y=0; y<3; y++) { for (int x=0; x<3; x++) { maskx(x,y,z)=(x-1.0)*pow(3.0,1.0-fabs(y-1.0)-fabs(z-1.0)); masky(x,y,z)=(y-1.0)*pow(3.0,1.0-fabs(x-1.0)-fabs(z-1.0)); maskz(x,y,z)=(z-1.0)*pow(3.0,1.0-fabs(x-1.0)-fabs(y-1.0)); } } } return; } void make_blur_mask(ColumnVector& bmask, const float final_vox_dim, const float init_vox_dim) { // construct the default output bmask.ReSize(1); bmask = 1.0; if (fabs(init_vox_dim)<1e-8) { return; } float sampling_ratio = final_vox_dim / init_vox_dim; if (sampling_ratio < 1.1) { return; } float sigma = 0.85*(sampling_ratio/2.0); if (sigma<0.5) { return; } int n=((int) (sigma-0.001))*2 + 3; int midn = n/2 + 1; bmask.ReSize(n); for (int x=1; x<=n; x++) { bmask(x) = exp(-((float) Sqr(x-midn))/( Sqr(sigma) * 4.0)); } bmask = bmask / Sum(bmask); return; } ColumnVector gaussian_kernel1D(float sigma, int radius) { ColumnVector kern(2*radius+1); float sum=0.0, val=0.0; for(int j=-radius; j<=radius; j++) { if (sigma>1e-6) { val = exp(-(j*j)/(2.0*sigma*sigma)); } else { if (j==0) { val=1; } else { val=0; } } kern(j+radius+1) = val; sum += val; } kern *= (1.0/sum); return kern; } volume gaussian_kernel2D(float sigma, int radius) { volume new_kernel((2*radius+1),(2*radius+1),1); float sum=0.0, val=0.0; for(int i=-radius; i<=radius; i++) { for(int j=-radius; j<=radius; j++) { if (sigma>1e-6) { val = exp(-(i*i+j*j)/(2.0*sigma*sigma)); } else { if ((i*i + j*j)==0) { val=1; } else { val=0; } } new_kernel((j+radius),(i+radius),0) = val; sum += val; } } new_kernel *= (1.0/sum); return new_kernel; } volume gaussian_kernel3D(float sigma, int radius) { volume new_kernel((2*radius+1),(2*radius+1),(2*radius+1)); float sum=0.0, sum2=0.0, val=0.0; for(int i=-radius; i<=radius; i++) { for(int j=-radius; j<=radius; j++) { for(int k=-radius; k<=radius; k++) { if (sigma>1e-6) { val = exp(-(i*i+j*j+k*k)/(2.0*sigma*sigma)); } else { if ((i*i + j*j + k*k)==0) { val=1; } else { val=0; } } new_kernel((j+radius),(i+radius),(k+radius)) = val; sum += val; } } sum2 += sum; sum=0.0; } new_kernel *= (1.0/sum2); return new_kernel; } volume gaussian_kernel3D(float sigma, float xdim, float ydim, float zdim,float cutoff) { int sx = ((int) ceil(sigma*cutoff/xdim))*2 + 1; int sy = ((int) ceil(sigma*cutoff/ydim))*2 + 1; int sz = ((int) ceil(sigma*cutoff/zdim))*2 + 1; volume vker(sx,sy,sz); float dx2=Sqr(xdim); float dy2=Sqr(ydim); float dz2=Sqr(zdim); for (int z=-sz/2; z<=sz/2; z++) { for (int y=-sy/2; y<=sy/2; y++) { for (int x=-sx/2; x<=sx/2; x++) { vker(x+sx/2,y+sy/2,z+sz/2)=exp(-(x*x*dx2+y*y*dy2+z*z*dz2)/(2*sigma*sigma)); } } } return vker; } volume spherical_kernel(float radius, float xdim, float ydim, float zdim) { int sx = MISCMATHS::round(radius/xdim)*2 + 1; int sy = MISCMATHS::round(radius/ydim)*2 + 1; int sz = MISCMATHS::round(radius/zdim)*2 + 1; volume vker(sx,sy,sz); vker = 0.0; float dx2=Sqr(xdim); float dy2=Sqr(ydim); float dz2=Sqr(zdim); for (int z=-sz/2; z<=sz/2; z++) { for (int y=-sy/2; y<=sy/2; y++) { for (int x=-sx/2; x<=sx/2; x++) { if ((x*x*dx2+y*y*dy2+z*z*dz2)<=Sqr(radius)) { vker(x+sx/2,y+sy/2,z+sz/2)=1.0; } } } } return vker; } volume box_kernel(float length, float xdim,float ydim,float zdim) //mm dimensions { int x = ((int) floor(length/xdim/2))*2 + 1; int y = ((int) floor(length/ydim/2))*2 + 1; int z = ((int) floor(length/zdim/2))*2 + 1; volume new_kernel(x,y,z); new_kernel=1.0; return new_kernel; } volume box_kernel(int x,int y, int z) //voxel dimensions { volume new_kernel(x,y,z); new_kernel=1.0; return new_kernel; } float fsllog2(float x) { // a cygwin annoyance! return log(x)/log(2); } /////////////////////////////////////////////////////////////////////////// // support functions for connected components int find_first_nonzero(const Matrix& mat) { Tracer tr("first"); for (int idx=1; idx<=mat.Nrows(); idx++) { if (mat(idx,1)!=0.0) return idx; } return -1; // Failed } void addpair2set(int x, int y, std::vector& sx, std::vector& sy) { sx.push_back(x); sy.push_back(y); } inline void get_parent_label(int& idx, const Matrix& idxmap) { while (idxmap(idx,1)>0.0) { idx = MISCMATHS::round(float(idxmap(idx,1))); } } void relabel_components_uniquely(volume& labelvol, const std::vector& equivlista, const std::vector& equivlistb, ColumnVector& clustersizes) { int labelnum = labelvol.max(); Matrix emap(labelnum,1); emap = -0.2; int n1, n2; for (unsigned int n=0; n0) { int tmp = MISCMATHS::round(-float(emap(labelvol(x,y,z),1))); labelvol(x,y,z)=tmp; clustersizes(tmp)+=1; } } } } } void relabel_components_uniquely(volume& labelvol, const std::vector& equivlista, const std::vector& equivlistb){ ColumnVector clustersize; relabel_components_uniquely(labelvol, equivlista, equivlistb,clustersize); } bool rowentry_lessthan(const rowentry& r1, const rowentry& r2) { return r1.d < r2.d ; } /////////////////////////////////////////////////////////////////////////// template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol) { Matrix v2vmat, in2mm, ref2mm; in2mm = invol.sampling_mat(); ref2mm = refvol.sampling_mat(); if (invol.left_right_order() == FSL_NEUROLOGICAL) { in2mm = invol.swapmat(-1,2,3); } if (refvol.left_right_order() == FSL_NEUROLOGICAL) { ref2mm = refvol.swapmat(-1,2,3); } v2vmat = ref2mm.i() * flirt_in2ref * in2mm; return v2vmat; } template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol); template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol); template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol); template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol); template Matrix NewimageVox2NewimageVoxMatrix(const Matrix& flirt_in2ref, const volume& invol, const volume& refvol); /////////////////////////////////////////////////////////////////////////// }