From 3302348fd4ace1845aef60b3b07eb74bc7bd7d7f Mon Sep 17 00:00:00 2001 From: Saad Jbabdi <saad@fmrib.ox.ac.uk> Date: Tue, 5 May 2009 13:08:56 +0000 Subject: [PATCH] nonlinear warp in probtrackx -> reorient starting orientation from meshes --- streamlines.cc | 126 ++++++++++++++++++++++++++++++++++++------------- streamlines.h | 6 +++ 2 files changed, 100 insertions(+), 32 deletions(-) diff --git a/streamlines.cc b/streamlines.cc index 69dac58..b0a3e6d 100644 --- a/streamlines.cc +++ b/streamlines.cc @@ -37,7 +37,33 @@ namespace TRACT{ exit(0); } } + void sjgradient(const volume<float>& im,volume4D<float>& grad){ + grad.reinitialize(im.xsize(),im.ysize(),im.zsize(),3); + copybasicproperties(im,grad[0]); + + int fx,fy,fz,bx,by,bz; + float dx,dy,dz; + for (int z=0; z<grad.zsize(); z++){ + fz = z ==(grad.zsize()-1) ? 0 : 1; + bz = z == 0 ? 0 : -1; + dz = (fz==0 || bz==0) ? 1.0 : 2.0; + for (int y=0; y<grad.ysize(); y++){ + fy = y ==(grad.ysize()-1) ? 0 : 1; + by = y == 0 ? 0 : -1; + dy = (fy==0 || by==0) ? 1.0 : 2.0; + for (int x=0; x<grad.xsize(); x++){ + fx = x ==(grad.xsize()-1) ? 0 : 1; + bx = x == 0 ? 0 : -1; + dx = (fx==0 || bx==0) ? 1.0 : 2.0; + grad[0](x,y,z) = (im(x+fx,y,z) - im(x+bx,y,z))/dx; + grad[1](x,y,z) = (im(x,y+fy,z) - im(x,y+by,z))/dy; + grad[2](x,y,z) = (im(x,y,z+fz) - im(x,y,z+bz))/dz; + } + } + } + +} Streamliner::Streamliner(const volume<float>& seeds):opts(probtrackxOptions::getInstance()),logger(LogSingleton::getInstance()), vols(opts.usef.value()),m_seeds(seeds){ @@ -79,16 +105,31 @@ namespace TRACT{ m_own_waymasks.push_back(true); } } - + + // Allow for either matrix transform (12dof affine) or nonlinear (warpfield) m_Seeds_to_DTI = IdentityMatrix(4); m_DTI_to_Seeds = IdentityMatrix(4); + m_rotdir = IdentityMatrix(3); + m_IsNonlinXfm = false; if(opts.seeds_to_dti.value()!=""){ if(!fsl_imageexists(opts.seeds_to_dti.value())){ m_Seeds_to_DTI = read_ascii_matrix(opts.seeds_to_dti.value()); m_DTI_to_Seeds = m_Seeds_to_DTI.i(); + + // set rotation matrix + Matrix F(3,3),u(3,3),v(3,3); + DiagonalMatrix d(3); + F << -m_Seeds_to_DTI(1,1) << m_Seeds_to_DTI(1,3) << -m_Seeds_to_DTI(1,2) + << -m_Seeds_to_DTI(2,1) << m_Seeds_to_DTI(2,3) << -m_Seeds_to_DTI(2,2) + << -m_Seeds_to_DTI(3,1) << m_Seeds_to_DTI(3,3) << -m_Seeds_to_DTI(3,2); + + SVD(F*F.t(),d,u,v); + m_rotdir.ReSize(3,3); + m_rotdir = (u*sqrt(d)*v.t()).i()*F; + } else{ m_IsNonlinXfm = true; @@ -100,6 +141,12 @@ namespace TRACT{ } FnirtFileReader iffr(opts.dti_to_seeds.value()); m_DTI_to_Seeds_warp = iffr.FieldAsNewimageVolume4D(true); + + // now calculate the jacobian of this transformation (useful for rotating vectors) + sjgradient(m_Seeds_to_DTI_warp[0],m_jacx); + sjgradient(m_Seeds_to_DTI_warp[1],m_jacy); + sjgradient(m_Seeds_to_DTI_warp[2],m_jacz); + } } @@ -110,16 +157,7 @@ namespace TRACT{ m_y_s_init=0; m_z_s_init=0; - // create rotdir for cases where seeding from a freesurfer mesh - Matrix F(3,3),u(3,3),v(3,3); - DiagonalMatrix d(3); - F << -m_Seeds_to_DTI(1,1) << m_Seeds_to_DTI(1,3) << -m_Seeds_to_DTI(1,2) - << -m_Seeds_to_DTI(2,1) << m_Seeds_to_DTI(2,3) << -m_Seeds_to_DTI(2,2) - << -m_Seeds_to_DTI(3,1) << m_Seeds_to_DTI(3,3) << -m_Seeds_to_DTI(3,2); - SVD(F*F.t(),d,u,v); - m_rotdir.ReSize(3,3); - m_rotdir = (u*sqrt(d)*v.t()).i()*F; } @@ -146,26 +184,21 @@ namespace TRACT{ } xst=xyz_dti(1);yst=xyz_dti(2);zst=xyz_dti(3); - m_path.clear(); + //m_path.clear(); x=xst;y=yst;z=zst; m_part.change_xyz(x,y,z); - - if(opts.meshfile.value()!=""){ - // rotate dir using seeds_to_dti*mm_to_vox - ColumnVector rotdir(3); - rotdir = m_rotdir*dir; - m_part.set_dir(rotdir(1),rotdir(2),rotdir(3));//Set the start dir so that we track inwards from cortex - } + m_part.set_dir(dir(1),dir(2),dir(3));//Set the start dir so that we track inwards from cortex int partlength=0; bool rubbish_passed=false; bool stop_flag=false; //bool has_goneout=false; //NB - this only goes in one direction!! - for(unsigned int pf=0;pf<m_passed_flags.size();pf++) { - m_passed_flags[pf]=false; /// only keep it if this streamline went through all the masks - } - + if(opts.waypoints.value()!="") + for(unsigned int pf=0;pf<m_passed_flags.size();pf++) { + m_passed_flags[pf]=false; /// only keep it if this streamline went through all the masks + } + for( int it = 1 ; it <= opts.nsteps.value()/2; it++){ if( (m_mask( round(m_part.x()), round(m_part.y()), round(m_part.z())) > 0) ){ /////////////////////////////////// @@ -210,17 +243,18 @@ namespace TRACT{ pref_z = m_prefdir((int)xyz_seeds(1),(int)xyz_seeds(2),(int)xyz_seeds(3),2); } //update every passed_flag - for( unsigned int wm=0;wm<m_waymasks.size();wm++ ){ - if( (*m_waymasks[wm])(x_s,y_s,z_s)!=0 ) { - m_passed_flags[wm]=true; + if(opts.waypoints.value()!="") + for( unsigned int wm=0;wm<m_waymasks.size();wm++ ){ + if( (*m_waymasks[wm])(x_s,y_s,z_s)!=0 ) { + m_passed_flags[wm]=true; + } } - } + + m_path.push_back(xyz_seeds); - // m_path(it,1)=x_s; - // m_path(it,2)=y_s; - // m_path(it,3)=z_s; partlength++; + if(opts.rubbishfile.value()!=""){ if(m_rubbish(x_s,y_s,z_s)!=0){ @@ -290,6 +324,27 @@ namespace TRACT{ return accept_path; } + + void Streamliner::rotdir(const ColumnVector& dir,ColumnVector& rotdir, + const float& x,const float& y,const float& z){ + if(!m_IsNonlinXfm){ + rotdir = m_rotdir*dir; + } + else{ + ColumnVector xyz_dti(3),xyz_seeds(3); + xyz_seeds << x << y << z; + xyz_dti = NewimageCoord2NewimageCoord(m_DTI_to_Seeds_warp,false,m_seeds,m_mask,xyz_seeds); + + Matrix F(3,3),Jw(3,3); + Jw << m_jacx(xyz_dti(1),xyz_dti(2),xyz_dti(3),0) << m_jacx(xyz_dti(1),xyz_dti(2),xyz_dti(3),1) << m_jacx(xyz_dti(1),xyz_dti(2),xyz_dti(3),2) + << m_jacy(xyz_dti(1),xyz_dti(2),xyz_dti(3),0) << m_jacy(xyz_dti(1),xyz_dti(2),xyz_dti(3),1) << m_jacy(xyz_dti(1),xyz_dti(2),xyz_dti(3),2) + << m_jacz(xyz_dti(1),xyz_dti(2),xyz_dti(3),0) << m_jacz(xyz_dti(1),xyz_dti(2),xyz_dti(3),1) << m_jacz(xyz_dti(1),xyz_dti(2),xyz_dti(3),2); + + F = (IdentityMatrix(3) + Jw).i(); + rotdir = F*dir; + } + } + void Counter::initialise(){ @@ -828,7 +883,7 @@ namespace TRACT{ } } - + int Seedmanager::run(const float& x,const float& y,const float& z,bool onewayonly, int fibst){ ColumnVector dir(3); dir=0; @@ -856,6 +911,10 @@ namespace TRACT{ } } + // now re-orient dir using xfm transform + ColumnVector rotdir(3); + m_stline.rotdir(dir,rotdir,x,y,z); + int nlines=0; for(int p=0;p<opts.nparticles.value();p++){ if(opts.verbose.value()>1) @@ -865,7 +924,7 @@ namespace TRACT{ bool forwardflag=false,backwardflag=false; bool counted=false; if(!onewayonly){ - if(m_stline.streamline(x,y,z,m_seeddims,fibst,dir)){ //returns whether to count the streamline or not + if(m_stline.streamline(x,y,z,m_seeddims,fibst,rotdir)){ //returns whether to count the streamline or not forwardflag=true; m_counter.store_path(); m_counter.count_streamline(); @@ -873,9 +932,12 @@ namespace TRACT{ } m_stline.reverse(); } - if(m_stline.streamline(x,y,z,m_seeddims,fibst,dir)){ + + if(m_stline.streamline(x,y,z,m_seeddims,fibst,rotdir)){ + backwardflag=true; m_counter.count_streamline(); + if(!counted)nlines++; // the other half has is counted here } diff --git a/streamlines.h b/streamlines.h index a17e167..08c5fa8 100644 --- a/streamlines.h +++ b/streamlines.h @@ -44,6 +44,9 @@ namespace TRACT{ Matrix m_DTI_to_Seeds; volume4D<float> m_Seeds_to_DTI_warp; volume4D<float> m_DTI_to_Seeds_warp; + volume4D<float> m_jacx; + volume4D<float> m_jacy; + volume4D<float> m_jacz; bool m_IsNonlinXfm; Matrix m_rotdir; Tractvolsx vols; @@ -100,6 +103,9 @@ namespace TRACT{ } bool streamline(const float& x_init,const float& y_init, const float& z_init,const ColumnVector& dim_seeds,const int& fibst,const ColumnVector& dir); + void rotdir(const ColumnVector& dir,ColumnVector& rotdir,const float& x,const float& y,const float& z); + + }; -- GitLab