// Utility for resampling of DTI data using fields/data // estimated by topup. // // applytopup.cpp // // Jesper Andersson, FMRIB Image Analysis Group // // Copyright (C) 2012 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. */ #include #include "utils/options.h" #include "newmat.h" #ifndef EXPOSE_TREACHEROUS #define EXPOSE_TREACHEROUS // To allow us to use .set_sform etc #endif #include "miscmaths/miscmaths.h" #include "newimage/newimageall.h" #include "warpfns/warpfns.h" #include "basisfield/basisfield.h" #include "basisfield/splinefield.h" #include "warpfns/fnirt_file_reader.h" #include "topup_file_io.h" #include "displacement_vector.h" #include "applytopup.h" using namespace Utilities; using namespace TOPUP; //////////////////////////////////////////////////////////////////////////// // COMMAND LINE OPTIONS string title="applytopup (Version 1.0)\nCopyright(c) 2009, University of Oxford (Jesper Andersson)"; string examples=string("applytopup -in=topdn,botup --topup=mytu --inindex=1,2 --out=hifi\n") + string("applytopup -in=topdn --topup=mytu --inindex=1 --method=jac --interp=spline --out=hifi\n"); Utilities::Option verbose(string("-v,--verbose"), false, string("switch on diagnostic messages"), false, Utilities::no_argument); Utilities::Option help(string("-h,--help"), false, string("display this message"), false, Utilities::no_argument); Utilities::Option interpstr(string("-n,--interp"), string("spline"), string("interpolation method {trilinear,spline}, default=spline"), false, Utilities::requires_argument); Utilities::Option infname(string("-i,--imain"), string(""), string("comma separated list of names of input image (to be corrected)"), true, Utilities::requires_argument); Utilities::Option datain(string("-a,--datain"), string(""), string("name of text file with PE directions/times"), true, Utilities::requires_argument); Utilities::Option inindex(string("-x,--inindex"), string(""), string("comma separated list of indicies into --datain of the input image (to be corrected)"), true, Utilities::requires_argument); Utilities::Option outfname(string("-o,--out"), string(""), string("basename for output (warped) image"), true, Utilities::requires_argument); Utilities::Option datatype(string("-d,--datatype"), string(""), string("Force output data type [char short int float double]."), false, Utilities::requires_argument); Utilities::Option method(string("-m,--method"), string("lsr"), string("Use jacobian modulation (jac) or least-squares resampling (lsr), default=lsr."), false, Utilities::requires_argument); Utilities::Option topupfname(string("-t,--topup"), string(""), string("name of field/movements (from topup)"), true, Utilities::requires_argument); int main(int argc, char *argv[]) { Tracer tr("main"); OptionParser options(title, examples); try { options.add(infname); options.add(datain); options.add(inindex); options.add(topupfname); options.add(outfname); options.add(method); options.add(interpstr); options.add(datatype); options.add(verbose); options.add(help); int i=options.parse_command_line(argc, argv); if (i < argc) { for (; i infnames = parse_commaseparated_list(infname.value()); std::vector inindices = parse_commaseparated_numbers(inindex.value()); if (infnames.size() != inindices.size()) throw ApplyTopupException("Mismatched --in and --inindex lists"); std::vector > scans(infnames.size()); for (unsigned int i=0; idatafile.N()) throw ApplyTopupException("Invalid entry in --inindex list"); // Read and parse field and movements estimated by topup TopupFileReader topupfile(topupfname.value()); NEWIMAGE::volume4D ovol; NEWIMAGE::volume mask(scans[0][0].xsize(),scans[0][0].ysize(),scans[0][0].zsize()); copybasicproperties(scans[0][0],mask); mask = 1; if (method.value() == "jac") { // Use simple resampling and jacobian modulation ovol = jac_resample(datafile,topupfile,inindices,mask,scans,interp); } else if (method.value() == "lsr") { // Use least squares restoration // First resample everything using the movement parameters resample_using_movement_parameters(datafile,topupfile,inindices,mask,scans,interp); // Then do LSR resampling ovol = lsr_resample(datafile,topupfile,inindices,mask,scans); } else if (method.value() == "vb2D") { // Use VB based least squares restoration // First resample everything using the movement parameters resample_using_movement_parameters(datafile,topupfile,inindices,mask,scans,interp); // Then do LSR resamling using VB to infer on the regularisation ovol = vb_resample_2D(datafile,topupfile,inindices,mask,scans); } else if (method.value() == "vb3D") { // Use VB based least squares restoration // First resample everything using the movement parameters resample_using_movement_parameters(datafile,topupfile,inindices,mask,scans,interp); // Then do LSR resamling using VB to infer on the regularisation ovol = vb_resample_3D(datafile,topupfile,inindices,mask,scans); } else if (method.value() == "vb4D") { // Use VB based least squares restoration // First resample everything using the movement parameters resample_using_movement_parameters(datafile,topupfile,inindices,mask,scans,interp); // Then do LSR resamling using VB to infer on the regularisation ovol = vb_resample_4D(datafile,topupfile,inindices,mask,scans); } else { // Dodgy!! } // Mask out other dodgy bits for (int t=0; t vb_resample_4D(const TopupDatafileReader& datafile, const TopupFileReader& topupfile, const std::vector& inindices, NEWIMAGE::volume& mask, std::vector >& scans) { NEWIMAGE::volume field = topupfile.FieldAsVolume(); TopupCollections collections(inindices,datafile); NEWIMAGE::volume4D ovol = scans[0]; ovol = 0.0; cout << "NCollections = " << collections.NCollections() << endl; cout << "NScans = " << collections.NScans(0) << endl; for (unsigned int c=0; c > > K(scans[0].zsize()); // ALL K-matrices std::vector > > KtK(scans[0].zsize()); // ALL KtK-matrices std::vector > > y(scans[0].tsize()); // All data for all diffusion gradients std::vector > > yty(scans[0].tsize()); // All yty for all diffusion gradients std::vector sf(2,0.0); if (row) { sf[0] = scans[0].xdim()/scans[0].ydim(); sf[1] = scans[0].xdim()/scans[0].zdim(); } else { sf[0] = scans[0].ydim()/scans[0].xdim(); sf[1] = scans[0].ydim()/scans[0].zdim(); } std::vector > > Lijk = GetLijk(pesz,sf); // Regularisation sub-matrices MISCMATHS::SpMat Lii = GetLii(pesz); // For initialization of mu // Pre-compute K- and KtK-matrices for (int sl=0; sl > > Lambda(scans[0].zsize()); std::vector > > mu(scans[0].tsize()); for (int d=0; d vb_resample_3D(const TopupDatafileReader& datafile, const TopupFileReader& topupfile, const std::vector& inindices, NEWIMAGE::volume& mask, std::vector >& scans) { NEWIMAGE::volume field = topupfile.FieldAsVolume(); TopupCollections collections(inindices,datafile); NEWIMAGE::volume4D ovol = scans[0]; ovol = 0.0; cout << "NCollections = " << collections.NCollections() << endl; cout << "NScans = " << collections.NScans(0) << endl; for (unsigned int c=0; c > > K(scans[0].zsize()); // ALL K-matrices std::vector > > KtK(scans[0].zsize()); // ALL KtK-matrices std::vector > y(scans[0].zsize()); // All data for one diffusion gradient std::vector > yty(scans[0].zsize()); // ALl yty for one diffusion gradient std::vector sf(2,0.0); if (row) { sf[0] = scans[0].xdim()/scans[0].ydim(); sf[1] = scans[0].xdim()/scans[0].zdim(); } else { sf[0] = scans[0].ydim()/scans[0].xdim(); sf[1] = scans[0].ydim()/scans[0].zdim(); } std::vector > > Lijk = GetLijk(pesz,sf); // Regularisation sub-matrices MISCMATHS::SpMat Lii = GetLii(pesz); // For initialization of mu // Pre-compute K- and KtK-matrices for (int sl=0; sl > > Lambda(scans[0].zsize()); std::vector > mu(scans[0].zsize()); for (int sl=0; sl sf(2,scans[0][0].ydim()/scans[0][0].xdim()); sf[1] = scans[0][0].ydim()/scans[0][0].zdim(); std::vector > > Lijk = GetLijk(scans[0][0].ysize(),sf); SpMat Lii = GetLii(scans[0][0].ysize()); // For initialization of mu (images) // Initialize constants int m=scans[0][0].ysize(); int n=2*m; int N=scans[0][0].xsize()*scans[0][0].zsize(); // Set priors double l_0 = 1e-10; double tau_0 = 1e10; double k_0 = 1e-10; double theta_0 = 1e10; // Initialize all parameters to their priors double ll = l_0; double tau = tau_0; double kk = k_0; double theta = theta_0; std::vector > > Lambda(scans[0][0].zsize()); std::vector > mu(scans[0][0].zsize()); for (int k=0; k >& mu, const std::vector > >& Lambda, const std::vector > >& Lijk) { int nsl = mu.size(); // Number of slices int nrow = mu[0].size(); // Number of frequency encodes double tauc = 0.0; for (int k=0; k > >& mu, const std::vector > >& Lambda, const std::vector > >& Lijk, double tau_0) { int nd = mu.size(); // Number of directions int nsl = mu[0].size(); // Number of slices int nrow = mu[0][0].size(); // Number of frequency encodes double tau = 1.0 / tau_0; for (int k=0; k >& mu, const std::vector > >& Lambda, const std::vector > >& Lijk, double tau_0) { int nsl = mu.size(); int nrow = mu[0].size(); double tau = 1.0 / tau_0; for (int k=0; k >& mu, const MISCMATHS::SpMat& K, const NEWMAT::ColumnVector& y, const NEWMAT::CroutMatrix& Lambda, const std::vector > >& Lijk, double phi, double lambda, int sl, int row) { int nsl = mu.size(); int nrow = mu[0].size(); NEWMAT::ColumnVector newmu = phi*K.TransMult(y); for (int i=max(0,row-2); i<=min(nrow-1,row+2); i++) { if (i != row) newmu -= lambda*Lijk[0][abs(i-row)]*mu[sl][i]; } for (int i=max(0,sl-2); i<=min(nsl-1,sl+2); i++) { if (i != sl) newmu -= lambda*Lijk[abs(i-sl)][0]*mu[i][row]; } if (sl && row) newmu -= lambda*Lijk[1][1]*mu[sl-1][row-1]; if (sl && row<(nrow-1)) newmu -= lambda*Lijk[1][1]*mu[sl-1][row+1]; if (sl<(nsl-1) && row<(nrow-1)) newmu -= lambda*Lijk[1][1]*mu[sl+1][row+1]; if (sl<(nsl-1) && row) newmu -= lambda*Lijk[1][1]*mu[sl+1][row-1]; newmu = Lambda.i()*newmu; return(newmu); } NEWIMAGE::volume4D vb_resample_2D(const TopupDatafileReader& datafile, const TopupFileReader& topupfile, const std::vector& inindices, NEWIMAGE::volume& mask, std::vector >& scans) { NEWIMAGE::volume field = topupfile.FieldAsVolume(); TopupCollections collections(inindices,datafile); NEWIMAGE::volume4D ovol = scans[0]; ovol = 0.0; cout << "NCollections = " << collections.NCollections() << endl; cout << "NScans = " << collections.NScans(0) << endl; for (unsigned int c=0; c > K(fesz); // All K-matrices for one slice std::vector > KtK(fesz); // All KtK-matrices for one slice std::vector y(fesz); // All data for one slice and direction std::vector yty(fesz,0.0); // Well.. double sf = scans[0][0].ydim()/scans[0][0].xdim(); if (row) sf = 1.0/sf; std::vector > Lij = GetLij(pesz,sf);// Regularisation sub-matrices MISCMATHS::SpMat Lii = GetLii(pesz); // For initialization of mu int m=pesz; // Number of elements along PE int N=fesz; // Number if frequency encodes in one slice int n=collections.NScans(c)*m; // Number of data-points for one "column" for (int sl=0; sl > > GetLijk(int sz, const std::vector sf) { SpMat tmpL(sz,sz); std::vector > > Lijk(3); Lijk[0].resize(3,tmpL); Lijk[1].resize(2,tmpL); Lijk[2].resize(1,tmpL); { // Lii double A11 = Sqr(2+2*sf[0]+2*sf[1]) + 2*Sqr(-1.0) + 2*Sqr(-sf[0]) + 2*Sqr(-sf[1]); double A12 = 2*(-1*(2+2*sf[0]*sf[1])); double A13 = 1.0; Lijk[0][0].Set(1,sz-1,A13); Lijk[0][0].Set(1,sz,A12); Lijk[0][0].Set(1,1,A11); Lijk[0][0].Set(1,2,A12); Lijk[0][0].Set(1,3,A13); Lijk[0][0].Set(2,sz,A13); Lijk[0][0].Set(2,1,A12); Lijk[0][0].Set(2,2,A11); Lijk[0][0].Set(2,3,A12); Lijk[0][0].Set(2,4,A13); for (int i=3; i<=sz-2; i++) { Lijk[0][0].Set(i,i-2,A13); Lijk[0][0].Set(i,i-1,A12); Lijk[0][0].Set(i,i,A11); Lijk[0][0].Set(i,i+1,A12); Lijk[0][0].Set(i,i+2,A13); } Lijk[0][0].Set(sz-1,sz-3,A13); Lijk[0][0].Set(sz-1,sz-2,A12); Lijk[0][0].Set(sz-1,sz-1,A11); Lijk[0][0].Set(sz-1,sz,A12); Lijk[0][0].Set(sz-1,1,A13); Lijk[0][0].Set(sz,sz-2,A13); Lijk[0][0].Set(sz,sz-1,A12); Lijk[0][0].Set(sz,sz,A11); Lijk[0][0].Set(sz,1,A12); Lijk[0][0].Set(sz,2,A13); } { // Lij: One off in the first direction double A11 = 2*((-sf[0])*(2+2*sf[0]+2*sf[1])); double A12 = 2*(-1)*(-sf[0]); Lijk[0][1].Set(1,sz,A12); Lijk[0][1].Set(1,1,A11); Lijk[0][1].Set(1,2,A12); for (int i=2; i<=sz-1; i++) { Lijk[0][1].Set(i,i-1,A12); Lijk[0][1].Set(i,i,A11); Lijk[0][1].Set(i,i+1,A12); } Lijk[0][1].Set(sz,sz-1,A12); Lijk[0][1].Set(sz,sz,A11); Lijk[0][1].Set(sz,1,A12); } { // Lij: Two off in the first direction double A11 = Sqr(-sf[0]); for (int i=1; i<=sz; i++) { Lijk[0][2].Set(i,i,A11); } } { // Lij: One off in the second direction double A11 = 2*((-sf[1])*(2+2*sf[0]+2*sf[1])); double A12 = 1*(-1)*(-sf[1]); Lijk[1][0].Set(1,sz,A12); Lijk[1][0].Set(1,1,A11); Lijk[1][0].Set(1,2,A12); for (int i=2; i<=sz-1; i++) { Lijk[1][0].Set(i,i-1,A12); Lijk[1][0].Set(i,i,A11); Lijk[1][0].Set(i,i+1,A12); } Lijk[1][0].Set(sz,sz-1,A12); Lijk[1][0].Set(sz,sz,A11); Lijk[1][0].Set(sz,1,A12); } { // Lij: One off in BOTH directions double A11 = 2*(-sf[0])*(-sf[1]); for (int i=1; i<=sz; i++) { Lijk[1][1].Set(i,i,A11); } } { // Lij: Two off in the second direction double A11 = Sqr(-sf[1]); for (int i=1; i<=sz; i++) { Lijk[2][0].Set(i,i,A11); } } return(Lijk); } ///////////////////////////////////////////////////////////////////// // // Returns the diagonal and off-diagonal (those that contain non-zero // values) blocks of a matrix A'*A where A is a matrix implementing // a 2D 2nd derivative. If the full 2D slice is mxn, where the // first direction is of size sz (i.e. sz=m) and represents the // direction of phase-encoding then each "block" is an mxm matrix. // It returns three such blocks in a vector corresponding to the // diagonal block and to moving one and two steps in the 2n direction. // // The scale-factor in sf corresponds to a scaling to the voxel-size // in the 2nd direction so that the scale of the derivative is the // same in both directions (i.e. per-voxel-in-first-direction). // If your slice has voxel-sizes vxs then sf=vxs[0]/vxs[1]. // ///////////////////////////////////////////////////////////////////// std::vector > GetLij(int sz, double sf) { SpMat tmp(sz,sz); std::vector > Lij(3,tmp); { // Lii double A11 = Sqr(2+2*sf) + 2*Sqr(-1.0) + 2*Sqr(-sf); double A12 = 2 * (-1) * (2+2*sf); double A13 = 1; Lij[0].Set(1,sz-1,A13); Lij[0].Set(1,sz,A12); Lij[0].Set(1,1,A11); Lij[0].Set(1,2,A12); Lij[0].Set(1,3,A13); Lij[0].Set(2,sz,A13); Lij[0].Set(2,1,A12); Lij[0].Set(2,2,A11); Lij[0].Set(2,3,A12); Lij[0].Set(2,4,A13); for (int i=3; i<=sz-2; i++) { Lij[0].Set(i,i-2,A13); Lij[0].Set(i,i-1,A12); Lij[0].Set(i,i,A11); Lij[0].Set(i,i+1,A12); Lij[0].Set(i,i+2,A13); } Lij[0].Set(sz-1,sz-3,A13); Lij[0].Set(sz-1,sz-2,A12); Lij[0].Set(sz-1,sz-1,A11); Lij[0].Set(sz-1,sz,A12); Lij[0].Set(sz-1,1,A13); Lij[0].Set(sz,sz-2,A13); Lij[0].Set(sz,sz-1,A12); Lij[0].Set(sz,sz,A11); Lij[0].Set(sz,1,A12); Lij[0].Set(sz,2,A13); } { // Lij: One off double A11 = 2 * (-sf) * (2+2*sf); double A12 = 2 * (-1) * (-sf); Lij[1].Set(1,sz,A12); Lij[1].Set(1,1,A11); Lij[1].Set(1,2,A12); for (int i=2; i<=sz-1; i++) { Lij[1].Set(i,i-1,A12); Lij[1].Set(i,i,A11); Lij[1].Set(i,i+1,A12); } Lij[1].Set(sz,sz-1,A12); Lij[1].Set(sz,sz,A11); Lij[1].Set(sz,1,A12); } { // Lij: Two off double A11 = Sqr(-sf); for (int i=1; i<=sz; i++) { Lij[2].Set(i,i,A11); } } return(Lij); } MISCMATHS::SpMat GetLii(int sz) { SpMat Lii(sz,sz); double A11 = 6; double A12 = -4; double A13 = 1; Lii.Set(1,sz-1,A13); Lii.Set(1,sz,A12); Lii.Set(1,1,A11); Lii.Set(1,2,A12); Lii.Set(1,3,A13); Lii.Set(2,sz,A13); Lii.Set(2,1,A12); Lii.Set(2,2,A11); Lii.Set(2,3,A12); Lii.Set(2,4,A13); for (int i=3; i<=sz-2; i++) { Lii.Set(i,i-2,A13); Lii.Set(i,i-1,A12); Lii.Set(i,i,A11); Lii.Set(i,i+1,A12); Lii.Set(i,i+2,A13); } Lii.Set(sz-1,sz-3,A13); Lii.Set(sz-1,sz-2,A12); Lii.Set(sz-1,sz-1,A11); Lii.Set(sz-1,sz,A12); Lii.Set(sz-1,1,A13); Lii.Set(sz,sz-2,A13); Lii.Set(sz,sz-1,A12); Lii.Set(sz,sz,A11); Lii.Set(sz,1,A12); Lii.Set(sz,2,A13); return(Lii); } /* MISCMATHS::SpMat GetLii(int sz) { SpMat Lii(sz,sz); Lii.Set(1,sz-1,1); Lii.Set(1,sz,-8); Lii.Set(1,1,20); Lii.Set(1,2,-8); Lii.Set(1,3,1); Lii.Set(2,sz,1); Lii.Set(2,1,-8); Lii.Set(2,2,20); Lii.Set(2,3,-8); Lii.Set(2,4,1); for (int i=3; i<=sz-2; i++) { Lii.Set(i,i-2,1); Lii.Set(i,i-1,-8); Lii.Set(i,i,20); Lii.Set(i,i+1,-8); Lii.Set(i,i+2,1); } Lii.Set(sz-1,sz-3,1); Lii.Set(sz-1,sz-2,-8); Lii.Set(sz-1,sz-1,20); Lii.Set(sz-1,sz,-8); Lii.Set(sz-1,1,1); Lii.Set(sz,sz-2,1); Lii.Set(sz,sz-1,-8); Lii.Set(sz,sz,20); Lii.Set(sz,1,-8); Lii.Set(sz,2,1); return(Lii); } std::vector > GetLij(int sz) { SpMat tmp(sz,sz); std::vector > Lij(2,tmp); Lij[0].Set(1,sz,2); Lij[0].Set(1,1,-8); Lij[0].Set(1,2,2); for (int i=2; i<=sz-1; i++) { Lij[0].Set(i,i-1,2); Lij[0].Set(i,i,-8); Lij[0].Set(i,i+1,2); } Lij[0].Set(sz,sz-1,2); Lij[0].Set(sz,sz,-8); Lij[0].Set(sz,1,2); for (int i=1; i<=sz; i++) Lij[1].Set(i,i,1); return(Lij); } MISCMATHS::SpMat GetS_Matrix(const std::vector& isz, const std::vector& wrap) { unsigned int mn=1; for (unsigned int i=0; i S(mn,mn); // Do first direction int nline = mn/isz[0]; for (int line = 1; line<=nline; line++) { int offs = (line-1)*isz[0]; // First row if (wrap[0]) { S.Set(offs+1,offs+isz[0],-1); S.Set(offs+1,offs+1,2); S.Set(offs+1,offs+2,-1); } else { S.Set(offs+1,offs+1,-1); S.Set(offs+1,offs+2,1); } // Rows 2 to N-1 for (int i=2; i 1) { int nline = mn/isz[0]; // First line for (int i=1; i<=isz[0]; i++) { if (wrap[1]) { S.AddTo(i,i+(isz[1]-1)*isz[0],-1); S.AddTo(i,i,2); S.AddTo(i,i+isz[0],-1); } else { S.AddTo(i,i,-1); S.AddTo(i,i+isz[0],1); } } // Lines 2 to N-1 for (int line=2; line jac_resample(const TopupDatafileReader& datafile, const TopupFileReader& topupfile, const std::vector& inindices, NEWIMAGE::volume& mask, std::vector >& scans, NEWIMAGE::interpolation interp) { NEWIMAGE::volume tmp = scans[0][0]; NEWIMAGE::volume4D df(tmp.xsize(),tmp.ysize(),tmp.zsize(),3); copybasicproperties(tmp,df[0]); copybasicproperties(tmp,df[1]); copybasicproperties(tmp,df[2]); NEWIMAGE::volume4D ovol = scans[0]; ovol = 0.0; for (unsigned int i=0; i jac = tmp; NEWIMAGE::volume tmpmask = mask; jac = 0.0; NEWIMAGE::deffield2jacobian(xcomp,ycomp,zcomp,jac); NEWMAT::Matrix M = topupfile.MoveMatrix(inindices[i]); for (int j=0; j lsr_resample(const TopupDatafileReader& datafile, const TopupFileReader& topupfile, const std::vector& inindices, NEWIMAGE::volume& mask, std::vector >& scans) { NEWIMAGE::volume field = topupfile.FieldAsVolume(); // Get off-resonance field TopupCollections collections(inindices,datafile); // Divide data into "Collections" std::vector mis_map(collections.NCollections()); // Indicator of "missing" data NEWIMAGE::volume4D ovol = scans[0]; // N.B. that scans is a vector ovol = 0.0; for (unsigned int c=0; c& inindices, NEWIMAGE::volume& mask, std::vector >& scans, NEWIMAGE::interpolation interp) { NEWIMAGE::volume tmpmask = mask; NEWIMAGE::volume tmp = scans[0][0]; tmp = 0.0; for (unsigned int i=0; i parse_commaseparated_numbers(const std::string& list) { std::vector str_list = parse_commaseparated_list(list); std::vector number_list(str_list.size(),0); for (unsigned int i=0; i parse_commaseparated_list(const std::string& list) { std::vector ostr; size_t cur_pos = 0; size_t new_pos = 0; unsigned int n=0; while ((new_pos = list.find_first_of(',',cur_pos)) != string::npos) { ostr.resize(++n); ostr[n-1] = list.substr(cur_pos,new_pos-cur_pos); cur_pos = new_pos+1; } ostr.resize(++n); ostr[n-1] = list.substr(cur_pos,string::npos); return(ostr); } // Makes sure that data are suited for least-squares restoration and // divides it into groups depending on phase-encode vectors TopupCollections::TopupCollections(const std::vector& indx, const TopupDatafileReader& dfile) { // First crude division std::vector > tmp(2); for (unsigned int i=0; i=NCollections() || i>=NIndices(c)) throw ApplyTopupException("TopupCollections::IndexAt: Indices out of range"); return(indxs[c][i]); } unsigned int TopupCollections::ScanAt(unsigned int c, unsigned int i) { if (c>=NCollections() || i>=NIndices(c)) throw ApplyTopupException("TopupCollections::ScanAt: Indices out of range"); return(scans[c][i]); } bool row_col_is_alright(const NEWIMAGE::volume& mask, unsigned int k, unsigned int ij, bool row) { if (row) { for (int i=0; i& vol, unsigned int k, unsigned int ij, bool row) { NEWMAT::ColumnVector v; if (row) v.ReSize(vol.xsize()); else v.ReSize(vol.ysize()); if (row) { for (int i=0; i& vol, const std::vector& mu, unsigned int sl, bool row) { for (unsigned int i=0; i& vol, const NEWMAT::Matrix& B, unsigned int k, unsigned int ij, bool row) { if (vol.tsize() != B.Ncols()) throw ApplyTopupException("add_to_rows_cols: Mismatch between vol and B"); for (int d=0; d& vol, const NEWMAT::Matrix& map, bool row) { for (int d=0; d