/* * for each input dataset name * open (check dims, etc.) * dilate (zeropad, make binary, dilate, unpad, apply) * fill list of bytemask datasets * * also, count total volumes */ int process_input_dsets(param_t * params) { THD_3dim_dataset * dset, * dfirst=NULL; int iset, nxyz; ENTRY("process_input_dsets"); if( !params ) ERROR_exit("NULL inputs to PID"); if( params->ndsets <= 0 ) { ERROR_message("process_input_dsets: no input datasets"); RETURN(1); } /* allocate space for dsets array */ params->dsets = (THD_3dim_dataset **)malloc(params->ndsets* sizeof(THD_3dim_dataset*)); if( !params->dsets ) ERROR_exit("failed to allocate dset pointers"); if( params->verb ) INFO_message("processing %d input datasets...", params->ndsets); /* warn user of dilations */ if(params->verb && params->ndsets) { int pad = needed_padding(¶ms->IND); INFO_message("padding all datasets by %d (for dilations)", pad); } /* process the datasets */ nxyz = 0; for( iset=0; iset < params->ndsets; iset++ ) { /* open and verify dataset */ dset = THD_open_dataset(params->inputs[iset]); if( !dset ) ERROR_exit("failed to open mask dataset '%s'", params->inputs[iset]); DSET_load(dset); CHECK_LOAD_ERROR(dset); if( params->verb>1 ) INFO_message("loaded dset %s, with %d volumes", DSET_PREFIX(dset), DSET_NVALS(dset)); if( nxyz == 0 ) { /* make an empty copy of the first dataset */ nxyz = DSET_NVOX(dset); dfirst = EDIT_empty_copy(dset); } /* check for consistency in voxels and grid */ if( DSET_NVOX(dset) != nxyz ) ERROR_exit("nvoxel mis-match"); if( ! EQUIV_GRIDS(dset, dfirst) ) WARNING_message("grid from dset %s does not match that of dset %s", DSET_PREFIX(dset), DSET_PREFIX(dfirst)); /* apply dilations to all volumes, returning bytemask datasets */ params->dsets[iset] = apply_dilations(dset, ¶ms->IND,1,params->verb); if( ! params->dsets[iset] ) RETURN(1); } DSET_delete(dfirst); /* and nuke */ RETURN(0); }
void get_options ( int argc, /* number of input arguments */ char ** argv /* array of input arguments */ ) { int nopt = 1; /* input option argument counter */ int ival, index; /* integer input */ float fval; /* float input */ char message[MAX_STRING_LENGTH]; /* error message */ /*----- does user request help menu? -----*/ if (argc < 2 || strncmp(argv[1], "-help", 5) == 0) display_help_menu(); /*----- main loop over input options -----*/ while (nopt < argc ) { /*----- -anat filename -----*/ if (strncmp(argv[nopt], "-anat", 5) == 0) { nopt++; if (nopt >= argc) estPDF_error ("need argument after -anat "); anat_filename = malloc (sizeof(char) * MAX_STRING_LENGTH); MTEST (anat_filename); strcpy (anat_filename, argv[nopt]); anat = THD_open_one_dataset (anat_filename); if (!ISVALID_3DIM_DATASET (anat)) { sprintf (message, "Can't open dataset: %s\n", anat_filename); estPDF_error (message); } DSET_load(anat); CHECK_LOAD_ERROR(anat); nopt++; continue; } /*----- unknown command -----*/ sprintf(message,"Unrecognized command line option: %s\n", argv[nopt]); estPDF_error (message); } }
int fill_mask(options_t * opts) { THD_3dim_dataset * mset; int nvox; ENTRY("fill_mask"); if( opts->automask ) { if( opts->verb ) INFO_message("creating automask..."); opts->mask = THD_automask(opts->inset); if( ! opts->mask ) { ERROR_message("failed to apply -automask"); RETURN(1); } RETURN(0); } if( opts->mask_name ) { if( opts->verb ) INFO_message("reading mask dset from %s...", opts->mask_name); mset = THD_open_dataset( opts->mask_name ); if( ! mset ) ERROR_exit("cannot open mask dset '%s'", opts->mask_name); nvox = DSET_NVOX(opts->inset); if( DSET_NVOX(mset) != nvox ) { ERROR_message("mask does not have the same voxel count as input"); RETURN(1); } /* fill mask array and mask_nxyz, remove mask dset */ DSET_load(mset); CHECK_LOAD_ERROR(mset); opts->mask = THD_makemask(mset, 0, 1, 0); DSET_delete(mset); if( ! opts->mask ) { ERROR_message("cannot make mask from '%s'", opts->mask_name); RETURN(1); } if( opts->verb > 1 ) INFO_message("have mask with %d voxels", nvox); } RETURN(0); }
static inline ImageObject * _imlib2_open(char *filename, int use_cache) { Imlib_Image *image; Imlib_Load_Error error = IMLIB_LOAD_ERROR_NONE; if (use_cache){ image = imlib_load_image_with_error_return(filename, &error); }else{ image = imlib_load_image_immediately_without_cache(filename); } CHECK_LOAD_ERROR(error); #ifdef DEVELOP imlib_context_set_image(image); DEBUG("width %d", imlib_image_get_width()); DEBUG("height %d", imlib_image_get_height()); #endif return ImageObject_New(image); }
static inline PyObject * ImageObject_save(PyObject* self, PyObject *args) { char *filename, *ext; Imlib_Load_Error error = IMLIB_LOAD_ERROR_NONE; if (!PyArg_ParseTuple(args, "ss:save", &filename, &ext)){ return NULL; } imlib_context_set_image(((ImageObject *)self)->image); imlib_image_set_format(ext); imlib_save_image_with_error_return(filename, &error); CHECK_LOAD_ERROR(error); Py_RETURN_NONE; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *dset ; char *prefix ; int narg=1 ; #ifndef DONT_ALLOW_MINC WARNING_message("This program (3dMINCtoAFNI) is old, obsolete, and not maintained!") ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dMINCtoAFNI [-prefix ppp] dataset.mnc\n" "Reads in a MINC formatted file and writes it out as an\n" "AFNI dataset file pair with the given prefix. If the\n" "prefix option isn't used, the input filename will be\n" "used, after the '.mnc' is chopped off.\n" "\n" "NOTES:\n" "* Setting environment variable AFNI_MINC_FLOATIZE to Yes\n" " will cause MINC datasets to be converted to floats on\n" " input. Otherwise, they will be kept in their 'native'\n" " data type if possible, which may cause problems with\n" " scaling on occasion.\n" "* The TR recorded in MINC files is often incorrect. You may\n" " need to fix this (or other parameters) using 3drefit.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } if( strcmp(argv[narg],"-prefix") == 0 ){ prefix = argv[++narg] ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"** Prefix string is illegal: %s\n",prefix) ; exit(1) ; } narg++ ; } else { int ii ; prefix = strdup(argv[narg]) ; ii = strlen(prefix) ; if( ii > 5 ) prefix[ii-4] = '\0' ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"** Prefix string is illegal: %s\n",prefix) ; exit(1) ; } } dset = THD_open_minc( argv[narg] ) ; if( dset == NULL ){ fprintf(stderr,"** Can't open dataset %s\n",argv[narg]) ; exit(1) ; } if( !DSET_IS_MINC(dset) ){ fprintf(stderr,"** Not a MINC dataset: %s\n",argv[narg]) ; exit(1) ; } DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; EDIT_dset_items( dset , ADN_prefix,prefix , ADN_none ) ; dset->idcode = MCW_new_idcode() ; dset->dblk->diskptr->storage_mode = STORAGE_BY_BRICK ; tross_Make_History( "3dMINCtoAFNI" , argc,argv , dset ) ; DSET_write(dset) ; fprintf(stderr,"++ Wrote dataset %s\n",DSET_BRIKNAME(dset)) ; exit(0) ; #else ERROR_exit("3dMINCtoAFNI is no longer compiled") ; #endif }
int main( int argc , char *argv[] ) { THD_3dim_dataset *dset_in=NULL , *dset_out ; int Lxx=-1 , Lyy=-1 , Lzz=-1 , Mode=FFT_ABS , Sign=-1 , do_alt=0 ; char *prefix = "FFTout" ; int iarg ; MRI_IMAGE *inim , *outim ; float fac ; int nx,ny,nz ; THD_ivec3 iv ; if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dFFT [options] dataset\n" "\n" "* Does the FFT of the input dataset in 3 directions (x,y,z) and\n" " produces the output dataset.\n" "\n" "* Why you'd want to do this is an interesting question.\n" "\n" "* Program 3dcalc can operate on complex-valued datasets, but\n" " only on one component at a time (cf. the '-cx2r' option).\n" "\n" "* Most other AFNI programs can only operate on real-valued\n" " datasets.\n" "\n" "* You could use 3dcalc (twice) to split a complex-valued dataset\n" " into two real-valued datasets, do your will on those with other\n" " AFNI programs, then merge the results back into a complex-valued\n" " dataset with 3dTwotoComplex.\n" "\n" "Options\n" "=======\n" " -abs = Outputs the magnitude of the FFT [default]\n" " -phase = Outputs the phase of the FFT (-PI..PI == no unwrapping!)\n" " -complex = Outputs the complex-valued FFT\n" " -inverse = Does the inverse FFT instead of the forward FFT\n" "\n" " -Lx xx = Use FFT of length 'xx' in the x-direction\n" " -Ly yy = Use FFT of length 'yy' in the y-direction\n" " -Lz zz = Use FFT of length 'zz' in the z-direction\n" " * Set a length to 0 to skip the FFT in that direction\n" "\n" " -altIN = Alternate signs of input data before FFT, to bring\n" " zero frequency from edge of FFT-space to center of grid\n" " for cosmetic purposes.\n" " -altOUT = Alternate signs of output data after FFT. If you\n" " use '-altI' on the forward transform, then you should\n" " use '-altO' an the inverse transform, to get the\n" " signs of the recovered image correct.\n" " **N.B.: You cannot use '-altIN' and '-altOUT' in the same run!\n" "\n" " -input dd = Read the input dataset from 'dd', instead of\n" " from the last argument on the command line.\n" "\n" " -prefix pp = Use 'pp' for the output dataset prefix.\n" "\n" "Notes\n" "=====\n" " * In the present avatar, only 1 sub-brick will be processed.\n" "\n" " * The program can only do FFT lengths that are factorable\n" " into a product of powers of 2, 3, and 5, and are even.\n" " + The largest power of 3 that is allowed is 3^3 = 27.\n" " + The largest power of 5 that is allowed is 5^3 = 125.\n" " + e.g., FFT of length 3*5*8=120 is possible.\n" " + e.g., FFT of length 4*31 =124 is not possible.\n" "\n" " * The 'x', 'y', and 'z' axes here refer to the order the\n" " data is stored, not DICOM coordinates; cf. 3dinfo.\n" "\n" " * If you force (via '-Lx' etc.) an FFT length that is not\n" " allowed, the program will stop with an error message.\n" "\n" " * If you force an FFT length that is shorter than an dataset\n" " axis dimension, the program will stop with an error message.\n" "\n" " * If you don't force an FFT length along a particular axis,\n" " the program will pick the smallest legal value that is\n" " greater than or equal to the corresponding dataset dimension.\n" " + e.g., 124 would be increased to 128.\n" "\n" " * If an FFT length is longer than an axis length, then the\n" " input data in that direction is zero-padded at the end.\n" "\n" " * For -abs and -phase, the output dataset is in float format.\n" "\n" " * If you do the forward and inverse FFT, then you should get back\n" " the original dataset, except for roundoff error and except that\n" " the new dataset axis dimensions may be longer than the original.\n" "\n" " * Forward FFT = sum_{k=0..N-1} [ exp(-2*PI*i*k/N) * data(k) ]\n" "\n" " * Inverse FFT = sum_{k=0..N-1} [ exp(+2*PI*i*k/N) * data(k) ] / N\n" "\n" " * Started a long time ago, but only finished in Aug 2009 at the\n" " request of John Butman, because he asked so nicely. (Now pay up!)\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } PRINT_VERSION("3dFFT") ; mainENTRY("3dFFT main") ; machdep() ; AUTHOR("RW Cox") ; AFNI_logger("3dFFT",argc,argv) ; /*--- scan args ---*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncasecmp(argv[iarg],"-altI",5) == 0 ){ do_alt = 1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-altOUT",5) == 0 ){ do_alt = -1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-inverse",4) == 0 ){ Sign = +1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-abs",4) == 0 ){ Mode = FFT_ABS ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-phase",4) == 0 ){ Mode = FFT_PHASE ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-complex",4) == 0 ){ Mode = FFT_COMPLEX ; iarg++ ; continue ; } if( strlen(argv[iarg]) == 3 && strncmp(argv[iarg],"-L",2) == 0 ){ int lll=-1 , mmm ; char *ept ; iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after option %s",argv[iarg-1]) ; lll = strtol( argv[iarg] , &ept , 10 ) ; if( *ept != '\0' ) ERROR_exit("bad argument after option %s",argv[iarg-1]) ; if( lll > 0 && (mmm = csfft_nextup_even(lll)) != lll ) ERROR_exit( "'%s %d' is not a legal FFT length here: next largest legal value = %d" , argv[iarg-1] , lll , mmm ) ; switch( argv[iarg-1][2] ){ case 'x': case 'X': Lxx = lll ; break ; case 'y': case 'Y': Lyy = lll ; break ; case 'z': case 'Z': Lzz = lll ; break ; default: ERROR_exit("unknown option '%s'",argv[iarg-1]) ; } iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-prefix",4) == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after %s\n",argv[iarg-1]) ; prefix = strdup( argv[iarg] ) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad argument after %s\n",argv[iarg-1]) ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-input",4) == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after %s\n",argv[iarg-1]) ; dset_in = THD_open_dataset(argv[iarg]); CHECK_OPEN_ERROR(dset_in,argv[iarg]); iarg++ ; continue ; } ERROR_exit("unknown option '%s'\n",argv[iarg]) ; } /* check for simple errors */ if( Lxx == 0 && Lyy == 0 && Lzz == 0 ) ERROR_exit("-Lx, -Ly, -Lz all given as zero?!") ; /* open input dataset */ if( dset_in == NULL ){ if( iarg >= argc ) ERROR_exit("no input dataset on command line?!\n") ; dset_in = THD_open_dataset(argv[iarg]); CHECK_OPEN_ERROR(dset_in,argv[iarg]); } nx = DSET_NX(dset_in) ; ny = DSET_NY(dset_in) ; nz = DSET_NZ(dset_in) ; if( DSET_NVALS(dset_in) > 1 ) WARNING_message("only 3dFFT-ing sub-brick #0 of input dataset") ; /* establish actual FFT lengths now (0 ==> no FFT) */ if( nx == 1 ) Lxx = 0 ; /* can't FFT if dataset is shrimpy! */ if( ny == 1 ) Lyy = 0 ; if( nz == 1 ) Lzz = 0 ; if( Lxx < 0 ) Lxx = csfft_nextup_even(nx) ; /* get FFT length from */ if( Lyy < 0 ) Lyy = csfft_nextup_even(ny) ; /* dataset dimensions */ if( Lzz < 0 ) Lzz = csfft_nextup_even(nz) ; INFO_message("x-axis length=%d ; FFT length=%d %s",nx,Lxx,(Lxx==0)?"==> none":"\0") ; INFO_message("y-axis length=%d ; FFT length=%d %s",ny,Lyy,(Lyy==0)?"==> none":"\0") ; INFO_message("z-axis length=%d ; FFT length=%d %s",nz,Lzz,(Lzz==0)?"==> none":"\0") ; if( Lxx > 0 && Lxx < nx ) ERROR_exit("x-axis FFT length too short for data!") ; if( Lyy > 0 && Lyy < ny ) ERROR_exit("y-axis FFT length too short for data!") ; if( Lzz > 0 && Lzz < nz ) ERROR_exit("z-axis FFT length too short for data!") ; /* extract sub-brick #0 */ DSET_load(dset_in) ; CHECK_LOAD_ERROR(dset_in) ; inim = mri_to_complex( DSET_BRICK(dset_in,0) ) ; /* convert input to complex */ fac = DSET_BRICK_FACTOR(dset_in,0) ; if( fac > 0.0f && fac != 1.0f ){ /* scale it if needed */ int ii , nvox = nx*ny*nz ; complex *car = MRI_COMPLEX_PTR(inim) ; for( ii=0 ; ii < nvox ; ii++ ){ car[ii].r *= fac ; car[ii].i *= fac ; } } DSET_unload(dset_in) ; /* input data is all copied now */ /* FFT to get output image */ csfft_scale_inverse(1) ; /* scale by 1/N for inverse FFTs */ outim = mri_fft_3D( Sign , inim , Lxx,Lyy,Lzz , do_alt ) ; mri_free(inim) ; /* post-process output? */ switch( Mode ){ case FFT_ABS:{ MRI_IMAGE *qim = mri_complex_abs(outim) ; mri_free(outim) ; outim = qim ; } break ; case FFT_PHASE:{ MRI_IMAGE *qim = mri_complex_phase(outim) ; mri_free(outim) ; outim = qim ; } break ; } /* create and write output dataset */ dset_out = EDIT_empty_copy( dset_in ) ; tross_Copy_History( dset_in , dset_out ) ; tross_Make_History( "3dFFT" , argc,argv , dset_out ) ; LOAD_IVEC3( iv , outim->nx , outim->ny , outim->nz ) ; EDIT_dset_items( dset_out , ADN_prefix , prefix , ADN_nvals , 1 , ADN_ntt , 0 , ADN_nxyz , iv , /* change dimensions, possibly */ ADN_none ) ; EDIT_BRICK_FACTOR( dset_out , 0 , 0.0 ) ; EDIT_substitute_brick( dset_out , 0 , outim->kind , mri_data_pointer(outim) ) ; DSET_write(dset_out) ; WROTE_DSET(dset_out) ; DSET_unload(dset_out) ; exit(0) ; }
/* ---------------------------------------------------------------------- * fill the options_t struct * return 1 on (acceptable) termination * 0 on continue * -1 on error */ int process_opts(options_t * opts, int argc, char * argv[] ) { int ac; ENTRY("process_opts"); memset(opts, 0, sizeof(options_t)); /* init everything to 0 */ opts->method = T21_METH_UNDEF; /* be explicit, required option */ opts->verb = 1; ac = 1; while( ac < argc ) { /* check for terminal options */ if( ! strcmp(argv[ac],"-help") || ! strcmp(argv[ac],"-h") ) { show_help(); RETURN(1); } else if( strcmp(argv[ac],"-hist") == 0 ) { int c, len = sizeof(g_history)/sizeof(char *); for( c = 0; c < len; c++) fputs(g_history[c], stdout); putchar('\n'); RETURN(1); } else if( strcmp(argv[ac],"-ver") == 0 ) { puts(g_version); RETURN(1); } /* the remaining options are alphabetical */ else if( strcmp(argv[ac],"-automask") == 0 ) { opts->automask = 1; ac++; continue; } else if( ! strcmp(argv[ac],"-input") || ! strcmp(argv[ac], "-inset") ) { if( opts->inset ) ERROR_exit("-input already applied"); if( ++ac >= argc ) ERROR_exit("need argument after '-input'"); opts->inset = THD_open_dataset( argv[ac] ); opts->nt = DSET_NVALS(opts->inset); if( ! opts->inset ) ERROR_exit("cannot open dset '%s'", argv[ac]); DSET_load(opts->inset); CHECK_LOAD_ERROR(opts->inset); ac++; continue; } else if( ! strcmp(argv[ac],"-mask") ) { if( opts->mask_name ) ERROR_exit("-mask already applied"); if( ++ac >= argc ) ERROR_exit("need argument after '-mask'"); opts->mask_name = argv[ac]; ac++; continue; } else if( ! strcmp(argv[ac],"-method") ) { if( ++ac >= argc ) ERROR_exit("need argument after '-method'"); opts->method = meth_name_to_index(argv[ac]); if( opts->method == T21_METH_UNDEF ) ERROR_exit("illegal -method '%s'", argv[ac]); ac++; continue; } else if( strcmp(argv[ac],"-prefix") == 0 ) { if( ++ac >= argc ) ERROR_exit("need argument after '-prefix'"); opts->prefix = argv[ac]; if( !THD_filename_ok(opts->prefix) ) ERROR_exit("Illegal name after '-prefix'"); ac++; continue; } else if( strcmp(argv[ac],"-verb") == 0 ) { if( ++ac >= argc ) ERROR_exit("need argument after '-verb'"); opts->verb = atoi(argv[ac]); ac++; continue; } ERROR_message("** unknown option '%s'\n",argv[ac]); RETURN(-1); } /* require data and method */ if( !opts->inset ) ERROR_exit("missing -input dataset"); if( opts->method == T21_METH_UNDEF ) ERROR_exit("missing -method option"); if( opts->verb > 1 ) { INFO_message("input dataset loaded\n"); INFO_message("will apply method %s", meth_index_to_name(opts->method)); } if( opts->automask && opts->mask_name ) ERROR_exit("cannot apply both -mask and -mset"); if( opts->automask || opts->mask_name ) { if( fill_mask(opts) ) RETURN(1); } RETURN(0); }
int main( int argc , char *argv[] ) { THD_3dim_dataset *yset=NULL , *aset=NULL , *mset=NULL , *wset=NULL ; MRI_IMAGE *fim=NULL, *qim,*tim, *pfim=NULL , *vim , *wim=NULL ; float *flar , *qar,*tar, *par=NULL , *var , *war=NULL ; MRI_IMARR *fimar=NULL ; MRI_IMAGE *aim , *yim ; float *aar , *yar ; int nt=0 , nxyz=0 , nvox=0 , nparam=0 , nqbase , polort=0 , ii,jj,kk,bb ; byte *mask=NULL ; int nmask=0 , iarg ; char *fname_out="-" ; /** equiv to stdout **/ float alpha=0.0f ; int nfir =0 ; float firwt[5]={0.09f,0.25f,0.32f,0.25f,0.09f} ; int nmed =0 ; int nwt =0 ; #define METHOD_C 3 #define METHOD_K 11 int method = METHOD_C ; /**--- help the pitiful user? ---**/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dInvFMRI [options]\n" "Program to compute stimulus time series, given a 3D+time dataset\n" "and an activation map (the inverse of the usual FMRI analysis problem).\n" "-------------------------------------------------------------------\n" "OPTIONS:\n" "\n" " -data yyy =\n" " *OR* = Defines input 3D+time dataset [a non-optional option].\n" " -input yyy =\n" "\n" " -map aaa = Defines activation map; 'aaa' should be a bucket dataset,\n" " each sub-brick of which defines the beta weight map for\n" " an unknown stimulus time series [also non-optional].\n" "\n" " -mapwt www = Defines a weighting factor to use for each element of\n" " the map. The dataset 'www' can have either 1 sub-brick,\n" " or the same number as in the -map dataset. In the\n" " first case, in each voxel, each sub-brick of the map\n" " gets the same weight in the least squares equations.\n" " [default: all weights are 1]\n" "\n" " -mask mmm = Defines a mask dataset, to restrict input voxels from\n" " -data and -map. [default: all voxels are used]\n" "\n" " -base fff = Each column of the 1D file 'fff' defines a baseline time\n" " series; these columns should be the same length as\n" " number of time points in 'yyy'. Multiple -base options\n" " can be given.\n" " -polort pp = Adds polynomials of order 'pp' to the baseline collection.\n" " The default baseline model is '-polort 0' (constant).\n" " To specify no baseline model at all, use '-polort -1'.\n" "\n" " -out vvv = Name of 1D output file will be 'vvv'.\n" " [default = '-', which is stdout; probably not good]\n" "\n" " -method M = Determines the method to use. 'M' is a single letter:\n" " -method C = least squares fit to data matrix Y [default]\n" " -method K = least squares fit to activation matrix A\n" "\n" " -alpha aa = Set the 'alpha' factor to 'aa'; alpha is used to penalize\n" " large values of the output vectors. Default is 0.\n" " A large-ish value for alpha would be 0.1.\n" "\n" " -fir5 = Smooth the results with a 5 point lowpass FIR filter.\n" " -median5 = Smooth the results with a 5 point median filter.\n" " [default: no smoothing; only 1 of these can be used]\n" "-------------------------------------------------------------------\n" "METHODS:\n" " Formulate the problem as\n" " Y = V A' + F C' + errors\n" " where Y = data matrix (N x M) [from -data]\n" " V = stimulus (N x p) [to -out]\n" " A = map matrix (M x p) [from -map]\n" " F = baseline matrix (N x q) [from -base and -polort]\n" " C = baseline weights (M x q) [not computed]\n" " N = time series length = length of -data file\n" " M = number of voxels in mask\n" " p = number of stimulus time series to estimate\n" " = number of parameters in -map file\n" " q = number of baseline parameters\n" " and ' = matrix transpose operator\n" " Next, define matrix Z (Y detrended relative to columns of F) by\n" " -1\n" " Z = [I - F(F'F) F'] Y\n" "-------------------------------------------------------------------\n" " The method C solution is given by\n" " -1\n" " V0 = Z A [A'A]\n" "\n" " This solution minimizes the sum of squares over the N*M elements\n" " of the matrix Y - V A' + F C' (N.B.: A' means A-transpose).\n" "-------------------------------------------------------------------\n" " The method K solution is given by\n" " -1 -1\n" " W = [Z Z'] Z A and then V = W [W'W]\n" "\n" " This solution minimizes the sum of squares of the difference between\n" " the A(V) predicted from V and the input A, where A(V) is given by\n" " -1\n" " A(V) = Z' V [V'V] = Z'W\n" "-------------------------------------------------------------------\n" " Technically, the solution is unidentfiable up to an arbitrary\n" " multiple of the columns of F (i.e., V = V0 + F G, where G is\n" " an arbitrary q x p matrix); the solution above is the solution\n" " that is orthogonal to the columns of F.\n" "\n" "-- RWCox - March 2006 - purely for experimental purposes!\n" ) ; printf("\n" "===================== EXAMPLE USAGE =====================================\n" "** Step 1: From a training dataset, generate activation map.\n" " The input dataset has 4 runs, each 108 time points long. 3dDeconvolve\n" " is used on the first 3 runs (time points 0..323) to generate the\n" " activation map. There are two visual stimuli (Complex and Simple).\n" "\n" " 3dDeconvolve -x1D xout_short_two.1D -input rall_vr+orig'[0..323]' \\\n" " -num_stimts 2 \\\n" " -stim_file 1 hrf_complex.1D -stim_label 1 Complex \\\n" " -stim_file 2 hrf_simple.1D -stim_label 2 Simple \\\n" " -concat '1D:0,108,216' \\\n" " -full_first -fout -tout \\\n" " -bucket func_ht2_short_two -cbucket cbuc_ht2_short_two\n" "\n" " N.B.: You may want to de-spike, smooth, and register the 3D+time\n" " dataset prior to the analysis (as usual). These steps are not\n" " shown here -- I'm presuming you know how to use AFNI already.\n" "\n" "** Step 2: Create a mask of highly activated voxels.\n" " The F statistic threshold is set to 30, corresponding to a voxel-wise\n" " p = 1e-12 = very significant. The mask is also lightly clustered, and\n" " restricted to brain voxels.\n" "\n" " 3dAutomask -prefix Amask rall_vr+orig\n" " 3dcalc -a 'func_ht2_short+orig[0]' -b Amask+orig -datum byte \\\n" " -nscale -expr 'step(a-30)*b' -prefix STmask300\n" " 3dmerge -dxyz=1 -1clust 1.1 5 -prefix STmask300c STmask300+orig\n" "\n" "** Step 3: Run 3dInvFMRI to estimate the stimulus functions in run #4.\n" " Run #4 is time points 324..431 of the 3D+time dataset (the -data\n" " input below). The -map input is the beta weights extracted from\n" " the -cbucket output of 3dDeconvolve.\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method K \\\n" " -out ii300K_short_two.1D\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method C \\\n" " -out ii300C_short_two.1D\n" "\n" "** Step 4: Plot the results, and get confused.\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel ComplexStim \\\n" " hrf_complex.1D'{324..432}' \\\n" " ii300K_short_two.1D'[0]' \\\n" " ii300C_short_two.1D'[0]'\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel SimpleStim \\\n" " hrf_simple.1D'{324..432}' \\\n" " ii300K_short_two.1D'[1]' \\\n" " ii300C_short_two.1D'[1]'\n" "\n" " N.B.: I've found that method K works better if MORE voxels are\n" " included in the mask (lower threshold) and method C if\n" " FEWER voxels are included. The above threshold gave 945\n" " voxels being used to determine the 2 output time series.\n" "=========================================================================\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /**--- bureaucracy ---**/ mainENTRY("3dInvFMRI main"); machdep(); PRINT_VERSION("3dInvFMRI"); AUTHOR("Zhark"); AFNI_logger("3dInvFMRI",argc,argv) ; /**--- scan command line ---**/ iarg = 1 ; while( iarg < argc ){ if( strcmp(argv[iarg],"-method") == 0 ){ switch( argv[++iarg][0] ){ default: WARNING_message("Ignoring illegal -method '%s'",argv[iarg]) ; break ; case 'C': method = METHOD_C ; break ; case 'K': method = METHOD_K ; break ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-fir5") == 0 ){ if( nmed > 0 ) WARNING_message("Ignoring -fir5 in favor of -median5") ; else nfir = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-median5") == 0 ){ if( nfir > 0 ) WARNING_message("Ignoring -median5 in favor of -fir5") ; else nmed = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-alpha") == 0 ){ alpha = (float)strtod(argv[++iarg],NULL) ; if( alpha <= 0.0f ){ alpha = 0.0f ; WARNING_message("-alpha '%s' ignored!",argv[iarg]) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-data") == 0 || strcmp(argv[iarg],"-input") == 0 ){ if( yset != NULL ) ERROR_exit("Can't input 2 3D+time datasets") ; yset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(yset,argv[iarg]) ; nt = DSET_NVALS(yset) ; if( nt < 2 ) ERROR_exit("Only 1 sub-brick in dataset %s",argv[iarg]) ; nxyz = DSET_NVOX(yset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-map") == 0 ){ if( aset != NULL ) ERROR_exit("Can't input 2 -map datasets") ; aset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(aset,argv[iarg]) ; nparam = DSET_NVALS(aset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mapwt") == 0 ){ if( wset != NULL ) ERROR_exit("Can't input 2 -mapwt datasets") ; wset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(wset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ if( mset != NULL ) ERROR_exit("Can't input 2 -mask datasets") ; mset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *cpt ; polort = (int)strtod(argv[++iarg],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-out") == 0 ){ fname_out = strdup(argv[++iarg]) ; if( !THD_filename_ok(fname_out) ) ERROR_exit("Bad -out filename '%s'",fname_out) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-base") == 0 ){ if( fimar == NULL ) INIT_IMARR(fimar) ; qim = mri_read_1D( argv[++iarg] ) ; if( qim == NULL ) ERROR_exit("Can't read 1D file %s",argv[iarg]) ; ADDTO_IMARR(fimar,qim) ; iarg++ ; continue ; } ERROR_exit("Unrecognized option '%s'",argv[iarg]) ; } /**--- finish up processing options ---**/ if( yset == NULL ) ERROR_exit("No input 3D+time dataset?!") ; if( aset == NULL ) ERROR_exit("No input FMRI -map dataset?!") ; if( DSET_NVOX(aset) != nxyz ) ERROR_exit("Grid mismatch between -data and -map") ; INFO_message("Loading dataset for Y") ; DSET_load(yset); CHECK_LOAD_ERROR(yset) ; INFO_message("Loading dataset for A") ; DSET_load(aset); CHECK_LOAD_ERROR(aset) ; if( wset != NULL ){ if( DSET_NVOX(wset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mapwt") ; nwt = DSET_NVALS(wset) ; if( nwt > 1 && nwt != nparam ) ERROR_exit("Wrong number of values=%d in -mapwt; should be 1 or %d", nwt , nparam ) ; INFO_message("Loading dataset for mapwt") ; DSET_load(wset); CHECK_LOAD_ERROR(wset) ; } if( mset != NULL ){ if( DSET_NVOX(mset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mask") ; INFO_message("Loading dataset for mask") ; DSET_load(mset); CHECK_LOAD_ERROR(mset) ; mask = THD_makemask( mset , 0 , 1.0f,-1.0f ); DSET_delete(mset); nmask = THD_countmask( nxyz , mask ) ; if( nmask < 3 ){ WARNING_message("Mask has %d voxels -- ignoring!",nmask) ; free(mask) ; mask = NULL ; nmask = 0 ; } } nvox = (nmask > 0) ? nmask : nxyz ; INFO_message("N = time series length = %d",nt ) ; INFO_message("M = number of voxels = %d",nvox ) ; INFO_message("p = number of params = %d",nparam) ; /**--- set up baseline funcs in one array ---*/ nqbase = (polort >= 0 ) ? polort+1 : 0 ; if( fimar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; if( qim != NULL && qim->nx != nt ) WARNING_message("-base #%d length=%d; data length=%d",kk+1,qim->nx,nt) ; nqbase += qim->ny ; } } INFO_message("q = number of baselines = %d",nqbase) ; #undef F #define F(i,j) flar[(i)+(j)*nt] /* nt X nqbase */ if( nqbase > 0 ){ fim = mri_new( nt , nqbase , MRI_float ) ; /* F matrix */ flar = MRI_FLOAT_PTR(fim) ; bb = 0 ; if( polort >= 0 ){ /** load polynomial baseline **/ double a = 2.0/(nt-1.0) ; for( jj=0 ; jj <= polort ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) = (float)Plegendre( a*ii-1.0 , jj ) ; } bb = polort+1 ; } #undef Q #define Q(i,j) qar[(i)+(j)*qim->nx] /* qim->nx X qim->ny */ if( fimar != NULL ){ /** load -base baseline columns **/ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; qar = MRI_FLOAT_PTR(qim) ; for( jj=0 ; jj < qim->ny ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,bb+jj) = (ii < qim->nx) ? Q(ii,jj) : 0.0f ; } bb += qim->ny ; } DESTROY_IMARR(fimar) ; fimar=NULL ; } /* remove mean from each column after first? */ if( polort >= 0 && nqbase > 1 ){ float sum ; for( jj=1 ; jj < nqbase ; jj++ ){ sum = 0.0f ; for( ii=0 ; ii < nt ; ii++ ) sum += F(ii,jj) ; sum /= nt ; for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) -= sum ; } } /* compute pseudo-inverse of baseline matrix, so we can project it out from the data time series */ /* -1 */ /* (F'F) F' matrix */ INFO_message("Computing pseudo-inverse of baseline matrix F") ; pfim = mri_matrix_psinv(fim,NULL,0.0f) ; par = MRI_FLOAT_PTR(pfim) ; #undef P #define P(i,j) par[(i)+(j)*nqbase] /* nqbase X nt */ #if 0 qim = mri_matrix_transpose(pfim) ; /** save to disk? **/ mri_write_1D( "Fpsinv.1D" , qim ) ; mri_free(qim) ; #endif } /**--- set up map image into aim/aar = A matrix ---**/ #undef GOOD #define GOOD(i) (mask==NULL || mask[i]) #undef A #define A(i,j) aar[(i)+(j)*nvox] /* nvox X nparam */ INFO_message("Loading map matrix A") ; aim = mri_new( nvox , nparam , MRI_float ); aar = MRI_FLOAT_PTR(aim); for( jj=0 ; jj < nparam ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ A(kk,jj) = THD_get_voxel(aset,ii,jj); kk++; } }} DSET_unload(aset) ; /**--- set up map weight into wim/war ---**/ #undef WT #define WT(i,j) war[(i)+(j)*nvox] /* nvox X nparam */ if( wset != NULL ){ int numneg=0 , numpos=0 ; float fac ; INFO_message("Loading map weight matrix") ; wim = mri_new( nvox , nwt , MRI_float ) ; war = MRI_FLOAT_PTR(wim) ; for( jj=0 ; jj < nwt ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ WT(kk,jj) = THD_get_voxel(wset,ii,jj); if( WT(kk,jj) > 0.0f ){ numpos++; WT(kk,jj) = sqrt(WT(kk,jj)); } else if( WT(kk,jj) < 0.0f ){ numneg++; WT(kk,jj) = 0.0f; } kk++; } }} DSET_unload(wset) ; if( numpos <= nparam ) WARNING_message("Only %d positive weights found in -wtmap!",numpos) ; if( numneg > 0 ) WARNING_message("%d negative weights found in -wtmap!",numneg) ; for( jj=0 ; jj < nwt ; jj++ ){ fac = 0.0f ; for( kk=0 ; kk < nvox ; kk++ ) if( WT(kk,jj) > fac ) fac = WT(kk,jj) ; if( fac > 0.0f ){ fac = 1.0f / fac ; for( kk=0 ; kk < nvox ; kk++ ) WT(kk,jj) *= fac ; } } } /**--- set up data image into yim/yar = Y matrix ---**/ #undef Y #define Y(i,j) yar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Loading data matrix Y") ; yim = mri_new( nt , nvox , MRI_float ); yar = MRI_FLOAT_PTR(yim); for( ii=0 ; ii < nt ; ii++ ){ for( jj=kk=0 ; jj < nxyz ; jj++ ){ if( GOOD(jj) ){ Y(ii,kk) = THD_get_voxel(yset,jj,ii); kk++; } }} DSET_unload(yset) ; /**--- project baseline out of data image = Z matrix ---**/ if( pfim != NULL ){ #undef T #define T(i,j) tar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Projecting baseline out of Y") ; qim = mri_matrix_mult( pfim , yim ) ; /* nqbase X nvox */ tim = mri_matrix_mult( fim , qim ) ; /* nt X nvox */ tar = MRI_FLOAT_PTR(tim) ; /* Y projected onto baseline */ for( jj=0 ; jj < nvox ; jj++ ) for( ii=0 ; ii < nt ; ii++ ) Y(ii,jj) -= T(ii,jj) ; mri_free(tim); mri_free(qim); mri_free(pfim); mri_free(fim); } /***** At this point: matrix A is in aim, matrix Z is in yim. Solve for V into vim, using the chosen method *****/ switch( method ){ default: ERROR_exit("Illegal method code! WTF?") ; /* Huh? */ /*.....................................................................*/ case METHOD_C: /**--- compute pseudo-inverse of A map ---**/ INFO_message("Method C: Computing pseudo-inverse of A") ; if( wim != NULL ) WARNING_message("Ignoring -mapwt dataset") ; pfim = mri_matrix_psinv(aim,NULL,alpha) ; /* nparam X nvox */ if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; mri_free(aim) ; /**--- and apply to data to get results ---*/ INFO_message("Computing result V") ; vim = mri_matrix_multranB( yim , pfim ) ; /* nt x nparam */ mri_free(pfim) ; mri_free(yim) ; break ; /*.....................................................................*/ case METHOD_K: /**--- compute pseudo-inverse of transposed Z ---*/ INFO_message("Method K: Computing pseudo-inverse of Z'") ; if( nwt > 1 ){ WARNING_message("Ignoring -mapwt dataset: more than 1 sub-brick") ; nwt = 0 ; mri_free(wim) ; wim = NULL ; war = NULL ; } if( nwt == 1 ){ float fac ; for( kk=0 ; kk < nvox ; kk++ ){ fac = war[kk] ; for( ii=0 ; ii < nt ; ii++ ) Y(ii,kk) *= fac ; for( ii=0 ; ii < nparam ; ii++ ) A(kk,ii) *= fac ; } } tim = mri_matrix_transpose(yim) ; mri_free(yim) ; pfim = mri_matrix_psinv(tim,NULL,alpha) ; mri_free(tim) ; if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; INFO_message("Computing W") ; tim = mri_matrix_mult( pfim , aim ) ; mri_free(aim) ; mri_free(pfim) ; INFO_message("Computing result V") ; pfim = mri_matrix_psinv(tim,NULL,0.0f) ; mri_free(tim) ; vim = mri_matrix_transpose(pfim) ; mri_free(pfim); break ; } /* end of switch on method */ if( wim != NULL ) mri_free(wim) ; /**--- smooth? ---**/ if( nfir > 0 && vim->nx > nfir ){ INFO_message("FIR-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) linear_filter_reflect( nfir,firwt , vim->nx , var + (jj*vim->nx) ) ; } if( nmed > 0 && vim->nx > nmed ){ INFO_message("Median-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) median5_filter_reflect( vim->nx , var + (jj*vim->nx) ) ; } /**--- write results ---**/ INFO_message("Writing result to '%s'",fname_out) ; mri_write_1D( fname_out , vim ) ; exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *xset , *cset, *mset=NULL ; int nopt=1 , method=PEARSON , do_autoclip=0 ; int nvox , nvals , ii, jj, kout, kin, polort=1 ; int ix1,jy1,kz1, ix2, jy2, kz2 ; char *prefix = "degree_centrality" ; byte *mask=NULL; int nmask , abuc=1 ; int all_source=0; /* output all source voxels 25 Jun 2010 [rickr] */ char str[32] , *cpt ; int *imap = NULL ; MRI_vectim *xvectim ; float (*corfun)(int,float *,float*) = NULL ; /* djc - add 1d file output for similarity matrix */ FILE *fout1D=NULL; /* CC - we will have two subbricks: binary and weighted centrality */ int nsubbriks = 2; int subbrik = 0; float * bodset; float * wodset; int nb_ctr = 0; /* CC - added flags for thresholding correlations */ double thresh = 0.0; double othresh = 0.0; int dothresh = 0; double sparsity = 0.0; int dosparsity = 0; /* variables for calculating degree centrality */ long * binaryDC = NULL; double * weightedDC = NULL; /* variables for histogram */ hist_node_head* histogram=NULL; hist_node* hptr=NULL; hist_node* pptr=NULL; int bottom_node_idx = 0; int totNumCor = 0; long totPosCor = 0; int ngoal = 0; int nretain = 0; float binwidth = 0.0; int nhistnodes = 50; /*----*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dDegreeCentrality [options] dset\n" " Computes voxelwise weighted and binary degree centrality and\n" " stores the result in a new 3D bucket dataset as floats to\n" " preserve their values. Degree centrality reflects the strength and\n" " extent of the correlation of a voxel with every other voxel in\n" " the brain.\n\n" " Conceptually the process involves: \n" " 1. Calculating the correlation between voxel time series for\n" " every pair of voxels in the brain (as determined by masking)\n" " 2. Applying a threshold to the resulting correlations to exclude\n" " those that might have arisen by chance, or to sparsify the\n" " connectivity graph.\n" " 3. At each voxel, summarizing its correlation with other voxels\n" " in the brain, by either counting the number of voxels correlated\n" " with the seed voxel (binary) or by summing the correlation \n" " coefficients (weighted).\n" " Practically the algorithm is ordered differently to optimize for\n" " computational time and memory usage.\n\n" " The threshold can be supplied as a correlation coefficient, \n" " or a sparsity threshold. The sparsity threshold reflects the fraction\n" " of connections that should be retained after the threshold has been\n" " applied. To minimize resource consumption, using a sparsity threshold\n" " involves a two-step procedure. In the first step, a correlation\n" " coefficient threshold is applied to substantially reduce the number\n" " of correlations. Next, the remaining correlations are sorted and a\n" " threshold is calculated so that only the specified fraction of \n" " possible correlations are above threshold. Due to ties between\n" " correlations, the fraction of correlations that pass the sparsity\n" " threshold might be slightly more than the number specified.\n\n" " Regardless of the thresholding procedure employed, negative \n" " correlations are excluded from the calculations.\n" "\n" "Options:\n" " -pearson = Correlation is the normal Pearson (product moment)\n" " correlation coefficient [default].\n" #if 0 " -spearman = Correlation is the Spearman (rank) correlation\n" " coefficient.\n" " -quadrant = Correlation is the quadrant correlation coefficient.\n" #else " -spearman AND -quadrant are disabled at this time :-(\n" #endif "\n" " -thresh r = exclude correlations <= r from calculations\n" " -sparsity s = only use top s percent of correlations in calculations\n" " s should be an integer between 0 and 100. Uses an\n" " an adaptive thresholding procedure to reduce memory.\n" " The speed of determining the adaptive threshold can\n" " be improved by specifying an initial threshold with\n" " the -thresh flag.\n" "\n" " -polort m = Remove polynomical trend of order 'm', for m=-1..3.\n" " [default is m=1; removal is by least squares].\n" " Using m=-1 means no detrending; this is only useful\n" " for data/information that has been pre-processed.\n" "\n" " -autoclip = Clip off low-intensity regions in the dataset,\n" " -automask = so that the correlation is only computed between\n" " high-intensity (presumably brain) voxels. The\n" " mask is determined the same way that 3dAutomask works.\n" "\n" " -mask mmm = Mask to define 'in-brain' voxels. Reducing the number\n" " the number of voxels included in the calculation will\n" " significantly speedup the calculation. Consider using\n" " a mask to constrain the calculations to the grey matter\n" " rather than the whole brain. This is also preferrable\n" " to using -autoclip or -automask.\n" "\n" " -prefix p = Save output into dataset with prefix 'p', this file will\n" " contain bricks for both 'weighted' or 'degree' centrality\n" " [default prefix is 'deg_centrality'].\n" "\n" " -out1D f = Save information about the above threshold correlations to\n" " 1D file 'f'. Each row of this file will contain:\n" " Voxel1 Voxel2 i1 j1 k1 i2 j2 k2 Corr\n" " Where voxel1 and voxel2 are the 1D indices of the pair of\n" " voxels, i j k correspond to their 3D coordinates, and Corr\n" " is the value of the correlation between the voxel time courses.\n" "\n" "Notes:\n" " * The output dataset is a bucket type of floats.\n" " * The program prints out an estimate of its memory used\n" " when it ends. It also prints out a progress 'meter'\n" " to keep you pacified.\n" "\n" "-- RWCox - 31 Jan 2002 and 16 Jul 2010\n" "-- Cameron Craddock - 26 Sept 2015 \n" ) ; PRINT_AFNI_OMP_USAGE("3dDegreeCentrality",NULL) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dDegreeCentrality main"); machdep(); PRINT_VERSION("3dDegreeCentrality"); AFNI_logger("3dDegreeCentrality",argc,argv); /*-- option processing --*/ while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-time") == 0 ){ abuc = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-autoclip") == 0 || strcmp(argv[nopt],"-automask") == 0 ){ do_autoclip = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ mset = THD_open_dataset(argv[++nopt]); CHECK_OPEN_ERROR(mset,argv[nopt]); nopt++ ; continue ; } if( strcmp(argv[nopt],"-pearson") == 0 ){ method = PEARSON ; nopt++ ; continue ; } #if 0 if( strcmp(argv[nopt],"-spearman") == 0 ){ method = SPEARMAN ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quadrant") == 0 ){ method = QUADRANT ; nopt++ ; continue ; } #endif if( strcmp(argv[nopt],"-eta2") == 0 ){ method = ETA2 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ prefix = strdup(argv[++nopt]) ; if( !THD_filename_ok(prefix) ){ ERROR_exit("Illegal value after -prefix!") ; } nopt++ ; continue ; } if( strcmp(argv[nopt],"-thresh") == 0 ){ double val = (double)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val >= 1.0 || val < 0.0 ){ ERROR_exit("Illegal value (%f) after -thresh!", val) ; } dothresh = 1; thresh = val ; othresh = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-sparsity") == 0 ){ double val = (double)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val > 100 || val <= 0 ){ ERROR_exit("Illegal value (%f) after -sparsity!", val) ; } if( val > 5.0 ) { WARNING_message("Sparsity %3.2f%% is large and will require alot of memory and time, consider using a smaller value. ", val); } dosparsity = 1 ; sparsity = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-polort") == 0 ){ int val = (int)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val < -1 || val > 3 ){ ERROR_exit("Illegal value after -polort!") ; } polort = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mem_stat") == 0 ){ MEM_STAT = 1 ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-mem_profile",8) == 0 ){ MEM_PROF = 1 ; nopt++ ; continue ; } /* check for 1d argument */ if ( strcmp(argv[nopt],"-out1D") == 0 ){ if (!(fout1D = fopen(argv[++nopt], "w"))) { ERROR_message("Failed to open %s for writing", argv[nopt]); exit(1); } nopt++ ; continue ; } ERROR_exit("Illegal option: %s",argv[nopt]) ; } /*-- open dataset, check for legality --*/ if( nopt >= argc ) ERROR_exit("Need a dataset on command line!?") ; xset = THD_open_dataset(argv[nopt]); CHECK_OPEN_ERROR(xset,argv[nopt]); if( DSET_NVALS(xset) < 3 ) ERROR_exit("Input dataset %s does not have 3 or more sub-bricks!",argv[nopt]) ; DSET_load(xset) ; CHECK_LOAD_ERROR(xset) ; /*-- compute mask array, if desired --*/ nvox = DSET_NVOX(xset) ; nvals = DSET_NVALS(xset) ; INC_MEM_STATS((nvox * nvals * sizeof(double)), "input dset"); PRINT_MEM_STATS("inset"); /* if a mask was specified make sure it is appropriate */ if( mset ){ if( DSET_NVOX(mset) != nvox ) ERROR_exit("Input and mask dataset differ in number of voxels!") ; mask = THD_makemask(mset, 0, 1.0, 0.0) ; /* update running memory statistics to reflect loading the image */ INC_MEM_STATS( mset->dblk->total_bytes, "mask dset" ); PRINT_MEM_STATS( "mset load" ); nmask = THD_countmask( nvox , mask ) ; INC_MEM_STATS( nmask * sizeof(byte), "mask array" ); PRINT_MEM_STATS( "mask" ); INFO_message("%d voxels in -mask dataset",nmask) ; if( nmask < 2 ) ERROR_exit("Only %d voxels in -mask, exiting...",nmask); /* update running memory statistics to reflect loading the image */ DEC_MEM_STATS( mset->dblk->total_bytes, "mask dset" ); DSET_unload(mset) ; PRINT_MEM_STATS( "mset unload" ); } /* if automasking is requested, handle that now */ else if( do_autoclip ){ mask = THD_automask( xset ) ; nmask = THD_countmask( nvox , mask ) ; INFO_message("%d voxels survive -autoclip",nmask) ; if( nmask < 2 ) ERROR_exit("Only %d voxels in -automask!",nmask); } /* otherwise we use all of the voxels in the image */ else { nmask = nvox ; INFO_message("computing for all %d voxels",nmask) ; } if( method == ETA2 && polort >= 0 ) WARNING_message("Polort for -eta2 should probably be -1..."); /* djc - 1d file out init */ if (fout1D != NULL) { /* define affine matrix */ mat44 affine_mat = xset->daxes->ijk_to_dicom; /* print command line statement */ fprintf(fout1D,"#Similarity matrix from command:\n#"); for(ii=0; ii<argc; ++ii) fprintf(fout1D,"%s ", argv[ii]); /* Print affine matrix */ fprintf(fout1D,"\n"); fprintf(fout1D,"#[ "); int mi, mj; for(mi = 0; mi < 4; mi++) { for(mj = 0; mj < 4; mj++) { fprintf(fout1D, "%.6f ", affine_mat.m[mi][mj]); } } fprintf(fout1D, "]\n"); /* Print image extents*/ THD_dataxes *xset_daxes = xset->daxes; fprintf(fout1D, "#Image dimensions:\n"); fprintf(fout1D, "#[%d, %d, %d]\n", xset_daxes->nxx, xset_daxes->nyy, xset_daxes->nzz); /* Similarity matrix headers */ fprintf(fout1D,"#Voxel1 Voxel2 i1 j1 k1 i2 j2 k2 Corr\n"); } /* CC calculate the total number of possible correlations, will be usefule down the road */ totPosCor = (.5*((float)nmask))*((float)(nmask-1)); /** For the case of Pearson correlation, we make sure the **/ /** data time series have their mean removed (polort >= 0) **/ /** and are normalized, so that correlation = dot product, **/ /** and we can use function zm_THD_pearson_corr for speed. **/ switch( method ){ default: case PEARSON: corfun = zm_THD_pearson_corr ; break ; case ETA2: corfun = my_THD_eta_squared ; break ; } /*-- create vectim from input dataset --*/ INFO_message("vectim-izing input dataset") ; /*-- CC added in mask to reduce the size of xvectim -- */ xvectim = THD_dset_to_vectim( xset , mask , 0 ) ; if( xvectim == NULL ) ERROR_exit("Can't create vectim?!") ; /*-- CC update our memory stats to reflect vectim -- */ INC_MEM_STATS((xvectim->nvec*sizeof(int)) + ((xvectim->nvec)*(xvectim->nvals))*sizeof(float) + sizeof(MRI_vectim), "vectim"); PRINT_MEM_STATS( "vectim" ); /*--- CC the vectim contains a mapping between voxel index and mask index, tap into that here to avoid duplicating memory usage ---*/ if( mask != NULL ) { imap = xvectim->ivec; /* --- CC free the mask */ DEC_MEM_STATS( nmask*sizeof(byte), "mask array" ); free(mask); mask=NULL; PRINT_MEM_STATS( "mask unload" ); } /* -- CC unloading the dataset to reduce memory usage ?? -- */ DEC_MEM_STATS((DSET_NVOX(xset) * DSET_NVALS(xset) * sizeof(double)), "input dset"); DSET_unload(xset) ; PRINT_MEM_STATS("inset unload"); /* -- CC configure detrending --*/ if( polort < 0 && method == PEARSON ){ polort = 0; WARNING_message("Pearson correlation always uses polort >= 0"); } if( polort >= 0 ){ for( ii=0 ; ii < xvectim->nvec ; ii++ ){ /* remove polynomial trend */ DETREND_polort(polort,nvals,VECTIM_PTR(xvectim,ii)) ; } } /* -- this procedure does not change time series that have zero variance -- */ if( method == PEARSON ) THD_vectim_normalize(xvectim) ; /* L2 norm = 1 */ /* -- CC create arrays to hold degree and weighted centrality while they are being calculated -- */ if( dosparsity == 0 ) { if( ( binaryDC = (long*)calloc( nmask, sizeof(long) )) == NULL ) { ERROR_message( "Could not allocate %d byte array for binary DC calculation\n", nmask*sizeof(long)); } /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nmask*sizeof(long), "binary DC array" ); PRINT_MEM_STATS( "binaryDC" ); if( ( weightedDC = (double*)calloc( nmask, sizeof(double) )) == NULL ) { if (binaryDC){ free(binaryDC); binaryDC = NULL; } ERROR_message( "Could not allocate %d byte array for weighted DC calculation\n", nmask*sizeof(double)); } /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nmask*sizeof(double), "weighted DC array" ); PRINT_MEM_STATS( "weightedDC" ); } /* -- CC if we are using a sparsity threshold, build a histogram to calculate the threshold */ if (dosparsity == 1) { /* make sure that there is a bin for correlation values that == 1.0 */ binwidth = (1.005-thresh)/nhistnodes; /* calculate the number of correlations we wish to retain */ ngoal = nretain = (int)(((double)totPosCor)*((double)sparsity) / 100.0); /* allocate memory for the histogram bins */ if(( histogram = (hist_node_head*)malloc(nhistnodes*sizeof(hist_node_head))) == NULL ) { /* if the allocation fails, free all memory and exit */ if (binaryDC){ free(binaryDC); binaryDC = NULL; } if (weightedDC){ free(weightedDC); weightedDC = NULL; } ERROR_message( "Could not allocate %d byte array for histogram\n", nhistnodes*sizeof(hist_node_head)); } else { /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nhistnodes*sizeof(hist_node_head), "hist bins" ); PRINT_MEM_STATS( "hist1" ); } /* initialize history bins */ for( kout = 0; kout < nhistnodes; kout++ ) { histogram[ kout ].bin_low = thresh+kout*binwidth; histogram[ kout ].bin_high = histogram[ kout ].bin_low+binwidth; histogram[ kout ].nbin = 0; histogram[ kout ].nodes = NULL; /*INFO_message("Hist bin %d [%3.3f, %3.3f) [%d, %p]\n", kout, histogram[ kout ].bin_low, histogram[ kout ].bin_high, histogram[ kout ].nbin, histogram[ kout ].nodes );*/ } } /*-- tell the user what we are about to do --*/ if (dosparsity == 0 ) { INFO_message( "Calculating degree centrality with threshold = %f.\n", thresh); } else { INFO_message( "Calculating degree centrality with threshold = %f and sparsity = %3.2f%% (%d)\n", thresh, sparsity, nretain); } /*---------- loop over mask voxels, correlate ----------*/ AFNI_OMP_START ; #pragma omp parallel if( nmask > 999 ) { int lii,ljj,lin,lout,ithr,nthr,vstep,vii ; float *xsar , *ysar ; hist_node* new_node = NULL ; hist_node* tptr = NULL ; hist_node* rptr = NULL ; int new_node_idx = 0; double car = 0.0 ; /*-- get information about who we are --*/ #ifdef USE_OMP ithr = omp_get_thread_num() ; nthr = omp_get_num_threads() ; if( ithr == 0 ) INFO_message("%d OpenMP threads started",nthr) ; #else ithr = 0 ; nthr = 1 ; #endif /*-- For the progress tracker, we want to print out 50 numbers, figure out a number of loop iterations that will make this easy */ vstep = (int)( nmask / (nthr*50.0f) + 0.901f ) ; vii = 0 ; if((MEM_STAT==0) && (ithr == 0 )) fprintf(stderr,"Looping:") ; #pragma omp for schedule(static, 1) for( lout=0 ; lout < xvectim->nvec ; lout++ ){ /*----- outer voxel loop -----*/ if( ithr == 0 && vstep > 2 ) /* allow small dsets 16 Jun 2011 [rickr] */ { vii++ ; if( vii%vstep == vstep/2 && MEM_STAT == 0 ) vstep_print(); } /* get ref time series from this voxel */ xsar = VECTIM_PTR(xvectim,lout) ; /* try to make calculation more efficient by only calculating the unique correlations */ for( lin=(lout+1) ; lin < xvectim->nvec ; lin++ ){ /*----- inner loop over voxels -----*/ /* extract the voxel time series */ ysar = VECTIM_PTR(xvectim,lin) ; /* now correlate the time series */ car = (double)(corfun(nvals,xsar,ysar)) ; if ( car <= thresh ) { continue ; } /* update degree centrality values, hopefully the pragma will handle mutual exclusion */ #pragma omp critical(dataupdate) { /* if the correlation is less than threshold, ignore it */ if ( car > thresh ) { totNumCor += 1; if ( dosparsity == 0 ) { binaryDC[lout] += 1; binaryDC[lin] += 1; weightedDC[lout] += car; weightedDC[lin] += car; /* print correlation out to the 1D file */ if ( fout1D != NULL ) { /* determine the i,j,k coords */ ix1 = DSET_index_to_ix(xset,lii) ; jy1 = DSET_index_to_jy(xset,lii) ; kz1 = DSET_index_to_kz(xset,lii) ; ix2 = DSET_index_to_ix(xset,ljj) ; jy2 = DSET_index_to_jy(xset,ljj) ; kz2 = DSET_index_to_kz(xset,ljj) ; /* add source, dest, correlation to 1D file */ fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", lii, ljj, ix1, jy1, kz1, ix2, jy2, kz2, car); } } else { /* determine the index in the histogram to add the node */ new_node_idx = (int)floor((double)(car-othresh)/(double)binwidth); if ((new_node_idx > nhistnodes) || (new_node_idx < bottom_node_idx)) { /* this error should indicate a programming error and should not happen */ WARNING_message("Node index %d is out of range [%d,%d)!",new_node_idx, bottom_node_idx, nhistnodes); } else { /* create a node to add to the histogram */ new_node = (hist_node*)calloc(1,sizeof(hist_node)); if( new_node == NULL ) { /* allocate memory for this node, rather than fiddling with error handling here, lets just move on */ WARNING_message("Could not allocate a new node!"); } else { /* populate histogram node */ new_node->i = lout; new_node->j = lin; new_node->corr = car; new_node->next = NULL; /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( sizeof(hist_node), "hist nodes" ); if ((totNumCor % (1024*1024)) == 0) PRINT_MEM_STATS( "hist nodes" ); /* populate histogram */ new_node->next = histogram[new_node_idx].nodes; histogram[new_node_idx].nodes = new_node; histogram[new_node_idx].nbin++; /* see if there are enough correlations in the histogram for the sparsity */ if ((totNumCor - histogram[bottom_node_idx].nbin) > nretain) { /* delete the list of nodes */ rptr = histogram[bottom_node_idx].nodes; while(rptr != NULL) { tptr = rptr; rptr = rptr->next; /* check that the ptr is not null before freeing it*/ if(tptr!= NULL) { DEC_MEM_STATS( sizeof(hist_node), "hist nodes" ); free(tptr); } } PRINT_MEM_STATS( "unloaded hist nodes - thresh increase" ); histogram[bottom_node_idx].nodes = NULL; totNumCor -= histogram[bottom_node_idx].nbin; histogram[bottom_node_idx].nbin=0; /* get the new threshold */ thresh = (double)histogram[++bottom_node_idx].bin_low; if(MEM_STAT == 1) INFO_message("Increasing threshold to %3.2f (%d)\n", thresh,bottom_node_idx); } } /* else, newptr != NULL */ } /* else, new_node_idx in range */ } /* else, do_sparsity == 1 */ } /* car > thresh */ } /* this is the end of the critical section */ } /* end of inner loop over voxels */ } /* end of outer loop over ref voxels */ if( ithr == 0 ) fprintf(stderr,".\n") ; } /* end OpenMP */ AFNI_OMP_END ; /* update the user so that they know what we are up to */ INFO_message ("AFNI_OMP finished\n"); INFO_message ("Found %d (%3.2f%%) correlations above threshold (%f)\n", totNumCor, 100.0*((float)totNumCor)/((float)totPosCor), thresh); /*---------- Finish up ---------*/ /*if( dosparsity == 1 ) { for( kout = 0; kout < nhistnodes; kout++ ) { INFO_message("Hist bin %d [%3.3f, %3.3f) [%d, %p]\n", kout, histogram[ kout ].bin_low, histogram[ kout ].bin_high, histogram[ kout ].nbin, histogram[ kout ].nodes ); } }*/ /*-- create output dataset --*/ cset = EDIT_empty_copy( xset ) ; /*-- configure the output dataset */ if( abuc ){ EDIT_dset_items( cset , ADN_prefix , prefix , ADN_nvals , nsubbriks , /* 2 subbricks, degree and weighted centrality */ ADN_ntt , 0 , /* no time axis */ ADN_type , HEAD_ANAT_TYPE , ADN_func_type , ANAT_BUCK_TYPE , ADN_datum_all , MRI_float , ADN_none ) ; } else { EDIT_dset_items( cset , ADN_prefix , prefix , ADN_nvals , nsubbriks , /* 2 subbricks, degree and weighted centrality */ ADN_ntt , nsubbriks , /* num times */ ADN_ttdel , 1.0 , /* fake TR */ ADN_nsl , 0 , /* no slice offsets */ ADN_type , HEAD_ANAT_TYPE , ADN_func_type , ANAT_EPI_TYPE , ADN_datum_all , MRI_float , ADN_none ) ; } /* add history information to the hearder */ tross_Make_History( "3dDegreeCentrality" , argc,argv , cset ) ; ININFO_message("creating output dataset in memory") ; /* -- Configure the subbriks: Binary Degree Centrality */ subbrik = 0; EDIT_BRICK_TO_NOSTAT(cset,subbrik) ; /* stat params */ /* CC this sets the subbrik scaling factor, which we will probably want to do again after we calculate the voxel values */ EDIT_BRICK_FACTOR(cset,subbrik,1.0) ; /* scale factor */ sprintf(str,"Binary Degree Centrality") ; EDIT_BRICK_LABEL(cset,subbrik,str) ; EDIT_substitute_brick(cset,subbrik,MRI_float,NULL) ; /* make array */ /* copy measure data into the subbrik */ bodset = DSET_ARRAY(cset,subbrik); /* -- Configure the subbriks: Weighted Degree Centrality */ subbrik = 1; EDIT_BRICK_TO_NOSTAT(cset,subbrik) ; /* stat params */ /* CC this sets the subbrik scaling factor, which we will probably want to do again after we calculate the voxel values */ EDIT_BRICK_FACTOR(cset,subbrik,1.0) ; /* scale factor */ sprintf(str,"Weighted Degree Centrality") ; EDIT_BRICK_LABEL(cset,subbrik,str) ; EDIT_substitute_brick(cset,subbrik,MRI_float,NULL) ; /* make array */ /* copy measure data into the subbrik */ wodset = DSET_ARRAY(cset,subbrik); /* increment memory stats */ INC_MEM_STATS( (DSET_NVOX(cset)*DSET_NVALS(cset)*sizeof(float)), "output dset"); PRINT_MEM_STATS( "outset" ); /* pull the values out of the histogram */ if( dosparsity == 0 ) { for( kout = 0; kout < nmask; kout++ ) { if ( imap != NULL ) { ii = imap[kout] ; /* ii= source voxel (we know that ii is in the mask) */ } else { ii = kout ; } if( ii >= DSET_NVOX(cset) ) { WARNING_message("Avoiding bodset, wodset overflow %d > %d (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } else { bodset[ ii ] = (float)(binaryDC[kout]); wodset[ ii ] = (float)(weightedDC[kout]); } } /* we are done with this memory, and can kill it now*/ if(binaryDC) { free(binaryDC); binaryDC=NULL; /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS( nmask*sizeof(long), "binary DC array" ); PRINT_MEM_STATS( "binaryDC" ); } if(weightedDC) { free(weightedDC); weightedDC=NULL; /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS( nmask*sizeof(double), "weighted DC array" ); PRINT_MEM_STATS( "weightedDC" ); } } else { /* add in the values from the histogram, this is a two stage procedure: at first we add in values a whole bin at the time until we get to a point where we need to add in a partial bin, then we create a new histogram to sort the values in the bin and then add those bins at a time */ kout = nhistnodes - 1; while (( histogram[kout].nbin < nretain ) && ( kout >= 0 )) { hptr = pptr = histogram[kout].nodes; while( hptr != NULL ) { /* determine the indices corresponding to this node */ if ( imap != NULL ) { ii = imap[hptr->i] ; /* ii= source voxel (we know that ii is in the mask) */ } else { ii = hptr->i ; } if ( imap != NULL ) { jj = imap[hptr->j] ; /* ii= source voxel (we know that ii is in the mask) */ } else { jj = hptr->j ; } /* add in the values */ if(( ii >= DSET_NVOX(cset) ) || ( jj >= DSET_NVOX(cset))) { if( ii >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (ii) %d > %d\n (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } if( jj >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (jj) %d > %d\n (%s,%d)\n", jj,DSET_NVOX(cset),__FILE__,__LINE__ ); } } else { bodset[ ii ] += 1.0 ; wodset[ ii ] += (float)(hptr->corr); bodset[ jj ] += 1.0 ; wodset[ jj ] += (float)(hptr->corr); } if( fout1D != NULL ) { /* add source, dest, correlation to 1D file */ ix1 = DSET_index_to_ix(cset,ii) ; jy1 = DSET_index_to_jy(cset,ii) ; kz1 = DSET_index_to_kz(cset,ii) ; ix2 = DSET_index_to_ix(cset,jj) ; jy2 = DSET_index_to_jy(cset,jj) ; kz2 = DSET_index_to_kz(cset,jj) ; fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", ii, jj, ix1, jy1, kz1, ix2, jy2, kz2, (float)(hptr->corr)); } /* increment node pointers */ pptr = hptr; hptr = hptr->next; /* delete the node */ if(pptr) { /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS(sizeof( hist_node ), "hist nodes" ); /* free the mem */ free(pptr); pptr=NULL; } } /* decrement the number of correlations we wish to retain */ nretain -= histogram[kout].nbin; histogram[kout].nodes = NULL; /* go on to the next bin */ kout--; } PRINT_MEM_STATS( "hist1 bins free - inc into output" ); /* if we haven't used all of the correlations that are available, go through and add a subset of the voxels from the remaining bin */ if(( nretain > 0 ) && (kout >= 0)) { hist_node_head* histogram2 = NULL; hist_node_head* histogram2_save = NULL; int h2nbins = 100; float h2binwidth = 0.0; int h2ndx=0; h2binwidth = (((1.0+binwidth/((float)h2nbins))*histogram[kout].bin_high) - histogram[kout].bin_low) / ((float)h2nbins); /* allocate the bins */ if(( histogram2 = (hist_node_head*)malloc(h2nbins*sizeof(hist_node_head))) == NULL ) { if (binaryDC){ free(binaryDC); binaryDC = NULL; } if (weightedDC){ free(weightedDC); weightedDC = NULL; } if (histogram){ histogram = free_histogram(histogram, nhistnodes); } ERROR_message( "Could not allocate %d byte array for histogram2\n", h2nbins*sizeof(hist_node_head)); } else { /* -- update running memory estimate to reflect memory allocation */ histogram2_save = histogram2; INC_MEM_STATS(( h2nbins*sizeof(hist_node_head )), "hist bins"); PRINT_MEM_STATS( "hist2" ); } /* initiatize the bins */ for( kin = 0; kin < h2nbins; kin++ ) { histogram2[ kin ].bin_low = histogram[kout].bin_low + kin*h2binwidth; histogram2[ kin ].bin_high = histogram2[ kin ].bin_low + h2binwidth; histogram2[ kin ].nbin = 0; histogram2[ kin ].nodes = NULL; /*INFO_message("Hist2 bin %d [%3.3f, %3.3f) [%d, %p]\n", kin, histogram2[ kin ].bin_low, histogram2[ kin ].bin_high, histogram2[ kin ].nbin, histogram2[ kin ].nodes );*/ } /* move correlations from histogram to histgram2 */ INFO_message ("Adding %d nodes from histogram to histogram2",histogram[kout].nbin); while ( histogram[kout].nodes != NULL ) { hptr = histogram[kout].nodes; h2ndx = (int)floor((double)(hptr->corr - histogram[kout].bin_low)/(double)h2binwidth); if(( h2ndx < h2nbins ) && ( h2ndx >= 0 )) { histogram[kout].nodes = hptr->next; hptr->next = histogram2[h2ndx].nodes; histogram2[h2ndx].nodes = hptr; histogram2[h2ndx].nbin++; histogram[kout].nbin--; } else { WARNING_message("h2ndx %d is not in range [0,%d) :: %.10f,%.10f\n",h2ndx,h2nbins,hptr->corr, histogram[kout].bin_low); } } /* free the remainder of histogram */ { int nbins_rem = 0; for(ii = 0; ii < nhistnodes; ii++) nbins_rem+=histogram[ii].nbin; histogram = free_histogram(histogram, nhistnodes); PRINT_MEM_STATS( "free remainder of histogram1" ); } kin = h2nbins - 1; while (( nretain > 0 ) && ( kin >= 0 )) { hptr = pptr = histogram2[kin].nodes; while( hptr != NULL ) { /* determine the indices corresponding to this node */ if ( imap != NULL ) { ii = imap[hptr->i] ; } else { ii = hptr->i ; } if ( imap != NULL ) { jj = imap[hptr->j] ; } else { jj = hptr->j ; } /* add in the values */ if(( ii >= DSET_NVOX(cset) ) || ( jj >= DSET_NVOX(cset))) { if( ii >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (ii) %d > %d\n (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } if( jj >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (jj) %d > %d\n (%s,%d)\n", jj,DSET_NVOX(cset),__FILE__,__LINE__ ); } } else { bodset[ ii ] += 1.0 ; wodset[ ii ] += (float)(hptr->corr); bodset[ jj ] += 1.0 ; wodset[ jj ] += (float)(hptr->corr); } if( fout1D != NULL ) { /* add source, dest, correlation to 1D file */ ix1 = DSET_index_to_ix(cset,ii) ; jy1 = DSET_index_to_jy(cset,ii) ; kz1 = DSET_index_to_kz(cset,ii) ; ix2 = DSET_index_to_ix(cset,jj) ; jy2 = DSET_index_to_jy(cset,jj) ; kz2 = DSET_index_to_kz(cset,jj) ; fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", ii, jj, ix1, jy1, kz1, ix2, jy2, kz2, (float)(hptr->corr)); } /* increment node pointers */ pptr = hptr; hptr = hptr->next; /* delete the node */ if(pptr) { free(pptr); DEC_MEM_STATS(( sizeof(hist_node) ), "hist nodes"); pptr=NULL; } } /* decrement the number of correlations we wish to retain */ nretain -= histogram2[kin].nbin; histogram2[kin].nodes = NULL; /* go on to the next bin */ kin--; } PRINT_MEM_STATS("hist2 nodes free - incorporated into output"); /* we are finished with histogram2 */ { histogram2 = free_histogram(histogram2, h2nbins); /* -- update running memory estimate to reflect memory allocation */ PRINT_MEM_STATS( "free hist2" ); } if (nretain < 0 ) { WARNING_message( "Went over sparsity goal %d by %d, with a resolution of %f", ngoal, -1*nretain, h2binwidth); } } if (nretain > 0 ) { WARNING_message( "Was not able to meet goal of %d (%3.2f%%) correlations, %d (%3.2f%%) correlations passed the threshold of %3.2f, maybe you need to change the threshold or the desired sparsity?", ngoal, 100.0*((float)ngoal)/((float)totPosCor), totNumCor, 100.0*((float)totNumCor)/((float)totPosCor), thresh); } } INFO_message("Done..\n") ; /* update running memory statistics to reflect freeing the vectim */ DEC_MEM_STATS(((xvectim->nvec*sizeof(int)) + ((xvectim->nvec)*(xvectim->nvals))*sizeof(float) + sizeof(MRI_vectim)), "vectim"); /* toss some trash */ VECTIM_destroy(xvectim) ; DSET_delete(xset) ; if(fout1D!=NULL)fclose(fout1D); PRINT_MEM_STATS( "vectim unload" ); if (weightedDC) free(weightedDC) ; weightedDC = NULL; if (binaryDC) free(binaryDC) ; binaryDC = NULL; /* finito */ INFO_message("Writing output dataset to disk [%s bytes]", commaized_integer_string(cset->dblk->total_bytes)) ; /* write the dataset */ DSET_write(cset) ; WROTE_DSET(cset) ; /* increment our memory stats, since we are relying on the header for this information, we update the stats before actually freeing the memory */ DEC_MEM_STATS( (DSET_NVOX(cset)*DSET_NVALS(cset)*sizeof(float)), "output dset"); /* free up the output dataset memory */ DSET_unload(cset) ; DSET_delete(cset) ; /* force a print */ MEM_STAT = 1; PRINT_MEM_STATS( "Fin" ); exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL , *outset ; THD_3dim_dataset **insar=NULL ; int nsar=0 ; int iarg=1 , ii,kk , ids ; MCW_cluster *nbhd=NULL ; char *prefix="./localhistog" ; int ntype=0 ; float na=0.0f,nb=0.0f,nc=0.0f ; int verb=1 , do_prob=0 ; int nx=0,ny=0,nz=0,nvox=0, rbot,rtop ; char *labfile=NULL ; NI_element *labnel=NULL ; int nlab=0 , *labval=NULL ; char **lablab=NULL ; char buf[THD_MAX_SBLABEL] ; UINT32 *ohist , *mhist=NULL ; char *ohist_name=NULL ; int ohzadd=0 ; int *rlist , numval ; float mincount=0.0f ; int mcc ; int *exlist=NULL, numex=0 ; int do_excNONLAB=0 ; /*---- for the clueless who wish to become clued-in ----*/ if( argc == 1 ){ usage_3dLocalHistog(1); exit(0); } /* Bob's help shortcut */ /*---- official startup ---*/ #if defined(USING_MCW_MALLOC) && !defined(USE_OMP) enable_mcw_malloc() ; #endif PRINT_VERSION("3dLocalHistog"); mainENTRY("3dLocalHistog main"); machdep(); AFNI_logger("3dLocalHistog",argc,argv); if( getpid()%2 ) AUTHOR("Bilbo Baggins"); else AUTHOR("Thorin Oakenshield"); AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ /*---- loop over options ----*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0){ usage_3dLocalHistog(strlen(argv[iarg])>3 ? 2:1); exit(0); } if( strncmp(argv[iarg],"-qu",3) == 0 ){ verb = 0 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-verb",5) == 0 ){ verb++ ; iarg++ ; continue ; } #ifdef ALLOW_PROB if( strncmp(argv[iarg],"-prob",5) == 0 ){ do_prob = 1 ; iarg++ ; continue ; } #endif if( strcmp(argv[iarg],"-exclude") == 0 ){ int ebot=-6666666,etop=-6666666 , ee ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-exclude'") ; sscanf(argv[iarg],"%d..%d",&ebot,&etop) ; if( ebot >= -TWO15 && ebot <= TWO15 ){ if( etop < -TWO15 || etop > TWO15 || etop < ebot ) etop = ebot ; exlist = (int *)realloc(exlist,sizeof(int)*(etop-ebot+1+numex+1)) ; for( ee=ebot ; ee <= etop ; ee++ ){ if( ee != 0 ) exlist[numex++] = ee ; } } iarg++ ; continue ; } if( strcmp(argv[iarg],"-excNONLAB") == 0 ){ do_excNONLAB = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-prefix'") ; prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Bad -prefix!") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-hsave") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-hsave'") ; ohist_name = strdup(argv[iarg]) ; if( !THD_filename_ok(ohist_name) ) ERROR_exit("Bad -hsave!") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mincount") == 0 ){ char *cpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mincount'") ; mincount = (float)strtod(argv[iarg],&cpt) ; #if 0 if( mincount > 0.0f && mincount < 50.0f && *cpt == '%' ) /* percentage */ mincount = -0.01f*mincount ; #endif iarg++ ; continue ; } if( strcmp(argv[iarg],"-nbhd") == 0 ){ char *cpt ; if( ntype > 0 ) ERROR_exit("Can't have 2 '-nbhd' options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-nbhd'") ; cpt = argv[iarg] ; if( strncasecmp(cpt,"SPHERE",6) == 0 ){ sscanf( cpt+7 , "%f" , &na ) ; ntype = NTYPE_SPHERE ; } else if( strncasecmp(cpt,"RECT",4) == 0 ){ sscanf( cpt+5 , "%f,%f,%f" , &na,&nb,&nc ) ; if( na == 0.0f && nb == 0.0f && nc == 0.0f ) ERROR_exit("'RECT(0,0,0)' is not a legal neighborhood") ; ntype = NTYPE_RECT ; } else if( strncasecmp(cpt,"RHDD",4) == 0 ){ sscanf( cpt+5 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a RHDD of radius 0") ; ntype = NTYPE_RHDD ; } else if( strncasecmp(cpt,"TOHD",4) == 0 ){ sscanf( cpt+5 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a TOHD of radius 0") ; ntype = NTYPE_TOHD ; } else { ERROR_exit("Unknown -nbhd shape: '%s'",cpt) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-lab_file") == 0 || strcmp(argv[iarg],"-labfile") == 0 ){ char **labnum ; int nbad=0 ; if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; if( labfile != NULL ) ERROR_exit("Can't use '%s' twice!",argv[iarg-1]) ; labfile = strdup(argv[iarg]) ; labnel = THD_string_table_read(labfile,0) ; if( labnel == NULL || labnel->vec_num < 2 ) ERROR_exit("Can't read label file '%s'",labfile) ; nlab = labnel->vec_len ; labnum = (char **)labnel->vec[0] ; lablab = (char **)labnel->vec[1] ; labval = (int *)calloc(sizeof(int),nlab) ; for( ii=0 ; ii < nlab ; ii++ ){ if( labnum[ii] != NULL ){ labval[ii] = (int)strtod(labnum[ii],NULL) ; if( labval[ii] < -TWO15 || labval[ii] > TWO15 ){ labval[ii] = 0; nbad++; } } } if( nbad > 0 ) ERROR_message("%d label values are outside the range %d..%d :-(" , nbad , -TWO15 , TWO15 ) ; iarg++ ; continue ; } ERROR_message("** 3dLocalHistog: Illegal option: '%s'",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1) ; } /*--- end of loop over options ---*/ /*---- check for stupid user inputs ----*/ if( iarg >= argc ) ERROR_exit("No datasets on command line?") ; if( ohist_name == NULL && strcmp(prefix,"NULL") == 0 ) ERROR_exit("-prefix NULL is only meaningful if you also use -hsave :-(") ; /*------------ scan input datasets, built overall histogram ------------*/ nsar = argc - iarg ; insar = (THD_3dim_dataset **)malloc(sizeof(THD_3dim_dataset *)*nsar) ; if( verb ) fprintf(stderr,"Scanning %d datasets ",nsar) ; ohist = (UINT32 *)calloc(sizeof(UINT32),TWO16) ; for( ids=iarg ; ids < argc ; ids++ ){ /* dataset loop */ insar[ids-iarg] = inset = THD_open_dataset(argv[ids]) ; CHECK_OPEN_ERROR(inset,argv[ids]) ; if( ids == iarg ){ nx = DSET_NX(inset); ny = DSET_NY(inset); nz = DSET_NZ(inset); nvox = nx*ny*nz; } else if( nx != DSET_NX(inset) || ny != DSET_NY(inset) || nz != DSET_NZ(inset) ){ ERROR_exit("Dataset %s grid doesn't match!",argv[ids]) ; } if( !THD_datum_constant(inset->dblk) ) ERROR_exit("Dataset %s doesn't have a fixed data type! :-(",argv[ids]) ; if( THD_need_brick_factor(inset) ) ERROR_exit("Dataset %s has scale factors! :-(",argv[ids]) ; if( DSET_BRICK_TYPE(inset,0) != MRI_byte && DSET_BRICK_TYPE(inset,0) != MRI_short && DSET_BRICK_TYPE(inset,0) != MRI_float ) ERROR_exit("Dataset %s is not byte- or short-valued! :-(",argv[ids]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; for( ii=0 ; ii < DSET_NVALS(inset) ; ii++ ){ /* add to overall histogram */ if( verb ) fprintf(stderr,".") ; switch( DSET_BRICK_TYPE(inset,ii) ){ case MRI_short:{ short *sar = (short *)DSET_BRICK_ARRAY(inset,ii) ; for( kk=0 ; kk < nvox ; kk++ ) ohist[ sar[kk]+TWO15 ]++ ; } break ; case MRI_byte:{ byte *bar = (byte *)DSET_BRICK_ARRAY(inset,ii) ; for( kk=0 ; kk < nvox ; kk++ ) ohist[ bar[kk]+TWO15 ]++ ; } break ; case MRI_float:{ float *far = (float *)DSET_BRICK_ARRAY(inset,ii) ; short ss ; for( kk=0 ; kk < nvox ; kk++ ){ ss = SHORTIZE(far[kk]); ohist[ss+TWO15]++; } } break ; } } /* end of sub-brick loop */ DSET_unload(inset) ; /* will re-load later, as needed */ } /* end of dataset loop */ if( verb ) fprintf(stderr,"\n") ; /*-------------- process overall histogram for fun and profit -------------*/ /* if we didn't actually find 0, put it in the histogram now */ if( ohist[0+TWO15] == 0 ){ ohist[0+TWO15] = 1 ; ohzadd = 1 ; } /* excNONLAB? */ if( nlab > 0 && do_excNONLAB ){ byte *klist = (byte *)calloc(sizeof(byte),TWO16) ; int nee ; for( ii=0 ; ii < nlab ; ii++ ){ if( labval[ii] != 0 ) klist[labval[ii]+TWO15] = 1 ; } for( nee=ii=0 ; ii < TWO16 ; ii++ ){ if( !klist[ii] ) nee++ ; } exlist = (int *)realloc(exlist,sizeof(int)*(numex+nee+1)) ; for( ii=0 ; ii < TWO16 ; ii++ ){ if( ii != TWO15 && !klist[ii] ) exlist[numex++] = ii-TWO15 ; } free(klist) ; } /* make a copy of ohist and edit it for mincount, etc */ mhist = (UINT32 *)malloc(sizeof(UINT32)*TWO16) ; memcpy(mhist,ohist,sizeof(UINT32)*TWO16) ; mcc = (mincount < 0.0f) ? (int)(-mincount*nvox) : (int)mincount ; if( mcc > 1 ){ for( ids=ii=0 ; ii < TWO16 ; ii++ ){ if( ii != TWO15 && mhist[ii] > 0 && mhist[ii] < mcc ){ mhist[ii] = 0; ids++; } } if( ids > 0 && verb ) INFO_message("Edited out %d values with overall histogram counts less than %d",ids,mcc) ; } if( numex > 0 ){ int ee ; for( ids=0,ii=0 ; ii < numex ; ii++ ){ ee = exlist[ii] ; if( mhist[ee+TWO15] > 0 ){ mhist[ee+TWO15] = 0; ids++; } } free(exlist) ; if( ids > 0 && verb ) INFO_message("Edited out %d values from the exclude list",ids) ; } /* count number of values with nonzero (edited) counts */ numval = 0 ; for( ii=0 ; ii < TWO16 ; ii++ ) if( mhist[ii] != 0 ) numval++ ; if( numval == 0 ) ERROR_exit("Nothing found! WTF?") ; /* should not happen */ /* make list of all values with nonzero (edited) count */ rlist = (int *)malloc(sizeof(int)*numval) ; if( verb > 1 ) fprintf(stderr,"++ Include list:") ; for( ii=kk=0 ; ii < TWO16 ; ii++ ){ if( mhist[ii] != 0 ){ rlist[kk++] = ii-TWO15 ; if( verb > 1 ) fprintf(stderr," %d[%u]",ii-TWO15,mhist[ii]) ; } } if( verb > 1 ) fprintf(stderr,"\n") ; rbot = rlist[0] ; rtop = rlist[numval-1] ; /* smallest and largest values found */ if( rbot == rtop ) ERROR_exit("Only one value (%d) found in all inputs!",rbot) ; /* if 0 isn't first in rlist, then put it in first place and move negative values up by one spot */ if( rbot < 0 ){ for( kk=0 ; kk < numval && rlist[kk] != 0 ; kk++ ) ; /*nada*/ if( kk < numval ){ /* should always be true */ for( ii=kk-1 ; ii >= 0 ; ii-- ) rlist[ii+1] = rlist[ii] ; rlist[0] = 0 ; } } if( verb ) INFO_message("Value range = %d..%d (%d distinct values)",rbot,rtop,numval ); /* save overall histogram? */ if( ohist_name != NULL ){ FILE *fp = fopen(ohist_name,"w") ; int nl=0 ; if( fp == NULL ) ERROR_exit("Can't open -hsave '%s' for output!",ohist_name) ; if( ohzadd ) ohist[0+TWO15] = 0 ; for( ii=0 ; ii < TWO16 ; ii++ ){ if( ohist[ii] != 0 ){ fprintf(fp,"%6d %u\n",ii-TWO15,ohist[ii]); nl++; } } fclose(fp) ; if( verb ) INFO_message("Wrote %d lines to -hsave file %s",nl,ohist_name) ; } free(ohist) ; free(mhist) ; mhist = ohist = NULL ; /* done with this */ if( strcmp(prefix,"NULL") == 0 ) exit(0) ; /* special case */ /*----------- build the neighborhood mask -----------*/ if( ntype <= 0 ){ /* default neighborhood */ ntype = NTYPE_SPHERE ; na = 0.0f ; if( verb ) INFO_message("Using default neighborhood = self") ; } switch( ntype ){ default: ERROR_exit("WTF? ntype=%d",ntype) ; /* should not happen */ case NTYPE_SPHERE:{ float dx , dy , dz ; if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(insar[0])) ; dy = fabsf(DSET_DY(insar[0])) ; dz = fabsf(DSET_DZ(insar[0])) ; } nbhd = MCW_spheremask( dx,dy,dz , na ) ; } break ; case NTYPE_RECT:{ float dx , dy , dz ; if( na < 0.0f ){ dx = 1.0f; na = -na; } else dx = fabsf(DSET_DX(insar[0])); if( nb < 0.0f ){ dy = 1.0f; nb = -nb; } else dy = fabsf(DSET_DY(insar[0])); if( nc < 0.0f ){ dz = 1.0f; nc = -nc; } else dz = fabsf(DSET_DZ(insar[0])); nbhd = MCW_rectmask( dx,dy,dz , na,nb,nc ) ; } break ; case NTYPE_RHDD:{ float dx , dy , dz ; if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(insar[0])) ; dy = fabsf(DSET_DY(insar[0])) ; dz = fabsf(DSET_DZ(insar[0])) ; } nbhd = MCW_rhddmask( dx,dy,dz , na ) ; } break ; case NTYPE_TOHD:{ float dx , dy , dz ; if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(insar[0])) ; dy = fabsf(DSET_DY(insar[0])) ; dz = fabsf(DSET_DZ(insar[0])) ; } nbhd = MCW_tohdmask( dx,dy,dz , na ) ; } break ; } if( verb ) INFO_message("Neighborhood comprises %d voxels",nbhd->num_pt) ; /*------- actually do some work for a change (is it lunchtime yet?) -------*/ if( verb ) fprintf(stderr,"Voxel-wise histograms ") ; outset = THD_localhistog( nsar,insar , numval,rlist , nbhd , do_prob,verb ) ; if( outset == NULL ) ERROR_exit("Function THD_localhistog() fails?!") ; /*---- save resulting dataset ----*/ EDIT_dset_items( outset , ADN_prefix,prefix , ADN_none ) ; tross_Copy_History( insar[0] , outset ) ; tross_Make_History( "3dLocalHistog" , argc,argv , outset ) ; /* but first attach labels to sub-bricks */ EDIT_BRICK_LABEL(outset,0,"0:Other") ; for( kk=1 ; kk < numval ; kk++ ){ sprintf(buf,"%d:",rlist[kk]) ; for( ii=0 ; ii < nlab ; ii++ ){ if( labval[ii] == rlist[kk] && lablab[ii] != NULL ){ ids = strlen(buf) ; MCW_strncpy(buf+ids,lablab[ii],THD_MAX_SBLABEL-ids) ; break ; } } EDIT_BRICK_LABEL(outset,kk,buf) ; } DSET_write( outset ) ; if( verb ) WROTE_DSET( outset ) ; exit(0) ; }
int main( int argc , char * argv[] ) { float mrad=0.0f , fwhm=0.0f ; int nrep=1 ; char *prefix = "Polyfit" ; char *resid = NULL ; char *cfnam = NULL ; int iarg , verb=0 , do_automask=0 , nord=3 , meth=2 , do_mclip=0 ; THD_3dim_dataset *inset ; MRI_IMAGE *imout , *imin ; byte *mask=NULL ; int nvmask=0 , nmask=0 , do_mone=0 , do_byslice=0 ; MRI_IMARR *exar=NULL ; floatvec *fvit=NULL ; /* 26 Feb 2019 */ if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf("\n" "Usage: 3dPolyfit [options] dataset ~1~\n" "\n" "* Fits a polynomial in space to the input dataset and outputs that fitted dataset.\n" "\n" "* You can also add your own basis datasets to the fitting mix, using the\n" " '-base' option.\n" "\n" "* You can get the fit coefficients using the '-1Dcoef' option.\n" "\n" "--------\n" "Options: ~1~\n" "--------\n" "\n" " -nord n = Maximum polynomial order (0..9) [default order=3]\n" " [n=0 is the constant 1]\n" " [n=-1 means only use volumes from '-base']\n" "\n" " -blur f = Gaussian blur input dataset (inside mask) with FWHM='f' (mm)\n" "\n" " -mrad r = Radius (voxels) of preliminary median filter of input\n" " [default is no blurring of either type; you can]\n" " [do both types (Gaussian and median), but why??]\n" " [N.B.: median blur is slower than Gaussian]\n" "\n" " -prefix pp = Use 'pp' for prefix of output dataset (the fit).\n" " [default prefix is 'Polyfit'; use NULL to skip this output]\n" "\n" " -resid rr = Use 'rr' for the prefix of the residual dataset.\n" " [default is not to output residuals]\n" "\n" " -1Dcoef cc = Save coefficients of fit into text file cc.1D.\n" " [default is not to save these coefficients]\n" "\n" " -automask = Create a mask (a la 3dAutomask)\n" " -mask mset = Create a mask from nonzero voxels in 'mset'.\n" " [default is not to use a mask, which is probably a bad idea]\n" "\n" " -mone = Scale the mean value of the fit (inside the mask) to 1.\n" " [probably this option is not useful for anything]\n" "\n" " -mclip = Clip fit values outside the rectilinear box containing the\n" " mask to the edge of that box, to avoid weird artifacts.\n" "\n" " -meth mm = Set 'mm' to 2 for least squares fit;\n" " set it to 1 for L1 fit [default method=2]\n" " [Note that L1 fitting is slower than L2 fitting!]\n" "\n" " -base bb = In addition to the polynomial fit, also use\n" " the volumes in dataset 'bb' as extra basis functions.\n" " [If you use a base dataset, then you can set nord]\n" " [to -1, to skip using any spatial polynomial fit.]\n" "\n" " -verb = Print fun and useful progress reports :-)\n" "\n" "------\n" "Notes: ~1~\n" "------\n" "* Output dataset is always stored in float format.\n" "\n" "* If the input dataset has more than 1 sub-brick, only sub-brick #0\n" " is processed. To fit more than one volume, you'll have to use a script\n" " to loop over the input sub-bricks, and then glue (3dTcat) the results\n" " together to get a final result. A simple example:\n" " #!/bin/tcsh\n" " set base = model.nii\n" " set dset = errts.nii\n" " set nval = `3dnvals $dset`\n" " @ vtop = $nval - 1\n" " foreach vv ( `count 0 $vtop` )\n" " 3dPolyfit -base \"$base\" -nord 0 -mask \"$base\" -1Dcoef QQ.$vv -prefix QQ.$vv.nii $dset\"[$vv]\"\n" " end\n" " 3dTcat -prefix QQall.nii QQ.0*.nii\n" " 1dcat QQ.0*.1D > QQall.1D\n" " \rm QQ.0*\n" " exit 0\n" "\n" "* If the '-base' dataset has multiple sub-bricks, all of them are used.\n" "\n" "* You can use the '-base' option more than once, if desired or needed.\n" "\n" "* The original motivation for this program was to fit a spatial model\n" " to a field map MRI, but that didn't turn out to be useful. Nevertheless,\n" " I make this program available to someone who might find it beguiling.\n" "\n" "* If you really want, I could allow you to put sign constraints on the\n" " fit coefficients (e.g., say that the coefficient for a given base volume\n" " should be non-negative). But you'll have to beg for this.\n" "\n" "-- Emitted by RWCox\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup paperwork --*/ mainENTRY("3dPolyfit main"); machdep(); AFNI_logger("3dPolyfit",argc,argv); PRINT_VERSION("3dPolyfit") ; /*-- scan command line --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcasecmp(argv[iarg],"-base") == 0 ){ THD_3dim_dataset *bset ; int kk ; MRI_IMAGE *bim ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-base'") ; bset = THD_open_dataset(argv[iarg]) ; CHECK_OPEN_ERROR(bset,argv[iarg]) ; DSET_load(bset) ; CHECK_LOAD_ERROR(bset) ; if( exar == NULL ) INIT_IMARR(exar) ; for( kk=0 ; kk < DSET_NVALS(bset) ; kk++ ){ bim = THD_extract_float_brick(kk,bset) ; if( bim != NULL ) ADDTO_IMARR(exar,bim) ; DSET_unload_one(bset,kk) ; } DSET_delete(bset) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-verb") == 0 ){ verb++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-hermite") == 0 ){ /* 25 Mar 2013 [New Year's Day] */ mri_polyfit_set_basis("hermite") ; /* HIDDEN */ iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-byslice") == 0 ){ /* 25 Mar 2013 [New Year's Day] */ do_byslice++ ; iarg++ ; continue ; /* HIDDEN */ } if( strcasecmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || do_automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset(argv[iarg]) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; nvmask = DSET_NVOX(mset) ; mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ; nmask = THD_countmask( nvmask , mask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels in mask (%d)",nmask) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-nord") == 0 ){ nord = (int)strtol( argv[++iarg], NULL , 10 ) ; if( nord < -1 || nord > 9 ) ERROR_exit("Illegal value after -nord :(") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-meth") == 0 ){ meth = (int)strtol( argv[++iarg], NULL , 10 ) ; if( meth < 1 || meth > 2 ) ERROR_exit("Illegal value after -meth :(") ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-automask",5) == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask and -automask together!") ; do_automask++ ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mclip",5) == 0 ){ do_mclip++ ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mone",5) == 0 ){ do_mone++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-mrad") == 0 ){ mrad = strtod( argv[++iarg] , NULL ) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-blur") == 0 ){ fwhm = strtod( argv[++iarg] , NULL ) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix :("); if( strcasecmp(prefix,"NULL") == 0 ) prefix = NULL ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-resid") == 0 ){ resid = argv[++iarg] ; if( !THD_filename_ok(resid) ) ERROR_exit("Illegal value after -resid :("); if( strcasecmp(resid,"NULL") == 0 ) resid = NULL ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-1Dcoef") == 0 ){ /* 26 Feb 2019 */ cfnam = argv[++iarg] ; if( !THD_filename_ok(cfnam) ) ERROR_exit("Illegal value after -1Dcoef :("); if( strcasecmp(cfnam,"NULL") == 0 ) cfnam = NULL ; iarg++ ; continue ; } ERROR_exit("Unknown option: %s\n",argv[iarg]); } /*--- check for blatant errors ---*/ if( iarg >= argc ) ERROR_exit("No input dataset name on command line?"); if( prefix == NULL && resid == NULL && cfnam == NULL ) ERROR_exit("-prefix and -resid and -1Dcoef are all NULL?!") ; if( do_byslice && cfnam != NULL ){ WARNING_message("-byslice does not work with -1Dcoef option :(") ; cfnam = NULL ; } if( nord < 0 && exar == NULL ) ERROR_exit("no polynomial fit AND no -base option ==> nothing to compute :(") ; /*-- read input --*/ if( verb ) INFO_message("Load input dataset") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; if( DSET_NVALS(inset) > 1 ) WARNING_message( "Only processing sub-brick #0 (out of %d)" , DSET_NVALS(inset) ); /* check input mask or create automask */ if( mask != NULL ){ if( nvmask != DSET_NVOX(inset) ) ERROR_exit("-mask and input datasets don't match in voxel counts :-(") ; } else if( do_automask ){ THD_automask_verbose( (verb > 1) ) ; THD_automask_extclip( 1 ) ; mask = THD_automask( inset ) ; nvmask = DSET_NVOX(inset) ; nmask = THD_countmask( nvmask , mask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels in automask (%d)",nmask) ; if( verb ) ININFO_message("Number of voxels in automask = %d",nmask) ; } else { WARNING_message("3dPolyfit is running without a mask") ; } #undef GOOD #define GOOD(i) (mask == NULL || mask[i]) /* check -base input datasets */ if( exar != NULL ){ int ii,kk , nvbad=0 , nvox=DSET_NVOX(inset),nm ; float *ex , exb ; for( kk=0 ; kk < IMARR_COUNT(exar) ; kk++ ){ if( nvox != IMARR_SUBIM(exar,kk)->nvox ){ if( IMARR_SUBIM(exar,kk)->nvox != nvbad ){ ERROR_message("-base volume (%d voxels) doesn't match input dataset grid size (%d voxels)", IMARR_SUBIM(exar,kk)->nvox , nvox ) ; nvbad = IMARR_SUBIM(exar,kk)->nvox ; } } } if( nvbad != 0 ) ERROR_exit("Cannot continue :-(") ; /* subtract mean from each base input, if is a constant polynomial in the fit */ if( nord >= 0 ){ if( verb ) INFO_message("subtracting spatial mean from '-base'") ; for( kk=0 ; kk < IMARR_COUNT(exar) ; kk++ ){ exb = 0.0f ; ex = MRI_FLOAT_PTR(IMARR_SUBIM(exar,kk)) ; for( nm=ii=0 ; ii < nvox ; ii++ ){ if( GOOD(ii) ){ exb += ex[ii]; nm++; } } exb /= nm ; for( ii=0 ; ii < nvox ; ii++ ) ex[ii] -= exb ; } } } /* if blurring, edit mask a little */ if( mask != NULL && (fwhm > 0.0f || mrad > 0.0f) ){ int ii ; ii = THD_mask_remove_isolas( DSET_NX(inset),DSET_NY(inset),DSET_NZ(inset),mask ) ; if( ii > 0 ){ nmask = THD_countmask( nvmask , mask ) ; if( verb ) ININFO_message("Removed %d isola%s from mask, leaving %d voxels" , ii,(ii==1)?"\0":"s" , nmask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels left in mask after isola removal :-(") ; } } /* convert input to float, which is simpler to deal with */ imin = THD_extract_float_brick(0,inset) ; if( imin == NULL ) ERROR_exit("Can't extract input dataset brick?! :-(") ; DSET_unload(inset) ; if( verb ) INFO_message("Start fitting process") ; /* do the Gaussian blurring */ if( fwhm > 0.0f ){ if( verb ) ININFO_message("Gaussian blur: FWHM=%g mm",fwhm) ; imin->dx = fabsf(DSET_DX(inset)) ; imin->dy = fabsf(DSET_DY(inset)) ; imin->dz = fabsf(DSET_DZ(inset)) ; mri_blur3D_addfwhm( imin , mask , fwhm ) ; } /* do the fitting */ mri_polyfit_verb(verb) ; if( do_byslice ) imout = mri_polyfit_byslice( imin , nord , exar , mask , mrad , meth ) ; else imout = mri_polyfit ( imin , nord , exar , mask , mrad , meth ) ; /* WTF? */ if( imout == NULL ) ERROR_exit("Can't compute polynomial fit :-( !?") ; if( resid == NULL ) mri_free(imin) ; if( ! do_byslice ) fvit = mri_polyfit_get_fitvec() ; /* get coefficients of fit [26 Feb 2019] */ /* scale the fit dataset? */ if( do_mone ){ float sum=0.0f ; int nsum=0 , ii,nvox ; float *par=MRI_FLOAT_PTR(imout) ; nvox = imout->nvox ; for( ii=0 ; ii < nvox ; ii++ ){ if( mask != NULL && mask[ii] == 0 ) continue ; sum += par[ii] ; nsum++ ; } if( nsum > 0 && sum != 0.0f ){ sum = nsum / sum ; if( verb ) ININFO_message("-mone: scaling fit by %g",sum) ; for( ii=0 ; ii < nvox ; ii++ ) par[ii] *= sum ; } } /* if there's a mask, clip values outside of its box */ #undef PF #define PF(i,j,k) par[(i)+(j)*nx+(k)*nxy] if( mask != NULL && do_mclip ){ int xm,xp,ym,yp,zm,zp , ii,jj,kk , nx,ny,nz,nxy ; float *par ; MRI_IMAGE *bim = mri_empty_conforming( imout , MRI_byte ) ; mri_fix_data_pointer(mask,bim) ; if( verb ) ININFO_message("-mclip: polynomial fit to autobox of mask") ; MRI_autobbox( bim , &xm,&xp , &ym,&yp , &zm,&zp ) ; mri_clear_data_pointer(bim) ; mri_free(bim) ; nx = imout->nx ; ny = imout->ny ; nz = imout->nz ; nxy = nx*ny ; par = MRI_FLOAT_PTR(imout) ; for( ii=0 ; ii < xm ; ii++ ) for( kk=0 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) PF(ii,jj,kk) = PF(xm,jj,kk) ; for( ii=xp+1 ; ii < nx ; ii++ ) for( kk=0 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) PF(ii,jj,kk) = PF(xp,jj,kk) ; for( jj=0 ; jj < ym ; jj++ ) for( kk=0 ; kk < nz ; kk++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,ym,kk) ; for( jj=yp+1 ; jj < ny ; jj++ ) for( kk=0 ; kk < nz ; kk++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,yp,kk) ; for( kk=0 ; kk < zm ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,jj,zm) ; for( kk=zp+1 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,jj,zp) ; } if( mask != NULL ) free(mask) ; /* write outputs */ if( prefix != NULL ){ THD_3dim_dataset *outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(imout) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dPolyfit" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; } if( resid != NULL ){ THD_3dim_dataset *outset = EDIT_empty_copy( inset ) ; float *inar=MRI_FLOAT_PTR(imin) , *outar=MRI_FLOAT_PTR(imout) ; int nx,ny,nz , nxyz , kk ; nx = imout->nx ; ny = imout->ny ; nz = imout->nz ; nxyz = nx*ny*nz ; for( kk=0 ; kk < nxyz ; kk++ ) outar[kk] = inar[kk] - outar[kk] ; mri_free(imin) ; EDIT_dset_items( outset , ADN_prefix , resid , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(imout) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dPolyfit" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; } if( cfnam != NULL && fvit != NULL ){ /* won't work with '-byslice' */ char *qn ; qn = STRING_HAS_SUFFIX(cfnam,".1D") ? cfnam : modify_afni_prefix(cfnam,NULL,".1D") ; mri_write_floatvec( qn , fvit ) ; } exit(0) ; }
int main( int argc , char *argv[] ) { int vstep=0 , ii,nvox , ntin , ntout , do_one=0 , nup=-1 ; THD_3dim_dataset *inset=NULL , *outset ; char *prefix="Upsam", *dsetname=NULL ; int verb=0 , iarg=1, datum = MRI_float; float *ivec , *ovec , trin , trout, *fac=NULL, *ofac=NULL, top=0.0, maxtop=0.0; /*------- help the pitifully ignorant user? -------*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dUpsample [options] n dataset\n" "\n" "* Upsamples a 3D+time dataset, in the time direction,\n" " by a factor of 'n'.\n" "* The value of 'n' must be between 2 and 320 (inclusive).\n" "* The output dataset is in float format by default.\n" "\n" "Options:\n" "--------\n" " -1 or -one = Use linear interpolation. Otherwise,\n" " or -linear 7th order polynomial interpolation is used.\n" "\n" " -prefix pp = Define the prefix name of the output dataset.\n" " [default prefix is 'Upsam']\n" "\n" " -verb = Be eloquently and mellifluosly verbose.\n" "\n" " -n n = An alternate way to specify n\n" " -input dataset = An alternate way to specify dataset\n" "\n" " -datum ddd = Use datatype ddd at output. Choose from\n" " float (default), short, byte.\n" "Example:\n" "--------\n" " 3dUpsample -prefix LongFred 5 Fred+orig\n" "\n" "Nota Bene:\n" "----------\n" "* You should not use this for files that were 3dTcat-ed across\n" " imaging run boundaries, since that will result in interpolating\n" " between non-contiguous time samples!\n" "* If the input has M time points, the output will have n*M time\n" " points. The last n-1 of them will be past the end of the original\n" " time series.\n" "* This program gobbles up memory and diskspace as a function of n.\n" " You can reduce output file size with -datum option.\n" "\n" "--- RW Cox - April 2008\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dUpsample"); machdep(); PRINT_VERSION("3dUpsample"); AUTHOR("RWCox") ; AFNI_logger("3dUpsample",argc,argv); /*------- read command line args -------*/ datum = MRI_float; iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncasecmp(argv[iarg],"-prefix",5) == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal string after -prefix: '%s'",prefix) ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-one",4) == 0 || strcmp (argv[iarg],"-1" ) == 0 || strncasecmp(argv[iarg],"-lin",4) == 0 ){ do_one = 1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-verb",3) == 0 ){ verb = 1 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-n") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); nup = (int)strtod(argv[iarg],NULL) ; if( nup < 2 || nup > 320 ) ERROR_exit("3dUpsample rate '%d' is outside range 2..320",nup) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-input") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); dsetname = argv[iarg]; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-datum") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); if( strcmp(argv[iarg],"short") == 0 ){ datum = MRI_short ; } else if( strcmp(argv[iarg],"float") == 0 ){ datum = MRI_float ; } else if( strcmp(argv[iarg],"byte") == 0 ){ datum = MRI_byte ; } else { ERROR_message("-datum of type '%s' not supported in 3dUpsample!\n", argv[iarg] ) ; exit(1) ; } iarg++ ; continue ; } ERROR_message("Unknown argument on command line: '%s'",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit (1); } /*------- check options for completeness and consistency -----*/ if (nup == -1) { if( iarg+1 >= argc ) ERROR_exit("need 'n' and 'dataset' on command line!") ; nup = (int)strtod(argv[iarg++],NULL) ; if( nup < 2 || nup > 320 ) ERROR_exit("3dUpsample rate '%d' is outside range 2..320",nup) ; } if (!dsetname) { if( iarg >= argc ) ERROR_exit("need 'dataset' on command line!") ; dsetname = argv[iarg]; } inset = THD_open_dataset(dsetname) ; if( !ISVALID_DSET(inset) ) ERROR_exit("3dUpsample can't open dataset '%s'", dsetname) ; ntin = DSET_NVALS(inset) ; trin = DSET_TR(inset) ; if( ntin < 2 ) ERROR_exit("dataset '%s' has only 1 value per voxel?!",dsetname) ; nvox = DSET_NVOX(inset) ; if( verb ) INFO_message("loading input dataset into memory") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; /*------ create output dataset ------*/ ntout = ntin * nup ; trout = trin / nup ; /* scaling factor for output */ fac = NULL; maxtop = 0.0; if (MRI_IS_INT_TYPE(datum)) { fac = (float *)calloc(DSET_NVALS(inset), sizeof(float)); ofac = (float *)calloc(ntout, sizeof(float)); for (ii=0; ii<DSET_NVALS(inset); ++ii) { top = MCW_vol_amax( DSET_NVOX(inset),1,1 , DSET_BRICK_TYPE(inset,ii), DSET_BRICK_ARRAY(inset,ii) ) ; if (DSET_BRICK_FACTOR(inset, ii)) top = top * DSET_BRICK_FACTOR(inset,ii); fac[ii] = (top > MRI_TYPE_maxval[datum]) ? top/MRI_TYPE_maxval[datum] : 0.0 ; if (top > maxtop) maxtop = top; } if (storage_mode_from_filename(prefix) != STORAGE_BY_BRICK) { fac[0] = (maxtop > MRI_TYPE_maxval[datum]) ? maxtop/MRI_TYPE_maxval[datum] : 0.0 ; for (ii=0; ii<ntout; ++ii) ofac[ii] = fac[0]; if (verb) INFO_message("Forcing global scaling, Max = %f, fac = %f\n", maxtop, fac[0]); } else { if (verb) INFO_message("Reusing scaling factors of input dset\n"); upsample_1( nup, DSET_NVALS(inset), fac, ofac); } } free(fac); fac = NULL; outset = EDIT_empty_copy(inset) ; EDIT_dset_items( outset , ADN_nvals , ntout , ADN_ntt , DSET_NUM_TIMES(inset) > 1 ? ntout : 0 , ADN_datum_all , datum , ADN_brick_fac , ofac , ADN_prefix , prefix , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dUpsample" , argc,argv , outset ) ; free(ofac); ofac = NULL; if( outset->taxis != NULL ){ outset->taxis->ttdel /= nup ; outset->taxis->ttdur /= nup ; if( outset->taxis->toff_sl != NULL ){ for( ii=0 ; ii < outset->taxis->nsl ; ii++ ) outset->taxis->toff_sl[ii] /= nup ; } } for( ii=0 ; ii < ntout ; ii++ ){ /* create empty bricks to be filled below */ EDIT_substitute_brick( outset , ii , datum , NULL ) ; } /*------- loop over voxels and process them one at a time ---------*/ if( verb ) INFO_message("Upsampling time series from %d to %d: %s interpolation", ntin , ntout , (do_one) ? "linear" : "heptic" ) ; if( verb && nvox > 499 ) vstep = nvox / 50 ; if( vstep > 0 ) fprintf(stderr,"++ voxel loop: ") ; ivec = (float *)malloc(sizeof(float)*ntin) ; ovec = (float *)malloc(sizeof(float)*ntout) ; for( ii=0 ; ii < nvox ; ii++ ){ if( vstep > 0 && ii%vstep==vstep-1 ) vstep_print() ; THD_extract_array( ii , inset , 0 , ivec ) ; if( do_one ) upsample_1( nup , ntin , ivec , ovec ) ; else upsample_7( nup , ntin , ivec , ovec ) ; THD_insert_series( ii , outset , ntout , MRI_float , ovec , datum==MRI_float ? 1:0 ) ; } /* end of loop over voxels */ if( vstep > 0 ) fprintf(stderr," Done!\n") ; /*----- clean up and go away -----*/ DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; if( verb ) INFO_message("Total CPU time = %.1f s",COX_cpu_time()) ; exit(0); }
int main( int argc , char *argv[] ) { char *aname ; THD_3dim_dataset *dset ; int ii , scl ; MRI_IMAGE *im , *qim ; char *fname ; float fac ; int do_4D=0 , iarg=1 ; /* 30 Sep 2002 */ FILE *ifp=NULL ; int xxor=-1,yyor=0,zzor=0 , xdir=0,ydir=0,zdir=0; /* 19 Mar 2003 */ float xdel=0.0 ,ydel=0.0,zdel=0.0; char orient_code[4] ; /*-- help me if you can --*/ WARNING_message("This program (3dAFNItoANALYZE) is old, not maintained, and probably useless!") ; if( argc < 3 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dAFNItoANALYZE [-4D] [-orient code] aname dset\n" "Writes AFNI dataset 'dset' to 1 or more ANALYZE 7.5 format\n" ".hdr/.img file pairs (one pair for each sub-brick in the\n" "AFNI dataset). The ANALYZE files will be named\n" " aname_0000.hdr aname_0000.img for sub-brick #0\n" " aname_0001.hdr aname_0001.img for sub-brick #1\n" "and so forth. Each file pair will contain a single 3D array.\n" "\n" "* If the AFNI dataset does not include sub-brick scale\n" " factors, then the ANALYZE files will be written in the\n" " datum type of the AFNI dataset.\n" "* If the AFNI dataset does have sub-brick scale factors,\n" " then each sub-brick will be scaled to floating format\n" " and the ANALYZE files will be written as floats.\n" "* The .hdr and .img files are written in the native byte\n" " order of the computer on which this program is executed.\n" "\n" "Options\n" "-------\n" "-4D [30 Sep 2002]:\n" " If you use this option, then all the data will be written to\n" " one big ANALYZE file pair named aname.hdr/aname.img, rather\n" " than a series of 3D files. Even if you only have 1 sub-brick,\n" " you may prefer this option, since the filenames won't have\n" " the '_0000' appended to 'aname'.\n" "\n" "-orient code [19 Mar 2003]:\n" " This option lets you flip the dataset to a different orientation\n" " when it is written to the ANALYZE files. The orientation code is\n" " formed as follows:\n" " The code must be 3 letters, one each from the\n" " pairs {R,L} {A,P} {I,S}. The first letter gives\n" " the orientation of the x-axis, the second the\n" " orientation of the y-axis, the third the z-axis:\n" " R = Right-to-Left L = Left-to-Right\n" " A = Anterior-to-Posterior P = Posterior-to-Anterior\n" " I = Inferior-to-Superior S = Superior-to-Inferior\n" " For example, 'LPI' means\n" " -x = Left +x = Right\n" " -y = Posterior +y = Anterior\n" " -z = Inferior +z = Superior\n" " * For display in SPM, 'LPI' or 'RPI' seem to work OK.\n" " Be careful with this: you don't want to confuse L and R\n" " in the SPM display!\n" " * If you DON'T use this option, the dataset will be written\n" " out in the orientation in which it is stored in AFNI\n" " (e.g., the output of '3dinfo dset' will tell you this.)\n" " * The dataset orientation is NOT stored in the .hdr file.\n" " * AFNI and ANALYZE data are stored in files with the x-axis\n" " varying most rapidly and the z-axis most slowly.\n" " * Note that if you read an ANALYZE dataset into AFNI for\n" " display, AFNI assumes the LPI orientation, unless you\n" " set environment variable AFNI_ANALYZE_ORIENT.\n" ) ; PRINT_COMPILE_DATE; exit(0) ; } mainENTRY("3dAFNItoANALYZE main"); machdep(); PRINT_VERSION("3dAFNItoANALYZE"); /*-- read inputs --*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-4D") == 0 ){ /* 30 Sep 2002 */ do_4D = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-orient") == 0 ){ /* 19 Mar 2003 */ char acod ; if( iarg+1 >= argc ){ fprintf(stderr,"** Need something after -orient!\n"); exit(1); } MCW_strncpy(orient_code,argv[++iarg],4) ; if( strlen(orient_code) != 3 ){ fprintf(stderr,"** Illegal code '%s' after -orient!\n",argv[iarg]); exit(1); } acod = toupper(orient_code[0]) ; xxor = ORCODE(acod) ; acod = toupper(orient_code[1]) ; yyor = ORCODE(acod) ; acod = toupper(orient_code[2]) ; zzor = ORCODE(acod) ; if( xxor<0 || yyor<0 || zzor<0 || !OR3OK(xxor,yyor,zzor) ){ fprintf(stderr,"** Unusable code after -orient!\n"); exit(1); } iarg++ ; continue ; } fprintf(stderr,"** Illegal option: %s\n",argv[iarg]); exit(1); } if( iarg >= argc-1 ){ fprintf(stderr,"** Not enough arguments on command line!\n"); exit(1); } aname = argv[iarg++] ; if( !THD_filename_ok(aname) ){ fprintf(stderr,"** Illegal aname string %s\n",aname) ; exit(1) ; } fname = malloc( strlen(aname)+16 ) ; dset = THD_open_dataset( argv[iarg++] ); CHECK_OPEN_ERROR(dset,argv[iarg-1]); if( xxor >= 0 ){ /* 19 Mar 2003: figure how to flip */ xdir = THD_get_axis_direction( dset->daxes , xxor ) ; ydir = THD_get_axis_direction( dset->daxes , yyor ) ; zdir = THD_get_axis_direction( dset->daxes , zzor ) ; if( ydir == 0 || zdir == 0 ) xdir = 0 ; if( xdir == 1 && ydir == 2 && zdir == 3 ) xdir = 0 ; } if( xdir != 0 ){ float dx=fabs(DSET_DX(dset)) , dy=fabs(DSET_DY(dset)) , dz=fabs(DSET_DZ(dset)) ; DSET_mallocize(dset) ; switch( xdir ){ case 1: case -1: xdel = dx ; break ; case 2: case -2: xdel = dy ; break ; case 3: case -3: xdel = dz ; break ; } switch( ydir ){ case 1: case -1: ydel = dx ; break ; case 2: case -2: ydel = dy ; break ; case 3: case -3: ydel = dz ; break ; } switch( zdir ){ case 1: case -1: zdel = dx ; break ; case 2: case -2: zdel = dy ; break ; case 3: case -3: zdel = dz ; break ; } } else { xdel = fabs(DSET_DX(dset)) ; ydel = fabs(DSET_DY(dset)) ; zdel = fabs(DSET_DZ(dset)) ; } DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; /* determine if we scale to floats */ scl = THD_need_brick_factor( dset ) ; /* 30 Sep 2002: if doing a 4D file, write single .hdr now */ if( do_4D ){ im = mri_empty_conforming( DSET_BRICK(dset,0) , (scl) ? MRI_float : DSET_BRICK_TYPE(dset,0) ) ; if( xdir != 0 ){ qim = mri_flip3D( xdir,ydir,zdir , im ) ; if( qim == NULL){ fprintf(stderr,"mri_flip3D fails?!\n"); exit(1); } mri_free(im); im = qim; } im->dx = xdel ; /* load voxel sizes */ im->dy = ydel ; im->dz = zdel ; im->dw = 1.0 ; if( AFNI_yesenv("AFNI_ANALYZE_ORIGINATOR") ){ im->xo = dset->daxes->xxorg ; /* load voxel origin */ im->yo = dset->daxes->yyorg ; /* 03/11/04 KRH added this bit for SPM */ im->zo = dset->daxes->zzorg ; if( ORIENT_sign[dset->daxes->xxorient] == '-' ){ im->dx = -im->dx ; /* im->xo = -im->xo ; */ } if( ORIENT_sign[dset->daxes->yyorient] == '-' ){ im->dy = -im->dy ; /* im->yo = -im->yo ; */ } if( ORIENT_sign[dset->daxes->zzorient] == '-' ){ im->dz = -im->dz ; /* im->zo = -im->zo ; */ } } im->nt = DSET_NVALS(dset) ; /* add a time axis */ im->dt = DSET_TR(dset) ; if( im->dt <= 0.0 ) im->dt = 1.0 ; if( DSET_TIMEUNITS(dset) == UNITS_MSEC_TYPE ) im->dt *= 0.001 ; /* 05 Jul 2005 */ mri_write_analyze( aname , im ) ; /* output 4D .hdr file */ mri_free(im) ; sprintf(fname,"%s.img",aname) ; /* open output .img file */ ifp = fopen( fname , "wb" ) ; if( ifp == NULL ){ fprintf(stderr,"** Can't open file %s for output!\n",fname) ; exit(1) ; } } /* loop over sub-bricks */ for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ){ im = DSET_BRICK(dset,ii) ; /* get the sub-brick */ if( scl ){ /* scale it to floats */ fac = DSET_BRICK_FACTOR(dset,ii) ; if( fac == 0.0 ) fac = 1.0 ; qim = mri_scale_to_float( fac , im ) ; } else { qim = im ; } if( xdir != 0 ){ /* 19 Mar 2003: flip it */ MRI_IMAGE *fim ; fim = mri_flip3D( xdir,ydir,zdir , qim ) ; if( fim == NULL ){ fprintf(stderr,"mri_flip3D fails at ii=%d ?!\n",ii); exit(1); } if( qim != im ) mri_free(qim) ; qim = fim ; } if( do_4D ){ /* 30 Sep 2002: write into 4D .img file */ fwrite( mri_data_pointer(qim) , qim->nvox , qim->pixel_size , ifp ) ; } else { /* write separate 3D .hdr/.img files */ qim->dx = xdel ; /* load voxel sizes */ qim->dy = ydel ; qim->dz = zdel ; qim->dw = 1.0 ; if( AFNI_yesenv("AFNI_ANALYZE_ORIGINATOR") ){ qim->xo = dset->daxes->xxorg ; /* load voxel origin */ qim->yo = dset->daxes->yyorg ; /* 03/11/04 KRH added this bit for SPM */ qim->zo = dset->daxes->zzorg ; if( ORIENT_sign[dset->daxes->xxorient] == '-' ){ qim->dx = -qim->dx ; /* qim->xo = -qim->xo ; */ } if( ORIENT_sign[dset->daxes->yyorient] == '-' ){ qim->dy = -qim->dy ; /* qim->yo = -qim->yo ; */ } if( ORIENT_sign[dset->daxes->zzorient] == '-' ){ qim->dz = -qim->dz ; /* qim->zo = -qim->zo ; */ } } sprintf(fname,"%s_%04d",aname,ii) ; /* make up a filename */ mri_write_analyze( fname , qim ) ; /* do the real work */ } if( qim != im ) mri_free(qim) ; DSET_unload_one(dset,ii) ; /* clean up the trash */ } if( ifp != NULL ) fclose(ifp) ; /* 30 Sep 2002 */ free(fname) ; exit(0) ; }
int main( int argc , char * argv[] ) { int narg , ndset , nvox , nvals,iv ; THD_3dim_dataset *xset , *yset , *mask_dset=NULL ; byte *mmm=NULL ; float met[9] ; /*-- read command line arguments --*/ if( argc < 3 || strncmp(argv[1],"-help",5) == 0 ){ printf("Usage: 3Hmetric [options] dset1 dset2\n" "Output = Histogram metrics between 2 dataset bricks\n" "Options:\n" " -mask mset Means to use the dataset 'mset' as a mask:\n" " Only voxels with nonzero values in 'mset'\n" " will be averaged from 'dataset'.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } narg = 1 ; while( narg < argc && argv[narg][0] == '-' ){ if( strncmp(argv[narg],"-mask",5) == 0 ){ if( mask_dset != NULL ) ERROR_exit("Can't use -mask twice") ; if( narg+1 >= argc ) ERROR_exit("Need argument after -mask") ; mask_dset = THD_open_dataset( argv[++narg] ) ; CHECK_OPEN_ERROR(mask_dset,argv[narg]) ; narg++ ; continue ; } ERROR_exit("Unknown option: %s",argv[narg]) ; } /* should have at least 2 more arguments */ ndset = argc - narg ; if( ndset <= 1 ) ERROR_exit("Need two input datasets") ; xset = THD_open_dataset( argv[narg++] ) ; CHECK_OPEN_ERROR(xset,argv[narg-1]) ; yset = THD_open_dataset( argv[narg++] ) ; CHECK_OPEN_ERROR(yset,argv[narg-1]) ; if( DSET_NVALS(xset) > 1 ) WARNING_message("Will only use sub-brick #0 of 1st input dataset") ; nvals = DSET_NVALS(yset) ; nvox = DSET_NVOX(xset) ; if( nvox != DSET_NVOX(yset) ) ERROR_exit("Input datasets grid dimensions don't match!\n") ; /* make a byte mask from mask dataset */ if( mask_dset != NULL ){ int mcount ; if( DSET_NVOX(mask_dset) != nvox ) ERROR_exit("Input and mask datasets are not same dimensions!\n"); DSET_load(mask_dset) ; CHECK_LOAD_ERROR(mask_dset) ; mmm = THD_makemask( mask_dset , 0 , 1.0f,-1.0f ) ; mcount = THD_countmask( nvox , mmm ) ; INFO_message("Have %d voxels in the mask\n",mcount) ; if( mcount <= 666 ) ERROR_exit("Mask is too small") ; DSET_delete(mask_dset) ; } DSET_load(xset) ; CHECK_LOAD_ERROR(xset) ; DSET_load(yset) ; CHECK_LOAD_ERROR(yset) ; printf("# LOG SQRT CBRT\n") ; for( iv=0 ; iv < nvals ; iv++ ){ mri_metrics_pp( DSET_BRICK(xset,0), DSET_BRICK(yset,iv), met, mmm ) ; printf( "%f %f %f\n",met[0],met[1],met[2]) ; } exit(0) ; }
int main( int argc , char * argv[] ) { int ninp , ids , nv , iv,jv,kv , ivout , new_nvals , have_fdr = 0, nfdr = 0 ; THD_3dim_dataset * new_dset=NULL , * dset ; char buf[256] ; double angle; /*----- identify program -----*/ #if 0 printf ("\n\nProgram %s \n", PROGRAM_NAME); printf ("Last revision: %s \n\n", LAST_MOD_DATE); #endif /*** read input options ***/ mainENTRY("3dbucket main"); machdep(); PRINT_VERSION("3dbucket") ; set_obliquity_report(0); /* silence obliquity */ /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/ { int new_argc ; char ** new_argv ; addto_args( argc , argv , &new_argc , &new_argv ) ; if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; } } AFNI_logger("3dbucket",argc,argv) ; BUCK_read_opts( argc , argv ) ; /*** create new dataset (empty) ***/ ninp = BUCK_dsar->num ; if( ninp < 1 ){ fprintf(stderr,"*** No input datasets?\n") ; exit(1) ; } new_nvals = 0 ; for( ids=0 ; ids < ninp ; ids++ ) new_nvals += NSUBV(ids) ; if( BUCK_verb ) printf("-verb: output will have %d sub-bricks\n",new_nvals) ; new_dset = EDIT_empty_copy( DSUB(0) ) ; /* 23 May 2005: check for axis consistency */ /* 06 Feb 2008: and see if there are fdrcurves to perpetuate */ if( DSUB(0)->dblk->brick_fdrcurve ) have_fdr = 1 ; for( iv=1 ; iv < ninp ; iv++ ){ if( !EQUIV_DATAXES(new_dset->daxes,DSUB(iv)->daxes) ) fprintf(stderr,"++ WARNING: %s grid mismatch with %s\n", DSET_BRIKNAME(DSUB(0)) , DSET_BRIKNAME(DSUB(iv)) ) ; if( DSUB(iv)->dblk->brick_fdrcurve ) have_fdr = 1 ; angle = dset_obliquity_angle_diff(new_dset, DSUB(iv), -1.0); if (angle > 0.0) { WARNING_message( "dataset %s has an obliquity difference of %f degress with %s\n", new_dset , angle, DSUB(iv) ); } } /* if( ninp == 1 ) */ tross_Copy_History( DSUB(0) , new_dset ) ; tross_Make_History( "3dbucket" , argc,argv , new_dset ) ; EDIT_dset_items( new_dset , ADN_prefix , BUCK_output_prefix , ADN_directory_name, BUCK_session , ADN_type , BUCK_type , ADN_func_type , ISANATTYPE(BUCK_type) ? ANAT_BUCK_TYPE : FUNC_BUCK_TYPE, ADN_ntt , 0 , ADN_nvals , new_nvals , ADN_none ) ; /* can't re-write existing dataset, unless glueing is used */ if (! BUCK_glue){ if( THD_deathcon() && THD_is_file(DSET_HEADNAME(new_dset)) ){ fprintf(stderr,"*** Fatal error: file %s already exists!\n", DSET_HEADNAME(new_dset) ) ; exit(1) ; } } else { /* if glueing is used, make the 'new' dataset have the same idcode as the old one */ new_dset->idcode = DSUB(0) -> idcode ; /* copy the struct */ } THD_force_malloc_type( new_dset->dblk , DATABLOCK_MEM_MALLOC ) ; /* if there are fdr curves, allocate space 06 Feb 2008 [rickr] */ if( have_fdr ){ new_dset->dblk->brick_fdrcurve = (floatvec **)calloc(sizeof(floatvec *), new_nvals) ; if( !new_dset->dblk->brick_fdrcurve ){ fprintf(stderr,"** failed to alloc %d fdrcurves\n",new_nvals); exit(1); } if( BUCK_verb ) printf("-verb: adding fdrcurve list\n"); new_dset->dblk->brick_mdfcurve = (floatvec **)calloc(sizeof(floatvec *), /* 22 Oct 2008 */ new_nvals) ; } /*** loop over input datasets ***/ if( ninp > 1 ) myXtFree( new_dset->keywords ) ; ivout = 0 ; for( ids=0 ; ids < ninp ; ids++ ){ dset = DSUB(ids) ; nv = NSUBV(ids) ; if( ! BUCK_dry ){ DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; } /** loop over sub-bricks to output **/ for( iv=0 ; iv < nv ; iv++ ){ jv = SUBV(ids,iv) ; /* which sub-brick to use */ if( ! BUCK_dry ){ EDIT_substitute_brick( new_dset , ivout , DSET_BRICK_TYPE(dset,jv) , DSET_ARRAY(dset,jv) ) ; /*----- preserve label when one exists --- Modified March 2010 ZSS*/ if (DSET_HAS_LABEL(dset, jv) ) sprintf (buf, "%s", DSET_BRICK_LABEL(dset,jv)); else sprintf(buf,"%.12s[%d]",DSET_PREFIX(dset),jv) ; EDIT_dset_items( new_dset , ADN_brick_label_one+ivout, buf , ADN_none ) ; #if 0 sprintf(buf,"%s[%d]",DSET_FILECODE(dset),jv) ; EDIT_dset_items( new_dset, ADN_brick_keywords_replace_one+ivout, buf, ADN_none ) ; #endif EDIT_dset_items( new_dset , ADN_brick_fac_one +ivout, DSET_BRICK_FACTOR(dset,jv), #if 0 ADN_brick_keywords_append_one+ivout, DSET_BRICK_KEYWORDS(dset,jv) , #endif ADN_none ) ; /** possibly write statistical parameters for this sub-brick **/ kv = DSET_BRICK_STATCODE(dset,jv) ; if( FUNC_IS_STAT(kv) ){ /* input sub-brick has stat params */ int npar = FUNC_need_stat_aux[kv] , lv ; float * par = (float *) malloc( sizeof(float) * (npar+2) ) ; float * sax = DSET_BRICK_STATAUX(dset,jv) ; par[0] = kv ; par[1] = npar ; for( lv=0 ; lv < npar ; lv++ ) par[lv+2] = (sax != NULL) ? sax[lv] : 0.0 ; EDIT_dset_items(new_dset , ADN_brick_stataux_one+ivout , par , ADN_none ) ; free(par) ; /* 2: if the input dataset has statistical parameters */ } else if( ISFUNC(dset) && /* dset has stat */ FUNC_IS_STAT(dset->func_type) && /* params */ jv == FUNC_ival_thr[dset->func_type] ){ /* thr sub-brick */ int npar , lv ; float * par , * sax ; kv = dset->func_type ; npar = FUNC_need_stat_aux[kv] ; par = (float *) malloc( sizeof(float) * (npar+2) ) ; sax = dset->stat_aux ; par[0] = kv ; par[1] = npar ; for( lv=0 ; lv < npar ; lv++ ) par[lv+2] = (sax != NULL) ? sax[lv] : 0.0 ; EDIT_dset_items(new_dset , ADN_brick_stataux_one+ivout , par , ADN_none ) ; free(par) ; } /** append any fdrcurve **/ if( have_fdr ){ /* fixed iv->jv (ick!), noticed by dglen 16 Mar 2010 [rickr] */ if(dset->dblk->brick_fdrcurve && dset->dblk->brick_fdrcurve[jv]){ COPY_floatvec(new_dset->dblk->brick_fdrcurve[ivout], dset->dblk->brick_fdrcurve[jv]) ; nfdr++; } else new_dset->dblk->brick_fdrcurve[ivout] = NULL ; if(dset->dblk->brick_mdfcurve && dset->dblk->brick_mdfcurve[jv]){ COPY_floatvec(new_dset->dblk->brick_mdfcurve[ivout], dset->dblk->brick_mdfcurve[jv]) ; } else new_dset->dblk->brick_mdfcurve[ivout] = NULL ; } /** print a message? **/ if( BUCK_verb ) printf("-verb: copied %s[%d] into %s[%d]\n" , DSET_FILECODE(dset) , jv , DSET_FILECODE(new_dset) , ivout ) ; } else { printf("-dry: would copy %s[%d] into %s[%d]\n" , DSET_FILECODE(dset) , jv , DSET_FILECODE(new_dset) , ivout ) ; } ivout++ ; } /** loop over all bricks in input dataset and unload them if they aren't going into the output (not required, but is done to economize on memory) **/ if( ! BUCK_dry && nv < DSET_NVALS(dset) ){ for( kv=0 ; kv < DSET_NVALS(dset) ; kv++ ){ /* all input sub-bricks */ for( iv=0 ; iv < nv ; iv++ ){ /* all output sub-bricks */ jv = SUBV(ids,iv) ; if( jv == kv ) break ; /* input matches output */ } if( iv == nv ){ mri_free( DSET_BRICK(dset,kv) ) ; #if 0 if( BUCK_verb ) printf("-verb: unloaded unused %s[%d]\n" , DSET_FILECODE(dset) , kv ) ; #endif } } } } /* end of loop over input datasets */ if( ! BUCK_dry ){ if( BUCK_verb ){ if( have_fdr ) fprintf(stderr,"-verb: added %d of %d fdr curves\n", nfdr, new_nvals); fprintf(stderr,"-verb: loading statistics\n") ; } THD_load_statistics( new_dset ) ; if( BUCK_glue ) putenv("AFNI_DECONFLICT=OVERWRITE") ; if( BUCK_glue && BUCK_ccode >= 0 ) THD_set_write_compression(BUCK_ccode) ; /* 16 Mar 2010 */ THD_write_3dim_dataset( NULL,NULL , new_dset , True ) ; if( BUCK_verb ) fprintf(stderr,"-verb: wrote output: %s\n",DSET_BRIKNAME(new_dset)) ; } exit(0) ; }
void UC_read_opts( int argc , char * argv[] ) { int nopt = 1 ; float val ; int kk, nxyz, mm,nn ; float * vv , * bb ; while( nopt < argc && argv[nopt][0] == '-' ){ /**** -verbose ****/ if( strncmp(argv[nopt],"-verbose",5) == 0 ){ UC_be_quiet = 0 ; nopt++ ; continue ; } /**** -ref file.1D ****/ if( strncmp(argv[nopt],"-ref",4) == 0 ){ MRI_IMAGE * im ; nopt++ ; if( nopt >= argc ) UC_syntax("-ref needs an argument!") ; im = mri_read( argv[nopt] ) ; if( im == NULL ) UC_syntax("Can't read -ref file!") ; if( im->kind == MRI_float ){ UC_ref = im ; } else { UC_ref = mri_to_float(im) ; mri_free(im) ; } im = mri_transpose(UC_ref) ; mri_free(UC_ref) ; UC_ref = im ; nopt++ ; continue ; } /**** -prefix prefix ****/ if( strncmp(argv[nopt],"-prefix",6) == 0 ){ nopt++ ; if( nopt >= argc ) UC_syntax("-prefix needs an argument!") ; MCW_strncpy( UC_prefix , argv[nopt++] , THD_MAX_PREFIX ) ; continue ; } /**** -mask mset ****/ if( strncmp(argv[nopt],"-mask",5) == 0 ){ THD_3dim_dataset * mset ; int ii ; nopt++ ; if( nopt >= argc ) UC_syntax("need arguments after -mask!") ; mset = THD_open_dataset( argv[nopt] ) ; if( mset == NULL ) UC_syntax("can't open -mask dataset!") ; UC_mask = THD_makemask( mset , 0 , 1.0,0.0 ) ; UC_mask_nvox = DSET_NVOX(mset) ; DSET_delete(mset) ; if( UC_mask == NULL ) UC_syntax("can't use -mask dataset!") ; UC_mask_hits = THD_countmask( UC_mask_nvox , UC_mask ) ; if( UC_mask_hits == 0 ) UC_syntax("mask is all zeros!") ; if( !UC_be_quiet ) printf("--- %d voxels in mask\n",UC_mask_hits) ; nopt++ ; continue ; } /**** unknown switch ****/ fprintf(stderr,"\n*** unrecognized option %s\n",argv[nopt]) ; exit(1) ; } /* end of loop over options */ /*--- a simple consistency check ---*/ /*--- last input is dataset name ---*/ if( nopt >= argc ) UC_syntax("no input dataset name?") ; UC_dset = THD_open_dataset( argv[nopt] ) ; if( !ISVALID_3DIM_DATASET(UC_dset) ){ fprintf(stderr,"\n*** can't open dataset file %s\n",argv[nopt]) ; exit(1) ; } nxyz = DSET_NVOX(UC_dset) ; if( UC_mask != NULL && nxyz != UC_mask_nvox ) UC_syntax("mask and input dataset size mismatch!") ; /*--- load vectors ---*/ UC_nvec = (UC_mask_hits > 0) ? UC_mask_hits : nxyz ; UC_vdim = DSET_NVALS(UC_dset) ; if( UC_vdim < 4 ) UC_syntax("input dataset needs at least 4 sub-bricks!") ; if( UC_ref == NULL || UC_ref->nx < UC_vdim ) UC_syntax("input ref not long enough for input dataset!") ; vv = (float *) malloc( sizeof(float) * UC_nvec * UC_vdim ) ; UC_vec = (float **) malloc( sizeof(float *) * UC_nvec ) ; for( kk=0 ; kk < UC_nvec ; kk++ ) UC_vec[kk] = vv + (kk*UC_vdim) ; if( !UC_be_quiet ) printf("--- reading dataset\n") ; DSET_load(UC_dset) ; CHECK_LOAD_ERROR(UC_dset) ; /* copy brick data into float storage */ if( !UC_be_quiet ) printf("--- loading vectors\n") ; bb = (float *) malloc( sizeof(float) * nxyz ) ; for( mm=0 ; mm < UC_vdim ; mm++ ){ EDIT_coerce_type( nxyz , DSET_BRICK_TYPE(UC_dset,mm) , DSET_ARRAY(UC_dset,mm) , MRI_float , bb ) ; DSET_unload_one( UC_dset , mm ) ; if( UC_mask == NULL ){ for( kk=0 ; kk < nxyz ; kk++ ) UC_vec[kk][mm] = bb[kk] ; } else { for( nn=kk=0 ; kk < nxyz ; kk++ ) if( UC_mask[kk] ) UC_vec[nn++][mm] = bb[kk] ; } } free(bb) ; DSET_unload( UC_dset ) ; /* detrend and normalize vectors */ if( !UC_be_quiet ) printf("--- normalizing vectors\n") ; for( kk=0 ; kk < UC_nvec ; kk++ ) normalize( UC_vdim , UC_vec[kk] ) ; for( kk=0 ; kk < UC_ref->ny ; kk++ ) normalize( UC_vdim , MRI_FLOAT_PTR(UC_ref) + kk*UC_ref->nx ) ; return ; }
int main(int argc, char *argv[]) { int i, k, ii; int iarg; char *prefix=NULL; char *maskname=NULL; char *gradsname=NULL; char *dtsname=NULL; THD_3dim_dataset *MASK=NULL; THD_3dim_dataset *DTS=NULL; MRI_IMAGE *GRADS=NULL, *GRADS_IN=NULL; int Ngrads=0, Nfull=0; int Nvox=-1; // tot number vox int Dim[3]={0,0,0}; // dim in each dir float NOISESCALE_DWI = -1.; float NOISESCALE_B0 = -1; float S0 = 1000.; float bval = 1.; int NOISE_IN_S0 = 0; byte *mskd2=NULL; // not great, but another format of mask float **dwi=NULL; THD_3dim_dataset *DWI_OUT=NULL; const gsl_rng_type * T; gsl_rng *r; long seed; srand(time(0)); seed = time(NULL) ; gsl_rng_env_setup(); T = gsl_rng_default; r = gsl_rng_alloc (T); gsl_rng_set (r, seed); // ################################################################### // ######################### load ################################## // ################################################################### mainENTRY("3dDTtoNoisyDWI"); machdep(); if (argc == 1) { usage_DTtoNoisyDWI(1); exit(0); } iarg = 1; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0 ) { usage_DTtoNoisyDWI(strlen(argv[iarg])>3 ? 2:1); exit(0); } if( strcmp(argv[iarg],"-dt_in") == 0) { iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-eig_vecs'"); dtsname = strdup(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-prefix'"); prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal name after '-prefix'"); iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0) { iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-mask'"); maskname = strdup(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-grads") == 0) { iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-mask'"); gradsname = strdup(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-noise_DWI") == 0) { if( ++iarg >= argc ) ERROR_exit("Need numerical argument after '-noise_DWI'"); NOISESCALE_DWI = atof(argv[iarg]); iarg++ ; continue ; } if( strcmp(argv[iarg],"-noise_B0") == 0) { if( ++iarg >= argc ) ERROR_exit("Need numerical argument after '-noise_B0'"); NOISESCALE_B0 = atof(argv[iarg]); iarg++ ; continue ; } if( strcmp(argv[iarg],"-S0") == 0) { if( ++iarg >= argc ) ERROR_exit("Need numerical argument after '-S0'"); S0 = atof(argv[iarg]); if(S0 <= 0 ) ERROR_exit("The '-S0' value must be >0."); iarg++ ; continue ; } if( strcmp(argv[iarg],"-bval") == 0) { if( ++iarg >= argc ) ERROR_exit("Need numerical argument after '-bval'"); bval = atof(argv[iarg]); if(bval <= 0 ) ERROR_exit("The '-bval' value must be >0."); iarg++ ; continue ; } ERROR_message("Bad option '%s'\n",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } // ################################################################### // #################### some checks ############################### // ################################################################### if(!prefix) ERROR_exit("Need to give a '-prefix'."); if(!dtsname) ERROR_exit("Need to input diffusion tensor file after '-dt_in'."); if(!gradsname) ERROR_exit("Need to input gradient file after '-grads'."); if( NOISESCALE_DWI<0 ) ERROR_exit("Fractional noise value after '-snr0' needs to be >0. " "It sets the noise scale of ref signal S0."); if(NOISESCALE_DWI > 0) INFO_message("You have chosen an SNR0 of approximately %.2f for DWIs", 1./NOISESCALE_DWI); else INFO_message("You have noiseless (i.e., infinite SNR) set of DWIs"); if( NOISESCALE_B0 < 0 ) NOISESCALE_B0 = NOISESCALE_DWI; if(NOISESCALE_B0 > 0) INFO_message("You have chosen an SNR0 of approximately %.2f for the B0", 1./NOISESCALE_B0); else INFO_message("You have noiseless (i.e., infinite SNR) reference B0."); // ################################################################### if(dtsname) { DTS = THD_open_dataset(dtsname); DSET_load(DTS); CHECK_LOAD_ERROR(DTS); if( 6 != DSET_NVALS(DTS) ) ERROR_exit("DT file '%s' must have 6 bricks-- " "it has %d bricks!", dtsname, DSET_NVALS(DTS)); } Nvox = DSET_NVOX(DTS); Dim[0] = DSET_NX(DTS); Dim[1] = DSET_NY(DTS); Dim[2] = DSET_NZ(DTS); if(Nvox<0) ERROR_exit("Error reading Nvox from eigenvalue file."); mskd2 = (byte *)calloc(Nvox,sizeof(byte)); if( (mskd2 == NULL)) { fprintf(stderr, "\n\n MemAlloc failure (masks).\n\n"); exit(122); } if(maskname) { MASK = THD_open_dataset(maskname); DSET_load(MASK); CHECK_LOAD_ERROR(MASK); if( 1 != DSET_NVALS(MASK) ) ERROR_exit("Mask file '%s' is not scalar-- " "it has %d bricks!", maskname, DSET_NVALS(MASK)); for( k=0 ; k<Nvox ; k++ ) if (THD_get_voxel(MASK, k, 0) > 0 ) mskd2[k] = 1; DSET_delete(MASK); free(MASK); free(maskname); } else { for( k=0 ; k<Nvox ; k++ ) if( fabs(THD_get_voxel(DTS,k,0) > EPS_V) ) mskd2[k] = 1; } GRADS_IN = mri_read_1D (gradsname); GRADS = mri_transpose(GRADS_IN); // get rid of autotranspose... if (GRADS == NULL) ERROR_exit("Error reading gradient vector file"); mri_free(GRADS_IN); Ngrads = GRADS->ny; if(Ngrads < 6) ERROR_exit("Too few grads (there appear to be only %d).",Ngrads); if(GRADS->nx !=3 ) ERROR_exit("Wrong number of columns in the grad file: " " am reading %d instead of 3.",GRADS->nx); Nfull = Ngrads+1; INFO_message("Have surmised there are %d total grads; " "output file will have %d bricks", Ngrads,Nfull); dwi = calloc(Nfull,sizeof(dwi)); for(i=0 ; i<Nfull ; i++) dwi[i] = calloc( Nvox,sizeof(float)); INFO_message("Calculating the DWIs."); i = RicianNoiseDWIs( dwi, Nvox, Ngrads, DTS, NOISESCALE_DWI, NOISESCALE_B0, GRADS, mskd2, S0, bval, r); INFO_message("Writing the DWIs."); DWI_OUT = EDIT_empty_copy( DTS ); EDIT_dset_items(DWI_OUT, ADN_nvals, Nfull, ADN_datum_all, MRI_float , ADN_prefix, prefix, ADN_none ); for( i=0; i<Nfull ; i++) { EDIT_substitute_brick(DWI_OUT, i, MRI_float, dwi[i]); dwi[i]=NULL; } THD_load_statistics( DWI_OUT ); if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(DWI_OUT)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(DWI_OUT)); tross_Make_History("3dDTtoNoisyDWI", argc, argv, DWI_OUT); THD_write_3dim_dataset(NULL, NULL, DWI_OUT, True); DSET_delete(DWI_OUT); free(DWI_OUT); // ################################################################# // ########################## free ############################### // ################################################################# DSET_delete(DTS); free(DTS); for( i=0 ; i<Nfull ; i++) free(dwi[i]); free(dwi); free(prefix); free(gradsname); free(dtsname); mri_free(GRADS); return 0; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0 , automask=0 , masknum=0 ; int iarg=1 , verb=1 , ntype=0 , nev,kk,ii,nxyz,nt ; float na,nb,nc , dx,dy,dz ; MRI_IMARR *imar=NULL ; int *ivox ; MRI_IMAGE *pim ; int do_vmean=0 , do_vnorm=0 , sval_itop=0 ; int polort=-1 ; float *ev ; MRI_IMARR *ortar ; MRI_IMAGE *ortim ; int nyort=0 ; float bpass_L=0.0f , bpass_H=0.0f , dtime ; int do_bpass=0 ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dmaskSVD [options] inputdataset\n" "Author: Zhark the Gloriously Singular\n" "\n" "* Computes the principal singular vector of the time series\n" " vectors extracted from the input dataset over the input mask.\n" " ++ You can use the '-sval' option to change which singular\n" " vectors are output.\n" "* The sign of the output vector is chosen so that the average\n" " of arctanh(correlation coefficient) over all input data\n" " vectors (from the mask) is positive.\n" "* The output vector is normalized: the sum of its components\n" " squared is 1.\n" "* You probably want to use 3dDetrend (or something similar) first,\n" " to get rid of annoying artifacts, such as motion, breathing,\n" " dark matter interactions with the brain, etc.\n" " ++ If you are lazy scum like Zhark, you might be able to get\n" " away with using the '-polort' option.\n" " ++ In particular, if your data time series has a nonzero mean,\n" " then you probably want at least '-polort 0' to remove the\n" " mean, otherwise you'll pretty much just get a constant\n" " time series as the principal singular vector!\n" "* An alternative to this program would be 3dmaskdump followed\n" " by 1dsvd, which could give you all the singular vectors you\n" " could ever want, and much more -- enough to confuse you for days.\n" " ++ In particular, although you COULD input a 1D file into\n" " 3dmaskSVD, the 1dsvd program would make much more sense.\n" "* This program will be pretty slow if there are over about 2000\n" " voxels in the mask. It could be made more efficient for\n" " such cases, but you'll have to give Zhark some 'incentive'.\n" "* Result vector goes to stdout. Redirect per your pleasures and needs.\n" "* Also see program 3dLocalSVD if you want to compute the principal\n" " singular time series vector from a neighborhood of EACH voxel.\n" " ++ (Which is a pretty slow operation!)\n" "* http://en.wikipedia.org/wiki/Singular_value_decomposition\n" "\n" "-------\n" "Options:\n" "-------\n" " -vnorm = L2 normalize all time series before SVD [recommended!]\n" " -sval a = output singular vectors 0 .. a [default a=0 = first one only]\n" " -mask mset = define the mask [default is entire dataset == slow!]\n" " -automask = you'll have to guess what this option does\n" " -polort p = if you are lazy and didn't run 3dDetrend (like Zhark)\n" " -bpass L H = bandpass [mutually exclusive with -polort]\n" " -ort xx.1D = time series to remove from the data before SVD-ization\n" " ++ You can give more than 1 '-ort' option\n" " ++ 'xx.1D' can contain more than 1 column\n" " -input ddd = alternative way to give the input dataset name\n" "\n" "-------\n" "Example:\n" "-------\n" " You have a mask dataset with discrete values 1, 2, ... 77 indicating\n" " some ROIs; you want to get the SVD from each ROI's time series separately,\n" " and then put these into 1 big 77 column .1D file. You can do this using\n" " a csh shell script like the one below:\n" "\n" " # Compute the individual SVD vectors\n" " foreach mm ( `count 1 77` )\n" " 3dmaskSVD -vnorm -mask mymask+orig\"<${mm}..${mm}>\" epi+orig > qvec${mm}.1D\n" " end\n" " # Glue them together into 1 big file, then delete the individual files\n" " 1dcat qvec*.1D > allvec.1D\n" " /bin/rm -f qvec*.1D\n" " # Plot the results to a JPEG file, then compute their correlation matrix\n" " 1dplot -one -nopush -jpg allvec.jpg allvec.1D\n" " 1ddot -terse allvec.1D > allvec_COR.1D\n" "\n" " [[ If you use the bash shell, you'll have to figure out the syntax ]]\n" " [[ yourself. Zhark has no sympathy for you bash shell infidels, and ]]\n" " [[ considers you only slightly better than those lowly Emacs users. ]]\n" " [[ And do NOT ever even mention 'nedit' in Zhark's august presence! ]]\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dmaskSVD"); mainENTRY("3dmaskSVD main"); machdep(); AFNI_logger("3dmaskSVD",argc,argv); AUTHOR("Zhark the Singular"); /*---- loop over options ----*/ INIT_IMARR(ortar) ; mpv_sign_meth = AFNI_yesenv("AFNI_3dmaskSVD_meansign") ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcasecmp(argv[iarg],"-bpass") == 0 ){ if( iarg+2 >= argc ) ERROR_exit("need 2 args after -bpass") ; bpass_L = (float)strtod(argv[++iarg],NULL) ; bpass_H = (float)strtod(argv[++iarg],NULL) ; if( bpass_L < 0.0f || bpass_H <= bpass_L ) ERROR_exit("Illegal values after -bpass: %g %g",bpass_L,bpass_H) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-ort") == 0 ){ /* 01 Oct 2009 */ int nx,ny ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-ort'") ; ortim = mri_read_1D( argv[iarg] ) ; if( ortim == NULL ) ERROR_exit("-ort '%s': Can't read 1D file",argv[iarg]) ; nx = ortim->nx ; ny = ortim->ny ; if( nx == 1 && ny > 1 ){ MRI_IMAGE *tim=mri_transpose(ortim); mri_free(ortim); ortim = tim; ny = 1; } mri_add_name(argv[iarg],ortim) ; ADDTO_IMARR(ortar,ortim) ; nyort += ny ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *qpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-polort'") ; polort = (int)strtod(argv[iarg],&qpt) ; if( *qpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-vnorm") == 0 ){ do_vnorm = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have two -input options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-input'") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-sval") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-sval'") ; sval_itop = (int)strtod(argv[iarg],NULL) ; if( sval_itop < 0 ){ sval_itop = 0 ; WARNING_message("'-sval' reset to 0") ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; int mmm ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ; masknum = mmm = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; INFO_message("Number of voxels in mask = %d",mmm) ; if( mmm < 2 ) ERROR_exit("Mask is too small to process") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't have two mask inputs!") ; automask = 1 ; iarg++ ; continue ; } ERROR_exit("Unknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ /*---- deal with input dataset ----*/ if( inset == NULL ){ if( iarg >= argc ) ERROR_exit("No input dataset on command line?") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; } nt = DSET_NVALS(inset) ; /* vector lengths */ if( nt < 9 ) ERROR_exit("Must have at least 9 values per voxel") ; if( polort+1 >= nt ) ERROR_exit("'-polort %d' too big for time series length = %d",polort,nt) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; nxyz = DSET_NVOX(inset) ; DSET_UNMSEC(inset) ; dtime = DSET_TR(inset) ; if( dtime <= 0.0f ) dtime = 1.0f ; do_bpass = (bpass_L < bpass_H) ; if( do_bpass ){ kk = THD_bandpass_OK( nt , dtime , bpass_L , bpass_H , 1 ) ; if( kk <= 0 ) ERROR_exit("Can't continue since -bpass setup is illegal") ; polort = -1 ; } /*--- deal with the masking ---*/ if( mask != NULL ){ if( mask_nx != DSET_NX(inset) || mask_ny != DSET_NY(inset) || mask_nz != DSET_NZ(inset) ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( automask ){ int mmm ; mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; masknum = mmm = THD_countmask( DSET_NVOX(inset) , mask ) ; INFO_message("Number of voxels in automask = %d",mmm) ; if( mmm < 9 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nxyz) ; masknum = nxyz ; memset( mask , 1 , sizeof(byte)*nxyz ) ; INFO_message("Using all %d voxels in dataset",nxyz) ; } nev = MIN(nt,masknum) ; /* max possible number of eigenvalues */ if( sval_itop >= nev ){ sval_itop = nev-1 ; WARNING_message("'-sval' reset to '%d'",sval_itop) ; } mri_principal_vector_params( 0 , do_vnorm , sval_itop ) ; mri_principal_setev(nev) ; /*-- get data vectors --*/ ivox = (int *)malloc(sizeof(int)*masknum) ; for( kk=ii=0 ; ii < nxyz ; ii++ ) if( mask[ii] ) ivox[kk++] = ii ; INFO_message("Extracting data vectors") ; imar = THD_extract_many_series( masknum, ivox, inset ) ; DSET_unload(inset) ; if( imar == NULL ) ERROR_exit("Can't get data vector?!") ; /*-- detrending --*/ if( polort >= 0 || nyort > 0 || do_bpass ){ float **polref=NULL ; float *tsar ; int nort=IMARR_COUNT(ortar) , nref=0 ; if( polort >= 0 ){ /* polynomials */ nref = polort+1 ; polref = THD_build_polyref(nref,nt) ; } if( nort > 0 ){ /* other orts */ float *oar , *par ; int nx,ny , qq,tt ; for( kk=0 ; kk < nort ; kk++ ){ /* loop over input -ort files */ ortim = IMARR_SUBIM(ortar,kk) ; nx = ortim->nx ; ny = ortim->ny ; if( nx < nt ) ERROR_exit("-ort '%s' length %d shorter than dataset length %d" , ortim->name , nx , nt ) ; polref = (float **)realloc(polref,(nref+ny)*sizeof(float *)) ; oar = MRI_FLOAT_PTR(ortim) ; for( qq=0 ; qq < ny ; qq++,oar+=nx ){ par = polref[nref+qq] = (float *)malloc(sizeof(float)*nt) ; for( tt=0 ; tt < nt ; tt++ ) par[tt] = oar[tt] ; if( polort == 0 ) THD_const_detrend (nt,par,NULL) ; else if( polort > 0 ) THD_linear_detrend(nt,par,NULL,NULL) ; } nref += ny ; } DESTROY_IMARR(ortar) ; } if( !do_bpass ){ /* old style ort-ification */ MRI_IMAGE *imq , *imp ; float *qar ; INFO_message("Detrending data vectors") ; #if 1 imq = mri_new( nt , nref , MRI_float) ; qar = MRI_FLOAT_PTR(imq) ; for( kk=0 ; kk < nref ; kk++ ) memcpy( qar+kk*nt , polref[kk] , sizeof(float)*nt ) ; imp = mri_matrix_psinv( imq , NULL , 1.e-8 ) ; for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ){ mri_matrix_detrend( IMARR_SUBIM(imar,kk) , imq , imp ) ; } mri_free(imp) ; mri_free(imq) ; #else for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ){ tsar = MRI_FLOAT_PTR(IMARR_SUBIM(imar,kk)) ; THD_generic_detrend_LSQ( nt , tsar , -1 , nref , polref , NULL ) ; } #endif } else { /* bandpass plus (maybe) orts */ float **vec = (float **)malloc(sizeof(float *)*IMARR_COUNT(imar)) ; INFO_message("Bandpassing data vectors") ; for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ) vec[kk] = MRI_FLOAT_PTR(IMARR_SUBIM(imar,kk)) ; (void)THD_bandpass_vectors( nt , IMARR_COUNT(imar) , vec , dtime , bpass_L , bpass_H , 2 , nref , polref ) ; free(vec) ; } for( kk=0 ; kk < nref; kk++ ) free(polref[kk]) ; free(polref) ; } /* end of detrendization */ /*--- the actual work ---*/ INFO_message("Computing SVD") ; pim = mri_principal_vector( imar ) ; DESTROY_IMARR(imar) ; if( pim == NULL ) ERROR_exit("SVD failure!?!") ; ev = mri_principal_getev() ; switch(sval_itop+1){ case 1: INFO_message("First singular value: %g",ev[0]) ; break ; case 2: INFO_message("First 2 singular values: %g %g",ev[0],ev[1]) ; break ; case 3: INFO_message("First 3 singular values: %g %g %g",ev[0],ev[1],ev[2]) ; break ; case 4: INFO_message("First 4 singular values: %g %g %g %g",ev[0],ev[1],ev[2],ev[3]) ; break ; default: case 5: INFO_message("First 5 singular values: %g %g %g %g %g",ev[0],ev[1],ev[2],ev[3],ev[4]) ; break ; } mri_write_1D(NULL,pim) ; exit(0) ; }
int main( int argc , char *argv[] ) { MRI_IMAGE *xim , *yim ; float *xar , *yar , *war ; int iarg , ndset , nvox , ii , jj, xyall , clip=0 ; THD_3dim_dataset *xset , *yset , * mask_dset=NULL ; float xbot=1.0f,xtop=0.0f , ybot=1.0f,ytop=0.0f , val ; float xsum,ysum , xsig,ysig ; byte *mmm=NULL ; char *save_hist=NULL, *save_hist_1D=NULL ; /*-- read command line arguments --*/ if( argc < 3 || strncmp(argv[1],"-help",5) == 0 ){ printf("Usage: 3dAcost [options] xset yset\n" "Output = 3dAllineate cost functions between 2 dataset bricks\n" " (for debugging purposes, mostly).\n" "\n" "Options:\n" " -mask mset Means to use the dataset 'mset' as a mask:\n" " Only voxels with nonzero values in 'mset'\n" " will be averaged from 'dataset'. Note\n" " that the mask dataset and the input dataset\n" " must have the same number of voxels.\n" " -histpow p Set histogram power to 'p'; number of bins in\n" " histogram (each axis) = n^p (n=# of points).\n" " (Default is p=0.33333.)\n" " -histbin m Set histogram to use 'm' bins (each axis).\n" " (Max number of bins is 255.)\n" " -savehist ss Save 2D histogram to image file 'ss'\n" " (floating point image; read with 'afni -im')\n" " -savehist_1D dd Save original form of 2D histogram to 1D file 'dd'\n" " (-savehist produces the rootogram)\n" " -xrange a b Use only xset values in range a..b.\n" " -yrange c d Use only yset values in range c..d.\n" " (Default is to use all values.)\n" " -clip Use values from min to mri_topclip()\n" ) ; exit(0) ; } iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-xrange") == 0 ){ if( ++iarg >= argc-1 ) ERROR_exit("no arguments after '%s'!",argv[iarg-1]) ; xbot = (float)strtod(argv[iarg++],NULL) ; xtop = (float)strtod(argv[iarg++],NULL) ; continue ; } if( strcmp(argv[iarg],"-yrange") == 0 ){ if( ++iarg >= argc-1 ) ERROR_exit("no arguments after '%s'!",argv[iarg-1]) ; ybot = (float)strtod(argv[iarg++],NULL) ; ytop = (float)strtod(argv[iarg++],NULL) ; continue ; } if( strcmp(argv[iarg],"-clip") == 0 ){ clip = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-savehist") == 0 ){ if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; if( !THD_filename_ok(argv[iarg]) ) ERROR_exit("badly formed filename: '%s' '%s'",argv[iarg-1],argv[iarg]); save_hist = argv[iarg] ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-savehist_1D") == 0 ){ if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; save_hist_1D= argv[iarg] ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-histpow") == 0 ){ double hist_pow ; if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; hist_pow = strtod(argv[iarg],NULL) ; set_2Dhist_hpower(hist_pow) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-histbin") == 0 ){ int hist_nbin ; if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; hist_nbin = (int)strtod(argv[iarg],NULL) ; set_2Dhist_hbin(hist_nbin) ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mask",5) == 0 ){ if( mask_dset != NULL ) ERROR_exit("Can't use -mask twice!") ; if( iarg+1 >= argc ) ERROR_exit("-mask needs a filename!") ; mask_dset = THD_open_dataset( argv[++iarg] ) ; CHECK_OPEN_ERROR(mask_dset,argv[iarg]) ; iarg++ ; continue ; } fprintf(stderr,"*** Unknown option: %s\n",argv[iarg]) ; exit(1) ; } /* should have at least 2 more arguments */ ndset = argc - iarg ; if( ndset <= 1 ){ fprintf(stderr,"*** No input datasets!?\n") ; exit(1) ; } xset = THD_open_dataset(argv[iarg++]) ; CHECK_OPEN_ERROR(xset,argv[iarg-1]) ; yset = THD_open_dataset(argv[iarg++]) ; CHECK_OPEN_ERROR(yset,argv[iarg-1]) ; DSET_load(xset) ; DSET_load(yset) ; CHECK_LOAD_ERROR(xset) ; CHECK_LOAD_ERROR(yset) ; if( DSET_NVALS(xset) > 1 || DSET_NVALS(yset) > 1 ) WARNING_message("Using only sub-brick [0] of input datasets") ; nvox = DSET_NVOX(xset) ; if( nvox != DSET_NVOX(yset) ) ERROR_exit("Input datasets dimensions don't match!") ; xim = mri_scale_to_float( DSET_BRICK_FACTOR(xset,0) , DSET_BRICK(xset,0) ); yim = mri_scale_to_float( DSET_BRICK_FACTOR(yset,0) , DSET_BRICK(yset,0) ); xar = MRI_FLOAT_PTR(xim) ; yar = MRI_FLOAT_PTR(yim) ; DSET_unload(xset); DSET_unload(yset); /* make a byte mask from mask dataset */ war = (float *)malloc(sizeof(float)*nvox) ; if( mask_dset != NULL ){ int mcount ; if( DSET_NVOX(mask_dset) != nvox ) ERROR_exit("Input and mask datasets are not same dimensions!"); mmm = THD_makemask( mask_dset , 0 , 666.0,-666.0 ) ; mcount = THD_countmask( nvox , mmm ) ; if( mcount <= 5 ) ERROR_exit("Mask is too small: %d voxels",mcount) ; DSET_delete(mask_dset) ; for( ii=0 ; ii < nvox ; ii++ ) war[ii] = (float)mmm[ii] ; free((void *)mmm) ; } else { for( ii=0 ; ii < nvox ; ii++ ) war[ii] = 1.0f ; } if( clip ){ xbot = mri_min(xim) ; xtop = mri_topclip(xim) ; INFO_message("xbot=%g xclip=%g",xbot,xtop) ; ybot = mri_min(yim) ; ytop = mri_topclip(yim) ; INFO_message("ybot=%g yclip=%g",ybot,ytop) ; } xyall = 0 ; if( xbot >= xtop ){ xbot = 1.e+38 ; xtop = -1.e+38 ; for( ii=0 ; ii < nvox ; ii++ ) if( war[ii] > 0.0f ){ if( xar[ii] < xbot ) xbot = xar[ii] ; else if( xar[ii] > xtop ) xtop = xar[ii] ; } INFO_message("xbot=%g xtop=%g",xbot,xtop) ; if( xbot >= xtop ) ERROR_exit("no x range?!") ; xyall++ ; } if( ybot >= ytop ){ ybot = 1.e+38 ; ytop = -1.e+38 ; for( ii=0 ; ii < nvox ; ii++ ) if( war[ii] > 0.0f ){ if( yar[ii] < ybot ) ybot = yar[ii] ; else if( yar[ii] > ytop ) ytop = yar[ii] ; } INFO_message("ybot=%g ytop=%g",ybot,ytop) ; if( ybot >= ytop ) ERROR_exit("no y range?!") ; xyall++ ; } if( xyall < 2 ){ for( ii=0 ; ii < nvox ; ii++ ) if( xar[ii] < xbot || xar[ii] > xtop || yar[ii] < ybot || yar[ii] > ytop ) war[ii] = 0.0f ; } xyall = 0 ; for( ii=0 ; ii < nvox ; ii++ ) xyall += (war[ii] > 0.0f) ; INFO_message("Processing %d voxels",xyall) ; if( xyall <= 5 ) ERROR_exit("Too few voxels to continue!") ; xsum = ysum = 0.0f ; for( ii=0 ; ii < nvox ; ii++ ){ if( war[ii] > 0.0f ){ xsum += xar[ii]; ysum += yar[ii]; } } xsum /= xyall ; ysum /= xyall ; INFO_message("xmean=%g ymean=%g",xsum,ysum) ; xsig = ysig = 0.0f ; for( ii=0 ; ii < nvox ; ii++ ){ if( war[ii] > 0.0f ){ val = (xar[ii]-xsum) ; xsig += val*val ; val = (yar[ii]-ysum) ; ysig += val*val ; } } xsig = sqrt( xsig/(xyall-1.0) ); ysig = sqrt( ysig/(xyall-1.0) ); INFO_message("xsig =%g ysig =%g",xsig,ysig) ; val = THD_pearson_corr_wt( nvox , xar , yar , war ) ; val = 1.0 - fabs(val) ; printf("1-Correlation = %+.5f\n",val) ; val = -THD_mutual_info_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; printf("-Mutual Info = %+.5f\n",val ) ; val = THD_norm_mutinf_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; printf("Norm Mutual Info = %+.5f\n",val ) ; #if 0 INFO_message("THD_corr_ratio_scl(%d,%g,%g,xar,%g,%g,yar,war)", nvox , xbot,xtop , ybot,ytop ) ; #endif THD_corr_ratio_sym_mul ; val = THD_corr_ratio_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; val = 1.0 - fabs(val) ; printf("1-Corr ratio sym* = %+.5f\n",val) ; THD_corr_ratio_sym_add ; val = THD_corr_ratio_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; val = 1.0 - fabs(val) ; printf("1-Corr ratio sym+ = %+.5f\n",val) ; THD_corr_ratio_sym_not ; val = THD_corr_ratio_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; val = 1.0 - fabs(val) ; printf("1-Corr ratio unsym= %+.5f\n",val) ; val = -THD_hellinger_scl( nvox , xbot,xtop,xar , ybot,ytop,yar , war ) ; printf("-Hellinger metric = %+.5f\n",val) ; if( save_hist != NULL ){ /* Save 2D histogram */ int nbin ; float *xyc ; nbin = retrieve_2Dhist( &xyc ) ; if( nbin > 0 && xyc != NULL ){ MRI_IMAGE *fim,*qim ; double ftop ; fim = mri_new(nbin,nbin,MRI_float); mri_fix_data_pointer(xyc,fim); #if 0 for( ii=0 ; ii < nbin*nbin ; ii++ ) xyc[ii] = sqrtf(xyc[ii]) ; ftop = mri_max(fim); if( ftop == 0.0 ) ftop = 1.0; qim = mri_to_byte_scl(255.4/ftop,0.0,fim) ; mri_clear_data_pointer(fim); mri_free(fim); fim = mri_flippo(MRI_ROT_180,1,qim); mri_free(qim); mri_write_pnm(save_hist,fim); mri_free(fim); #else qim = mri_flippo(MRI_ROT_180,1,fim); mri_clear_data_pointer(fim); mri_free(fim); mri_write(save_hist,qim); mri_free(qim); #endif INFO_message("- Saved %dx%d histogram to %s",nbin,nbin,save_hist) ; } } if( save_hist_1D != NULL ){ /* Save 2D raw histogram */ int nbin ; float *xyc ; nbin = retrieve_2Dhist( &xyc ) ; if( nbin > 0 && xyc != NULL ){ FILE *fid=fopen(save_hist_1D,"w"); for( ii=0 ; ii < nbin; ii++ ) { for( jj=0 ; jj < nbin; jj++ ) { fprintf(fid,"%.4f\t", xyc[ii*nbin+jj]); } fprintf(fid,"\n"); } fclose(fid); } INFO_message("- Saved %dx%d 1D histogram to %s",nbin,nbin,save_hist_1D) ; } exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *old_dset=NULL , *new_dset=NULL ; char *prefix = "Filtered" ; int hh=0 ; int nvals , nopt ; if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf( "\n" "3dTfilter takes as input a dataset, filters the time series in\n" "each voxel as ordered by the user, and outputs a new dataset.\n" "The data in each voxel is processed separately.\n" "\n" "The user (you?) specifies the filter functions to apply.\n" "They are applied in the order given on the command line:\n" " -filter rank -filter adaptive:7\n" "means to do the following operations\n" " (1) turn the data into ranks\n" " (2) apply the adaptive mean filter to the ranks\n" "\n" "Notes:\n" "------\n" "** This program is a work in progress, and more capabilities\n" " will be added as time allows, as the need arises, and as\n" " the author's whims bubble to the surface of his febrile brain.\n" "\n" "** This program is for people who have Sisu.\n" "\n" "Options:\n" "--------\n" "\n" " -input inputdataset\n" "\n" " -prefix outputdataset\n" "\n" " -filter FunctionName\n" " At least one '-filter' option is required!\n" " The FunctionName values that you can give are:\n" "\n" " rank = smallest value is replaced by 0,\n" " next smallest value by 1, and so forth.\n" " ** This filter is pretty useless.\n" "\n" " adaptive:H = adaptive mean filter with half-width of\n" " 'H' time points (H > 0).\n" " ** At most one 'adaptive' filter can be used!\n" " ** The filter 'footprint' is 2*H+1 points.\n" " ** This filter does local smoothing over the\n" " 'footprint', with values far away from\n" " the local median being weighted less.\n" "\n" " detrend:P = (least squares) detrend with polynomials of up\n" " order 'P' for P=0, 1, 2, ....\n" " ** At most one 'detrend' filter can be used!\n" "\n" " despike = apply the 'NEW25' despiking algorithm, as in\n" " program 3dDespike.\n" "\n" "Example:\n" "--------\n" " 3dTfilter -input fred.nii -prefix fred.af.nii -filter adaptive:7\n" "\n" "-------\n" "Author: The Programmer with No Name\n" "-------\n" "\n" ) ; exit(0) ; } /* bureaucracy */ mainENTRY("3dTfilter main"); machdep(); AFNI_logger("3dTfilter",argc,argv); PRINT_VERSION("3dTfilter"); AUTHOR("Thorby Baslim"); /*--- scan command line for options ---*/ nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ /*-- prefix --*/ if( strcasecmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("%s needs an argument!",argv[nopt-1]); prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("%s is not a valid prefix!",prefix); nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-input") == 0 || strcasecmp(argv[nopt],"-inset") == 0 ){ if( ++nopt >= argc ) ERROR_exit("%s needs an argument!",argv[nopt-1]); if( old_dset != NULL ) ERROR_exit("you can't have 2 input datasets!") ; old_dset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(old_dset,argv[nopt]) ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-filter") == 0 ){ if( ++nopt >= argc ) ERROR_exit("%s needs an argument!",argv[nopt-1]); if( strcasecmp(argv[nopt],"rank") == 0 ){ ADD_FILTER(rank_order_float) ; INFO_message("Filter #%d = rank",nffunc) ; } else if( strncasecmp(argv[nopt],"adaptive:",9) == 0 ){ char *cpt=argv[nopt]+9 ; if( hh > 0 ) ERROR_exit("You can't use more than one 'adaptive' filter :(") ; if( !isdigit(*cpt) ) ERROR_exit("'%s' is not a valid 'adaptive' filter name",argv[nopt]) ; hh = (int)strtod(cpt,NULL) ; if( hh > 29 ) WARNING_message("Very long filter '%s' will be very slow",argv[nopt]) ; else if( hh <= 0 ) ERROR_exit("'%s' is not a legal 'adaptive' filter name",argv[nopt]) ; ADD_FILTER(adaptive_filter) ; INFO_message("Filter #%d = adaptive:%d",nffunc,hh) ; } else if( strncasecmp(argv[nopt],"detrend:",8) == 0 ){ char *cpt=argv[nopt]+8 ; if( polort > 0 ) ERROR_exit("You can't use more than one 'detrend' filter :(") ; if( !isdigit(*cpt) ) ERROR_exit("'%s' is not a valid 'detrend' filter name",argv[nopt]) ; polort = (int)strtod(cpt,NULL) ; if( polort < 0 ) ERROR_exit("'%s' is not a legal 'detrend' filter name",argv[nopt]) ; ADD_FILTER(polort_filter) ; INFO_message("Filter #%d = detrend:%d",nffunc,polort) ; } else if( strcasecmp(argv[nopt],"despike") == 0 ){ ADD_FILTER(DES_despike25) ; INFO_message("Filter #%d = despike",nffunc) ; } else { ERROR_exit("Unkown filter type '%s'",argv[nopt]) ; } nopt++ ; continue ; } ERROR_exit("Unknown option: '%s'",argv[nopt]) ; } if( nffunc == 0 ) ERROR_exit("No -filter options given !? :(") ; if( old_dset == NULL ){ if( nopt >= argc ) ERROR_exit("no input dataset?") ; old_dset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(old_dset,argv[nopt]) ; } nvals = DSET_NVALS(old_dset) ; if( nvals < 2 ) ERROR_exit("Input dataset too short to filter!") ; if( hh > 0 ) setup_adaptive_filter( hh , nvals ) ; INFO_message("Load input dataset") ; DSET_load(old_dset) ; CHECK_LOAD_ERROR(old_dset) ; /** do the work **/ INFO_message("Start processing") ; new_dset = MAKER_4D_to_typed_fbuc( old_dset , /* input dataset */ prefix , /* output prefix */ MRI_float , /* output datum */ 0 , /* ignore count */ 0 , /* don't detrend */ nvals , /* number of briks */ FILTER_tsfunc , /* timeseries processor */ NULL, /* data for tsfunc */ NULL, /* mask */ 0 /* Allow auto scaling of output */ ) ; DSET_unload(old_dset) ; if( new_dset != NULL ){ tross_Copy_History( old_dset , new_dset ) ; tross_Make_History( "3dTfilter" , argc,argv , new_dset ) ; if( DSET_NUM_TIMES(old_dset) > 1 ) EDIT_dset_items( new_dset , ADN_ntt , DSET_NVALS(old_dset) , 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!\n") ; } exit(0) ; }
int main( int argc , char * argv[] ) { int do_norm=0 , qdet=2 , have_freq=0 , do_automask=0 ; float dt=0.0f , fbot=0.0f,ftop=999999.9f , blur=0.0f ; MRI_IMARR *ortar=NULL ; MRI_IMAGE *ortim=NULL ; THD_3dim_dataset **ortset=NULL ; int nortset=0 ; THD_3dim_dataset *inset=NULL , *outset=NULL; char *prefix="RSFC" ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0,nmask , verb=1 , nx,ny,nz,nvox , nfft=0 , kk ; float **vec , **ort=NULL ; int nort=0 , vv , nopt , ntime ; MRI_vectim *mrv ; float pvrad=0.0f ; int nosat=0 ; int do_despike=0 ; // @@ non-BP variables float fbotALL=0.0f, ftopALL=999999.9f; // do full range version int NumDen = 0; // switch for doing numerator or denom THD_3dim_dataset *outsetALL=NULL ; int m, mm; float delf; // harmonics int ind_low,ind_high,N_ny, ctr; float sqnt,nt_fac; gsl_fft_real_wavetable *real1, *real2; // GSL stuff gsl_fft_real_workspace *work; double *series1, *series2; double *xx1,*xx2; float numer,denom,val; float *alff=NULL,*malff=NULL,*falff=NULL, *rsfa=NULL,*mrsfa=NULL,*frsfa=NULL; // values float meanALFF=0.0f,meanRSFA=0.0f; // will be for mean in brain region THD_3dim_dataset *outsetALFF=NULL; THD_3dim_dataset *outsetmALFF=NULL; THD_3dim_dataset *outsetfALFF=NULL; THD_3dim_dataset *outsetRSFA=NULL; THD_3dim_dataset *outsetmRSFA=NULL; THD_3dim_dataset *outsetfRSFA=NULL; char out_lff[300]; char out_alff[300]; char out_malff[300]; char out_falff[300]; char out_rsfa[300]; char out_mrsfa[300]; char out_frsfa[300]; char out_unBP[300]; int SERIES_OUT = 1; int UNBP_OUT = 0; int DO_RSFA = 1; int BP_LAST = 0; // option for only doing filter to LFFs at very end of proc float de_rsfa=0.0f,nu_rsfa=0.0f; double pow1=0.0,pow2=0.0; /*-- help? --*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "\n Program to calculate common resting state functional connectivity (RSFC)\n" " parameters (ALFF, mALFF, fALFF, RSFA, etc.) for resting state time\n" " series. This program is **heavily** based on the existing\n" " 3dBandPass by RW Cox, with the amendments to calculate RSFC\n" " parameters written by PA Taylor (July, 2012).\n" " This program is part of FATCAT (Taylor & Saad, 2013) in AFNI. Importantly,\n" " its functionality can be included in the `afni_proc.py' processing-script \n" " generator; see that program's help file for an example including RSFC\n" " and spectral parameter calculation via the `-regress_RSFC' option.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " All options of 3dBandPass may be used here (with a couple other\n" " parameter options, as well): essentially, the motivation of this\n" " program is to produce ALFF, etc. values of the actual RSFC time\n" " series that you calculate. Therefore, all the 3dBandPass processing\n" " you normally do en route to making your final `resting state time\n" " series' is done here to generate your LFFs, from which the\n" " amplitudes in the LFF band are calculated at the end. In order to\n" " calculate fALFF, the same initial time series are put through the\n" " same processing steps which you have chosen but *without* the\n" " bandpass part; the spectrum of this second time series is used to\n" " calculate the fALFF denominator.\n" " \n" " For more information about each RSFC parameter, see, e.g.: \n" " ALFF/mALFF -- Zang et al. (2007),\n" " fALFF -- Zou et al. (2008),\n" " RSFA -- Kannurpatti & Biswal (2008).\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " + USAGE: 3dRSFC [options] fbot ftop dataset\n" "\n" "* One function of this program is to prepare datasets for input\n" " to 3dSetupGroupInCorr. Other uses are left to your imagination.\n" "\n" "* 'dataset' is a 3D+time sequence of volumes\n" " ++ This must be a single imaging run -- that is, no discontinuities\n" " in time from 3dTcat-ing multiple datasets together.\n" "\n" "* fbot = lowest frequency in the passband, in Hz\n" " ++ fbot can be 0 if you want to do a lowpass filter only;\n" " HOWEVER, the mean and Nyquist freq are always removed.\n" "\n" "* ftop = highest frequency in the passband (must be > fbot)\n" " ++ if ftop > Nyquist freq, then it's a highpass filter only.\n" "\n" "* Set fbot=0 and ftop=99999 to do an 'allpass' filter.\n" " ++ Except for removal of the 0 and Nyquist frequencies, that is.\n" "\n" "* You cannot construct a 'notch' filter with this program!\n" " ++ You could use 3dRSFC followed by 3dcalc to get the same effect.\n" " ++ If you are understand what you are doing, that is.\n" " ++ Of course, that is the AFNI way -- if you don't want to\n" " understand what you are doing, use Some other PrograM, and\n" " you can still get Fine StatisticaL maps.\n" "\n" "* 3dRSFC will fail if fbot and ftop are too close for comfort.\n" " ++ Which means closer than one frequency grid step df,\n" " where df = 1 / (nfft * dt) [of course]\n" "\n" "* The actual FFT length used will be printed, and may be larger\n" " than the input time series length for the sake of efficiency.\n" " ++ The program will use a power-of-2, possibly multiplied by\n" " a power of 3 and/or 5 (up to and including the 3rd power of\n" " each of these: 3, 9, 27, and 5, 25, 125).\n" "\n" "* Note that the results of combining 3dDetrend and 3dRSFC will\n" " depend on the order in which you run these programs. That's why\n" " 3dRSFC has the '-ort' and '-dsort' options, so that the\n" " time series filtering can be done properly, in one place.\n" "\n" "* The output dataset is stored in float format.\n" "\n" "* The order of processing steps is the following (most are optional), and\n" " for the LFFs, the bandpass is done between the specified fbot and ftop,\n" " while for the `whole spectrum' (i.e., fALFF denominator) the bandpass is:\n" " done only to exclude the time series mean and the Nyquist frequency:\n" " (0) Check time series for initial transients [does not alter data]\n" " (1) Despiking of each time series\n" " (2) Removal of a constant+linear+quadratic trend in each time series\n" " (3) Bandpass of data time series\n" " (4) Bandpass of -ort time series, then detrending of data\n" " with respect to the -ort time series\n" " (5) Bandpass and de-orting of the -dsort dataset,\n" " then detrending of the data with respect to -dsort\n" " (6) Blurring inside the mask [might be slow]\n" " (7) Local PV calculation [WILL be slow!]\n" " (8) L2 normalization [will be fast.]\n" " (9) Calculate spectrum and amplitudes, for RSFC parameters.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "--------\n" "OPTIONS:\n" "--------\n" " -despike = Despike each time series before other processing.\n" " ++ Hopefully, you don't actually need to do this,\n" " which is why it is optional.\n" " -ort f.1D = Also orthogonalize input to columns in f.1D\n" " ++ Multiple '-ort' options are allowed.\n" " -dsort fset = Orthogonalize each voxel to the corresponding\n" " voxel time series in dataset 'fset', which must\n" " have the same spatial and temporal grid structure\n" " as the main input dataset.\n" " ++ At present, only one '-dsort' option is allowed.\n" " -nodetrend = Skip the quadratic detrending of the input that\n" " occurs before the FFT-based bandpassing.\n" " ++ You would only want to do this if the dataset\n" " had been detrended already in some other program.\n" " -dt dd = set time step to 'dd' sec [default=from dataset header]\n" " -nfft N = set the FFT length to 'N' [must be a legal value]\n" " -norm = Make all output time series have L2 norm = 1\n" " ++ i.e., sum of squares = 1\n" " -mask mset = Mask dataset\n" " -automask = Create a mask from the input dataset\n" " -blur fff = Blur (inside the mask only) with a filter\n" " width (FWHM) of 'fff' millimeters.\n" " -localPV rrr = Replace each vector by the local Principal Vector\n" " (AKA first singular vector) from a neighborhood\n" " of radius 'rrr' millimiters.\n" " ++ Note that the PV time series is L2 normalized.\n" " ++ This option is mostly for Bob Cox to have fun with.\n" "\n" " -input dataset = Alternative way to specify input dataset.\n" " -band fbot ftop = Alternative way to specify passband frequencies.\n" "\n" " -prefix ppp = Set prefix name of output dataset. Name of filtered time\n" " series would be, e.g., ppp_LFF+orig.*, and the parameter\n" " outputs are named with obvious suffices.\n" " -quiet = Turn off the fun and informative messages. (Why?)\n" " -no_rs_out = Don't output processed time series-- just output\n" " parameters (not recommended, since the point of\n" " calculating RSFC params here is to have them be quite\n" " related to the time series themselves which are used for\n" " further analysis)." " -un_bp_out = Output the un-bandpassed series as well (default is not \n" " to). Name would be, e.g., ppp_unBP+orig.* .\n" " with suffix `_unBP'.\n" " -no_rsfa = If you don't want RSFA output (default is to do so).\n" " -bp_at_end = A (probably unnecessary) switch to have bandpassing be \n" " the very last processing step that is done in the\n" " sequence of steps listed above; at Step 3 above, only \n" " the time series mean and nyquist are BP'ed out, and then\n" " the LFF series is created only after Step 9. NB: this \n" " probably makes only very small changes for most\n" " processing sequences (but maybe not, depending usage).\n" "\n" " -notrans = Don't check for initial positive transients in the data:\n" " *OR* ++ The test is a little slow, so skipping it is OK,\n" " -nosat if you KNOW the data time series are transient-free.\n" " ++ Or set AFNI_SKIP_SATCHECK to YES.\n" " ++ Initial transients won't be handled well by the\n" " bandpassing algorithm, and in addition may seriously\n" " contaminate any further processing, such as inter-\n" " voxel correlations via InstaCorr.\n" " ++ No other tests are made [yet] for non-stationary \n" " behavior in the time series data.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " If you use this program, please reference the introductory/description\n" " paper for the FATCAT toolbox:\n" " Taylor PA, Saad ZS (2013). FATCAT: (An Efficient) Functional\n" " And Tractographic Connectivity Analysis Toolbox. Brain \n" " Connectivity 3(5):523-535.\n" "____________________________________________________________________________\n" ); PRINT_AFNI_OMP_USAGE( " 3dRSFC" , " * At present, the only part of 3dRSFC that is parallelized is the\n" " '-blur' option, which processes each sub-brick independently.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup --*/ mainENTRY("3dRSFC"); machdep(); AFNI_logger("3dRSFC",argc,argv); PRINT_VERSION("3dRSFC (from 3dBandpass by RW Cox): version THETA"); AUTHOR("PA Taylor"); nosat = AFNI_yesenv("AFNI_SKIP_SATCHECK") ; nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-despike") == 0 ){ /* 08 Oct 2010 */ do_despike++ ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-nfft") == 0 ){ int nnup ; if( ++nopt >= argc ) ERROR_exit("need an argument after -nfft!") ; nfft = (int)strtod(argv[nopt],NULL) ; nnup = csfft_nextup_even(nfft) ; if( nfft < 16 || nfft != nnup ) ERROR_exit("value %d after -nfft is illegal! Next legal value = %d",nfft,nnup) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-blur") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -blur!") ; blur = strtod(argv[nopt],NULL) ; if( blur <= 0.0f ) WARNING_message("non-positive blur?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-localPV") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -localpv!") ; pvrad = strtod(argv[nopt],NULL) ; if( pvrad <= 0.0f ) WARNING_message("non-positive -localpv?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -prefix!") ; prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad -prefix option!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask AND -automask!") ; do_automask = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++nopt >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || do_automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(mset,argv[nopt]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[nopt]) ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < 1 ) ERROR_exit("Mask is too small to process") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-norm") == 0 ){ do_norm = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quiet") == 0 ){ verb = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-no_rs_out") == 0 ){ // @@ SERIES_OUT = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-un_bp_out") == 0 ){ // @@ UNBP_OUT = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-no_rsfa") == 0 ){ // @@ DO_RSFA = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-bp_at_end") == 0 ){ // @@ BP_LAST = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-notrans") == 0 || strcmp(argv[nopt],"-nosat") == 0 ){ nosat = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-ort") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -ort!") ; if( ortar == NULL ) INIT_IMARR(ortar) ; ortim = mri_read_1D( argv[nopt] ) ; if( ortim == NULL ) ERROR_exit("can't read from -ort '%s'",argv[nopt]) ; mri_add_name(argv[nopt],ortim) ; ADDTO_IMARR(ortar,ortim) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dsort") == 0 ){ THD_3dim_dataset *qset ; if( ++nopt >= argc ) ERROR_exit("need an argument after -dsort!") ; if( nortset > 0 ) ERROR_exit("only 1 -dsort option is allowed!") ; qset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(qset,argv[nopt]) ; ortset = (THD_3dim_dataset **)realloc(ortset, sizeof(THD_3dim_dataset *)*(nortset+1)) ; ortset[nortset++] = qset ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-nodetrend",6) == 0 ){ qdet = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dt") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -dt!") ; dt = (float)strtod(argv[nopt],NULL) ; if( dt <= 0.0f ) WARNING_message("value after -dt illegal!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have 2 -input options!") ; if( ++nopt >= argc ) ERROR_exit("need an argument after -input!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-band",5) == 0 ){ if( ++nopt >= argc-1 ) ERROR_exit("need 2 arguments after -band!") ; if( have_freq ) WARNING_message("second -band option replaces first one!") ; fbot = strtod(argv[nopt++],NULL) ; ftop = strtod(argv[nopt++],NULL) ; have_freq = 1 ; continue ; } ERROR_exit("Unknown option: '%s'",argv[nopt]) ; } /** check inputs for reasonablositiness **/ if( !have_freq ){ if( nopt+1 >= argc ) ERROR_exit("Need frequencies on command line after options!") ; fbot = (float)strtod(argv[nopt++],NULL) ; ftop = (float)strtod(argv[nopt++],NULL) ; } if( inset == NULL ){ if( nopt >= argc ) ERROR_exit("Need input dataset name on command line after options!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; } DSET_UNMSEC(inset) ; if( fbot < 0.0f ) ERROR_exit("fbot value can't be negative!") ; if( ftop <= fbot ) ERROR_exit("ftop value %g must be greater than fbot value %g!",ftop,fbot) ; ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Input dataset is too short!") ; if( nfft <= 0 ){ nfft = csfft_nextup_even(ntime) ; if( verb ) INFO_message("Data length = %d FFT length = %d",ntime,nfft) ; (void)THD_bandpass_set_nfft(nfft) ; } else if( nfft < ntime ){ ERROR_exit("-nfft %d is less than data length = %d",nfft,ntime) ; } else { kk = THD_bandpass_set_nfft(nfft) ; if( kk != nfft && verb ) INFO_message("Data length = %d FFT length = %d",ntime,kk) ; } if( dt <= 0.0f ){ dt = DSET_TR(inset) ; if( dt <= 0.0f ){ WARNING_message("Setting dt=1.0 since input dataset lacks a time axis!") ; dt = 1.0f ; } } ftopALL = 1./dt ;// Aug,2016: should solve problem of a too-large // value for THD_bandpass_vectors(), while still // being >f_{Nyquist} if( !THD_bandpass_OK(ntime,dt,fbot,ftop,1) ) ERROR_exit("Can't continue!") ; nx = DSET_NX(inset); ny = DSET_NY(inset); nz = DSET_NZ(inset); nvox = nx*ny*nz; /* check mask, or create it */ if( verb ) INFO_message("Loading input dataset time series" ) ; DSET_load(inset) ; if( mask != NULL ){ if( mask_nx != nx || mask_ny != ny || mask_nz != nz ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( do_automask ){ mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; nmask = THD_countmask( DSET_NVOX(inset) , mask ) ; if( verb ) INFO_message("Number of voxels in automask = %d",nmask); if( nmask < 1 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nvox) ; nmask = nvox ; memset(mask,1,sizeof(byte)*nvox) ; // if( verb ) // @@ alert if aaaalllllll vox are going to be analyzed! INFO_message("No mask ==> processing all %d voxels",nvox); } /* A simple check of dataset quality [08 Feb 2010] */ if( !nosat ){ float val ; INFO_message( "Checking dataset for initial transients [use '-notrans' to skip this test]") ; val = THD_saturation_check(inset,mask,0,0) ; kk = (int)(val+0.54321f) ; if( kk > 0 ) ININFO_message( "Looks like there %s %d non-steady-state initial time point%s :-(" , ((kk==1) ? "is" : "are") , kk , ((kk==1) ? " " : "s") ) ; else if( val > 0.3210f ) /* don't ask where this threshold comes from! */ ININFO_message( "MAYBE there's an initial positive transient of 1 point, but it's hard to tell\n") ; else ININFO_message("No widespread initial positive transient detected :-)") ; } /* check -dsort inputs for match to inset */ for( kk=0 ; kk < nortset ; kk++ ){ if( DSET_NX(ortset[kk]) != nx || DSET_NY(ortset[kk]) != ny || DSET_NZ(ortset[kk]) != nz || DSET_NVALS(ortset[kk]) != ntime ) ERROR_exit("-dsort %s doesn't match input dataset grid" , DSET_BRIKNAME(ortset[kk]) ) ; } /* convert input dataset to a vectim, which is more fun */ // @@ convert BP'ing ftop/bot into indices for the DFT (below) delf = 1.0/(ntime*dt); ind_low = (int) rint(fbot/delf); ind_high = (int) rint(ftop/delf); if( ntime % 2 ) // nyquist number N_ny = (ntime-1)/2; else N_ny = ntime/2; sqnt = sqrt(ntime); nt_fac = sqrt(ntime*(ntime-1)); // @@ if BP_LAST==0: // now we go through twice, doing LFF bandpass for NumDen==0 and // `full spectrum' processing for NumDen==1. // if BP_LAST==1: // now we go through once, doing only `full spectrum' processing for( NumDen=0 ; NumDen<2 ; NumDen++) { //if( NumDen==1 ){ // full spectrum // fbot = fbotALL; // ftop = ftopALL; //} // essentially, just doesn't BP here, and the perfect filtering at end // is used for both still; this makes the final output spectrum // contain only frequencies in range of 0.01-0.08 if( BP_LAST==1 ) INFO_message("Only doing filtering to LFFs at end!"); mrv = THD_dset_to_vectim( inset , mask , 0 ) ; if( mrv == NULL ) ERROR_exit("Can't load time series data!?") ; if( NumDen==1 ) DSET_unload(inset) ; // @@ only unload on 2nd pass /* similarly for the ort vectors */ if( ortar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(ortar) ; kk++ ){ ortim = IMARR_SUBIM(ortar,kk) ; if( ortim->nx < ntime ) ERROR_exit("-ort file %s is shorter than input dataset time series", ortim->name ) ; ort = (float **)realloc( ort , sizeof(float *)*(nort+ortim->ny) ) ; for( vv=0 ; vv < ortim->ny ; vv++ ) ort[nort++] = MRI_FLOAT_PTR(ortim) + ortim->nx * vv ; } } /* all the real work now */ if( do_despike ){ int_pair nsp ; if( verb ) INFO_message("Testing data time series for spikes") ; nsp = THD_vectim_despike9( mrv ) ; if( verb ) ININFO_message(" -- Squashed %d spikes from %d voxels",nsp.j,nsp.i) ; } if( verb ) INFO_message("Bandpassing data time series") ; if( (BP_LAST==0) && (NumDen==0) ) (void)THD_bandpass_vectim( mrv , dt,fbot,ftop , qdet , nort,ort ) ; else (void)THD_bandpass_vectim( mrv , dt,fbotALL,ftopALL, qdet,nort,ort ) ; /* OK, maybe a little more work */ if( nortset == 1 ){ MRI_vectim *orv ; orv = THD_dset_to_vectim( ortset[0] , mask , 0 ) ; if( orv == NULL ){ ERROR_message("Can't load -dsort %s",DSET_BRIKNAME(ortset[0])) ; } else { float *dp , *mvv , *ovv , ff ; if( verb ) INFO_message("Orthogonalizing to bandpassed -dsort") ; //(void)THD_bandpass_vectim( orv , dt,fbot,ftop , qdet , nort,ort ) ; //@@ if( (BP_LAST==0) && (NumDen==0) ) (void)THD_bandpass_vectim(orv,dt,fbot,ftop,qdet,nort,ort); else (void)THD_bandpass_vectim(orv,dt,fbotALL,ftopALL,qdet,nort,ort); THD_vectim_normalize( orv ) ; dp = malloc(sizeof(float)*mrv->nvec) ; THD_vectim_vectim_dot( mrv , orv , dp ) ; for( vv=0 ; vv < mrv->nvec ; vv++ ){ ff = dp[vv] ; if( ff != 0.0f ){ mvv = VECTIM_PTR(mrv,vv) ; ovv = VECTIM_PTR(orv,vv) ; for( kk=0 ; kk < ntime ; kk++ ) mvv[kk] -= ff*ovv[kk] ; } } VECTIM_destroy(orv) ; free(dp) ; } } if( blur > 0.0f ){ if( verb ) INFO_message("Blurring time series data spatially; FWHM=%.2f",blur) ; mri_blur3D_vectim( mrv , blur ) ; } if( pvrad > 0.0f ){ if( verb ) INFO_message("Local PV-ing time series data spatially; radius=%.2f",pvrad) ; THD_vectim_normalize( mrv ) ; THD_vectim_localpv( mrv , pvrad ) ; } if( do_norm && pvrad <= 0.0f ){ if( verb ) INFO_message("L2 normalizing time series data") ; THD_vectim_normalize( mrv ) ; } /* create output dataset, populate it, write it, then quit */ if( (NumDen==0) ) { // @@ BP'ed version; will do filt if BP_LAST if(BP_LAST) // do bandpass here for BP_LAST (void)THD_bandpass_vectim(mrv,dt,fbot,ftop,qdet,0,NULL); if( verb ) INFO_message("Creating output dataset in memory, then writing it") ; outset = EDIT_empty_copy(inset) ; if(SERIES_OUT){ sprintf(out_lff,"%s_LFF",prefix); EDIT_dset_items( outset , ADN_prefix,out_lff , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dBandpass" , argc,argv , outset ) ; } for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outset , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outset ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outset,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; if(SERIES_OUT){ // @@ DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; } } else{ // @@ non-BP'ed version if( verb ) INFO_message("Creating output dataset 2 in memory") ; // do this here because LFF version was also BP'ed at end. if(BP_LAST) // do bandpass here for BP_LAST (void)THD_bandpass_vectim(mrv,dt,fbotALL,ftopALL,qdet,0,NULL); outsetALL = EDIT_empty_copy(inset) ; if(UNBP_OUT){ sprintf(out_unBP,"%s_unBP",prefix); EDIT_dset_items( outsetALL, ADN_prefix, out_unBP, ADN_none ); tross_Copy_History( inset , outsetALL ) ; tross_Make_History( "3dRSFC" , argc,argv , outsetALL ) ; } for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outsetALL , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outsetALL ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outsetALL,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; if(UNBP_OUT){ DSET_write(outsetALL) ; if( verb ) WROTE_DSET(outsetALL) ; } } }// end of NumDen loop // @@ INFO_message("Starting the (f)ALaFFel calcs") ; // allocations series1 = (double *)calloc(ntime,sizeof(double)); series2 = (double *)calloc(ntime,sizeof(double)); xx1 = (double *)calloc(2*ntime,sizeof(double)); xx2 = (double *)calloc(2*ntime,sizeof(double)); alff = (float *)calloc(nvox,sizeof(float)); malff = (float *)calloc(nvox,sizeof(float)); falff = (float *)calloc(nvox,sizeof(float)); if( (series1 == NULL) || (series2 == NULL) || (xx1 == NULL) || (xx2 == NULL) || (alff == NULL) || (malff == NULL) || (falff == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(122); } if(DO_RSFA) { rsfa = (float *)calloc(nvox,sizeof(float)); mrsfa = (float *)calloc(nvox,sizeof(float)); frsfa = (float *)calloc(nvox,sizeof(float)); if( (rsfa == NULL) || (mrsfa == NULL) || (frsfa == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(123); } } work = gsl_fft_real_workspace_alloc (ntime); real1 = gsl_fft_real_wavetable_alloc (ntime); real2 = gsl_fft_real_wavetable_alloc (ntime); gsl_complex_packed_array compl_freqs1 = xx1; gsl_complex_packed_array compl_freqs2 = xx2; // ********************************************************************* // ********************************************************************* // ************** Falafelling = ALFF/fALFF calcs ***************** // ********************************************************************* // ********************************************************************* // Be now have the BP'ed data set (outset) and the non-BP'ed one // (outsetALL). now we'll FFT both, get amplitudes in appropriate // ranges, and calculate: ALFF, mALFF, fALFF, ctr = 0; for( kk=0; kk<nvox ; kk++) { if(mask[kk]) { // BP one, and unBP one, either for BP_LAST or !BP_LAST for( m=0 ; m<ntime ; m++ ) { series1[m] = THD_get_voxel(outset,kk,m); series2[m] = THD_get_voxel(outsetALL,kk,m); } mm = gsl_fft_real_transform(series1, 1, ntime, real1, work); mm = gsl_fft_halfcomplex_unpack(series1, compl_freqs1, 1, ntime); mm = gsl_fft_real_transform(series2, 1, ntime, real2, work); mm = gsl_fft_halfcomplex_unpack(series2, compl_freqs2, 1, ntime); numer = 0.0f; denom = 0.0f; de_rsfa = 0.0f; nu_rsfa = 0.0f; for( m=1 ; m<N_ny ; m++ ) { mm = 2*m; pow2 = compl_freqs2[mm]*compl_freqs2[mm] + compl_freqs2[mm+1]*compl_freqs2[mm+1]; // power //pow2*=2;// factor of 2 since ampls are even funcs denom+= (float) sqrt(pow2); // amplitude de_rsfa+= (float) pow2; if( ( m>=ind_low ) && ( m<=ind_high ) ){ pow1 = compl_freqs1[mm]*compl_freqs1[mm]+ compl_freqs1[mm+1]*compl_freqs1[mm+1]; //pow1*=2; numer+= (float) sqrt(pow1); nu_rsfa+= (float) pow1; } } if( denom>0.000001 ) falff[kk] = numer/denom; else falff[kk] = 0.; alff[kk] = 2*numer/sqnt;// factor of 2 since ampl is even funct meanALFF+= alff[kk]; if(DO_RSFA){ nu_rsfa = sqrt(2*nu_rsfa); // factor of 2 since ampls de_rsfa = sqrt(2*de_rsfa); // are even funcs if( de_rsfa>0.000001 ) frsfa[kk] = nu_rsfa/de_rsfa; else frsfa[kk]=0.; rsfa[kk] = nu_rsfa/nt_fac; meanRSFA+= rsfa[kk]; } ctr+=1; } } meanALFF/= ctr; meanRSFA/= ctr; gsl_fft_real_wavetable_free(real1); gsl_fft_real_wavetable_free(real2); gsl_fft_real_workspace_free(work); // ALFFs divided by mean of brain value for( kk=0 ; kk<nvox ; kk++ ) if(mask[kk]){ malff[kk] = alff[kk]/meanALFF; if(DO_RSFA) mrsfa[kk] = rsfa[kk]/meanRSFA; } // ************************************************************** // ************************************************************** // Store and output // ************************************************************** // ************************************************************** outsetALFF = EDIT_empty_copy( inset ) ; sprintf(out_alff,"%s_ALFF",prefix); EDIT_dset_items( outsetALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_alff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetALFF)); EDIT_substitute_brick(outsetALFF, 0, MRI_float, alff); alff=NULL; THD_load_statistics(outsetALFF); tross_Make_History("3dRSFC", argc, argv, outsetALFF); THD_write_3dim_dataset(NULL, NULL, outsetALFF, True); outsetfALFF = EDIT_empty_copy( inset ) ; sprintf(out_falff,"%s_fALFF",prefix); EDIT_dset_items( outsetfALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_falff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetfALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetfALFF)); EDIT_substitute_brick(outsetfALFF, 0, MRI_float, falff); falff=NULL; THD_load_statistics(outsetfALFF); tross_Make_History("3dRSFC", argc, argv, outsetfALFF); THD_write_3dim_dataset(NULL, NULL, outsetfALFF, True); outsetmALFF = EDIT_empty_copy( inset ) ; sprintf(out_malff,"%s_mALFF",prefix); EDIT_dset_items( outsetmALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_malff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetmALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetmALFF)); EDIT_substitute_brick(outsetmALFF, 0, MRI_float, malff); malff=NULL; THD_load_statistics(outsetmALFF); tross_Make_History("3dRSFC", argc, argv, outsetmALFF); THD_write_3dim_dataset(NULL, NULL, outsetmALFF, True); if(DO_RSFA){ outsetRSFA = EDIT_empty_copy( inset ) ; sprintf(out_rsfa,"%s_RSFA",prefix); EDIT_dset_items( outsetRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_rsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetRSFA)); EDIT_substitute_brick(outsetRSFA, 0, MRI_float, rsfa); rsfa=NULL; THD_load_statistics(outsetRSFA); tross_Make_History("3dRSFC", argc, argv, outsetRSFA); THD_write_3dim_dataset(NULL, NULL, outsetRSFA, True); outsetfRSFA = EDIT_empty_copy( inset ) ; sprintf(out_frsfa,"%s_fRSFA",prefix); EDIT_dset_items( outsetfRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_frsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetfRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetfRSFA)); EDIT_substitute_brick(outsetfRSFA, 0, MRI_float, frsfa); frsfa=NULL; THD_load_statistics(outsetfRSFA); tross_Make_History("3dRSFC", argc, argv, outsetfRSFA); THD_write_3dim_dataset(NULL, NULL, outsetfRSFA, True); outsetmRSFA = EDIT_empty_copy( inset ) ; sprintf(out_mrsfa,"%s_mRSFA",prefix); EDIT_dset_items( outsetmRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_mrsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetmRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetmRSFA)); EDIT_substitute_brick(outsetmRSFA, 0, MRI_float, mrsfa); mrsfa=NULL; THD_load_statistics(outsetmRSFA); tross_Make_History("3dRSFC", argc, argv, outsetmRSFA); THD_write_3dim_dataset(NULL, NULL, outsetmRSFA, True); } // ************************************************************ // ************************************************************ // Freeing // ************************************************************ // ************************************************************ DSET_delete(inset); DSET_delete(outsetALL); DSET_delete(outset); DSET_delete(outsetALFF); DSET_delete(outsetmALFF); DSET_delete(outsetfALFF); DSET_delete(outsetRSFA); DSET_delete(outsetmRSFA); DSET_delete(outsetfRSFA); free(inset); free(outsetALL); free(outset); free(outsetALFF); free(outsetmALFF); free(outsetfALFF); free(outsetRSFA); free(outsetmRSFA); free(outsetfRSFA); free(rsfa); free(mrsfa); free(frsfa); free(alff); free(malff); free(falff); free(mask); free(series1); free(series2); free(xx1); free(xx2); exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL , *outset=NULL ; MCW_cluster *nbhd=NULL ; byte *mask=NULL ; int mask_nx,mask_ny,mask_nz , automask=0 ; char *prefix="./LocalCormat" ; int iarg=1 , verb=1 , ntype=0 , kk,nx,ny,nz,nxy,nxyz,nt , xx,yy,zz, vstep ; float na,nb,nc , dx,dy,dz ; MRI_IMARR *imar=NULL ; MRI_IMAGE *pim=NULL ; int mmlag=10 , ii,jj , do_arma=0 , nvout ; MRI_IMAGE *concim=NULL ; float *concar=NULL ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dLocalCORMAT [options] inputdataset\n" "\n" "Compute the correlation matrix (in time) of the input dataset,\n" "up to lag given by -maxlag. The matrix is averaged over the\n" "neighborhood specified by the -nbhd option, and then the entries\n" "are output at each voxel in a new dataset.\n" "\n" "Normally, the input to this program would be the -errts output\n" "from 3dDeconvolve, or the equivalent residuals from some other\n" "analysis. If you input a non-residual time series file, you at\n" "least should use an appropriate -polort level for detrending!\n" "\n" "Options:\n" " -input inputdataset\n" " -prefix ppp\n" " -mask mset {these 2 options are}\n" " -automask {mutually exclusive.}\n" " -nbhd nnn [e.g., 'SPHERE(9)' for 9 mm radius]\n" " -polort ppp [default = 0, which is reasonable for -errts output]\n" " -concat ccc [as in 3dDeconvolve]\n" " -maxlag mmm [default = 10]\n" " -ARMA [estimate ARMA(1,1) parameters into last 2 sub-bricks]\n" "\n" "A quick hack for my own benignant purposes -- RWCox -- June 2008\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dLocalCormat"); mainENTRY("3dLocalCormat main"); machdep(); AFNI_logger("3dLocalCormat",argc,argv); AUTHOR("Zhark the Toeplitzer"); /*---- loop over options ----*/ while( iarg < argc && argv[iarg][0] == '-' ){ #if 0 fprintf(stderr,"argv[%d] = %s\n",iarg,argv[iarg]) ; #endif if( strcmp(argv[iarg],"-ARMA") == 0 ){ do_arma = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *cpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; pport = (int)strtod(argv[iarg],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; if( pport > 3 ){ pport = 3 ; WARNING_message("-polort set to 3 == max implemented") ; } else if( pport < 0 ){ pport = 0 ; WARNING_message("-polort set to 0 == min implemented") ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have two -input options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-input'") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-prefix'") ; prefix = strdup(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; int mmm ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ; mmm = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; INFO_message("Number of voxels in mask = %d",mmm) ; if( mmm < 2 ) ERROR_exit("Mask is too small to process") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't have -automask and -mask") ; automask = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-nbhd") == 0 ){ char *cpt ; if( ntype > 0 ) ERROR_exit("Can't have 2 '-nbhd' options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-nbhd'") ; cpt = argv[iarg] ; if( strncasecmp(cpt,"SPHERE",6) == 0 ){ sscanf( cpt+7 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a SPHERE of radius 0") ; ntype = NTYPE_SPHERE ; } else if( strncasecmp(cpt,"RECT",4) == 0 ){ sscanf( cpt+5 , "%f,%f,%f" , &na,&nb,&nc ) ; if( na == 0.0f && nb == 0.0f && nc == 0.0f ) ERROR_exit("'RECT(0,0,0)' is not a legal neighborhood") ; ntype = NTYPE_RECT ; } else if( strncasecmp(cpt,"RHDD",4) == 0 ){ sscanf( cpt+5 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a RHDD of radius 0") ; ntype = NTYPE_RHDD ; } else { ERROR_exit("Unknown -nbhd shape: '%s'",cpt) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-maxlag") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; mmlag = (int)strtod(argv[iarg],NULL) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-concat") == 0 ){ if( concim != NULL ) ERROR_exit("Can't have two %s options!",argv[iarg]) ; if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; concim = mri_read_1D( argv[iarg] ) ; if( concim == NULL ) ERROR_exit("Can't read -concat file '%s'",argv[iarg]) ; if( concim->nx < 2 ) ERROR_exit("-concat file '%s' must have at least 2 entries!", argv[iarg]) ; concar = MRI_FLOAT_PTR(concim) ; for( ii=1 ; ii < concim->nx ; ii++ ) if( (int)concar[ii-1] >= (int)concar[ii] ) ERROR_exit("-concat file '%s' is not ordered increasingly!", argv[iarg]) ; iarg++ ; continue ; } ERROR_exit("Unknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ if( do_arma && mmlag > 0 && mmlag < 5 ) ERROR_exit("Can't do -ARMA with -maxlag %d",mmlag) ; /*---- deal with input dataset ----*/ if( inset == NULL ){ if( iarg >= argc ) ERROR_exit("No input dataset on command line?") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; } ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Must have at least 9 values per voxel") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; if( mask != NULL ){ if( mask_nx != DSET_NX(inset) || mask_ny != DSET_NY(inset) || mask_nz != DSET_NZ(inset) ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( automask ){ int mmm ; mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; mmm = THD_countmask( DSET_NVOX(inset) , mask ) ; INFO_message("Number of voxels in automask = %d",mmm) ; if( mmm < 2 ) ERROR_exit("Automask is too small to process") ; } /*-- set up blocks of continuous time data --*/ if( DSET_IS_TCAT(inset) ){ if( concim != NULL ){ WARNING_message("Ignoring -concat, since dataset is auto-catenated") ; mri_free(concim) ; } concim = mri_new(inset->tcat_num,1,MRI_float) ; concar = MRI_FLOAT_PTR(concim) ; concar[0] = 0.0 ; for( ii=0 ; ii < inset->tcat_num-1 ; ii++ ) concar[ii+1] = concar[ii] + inset->tcat_len[ii] ; } else if( concim == NULL ){ concim = mri_new(1,1,MRI_float) ; concar = MRI_FLOAT_PTR(concim) ; concar[0] = 0 ; } nbk = concim->nx ; bk = (int *)malloc(sizeof(int)*(nbk+1)) ; for( ii=0 ; ii < nbk ; ii++ ) bk[ii] = (int)concar[ii] ; bk[nbk] = ntime ; mri_free(concim) ; mlag = DSET_NVALS(inset) ; for( ii=0 ; ii < nbk ; ii++ ){ jj = bk[ii+1]-bk[ii] ; if( jj < mlag ) mlag = jj ; if( bk[ii] < 0 || jj < 9 ) ERROR_exit("something is rotten in the dataset run lengths") ; } mlag-- ; if( mmlag > 0 && mlag > mmlag ) mlag = mmlag ; else INFO_message("Max lag set to %d",mlag) ; if( do_arma && mlag < 5 ) ERROR_exit("Can't do -ARMA with maxlag=%d",mlag) ; /*---- create neighborhood (as a cluster) -----*/ if( ntype <= 0 ){ /* default neighborhood */ ntype = NTYPE_SPHERE ; na = -1.01f ; INFO_message("Using default neighborhood = self + 6 neighbors") ; } switch( ntype ){ default: ERROR_exit("WTF? ntype=%d",ntype) ; case NTYPE_SPHERE:{ if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(inset)) ; dy = fabsf(DSET_DY(inset)) ; dz = fabsf(DSET_DZ(inset)) ; } nbhd = MCW_spheremask( dx,dy,dz , na ) ; } break ; case NTYPE_RECT:{ if( na < 0.0f ){ dx = 1.0f; na = -na; } else dx = fabsf(DSET_DX(inset)); if( nb < 0.0f ){ dy = 1.0f; nb = -nb; } else dy = fabsf(DSET_DY(inset)); if( nc < 0.0f ){ dz = 1.0f; nc = -nc; } else dz = fabsf(DSET_DZ(inset)); nbhd = MCW_rectmask( dx,dy,dz , na,nb,nc ) ; } break ; case NTYPE_RHDD:{ if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(inset)) ; dy = fabsf(DSET_DY(inset)) ; dz = fabsf(DSET_DZ(inset)) ; } nbhd = MCW_rhddmask( dx,dy,dz , na ) ; } break ; } MCW_radsort_cluster( nbhd , dx,dy,dz ) ; /* 26 Feb 2008 */ INFO_message("Neighborhood comprises %d voxels",nbhd->num_pt) ; /** create output dataset **/ outset = EDIT_empty_copy(inset) ; nvout = mlag ; if( do_arma ) nvout += 2 ; EDIT_dset_items( outset, ADN_prefix , prefix, ADN_brick_fac, NULL , ADN_nvals , nvout , ADN_ntt , nvout , ADN_none ); tross_Copy_History( inset , outset ) ; tross_Make_History( "3dLocalCormat" , argc,argv , outset ) ; for( kk=0 ; kk < nvout ; kk++ ) EDIT_substitute_brick( outset , kk , MRI_float , NULL ) ; nx = DSET_NX(outset) ; ny = DSET_NY(outset) ; nxy = nx*ny ; nz = DSET_NZ(outset) ; nxyz = nxy*nz ; vstep = (verb && nxyz > 999) ? nxyz/50 : 0 ; if( vstep ) fprintf(stderr,"++ voxel loop: ") ; /** actually do the long long slog through all voxels **/ for( kk=0 ; kk < nxyz ; kk++ ){ if( vstep && kk%vstep==vstep-1 ) vstep_print() ; if( !INMASK(kk) ) continue ; IJK_TO_THREE( kk , xx,yy,zz , nx,nxy ) ; imar = THD_get_dset_nbhd_array( inset , mask , xx,yy,zz , nbhd ) ; if( imar == NULL ) continue ; pim = mri_cormat_vector(imar) ; DESTROY_IMARR(imar) ; if( pim == NULL ) continue ; THD_insert_series( kk, outset, pim->nx, MRI_float, MRI_FLOAT_PTR(pim), 0 ) ; if( do_arma ){ /* estimate ARMA(1,1) params and store those, too */ float_pair ab ; float *aa=DSET_ARRAY(outset,mlag), *bb=DSET_ARRAY(outset,mlag+1) ; ab = estimate_arma11( pim->nx , MRI_FLOAT_PTR(pim) ) ; aa[kk] = ab.a ; bb[kk] = ab.b ; } mri_free(pim) ; } if( vstep ) fprintf(stderr,"\n") ; DSET_delete(inset) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *dset=NULL , *oset=NULL ; MRI_IMAGE *thim=NULL ; float *thar ; int nthar ; byte *mask=NULL ; int nmask=0 ; MRI_IMAGE *datim=NULL, *thrim=NULL , *outim=NULL ; int iarg , dind=0 , tind=1 , ith , nnlev=1 ; int scode ; float *spar=NULL ; char *prefix = "ETC.nii" ; /*-- some pitiful help --*/ if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf("\n" "Usage: 3dETC [options] inputdataset\n" "\n" "Options:\n" "========\n" " -input dset = alternative way to input the dataset\n" " -prefix ppp = output prefix\n" " -thresh ttt = 1D file with\n" " column #1 = p-value\n" " column #2 = cluster threshold\n" " -mask mmm = dataset with mask\n" " -1dindex ii = output comes from sub-brick #ii\n" " -1tindex jj = threshold on sub-brick #jj\n" " -NN nn = nn is 1 or 2 or 3 [default 1]\n" "\n" "-- Experimental - RWCox - 24 Dec 2015\n" ) ; exit(0) ; } /*-- scan options --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcasecmp(argv[iarg],"-input") == 0 ){ if( dset != NULL ) ERROR_exit("You can't use option '%s' twice!",argv[iarg]) ; if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; dset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(dset,argv[iarg]) ; DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-mask") == 0 ){ bytevec *bvec ; int nmask_hits ; if( mask != NULL ) ERROR_exit("Can't use '-mask' twice!") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; bvec = THD_create_mask_from_string(argv[iarg]) ; if( bvec == NULL ) ERROR_exit("Can't create mask from '-mask' option") ; mask = bvec->ar ; nmask = bvec->nar ; nmask_hits = THD_countmask( nmask , mask ) ; if( nmask_hits > 0 ) INFO_message("%d voxels in -mask definition (out of %d total)", nmask_hits,nmask) ; else ERROR_exit("no nonzero voxels in -mask dataset") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; prefix = strdup(argv[iarg]) ; if( ! THD_filename_ok(prefix) ) ERROR_exit("-prefix '%s' is not a good filename prefix",prefix) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-1tindex") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; tind = (int)strtod(argv[iarg],NULL) ; if( tind < 0 ) ERROR_exit("-tind '%s' is illegal!",argv[iarg]) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-1dindex") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; dind = (int)strtod(argv[iarg],NULL) ; if( dind < 0 ) ERROR_exit("-dind '%s' is illegal!",argv[iarg]) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-NN") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; nnlev = (int)strtod(argv[iarg],NULL) ; if( nnlev < 1 || nnlev > 3 ) ERROR_exit("-nnlev '%s' is illegal!",argv[iarg]) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-NN1") == 0 ){ nnlev = 1 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-NN2") == 0 ){ nnlev = 2 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-NN3") == 0 ){ nnlev = 3 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-thresh") == 0 ){ int nbad=0 ; if( thim != NULL ) ERROR_exit("You can't use option '%s' twice!",argv[iarg]) ; if( ++iarg >= argc ) ERROR_exit("Option '%s' needs an argument to follow!",argv[iarg-1]) ; thim = mri_read_1D( argv[iarg] ) ; if( thim == NULL ) ERROR_exit("Cannot read file from option -thresh '%s'",argv[iarg]) ; if( thim->ny < 2 ) ERROR_exit("-thresh '%s' doesn't have at least 2 columns!",argv[iarg]) ; nthar = thim->nx ; thar = MRI_FLOAT_PTR(thim) ; for( ith=0 ; ith < nthar ; ith++ ){ if( thar[ith] <= 0.0f || thar[ith] > 0.10f ) nbad++ ; } if( nbad > 0 ) ERROR_exit("Some value%s in -thresh '%s' Column #1 %s outside 0 < p <= 0.1 :-(", (nbad==1)?"\0":"s" , argv[iarg] , (nbad==1)?"is":"are" ) ; for( ith=0 ; ith < nthar ; ith++ ){ if( thar[ith+nthar] < 1.0f ) nbad++ ; } if( nbad > 0 ) ERROR_exit("Some value%s in -thresh '%s' Column #2 %s less than 1 :-(", (nbad==1)?"\0":"s" , argv[iarg] , (nbad==1)?"is":"are" ) ; INFO_message("-thresh table has %d levels of thresholding",nthar) ; iarg++ ; continue ; } ERROR_exit("Unknown option '%s' :-(",argv[iarg] ) ; exit(1) ; } /*-- did we get the input dataset yet? --*/ if( dset == NULL ){ if( iarg >= argc ) ERROR_exit("no input dataset?!") ; dset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(dset,argv[iarg]) ; DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; iarg++ ; } /*-- check things --*/ if( nmask > 0 && DSET_NVOX(dset) != nmask ) ERROR_exit("mask and input datasets don't match in number of voxels") ; if( thim == NULL ) ERROR_exit("no -thresh option was given!?") ; if( dind >= DSET_NVALS(dset) ) ERROR_exit("data index %d is beyond end of input dataset!",dind) ; if( tind >= DSET_NVALS(dset) ) ERROR_exit("threshold index %d is beyond end of input dataset!",tind) ; /*-- record things for posterity, et cetera --*/ mainENTRY("3dETC main"); machdep(); AFNI_logger("3dETC",argc,argv); PRINT_VERSION("3dETC") ; AUTHOR("Bob the Equable") ; /*-- get the data and threshold volumes --*/ datim = THD_extract_float_brick( dind , dset ) ; thrim = THD_extract_float_brick( tind , dset ) ; if( datim == NULL || thrim == NULL ) /* should be impossible */ ERROR_exit("Can't get data and/or thresh data from input dataset???") ; DSET_unload(dset) ; scode = DSET_BRICK_STATCODE(dset,tind) ; if( scode < 0 ) ERROR_exit("thresh sub-brick index %d is NOT a statistical volume!?",tind) ; spar = DSET_BRICK_STATAUX(dset,tind) ; #if 1 INFO_message("value range in thrim = %g .. %g",mri_min(thrim),mri_max(thrim)) ; #endif outim = mri_multi_threshold_clusterize( datim , scode,spar,thrim , mask , nthar , thar , thar+nthar , nnlev , 0 ) ; oset = EDIT_empty_copy(dset) ; EDIT_dset_items( oset , ADN_prefix , prefix , ADN_nvals , 1 , ADN_ntt , 0 , ADN_brick_fac , NULL , ADN_type , HEAD_FUNC_TYPE , ADN_func_type , FUNC_BUCK_TYPE , ADN_none ) ; EDIT_substitute_brick( oset , 0 , MRI_float , MRI_FLOAT_PTR(outim) ) ; DSET_write(oset) ; WROTE_DSET(oset) ; INFO_message("# nonzero voxels = %d",mri_nonzero_count(outim)) ; exit(0) ; }
int main(int argc, char *argv[]) { int i,j,k,m,n,aa,ii,jj,kk,mm,rr; int iarg; int nmask1=0; int nmask2=0; THD_3dim_dataset *insetFA = NULL, *insetV1 = NULL, *insetMD = NULL, *insetL1 = NULL; THD_3dim_dataset *insetEXTRA=NULL; THD_3dim_dataset *mset2=NULL; THD_3dim_dataset *mset1=NULL; THD_3dim_dataset *outsetMAP=NULL, *outsetMASK=NULL; char *prefix="tracky"; int LOG_TYPE=0; char in_FA[300]; char in_V1[300]; char in_MD[300]; char in_L1[300]; int EXTRAFILE=0; // switch for whether other file is input as WM map char OUT_bin[300]; char OUT_tracstat[300]; char prefix_mask[300]; char prefix_map[300]; // FACT algopts FILE *fout0; float MinFA=0.2,MaxAngDeg=45,MinL=20.0; float MaxAng; int SeedPerV[3]={2,2,2}; int ArrMax=0; float tempvmagn; int Nvox=-1; // tot number vox int Dim[3]={0,0,0}; // dim in each dir int Nseed=0,M=30,bval=1000; int DimSeed[3]; // number of seeds there will be float Ledge[3]; // voxel edge lengths int *ROI1, *ROI2; short int *temp_arr; char *temp_byte; int **Tforw, **Tback; int **Ttot; float **flTforw, **flTback; float ****coorded; int ****INDEX; int len_forw, len_back; // int count of num of squares through float phys_forw[1], phys_back[1]; int idx; float ave_tract_len, ave_tract_len_phys; int inroi1, inroi2, KEEPIT; // switches for detecting int in[3]; // to pass to trackit float physin[3]; // also for trackit, physical loc, int totlen; float totlen_phys; int Numtract; int READS_in; float READS_fl; int end[2][3]; int test_ind[2][3]; int roi3_ct=0, id=0; float roi3_mu_MD = 0.,roi3_mu_RD = 0.,roi3_mu_L1 = 0.,roi3_mu_FA = 0.; float roi3_sd_MD = 0.,roi3_sd_RD = 0.,roi3_sd_L1 = 0.,roi3_sd_FA = 0.; float tempMD,tempFA,tempRD,tempL1; char dset_or[4] = "RAI"; THD_3dim_dataset *dsetn; int TV_switch[3] = {0,0,0}; TAYLOR_BUNDLE *tb=NULL; TAYLOR_TRACT *tt=NULL; char *mode = "NI_fast_binary"; NI_element *nel=NULL; int dump_opts=0; tv_io_header header1 = {.id_string = "TRACK\0", .origin = {0,0,0}, .n_scalars = 3, .scal_n[0] = "FA", .scal_n[1] = "MD", .scal_n[2] = "L1", .n_properties = 0, .vox_to_ras = {{0.,0.,0.,0.},{0.,0.,0.,0.}, {0.,0.,0.,0.},{0.,0.,0.,0.}}, // reset this later based on actual data set .voxel_order = "RAI\0", .invert_x = 0, .invert_y = 0, .invert_z = 0, .swap_xy = 0, .swap_yz = 0, .swap_zx = 0, .n_count = 0, .version = 2, .hdr_size = 1000}; // for testing names... char *postfix[4]={"+orig.HEAD\0",".nii.gz\0",".nii\0","+tlrc.HEAD\0"}; int FOUND =-1; int RECORD_ORIG = 0; float Orig[3] = {0.0,0.0,0.0}; mainENTRY("3dTrackID"); machdep(); // **************************************************************** // **************************************************************** // load AFNI stuff // **************************************************************** // **************************************************************** INFO_message("version: MU"); /** scan args **/ if (argc == 1) { usage_TrackID(1); exit(0); } iarg = 1; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0 ) { usage_TrackID(strlen(argv[iarg])>3 ? 2:1); exit(0); } if( strcmp(argv[iarg],"-verb") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-verb'") ; set_tract_verb(atoi(argv[iarg])); iarg++ ; continue ; } if( strcmp(argv[iarg],"-write_opts") == 0) { dump_opts=1; iarg++ ; continue ; } if( strcmp(argv[iarg],"-rec_orig") == 0) { RECORD_ORIG=1; iarg++ ; continue ; } if( strcmp(argv[iarg],"-tract_out_mode") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-tract_out_mode'") ; if (strcmp(argv[iarg], "NI_fast_binary") && strcmp(argv[iarg], "NI_fast_text") && strcmp(argv[iarg], "NI_slow_binary") && strcmp(argv[iarg], "NI_slow_text") ) { ERROR_message("Bad value (%s) for -tract_out_mode",argv[iarg]); exit(1); } mode = argv[iarg]; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask1") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask1'") ; mset1 = THD_open_dataset( argv[iarg] ) ; if( mset1 == NULL ) ERROR_exit("Can't open mask1 dataset '%s'", argv[iarg]) ; DSET_load(mset1) ; CHECK_LOAD_ERROR(mset1) ; nmask1 = DSET_NVOX(mset1) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask2") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask2'") ; mset2 = THD_open_dataset( argv[iarg] ) ; if( mset2 == NULL ) ERROR_exit("Can't open mask2 dataset '%s'", argv[iarg]) ; DSET_load(mset2) ; CHECK_LOAD_ERROR(mset2) ; nmask2 = DSET_NVOX(mset2) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-prefix'"); prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal name after '-prefix'"); iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-input'"); for( i=0 ; i<4 ; i++) { sprintf(in_FA,"%s_FA%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_FA)) { FOUND = i; break; } } insetFA = THD_open_dataset(in_FA) ; if( (insetFA == NULL ) || (FOUND==-1)) ERROR_exit("Can't open dataset '%s': for FA.",in_FA); DSET_load(insetFA) ; CHECK_LOAD_ERROR(insetFA) ; Nvox = DSET_NVOX(insetFA) ; Dim[0] = DSET_NX(insetFA); Dim[1] = DSET_NY(insetFA); Dim[2] = DSET_NZ(insetFA); Ledge[0] = fabs(DSET_DX(insetFA)); Ledge[1] = fabs(DSET_DY(insetFA)); Ledge[2] = fabs(DSET_DZ(insetFA)); Orig[0] = DSET_XORG(insetFA); Orig[1] = DSET_YORG(insetFA); Orig[2] = DSET_ZORG(insetFA); // check tot num vox match (as proxy for dims...) if( (Nvox != nmask1) || (Nvox != nmask2) ) ERROR_exit("Input dataset does not match both mask volumes!"); // this stores the original data file orientation for later use, // as well since we convert everything to RAI temporarily, as // described below header1.voxel_order[0]=ORIENT_typestr[insetFA->daxes->xxorient][0]; header1.voxel_order[1]=ORIENT_typestr[insetFA->daxes->yyorient][0]; header1.voxel_order[2]=ORIENT_typestr[insetFA->daxes->zzorient][0]; for( i=0 ; i<3 ; i++) { header1.dim[i] = Dim[i]; header1.voxel_size[i] = Ledge[i]; // will want this when outputting file later for TrackVis. TV_switch[i] = !(dset_or[i]==header1.voxel_order[i]); } dset_or[3]='\0'; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_V1,"%s_V1%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_V1)) { FOUND = i; break; } } insetV1 = THD_open_dataset(in_V1); if( insetV1 == NULL ) ERROR_exit("Can't open dataset '%s':V1",in_V1); DSET_load(insetV1) ; CHECK_LOAD_ERROR(insetV1) ; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_L1,"%s_L1%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_L1)) { FOUND = i; break; } } insetL1 = THD_open_dataset(in_L1); if( insetL1 == NULL ) ERROR_exit("Can't open dataset '%s':L1",in_L1); DSET_load(insetL1) ; CHECK_LOAD_ERROR(insetL1) ; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_MD,"%s_MD%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_MD)) { FOUND = i; break; } } insetMD = THD_open_dataset(in_MD); if( insetMD == NULL ) ERROR_exit("Can't open dataset '%s':MD",in_MD); DSET_load(insetMD) ; CHECK_LOAD_ERROR(insetMD) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-algopt") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-algopt'"); if (!(nel = ReadTractAlgOpts(argv[iarg]))) { ERROR_message("Failed to read options in %s\n", argv[iarg]); exit(19); } if (NI_getTractAlgOpts(nel, &MinFA, &MaxAngDeg, &MinL, SeedPerV, &M, &bval)) { ERROR_message("Failed to get options"); exit(1); } NI_free_element(nel); nel=NULL; iarg++ ; continue ; } if( strcmp(argv[iarg],"-logic") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-logic'"); INFO_message("ROI logic type is: %s",argv[iarg]); if( strcmp(argv[iarg],"AND") == 0 ) LOG_TYPE = 1; else if( strcmp(argv[iarg],"OR") == 0 ) LOG_TYPE = 0; else if( strcmp(argv[iarg],"ALL") == 0 ) LOG_TYPE = -1; else ERROR_exit("Illegal after '-logic': need 'OR' or 'AND'"); iarg++ ; continue ; } //@@ if( strcmp(argv[iarg],"-extra_set") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-extra_set'"); EXTRAFILE = 1; // switch on insetEXTRA = THD_open_dataset(argv[iarg]); if( (insetEXTRA == NULL ) ) ERROR_exit("Can't open dataset '%s': for extra set.",argv[iarg]); DSET_load(insetEXTRA) ; CHECK_LOAD_ERROR(insetEXTRA) ; if( !((Dim[0] == DSET_NX(insetEXTRA)) && (Dim[1] == DSET_NY(insetEXTRA)) && (Dim[2] == DSET_NZ(insetEXTRA)))) ERROR_exit("Dimensions of extra set '%s' don't match those of the DTI prop ones ('%s', etc.).",argv[iarg], in_FA); iarg++ ; continue ; } ERROR_message("Bad option '%s'\n",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } if (iarg < 4) { ERROR_message("Too few options. Try -help for details.\n"); exit(1); } if (dump_opts) { nel = NI_setTractAlgOpts(NULL, &MinFA, &MaxAngDeg, &MinL, SeedPerV, &M, &bval); WriteTractAlgOpts(prefix, nel); NI_free_element(nel); nel=NULL; } // Process the options a little for( i=0 ; i<3 ; i++) DimSeed[i] = Dim[i]*SeedPerV[i]; Nseed = Nvox*SeedPerV[0]*SeedPerV[1]*SeedPerV[2]; // convert to cos of rad value for comparisons, instead of using acos() MaxAng = cos(CONV*MaxAngDeg); // switch to add header-- option for now, added Sept. 2012 // for use with map_TrackID to map tracks to different space if(RECORD_ORIG) { for( i=0 ; i<3 ; i++) header1.origin[i] = Orig[i]; } // at some point, we will have to convert indices into // pseudo-locations; being forced into this choice means that // different data set orientations would be represented differently // and incorrectly in some instances... so, for now, we'll resample // everything to RAI, and then resample back later. guess this will // just slow things down slightly. // have all be RAI for processing here if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(insetFA, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetFA); insetFA=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetMD, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetMD); insetMD=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetV1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetV1); insetV1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetL1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetL1); insetL1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(mset1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(mset1); mset1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(mset2, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(mset2); mset2=dsetn; dsetn=NULL; if(EXTRAFILE) { dsetn = r_new_resam_dset(insetEXTRA, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetEXTRA); insetEXTRA=dsetn; dsetn=NULL; } } // **************************************************************** // **************************************************************** // make arrays for tracking // **************************************************************** // **************************************************************** // for temp storage array, just a multiple of longest dimension! if(Dim[0] > Dim[1]) ArrMax = Dim[0] * 4; else ArrMax = Dim[1] * 4; if(4*Dim[2] > ArrMax) ArrMax = Dim[2] * 4; ROI1 = (int *)calloc(Nvox, sizeof(int)); ROI2 = (int *)calloc(Nvox, sizeof(int)); temp_arr = (short int *)calloc(Nvox, sizeof(short int)); temp_byte = (char *)calloc(Nvox, sizeof(char)); // temp storage whilst tracking Tforw = calloc(ArrMax, sizeof(Tforw)); for(i=0 ; i<ArrMax ; i++) Tforw[i] = calloc(3, sizeof(int)); Ttot = calloc(2*ArrMax , sizeof(Ttot)); for(i=0 ; i<2*ArrMax ; i++) Ttot[i] = calloc(3, sizeof(int)); Tback = calloc(ArrMax, sizeof(Tback)); for(i=0 ; i<ArrMax ; i++) Tback[i] = calloc(3, sizeof(int)); // temp storage whilst tracking, physical loc flTforw = calloc(ArrMax, sizeof(flTforw)); for(i=0 ; i<ArrMax ; i++) flTforw[i] = calloc(3, sizeof(int)); flTback = calloc(ArrMax,sizeof(flTback)); for(i=0 ; i<ArrMax ; i++) flTback[i] = calloc(3, sizeof(int)); if( (ROI1 == NULL) || (ROI2 == NULL) || (temp_arr == NULL) || (Tforw == NULL) || (Tback == NULL) || (flTforw == NULL) || (flTback == NULL) || (Ttot == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(12); } coorded = (float ****) calloc( Dim[0], sizeof(float ***) ); for ( i = 0 ; i < Dim[0] ; i++ ) coorded[i] = (float ***) calloc( Dim[1], sizeof(float **) ); for ( i = 0 ; i < Dim[0] ; i++ ) for ( j = 0 ; j < Dim[1] ; j++ ) coorded[i][j] = (float **) calloc( Dim[2], sizeof(float *) ); for ( i=0 ; i<Dim[0] ; i++ ) for ( j=0 ; j<Dim[1] ; j++ ) for ( k= 0 ; k<Dim[2] ; k++ ) //3 comp of V1 and FA coorded[i][j][k] = (float *) calloc( 4, sizeof(float) ); INDEX = (int ****) calloc( Dim[0], sizeof(int ***) ); for ( i = 0 ; i < Dim[0] ; i++ ) INDEX[i] = (int ***) calloc( Dim[1], sizeof(int **) ); for ( i = 0 ; i < Dim[0] ; i++ ) for ( j = 0 ; j < Dim[1] ; j++ ) INDEX[i][j] = (int **) calloc( Dim[2], sizeof(int *) ); for ( i=0 ; i<Dim[0] ; i++ ) for ( j=0 ; j<Dim[1] ; j++ ) for ( k= 0 ; k<Dim[2] ; k++ ) INDEX[i][j][k] = (int *) calloc( 4, sizeof(int) ); // this statement will never be executed if allocation fails above if( (INDEX == NULL) || (coorded == NULL) ) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(122); } for(i=0 ; i<Nvox ; i++) { if(THD_get_voxel( mset1, i, 0) >0.5){ ROI1[i] = 1; } if(THD_get_voxel( mset2, i, 0) >0.5) ROI2[i] = 1; } // set up eigvecs in 3D coord sys, // mark off where ROIs are and keep index handy idx=0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { for( m=0 ; m<3 ; m++ ) coorded[i][j][k][m] = THD_get_voxel(insetV1, idx, m); if(EXTRAFILE) coorded[i][j][k][3] = THD_get_voxel(insetEXTRA, idx, 0); else coorded[i][j][k][3] = THD_get_voxel(insetFA, idx, 0); // make sure that |V1| == 1 for all eigenvects, otherwise it's /// a problem in the tractography; currently, some from // 3dDWItoDT do not have this property... tempvmagn = sqrt(coorded[i][j][k][0]*coorded[i][j][k][0]+ coorded[i][j][k][1]*coorded[i][j][k][1]+ coorded[i][j][k][2]*coorded[i][j][k][2]); if( tempvmagn<0.99 ) for( m=0 ; m<3 ; m++ ) coorded[i][j][k][m]/= tempvmagn; INDEX[i][j][k][0] =idx; // first value is the index itself if( ROI1[idx]==1 ) INDEX[i][j][k][1]=1; // second value identifies ROI1 mask else INDEX[i][j][k][1]=0; if( ROI2[idx]==1 ) INDEX[i][j][k][2]=1; // third value identifies ROI2 mask else INDEX[i][j][k][2]=0; // fourth value will be counter for number of kept tracks // passing through INDEX[i][j][k][3] = 0; idx+= 1; } // ************************************************************* // ************************************************************* // Beginning of main loop // ************************************************************* // ************************************************************* Numtract = 0; ave_tract_len = 0.; ave_tract_len_phys = 0.; sprintf(OUT_bin,"%s.trk",prefix); if( (fout0 = fopen(OUT_bin, "w")) == NULL) { fprintf(stderr, "Error opening file %s.",OUT_bin); exit(16); } fwrite(&header1,sizeof(tv_io_header),1,fout0); if (get_tract_verb()) { INFO_message("Begin tracking..."); } tb = AppCreateBundle(NULL, 0, NULL, insetFA); // start bundle id = 0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) if(coorded[i][j][k][3] >= MinFA) { for( ii=0 ; ii<SeedPerV[0] ; ii++ ) for( jj=0 ; jj<SeedPerV[1] ; jj++ ) for( kk=0 ; kk<SeedPerV[2] ; kk++ ) { in[0] = i; in[1] = j; in[2] = k; physin[0] = ((float) in[0] + (0.5 + (float) ii)/SeedPerV[0])*Ledge[0]; physin[1] = ((float) in[1] + (0.5 + (float) jj)/SeedPerV[1])*Ledge[1]; physin[2] = ((float) in[2] + (0.5 + (float) kk)/SeedPerV[2])*Ledge[2]; len_forw = TrackIt(coorded, in, physin, Ledge, Dim, MinFA, MaxAng, ArrMax, Tforw, flTforw, 1, phys_forw); // reset, because it's changed in TrackIt func in[0] = i; in[1] = j; in[2] = k; physin[0] = ((float) in[0] + (0.5 + (float) ii)/SeedPerV[0])*Ledge[0]; physin[1] = ((float) in[1] + (0.5 + (float) jj)/SeedPerV[1])*Ledge[1]; physin[2] = ((float) in[2] + (0.5 + (float) kk)/SeedPerV[2])*Ledge[2]; len_back = TrackIt(coorded, in, physin, Ledge, Dim, MinFA, MaxAng, ArrMax, Tback, flTback, -1, phys_back); KEEPIT = 0; // a simple switch totlen = len_forw+len_back-1; // NB: overlap of starts totlen_phys = phys_forw[0] + phys_back[0]; if( totlen_phys >= MinL ) { // glue together for simpler notation later for( n=0 ; n<len_back ; n++) { // all of this rr = len_back-n-1; // read in backward for(m=0;m<3;m++) Ttot[rr][m] = Tback[n][m]; } for( n=1 ; n<len_forw ; n++){// skip first->overlap rr = n+len_back-1; // put after for(m=0;m<3;m++) Ttot[rr][m] = Tforw[n][m]; } // <<So close and orthogonal condition>>: // test projecting ends, to see if they abut ROI. for(m=0;m<3;m++) { //actual projected ends end[1][m] = 2*Ttot[totlen-1][m]-Ttot[totlen-2][m]; end[0][m] = 2*Ttot[0][m]-Ttot[1][m]; // default choice, just retest known ends // as default test_ind[1][m] = test_ind[0][m] = Ttot[0][m]; } tt = Create_Tract(len_back, flTback, len_forw, flTforw, id, insetFA); ++id; if (LOG_TYPE == -1) { KEEPIT = 1; } else { inroi1 = 0; // check forw for( n=0 ; n<len_forw ; n++) { if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][1]==1){ inroi1 = 1; break; } else continue; } if( inroi1==0 ){// after 1st half, check 2nd half for( m=0 ; m<len_back ; m++) { if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][1]==1){ inroi1 = 1; break; } else continue; } } // after 1st&2nd halves, check bound/neigh if( inroi1==0 ) { if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][1]==1) inroi1 = 1; if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][1]==1) inroi1 = 1; } if( ((LOG_TYPE ==0) && (inroi1 ==0)) || ((LOG_TYPE ==1) && (inroi1 ==1))) { // have to check in ROI2 inroi2 = 0; // check forw for( n=0 ; n<len_forw ; n++) { if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][2]==1){ inroi2 = 1; break; } else continue; } //after 1st half, check 2nd half if( inroi2==0 ) { for( m=0 ; m<len_back ; m++) { if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][2]==1){ inroi2 = 1; break; } else continue; } } // after 1st&2nd halves, check bound/neigh if( inroi2==0 ) { if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][2]==1) inroi2 = 1; if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][2]==1) inroi2 = 1; } // for both cases, need to see it here to keep if( inroi2 ==1 ) KEEPIT = 1; // otherwise, it's gone } else if((LOG_TYPE ==0) && (inroi1 ==1)) KEEPIT = 1; } } // by now, we *know* if we're keeping this or not. if( KEEPIT == 1 ) { tb = AppCreateBundle(tb, 1, tt, NULL); tt = Free_Tracts(tt, 1); READS_in = totlen; fwrite(&READS_in,sizeof(READS_in),1,fout0); for( n=0 ; n<len_back ; n++) { //put this one in backwords, to make it connect m = len_back - 1 - n; for(aa=0 ; aa<3 ; aa++) { // recenter phys loc for trackvis, if nec... // just works this way (where they define // origin) READS_fl = flTback[m][aa]; if(!TV_switch[aa]) READS_fl = Ledge[aa]*Dim[aa]-READS_fl; fwrite(&READS_fl,sizeof(READS_fl),1,fout0); } mm = INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][0]; READS_fl =THD_get_voxel(insetFA, mm, 0); // FA fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetMD, mm, 0); // MD fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetL1, mm, 0); // L1 fwrite(&READS_fl,sizeof(READS_fl),1,fout0); // count this voxel for having a tract INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][3]+= 1; } for( m=1 ; m<len_forw ; m++) { for(aa=0 ; aa<3 ; aa++) { // recenter phys loc for trackvis, if nec... READS_fl = flTforw[m][aa]; if(!TV_switch[aa]) READS_fl = Ledge[aa]*Dim[aa]-READS_fl; fwrite(&READS_fl,sizeof(READS_fl),1,fout0); } mm = INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][0]; READS_fl =THD_get_voxel(insetFA, mm, 0); // FA fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetMD, mm, 0); // MD fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetL1, mm, 0); // L1 fwrite(&READS_fl,sizeof(READS_fl),1,fout0); // count this voxel for having a tract INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][3]+= 1; } ave_tract_len+= totlen; ave_tract_len_phys+= totlen_phys; Numtract+=1; } } } fclose(fout0); if (get_tract_verb()) { INFO_message("Done tracking, have %d tracks.", tb->N_tracts); Show_Taylor_Bundle(tb, NULL, 3); } if (!Write_Bundle(tb,prefix,mode)) { ERROR_message("Failed to write the bundle"); } // ************************************************************** // ************************************************************** // Some simple stats on ROIs and outputs // ************************************************************** // ************************************************************** for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { if( INDEX[i][j][k][3]>=1 ) { tempMD = THD_get_voxel(insetMD,INDEX[i][j][k][0],0); tempFA = THD_get_voxel(insetFA,INDEX[i][j][k][0],0); tempL1 = THD_get_voxel(insetL1,INDEX[i][j][k][0],0); tempRD = 0.5*(3*tempMD-tempL1); roi3_mu_MD+= tempMD; roi3_mu_FA+= tempFA; roi3_mu_L1+= tempL1; roi3_mu_RD+= tempRD; roi3_sd_MD+= tempMD*tempMD; roi3_sd_FA+= tempFA*tempFA; roi3_sd_L1+= tempL1*tempL1; roi3_sd_RD+= tempRD*tempRD; roi3_ct+= 1; } } if(roi3_ct > 0 ) { // !!!! make into afni file roi3_mu_MD/= (float) roi3_ct; roi3_mu_FA/= (float) roi3_ct; roi3_mu_L1/= (float) roi3_ct; roi3_mu_RD/= (float) roi3_ct; roi3_sd_MD-= roi3_ct*roi3_mu_MD*roi3_mu_MD; roi3_sd_FA-= roi3_ct*roi3_mu_FA*roi3_mu_FA; roi3_sd_L1-= roi3_ct*roi3_mu_L1*roi3_mu_L1; roi3_sd_RD-= roi3_ct*roi3_mu_RD*roi3_mu_RD; roi3_sd_MD/= (float) roi3_ct-1; roi3_sd_FA/= (float) roi3_ct-1; roi3_sd_L1/= (float) roi3_ct-1; roi3_sd_RD/= (float) roi3_ct-1; roi3_sd_MD = sqrt(roi3_sd_MD); roi3_sd_FA = sqrt(roi3_sd_FA); roi3_sd_L1 = sqrt(roi3_sd_L1); roi3_sd_RD = sqrt(roi3_sd_RD); sprintf(OUT_tracstat,"%s.stats",prefix); if( (fout0 = fopen(OUT_tracstat, "w")) == NULL) { fprintf(stderr, "Error opening file %s.",OUT_tracstat); exit(19); } fprintf(fout0,"%d\t%d\n",Numtract,roi3_ct); fprintf(fout0,"%.3f\t%.3f\n",ave_tract_len/Numtract, ave_tract_len_phys/Numtract); // as usual, these next values would have to be divided by the // bval to get their actual value in standard phys units fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_FA,roi3_sd_FA); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_MD,roi3_sd_MD); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_RD,roi3_sd_RD); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_L1,roi3_sd_L1); fclose(fout0); sprintf(prefix_map,"%s_MAP",prefix); sprintf(prefix_mask,"%s_MASK",prefix); outsetMAP = EDIT_empty_copy( mset1 ) ; EDIT_dset_items( outsetMAP , ADN_datum_all , MRI_short , ADN_prefix , prefix_map , ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMAP)); outsetMASK = EDIT_empty_copy( mset1 ) ; EDIT_dset_items( outsetMASK , ADN_datum_all , MRI_byte , ADN_prefix , prefix_mask , ADN_none ) ; if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMASK)); m=0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { temp_arr[m]=INDEX[i][j][k][3]; if(temp_arr[m]>0.5) temp_byte[m]=1; else temp_byte[m]=0; m++; } // re-orient the data as original inputs // (this function copies the pointer) EDIT_substitute_brick(outsetMAP, 0, MRI_short, temp_arr); temp_arr=NULL; if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(outsetMAP, NULL, 0.0, 0.0, 0.0, header1.voxel_order, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(outsetMAP); outsetMAP=dsetn; dsetn=NULL; } EDIT_dset_items( outsetMAP , ADN_prefix , prefix_map , ADN_none ) ; THD_load_statistics(outsetMAP ); if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMAP)); tross_Make_History( "3dTrackID" , argc , argv , outsetMAP) ; THD_write_3dim_dataset(NULL, NULL, outsetMAP, True); // re-orient the data as original inputs EDIT_substitute_brick(outsetMASK, 0, MRI_byte, temp_byte); temp_byte=NULL; if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(outsetMASK, NULL, 0.0, 0.0, 0.0, header1.voxel_order, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(outsetMASK); outsetMASK=dsetn; dsetn=NULL; } EDIT_dset_items( outsetMASK , ADN_prefix , prefix_mask , ADN_none ) ; THD_load_statistics(outsetMASK); if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMASK)); tross_Make_History( "3dTrackID" , argc , argv , outsetMASK) ; THD_write_3dim_dataset(NULL, NULL, outsetMASK, True); INFO_message("Number of tracts found = %d",Numtract) ; } else INFO_message("\n No Tracts Found!!!\n"); // ************************************************************ // ************************************************************ // Freeing // ************************************************************ // ************************************************************ // !!! need to free afni-sets? DSET_delete(insetFA); DSET_delete(insetMD); DSET_delete(insetL1); DSET_delete(insetV1); DSET_delete(insetEXTRA); //DSET_delete(outsetMAP); //DSET_delete(outsetMASK); DSET_delete(mset2); DSET_delete(mset1); free(prefix); free(insetV1); free(insetFA); free(mset1); free(mset2); free(insetEXTRA); free(ROI1); free(ROI2); free(temp_byte); for( i=0 ; i<ArrMax ; i++) { free(Tforw[i]); free(Tback[i]); free(flTforw[i]); free(flTback[i]); } free(Tforw); free(Tback); free(flTforw); free(flTback); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) for( k=0 ; k<Dim[2] ; k++) free(coorded[i][j][k]); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) free(coorded[i][j]); for( i=0 ; i<Dim[0] ; i++) free(coorded[i]); free(coorded); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) for( k=0 ; k<Dim[2] ; k++) free(INDEX[i][j][k]); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) free(INDEX[i][j]); for( i=0 ; i<Dim[0] ; i++) free(INDEX[i]); free(INDEX); free(temp_arr); // need to free for( i=0 ; i<2*ArrMax ; i++) free(Ttot[i]); free(Ttot); //free(mode); return 0; }
int main( int argc , char *argv[] ) { char *prefix = "Deghost" ; int iarg ; int fe=1 , pe=2 , se=3 , nvals ; THD_3dim_dataset *inset=NULL , *outset , *filset=NULL ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ) { printf( "Usage: 3dDeghost [options] dataset\n" "\n" "* This program tries do remove N/2 (AKA Nyquist) ghosts from an EPI\n" " magnitude time series dataset.\n" "* If you apply it to some other kind of dataset (e.g., spiral), weird\n" " things will probably transpire.\n" "* The input EPI dataset should NOT be filtered, masked, cropped,\n" " registered, or pre-processed in any way!\n" "* This program will not work well if the input EPI dataset is heavily\n" " 'shaded' -- that is, its intensity varies dramatically inside the brain.\n" "* The output dataset is always stored in float format.\n" "* Only the Amitabha Buddha knows if this program is actually useful.\n" "\n" "========\n" "OPTIONS:\n" "========\n" " -input dataset = Another way to specify the input dataset\n" " -prefix pp = Use 'pp' for prefix of output dataset\n" " -FPS abc = Define the Frequency, Phase, and Slice\n" " directions in the dataset based on the\n" " axis orientations inside the dataset header\n" " (e.g., see the output of 3dinfo). The 'abc'\n" " code is a permutaton of the digits '123'.\n" " * The first digit 'a' specifies which dataset\n" " axis/index is the Frequency encoding direction.\n" " * The second digit 'b' specifies which dataset\n" " direction is the Phase encoding direction.\n" " * The third digit 'c' specifies which dataset\n" " direction is the Slice encoding direction.\n" " -->>** The default value for 'abc' is '123'; that is,\n" " the dataset is ordered so that the first index\n" " (x-axis) is frequency, the second index is phase,\n" " and the third index is slice. In most cases,\n" " this is how the reconstruction software will\n" " store the images. Only in unusual cases should\n" " you need the '-FPS' option!\n" " -filt N = Length of time series filter to apply when\n" " estimating ghosting parameters. Set N to 0 or 1\n" " to turn this feature off; otherwise, N should be an\n" " odd positive integer from 3 to 19 [default N=%d].\n" " * Longer filter lengths ARE allowed, but will be slow\n" " (cases with N <= 19 are hand coded for speed).\n" " * Datasets with fewer than 4 time points will not\n" " be filtered. For longer datasets, if the filter\n" " length is too big, it will be shortened ruthlessly.\n" "=======\n" "METHOD:\n" "=======\n" "Would you believe me if I said magic? Would you accept secret algorithms\n" "known only to the Olmecs? How about something so ad hoc that it cannot\n" "be described without embarrasment and shame?\n" "\n" "-- Feb 2014 - Zhark the Phantasmal\n" , orfilt_len ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dDeghost main"); machdep(); AFNI_logger("3dDeghost",argc,argv); PRINT_VERSION("3dDeghost") ; /*-- scan command line --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ) { /*---*/ if( strcasecmp(argv[iarg],"-quiet") == 0 ) { verb = 0 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-verb") == 0 ) { verb++ ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-filt") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; orfilt_len = (int)strtod(argv[iarg],NULL) ; if( orfilt_len > 1 && orfilt_len%2 == 0 ) { orfilt_len++ ; INFO_message("-filt %d has been adjusted to %d (must be odd)" , orfilt_len-1 , orfilt_len) ; } if( orfilt_len > 19 ) WARNING_message("-filt %d is over the recommended limit of 19",orfilt_len) ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-prefix") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix!\n"); iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-input") == 0 || strcasecmp(argv[iarg],"-inset") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; if( inset != NULL ) ERROR_exit("You can't give the input dataset twice!") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-FPS") == 0 ) { /* stolen from 3dAllineate.c */ char *fps ; if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; fps = argv[iarg] ; if( strlen(fps) < 3 ) ERROR_exit("Code '%s' after '%s' is too short", fps , argv[iarg-1] ) ; switch( fps[0] ) { default: ERROR_exit("Illegal '%s' F code '%c' :-(" , argv[iarg-1],fps[0] ); case 'i': case 'I': case 'x': case 'X': case '1': fe = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': fe = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': fe = 3; break; } switch( fps[1] ) { default: ERROR_exit("Illegal '%s' P code '%c' :-(" , argv[iarg-1],fps[1] ); case 'i': case 'I': case 'x': case 'X': case '1': pe = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': pe = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': pe = 3; break; } switch( fps[2] ) { default: ERROR_exit("Illegal '%s' S code '%c' :-(" , argv[iarg-1],fps[2] ); case 'i': case 'I': case 'x': case 'X': case '1': se = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': se = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': se = 3; break; } if( fe+pe+se != 6 ) ERROR_exit("Code '%s' after '%s' is nonsensical", fps , argv[iarg-1] ) ; iarg++ ; continue ; } /*---*/ ERROR_exit("Unknown option: %s\n",argv[iarg]); } if( inset == NULL && iarg >= argc ) ERROR_exit("No dataset name on command line?\n"); /*-- read input if needed --*/ if( inset == NULL ) { inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load( inset ) ; CHECK_LOAD_ERROR(inset) ; } /*-- filter input? --*/ nvals = DSET_NVALS(inset) ; if( orfilt_len > nvals/2 ) { orfilt_len = nvals/2 ; if( orfilt_len%2 == 0 ) orfilt_len++ ; } if( orfilt_len > 1 && nvals > 1 ) { MRI_vectim *invect ; int ii ; if( verb ) INFO_message("Filtering input dataset: filter length=%d",orfilt_len) ; invect = THD_dset_to_vectim(inset,NULL,0) ; THD_vectim_applyfunc( invect , orfilt_vector ) ; filset = EDIT_empty_copy( inset ) ; for( ii=0 ; ii < nvals ; ii++ ) EDIT_substitute_brick( filset , ii , MRI_float , NULL ) ; THD_vectim_to_dset( invect , filset ) ; VECTIM_destroy(invect) ; } else { if( verb ) INFO_message("Time series filtering is turned off") ; } /***** outsource the work *****/ outset = THD_deghoster( inset , (filset!=NULL)?filset:inset , pe,fe,se ) ; if( outset == NULL ) ERROR_exit("THD_deghoster fails :-(((") ; if( filset != NULL ) DSET_delete(filset) ; EDIT_dset_items( outset , ADN_prefix,prefix , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dDeghost" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }
int main( int argc , char *argv[] ) { int iarg , nerr=0 , nvals,nvox , nx,ny,nz , ii,jj,kk ; char *prefix="LSSout" , *save1D=NULL , nbuf[256] ; THD_3dim_dataset *inset=NULL , *outset ; MRI_vectim *inset_mrv=NULL ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0, automask=0, nmask=0 ; NI_element *nelmat=NULL ; char *matname=NULL ; char *cgl ; int Ngoodlist,*goodlist=NULL , nfull , ncmat,ntime ; NI_int_array *giar ; NI_str_array *gsar ; NI_float_array *gfar ; MRI_IMAGE *imX, *imA, *imC, *imS ; float *Xar, *Sar ; MRI_IMARR *imar ; int nS ; float *ss , *oo , *fv , sum ; int nvec , iv ; int nbstim , nst=0 , jst_bot,jst_top ; char *stlab="LSS" ; int nodata=1 ; /*--- help me if you can ---*/ if( argc < 2 || strcasecmp(argv[1],"-HELP") == 0 ) LSS_help() ; /*--- bureaucratic startup ---*/ PRINT_VERSION("3dLSS"); mainENTRY("3dLSS main"); machdep(); AFNI_logger("3dLSS",argc,argv); AUTHOR("RWCox"); (void)COX_clock_time() ; /**------- scan command line --------**/ iarg = 1 ; while( iarg < argc ){ if( strcmp(argv[iarg],"-verb") == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-VERB") == 0 ){ verb+=2 ; iarg++ ; continue ; } /**========== -mask ==========**/ if( strcasecmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%.33s'",argv[iarg]) ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb || nmask < 1 ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < 1 ) ERROR_exit("Mask is too small to process") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't have -automask and -mask") ; automask = 1 ; iarg++ ; continue ; } /**========== -matrix ==========**/ if( strcasecmp(argv[iarg],"-matrix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; if( nelmat != NULL ) ERROR_exit("More than 1 -matrix option!?"); nelmat = NI_read_element_fromfile( argv[iarg] ) ; /* read NIML file */ matname = argv[iarg]; if( nelmat == NULL || nelmat->type != NI_ELEMENT_TYPE ) ERROR_exit("Can't process -matrix file '%s'!?",matname) ; iarg++ ; continue ; } /**========== -nodata ===========**/ if( strcasecmp(argv[iarg],"-nodata") == 0 ){ nodata = 1 ; iarg++ ; continue ; } /**========== -input ==========**/ if( strcasecmp(argv[iarg],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have two -input options!?") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; nodata = 0 ; iarg++ ; continue ; } /**========== -prefix =========**/ if( strcasecmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal string after %s",argv[iarg-1]) ; if( verb && strcmp(prefix,"NULL") == 0 ) INFO_message("-prefix NULL ==> no dataset will be written") ; iarg++ ; continue ; } /**========== -save1D =========**/ if( strcasecmp(argv[iarg],"-save1D") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; save1D = strdup(argv[iarg]) ; if( !THD_filename_ok(save1D) ) ERROR_exit("Illegal string after %s",argv[iarg-1]) ; iarg++ ; continue ; } /***** Loser User *****/ ERROR_message("Unknown option: %s",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } /* end of loop over options */ /*----- check for errors -----*/ if( nelmat == NULL ){ ERROR_message("No -matrix option!?") ; nerr++ ; } if( nerr > 0 ) ERROR_exit("Can't continue without these inputs!") ; if( inset != NULL ){ nvals = DSET_NVALS(inset) ; nvox = DSET_NVOX(inset) ; nx = DSET_NX(inset) ; ny = DSET_NY(inset) ; nz = DSET_NZ(inset) ; } else { automask = nvals = 0 ; nvox = nx = ny = nz = nodata = 1 ; /* nodata */ mask = NULL ; } /*----- masque -----*/ if( mask != NULL ){ /* check -mask option for compatibility */ if( mask_nx != nx || mask_ny != ny || mask_nz != nz ) ERROR_exit("-mask dataset grid doesn't match input dataset :-(") ; } else if( automask ){ /* create a mask from input dataset */ mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset :-(") ; nmask = THD_countmask( nvox , mask ) ; if( verb || nmask < 1 ) INFO_message("Number of voxels in automask = %d (out of %d = %.1f%%)", nmask, nvox, (100.0f*nmask)/nvox ) ; if( nmask < 1 ) ERROR_exit("Automask is too small to process") ; } else if( !nodata ) { /* create a 'mask' for all voxels */ if( verb ) INFO_message("No mask ==> computing for all %d voxels",nvox) ; mask = (byte *)malloc(sizeof(byte)*nvox) ; nmask = nvox ; memset( mask , 1 , sizeof(byte)*nvox ) ; } /*----- get matrix info from the NIML element -----*/ if( verb ) INFO_message("extracting matrix info") ; ncmat = nelmat->vec_num ; /* number of columns */ ntime = nelmat->vec_len ; /* number of rows */ if( ntime < ncmat+2 ) ERROR_exit("Matrix has too many columns (%d) for number of rows (%d)",ncmat,ntime) ; /*--- number of rows in the full matrix (without censoring) ---*/ cgl = NI_get_attribute( nelmat , "NRowFull" ) ; if( cgl == NULL ) ERROR_exit("Matrix is missing 'NRowFull' attribute!") ; nfull = (int)strtod(cgl,NULL) ; if( nodata ){ nvals = nfull ; } else if( nvals != nfull ){ ERROR_exit("-input dataset has %d time points, but matrix indicates %d", nvals , nfull ) ; } /*--- the goodlist = mapping from matrix row index to time index (which allows for possible time point censoring) ---*/ cgl = NI_get_attribute( nelmat , "GoodList" ) ; if( cgl == NULL ) ERROR_exit("Matrix is missing 'GoodList' attribute!") ; giar = NI_decode_int_list( cgl , ";," ) ; if( giar == NULL || giar->num < ntime ) ERROR_exit("Matrix 'GoodList' badly formatted?!") ; Ngoodlist = giar->num ; goodlist = giar->ar ; if( Ngoodlist != ntime ) ERROR_exit("Matrix 'GoodList' incorrect length?!") ; else if( verb > 1 && Ngoodlist < nfull ) ININFO_message("censoring reduces time series length from %d to %d",nfull,Ngoodlist) ; /*--- extract the matrix from the NIML element ---*/ imX = mri_new( ntime , ncmat , MRI_float ) ; Xar = MRI_FLOAT_PTR(imX) ; if( nelmat->vec_typ[0] == NI_FLOAT ){ /* from 3dDeconvolve_f */ float *cd ; for( jj=0 ; jj < ncmat ; jj++ ){ cd = (float *)nelmat->vec[jj] ; for( ii=0 ; ii < ntime ; ii++ ) Xar[ii+jj*ntime] = cd[ii] ; } } else if( nelmat->vec_typ[0] == NI_DOUBLE ){ /* from 3dDeconvolve */ double *cd ; for( jj=0 ; jj < ncmat ; jj++ ){ cd = (double *)nelmat->vec[jj] ; for( ii=0 ; ii < ntime ; ii++ ) Xar[ii+jj*ntime] = cd[ii] ; } } else { ERROR_exit("Matrix file stored with illegal data type!?") ; } /*--- find the stim_times_IM option ---*/ cgl = NI_get_attribute( nelmat , "BasisNstim") ; if( cgl == NULL ) ERROR_exit("Matrix doesn't have 'BasisNstim' attribute!") ; nbstim = (int)strtod(cgl,NULL) ; if( nbstim <= 0 ) ERROR_exit("Matrix 'BasisNstim' attribute is %d",nbstim) ; for( jj=1 ; jj <= nbstim ; jj++ ){ sprintf(nbuf,"BasisOption_%06d",jj) ; cgl = NI_get_attribute( nelmat , nbuf ) ; if( cgl == NULL || strcmp(cgl,"-stim_times_IM") != 0 ) continue ; if( nst > 0 ) ERROR_exit("More than one -stim_times_IM option was found in the matrix") ; nst = jj ; sprintf(nbuf,"BasisColumns_%06d",jj) ; cgl = NI_get_attribute( nelmat , nbuf ) ; if( cgl == NULL ) ERROR_exit("Matrix doesn't have %s attribute!",nbuf) ; jst_bot = jst_top = -1 ; sscanf(cgl,"%d:%d",&jst_bot,&jst_top) ; if( jst_bot < 0 || jst_top < 0 ) ERROR_exit("Can't decode matrix attribute %s",nbuf) ; if( jst_bot == jst_top ) ERROR_exit("Matrix attribute %s shows only 1 column for -stim_time_IM:\n" " -->> 3dLSS is meant to be used when more than one stimulus\n" " time was given, and then it computes the response beta\n" " for each stim time separately. If you have only one\n" " stim time with -stim_times_IM, you can use the output\n" " dataset from 3dDeconvolve (or 3dREMLfit) to get that\n" " single beta directly.\n" , nbuf ) ; if( jst_bot >= jst_top || jst_top >= ncmat ) ERROR_exit("Matrix attribute %s has illegal value: %d:%d (ncmat=%d)",nbuf,jst_bot,jst_top,ncmat) ; sprintf(nbuf,"BasisName_%06d",jj) ; cgl = NI_get_attribute( nelmat , nbuf ) ; if( cgl != NULL ) stlab = strdup(cgl) ; if( verb > 1 ) ININFO_message("-stim_times_IM at stim #%d; cols %d..%d",jj,jst_bot,jst_top) ; } if( nst == 0 ) ERROR_exit("Matrix doesn't have any -stim_times_IM options inside :-(") ; /*--- mangle matrix to segregate IM regressors from the rest ---*/ if( verb ) INFO_message("setting up LSS vectors") ; imar = LSS_mangle_matrix( imX , jst_bot , jst_top ) ; if( imar == NULL ) ERROR_exit("Can't compute LSS 'mangled' matrix :-(") ; /*--- setup for LSS computations ---*/ imA = IMARR_SUBIM(imar,0) ; imC = IMARR_SUBIM(imar,1) ; imS = LSS_setup( imA , imC ) ; DESTROY_IMARR(imar) ; if( imS == NULL ) ERROR_exit("Can't complete LSS setup :-((") ; nS = imS->ny ; Sar = MRI_FLOAT_PTR(imS) ; if( save1D != NULL ){ mri_write_1D( save1D , imS ) ; if( verb ) ININFO_message("saved LSS vectors into file %s",save1D) ; } else if( nodata ){ WARNING_message("-nodata used but -save1D not used ==> you get no output!") ; } if( nodata || strcmp(prefix,"NULL") == 0 ){ INFO_message("3dLSS ends since prefix is 'NULL' or -nodata was used") ; exit(0) ; } /*----- create output dataset -----*/ if( verb ) INFO_message("creating output datset in memory") ; outset = EDIT_empty_copy(inset) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_datum_all , MRI_float , ADN_brick_fac , NULL , ADN_nvals , nS , ADN_ntt , nS , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dLSS" , argc,argv , outset ) ; for( kk=0 ; kk < nS ; kk++ ){ EDIT_substitute_brick( outset , kk , MRI_float , NULL ) ; sprintf(nbuf,"%s#%03d",stlab,kk) ; EDIT_BRICK_LABEL( outset , kk , nbuf ) ; } /*----- convert input dataset to vectim -----*/ if( verb ) INFO_message("loading input dataset into memory") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; inset_mrv = THD_dset_to_vectim( inset , mask , 0 ) ; DSET_unload(inset) ; /*----- compute dot products, store results -----*/ if( verb ) INFO_message("computing away, me buckos!") ; nvec = inset_mrv->nvec ; for( kk=0 ; kk < nS ; kk++ ){ ss = Sar + kk*ntime ; oo = DSET_ARRAY(outset,kk) ; for( iv=0 ; iv < nvec ; iv++ ){ fv = VECTIM_PTR(inset_mrv,iv) ; for( sum=0.0f,ii=0 ; ii < ntime ; ii++ ) sum += ss[ii] * fv[goodlist[ii]] ; oo[inset_mrv->ivec[iv]] = sum ; } } DSET_write(outset) ; WROTE_DSET(outset) ; /*-------- Hasta la vista, baby --------*/ if( verb ) INFO_message("3dLSS finished: total CPU=%.2f Elapsed=%.2f", COX_cpu_time() , COX_clock_time() ) ; exit(0) ; }
THD_3dim_dataset * fim3d_fimmer_compute ( THD_3dim_dataset * dset_time , time_series_array * ref_ts , time_series_array * ort_ts , int itbot, char * new_prefix, float max_percent /* 19 May 1997 */ ) { THD_3dim_dataset * new_dset ; int ifim , it,iv , nvox=0 , ngood_ref , ntime , it1 , dtyp , nxyz; float * vval , * tsar , * aval , * rbest , * abest ; int * indx=NULL ; short * bar ; void * ptr ; float stataux[MAX_STAT_AUX]; float fthr , topval ; int nx_ref , ny_ref , ivec , nnow ; PCOR_references ** pc_ref ; PCOR_voxel_corr ** pc_vc ; int save_resam ; int fim_nref , nx_ort , ny_ort=0 , internal_ort ; /* 10 Dec 1996 */ static float * ref_vec = NULL ; static int nref_vec = -666 ; float * ref_ts_min = NULL, * ref_ts_max = NULL, * baseline = NULL; /* 19 May 1997 */ int i; int nupdt = 0 , /* number of updates done yet */ min_updt = 5 ; /* min number needed for display */ /*--- check for legal inputs ---*/ /* 14 Jan 1998 */ if (!DSET_GRAPHABLE(dset_time)) { fprintf (stderr, "Error: Invalid 3d+time input data file \n"); RETURN (NULL); } if (ref_ts == NULL) { fprintf (stderr, "Error: No ideal time series \n"); RETURN (NULL); } for (i = 0; i < ref_ts->num; i++) if (ref_ts->tsarr[i]->len < DSET_NUM_TIMES(dset_time)) { fprintf (stderr, "Error: ideal time series is too short: ntime=%d num_ts=%d \n", DSET_NUM_TIMES(dset_time), ref_ts->tsarr[i]->len); RETURN (NULL) ; } /** 10 Dec 1996: allow for orts **/ if( ort_ts->num > 0 ) /** 05 Sept 1997 **/ { internal_ort = 0; ny_ort = ort_ts->num; for (i = 0; i < ny_ort; i++) { nx_ort = ort_ts->tsarr[i]->len ; if (nx_ort < DSET_NUM_TIMES(dset_time)) /* 14 Jan 1998 */ { fprintf (stderr, "Error: ort time series is too short: ntime=%d ort_ts=%d \n", DSET_NUM_TIMES(dset_time), ort_ts->tsarr[i]->len); RETURN (NULL) ; } } } else { internal_ort = 1 ; } fim_nref = (internal_ort) ? 3 : (ny_ort+3) ; if( nref_vec < fim_nref ) { ref_vec = (float *) malloc (sizeof(float)*fim_nref) ; nref_vec = fim_nref; } /* arrays to store maximum change in the ideal time series */ if (max_percent > 0.0) /* 19 May 1997 */ { ref_ts_max = (float *) malloc (sizeof(float) * (ref_ts->num)); ref_ts_min = (float *) malloc (sizeof(float) * (ref_ts->num)); } nx_ref = ref_ts->tsarr[0]->len; ny_ref = ref_ts->num; ntime = DSET_NUM_TIMES(dset_time) ; ngood_ref = 0 ; it1 = -1 ; for( ivec=0 ; ivec < ny_ref ; ivec++ ){ tsar = ref_ts->tsarr[ivec]->ts; ifim = 0 ; if (max_percent > 0.0) /* 19 May 1997 */ { ref_ts_min[ivec] = (float) SO_BIG; ref_ts_max[ivec] = - (float) SO_BIG; } for( it=itbot ; it < ntime ; it++ ) { if( tsar[it] < SO_BIG ) { ifim++ ; if( it1 < 0 ) it1 = it ; if (max_percent > 0.0) /* 19 May 1997 */ { if (tsar[it] > ref_ts_max[ivec]) ref_ts_max[ivec] = tsar[it]; if (tsar[it] < ref_ts_min[ivec]) ref_ts_min[ivec] = tsar[it]; } } } if( ifim < min_updt ){ STATUS("ref_ts has too few good entries!") ; RETURN(NULL) ; } ngood_ref = MAX( ifim , ngood_ref ) ; } /** at this point, ngood_ref = max number of good reference points, and it1 = index of first point used in first reference **/ dtyp = DSET_BRICK_TYPE(dset_time,it1) ; if( ! AFNI_GOOD_FUNC_DTYPE(dtyp) ){ STATUS("illegal input data type!") ; RETURN(NULL) ; } #ifdef AFNI_DEBUG { char str[256] ; sprintf(str,"new prefix = %s",new_prefix) ; STATUS(str) ; } #endif /*--- FIM: find values above threshold to fim ---*/ DSET_load(dset_time); CHECK_LOAD_ERROR(dset_time); nxyz = dset_time->dblk->diskptr->dimsizes[0] * dset_time->dblk->diskptr->dimsizes[1] * dset_time->dblk->diskptr->dimsizes[2] ; /** find the mean of the first array, compute the threshold (fthr) from it, make indx[i] be the 3D index of the i-th voxel above threshold **/ switch( dtyp ){ case MRI_short:{ short * dar = (short *) DSET_ARRAY(dset_time,it1) ; for( iv=0,fthr=0.0 ; iv < nxyz ; iv++ ) fthr += abs(dar[iv]) ; fthr = FIM_THR * fthr / nxyz ; for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( abs(dar[iv]) > fthr ) nvox++ ; indx = (int *) malloc( sizeof(int) * nvox ) ; if( indx == NULL ){ fprintf(stderr,"\n*** indx malloc failure in fim3d_fimmer_compute\n") ; RETURN(NULL) ; } for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( abs(dar[iv]) > fthr ) indx[nvox++] = iv ; } break ; case MRI_float:{ float * dar = (float *) DSET_ARRAY(dset_time,it1) ; for( iv=0,fthr=0.0 ; iv < nxyz ; iv++ ) fthr += fabs(dar[iv]) ; fthr = FIM_THR * fthr / nxyz ; for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( fabs(dar[iv]) > fthr ) nvox++ ; indx = (int *) malloc( sizeof(int) * nvox ) ; if( indx == NULL ){ fprintf(stderr,"\n*** indx malloc failure in fim3d_fimmer_compute\n") ; RETURN(NULL) ; } for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( fabs(dar[iv]) > fthr ) indx[nvox++] = iv ; } break ; case MRI_byte:{ byte * dar = (byte *) DSET_ARRAY(dset_time,it1) ; for( iv=0,fthr=0.0 ; iv < nxyz ; iv++ ) fthr += dar[iv] ; fthr = FIM_THR * fthr / nxyz ; for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( dar[iv] > fthr ) nvox++ ; indx = (int *) malloc( sizeof(int) * nvox ) ; if( indx == NULL ){ fprintf(stderr,"\n*** indx malloc failure in fim3d_fimmer_compute\n") ; RETURN(NULL) ; } for( iv=0,nvox=0 ; iv < nxyz ; iv++ ) if( dar[iv] > fthr ) indx[nvox++] = iv ; } break ; } /** allocate space for voxel values **/ vval = (float *) malloc( sizeof(float) * nvox) ; if( vval == NULL ){ fprintf(stderr,"\n*** vval malloc failure in fim3d_fimmer_compute\n") ; free(indx) ; RETURN(NULL) ; } /*----- allocate space for baseline values -----*/ if (max_percent > 0.0) /* 19 May 1997 */ { baseline = (float *) malloc (sizeof(float) * nvox); if (baseline == NULL) { fprintf(stderr, "\n*** baseline malloc failure in fim3d_fimmer_compute\n") ; free(indx) ; free(vval); RETURN(NULL) ; } else /* initialize baseline values to zero */ for (iv = 0; iv < nvox; iv++) baseline[iv] = 0.0; } /** allocate extra space for comparing results from multiple ref vectors **/ if( ny_ref > 1 ){ aval = (float *) malloc( sizeof(float) * nvox) ; rbest = (float *) malloc( sizeof(float) * nvox) ; abest = (float *) malloc( sizeof(float) * nvox) ; if( aval==NULL || rbest==NULL || abest==NULL ){ fprintf(stderr,"\n*** abest malloc failure in fim3d_fimmer_compute\n") ; free(vval) ; free(indx) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; RETURN(NULL) ; } } else { aval = rbest = abest = NULL ; } #ifdef AFNI_DEBUG { char str[256] ; sprintf(str,"nxyz = %d nvox = %d",nxyz,nvox) ; STATUS(str) ; } #endif /*--- FIM: initialize recursive updates ---*/ pc_ref = (PCOR_references **) malloc( sizeof(PCOR_references *) * ny_ref ) ; pc_vc = (PCOR_voxel_corr **) malloc( sizeof(PCOR_voxel_corr *) * ny_ref ) ; if( pc_ref == NULL || pc_vc == NULL ){ free(vval) ; free(indx) ; free(pc_ref) ; free(pc_vc) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; fprintf(stderr,"\n*** FIM initialization fails in fim3d_fimmer_compute\n") ; RETURN(NULL) ; } ifim = 0 ; for( ivec=0 ; ivec < ny_ref ; ivec++ ){ pc_ref[ivec] = new_PCOR_references( fim_nref ) ; pc_vc[ivec] = new_PCOR_voxel_corr( nvox , fim_nref ) ; if( pc_ref[ivec] == NULL || pc_vc[ivec] == NULL ) ifim++ ; } if( ifim > 0 ){ for( ivec=0 ; ivec < ny_ref ; ivec++ ){ free_PCOR_references(pc_ref[ivec]) ; free_PCOR_voxel_corr(pc_vc[ivec]) ; } free(vval) ; free(indx) ; free(pc_ref) ; free(pc_vc) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; fprintf(stderr,"\n*** FIM initialization fails in fim3d_fimmer_compute\n") ; RETURN(NULL) ; } /*--- Make a new dataset to hold the output ---*/ new_dset = EDIT_empty_copy( dset_time ) ; it = EDIT_dset_items( new_dset , ADN_prefix , new_prefix , ADN_malloc_type , DATABLOCK_MEM_MALLOC , ADN_type , ISHEAD(dset_time) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_func_type , FUNC_COR_TYPE , ADN_nvals , FUNC_nvals[FUNC_COR_TYPE] , ADN_datum_all , MRI_short , ADN_ntt , 0 , ADN_none ) ; if( it > 0 ){ fprintf(stderr, "\n*** EDIT_dset_items error %d in fim3d_fimmer_compute\n",it) ; THD_delete_3dim_dataset( new_dset , False ) ; for( ivec=0 ; ivec < ny_ref ; ivec++ ){ free_PCOR_references(pc_ref[ivec]) ; free_PCOR_voxel_corr(pc_vc[ivec]) ; } free(vval) ; free(indx) ; free(pc_ref) ; free(pc_vc) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; RETURN(NULL) ; } for( iv=0 ; iv < new_dset->dblk->nvals ; iv++ ){ ptr = malloc( DSET_BRICK_BYTES(new_dset,iv) ) ; mri_fix_data_pointer( ptr , DSET_BRICK(new_dset,iv) ) ; } if( THD_count_databricks(new_dset->dblk) < new_dset->dblk->nvals ){ fprintf(stderr, "\n*** failure to malloc new bricks in fim3d_fimmer_compute\n") ; THD_delete_3dim_dataset( new_dset , False ) ; for( ivec=0 ; ivec < ny_ref ; ivec++ ){ free_PCOR_references(pc_ref[ivec]) ; free_PCOR_voxel_corr(pc_vc[ivec]) ; } free(vval) ; free(indx) ; free(pc_ref) ; free(pc_vc) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; RETURN(NULL) ; } /*--- FIM: do recursive updates ---*/ for( it=itbot ; it < ntime ; it++ ){ nnow = 0 ; for( ivec=0 ; ivec < ny_ref ; ivec++ ){ tsar = ref_ts->tsarr[ivec]->ts ; if( tsar[it] >= SO_BIG ) continue ; /* skip this */ ref_vec[0] = 1.0 ; /* we always supply orts */ ref_vec[1] = (float) it ; /* for mean and linear trend */ if (internal_ort) /* 10 Dec 1996 */ { ref_vec[2] = tsar[it] ; } else { for( iv=0 ; iv < ny_ort ; iv++ ) ref_vec[iv+2] = ort_ts->tsarr[iv]->ts[it]; ref_vec[ny_ort+2] = tsar[it] ; } #ifdef AFNI_DEBUG { char str[256] ; sprintf(str,"time index=%d ideal[%d]=%f" , it,ivec,tsar[it] ) ; if (ivec == 0) STATUS(str) ; } #endif update_PCOR_references( ref_vec , pc_ref[ivec] ) ; switch( dtyp ){ case MRI_short:{ short * dar = (short *) DSET_ARRAY(dset_time,it) ; for( iv=0 ; iv < nvox ; iv++ ) vval[iv] = (float) dar[indx[iv]] ; } break ; case MRI_float:{ float * dar = (float *) DSET_ARRAY(dset_time,it) ; for( iv=0 ; iv < nvox ; iv++ ) vval[iv] = (float) dar[indx[iv]] ; } break ; case MRI_byte:{ byte * dar = (byte *) DSET_ARRAY(dset_time,it) ; for( iv=0 ; iv < nvox ; iv++ ) vval[iv] = (float) dar[indx[iv]] ; } break ; } PCOR_update_float( vval , pc_ref[ivec] , pc_vc[ivec] ) ; nnow++ ; /*----- update baseline value calculation -----*/ if (max_percent > 0.0) /* 19 May 1997 */ if (ivec == 0) for (iv = 0; iv < nvox; iv++) baseline[iv] += vval[iv] / ngood_ref; } if( nnow > 0 ) nupdt++ ; /*--- Load results into the dataset and redisplay it ---*/ if( nupdt == ngood_ref ) { /*--- set the statistical parameters ---*/ stataux[0] = nupdt ; /* number of points used */ stataux[1] = (ny_ref==1) ? 1 : 2 ; /* number of references */ stataux[2] = fim_nref - 1 ; /* number of orts */ /* 12 Dec 96 */ for( iv=3 ; iv < MAX_STAT_AUX ; iv++ ) stataux[iv] = 0.0 ; STATUS("setting statistical parameters") ; (void) EDIT_dset_items( new_dset , ADN_stat_aux , stataux , ADN_none ) ; /*** Compute brick arrays for new dataset ***/ if( ny_ref == 1 ){ /*** Just 1 ref vector --> load values directly into dataset ***/ /*--- get alpha (coef) into vval, find max value, scale into brick array ---*/ STATUS("getting 1 ref alpha") ; PCOR_get_coef( pc_ref[0] , pc_vc[0] , vval ) ; /*--- replace alpha with percentage change, if so requested ---*/ if (max_percent > 0.0) /* 19 May 1997 */ { for (iv = 0; iv < nvox; iv++) { vval[iv] *= 100.0 * (ref_ts_max[0] - ref_ts_min[0]); if (fabs(vval[iv]) < max_percent * fabs(baseline[iv])) vval[iv] = fabs( vval[iv] / baseline[iv] ); else vval[iv] = max_percent; } topval = max_percent; } else { topval = 0.0 ; for( iv=0 ; iv < nvox ; iv++ ) if( fabs(vval[iv]) > topval ) topval = fabs(vval[iv]) ; } bar = DSET_ARRAY( new_dset , FUNC_ival_fim[FUNC_COR_TYPE] ) ; memset( bar , 0 , sizeof(short)*nxyz ) ; if( topval > 0.0 ){ topval = MRI_TYPE_maxval[MRI_short] / topval ; for( iv=0 ; iv < nvox ; iv++ ) bar[indx[iv]] = (short)(topval * vval[iv] + 0.499) ; stataux[0] = 1.0/topval ; } else { stataux[0] = 0.0 ; } /*--- get correlation coefficient (pcor) into vval, scale into brick array (with fixed scaling factor) ---*/ STATUS("getting 1 ref pcor") ; PCOR_get_pcor( pc_ref[0] , pc_vc[0] , vval ) ; bar = DSET_ARRAY( new_dset , FUNC_ival_thr[FUNC_COR_TYPE] ) ; memset( bar , 0 , sizeof(short)*nxyz ) ; for( iv=0 ; iv < nvox ; iv++ ) bar[indx[iv]] = (short)(FUNC_COR_SCALE_SHORT * vval[iv] + 0.499) ; stataux[1] = 1.0 / FUNC_COR_SCALE_SHORT ; } else { /*** Multiple references --> find best correlation at each voxel ***/ /*--- get first ref results into abest and rbest (best so far) ---*/ PCOR_get_coef( pc_ref[0] , pc_vc[0] , abest ) ; /*--- modify alpha for percentage change calculation ---*/ if (max_percent > 0.0) /* 19 May 1997 */ for (iv = 0; iv < nvox; iv++) abest[iv] *= 100.0 * (ref_ts_max[0] - ref_ts_min[0]); PCOR_get_pcor( pc_ref[0] , pc_vc[0] , rbest ) ; /*--- for each succeeding ref vector, get results into aval and vval, if |vval| > |rbest|, then use that result instead ---*/ for( ivec=1 ; ivec < ny_ref ; ivec++ ){ PCOR_get_coef( pc_ref[ivec] , pc_vc[ivec] , aval ) ; PCOR_get_pcor( pc_ref[ivec] , pc_vc[ivec] , vval ) ; for( iv=0 ; iv < nvox ; iv++ ){ if( fabs(vval[iv]) > fabs(rbest[iv]) ){ rbest[iv] = vval[iv] ; abest[iv] = aval[iv] ; /*--- modify alpha for percentage change calculation ---*/ if (max_percent > 0.0) /* 19 May 1997 */ abest[iv] *= 100.0 * (ref_ts_max[ivec] - ref_ts_min[ivec]); } } } /*--- at this point, abest and rbest are the best results, so scale them into the dataset bricks ---*/ /*--- finish percentage change calculation, if so requested ---*/ if (max_percent > 0.0) /* 19 May 1997 */ { for (iv = 0; iv < nvox; iv++) { if (fabs(abest[iv]) < max_percent * fabs(baseline[iv])) abest[iv] = fabs( abest[iv] / baseline[iv] ); else abest[iv] = max_percent; } topval = max_percent; } else { topval = 0.0 ; for( iv=0 ; iv < nvox ; iv++ ) if( fabs(abest[iv]) > topval ) topval = fabs(abest[iv]) ; } bar = DSET_ARRAY( new_dset , FUNC_ival_fim[FUNC_COR_TYPE] ) ; memset( bar , 0 , sizeof(short)*nxyz ) ; if( topval > 0.0 ){ topval = MRI_TYPE_maxval[MRI_short] / topval ; for( iv=0 ; iv < nvox ; iv++ ) bar[indx[iv]] = (short)(topval * abest[iv] + 0.499) ; stataux[0] = 1.0/topval ; } else { stataux[0] = 0.0 ; } bar = DSET_ARRAY( new_dset , FUNC_ival_thr[FUNC_COR_TYPE] ) ; memset( bar , 0 , sizeof(short)*nxyz ) ; for( iv=0 ; iv < nvox ; iv++ ) bar[indx[iv]] = (short)(FUNC_COR_SCALE_SHORT * rbest[iv] + 0.499) ; stataux[1] = 1.0 / FUNC_COR_SCALE_SHORT ; } STATUS("setting brick_fac") ; (void) EDIT_dset_items( new_dset , ADN_brick_fac , stataux , ADN_none ) ; } } /*--- End of recursive updates; now free temporary workspaces ---*/ for( ivec=0 ; ivec < ny_ref ; ivec++ ){ free_PCOR_references(pc_ref[ivec]) ; free_PCOR_voxel_corr(pc_vc[ivec]) ; } free(vval) ; free(indx) ; free(pc_ref) ; free(pc_vc) ; if( aval != NULL ) free(aval) ; if( rbest != NULL ) free(rbest) ; if( abest != NULL ) free(abest) ; if (ref_ts_min != NULL) free (ref_ts_min); /* 19 May 1997 */ if (ref_ts_max != NULL) free (ref_ts_max); if (baseline != NULL) free (baseline); /* --- load the statistics --- */ THD_load_statistics (new_dset); /*--- Return new dataset ---*/ RETURN(new_dset) ; }
int main( int argc , char * argv[] ) { int iarg=1 , dcode=0 , maxgap=2 , nftot=0 ; char * prefix="zfillin" , * dstr=NULL; THD_3dim_dataset * inset , * outset ; MRI_IMAGE * brim ; int verb=0 ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dZFillin [options] dataset\n" "Extracts 1D rows in the given direction from a 3D dataset,\n" "searches for zeros that are 'close' to nonzero values in the row,\n" "and replaces the zeros with the closest nonzero neighbor.\n" "\n" "OPTIONS:\n" " -maxstep N = set the maximum distance to a neighbor\n" " [default=2].\n" " -dir D = set the direction of fill to 'D', which can\n" " be one of the following:\n" " A-P, P-A, I-S, S-I, L-R, R-L, x, y, z\n" " The first 6 are anatomical directions;\n" " the last 3 are reference to the dataset\n" " internal axes [no default value].\n" " -prefix P = set the prefix to 'P' for the output dataset.\n" "\n" "N.B.: * If the input dataset has more than one sub-brick,\n" " only the first one will be processed.\n" " * At this time, 3dZFillin only works on byte-valued datasets\n" "\n" "This program's only purpose is to fill up the Talairach Daemon\n" "bricks obtained from the UT San Antonio database.\n" "\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dZFillin main") ; machdep() ; AFNI_logger("3dZfillin",argc,argv) ; PRINT_VERSION(3dZFillin") ; /*-- scan args --*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-verb",5) == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"*** Illegal string after -prefix!\n"); exit(1) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-maxstep") == 0 ){ maxgap = strtol( argv[++iarg] , NULL , 10 ) ; if( maxgap < 1 ){ fprintf(stderr,"*** Illegal value after -maxgap!\n"); exit(1); } iarg++ ; continue ; } if( strcmp(argv[iarg],"-dir") == 0 ){ dstr = argv[++iarg] ; iarg++ ; continue ; } fprintf(stderr,"*** Illegal option: %s\n",argv[iarg]) ; exit(1) ; } if( dstr == NULL ){ fprintf(stderr,"*** No -dir option on command line!\n"); exit(1); } if( iarg >= argc ){ fprintf(stderr,"*** No input dataset on command line!\n"); exit(1); } inset = THD_open_dataset( argv[iarg] ) ; if( inset == NULL ){ fprintf(stderr,"*** Can't open dataset %s\n",argv[iarg]); exit(1); } outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_none ) ; if( THD_deathcon() && THD_is_file( DSET_HEADNAME(outset) ) ){ fprintf(stderr,"** Output file %s exists -- cannot overwrite!\n", DSET_HEADNAME(outset) ) ; exit(1) ; } tross_Copy_History( inset , outset ) ; tross_Make_History( "3dZFillin" , argc,argv , outset ) ; if( DSET_NVALS(inset) > 1 ){ fprintf(stderr,"++ WARNING: input dataset has more than one sub-brick!\n"); EDIT_dset_items( outset , ADN_ntt , 0 , ADN_nvals , 1 , ADN_none ) ; } if( DSET_BRICK_TYPE(outset,0) != MRI_byte ){ fprintf(stderr,"*** This program only works on byte datasets!\n"); exit(1) ; } switch( *dstr ){ case 'x': dcode = 1 ; break ; case 'y': dcode = 2 ; break ; case 'z': dcode = 3 ; break ; default: if( *dstr == ORIENT_tinystr[outset->daxes->xxorient][0] || *dstr == ORIENT_tinystr[outset->daxes->xxorient][1] ) dcode = 1 ; if( *dstr == ORIENT_tinystr[outset->daxes->yyorient][0] || *dstr == ORIENT_tinystr[outset->daxes->yyorient][1] ) dcode = 2 ; if( *dstr == ORIENT_tinystr[outset->daxes->zzorient][0] || *dstr == ORIENT_tinystr[outset->daxes->zzorient][1] ) dcode = 3 ; break ; } if( dcode == 0 ){ fprintf(stderr,"*** Illegal -dir direction!\n") ; exit(1) ; } if( verb ) fprintf(stderr,"++ Direction = axis %d in dataset\n",dcode) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; brim = mri_copy( DSET_BRICK(inset,0) ) ; DSET_unload(inset) ; EDIT_substitute_brick( outset , 0 , brim->kind , mri_data_pointer(brim) ) ; nftot = THD_dataset_zfillin( outset , 0 , dcode , maxgap ) ; fprintf(stderr,"++ Number of voxels filled = %d\n",nftot) ; if (DSET_write(outset) != False) { fprintf(stderr,"++ output dataset: %s\n",DSET_BRIKNAME(outset)) ; exit(0) ; } else { fprintf(stderr, "** 3dZFillin: Failed to write output!\n" ) ; exit(1) ; } }
int main( int argc , char * argv[] ) { int do_norm=0 , qdet=2 , have_freq=0 , do_automask=0 ; float dt=0.0f , fbot=0.0f,ftop=999999.9f , blur=0.0f ; MRI_IMARR *ortar=NULL ; MRI_IMAGE *ortim=NULL ; THD_3dim_dataset **ortset=NULL ; int nortset=0 ; THD_3dim_dataset *inset=NULL , *outset ; char *prefix="bandpass" ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0,nmask , verb=1 , nx,ny,nz,nvox , nfft=0 , kk ; float **vec , **ort=NULL ; int nort=0 , vv , nopt , ntime ; MRI_vectim *mrv ; float pvrad=0.0f ; int nosat=0 ; int do_despike=0 ; /*-- help? --*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "\n" "** NOTA BENE: For the purpose of preparing resting-state FMRI datasets **\n" "** for analysis (e.g., with 3dGroupInCorr), this program is now mostly **\n" "** superseded by the afni_proc.py script. See the 'afni_proc.py -help' **\n" "** section 'Resting state analysis (modern)' to get our current rs-FMRI **\n" "** pre-processing recommended sequence of steps. -- RW Cox, et alii. **\n" "\n" "Usage: 3dBandpass [options] fbot ftop dataset\n" "\n" "* One function of this program is to prepare datasets for input\n" " to 3dSetupGroupInCorr. Other uses are left to your imagination.\n" "\n" "* 'dataset' is a 3D+time sequence of volumes\n" " ++ This must be a single imaging run -- that is, no discontinuities\n" " in time from 3dTcat-ing multiple datasets together.\n" "\n" "* fbot = lowest frequency in the passband, in Hz\n" " ++ fbot can be 0 if you want to do a lowpass filter only;\n" " HOWEVER, the mean and Nyquist freq are always removed.\n" "\n" "* ftop = highest frequency in the passband (must be > fbot)\n" " ++ if ftop > Nyquist freq, then it's a highpass filter only.\n" "\n" "* Set fbot=0 and ftop=99999 to do an 'allpass' filter.\n" " ++ Except for removal of the 0 and Nyquist frequencies, that is.\n" "\n" "* You cannot construct a 'notch' filter with this program!\n" " ++ You could use 3dBandpass followed by 3dcalc to get the same effect.\n" " ++ If you are understand what you are doing, that is.\n" " ++ Of course, that is the AFNI way -- if you don't want to\n" " understand what you are doing, use Some other PrograM, and\n" " you can still get Fine StatisticaL maps.\n" "\n" "* 3dBandpass will fail if fbot and ftop are too close for comfort.\n" " ++ Which means closer than one frequency grid step df,\n" " where df = 1 / (nfft * dt) [of course]\n" "\n" "* The actual FFT length used will be printed, and may be larger\n" " than the input time series length for the sake of efficiency.\n" " ++ The program will use a power-of-2, possibly multiplied by\n" " a power of 3 and/or 5 (up to and including the 3rd power of\n" " each of these: 3, 9, 27, and 5, 25, 125).\n" "\n" "* Note that the results of combining 3dDetrend and 3dBandpass will\n" " depend on the order in which you run these programs. That's why\n" " 3dBandpass has the '-ort' and '-dsort' options, so that the\n" " time series filtering can be done properly, in one place.\n" "\n" "* The output dataset is stored in float format.\n" "\n" "* The order of processing steps is the following (most are optional):\n" " (0) Check time series for initial transients [does not alter data]\n" " (1) Despiking of each time series\n" " (2) Removal of a constant+linear+quadratic trend in each time series\n" " (3) Bandpass of data time series\n" " (4) Bandpass of -ort time series, then detrending of data\n" " with respect to the -ort time series\n" " (5) Bandpass and de-orting of the -dsort dataset,\n" " then detrending of the data with respect to -dsort\n" " (6) Blurring inside the mask [might be slow]\n" " (7) Local PV calculation [WILL be slow!]\n" " (8) L2 normalization [will be fast.]\n" "\n" "--------\n" "OPTIONS:\n" "--------\n" " -despike = Despike each time series before other processing.\n" " ++ Hopefully, you don't actually need to do this,\n" " which is why it is optional.\n" " -ort f.1D = Also orthogonalize input to columns in f.1D\n" " ++ Multiple '-ort' options are allowed.\n" " -dsort fset = Orthogonalize each voxel to the corresponding\n" " voxel time series in dataset 'fset', which must\n" " have the same spatial and temporal grid structure\n" " as the main input dataset.\n" " ++ At present, only one '-dsort' option is allowed.\n" " -nodetrend = Skip the quadratic detrending of the input that\n" " occurs before the FFT-based bandpassing.\n" " ++ You would only want to do this if the dataset\n" " had been detrended already in some other program.\n" " -dt dd = set time step to 'dd' sec [default=from dataset header]\n" " -nfft N = set the FFT length to 'N' [must be a legal value]\n" " -norm = Make all output time series have L2 norm = 1\n" " ++ i.e., sum of squares = 1\n" " -mask mset = Mask dataset\n" " -automask = Create a mask from the input dataset\n" " -blur fff = Blur (inside the mask only) with a filter\n" " width (FWHM) of 'fff' millimeters.\n" " -localPV rrr = Replace each vector by the local Principal Vector\n" " (AKA first singular vector) from a neighborhood\n" " of radius 'rrr' millimiters.\n" " ++ Note that the PV time series is L2 normalized.\n" " ++ This option is mostly for Bob Cox to have fun with.\n" "\n" " -input dataset = Alternative way to specify input dataset.\n" " -band fbot ftop = Alternative way to specify passband frequencies.\n" "\n" " -prefix ppp = Set prefix name of output dataset.\n" " -quiet = Turn off the fun and informative messages. (Why?)\n" "\n" " -notrans = Don't check for initial positive transients in the data:\n" " *OR* ++ The test is a little slow, so skipping it is OK,\n" " -nosat if you KNOW the data time series are transient-free.\n" " ++ Or set AFNI_SKIP_SATCHECK to YES.\n" " ++ Initial transients won't be handled well by the\n" " bandpassing algorithm, and in addition may seriously\n" " contaminate any further processing, such as inter-voxel\n" " correlations via InstaCorr.\n" " ++ No other tests are made [yet] for non-stationary behavior\n" " in the time series data.\n" ) ; PRINT_AFNI_OMP_USAGE( "3dBandpass" , "* At present, the only part of 3dBandpass that is parallelized is the\n" " '-blur' option, which processes each sub-brick independently.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup --*/ mainENTRY("3dBandpass"); machdep(); AFNI_logger("3dBandpass",argc,argv); PRINT_VERSION("3dBandpass"); AUTHOR("RW Cox"); nosat = AFNI_yesenv("AFNI_SKIP_SATCHECK") ; nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-despike") == 0 ){ /* 08 Oct 2010 */ do_despike++ ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-nfft") == 0 ){ int nnup ; if( ++nopt >= argc ) ERROR_exit("need an argument after -nfft!") ; nfft = (int)strtod(argv[nopt],NULL) ; nnup = csfft_nextup_even(nfft) ; if( nfft < 16 || nfft != nnup ) ERROR_exit("value %d after -nfft is illegal! Next legal value = %d",nfft,nnup) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-blur") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -blur!") ; blur = strtod(argv[nopt],NULL) ; if( blur <= 0.0f ) WARNING_message("non-positive blur?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-localPV") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -localpv!") ; pvrad = strtod(argv[nopt],NULL) ; if( pvrad <= 0.0f ) WARNING_message("non-positive -localpv?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -prefix!") ; prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad -prefix option!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask AND -automask!") ; do_automask = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++nopt >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || do_automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(mset,argv[nopt]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[nopt]) ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < 1 ) ERROR_exit("Mask is too small to process") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-norm") == 0 ){ do_norm = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quiet") == 0 ){ verb = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-notrans") == 0 || strcmp(argv[nopt],"-nosat") == 0 ){ nosat = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-ort") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -ort!") ; if( ortar == NULL ) INIT_IMARR(ortar) ; ortim = mri_read_1D( argv[nopt] ) ; if( ortim == NULL ) ERROR_exit("can't read from -ort '%s'",argv[nopt]) ; mri_add_name(argv[nopt],ortim) ; ADDTO_IMARR(ortar,ortim) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dsort") == 0 ){ THD_3dim_dataset *qset ; if( ++nopt >= argc ) ERROR_exit("need an argument after -dsort!") ; if( nortset > 0 ) ERROR_exit("only 1 -dsort option is allowed!") ; qset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(qset,argv[nopt]) ; ortset = (THD_3dim_dataset **)realloc(ortset, sizeof(THD_3dim_dataset *)*(nortset+1)) ; ortset[nortset++] = qset ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-nodetrend",6) == 0 ){ qdet = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dt") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -dt!") ; dt = (float)strtod(argv[nopt],NULL) ; if( dt <= 0.0f ) WARNING_message("value after -dt illegal!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have 2 -input options!") ; if( ++nopt >= argc ) ERROR_exit("need an argument after -input!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-band",5) == 0 ){ if( ++nopt >= argc-1 ) ERROR_exit("need 2 arguments after -band!") ; if( have_freq ) WARNING_message("second -band option replaces first one!") ; fbot = strtod(argv[nopt++],NULL) ; ftop = strtod(argv[nopt++],NULL) ; have_freq = 1 ; continue ; } ERROR_exit("Unknown option: '%s'",argv[nopt]) ; } /** check inputs for reasonablositiness **/ if( !have_freq ){ if( nopt+1 >= argc ) ERROR_exit("Need frequencies on command line after options!") ; fbot = (float)strtod(argv[nopt++],NULL) ; ftop = (float)strtod(argv[nopt++],NULL) ; } if( inset == NULL ){ if( nopt >= argc ) ERROR_exit("Need input dataset name on command line after options!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; } DSET_UNMSEC(inset) ; if( fbot < 0.0f ) ERROR_exit("fbot value can't be negative!") ; if( ftop <= fbot ) ERROR_exit("ftop value %g must be greater than fbot value %g!",ftop,fbot) ; ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Input dataset is too short!") ; if( nfft <= 0 ){ nfft = csfft_nextup_even(ntime) ; if( verb ) INFO_message("Data length = %d FFT length = %d",ntime,nfft) ; (void)THD_bandpass_set_nfft(nfft) ; } else if( nfft < ntime ){ ERROR_exit("-nfft %d is less than data length = %d",nfft,ntime) ; } else { kk = THD_bandpass_set_nfft(nfft) ; if( kk != nfft && verb ) INFO_message("Data length = %d FFT length = %d",ntime,kk) ; } if( dt <= 0.0f ){ dt = DSET_TR(inset) ; if( dt <= 0.0f ){ WARNING_message("Setting dt=1.0 since input dataset lacks a time axis!") ; dt = 1.0f ; } } if( !THD_bandpass_OK(ntime,dt,fbot,ftop,1) ) ERROR_exit("Can't continue!") ; nx = DSET_NX(inset); ny = DSET_NY(inset); nz = DSET_NZ(inset); nvox = nx*ny*nz; /* check mask, or create it */ if( verb ) INFO_message("Loading input dataset time series" ) ; DSET_load(inset) ; if( mask != NULL ){ if( mask_nx != nx || mask_ny != ny || mask_nz != nz ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( do_automask ){ mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; nmask = THD_countmask( DSET_NVOX(inset) , mask ) ; if( verb ) INFO_message("Number of voxels in automask = %d",nmask); if( nmask < 1 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nvox) ; nmask = nvox ; memset(mask,1,sizeof(byte)*nvox) ; if( verb ) INFO_message("No mask ==> processing all %d voxels",nvox); } /* A simple check of dataset quality [08 Feb 2010] */ if( !nosat ){ float val ; INFO_message( "Checking dataset for initial transients [use '-notrans' to skip this test]") ; val = THD_saturation_check(inset,mask,0,0) ; kk = (int)(val+0.54321f) ; if( kk > 0 ) ININFO_message( "Looks like there %s %d non-steady-state initial time point%s :-(" , ((kk==1) ? "is" : "are") , kk , ((kk==1) ? " " : "s") ) ; else if( val > 0.3210f ) /* don't ask where this threshold comes from! */ ININFO_message( "MAYBE there's an initial positive transient of 1 point, but it's hard to tell\n") ; else ININFO_message("No widespread initial positive transient detected :-)") ; } /* check -dsort inputs for match to inset */ for( kk=0 ; kk < nortset ; kk++ ){ if( DSET_NX(ortset[kk]) != nx || DSET_NY(ortset[kk]) != ny || DSET_NZ(ortset[kk]) != nz || DSET_NVALS(ortset[kk]) != ntime ) ERROR_exit("-dsort %s doesn't match input dataset grid" , DSET_BRIKNAME(ortset[kk]) ) ; } /* convert input dataset to a vectim, which is more fun */ mrv = THD_dset_to_vectim( inset , mask , 0 ) ; if( mrv == NULL ) ERROR_exit("Can't load time series data!?") ; DSET_unload(inset) ; /* similarly for the ort vectors */ if( ortar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(ortar) ; kk++ ){ ortim = IMARR_SUBIM(ortar,kk) ; if( ortim->nx < ntime ) ERROR_exit("-ort file %s is shorter than input dataset time series", ortim->name ) ; ort = (float **)realloc( ort , sizeof(float *)*(nort+ortim->ny) ) ; for( vv=0 ; vv < ortim->ny ; vv++ ) ort[nort++] = MRI_FLOAT_PTR(ortim) + ortim->nx * vv ; } } /* check whether processing leaves any DoF remaining 18 Mar 2015 [rickr] */ { int nbprem = THD_bandpass_remain_dim(ntime, dt, fbot, ftop, 1); int bpused, nremain; int wlimit; /* warning limit */ bpused = ntime - nbprem; /* #dim lost in bandpass step */ nremain = nbprem - nort; /* #dim left in output */ if( nortset == 1 ) nremain--; nremain -= (qdet+1); if( verb ) INFO_message("%d dimensional data reduced to %d by:\n" " %d (bandpass), %d (-ort), %d (-dsort), %d (detrend)", ntime, nremain, bpused, nort, nortset?1:0, qdet+1); /* possibly warn (if 95% lost) user or fail */ wlimit = ntime/20; if( wlimit < 3 ) wlimit = 3; if( nremain < wlimit && nremain > 0 ) WARNING_message("dimensionality reduced from %d to %d, be careful!", ntime, nremain); if( nremain <= 0 ) /* FAILURE */ ERROR_exit("dimensionality reduced from %d to %d, failing!", ntime, nremain); } /* all the real work now */ if( do_despike ){ int_pair nsp ; if( verb ) INFO_message("Testing data time series for spikes") ; nsp = THD_vectim_despike9( mrv ) ; if( verb ) ININFO_message(" -- Squashed %d spikes from %d voxels",nsp.j,nsp.i) ; } if( verb ) INFO_message("Bandpassing data time series") ; (void)THD_bandpass_vectim( mrv , dt,fbot,ftop , qdet , nort,ort ) ; /* OK, maybe a little more work */ if( nortset == 1 ){ MRI_vectim *orv ; orv = THD_dset_to_vectim( ortset[0] , mask , 0 ) ; if( orv == NULL ){ ERROR_message("Can't load -dsort %s",DSET_BRIKNAME(ortset[0])) ; } else { float *dp , *mvv , *ovv , ff ; if( verb ) INFO_message("Orthogonalizing to bandpassed -dsort") ; (void)THD_bandpass_vectim( orv , dt,fbot,ftop , qdet , nort,ort ) ; THD_vectim_normalize( orv ) ; dp = malloc(sizeof(float)*mrv->nvec) ; THD_vectim_vectim_dot( mrv , orv , dp ) ; for( vv=0 ; vv < mrv->nvec ; vv++ ){ ff = dp[vv] ; if( ff != 0.0f ){ mvv = VECTIM_PTR(mrv,vv) ; ovv = VECTIM_PTR(orv,vv) ; for( kk=0 ; kk < ntime ; kk++ ) mvv[kk] -= ff*ovv[kk] ; } } VECTIM_destroy(orv) ; free(dp) ; } } if( blur > 0.0f ){ if( verb ) INFO_message("Blurring time series data spatially; FWHM=%.2f",blur) ; mri_blur3D_vectim( mrv , blur ) ; } if( pvrad > 0.0f ){ if( verb ) INFO_message("Local PV-ing time series data spatially; radius=%.2f",pvrad) ; THD_vectim_normalize( mrv ) ; THD_vectim_localpv( mrv , pvrad ) ; } if( do_norm && pvrad <= 0.0f ){ if( verb ) INFO_message("L2 normalizing time series data") ; THD_vectim_normalize( mrv ) ; } /* create output dataset, populate it, write it, then quit */ if( verb ) INFO_message("Creating output dataset in memory, then writing it") ; outset = EDIT_empty_copy(inset) ; /* do not copy scalars 11 Sep 2015 [rickr] */ EDIT_dset_items( outset , ADN_prefix,prefix , ADN_brick_fac,NULL , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dBandpass" , argc,argv , outset ) ; for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outset , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outset ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outset,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; exit(0) ; }