#include "mrilib.h" static char prefix[THD_MAX_PREFIX] = "tnorm" ; static int datum = MRI_float ; static int mode = 2 ; static int polort = -1 ; static int dmode = 2 ; static void NORM_tsfunc( double tzero , double tdelta , int npts , float ts[] , double ts_mean , double ts_slope , void *ud , int nbriks, float *val ) ; int main( int argc , char *argv[] ) { THD_3dim_dataset *old_dset , *new_dset ; /* input and output datasets */ int nopt, ii , nvals ; /*----- Help the blessedly ignorant user? -----*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dTnorm [options] dataset\n" "Takes each voxel time series and normalizes it\n" "(by multiplicative scaling) -- in some sense.\n" "\n" "Options:\n" " -prefix p = use string 'p' for the prefix of the\n" " output dataset [DEFAULT = 'tnorm']\n" " -norm2 = L2 normalize (sum of squares = 1) [DEFAULT]\n" " -normR = normalize so sum of squares = number of time points\n" " * e.g., so RMS = 1.\n" " -norm1 = L1 normalize (sum of absolute values = 1)\n" " -normx = Scale so max absolute value = 1 (L_infinity norm)\n" " -polort p = Detrend with polynomials of order p before normalizing\n" " [DEFAULT = don't do this]\n" " * Use '-polort 0' to remove the mean, for example\n" " -L1fit = Detrend with L1 regression (L2 is the default)\n" " * This option is here just for the hell of it\n" "\n" "Notes:\n" "* Each voxel is processed separately\n" "* A voxel that is all zero will be unchanged (duh)\n" "* Output dataset is in float format, no matter what the input format\n" "* This program is for producing regressors to use in 3dTfitter\n" "* Also see programs 1dnorm and 3dcalc\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /* bureaucracy */ mainENTRY("3dTnorm main"); machdep(); AFNI_logger("3dTnorm",argc,argv); PRINT_VERSION("3dTnorm"); AUTHOR("RW Cox"); /*--- scan command line for options ---*/ nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ /*-- prefix --*/ if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-prefix needs an argument!"); MCW_strncpy(prefix,argv[nopt],THD_MAX_PREFIX) ; if( !THD_filename_ok(prefix) ) ERROR_exit("%s is not a valid prefix!",prefix); nopt++ ; continue ; } if( strncmp(argv[nopt],"-norm",5) == 0 ){ if( argv[nopt][5] == '1' ) mode = 1 ; else if( argv[nopt][5] == 'x' ) mode = 666 ; else if( argv[nopt][5] == '2' ) mode = 2 ; else if( argv[nopt][5] == 'R' ) mode = 3 ; else ERROR_message("Don't understand option '%s'",argv[nopt]) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-polort") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-polort needs an argument!"); polort = (int)strtod(argv[nopt],NULL) ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-L1fit") == 0 ){ dmode = 1 ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-L2fit") == 0 ){ dmode = 2 ; nopt++ ; continue ; } /*-- Quien sabe'? --*/ ERROR_message("Unknown option: %s",argv[nopt]) ; suggest_best_prog_option(argv[0],argv[nopt]); exit(1); } /*----- read input dataset -----*/ if( nopt >= argc ) ERROR_exit(" No input dataset!?") ; old_dset = THD_open_dataset( argv[nopt] ) ; if( !ISVALID_DSET(old_dset) ) ERROR_exit("Can't open dataset %s",argv[nopt]); DSET_load(old_dset) ; if( !DSET_LOADED(old_dset) ) ERROR_exit("Can't load dataset %s",argv[nopt]) ; nvals = DSET_NVALS(old_dset) ; if( nvals < 2 || nvals <= polort ) ERROR_exit("Need at least %d time points, but have only %d", MAX(2,polort+1) , nvals ) ; nopt++ ; if( nopt < argc ) WARNING_message("Trailing inputs on command line ignored: %s ...",argv[nopt]) ; /*------------- ready to compute new dataset -----------*/ new_dset = MAKER_4D_to_typed_fbuc( old_dset , /* input dataset */ prefix , /* output prefix */ datum , /* output datum */ 0 , /* ignore count */ 0 , /* don't detrend */ nvals , /* number of briks in output */ NORM_tsfunc , /* timeseries processor */ NULL, /* data for tsfunc */ NULL, /* mask */ 0 /* Allow auto scaling of output */ ) ; if( new_dset != NULL ){ tross_Copy_History( old_dset , new_dset ) ; tross_Make_History( "3dTnorm" , argc,argv , new_dset ) ; EDIT_dset_items( new_dset , ADN_ntt , nvals , ADN_ttorg , DSET_TIMEORIGIN(old_dset) , ADN_ttdel , DSET_TR(old_dset) , ADN_tunits , UNITS_SEC_TYPE , NULL ) ; DSET_write(new_dset) ; WROTE_DSET(new_dset) ; } else { ERROR_exit("Unable to compute output dataset for some unknowable reason :-(") ; } exit(0) ; } /********************************************************************** Function that does the real work ***********************************************************************/ static void NORM_tsfunc( double tzero, double tdelta , int npts, float ts[], double ts_mean, double ts_slope, void *ud, int nbriks, float *val ) { int ii , nval ; /** is this a "notification"? **/ if( val == NULL ){ #if 0 if( npts > 0 ){ /* the "start notification" */ } else { /* the "end notification" */ } #endif return ; } /** do the work **/ nval = MIN(nbriks,npts) ; memcpy( val , ts , sizeof(float)*nval ) ; if( polort >= 0 ){ switch( dmode ){ default: case 2: THD_generic_detrend_LSQ( nval,val, polort, 0,NULL,NULL ); break; case 1: THD_generic_detrend_L1 ( nval,val, polort, 0,NULL,NULL ); break; } } switch( mode ){ default: case 2: THD_normalize( nval,val ) ; break ; case 1: THD_normL1 ( nval,val ) ; break ; case 3: THD_normRMS ( nval,val ) ; break ; case 666: THD_normmax ( nval,val ) ; break ; } return ; }