/* 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 "streamlines.h" #include "warpfns/fnirt_file_reader.h" #include "warpfns/warpfns.h" //***************************************** //************* MatCell_cmpr ************** void MatCell_cmpr::decode(int64_t incode, int& nsamples, int& fibcnt1, int& fibcnt2, float& length_tot) const{ //undo the coding for incode //code = two32*fibre_count + mult*mult*fibre_prop1 + mult*fibre_prop2 + length_val; int64_t fibre_count, fibre_prop1, fibre_prop2, length_val, two32=(1LL<<32), mult=1001, multmult=mult*mult; fibre_count = incode / two32; incode = incode % two32; fibre_prop1 = incode / multmult; incode = incode % multmult; fibre_prop2 = incode / mult; incode = incode % mult; length_val = incode; fibcnt1=(int)round((float)(fibre_prop1*0.001*fibre_count)); fibcnt2=(int)round((float)(fibre_prop2*0.001*fibre_count)); length_tot=float(length_val*fibre_count); nsamples=(int)fibre_count; } void MatCell_cmpr::encode(const int nsamples, const int fibcnt1, const int fibcnt2, const float length_tot){ //store new coding in code2 int64_t fibre_count, fibre_prop1, fibre_prop2, length_val, two32=(1LL<<32), mult=1001; // fibre_prop1, fibre_prop2 and length_val ***MUST*** BE WITHIN 0 and 1000 INCLUSIVE fibre_count = (int64_t)MIN((int64_t)nsamples,two32-1); //Notice that every time we decode and encode there are rounding errors because of the following functions. //We considered using the absolute values instead of proportions or average distances, but then the dynamic range of the values we can code is reduced. fibre_prop1 = (int64_t)MIN((int64_t)(MISCMATHS::round(float(fibcnt1)/float(nsamples)*1000)),1000); fibre_prop2 = (int64_t)MIN((int64_t)(MISCMATHS::round(float(fibcnt2)/float(nsamples)*1000)),1000); fibre_prop2 = (int64_t)MIN(fibre_prop2, (int64_t)(1000-fibre_prop1)); //Avoid sum over 1000 due to rounding errors length_val = (int64_t)MIN((int64_t)(MISCMATHS::round((nsamples!=0?length_tot/float(nsamples):0.0))),1000); code2 = two32*fibre_count + mult*mult*fibre_prop1 + mult*fibre_prop2 + length_val; } void MatCell_cmpr::add_one(float dist,int fib){ int nsamples, fibcnt1, fibcnt2; float length_tot; //Undo the coding for current value decode(code2,nsamples, fibcnt1, fibcnt2, length_tot); //Update Values if (fib==1) fibcnt1+=1; if (fib==2) fibcnt2+=1; length_tot+=dist; nsamples+=1; //Code again encode(nsamples, fibcnt1, fibcnt2, length_tot); } void MatCell_cmpr::add_n(float dist,vector props,int n){ int nsamples, fibcnt1, fibcnt2; float length_tot; if(props.size()!=2){ cerr<<"MatCell_cmpr::add_n:Only valid with 3 fibres for now"<::SpMat(m,n){ string extension="mtx"; string file1=basename+"1."+extension; string file2=basename+"2."+extension; string file3=basename+"3."+extension; ifstream fs1,fs2,fs3; // FIRST FILE (text file of matrix dimensions) try{ fs1.open(file1.c_str()); } catch(...) { throw SpMatHCPException("SpMat_HCP::SpMat_HCP(unsigned int m, unsigned int n,const string& basename): cannot open file1 for reading"); } int nrows, ncols; fs1 >> nrows; fs1 >> ncols; fs1.close(); if(nrows!=(int)Nrows() || ncols!=(int)Ncols()){ cerr<<"SpMat_HCP::SpMat_HCP(unsigned int m, unsigned int n,const string& basename): Incompatible matrix dimensions"<& ri = get_ri(c); const std::vector& val = get_val(c); for (unsigned int r=0; r::SpMat(m,n){ string extension="mtx"; string file1=basename+"1."+extension; string file2=basename+"2."+extension; string file3=basename+"3."+extension; ifstream fs1,fs2,fs3; // FIRST FILE (text file of matrix dimensions) try{ fs1.open(file1.c_str()); } catch(...) { throw SpMatHCPException("SpMat_HCP::SpMat_HCP(unsigned int m, unsigned int n,const string& basename): cannot open file1 for reading"); } int nrows, ncols; fs1 >> nrows; fs1 >> ncols; fs1.close(); if(nrows!=(int)Nrows() || ncols!=(int)Ncols()){ cerr<<"SpMat_HCP::SpMat_HCP(unsigned int m, unsigned int n,const string& basename): Incompatible matrix dimensions"< props(2); props[0]=fprop1;props[1]=fprop2; AddToTraj(r+1,c+1,(float)length_val,props,fibre_count); } } fs3.close(); } // Trajectory file writer int SpMat_HCP::SaveTrajFile(const string& basename)const { if ( (basename.size()<1) ) return -1; string extension="mtx"; string file1=basename+"1."+extension; string file2=basename+"2."+extension; string file3=basename+"3."+extension; ofstream fs1, fs2, fs3; // FIRST FILE (text file of matrix dimensions) try{ fs1.open(file1.c_str(), ios::out | ios::binary); } catch(...) { throw SpMatHCPException("SpMat_HCP::SaveTrajFile(const string& basename): cannot open file1 for writing"); } fs1 << Nrows() << endl; fs1 << Ncols() << endl; fs1.close(); // SECOND FILE (binary file of lengths) try{ fs2.open(file2.c_str(), ios::out | ios::binary); } catch(...) { throw SpMatHCPException("SpMat_HCP::SaveTrajFile(const string& basename): cannot open file2 for writing"); } for(unsigned int c=0; c < Ncols(); c++) { int64_t sz = get_ri(c).size(); fs2.write((char*)&sz,sizeof(sz)); } fs2.close(); // THIRD FILE (binary file of contents, integer coded) try{ fs3.open(file3.c_str(), ios::out | ios::binary); } catch(...) { throw SpMatHCPException("SpMat_HCP::SaveTrajFile(const string& basename): cannot open file3 for writing"); } int64_t code1, code2; int64_t two32=(1LL<<32), mult=1001; for(unsigned int c=0; c < Ncols(); c++) { if(get_ri(c).size()){ const std::vector& ri = get_ri(c); const std::vector& val = get_val(c); for (unsigned int r=0; r& content){ ifstream fs(filename.c_str()); string tmp; if(fs){ fs>>tmp; do{ content.push_back(tmp); fs>>tmp; }while(!fs.eof()); } else{ cerr<<"TRACT::read_ascii_files: "< tmp(M.Nrows(),M.Ncols(),1); for(int i=1;i<=M.Nrows();i++) for(int j=1;j<=M.Ncols();j++) tmp(i-1,j-1,0)=M(i,j); save_volume(tmp,filename); } ColumnVector mean_sph_pol(ColumnVector& A, ColumnVector& B){ // A and B contain th, ph f. float th,ph; ColumnVector rA(3), rB(3); rA << (sin(A(1))*cos(A(2))) << (sin(A(1))*sin(A(2))) << (cos(A(1))); rB << (sin(B(1))*cos(B(2))) << (sin(B(1))*sin(B(2))) << (cos(B(1))); if(sum(SP(rA,rB)).AsScalar()>0) cart2sph((rA+rB)/2,th,ph); else cart2sph((rA-rB)/2,th,ph); A(1)=th; A(2)=ph; return A; } void imgradient(const volume& im,volume4D& 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& x,vector& y){ // sort vector< pair > p; for(unsigned int i=0;i pp; pp.first=x[i]; pp.second=i; p.push_back(pp); } sort(p.begin(),p.end()); vector ycp(y.begin(),y.end()); for(unsigned int i=0;i xx;vector yy; for(unsigned int i=0;i0){ if( x[i]==x[i-1] )continue; } xx.push_back(x[i]); yy.push_back(y[i]); } x=xx; y=yy; } void make_unique(vector& x){ sort(x.begin(),x.end()); vector xx; for(unsigned int i=0;i0){ if( x[i]==x[i-1] )continue; } xx.push_back(x[i]); } x=xx; } void make_unique(vector< pair >&x){ sort(x.begin(),x.end()); vector< pair > xx; for(unsigned int i=0;i0){ if( x[i].first==x[i-1].first )continue; } xx.push_back(x[i]); } x=xx; } Streamliner::Streamliner(const CSV& seeds):opts(probtrackxOptions::getInstance()), logger(LogSingleton::getInstance()), vols(opts.usef.value()), m_seeds(seeds) { // the tracking mask - no tracking outside of this read_volume(m_mask,opts.maskfile.value()); // particle m_part.initialise(0,0,0,0,0,0,opts.steplength.value(), m_mask.xdim(),m_mask.ydim(),m_mask.zdim(), false); // no-integrity if(opts.skipmask.value()!="") read_volume(m_skipmask,opts.skipmask.value()); // loop checking box m_lcrat=5; // hard-coded! box is five times smaller than brain mask if(opts.loopcheck.value()){ m_loopcheck.reinitialize(int(ceil(m_mask.xsize()/m_lcrat)+1), int(ceil(m_mask.ysize()/m_lcrat)+1), int(ceil(m_mask.zsize()/m_lcrat)+1),3); m_loopcheck=0; } // by default, assume there is no surface (speed) m_surfexists=false; if(m_seeds.nSurfs()>0){surfexists();} // exclusion mask // now in CSV format if(opts.rubbishfile.value()!=""){ load_rubbish(opts.rubbishfile.value()); } // stopping mask // now in CSV format if(opts.stopfile.value()!=""){ load_stop(opts.stopfile.value()); } // waymasks in CSV format if(opts.waypoints.set()){ load_waymasks(opts.waypoints.value()); m_waycond=opts.waycond.value(); } // choose preferred fibre within this mask (prior knowledge) if(opts.prefdirfile.value()!=""){ read_volume4D(m_prefdir,opts.prefdirfile.value()); } // local curvature threshold if(opts.loccurvthresh.value()!=""){ read_volume(m_loccurvthresh,opts.loccurvthresh.value()); } // 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())){//presumably ascii file provided m_Seeds_to_DTI = read_ascii_matrix(opts.seeds_to_dti.value()); m_DTI_to_Seeds = m_Seeds_to_DTI.i(); m_rotdir = m_Seeds_to_DTI.SubMatrix(1,3,1,3); } else{ m_IsNonlinXfm = true; FnirtFileReader ffr(opts.seeds_to_dti.value()); m_Seeds_to_DTI_warp = ffr.FieldAsNewimageVolume4D(true); if(opts.dti_to_seeds.value()==""){ cerr << "TRACT::Streamliner:: DTI -> Seeds transform needed" << endl; exit(1); } 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) imgradient(m_Seeds_to_DTI_warp[0],m_jacx); imgradient(m_Seeds_to_DTI_warp[1],m_jacy); imgradient(m_Seeds_to_DTI_warp[2],m_jacz); } } vols.initialise(opts.basename.value(),m_mask); m_path.reserve(opts.nsteps.value()); m_diff_path.reserve(opts.nsteps.value()); if(m_surfexists) m_crossedvox.reserve(opts.nsteps.value()); m_x_s_init=0; m_y_s_init=0; m_z_s_init=0; m_inmask3.reserve(opts.nsteps.value()); m_inlrmask3.reserve(opts.nsteps.value()); } void Streamliner::rotdir(const ColumnVector& dir,ColumnVector& rotdir, const float& x,const float& y,const float& z){ if(!m_IsNonlinXfm){ rotdir = m_rotdir*dir; if(rotdir.MaximumAbsoluteValue()>0) rotdir = rotdir/std::sqrt(rotdir.SumSquare()); } else{ ColumnVector xyz_dti(3),xyz_seeds(3); xyz_seeds << x << y << z; xyz_dti = NewimageCoord2NewimageCoord(m_DTI_to_Seeds_warp, false,m_seeds.get_refvol(),m_mask,xyz_seeds); Matrix F(3,3),Jw(3,3); int x=(int)round((float)xyz_dti(1)); int y=(int)round((float)xyz_dti(2)); int z=(int)round((float)xyz_dti(3)); Jw << m_jacx(x,y,z,0) << m_jacx(x,y,z,1) << m_jacx(x,y,z,2) << m_jacy(x,y,z,0) << m_jacy(x,y,z,1) << m_jacy(x,y,z,2) << m_jacz(x,y,z,0) << m_jacz(x,y,z,1) << m_jacz(x,y,z,2); F = (IdentityMatrix(3) + Jw).i(); rotdir = F*dir; if(rotdir.MaximumAbsoluteValue()>0) rotdir = rotdir/std::sqrt(rotdir.SumSquare()); } } int Streamliner::streamline(const float& x_init,const float& y_init,const float& z_init, const ColumnVector& dim_seeds,const int& fibst){ //Tracer_Plus tr("Streamliner::streamline"); //fibst tells tractvolsx which fibre to start with if there are more than one.. //x_init etc. are in seed space... vols.reset(fibst); m_x_s_init=x_init; // seed x position in voxels m_y_s_init=y_init; // and y m_z_s_init=z_init; // and z ColumnVector xyz_seeds(3); xyz_seeds< waycrossed; vector crossedlocs3; vector crossedvox; int cnt=-1; // loopcheck stuff float oldrx,oldry,oldrz; int lcx,lcy,lcz; bool forcedir=false; //NB - this only goes in one direction!! if(opts.onewaycondition.value()){ for(unsigned int i=0; i=0){ if(!m_IsNonlinXfm) xyz_seeds = vox_to_vox(xyz_dti,vols.dimensions(),dim_seeds,m_DTI_to_Seeds); else{ xyz_seeds = NewimageCoord2NewimageCoord(m_Seeds_to_DTI_warp,false,m_mask,m_seeds.get_refvol(),xyz_dti); } } x_s =(int)round((float)xyz_seeds(1)); y_s =(int)round((float)xyz_seeds(2)); z_s =(int)round((float)xyz_seeds(3)); // how prefdir works: // if a vector field is given (tested using 4th dim==3) then set prefdir to that orientation // eventually will be flipped to match the current direction of travel // if dim4<3, then : // - use dim1 scalar as fibre sampling method (i.e. randfib 1 2 3 ) // - use dim2 scalar (when given) as which fibre to follow blindly, i.e. without flipping pref_x=0;pref_y=0;pref_z=0; int sample_fib = 0; if(opts.prefdirfile.value()!=""){ if(m_prefdir.tsize()==3){ pref_x = m_prefdir(x_p,y_p,z_p,0); pref_y = m_prefdir(x_p,y_p,z_p,1); pref_z = m_prefdir(x_p,y_p,z_p,2); } else{ if(m_prefdir(x_s,y_s,z_s,0)!=0) sample_fib = (int)m_prefdir(x_p,y_p,z_p,0); if(sample_fib>3)sample_fib=3; } } // // attractor mask // if(opts.pullmask.value()!=""){ // ColumnVector pulldir(3);float mindist; // if(m_pullmask.is_near_surface(xyz_seeds,opts.pulldist.value(),pulldir,mindist)){ // m_prefx = pulldir(1); // m_prefy = pulldir(2); // m_prefz = pulldir(3); // } // } // augment the path m_path.push_back(xyz_seeds);cnt++; if(cnt>0) pathlength += opts.steplength.value(); // Do this only once as it is the same for all surfaces if(cnt>0 && m_surfexists){ float line[2][3]={{m_path[cnt-1](1),m_path[cnt-1](2),m_path[cnt-1](3)}, {m_path[cnt](1),m_path[cnt](2),m_path[cnt](3)}}; m_seeds.line_crossed_voxels(line,crossedvox); //crossed in voxels m_crossedvox.push_back(crossedvox); } // only test exclusion after at least one step if(opts.rubbishfile.value()!="" && cnt>0){ if(m_rubbish.has_crossed(m_path[cnt-1],m_path[cnt],crossedvox)){ rubbish_passed=1; break; } } // update every passed_flag if(m_way_passed_flags.size()>0){ if(cnt>0){ waycrossed.clear(); m_waymasks.has_crossed_roi(m_path[cnt-1],m_path[cnt],crossedvox,waycrossed); for(unsigned int wm=0;wm0){ waycrossed.clear(); m_netmasks.has_crossed_roi(m_path[cnt-1],m_path[cnt],crossedvox,waycrossed); for(unsigned int wm=0;wm0){ waycrossed.clear();crossedlocs3.clear(); if(m_mask3.has_crossed_roi(m_path[cnt-1],m_path[cnt],crossedvox,waycrossed,crossedlocs3)){ fill_inmask3(crossedlocs3,pathlength); } if(opts.lrmask3.value()!=""){ waycrossed.clear();crossedlocs3.clear(); if(m_lrmask3.has_crossed_roi(m_path[cnt-1],m_path[cnt],crossedvox,waycrossed,crossedlocs3)){ fill_inlrmask3(crossedlocs3,pathlength); } } } // ////////////////////////////// // sample a new fibre orientation int newx,newy,newz; if(opts.skipmask.value() == ""){ th_ph_f = vols.sample(m_part.x(),m_part.y(),m_part.z(), // sample at this location m_part.rx(),m_part.ry(),m_part.rz(), // choose closest sample to this pref_x,pref_y,pref_z, // unless we have this prefered direction sample_fib, // controls probabilities of sampling a given fibre sampled_fib, // which fibre has been sampled newx,newy,newz); // which voxel has been considered } else{ if(m_skipmask(x_s,y_s,z_s)==0)//only sample outside skipmask th_ph_f=vols.sample(m_part.x(),m_part.y(),m_part.z(), m_part.rx(),m_part.ry(),m_part.rz(), pref_x,pref_y,pref_z, sample_fib, sampled_fib, newx,newy,newz); } ColumnVector voxfib(4); voxfib<1){ if(m_path.size()==2 && opts.forcefirststep.value()){ // do nothing } else if(m_stop.has_crossed(m_path[cnt-1],m_path[cnt],crossedvox)){ break; } } // jump tmp2=0; if(opts.usef.value()){tmp2=(float)rand()/(float)RAND_MAX;} if(th_ph_f(3)>tmp2){ //volume fraction criterion if(opts.loccurvthresh.value()!=""){ cthr=m_loccurvthresh(x_p,y_p,z_p); } if(!m_part.check_dir(th_ph_f(1),th_ph_f(2),cthr,forcedir)){ // curvature threshold break; } if((th_ph_f(1)!=0 && th_ph_f(2)!=0)){ if( (m_mask(x_p,y_p,z_p) != 0) ){ if(!opts.modeuler.value()) m_part.jump(th_ph_f(1),th_ph_f(2),forcedir); else{ ColumnVector test_th_ph_f; m_part.testjump(th_ph_f(1),th_ph_f(2),forcedir); test_th_ph_f=vols.sample(m_part.testx(),m_part.testy(),m_part.testz(), m_part.rx(),m_part.ry(),m_part.rz(), pref_x,pref_y,pref_z,sample_fib,sampled_fib,newx,newy,newz); test_th_ph_f=mean_sph_pol(th_ph_f,test_th_ph_f); m_part.jump(test_th_ph_f(1),test_th_ph_f(2),forcedir); } } else{ break; // outside mask } } else{ break; // direction=zero } } else{ break; // volume fraction threshold } } else{ break; // outside mask } } // Close Step Number Loop (done tracking sample) // reset loopcheck box if(opts.loopcheck.value()){ m_loopcheck=0; } // rejflag = 0 (accept), 1 (reject) or 2 (wait for second direction) int rejflag=0; if(rubbish_passed) return(1); if(pathlength0)numpassed++; } if(numpassed==0)rejflag=1; else if(numpassed0){m_stline.surfexists();} // seeds are CSV-format if(!opts.simple.value()){ m_s2t_count=m_stline.get_seeds(); m_s2t_count.reset_values(); for(int m=0;m (m_numseeds,m_numseeds); m_Conrow1 = 1; vector coords = m_stline.get_seeds().get_locs_coords(); vector roicind = m_stline.get_seeds().get_locs_coord_index(); vector roiind = m_stline.get_seeds().get_locs_roi_index(); Matrix CoordMat1(m_numseeds,5); for (unsigned int i=0;i (m_numseeds,numnz); if( !opts.simple.value()){ vector coords = m_stline.get_seeds().get_locs_coords(); vector roicind = m_stline.get_seeds().get_locs_coord_index(); vector roiind = m_stline.get_seeds().get_locs_roi_index(); Matrix CoordMat2(m_numseeds,5); for (unsigned int i=0;i (nmask3,nlrmask3); //OUT(m_ConMat3->Nrows()); //OUT(m_ConMat3->Ncols()); //exit(1); // save lookup tables... CSV mask3(m_stline.get_mask3()); vector coords = mask3.get_locs_coords(); vector roicind = mask3.get_locs_coord_index(); vector roiind = mask3.get_locs_roi_index(); Matrix mat(mask3.nLocs(),5); for (unsigned int i=0;i lrcoords = lrmask3.get_locs_coords(); vector lrroicind = lrmask3.get_locs_coord_index(); vector lrroiind = lrmask3.get_locs_roi_index(); Matrix lrmat(lrmask3.nLocs(),5); for (unsigned int i=0;i0){m_stline.surfexists();} m_ConMat4 = new SpMat_HCP(numnz,m_mask4.nLocs()); } // COMMENTED OUT SOME OUTPUTS [NOT BEING USED AT THIS STAGE] // vector coords = m_stline.get_seeds().get_locs_coords(); // vector roicind = m_stline.get_seeds().get_locs_coord_index(); // vector roiind = m_stline.get_seeds().get_locs_roi_index(); // Matrix CoordMat4(m_numseeds,5); // for (unsigned int i=0;i crossedrois,crossedlocs; vector crossedvox; int nlocs=0; int offset=-1; bool restarted=false; for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0){ //m_lastpoint(x_s,y_s,z_s)+=1; pathlength=0; offset-=1; restarted=true; } if(m_beenhere(x_s,y_s,z_s)==0){ if(!opts.pathdist.value()) m_prob(x_s,y_s,z_s)+=1; else m_prob(x_s,y_s,z_s)+=pathlength; m_beenhere(x_s,y_s,z_s)=1; if(opts.opathdir.value() && i>0){ ColumnVector v(3); v=m_path[i]-m_path[i-1]; v/=std::sqrt(v.SumSquare()); // Add direction (needs to account for the current direction and flip if necessary) // lower diagonal rows (because of the way SymmetricMatrix works) m_localdir(x_s,y_s,z_s,0)+=v(1)*v(1); m_localdir(x_s,y_s,z_s,1)+=v(1)*v(2); m_localdir(x_s,y_s,z_s,2)+=v(2)*v(2); m_localdir(x_s,y_s,z_s,3)+=v(1)*v(3); m_localdir(x_s,y_s,z_s,4)+=v(2)*v(3); m_localdir(x_s,y_s,z_s,5)+=v(3)*v(3); } } // Fill alternative mask // This mask's values are: // 0: location not to be considered // 1: location has not been visited // 2: location has been visited if(opts.pathfile.set()){ if(pathlength>0 && !restarted){ if(m_beenhere_alt.nSurfs()>0){ crossedvox=m_crossedvox[i+offset]; } crossedrois.clear();crossedlocs.clear(); if(m_beenhere_alt.has_crossed_roi(m_path[i-1],m_path[i],crossedvox,crossedrois,crossedlocs)){ nlocs+=crossedlocs.size(); for(unsigned int i=0;i crossedlocs,crossedrois; vector crossedvox; bool hascrossed=false; for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0){ offset-=1; continue; } // alternative roi if(opts.pathfile.set()){ if(i>0){ if(m_beenhere_alt.nSurfs()>0){ crossedvox=m_crossedvox[i+offset]; } if(m_beenhere_alt.has_crossed_roi(m_path[i-1],m_path[i],crossedvox,crossedrois,crossedlocs)) hascrossed=true; } } } if(opts.pathfile.set() && hascrossed){ //cout<<"reset"<1) m_beenhere_alt.set_value(crossedlocs[i],1); } } } void Counter::add_path(){ m_save_paths.push_back(m_path); } void Counter::save_paths(){ string filename=logger.appendDir("saved_paths.txt"); ofstream of(filename.c_str()); if (of.is_open()){ for(unsigned int i=0;i crossed; vector crossedvox; float pathlength=0; int cnt=0,offset=-1; for(unsigned int i=1;i0){ if( ((i+offset) < 0 ) || ((i+offset)>=m_crossedvox.size())){ cout<<"-----------------------"<0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0){ pathlength=0; } if(m_beenhere(x_s,y_s,z_s)==0){ for(unsigned int t=0;t0){ ColumnVector v(3); v=m_path[i]-m_path[i-1]; v/=std::sqrt(v.SumSquare()); m_localdir_multi[t](x_s,y_s,z_s,0)+=v(1)*v(1); m_localdir_multi[t](x_s,y_s,z_s,1)+=v(1)*v(2); m_localdir_multi[t](x_s,y_s,z_s,2)+=v(2)*v(2); m_localdir_multi[t](x_s,y_s,z_s,3)+=v(1)*v(3); m_localdir_multi[t](x_s,y_s,z_s,4)+=v(2)*v(3); m_localdir_multi[t](x_s,y_s,z_s,5)+=v(3)*v(3); } } m_beenhere(x_s,y_s,z_s)=1; } } } void Counter::update_matrix1(){ //Tracer_Plus tr("Counter::update_matrix1"); // use path and has_crossed float pathlength=opts.steplength.value(),val=1; vector crossedseeds,crossedlocs; vector allcrossed;vector allvals; vector crossedvox; int offset=-1; for(unsigned int i=1;i0){ crossedvox=m_crossedvox[i+offset]; } if(m_stline.get_seeds().has_crossed_roi(m_path[i-1],m_path[i],crossedvox,crossedseeds,crossedlocs)){ allcrossed.insert(allcrossed.end(),crossedlocs.begin(),crossedlocs.end()); vector vals(crossedlocs.size(),val); allvals.insert(allvals.end(),vals.begin(),vals.end()); } val = opts.pathdist.value()?pathlength:1; pathlength+=opts.steplength.value(); } // fill matrix1 { //Tracer_Plus tr("make_unique"); make_unique(allcrossed,allvals); } for(unsigned int i=0;iAddTo(m_Conrow1,allcrossed[i]+1,allvals[i]); m_ConMat1->AddTo(m_curloc+1,allcrossed[i]+1,allvals[i]); } } void Counter::update_matrix2_row(){ //Tracer_Plus tr("Counter::update_matrix2"); //run this one every streamline - not every voxel.. float d=opts.steplength.value(); int x_lr,y_lr,z_lr,Concol2; ColumnVector xyz_lr(3); for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0) d=opts.steplength.value(); xyz_lr=vox_to_vox(m_path[i],m_seedsdim,m_lrdim,m_I); x_lr=(int)round((float)xyz_lr(1)); y_lr=(int)round((float)xyz_lr(2)); z_lr=(int)round((float)xyz_lr(3)); Concol2=m_lookup2(x_lr,y_lr,z_lr); if(Concol2>0){ if(m_beenhere2(x_lr,y_lr,z_lr)==0){ if(!opts.pathdist.value()) m_ConMat2->AddTo(m_curloc+1,Concol2,1); else m_ConMat2->AddTo(m_curloc+1,Concol2,d); m_beenhere2(x_lr,y_lr,z_lr)=1; d+=opts.steplength.value(); } } } } void Counter::update_matrix3(){ //Tracer_Plus tr("Counter::update_matrix3"); vector< pair >& inmask3 = m_stline.get_inmask3(); vector< pair >& inlrmask3 = m_stline.get_inlrmask3(); bool uselr = (opts.lrmask3.value()!=""); if(!uselr){ if(inmask3.size()<2)return; } else{ if(inmask3.size()<1 || inlrmask3.size()<1)return; } // remove duplicates make_unique(inmask3); if(!uselr){// where we update NxN matrix for(unsigned int i=0;iAddTo(inmask3[i].first+1,inmask3[j].first+1,1); else{ float val = fabs(inmask3[i].second-inmask3[j].second); m_ConMat3->AddTo(inmask3[i].first+1,inmask3[j].first+1,val); } } } } else{ // where we update Nxn matrix make_unique(inlrmask3); for(unsigned int i=0;iAddTo(inmask3[i].first+1,inlrmask3[j].first+1,1); else{ float val = fabs(inmask3[i].second-inlrmask3[j].second); m_ConMat3->AddTo(inmask3[i].first+1,inlrmask3[j].first+1,val); } } } } } void Counter::reset_beenhere3(){ m_stline.clear_inmask3(); m_stline.clear_inlrmask3(); } void Counter::reset_beenhere2(){ ColumnVector xyz_lr(3); for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0) d=opts.steplength.value(); xyz<0){ if(m_beenhere4(x,y,z)==0){ m_ConMat4->AddToTraj(Conrow4,m_curloc+1,d,(int)m_diff_path[i](4)); m_beenhere4(x,y,z)=1; d+=opts.steplength.value(); } } } } else{ //case where mask4 is set vector rows,cols,vals,crossedrois,crossedlocs; vector ds; bool restarted=false;int offset=-1; vector crossedvox; for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0){ d=opts.steplength.value();restarted=true; offset-=1; } x=(int)round(float(m_diff_path[i](1))); y=(int)round(float(m_diff_path[i](2))); z=(int)round(float(m_diff_path[i](3))); if(m_beenhere4(x,y,z)==0){ rows.push_back(m_lookup4(x,y,z)); vals.push_back((int)m_diff_path[i](4)); ds.push_back(d); m_beenhere4(x,y,z)=1; d+=opts.steplength.value(); } if(i>0 && !restarted){ crossedlocs.clear();crossedrois.clear(); if(m_mask4.nSurfs()>0){ crossedvox=m_crossedvox[i+offset]; } if(m_mask4.has_crossed_roi(m_path[i-1],m_path[i],crossedvox,crossedrois,crossedlocs)){ for(unsigned int j=0;j0){ for(unsigned int j=0;jAddToTraj(rows[i],cols[j],ds[i],vals[i]); } } } } } void Counter::save_total(const int& keeptotal){ // save total number of particles that made it through the streamlining ColumnVector keeptotvec(1); keeptotvec(1)=keeptotal; write_ascii_matrix(keeptotvec,logger.appendDir("waytotal")); } void Counter::save_total(const vector& keeptotal){ // save total number of particles that made it through the streamlining ColumnVector keeptotvec(keeptotal.size()); for (int i=1;i<=(int)keeptotal.size();i++) keeptotvec(i)=keeptotal[i-1]; write_ascii_matrix(keeptotvec,logger.appendDir("waytotal")); } void Counter::save(){ if(opts.simpleout.value() && !opts.simple.value()){ save_pathdist(); } if(opts.network.value()){ m_stline.save_network_mat(); } if(opts.save_paths.value()) save_paths(); if(opts.s2tout.value()){ save_seedcounts(); } if(opts.matrix1out.value()){ save_matrix1(); } if(opts.matrix2out.value()){ save_matrix2(); } if(opts.matrix3out.value()){ save_matrix3(); } if(opts.matrix4out.value()){ save_matrix4(); } } void Counter::save_pathdist(){ m_prob.setDisplayMaximumMinimum(m_prob.max(),m_prob.min()); save_volume(m_prob,logger.appendDir(opts.outfile.value())); //m_lastpoint.setDisplayMaximumMinimum(m_lastpoint.max(),m_lastpoint.min()); //save_volume(m_lastpoint,logger.appendDir("lastpoint")); if(opts.pathfile.set()){ m_prob_alt.save_rois(logger.appendDir(opts.outfile.value())+"_alt"); //m_prob_alt.save_as_volume(logger.appendDir(opts.outfile.value())+"_alt_vol"); //m_beenhere_alt.save_rois(logger.appendDir(opts.outfile.value())+"_beenhere"); } if(opts.opathdir.value()){ volume4D tmplocdir(m_prob.xsize(),m_prob.ysize(),m_prob.zsize(),3); copybasicproperties(m_prob,tmplocdir); tmplocdir=0; SymmetricMatrix Tens(3); DiagonalMatrix D;Matrix V; for(int z=0;z targetnames; for(int m=0;m=0){ lastpos=pos; pos=tmpname.find("/",pos); // replace / with _ tmpname[pos]='_'; } //only take things after the last pos tmpname=tmpname.substr(lastpos+1,tmpname.length()-lastpos-1); targetnames.push_back(tmpname); } for(int m=0;m1){ for(int i=0;i tmplocdir(m_prob.xsize(),m_prob.ysize(),m_prob.zsize(),3); copybasicproperties(m_prob,tmplocdir); for(unsigned int t=0;t& coordvol, const Matrix& old2new_mat) { for (int n=0; n<=coordvol.maxx(); n++) { ColumnVector v(4); v << coordvol(n,0,0) << coordvol(n,1,0) << coordvol(n,2,0) << 1.0; v = old2new_mat * v; coordvol(n,0,0) = MISCMATHS::round(v(1)); coordvol(n,1,0) = MISCMATHS::round(v(2)); coordvol(n,2,0) = MISCMATHS::round(v(3)); } } void applycoordchange(Matrix& coordvol, const Matrix& old2new_mat) { for (int n=1; n<=coordvol.Nrows(); n++) { ColumnVector v(4); v << coordvol(n,1) << coordvol(n,2) << coordvol(n,3) << 1.0; v = old2new_mat * v; coordvol(n,1) = MISCMATHS::round(v(1)); coordvol(n,2) = MISCMATHS::round(v(2)); coordvol(n,3) = MISCMATHS::round(v(3)); } } void Counter::save_matrix1(){ m_ConMat1->Print(logger.appendDir("fdt_matrix1.dot")); } void Counter::save_matrix2(){ m_ConMat2->Print(logger.appendDir("fdt_matrix2.dot")); } void Counter::save_matrix3(){ m_ConMat3->Print(logger.appendDir("fdt_matrix3.dot")); } void Counter::save_matrix4(){ m_ConMat4->SaveTrajFile(logger.appendDir("fdt_matrix4_")); } // this function returns the total number of pathways that survived streamlining int Seedmanager::run(const float& x,const float& y,const float& z, bool onewayonly, int fibst,float sampvox){ //Tracer_Plus tr("Seedmanager::run"); //onewayonly for mesh things.. if(opts.fibst.set()){ fibst=opts.fibst.value()-1; } else{ if(fibst == -1){ fibst=0; } //TB moved randfib option inside tractvols.h 28/10/2009 // This means that we have access to fsamples when figuring out fibst // so we can choose to seed in proportion to f in that voxel. } int nlines=0; for(int p=0;p2){ //This bit of code just does random sampling from all fibre populations - even those whose f value is less than f-thresh. //3 other possibilities - randfib==0 -> use fibst (default first fibre but can be set) // randfib==1 - random sampling of fibres bigger than fthresh // randfib==2 random sampling of fibres bigger than fthresh in proporthion to their f-values. float tmp=rand()/float(RAND_MAX) * float(m_counter.get_stline().nfibres()-1); fibst = (int)round(tmp); } // random jitter of seed point inside a sphere float newx=x,newy=y,newz=z; if(sampvox>0){ bool rej=true;float dx,dy,dz;float r2=sampvox*sampvox; while(rej){ dx=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); dy=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); dz=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); if( dx*dx+dy*dy+dz*dz <= r2 ) rej=false; } newx+=dx/m_seeddims(1); newy+=dy/m_seeddims(2); newz+=dz/m_seeddims(3); } if(opts.verbose.value()>1) logger.setLogFile("particle"+num2str(p)); m_counter.get_stline().reset(); //This now includes a vols.reset() in order to get fibst right. bool forwardflag=false,backwardflag=false; int rejflag1=1,rejflag2=1; // 0:accept, 1:reject, 2:wait m_counter.clear_path(); // track in one direction if(!onewayonly || opts.matrix3out.value()){//always go both ways in matrix3 mode rejflag1 = m_counter.get_stline().streamline(newx,newy,newz,m_seeddims,fibst); if(rejflag1==0 || rejflag1==2){ forwardflag=true; m_counter.append_path(); if(opts.save_paths.value()) m_counter.add_path(); } m_counter.get_stline().reverse(); } // track in the other direction rejflag2=m_counter.get_stline().streamline(newx,newy,newz,m_seeddims,fibst); if(rejflag2==0){ backwardflag=true; } if(rejflag2>0){ backwardflag=false; if(rejflag1>0) forwardflag=false; } if(!forwardflag) m_counter.clear_path(); if(backwardflag){ m_counter.append_path(); if(opts.save_paths.value()) m_counter.add_path(); } if(forwardflag || backwardflag){ nlines++; m_counter.count_streamline(); if(opts.matrix3out.value()||opts.matrix1out.value()){ float pathlength; if( !forwardflag || !backwardflag) pathlength = m_counter.calc_pathlength(0); else // if the paths are appended, one step has zero length pathlength = m_counter.calc_pathlength(1); if(opts.matrix3out.value() && pathlength>=opts.distthresh3.value()) m_counter.update_matrix3(); if(opts.matrix1out.value() && pathlength>=opts.distthresh1.value()) m_counter.update_matrix1(); } } m_counter.clear_streamline(); } m_counter.count_seed(); return nlines; } }