Skip to content
Snippets Groups Projects
slicetimer.cc 6.43 KiB
Newer Older
Stephen Smith's avatar
Stephen Smith committed
/*  slicetimer.cc - FMRIB's Slice Timing Utility
    
    Peter Bannister and Stephen Smith, FMRIB Image Analysis Group
    
Stephen Smith's avatar
 
Stephen Smith committed
    Copyright (C) 2001-2003 University of Oxford  */
Stephen Smith's avatar
Stephen Smith committed

/*  CCOPYRIGHT */


Stephen Smith's avatar
 
Stephen Smith committed
#include <cmath>
#include <iostream>
#include <iomanip>
Stephen Smith's avatar
 
Stephen Smith committed
#include <fstream>
#include <cstdlib>
#include <string>
#include <sstream>
Stephen Smith's avatar
 
Stephen Smith committed
#include <vector>
Stephen Smith's avatar
Stephen Smith committed

#include "miscmaths/optimise.h"
#include "newmatap.h"
#include "newmatio.h"
#include "newimage/newimageall.h"
#include "utils/options.h"
#include "miscmaths/kernel.h"
Stephen Smith's avatar
Stephen Smith committed

using namespace MISCMATHS;
using namespace NEWMAT;
using namespace NEWIMAGE;
using namespace Utilities;

string title="slicetimer (Version 1.8)\nFMRIB's Interpolation for Slice Timing\nCopyright(c) 2001-2002, University of Oxford";
string examples="slicetimer -i <timeseries> [-o <corrected_timeseries>] [options]\n";

Option<bool> help(string("-h,--help"), false,
		  string("display this message"),
		  false, no_argument);
Option<bool> verbose(string("-v,--verbose"), false, 
		     string("switch on diagnostic messages"), 
		     false, no_argument);
Option<bool> odd(string("--odd"), false, 
		     string("use interleaved acquisition"), 
		     false, no_argument);
Option<bool> down(string("--down"), false, 
		     string("reverse slice indexing"), 
		     false, no_argument);
Option<string> inputname(string("-i,--in"), string(""),
			 string("filename of input timeseries"),
			 true, requires_argument);
Option<string> outputname(string("-o,--out"), string(""),
			  string("filename of output timeseries"),
			  false, requires_argument);
Option<string> tcustom(string("--tcustom"), string(""),
			  string("filename of single-column custom interleave timing file"),
			  false, requires_argument);
Option<string> ocustom(string("--ocustom"), string(""),
Stephen Smith's avatar
Stephen Smith committed
			  string("filename of single-column custom interleave order file (first slice is referred to as 1 not 0)"),
Stephen Smith's avatar
Stephen Smith committed
			  false, requires_argument);
Option<int> direction(string("-d,--direction"), 3,
		      string("direction of slice acquisition (x=1,y=2,z=3) - default is z"),
		      false, requires_argument);
Option<float> repeat(string("-r,--repeat"), 3.0,
		      string("Specify TR of data - default is 3s"),
		      false, requires_argument);

