Skip to content
Snippets Groups Projects
xfibres_pred.cc 5.75 KiB
/*  Copyright (C) 2010 University of Oxford  */
/*  Stam Sotiropoulos, Saad Jbabdi    */
/*  CCOPYRIGHT  */

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cmath>
#include "newimage/newimageall.h"

using namespace std;
using namespace NEWIMAGE;
using namespace NEWMAT;

//Computes the model 1 predicted signal from the mode of the bedpostx samples
//An f0 compartment could also be included in the model   
int main ( int argc, char *argv[]){
  if(argc<3 || argc>4){
    cerr<<" "<<endl;
    cerr<<"usage: xfibres_pred bpx_dir [data_file] output"<<endl<<endl;
    cerr<<"       bpx_dir is the bedpostx output directory "<<endl; 
    cerr<<"       data_file is optional, in case no mean_S0samples exists in the bpx dir, get the mean S0 from the data "<<endl; 
    cerr<<" "<<endl;
    exit(1);
  }
  
  Matrix bvecs,bvals;   //Read Input 
  volume<float> mask;
  volume<float> d,d_std,S0,f0, temp;
  volume4D<float> temp4D;
  vector< volume<float> > f;  
  vector< volume4D<float> > dyads;  
  
  string dir_name=argv[1], temp_name;
  temp_name=dir_name+"/bvals";
  bvals=read_ascii_matrix(temp_name);
  temp_name=dir_name+"/bvecs";
  bvecs=read_ascii_matrix(temp_name);
  
  if(bvecs.Nrows()>3) bvecs=bvecs.t();   //Make sure the bvecs entries are normalized unit vectors
  if(bvals.Nrows()>1) bvals=bvals.t();
  for(int i=1;i<=bvecs.Ncols();i++){
    float tmpsum=sqrt(bvecs(1,i)*bvecs(1,i)+bvecs(2,i)*bvecs(2,i)+bvecs(3,i)*bvecs(3,i));
    if(tmpsum!=0){
      bvecs(1,i)=bvecs(1,i)/tmpsum;
      bvecs(2,i)=bvecs(2,i)/tmpsum;
      bvecs(3,i)=bvecs(3,i)/tmpsum;
    }  
  }

  int num_fibres=0;  //Check how many fibres exist
  while (fsl_imageexists(dir_name+"/dyads"+num2str(num_fibres+1)))
    num_fibres++;
 
  temp_name=dir_name+"/mean_dsamples";   //Read bedpostx results 
  if (!fsl_imageexists(temp_name)){
    cout<<"No mean_dsamples file exists!"<<endl;
    exit(1); 
  }
  else read_volume(d,temp_name);
 
  temp_name=dir_name+"/mean_S0samples";   //In case no S0samples is saved, use the mean b=0 from the data
  if (!fsl_imageexists(temp_name) && argc!=4){
    cerr<<"No mean_S0samples or data file exists!"<<endl;
    exit(1);
  } 

  if (!fsl_imageexists(temp_name)){
    string data_name=argv[2];
    if (!fsl_imageexists(data_name)){
      cerr<<"Wrong data filename!"<<endl;
      exit(1);
    }
    else{
      cout<<"No mean_SOsamples found, getting the average of b=0's from data..."<<endl;
      volume4D<float> data;
      read_volume4D(data,data_name);
      S0.reinitialize(data.xsize(),data.ysize(),data.zsize());
      S0=0;
      int b0count=0;
      for (int l=1; l<=bvals.Ncols(); l++)
	if (bvals(1,l)>=0 && bvals(1,l)<=50){  //Treat as b=0, volumes with b up to 50 (imaging gradients contribution)
	  S0+=data[l-1];
	  b0count++;
	}
      S0/=b0count;
    }
  }
  else read_volume(S0,temp_name);
  
  for (int n=0; n<num_fibres; n++){   //Read dyads
    temp_name=dir_name+"/dyads"+num2str(n+1);
    if (!fsl_imageexists(temp_name)){
      cerr<<"No dyads"<<n+1<<" file exists!"<<endl;
      exit(1); }
    else{
      read_volume4D(temp4D,temp_name);
      dyads.push_back(temp4D);
    }
    temp_name=dir_name+"/mean_f"+num2str(n+1)+"samples";
    if (!fsl_imageexists(temp_name)){
      cerr<<"No mean_f"<<n+1<<"samples file exists!"<<endl;
      exit(1); }
    else{
      read_volume(temp,temp_name);
      f.push_back(temp);
    }
  }

  int modelnum=1; 
  temp_name=dir_name+"/mean_d_stdsamples";    
  if (fsl_imageexists(temp_name)){   //Read d_std if model2
    modelnum=2;
    read_volume(d_std,temp_name);
  }

  int f0_incl=0;
  temp_name=dir_name+"/mean_f0samples";    
  if (fsl_imageexists(temp_name)){
    f0_incl=1;
    read_volume(f0,temp_name); 
  }

  cout<<"Files for model"<<modelnum<<" with "<<num_fibres<<" fibres found"<<endl;
  if (f0_incl==1)
    cout<<"Also an f0 noise floor is assumed"<<endl<<endl;

  temp_name=dir_name+"/nodif_brain_mask";    
  if (fsl_imageexists(temp_name))
    read_volume(mask,temp_name);
  else{ 
    mask.reinitialize(d.xsize(),d.ysize(),d.zsize());
    mask=1;
  }
  
  volume4D<float> output;
  copybasicproperties(d,output);
  output.reinitialize(d.xsize(),d.ysize(),d.zsize(),bvals.Ncols());
  output=0;

  for(int z=d.minz();z<=d.maxz();z++){   //Compute predicted signal for each voxel
    for(int y=d.miny();y<=d.maxy();y++){
      for(int x=d.minx();x<=d.maxx();x++){
	if (mask(x,y,z)!=0){
	  for (int l=0; l<bvals.Ncols(); l++){ //for each datapoint
	    if (modelnum==1 || (modelnum==2 && d_std(x,y,z)<=1e-5)){ //model1 or model2 with small dstd
	      float sumf=0;
	      for (int n=0; n<num_fibres; n++){
		sumf+=f[n](x,y,z);
		float angp=dyads[n](x,y,z,0)*bvecs(1,l+1)+dyads[n](x,y,z,1)*bvecs(2,l+1)+dyads[n](x,y,z,2)*bvecs(3,l+1);
		output(x,y,z,l)+=f[n](x,y,z)*std::exp(-bvals(1,l+1)*d(x,y,z)*angp*angp);
	      }
	      if (f0_incl==1)
		output(x,y,z,l)+=f0(x,y,z)+(1-sumf-f0(x,y,z))*std::exp(-bvals(1,l+1)*d(x,y,z));
	      else  
		output(x,y,z,l)+=(1-sumf)*std::exp(-bvals(1,l+1)*d(x,y,z));
	    }
	    else{ //model2
	      float invdstd2=1.0/(d_std(x,y,z)*d_std(x,y,z));
	      float a=d(x,y,z)*d(x,y,z)*invdstd2; 
	      float b=d(x,y,z)*invdstd2;
	      float sumf=0;
	      for (int n=0; n<num_fibres; n++){
		sumf+=f[n](x,y,z);
		float angp=dyads[n](x,y,z,0)*bvecs(1,l+1)+dyads[n](x,y,z,1)*bvecs(2,l+1)+dyads[n](x,y,z,2)*bvecs(3,l+1);
		output(x,y,z,l)+=f[n](x,y,z)*std::exp(a*std::log(b/(b+bvals(1,l+1)*angp*angp)));
	      }

	      if (f0_incl==1)
		output(x,y,z,l)+=f0(x,y,z)+(1-sumf-f0(x,y,z))*std::exp(a*std::log(b/(b+bvals(1,l+1))));
	      else  
		output(x,y,z,l)+=(1-sumf)*std::exp(a*std::log(b/(b+bvals(1,l+1))));
	    }
	    output(x,y,z,l)*=S0(x,y,z); 
	  }
	}
      }
    }
    cout<<z+1<<" slices processed"<<endl;
  }
  cout<<"saving results"<<endl;
  save_volume4D(output,argv[argc-1]); 
  return 0;
}