-
Christian Beckmann authoredChristian Beckmann authored
fsl_regfilt.cc 6.41 KiB
/* fsl_regfilt -
Christian Beckmann, FMRIB Image Analysis Group
Copyright (C) 2006-2007 University of Oxford */
/* CCOPYRIGHT */
#include "libvis/miscplot.h"
#include "miscmaths/miscmaths.h"
#include "miscmaths/miscprob.h"
#include "utils/options.h"
#include <vector>
#include "newimage/newimageall.h"
#include "melhlprfns.h"
using namespace MISCPLOT;
using namespace MISCMATHS;
using namespace Utilities;
using namespace std;
// The two strings below specify the title and example usage that is
// printed out as the help or usage message
string title=string("fsl_regfilt (Version 1.0)")+
string("\n\n Copyright(c) 2007, University of Oxford (Christian F. Beckmann)\n")+
string(" Data de-noising by regressing out part of a design matrix\n")+
string(" using simple OLS regression on 4D images");
string examples="fsl_regfilt -i <input> -d <design> -f <components> -o <out> [options]";
//Command line Options {
Option<string> fnin(string("-i,--in"), string(""),
string(" input file name (4D image)"),
true, requires_argument);
Option<string> fnout(string("-o,--out"), string(""),
string("output file name for the filtered data"),
true, requires_argument);
Option<string> fndesign(string("-d,--design"), string(""),
string("file name of the GLM design matrix (time courses)"),
true, requires_argument);
Option<string> fnmask(string("-m,--mask"), string(""),
string("mask image file name"),
false, requires_argument);
Option<string> filter(string("-f,--filter"),string(""),
string("filter out part of the regression model, e.g. -f \"1,2,3\""),
true, requires_argument);
Option<bool> verbose(string("-v"),FALSE,
string(" switch on diagnostic messages"),
false, no_argument);
Option<bool> perfvn(string("--vn"),FALSE,
string(" perfrom variance-normalisation on data"),
false, no_argument);
Option<int> help(string("-h,--help"), 0,
string("display this help text"),
false,no_argument);
// Output options
Option<string> outdata(string("--out_data"),string(""),
string("output data"),
false, requires_argument);
Option<string> outvnscales(string("--out_vnscales"),string(""),
string("output scaling factors for variance normalisation"),
false, requires_argument);
/*
}
*/
//Globals {
int voxels = 0;
Matrix data;
Matrix design;
Matrix meanR;
RowVector vnscales;
volume<float> mask;
volume<float> Mean;
volumeinfo volinf; /*
}
*/
////////////////////////////////////////////////////////////////////////////
// Local functions
void save4D(Matrix what, string fname){
if(what.Ncols()==data.Ncols()||what.Nrows()==data.Nrows()){
volume4D<float> tempVol;
if(what.Nrows()>what.Ncols())
tempVol.setmatrix(what.t(),mask);
else
tempVol.setmatrix(what,mask);
save_volume4D(tempVol,fname,volinf);
}
}
bool isimage(Matrix what){
if((voxels > 0)&&(what.Ncols()==voxels || what.Nrows()==voxels))
return TRUE;
else
return FALSE;
}
void saveit(Matrix what, string fname){
if(isimage(what))
save4D(what,fname);
else
write_ascii_matrix(what,fname);
}
int dofilter(){
if(!isimage(data)){
cerr << "ERROR: need to specify 4D input to use filtering" << endl;
return 1;
}
if(verbose.value())
cout << " Calculating maps " << endl;
Matrix unmixMatrix = pinv(design);
Matrix maps = unmixMatrix * data;
Matrix noisedes;
Matrix noisemaps;
int ctr=0;
char *p;
char t[1024];
const char *discard = ", [];{(})abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*_-=+|\':><./?";
strcpy(t, filter.value().c_str());
p=strtok(t,discard);
ctr = atoi(p);
if(ctr>0 && ctr<=design.Ncols()){
noisedes = design.Column(ctr);
noisemaps = maps.Row(ctr).t();
}
do{
p=strtok(NULL,discard);
if(p){
ctr = atoi(p);
if(ctr>0 && ctr<=design.Ncols()){
noisedes |= design.Column(ctr);
noisemaps |= maps.Row(ctr).t();
}
}
}while(p);
Matrix newData;
if(verbose.value())
cout << " Calculating filtered data " << endl;
newData = data - noisedes * noisemaps.t();
newData = newData + ones(newData.Nrows(),1)*meanR;
save4D(newData,fnout.value());
return 0;
}
int setup(){
if(fsl_imageexists(fnin.value())){//read data
//input is 3D/4D vol
volume4D<float> tmpdata;
read_volume4D(tmpdata,fnin.value(),volinf);
// create mask
if(fnmask.value()>""){
read_volume(mask,fnmask.value());
if(!samesize(tmpdata[0],mask)){
cerr << "ERROR: Mask image does not match input image" << endl;
return 1;
};
}else{
if(verbose.value())
cout << " Creating mask image " << endl;
Mean = meanvol(tmpdata);
float Mmin, Mmax;
Mmin = Mean.min(); Mmax = Mean.max();
mask = binarise(Mean,float(Mmin + 0.01* (Mmax-Mmin)),Mmax);
}
data = tmpdata.matrix(mask);
voxels = data.Ncols();
if(verbose.value())
cout << " Data matrix size : " << data.Nrows() << " x " << voxels << endl;
}else{
cerr << "ERROR: cannot read input image " << fnin.value()<<endl;
return 1;
}
design = read_ascii_matrix(fndesign.value());
meanR=mean(data,1);
data = remmean(data,1);
design = remmean(design,1);
if(perfvn.value())
vnscales = Melodic::varnorm(data);
return 0;
}
void write_res(){
if(outdata.value()>"")
saveit(data,outdata.value());
if(outvnscales.value()>"")
saveit(vnscales,outvnscales.value());
}
int do_work(int argc, char* argv[]) {
if(setup())
exit(1);
if(dofilter())
exit(1);
write_res();
return 0;
}
////////////////////////////////////////////////////////////////////////////
int main(int argc,char *argv[]){
Tracer tr("main");
OptionParser options(title, examples);
try{
// must include all wanted options here (the order determines how
// the help message is printed)
options.add(fnin);
options.add(fnout);
options.add(fndesign);
options.add(fnmask);
options.add(filter);
options.add(perfvn);
options.add(verbose);
options.add(help);
options.add(outdata);
options.add(outvnscales);
options.parse_command_line(argc, argv);
// line below stops the program if the help was requested or
// a compulsory option was not set
if ( (help.value()) || (!options.check_compulsory_arguments(true)) ){
options.usage();
exit(EXIT_FAILURE);
}else{
// Call the local functions
return do_work(argc,argv);
}
}catch(X_OptionError& e) {
options.usage();
cerr << endl << e.what() << endl;
exit(EXIT_FAILURE);
}catch(std::exception &e) {
cerr << e.what() << endl;
}
}