int do_slice_correction()
{
  volume4D<float> timeseries;
  volumeinfo in_info;
  Matrix timings;
  
  int no_volumes, no_slices;
Stephen Smith's avatar
Stephen Smith committed
  float repeat_time, offset=0, slice_spacing;
Stephen Smith's avatar
Stephen Smith committed

  if (inputname.set()) {
    if (verbose.value()) { cout << "Reading input volume" << endl; }
    read_volume4D(timeseries,inputname.value(),in_info);
    if (!outputname.set())
      outputname.set_value(inputname.value() + "_st");
  } else if (outputname.set()) {
    cerr << "Must specify an input volume (-i or --in) to generate corrected data." 
	 << endl;
    return -1;
  }

  no_slices = timeseries.zsize();
  no_volumes = timeseries.tsize();
  repeat_time = timeseries.tdim();
  if (repeat_time ==0){
Stephen Smith's avatar
 
Stephen Smith committed
    // cerr << "Zero TR in file header - fixing ... " ;
Stephen Smith's avatar
Stephen Smith committed
    repeat_time = repeat.value();
  }
Stephen Smith's avatar
 
Stephen Smith committed
  // cerr << "TR = " << repeat_time << endl;
Stephen Smith's avatar
Stephen Smith committed
  slice_spacing = repeat_time / no_slices;

  if (direction.value() == 1) timeseries. swapdimensions(3,2,1); // Flip z and x
  if (direction.value() == 2) timeseries. swapdimensions(1,3,2); // Flip z and y

  if (tcustom.set()) {
    timings.ReSize(1, timeseries.zsize());
    timings = read_ascii_matrix(tcustom.value(), timeseries.zsize(), 1);
  }  else if (ocustom.set()) {
    timings.ReSize(1, timeseries.zsize());
    timings = read_ascii_matrix(ocustom.value(), timeseries.zsize(), 1);
  }

  ColumnVector userkernel = sinckernel1D("hanning", 7, 1201);
Stephen Smith's avatar
Stephen Smith committed
  // for(int i=1; i<=1201; i++) cout << i << " " << userkernel(i) << endl;

  float recenter = (((float) no_slices)/2 - 0.5)/ no_slices;
Stephen Smith's avatar
Stephen Smith committed
  
  for (int slice=1; slice<=no_slices; slice++) {
Stephen Smith's avatar
Stephen Smith committed
    if (tcustom.set()) {
      offset = -timings(slice, 1);
    } else if (ocustom.set()) { 
      int local_count=1;
      while (local_count <= no_slices) {
	if (timings(local_count, 1) == slice) {
	  offset = -(local_count -1)* (slice_spacing / repeat_time);
	  local_count = no_slices + 1;
	} else 
	  local_count++;
      }
    } else if (odd.value()) { // acquisition order: 1,3,5, ..., 2,4,6 ...
      if ((slice % 2) == 0) // even
	offset = -( ceil((float)no_slices / 2) + ((slice -1)/ 2)) * (slice_spacing / repeat_time);
      else
	offset = -((slice -1) / 2) * (slice_spacing / repeat_time);
    } else if (down.value()) {
      offset = -(no_slices - slice)* (slice_spacing / repeat_time);
    } else { 
      offset = -(slice -1)* (slice_spacing / repeat_time);
    }
    
    for (int x_pos = 0; x_pos < timeseries. xsize(); x_pos++)
      for (int y_pos = 0; y_pos < timeseries. ysize(); y_pos++){
Stephen Smith's avatar
Stephen Smith committed
	ColumnVector voxeltimeseries = timeseries.voxelts(x_pos,y_pos,slice-1);
	ColumnVector interpseries = voxeltimeseries;
	for (int time_step=1; time_step <= no_volumes; time_step++){
Stephen Smith's avatar
 
Stephen Smith committed
	  // interpseries(time_step) = interpolate_1d(voxeltimeseries, time_step - offset - recenter);
	  interpseries(time_step) = kernelinterpolation_1d(voxeltimeseries, time_step - offset - recenter, userkernel, 7);
Stephen Smith's avatar
Stephen Smith committed
	timeseries.setvoxelts(interpseries,x_pos,y_pos,slice-1);
      }
    
    if (verbose.value())
Stephen Smith's avatar
Stephen Smith committed
      cerr << "Slice " << slice << " offset " << offset + recenter << endl;
Stephen Smith's avatar
Stephen Smith committed
  }
  
  if (direction.value() == 1) timeseries. swapdimensions(3,2,1); // reverse Flip z and x
  if (direction.value() == 2) timeseries. swapdimensions(1,3,2); // reverse Flip z and y

  save_volume4D(timeseries, outputname.value());
  return 0;
}

int main (int argc,char** argv)
{
  Tracer tr("main");
  
  OptionParser options(title, examples);

  try {
    options.add(inputname);
    options.add(outputname);
    options.add(help);
    options.add(verbose);
    options.add(down);
    options.add(repeat);
    options.add(direction);
    options.add(odd);
    options.add(tcustom);
    options.add(ocustom);

    options.parse_command_line(argc, argv);

    if ( (help.value()) || (!options.check_compulsory_arguments(true)) )
      {
	options.usage();
	exit(EXIT_FAILURE);
      }
        
    if ( inputname.unset()) 
      {
	options.usage();
	cerr << endl 
	     << "--in or -i MUST be used." 
	     << endl;
	exit(EXIT_FAILURE);
      }
    
  }  catch(X_OptionError& e) {
    options.usage();
    cerr << endl << e.what() << endl;
    exit(EXIT_FAILURE);
  } catch(std::exception &e) {
    cerr << e.what() << endl;
  } 

  int retval = do_slice_correction();
  
  if (retval!=0) {
    cerr << endl << endl << "Error detected: try -h for help" << endl;
  }

  return retval;
}