/* convert by hand, since no scaling will be done * (byte seems inappropriate and float does not need it) */ int write_result(param_t * params, THD_3dim_dataset * oset, int argc, char * argv[]) { short * sptr; int nvox = DSET_NVOX(oset), ind; ENTRY("write_results"); EDIT_dset_items(oset, ADN_prefix, params->prefix, ADN_none); if( params->verb ) INFO_message("writing result %s...\n", DSET_PREFIX(oset)); switch( params->datum ) { default: ERROR_exit("invalid datum for result: %d", params->datum); case MRI_short: break; /* nothing to do */ case MRI_float: { float * data = (float *)malloc(nvox*sizeof(float)); sptr = DBLK_ARRAY(oset->dblk, 0); if( ! data ) ERROR_exit("failed to alloc %d output floats\n", nvox); for( ind = 0; ind < nvox; ind++ ) data[ind] = (float)sptr[ind]; EDIT_substitute_brick(oset, 0, params->datum, data); } break; case MRI_byte: { byte * data = (byte *)malloc(nvox*sizeof(byte)); int errs = 0; sptr = DBLK_ARRAY(oset->dblk, 0); if( ! data ) ERROR_exit("failed to alloc %d output bytes\n", nvox); for( ind = 0; ind < nvox; ind++ ) { if( sptr[ind] > 255 ) { /* watch for overflow */ data[ind] = (byte)255; errs++; } else data[ind] = (byte)sptr[ind]; } EDIT_substitute_brick(oset, 0, params->datum, data); if(errs) WARNING_message("convert to byte: %d truncated voxels",errs); } break; } tross_Make_History( "3dmask_tool", argc, argv, oset ); DSET_write(oset); WROTE_DSET(oset); RETURN(0); }
int main( int argc , char *argv[] ) { THD_3dim_dataset *old_dset , *new_dset ; /* input and output datasets */ THD_3dim_dataset *mask_dset=NULL ; float mask_bot=666.0 , mask_top=-666.0 ; byte *cmask=NULL ; int ncmask=0 ; byte *mmm = NULL ; int mcount=0, verb=0; int nopt, nbriks, ii ; int addBriks = 0 ; /* n-1 sub-bricks out */ int fullBriks = 0 ; /* n sub-bricks out */ int tsout = 0 ; /* flag to output a time series (not a stat bucket) */ int numMultBriks,methIndex,brikIndex; /*----- Help the pitiful user? -----*/ /* bureaucracy */ mainENTRY("3dTstat main"); machdep(); AFNI_logger("3dTstat",argc,argv); PRINT_VERSION("3dTstat"); AUTHOR("KR Hammett & RW Cox"); /*--- scan command line for options ---*/ if (argc == 1) { usage_3dTstat(1); exit(0); } /* Bob's help shortcut */ nopt = 1 ; nbriks = 0 ; nmeths = 0 ; verb = 0; while( nopt < argc && argv[nopt][0] == '-' ){ if (strcmp(argv[nopt], "-h") == 0 || strcmp(argv[nopt], "-help") == 0) { usage_3dTstat(strlen(argv[nopt]) > 3 ? 2:1); exit(0); } if( strcmp(argv[nopt],"-verb") == 0 ){ verb++ ; nopt++ ; continue ; } /*-- methods --*/ if( strcasecmp(argv[nopt],"-centromean") == 0 ){ /* 01 Nov 2010 */ meth[nmeths++] = METH_CENTROMEAN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-bmv") == 0 ){ meth[nmeths++] = METH_BMV ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-median") == 0 ){ meth[nmeths++] = METH_MEDIAN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-nzmedian") == 0 ){ meth[nmeths++] = METH_NZMEDIAN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-DW") == 0 ){ meth[nmeths++] = METH_DW ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-zcount") == 0 ){ meth[nmeths++] = METH_ZCOUNT ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-nzcount") == 0 ){ meth[nmeths++] = METH_NZCOUNT ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-MAD") == 0 ){ meth[nmeths++] = METH_MAD ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-mean") == 0 ){ meth[nmeths++] = METH_MEAN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-sum") == 0 ){ meth[nmeths++] = METH_SUM ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-sos") == 0 ){ meth[nmeths++] = METH_SUM_SQUARES ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-abssum") == 0 ){ meth[nmeths++] = METH_ABSSUM ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-slope") == 0 ){ meth[nmeths++] = METH_SLOPE ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-stdev") == 0 || strcasecmp(argv[nopt],"-sigma") == 0 ){ meth[nmeths++] = METH_SIGMA ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-cvar") == 0 ){ meth[nmeths++] = METH_CVAR ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-cvarinv") == 0 ){ meth[nmeths++] = METH_CVARINV ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-stdevNOD") == 0 || strcasecmp(argv[nopt],"-sigmaNOD") == 0 ){ /* 07 Dec 2001 */ meth[nmeths++] = METH_SIGMA_NOD ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-cvarNOD") == 0 ){ /* 07 Dec 2001 */ meth[nmeths++] = METH_CVAR_NOD ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-cvarinvNOD") == 0 ){ meth[nmeths++] = METH_CVARINVNOD ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-min") == 0 ){ meth[nmeths++] = METH_MIN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-max") == 0 ){ meth[nmeths++] = METH_MAX ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-absmax") == 0 ){ meth[nmeths++] = METH_ABSMAX ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-signed_absmax") == 0 ){ meth[nmeths++] = METH_SIGNED_ABSMAX ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argmin") == 0 ){ meth[nmeths++] = METH_ARGMIN ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argmin1") == 0 ){ meth[nmeths++] = METH_ARGMIN1 ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argmax") == 0 ){ meth[nmeths++] = METH_ARGMAX ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argmax1") == 0 ){ meth[nmeths++] = METH_ARGMAX1 ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argabsmax") == 0 ){ meth[nmeths++] = METH_ARGABSMAX ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-argabsmax1") == 0 ){ meth[nmeths++] = METH_ARGABSMAX1; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-duration") == 0 ){ meth[nmeths++] = METH_DURATION ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-onset") == 0 ){ meth[nmeths++] = METH_ONSET ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-offset") == 0 ){ meth[nmeths++] = METH_OFFSET ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-centroid") == 0 ){ meth[nmeths++] = METH_CENTROID ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-centduration") == 0 ){ meth[nmeths++] = METH_CENTDURATION ; nbriks++ ; nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-nzmean") == 0 ){ meth[nmeths++] = METH_NZMEAN ; nbriks++ ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-mask",5) == 0 ){ if( mask_dset != NULL ) ERROR_exit("Cannot have two -mask options!\n") ; if( nopt+1 >= argc ) ERROR_exit("-mask option requires a following argument!\n"); mask_dset = THD_open_dataset( argv[++nopt] ) ; if( mask_dset == NULL ) ERROR_exit("Cannot open mask dataset!\n") ; if( DSET_BRICK_TYPE(mask_dset,0) == MRI_complex ) ERROR_exit("Cannot deal with complex-valued mask dataset!\n"); nopt++ ; continue ; } if( strncmp(argv[nopt],"-mrange",5) == 0 ){ if( nopt+2 >= argc ) ERROR_exit("-mrange option requires 2 following arguments!\n"); mask_bot = strtod( argv[++nopt] , NULL ) ; mask_top = strtod( argv[++nopt] , NULL ) ; if( mask_top < mask_top ) ERROR_exit("-mrange inputs are illegal!\n") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-cmask") == 0 ){ /* 16 Mar 2000 */ if( nopt+1 >= argc ) ERROR_exit("-cmask option requires a following argument!\n"); cmask = EDT_calcmask( argv[++nopt] , &ncmask, 0 ) ; if( cmask == NULL ) ERROR_exit("Can't compute -cmask!\n"); nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-autocorr") == 0 ){ meth[nmeths++] = METH_AUTOCORR ; if( ++nopt >= argc ) ERROR_exit("-autocorr needs an argument!\n"); meth[nmeths++] = atoi(argv[nopt++]); if (meth[nmeths - 1] == 0) { addBriks++; } else { nbriks+=meth[nmeths - 1] ; } continue ; } if( strcasecmp(argv[nopt],"-autoreg") == 0 ){ meth[nmeths++] = METH_AUTOREGP ; if( ++nopt >= argc ) ERROR_exit("-autoreg needs an argument!\n"); meth[nmeths++] = atoi(argv[nopt++]); if (meth[nmeths - 1] == 0) { addBriks++; } else { nbriks+=meth[nmeths - 1] ; } continue ; } if( strcasecmp(argv[nopt],"-accumulate") == 0 ){ /* 4 Mar 2008 [rickr] */ meth[nmeths++] = METH_ACCUMULATE ; meth[nmeths++] = -1; /* flag to add N (not N-1) output bricks */ fullBriks++; tsout = 1; /* flag to output a timeseries */ nopt++ ; continue ; } if( strcasecmp(argv[nopt],"-l2norm") == 0 ){ /* 07 Jan 2013 [rickr] */ meth[nmeths++] = METH_L2_NORM ; nbriks++ ; nopt++ ; continue ; } /*-- prefix --*/ if( strcasecmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-prefix needs an argument!\n"); MCW_strncpy(prefix,argv[nopt],THD_MAX_PREFIX) ; if( !THD_filename_ok(prefix) ) ERROR_exit("%s is not a valid prefix!\n",prefix); nopt++ ; continue ; } /*-- tdiff --*/ if( strcasecmp(argv[nopt],"-tdiff") == 0 ){ /* 25 May 2011 */ do_tdiff = 1 ; nopt++ ; continue ; } /*-- nscale --*/ if( strcasecmp(argv[nopt],"-nscale") == 0 ){ /* 25 May 2011 */ nscale = 1 ; nopt++ ; continue ; } /*-- datum --*/ if( strcasecmp(argv[nopt],"-datum") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-datum needs an argument!\n"); if( strcasecmp(argv[nopt],"short") == 0 ){ datum = MRI_short ; } else if( strcasecmp(argv[nopt],"float") == 0 ){ datum = MRI_float ; } else if( strcasecmp(argv[nopt],"byte") == 0 ){ datum = MRI_byte ; } else { ERROR_exit("-datum of type '%s' is not supported!\n", argv[nopt] ) ; } nopt++ ; continue ; } /* base percentage for duration calcs */ if (strcasecmp (argv[nopt], "-basepercent") == 0) { if( ++nopt >= argc ) ERROR_exit("-basepercent needs an argument!\n"); basepercent = strtod(argv[nopt], NULL); if(basepercent>1) basepercent /= 100.0; /* assume integer percent if >1*/ nopt++; continue; } /*-- Quien sabe'? --*/ ERROR_message("Unknown option: %s\n",argv[nopt]) ; suggest_best_prog_option(argv[0], argv[nopt]); exit(1); } if (argc < 2) { ERROR_message("Too few options, use -help for details"); exit(1); } /*--- If no options selected, default to single stat MEAN -- KRH ---*/ if (nmeths == 0) nmeths = 1; if (nbriks == 0 && addBriks == 0 && fullBriks == 0) nbriks = 1; /*----- read input dataset -----*/ if( nopt >= argc ) ERROR_exit(" No input dataset!?") ; old_dset = THD_open_dataset( argv[nopt] ) ; if( !ISVALID_DSET(old_dset) ) ERROR_exit("Can't open dataset %s\n",argv[nopt]); nopt++ ; if( nopt < argc ) WARNING_message("Trailing datasets on command line ignored: %s ...",argv[nopt]) ; if( DSET_NVALS(old_dset) == 1 ){ WARNING_message("Input dataset has 1 sub-brick ==> -tdiff is turned off") ; do_tdiff = 0 ; } /* no input volumes is bad, 1 volume applies to only certain methods */ /* 2 Nov 2010 [rickr] */ if( DSET_NVALS(old_dset) == 0 ) { ERROR_exit("Time series is of length 0?\n") ; } else if( DSET_NVALS(old_dset) == 1 || (do_tdiff && DSET_NVALS(old_dset)==2) ) { int methOK, OK = 1; /* see if each method is valid for nvals == 1 */ for( methIndex = 0; methIndex < nmeths; methIndex++ ) { methOK = 0; for( ii = 0; ii < NUM_1_INPUT_METHODS; ii++ ) { if( meth[methIndex] == valid_1_input_methods[ii] ) { methOK = 1; break; } } if( ! methOK ) ERROR_exit("Can't use dataset with %d values per voxel!" , DSET_NVALS(old_dset) ) ; } /* tell the library function that this case is okay */ g_thd_maker_allow_1brick = 1; } if( DSET_NUM_TIMES(old_dset) < 2 ){ WARNING_message("Input dataset is not 3D+time; assuming TR=1.0") ; EDIT_dset_items( old_dset , ADN_ntt , DSET_NVALS(old_dset) , ADN_ttorg , 0.0 , ADN_ttdel , 1.0 , ADN_tunits , UNITS_SEC_TYPE , NULL ) ; } /* If one or more of the -autocorr/-autoreg options was called with */ /* an argument of 0, then I'll now add extra BRIKs for the N-1 data */ /* output points for each. */ nbriks += ((DSET_NVALS(old_dset)-1) * addBriks); nbriks += ((DSET_NVALS(old_dset) ) * fullBriks); /* ------------- Mask business -----------------*/ if( mask_dset == NULL ){ mmm = NULL ; if( verb ) INFO_message("%d voxels in the entire dataset (no mask)\n", DSET_NVOX(old_dset)) ; } else { if( DSET_NVOX(mask_dset) != DSET_NVOX(old_dset) ) ERROR_exit("Input and mask datasets are not same dimensions!\n"); mmm = THD_makemask( mask_dset , 0 , mask_bot, mask_top ) ; mcount = THD_countmask( DSET_NVOX(old_dset) , mmm ) ; if( mcount <= 0 ) ERROR_exit("No voxels in the mask!\n") ; if( verb ) INFO_message("%d voxels in the mask\n",mcount) ; DSET_delete(mask_dset) ; } if( cmask != NULL ){ if( ncmask != DSET_NVOX(old_dset) ) ERROR_exit("Input and cmask datasets are not same dimensions!\n"); if( mmm != NULL ){ for( ii=0 ; ii < DSET_NVOX(old_dset) ; ii++ ) mmm[ii] = (mmm[ii] && cmask[ii]) ; free(cmask) ; mcount = THD_countmask( DSET_NVOX(old_dset) , mmm ) ; if( mcount <= 0 ) ERROR_exit("No voxels in the mask+cmask!\n") ; if( verb ) INFO_message("%d voxels in the mask+cmask\n",mcount) ; } else { mmm = cmask ; mcount = THD_countmask( DSET_NVOX(old_dset) , mmm ) ; if( mcount <= 0 ) ERROR_exit("No voxels in the cmask!\n") ; if( verb ) INFO_message("%d voxels in the cmask\n",mcount) ; } } /*------------- ready to compute new dataset -----------*/ new_dset = MAKER_4D_to_typed_fbuc( old_dset , /* input dataset */ prefix , /* output prefix */ datum , /* output datum */ 0 , /* ignore count */ 0 , /* can't detrend in maker function KRH 12/02*/ nbriks , /* number of briks */ STATS_tsfunc , /* timeseries processor */ NULL, /* data for tsfunc */ mmm, nscale ) ; if( new_dset != NULL ){ tross_Copy_History( old_dset , new_dset ) ; tross_Make_History( "3dTstat" , argc,argv , new_dset ) ; for (methIndex = 0,brikIndex = 0; methIndex < nmeths; methIndex++, brikIndex++) { if ((meth[methIndex] == METH_AUTOCORR) || (meth[methIndex] == METH_ACCUMULATE) || (meth[methIndex] == METH_AUTOREGP)) { numMultBriks = meth[methIndex+1]; /* note: this looks like it should be NV-1 4 Mar 2008 [rickr] */ if (numMultBriks == 0) numMultBriks = DSET_NVALS(old_dset)-1; /* new flag for NVALS [rickr] */ if (numMultBriks == -1) numMultBriks = DSET_NVALS(old_dset); for (ii = 1; ii <= numMultBriks; ii++) { char tmpstr[25]; if (meth[methIndex] == METH_AUTOREGP) { sprintf(tmpstr,"%s[%d](%d)",meth_names[meth[methIndex]], numMultBriks,ii); } else { sprintf(tmpstr,"%s(%d)",meth_names[meth[methIndex]],ii); } EDIT_BRICK_LABEL(new_dset, (brikIndex + ii - 1), tmpstr) ; } methIndex++; brikIndex += numMultBriks - 1; } else { EDIT_BRICK_LABEL(new_dset, brikIndex, meth_names[meth[methIndex]]) ; } } if( tsout ) /* then change output to a time series */ EDIT_dset_items( new_dset , ADN_ntt , brikIndex , ADN_ttorg , DSET_TIMEORIGIN(old_dset) , ADN_ttdel , DSET_TIMESTEP(old_dset) , ADN_tunits , DSET_TIMEUNITS(old_dset) , 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[] ) { 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 iv,nvals , nvec , ii,jj,kk , nvox ; THD_3dim_dataset * new_dset=NULL ; double * choleski ; float ** refvec , * fv , * fc , * fit ; MRI_IMAGE * flim ; /*** read input options ***/ if( argc < 2 || strncmp(argv[1],"-help",4) == 0 ) DT_Syntax() ; /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/ mainENTRY("3dDetrend main"); machdep() ; PRINT_VERSION("3dDetrend"); AFNI_logger("3dDetrend",argc,argv) ; { int new_argc ; char ** new_argv ; addto_args( argc , argv , &new_argc , &new_argv ) ; if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; } } DT_read_opts( argc , argv ) ; /*** create new dataset (empty) ***/ new_dset = EDIT_empty_copy( DT_dset ) ; /* make a copy of its header */ /* modify its header */ tross_Copy_History( DT_dset , new_dset ) ; tross_Make_History( "3dDetrend" , argc,argv , new_dset ) ; EDIT_dset_items( new_dset , ADN_prefix , DT_output_prefix , ADN_directory_name, DT_session , ADN_none ) ; /* can't re-write existing dataset */ if( THD_deathcon() && THD_is_file(DSET_HEADNAME(new_dset)) ) ERROR_exit("File %s already exists!\n",DSET_HEADNAME(new_dset) ) ; /* read input in, and attach its bricks to the output dataset */ /* (not good in a plugin, but OK in a standalone program!) */ if( DT_verb ) INFO_message("Loading input dataset bricks\n") ; DSET_mallocize( new_dset ) ; DSET_mallocize( DT_dset ) ; DSET_load( DT_dset ) ; CHECK_LOAD_ERROR(DT_dset) ; nvals = DSET_NVALS(new_dset) ; for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( new_dset , iv , DSET_BRICK_TYPE(DT_dset,iv) , DSET_ARRAY(DT_dset,iv) ) ; if( DT_norm && DSET_BRICK_TYPE(new_dset,0) != MRI_float ){ INFO_message("Turning -normalize option off (input not in float format)"); DT_norm = 0 ; } /* load reference (detrending) vectors; setup to do least squares fitting of each voxel */ nvec = 0 ; for( ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ ) /* number of detrending vectors */ nvec += IMARR_SUBIMAGE(DT_imar,ii)->ny ; refvec = (float **) malloc( sizeof(float *)*nvec ) ; for( kk=ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ ){ fv = MRI_FLOAT_PTR( IMARR_SUBIMAGE(DT_imar,ii) ) ; for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ ) /* compute ptr */ refvec[kk++] = fv + ( jj * IMARR_SUBIMAGE(DT_imar,ii)->nx ) ; /* to vectors */ } fit = (float *) malloc( sizeof(float) * nvals ) ; /* will get fit to voxel data */ /*--- do the all-voxels-together case ---*/ if( !DT_byslice ){ choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ; if( choleski == NULL ) ERROR_exit("Choleski factorization fails: linearly dependent vectors!\n") ; /* loop over voxels, fitting and detrending (or replacing) */ nvox = DSET_NVOX(new_dset) ; if( DT_verb ) INFO_message("Computing voxel fits\n") ; for( kk=0 ; kk < nvox ; kk++ ){ flim = THD_extract_series( kk , new_dset , 0 ) ; /* data */ fv = MRI_FLOAT_PTR(flim) ; fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ; /* coef */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ; for( jj=0 ; jj < nvec ; jj++ ) for( ii=0 ; ii < nvals ; ii++ ) fit[ii] += fc[jj] * refvec[jj][ii] ; /* fit */ if( !DT_replace ) /* remove */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ; if( DT_norm ) THD_normalize( nvals , fit ) ; /* 23 Nov 1999 */ THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ; free(fc) ; mri_free(flim) ; } free(choleski) ; /*- end of all-voxels-together case -*/ } #ifdef ALLOW_BYSLICE else { /*- start of slice case [08 Dec 1999] -*/ int ksl , nslice , tt , nx,ny , nxy , kxy ; MRI_IMAGE * vim ; /* make separate space for the slice-wise detrending vectors */ for( kk=ii=0 ; ii < DT_nvector ; ii++ ){ for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ ) /* replace ptrs */ refvec[kk++] = (float *) malloc( sizeof(float) * nvals ) ; /* to vectors */ } nslice = DSET_NZ(new_dset) ; nxy = DSET_NX(new_dset) * DSET_NY(new_dset) ; /* loop over slices */ for( ksl=0 ; ksl < nslice ; ksl++ ){ if( DT_verb ) INFO_message("Computing voxel fits for slice %d\n",ksl) ; /* extract slice vectors from input interlaced vectors */ for( kk=ii=0 ; ii < DT_nvector ; ii++ ){ /* loop over vectors */ vim = IMARR_SUBIMAGE(DT_imar,ii) ; /* ii-th vector image */ nx = vim->nx ; ny = vim->ny ; /* dimensions */ for( jj=0 ; jj < ny ; jj++ ){ /* loop over columns */ fv = MRI_FLOAT_PTR(vim) + (jj*nx) ; /* ptr to column */ for( tt=0 ; tt < nvals ; tt++ ) /* loop over time */ refvec[kk][tt] = fv[ksl+tt*nslice] ; /* data point */ } } /* initialize fitting for this slice */ choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ; if( choleski == NULL ) ERROR_exit("Choleski fails: linearly dependent vectors at slice %d\n",ksl) ; /* loop over voxels in this slice */ for( kxy=0 ; kxy < nxy ; kxy++ ){ kk = kxy + ksl*nxy ; /* 3D index */ flim = THD_extract_series( kk , new_dset , 0 ) ; /* data */ fv = MRI_FLOAT_PTR(flim) ; fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ; /* coef */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ; for( jj=0 ; jj < nvec ; jj++ ) for( ii=0 ; ii < nvals ; ii++ ) fit[ii] += fc[jj] * refvec[jj][ii] ; /* fit */ if( !DT_replace ) /* remove */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ; if( DT_norm ) THD_normalize( nvals , fit ) ; /* 23 Nov 1999 */ THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ; free(fc) ; mri_free(flim) ; } free(choleski) ; } /* end of loop over slices */ } /*- end of -byslice case -*/ #endif /*-- done done done done --*/ DSET_write(new_dset) ; if( DT_verb ) WROTE_DSET(new_dset) ; 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 *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[] ) { int narg , ndset , nvox , nvals,iv ; THD_3dim_dataset *xset , *yset , *mask_dset=NULL , *hset ; byte *mmm=NULL ; MRI_IMAGE *imh , *hdim ; float *har , *hdar ; char *prefix = "jhist" ; THD_ivec3 nxyz ; THD_fvec3 dxyz ; /*-- read command line arguments --*/ if( argc < 3 || strncmp(argv[1],"-help",5) == 0 ){ printf("Usage: 3JointHist [options] dset1 dset2\n" "Output = dataset of joint histogram between dset1[0] and\n" " each sub-brick of dset2 (1 histogram per slice).\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" " -prefix ppp = If you don't know this by now, you shouldn't\n" " even THINK about using this program!\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] ) ; if( mask_dset == NULL ) ERROR_exit("Can't open -mask %s",argv[narg]) ; narg++ ; continue ; } if( strcmp(argv[narg],"-prefix") == 0 ){ if( narg+1 >= argc ) ERROR_exit("Need argument after -prefix") ; prefix = 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++] ) ; yset = THD_open_dataset( argv[narg++] ) ; if( xset == NULL || yset == NULL ) ERROR_exit("Cannot open both input datasets!\n") ; 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) ; } INFO_message("loading 1st dataset") ; DSET_load(xset) ; CHECK_LOAD_ERROR(xset) ; INFO_message("loading 2nd dataset") ; DSET_load(yset) ; CHECK_LOAD_ERROR(yset) ; hset = EDIT_empty_copy(NULL) ; nxyz.ijk[0] = nxyz.ijk[1] = 256 ; nxyz.ijk[2] = nvals ; dxyz.xyz[0] = dxyz.xyz[1] = dxyz.xyz[2] = 1.0f ; EDIT_dset_items( hset , ADN_prefix , prefix , ADN_datum_all , MRI_float , ADN_nvals , 1 , ADN_type , HEAD_ANAT_TYPE , ADN_view_type , xset->view_type , ADN_func_type , ANAT_MRAN_TYPE , ADN_nxyz , nxyz , ADN_xyzdel , dxyz , ADN_malloc_type, DATABLOCK_MEM_MALLOC , ADN_none ) ; EDIT_substitute_brick( hset , 0 , MRI_float , NULL ) ; hdim = DSET_BRICK(hset,0) ; hdar = MRI_FLOAT_PTR(hdim) ; fprintf(stderr,"++ histogram-izing") ; for( iv=0 ; iv < nvals ; iv++ ){ fprintf(stderr,".") ; imh = mri_jointhist( DSET_BRICK(xset,0), DSET_BRICK(yset,iv), mmm ) ; har = MRI_FLOAT_PTR(imh) ; memcpy( hdar+(256*256*iv) , har , 256*256*sizeof(float) ) ; mri_free(imh) ; } fprintf(stderr,"\n") ; DSET_write(hset) ; WROTE_DSET(hset) ; exit(0) ; }
int main( int argc , char *argv[] ) { int nx,ny,nz , nxyz , ii,kk , num1,num2 , num_tt=0 , iv , piece , fim_offset; float dx,dy,dz , dxyz , num1_inv=0.0 , num2_inv , num1m1_inv=0.0 , num2m1_inv , dof , dd,tt,q1,q2 , f1,f2 , tt_max=0.0 ; THD_3dim_dataset *dset=NULL , *new_dset=NULL ; THD_3dim_dataset * base_dset; float *av1 , *av2 , *sd1 , *sd2 , *ffim , *gfim ; float *base_ary=NULL; void *vsp ; void *vdif ; /* output mean difference */ char cbuf[THD_MAX_NAME] ; float fbuf[MAX_STAT_AUX] , fimfac ; int output_datum ; float npiece , memuse ; float *dofbrik=NULL , *dofar=NULL ; THD_3dim_dataset *dof_dset=NULL ; /*-- read command line arguments --*/ if( argc < 2 || strncmp(argv[1],"-help",5) == 0 ) TT_syntax(NULL) ; /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/ mainENTRY("3dttest main"); machdep() ; PRINT_VERSION("3dttest") ; INFO_message("For most purposes, 3dttest++ should be used instead of 3dttest!") ; { 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("3dttest",argc,argv) ; TT_read_opts( argc , argv ) ; if( ! TT_be_quiet ) printf("3dttest: t-tests of 3D datasets, by RW Cox\n") ; /*-- read first dataset in set2 to get dimensions, etc. --*/ dset = THD_open_dataset( TT_set2->ar[0] ) ; /* 20 Dec 1999 BDW */ if( ! ISVALID_3DIM_DATASET(dset) ) ERROR_exit("Unable to open dataset file %s",TT_set2->ar[0]); nx = dset->daxes->nxx ; ny = dset->daxes->nyy ; nz = dset->daxes->nzz ; nxyz = nx * ny * nz ; dx = fabs(dset->daxes->xxdel) ; dy = fabs(dset->daxes->yydel) ; dz = fabs(dset->daxes->zzdel) ; dxyz = dx * dy * dz ; #ifdef TTDEBUG printf("*** nx=%d ny=%d nz=%d\n",nx,ny,nz) ; #endif /*-- make an empty copy of this dataset, for eventual output --*/ #ifdef TTDEBUG printf("*** making empty dataset\n") ; #endif new_dset = EDIT_empty_copy( dset ) ; tross_Make_History( "3dttest" , argc,argv , new_dset ) ; strcpy( cbuf , dset->self_name ) ; strcat( cbuf , "+TT" ) ; iv = DSET_PRINCIPAL_VALUE(dset) ; if( TT_datum >= 0 ){ output_datum = TT_datum ; } else { output_datum = DSET_BRICK_TYPE(dset,iv) ; if( output_datum == MRI_byte ) output_datum = MRI_short ; } #ifdef TTDEBUG printf(" ** datum = %s\n",MRI_TYPE_name[output_datum]) ; #endif iv = EDIT_dset_items( new_dset , ADN_prefix , TT_prefix , ADN_label1 , TT_prefix , ADN_directory_name , TT_session , ADN_self_name , cbuf , ADN_type , ISHEAD(dset) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_func_type , FUNC_TT_TYPE , ADN_nvals , FUNC_nvals[FUNC_TT_TYPE] , ADN_ntt , 0 , /* 07 Jun 2007 */ ADN_datum_all , output_datum , ADN_none ) ; if( iv > 0 ) ERROR_exit("%d errors in attempting to create output dataset!",iv ) ; if( THD_deathcon() && THD_is_file(new_dset->dblk->diskptr->header_name) ) ERROR_exit( "Output dataset file %s already exists--cannot continue!\a", new_dset->dblk->diskptr->header_name ) ; #ifdef TTDEBUG printf("*** deleting exemplar dataset\n") ; #endif THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; /** macro to test a malloc-ed pointer for validity **/ #define MTEST(ptr) \ if((ptr)==NULL) \ ( fprintf(stderr,"*** Cannot allocate memory for statistics!\n"), exit(0) ) /*-- make space for the t-test computations --*/ /* (allocate entire volumes) 13 Dec 2005 [rickr] */ npiece = 3.0 ; /* need at least this many */ if( TT_paired ) npiece += 1.0 ; else if( TT_set1 != NULL ) npiece += 2.0 ; npiece += mri_datum_size(output_datum) / (float) sizeof(float) ; npiece += mri_datum_size(output_datum) / (float) sizeof(float) ; #if 0 piece_size = TT_workmem * MEGA / ( npiece * sizeof(float) ) ; if( piece_size > nxyz ) piece_size = nxyz ; #ifdef TTDEBUG printf("*** malloc-ing space for statistics: %g float arrays of length %d\n", npiece,piece_size) ; #endif #endif av2 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(av2) ; sd2 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(sd2) ; ffim = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(ffim) ; num2 = TT_set2->num ; if( TT_paired ){ av1 = sd1 = NULL ; gfim = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(gfim) ; num1 = num2 ; } else if( TT_set1 != NULL ){ av1 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(av1) ; sd1 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(sd1) ; gfim = NULL ; num1 = TT_set1->num ; } else { av1 = sd1 = NULL ; gfim = NULL ; num1 = 0 ; } vdif = (void *) malloc( mri_datum_size(output_datum) * nxyz ) ; MTEST(vdif) ; vsp = (void *) malloc( mri_datum_size(output_datum) * nxyz ) ; MTEST(vsp) ; /* 27 Dec 2002: make DOF dataset (if prefix is given, and unpooled is on) */ if( TT_pooled == 0 && TT_dof_prefix[0] != '\0' ){ dofbrik = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(dofbrik) ; dof_dset = EDIT_empty_copy( new_dset ) ; tross_Make_History( "3dttest" , argc,argv , dof_dset ) ; EDIT_dset_items( dof_dset , ADN_prefix , TT_dof_prefix , ADN_directory_name , TT_session , ADN_type , ISHEAD(dset) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE, ADN_func_type , FUNC_BUCK_TYPE , ADN_nvals , 1 , ADN_datum_all , MRI_float , ADN_none ) ; if( THD_is_file(dof_dset->dblk->diskptr->header_name) ) ERROR_exit( "-dof_prefix dataset file %s already exists--cannot continue!\a", dof_dset->dblk->diskptr->header_name ) ; EDIT_substitute_brick( dof_dset , 0 , MRI_float , dofbrik ) ; } /* print out memory usage to edify the user */ if( ! TT_be_quiet ){ memuse = sizeof(float) * nxyz * npiece + ( mri_datum_size(output_datum) + sizeof(short) ) * nxyz ; if( dofbrik != NULL ) memuse += sizeof(float) * nxyz ; /* 27 Dec 2002 */ printf("--- allocated %d Megabytes memory for internal use (%d volumes)\n", (int)(memuse/MEGA), (int)npiece) ; } mri_fix_data_pointer( vdif , DSET_BRICK(new_dset,0) ) ; /* attach bricks */ mri_fix_data_pointer( vsp , DSET_BRICK(new_dset,1) ) ; /* to new dataset */ /** only short and float are allowed for output **/ if( output_datum != MRI_short && output_datum != MRI_float ) ERROR_exit("Illegal output data type %d = %s", output_datum , MRI_TYPE_name[output_datum] ) ; num2_inv = 1.0 / num2 ; num2m1_inv = 1.0 / (num2-1) ; if( num1 > 0 ){ num1_inv = 1.0 / num1 ; num1m1_inv = 1.0 / (num1-1) ; } /*----- loop over pieces to process the input datasets with -----*/ /** macro to open a dataset and make it ready for processing **/ #define DOPEN(ds,name) \ do{ int pv ; (ds) = THD_open_dataset((name)) ; /* 16 Sep 1999 */ \ if( !ISVALID_3DIM_DATASET((ds)) ) \ ERROR_exit("Can't open dataset: %s",(name)) ; \ if( (ds)->daxes->nxx!=nx || (ds)->daxes->nyy!=ny || (ds)->daxes->nzz!=nz ) \ ERROR_exit("Axes size mismatch: %s",(name)) ; \ if( !EQUIV_GRIDS((ds),new_dset) ) \ WARNING_message("Grid mismatch: %s",(name)) ; \ if( DSET_NUM_TIMES((ds)) > 1 ) \ ERROR_exit("Can't use time-dependent data: %s",(name)) ; \ if( TT_use_editor ) EDIT_one_dataset( (ds), &TT_edopt ) ; \ else DSET_load((ds)) ; \ pv = DSET_PRINCIPAL_VALUE((ds)) ; \ if( DSET_ARRAY((ds),pv) == NULL ) \ ERROR_exit("Can't access data: %s",(name)) ; \ if( DSET_BRICK_TYPE((ds),pv) == MRI_complex ) \ ERROR_exit("Can't use complex data: %s",(name)) ; \ break ; } while (0) #if 0 /* can do it directly now (without offsets) 13 Dec 2005 [rickr] */ /** macro to return pointer to correct location in brick for current processing **/ #define SUB_POINTER(ds,vv,ind,ptr) \ do{ switch( DSET_BRICK_TYPE((ds),(vv)) ){ \ default: ERROR_exit("Illegal datum! ***"); \ case MRI_short:{ short * fim = (short *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; \ case MRI_byte:{ byte * fim = (byte *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; \ case MRI_float:{ float * fim = (float *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; } break ; } while(0) #endif /** number of pieces to process **/ /* num_piece = (nxyz + piece_size - 1) / nxyz ; */ #if 0 nice(2) ; /** lower priority a little **/ #endif /* possibly open TT_base_dset now, and convert to floats */ if( TT_base_dname ) { DOPEN(base_dset, TT_base_dname) ; base_ary = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(base_ary) ; EDIT_coerce_scale_type(nxyz , DSET_BRICK_FACTOR(base_dset,0) , DSET_BRICK_TYPE(base_dset,0),DSET_ARRAY(base_dset,0), /* input */ MRI_float ,base_ary ) ; /* output */ THD_delete_3dim_dataset( base_dset , False ) ; base_dset = NULL ; } /* only 1 'piece' now 13 Dec 2005 [rickr] */ for( piece=0 ; piece < 1 ; piece++ ){ fim_offset = 0 ; #ifdef TTDEBUG printf("*** start of piece %d: length=%d offset=%d\n",piece,nxyz,fim_offset) ; #else if( ! TT_be_quiet ){ printf("--- starting piece %d/%d (%d voxels) ",piece+1,1,nxyz) ; fflush(stdout) ; } #endif /** process set2 (and set1, if paired) **/ for( ii=0 ; ii < nxyz ; ii++ ) av2[ii] = 0.0 ; for( ii=0 ; ii < nxyz ; ii++ ) sd2[ii] = 0.0 ; for( kk=0 ; kk < num2 ; kk++ ){ /** read in the data **/ DOPEN(dset,TT_set2->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set2->ar[kk]); #endif #if 0 /* fimfac will be compute when the results are ready */ if( piece == 0 && kk == 0 ){ fimfac = DSET_BRICK_FACTOR(dset,iv) ; if( fimfac == 0.0 ) fimfac = 1.0 ; fimfacinv = 1.0 / fimfac ; #ifdef TTDEBUG printf(" ** set fimfac = %g\n",fimfac) ; #endif } #endif /** convert it to floats (in ffim) **/ EDIT_coerce_scale_type(nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,ffim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; /** get the paired dataset, if present **/ if( TT_paired ){ DOPEN(dset,TT_set1->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set1->ar[kk]); #endif EDIT_coerce_scale_type( nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,gfim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; if( TT_voxel >= 0 ) fprintf(stderr,"-- paired values #%02d: %f, %f\n", kk,ffim[TT_voxel],gfim[TT_voxel]) ; for( ii=0 ; ii < nxyz ; ii++ ) ffim[ii] -= gfim[ii] ; } else if( TT_voxel >= 0 ) fprintf(stderr,"-- set2 value #%02d: %f\n",kk,ffim[TT_voxel]); #ifdef TTDEBUG printf(" * adding into av2 and sd2\n") ; #endif /* accumulate into av2 and sd2 */ for( ii=0 ; ii < nxyz ; ii++ ){ dd = ffim[ii] ; av2[ii] += dd ; sd2[ii] += dd * dd ; } } /* end of loop over set2 datasets */ /** form the mean and stdev of set2 **/ #ifdef TTDEBUG printf(" ** forming mean and sigma of set2\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] *= num2_inv ; dd = (sd2[ii] - num2*av2[ii]*av2[ii]) ; sd2[ii] = (dd > 0.0) ? sqrt( num2m1_inv * dd ) : 0.0 ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- s2 mean = %g, sd = %g\n", av2[TT_voxel],sd2[TT_voxel]) ; /** if set1 exists but is not paired with set2, process it now **/ if( ! TT_paired && TT_set1 != NULL ){ for( ii=0 ; ii < nxyz ; ii++ ) av1[ii] = 0.0 ; for( ii=0 ; ii < nxyz ; ii++ ) sd1[ii] = 0.0 ; for( kk=0 ; kk < num1 ; kk++ ){ DOPEN(dset,TT_set1->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set1->ar[kk]); #endif EDIT_coerce_scale_type( nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,ffim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; #ifdef TTDEBUG printf(" * adding into av1 and sd1\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ dd = ffim[ii] ; av1[ii] += dd ; sd1[ii] += dd * dd ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- set1 value #%02d: %g\n",kk,ffim[TT_voxel]) ; } /* end of loop over set1 datasets */ /** form the mean and stdev of set1 **/ #ifdef TTDEBUG printf(" ** forming mean and sigma of set1\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ av1[ii] *= num1_inv ; dd = (sd1[ii] - num1*av1[ii]*av1[ii]) ; sd1[ii] = (dd > 0.0) ? sqrt( num1m1_inv * dd ) : 0.0 ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- s1 mean = %g, sd = %g\n", av1[TT_voxel], sd1[TT_voxel]) ; } /* end of processing set1 by itself */ /***** now form difference and t-statistic *****/ #ifndef TTDEBUG if( ! TT_be_quiet ){ printf("+") ; fflush(stdout) ; } /* progress */ #else printf(" ** computing t-tests next\n") ; #endif #if 0 /* will do at end using EDIT_convert_dtype 13 Dec 2005 [rickr] */ /** macro to assign difference value to correct type of array **/ #define DIFASS switch( output_datum ){ \ case MRI_short: sdar[ii] = (short) (fimfacinv*dd) ; break ; \ case MRI_float: fdar[ii] = (float) dd ; break ; } #define TOP_SS 32700 #define TOP_TT (32700.0/FUNC_TT_SCALE_SHORT) #endif if( TT_paired || TT_use_bval == 1 ){ /** case 1: paired estimate or 1-sample **/ if( TT_paired || TT_n1 == 0 ){ /* the olde waye: 1 sample test */ f2 = 1.0 / sqrt( (double) num2 ) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= (base_ary ? base_ary[ii] : TT_bval) ; /* final mean */ if( sd2[ii] > 0.0 ){ num_tt++ ; tt = av2[ii] / (f2 * sd2[ii]) ; sd2[ii] = tt; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0; } } if( TT_voxel >= 0 ) fprintf(stderr,"-- paired/bval mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; } else { /* 10 Oct 2007: -sdn1 was used with -base1: 'two' sample test */ f1 = (TT_n1-1.0) * (1.0/TT_n1 + 1.0/num2) / (TT_n1+num2-2.0) ; f2 = (num2 -1.0) * (1.0/TT_n1 + 1.0/num2) / (TT_n1+num2-2.0) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= (base_ary ? base_ary[ii] : TT_bval) ; /* final mean */ q1 = f1 * TT_sd1*TT_sd1 + f2 * sd2[ii]*sd2[ii] ; if( q1 > 0.0 ){ num_tt++ ; tt = av2[ii] / sqrt(q1) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0 ; } } } /* end of -sdn1 special case */ #ifdef TTDEBUG printf(" ** paired or bval test: num_tt = %d\n",num_tt) ; #endif } else if( TT_pooled ){ /** case 2: unpaired 2-sample, pooled variance **/ f1 = (num1-1.0) * (1.0/num1 + 1.0/num2) / (num1+num2-2.0) ; f2 = (num2-1.0) * (1.0/num1 + 1.0/num2) / (num1+num2-2.0) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= av1[ii] ; /* final mean */ q1 = f1 * sd1[ii]*sd1[ii] + f2 * sd2[ii]*sd2[ii] ; if( q1 > 0.0 ){ num_tt++ ; tt = av2[ii] / sqrt(q1) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0 ; } } if( TT_voxel >= 0 ) fprintf(stderr,"-- unpaired, pooled mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; #ifdef TTDEBUG printf(" ** pooled test: num_tt = %d\n",num_tt) ; #endif } else { /** case 3: unpaired 2-sample, unpooled variance **/ /** 27 Dec 2002: modified to save DOF into dofar **/ if( dofbrik != NULL ) dofar = dofbrik + fim_offset ; /* 27 Dec 2002 */ for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= av1[ii] ; q1 = num1_inv * sd1[ii]*sd1[ii] ; q2 = num2_inv * sd2[ii]*sd2[ii] ; if( q1>0.0 && q2>0.0 ){ /* have positive variances? */ num_tt++ ; tt = av2[ii] / sqrt(q1+q2) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; if( dofar != NULL ) /* 27 Dec 2002 */ dofar[ii] = (q1+q2)*(q1+q2) / (num1m1_inv*q1*q1 + num2m1_inv*q2*q2) ; } else { sd2[ii] = 0.0 ; if( dofar != NULL ) dofar[ii] = 1.0 ; /* 27 Dec 2002 */ } } if( TT_voxel >= 0 ) fprintf(stderr,"-- unpaired, unpooled mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; #ifdef TTDEBUG printf(" ** unpooled test: num_tt = %d\n",num_tt) ; #endif } #ifndef TTDEBUG if( ! TT_be_quiet ){ printf("\n") ; fflush(stdout) ; } #endif } /* end of loop over pieces of the input */ if( TT_paired ){ printf("--- Number of degrees of freedom = %d (paired test)\n",num2-1) ; dof = num2 - 1 ; } else if( TT_use_bval == 1 ){ if( TT_n1 == 0 ){ printf("--- Number of degrees of freedom = %d (1-sample test)\n",num2-1) ; dof = num2 - 1 ; } else { dof = TT_n1+num2-2 ; printf("--- Number of degrees of freedom = %d (-sdn1 2-sample test)\n",(int)dof) ; } } else { printf("--- Number of degrees of freedom = %d (2-sample test)\n",num1+num2-2) ; dof = num1+num2-2 ; if( ! TT_pooled ) printf(" (For unpooled variance estimate, this is only approximate!)\n") ; } printf("--- Number of t-tests performed = %d out of %d voxels\n",num_tt,nxyz) ; printf("--- Largest |t| value found = %g\n",tt_max) ; kk = sizeof(ptable) / sizeof(float) ; for( ii=0 ; ii < kk ; ii++ ){ tt = student_p2t( ptable[ii] , dof ) ; printf("--- Double sided tail p = %8f at t = %8f\n" , ptable[ii] , tt ) ; } /**----------------------------------------------------------------------**/ /** now convert data to output format 13 Dec 2005 [rickr] **/ /* first set mean */ fimfac = EDIT_convert_dtype(nxyz , MRI_float,av2 , output_datum,vdif , 0.0) ; DSET_BRICK_FACTOR(new_dset, 0) = (fimfac != 0.0) ? 1.0/fimfac : 0.0 ; dd = fimfac; /* save for debug output */ /* if output is of type short, limit t-stat magnitude to 32.7 */ if( output_datum == MRI_short ){ for( ii=0 ; ii < nxyz ; ii++ ){ if ( sd2[ii] > 32.7 ) sd2[ii] = 32.7 ; else if( sd2[ii] < -32.7 ) sd2[ii] = -32.7 ; } } fimfac = EDIT_convert_dtype(nxyz , MRI_float,sd2 , output_datum,vsp , 0.0) ; DSET_BRICK_FACTOR(new_dset, 1) = (fimfac != 0.0) ? 1.0/fimfac : 0.0 ; #ifdef TTDEBUG printf(" ** fimfac for mean, t-stat = %g, %g\n",dd, fimfac) ; #endif /**----------------------------------------------------------------------**/ INFO_message("Writing combined dataset into %s\n", DSET_BRIKNAME(new_dset) ) ; fbuf[0] = dof ; for( ii=1 ; ii < MAX_STAT_AUX ; ii++ ) fbuf[ii] = 0.0 ; (void) EDIT_dset_items( new_dset , ADN_stat_aux , fbuf , ADN_none ) ; #if 0 /* factors already set */ fbuf[0] = (output_datum == MRI_short && fimfac != 1.0 ) ? fimfac : 0.0 ; fbuf[1] = (output_datum == MRI_short ) ? 1.0 / FUNC_TT_SCALE_SHORT : 0.0 ; (void) EDIT_dset_items( new_dset , ADN_brick_fac , fbuf , ADN_none ) ; #endif if( !AFNI_noenv("AFNI_AUTOMATIC_FDR") ) ii = THD_create_all_fdrcurves(new_dset) ; else ii = 0 ; THD_load_statistics( new_dset ) ; THD_write_3dim_dataset( NULL,NULL , new_dset , True ) ; if( ii > 0 ) ININFO_message("created %d FDR curves in header",ii) ; if( dof_dset != NULL ){ /* 27 Dec 2002 */ DSET_write( dof_dset ) ; WROTE_DSET( dof_dset ) ; } exit(0) ; }
int main( int argc , char *argv[] ) { char *prefix = "PVmap" , *uvpref=NULL , *cpt ; THD_3dim_dataset *inset=NULL , *outset=NULL , *mset=NULL ; char *maskname=NULL ; byte *mask=NULL ; int nmask ; int nopt ; MRI_IMAGE *pvim ; MRI_IMAGE *uvim ; float_pair uvlam ; float ulam , vlam , scon ; if( argc < 2 || ! strncmp(argv[1],"-h",2) ){ printf("\n" "3dPVmap [-prefix XXX] [-mask MMM] [-automask] inputdataset\n" "\n" "Computes the first 2 principal component vectors of a\n" "time series datasets, then outputs the R-squared coefficient\n" "of each voxel time series with these first 2 components.\n" "\n" "Each voxel times series from the input dataset is minimally pre-processed\n" "before the PCA is computed:\n" " Despiking\n" " Legendre polynomial detrending\n" " L2 normalizing (sum-of-squares = 1)\n" "If you want more impressive pre-processing, you'll have to do that\n" "before running 3dPVmap (e.g., use the errts dataset from afni_proc.py).\n" "\n" "Program also outputs the first 2 principal component time series\n" "vectors into a 1D file, for fun and profit.\n" "\n" "The fractions of total-sum-of-squares allocable to the first 2\n" "principal components are written to stdout at the end of the program.\n" "along with a 3rd number that is a measure of the spatial concentration\n" "or dispersion of the PVmap.\n" "\n" "These values can be captured into a file by Unix shell redirection\n" "or into a shell variable by assigment:\n" " 3dPVmap -mask AUTO Fred.nii > Fred.sval.1D\n" " set sval = ( `3dPVmap -mask AUTO Fred.nii` ) # csh syntax\n" "If the first value is very large, for example, this might indicate\n" "the widespread presence of some artifact in the dataset.\n" "\n" "If the 3rd number is bigger than 1, it indicates that the PVmap\n" "is more concentrated in space; if it is less than one, it indicates\n" "that it is more dispersed in space (relative to a uniform density).\n" " 3dPVmap -mask AUTO Zork.nii\n" " ++ mask has 21300 voxels\n" " ++ Output dataset ./PVmap+orig.BRIK\n" " 0.095960 0.074847 1.356635\n" "The first principal component accounted for 9.6%% of the total sum-of-squares,\n" "the second component for 7.5%%, and the PVmap is fairly concentrated in space.\n" "These %% values are not very unusual, but the concentration is fairly high\n" "and the dataset should be further investigated.\n" "\n" "A concentration value below 1 indicates the PVmap is fairly dispersed; this\n" "often means the larger PVmap values are found near the edges of the brain\n" "and can be caused by motion or respiration artifacts.\n" "\n" "The goal is to visualize any widespread time series artifacts.\n" "For example, if a 'significant' part of the brain shows R-squared > 0.25,\n" "that could be a subject for concern -- look at your data!\n" "\n" "Author: Zhark the Unprincipaled\n\n" ) ; exit(0) ; } nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-prefix needs an argument!"); prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("%s is not a valid prefix!",prefix); nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ if( ++nopt >= argc ) ERROR_exit("-mask needs an argument!"); maskname = strdup(argv[nopt]) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-automask") == 0 ){ /* 18 Apr 2019 */ maskname = strdup("AUTO") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-") == 0 ){ nopt++ ; continue ; } ERROR_exit("Unknown option %s",argv[nopt]) ; } if( nopt >= argc ) ERROR_exit("No input dataset name?") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; if( DSET_NVALS(inset) < 9 ) ERROR_exit("input dataset too short") ; if( maskname != NULL ){ if( strncasecmp(maskname,"AUTO",4) != 0 ){ mset = THD_open_dataset(maskname) ; CHECK_OPEN_ERROR(mset,maskname) ; if( !EQUIV_GRIDXYZ(inset,mset) ) ERROR_exit("-mask and input dataset don't match") ; mask = THD_makemask( mset , 0 , 1.0f,0.0f ) ; nmask = THD_countmask( DSET_NVOX(mset) , mask ) ; } else { mask = THD_automask(inset) ; if( mask == NULL ) ERROR_exit("Can't make automask :(") ; nmask = THD_countmask( DSET_NVOX(inset) , mask ) ; } INFO_message("mask has %d voxels",nmask) ; if( nmask < 9 ) ERROR_exit("mask is too small") ; } else { nmask = DSET_NVOX(inset) ; INFO_message("No mask == using all %d voxels",nmask) ; } pvim = THD_dataset_to_pvmap( inset , mask ) ; if( pvim == NULL ) ERROR_exit("Can't compute PVmap :(") ; DSET_unload(inset) ; outset = EDIT_empty_copy(inset) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_datum_all , MRI_float , ADN_nvals , 1 , ADN_ntt , 0 , ADN_type , HEAD_FUNC_TYPE , ADN_func_type , FUNC_FIM_TYPE , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(pvim) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dPVmap", argc,argv, outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; uvim = mri_pvmap_get_vecpair() ; uvlam = mri_pvmap_get_lampair() ; uvpref = (char *)malloc(sizeof(char)*(strlen(prefix)+32)) ; strcpy(uvpref,prefix) ; cpt = strstr(uvpref,".nii" ) ; if( cpt != NULL ) *cpt = '\0' ; cpt = strstr(uvpref,".HEAD") ; if( cpt != NULL ) *cpt = '\0' ; cpt = strrchr(uvpref,'+' ) ; if( cpt != NULL ) *cpt = '\0' ; strcat(uvpref,".1D") ; mri_write_1D( uvpref , uvim ) ; ulam = uvlam.a*uvlam.a / nmask ; vlam = uvlam.b*uvlam.b / nmask ; scon = mri_spatial_concentration(pvim) ; printf("%.6f %.6f %.6f\n",ulam,vlam,scon) ; exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL , *jnset=NULL , *outset , *wset=NULL; int ncode=0 , code[MAX_NCODE] , iarg=1 , ii ; MCW_cluster *nbhd=NULL ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0 , automask=0 ; char *prefix="./localstat" ; int ntype=0 ; float na=0.0f,nb=0.0f,nc=0.0f ; double hist_pow=0.3333333 ; int hist_nbin=0 ; float hbot1=1.0f , htop1=-1.0f ; int hbot1_perc=0, htop1_perc=0 ; float hbot2=1.0f , htop2=-1.0f ; int hbot2_perc=0, htop2_perc=0 ; /*---- for the clueless who wish to become clued-in ----*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dLocalBistat [options] dataset1 dataset2\n" "\n" "This program computes statistics between 2 datasets,\n" "at each voxel, based on a local neighborhood of that voxel.\n" " - The neighborhood is defined by the '-nbhd' option.\n" " - Statistics to be calculated are defined by the '-stat' option(s).\n" " - The 2 input datasets should have the same number of sub-bricks.\n" " - OR dataset1 should have 1 sub-brick and dataset2 can have more than 1:\n" " - In which case, the statistics of dataset2 against dataset1 are\n" " calculated for the #0 sub-brick of dataset1 against each sub-brick\n" " of dataset2.\n" "\n" "OPTIONS\n" "-------\n" " -nbhd 'nnn' = The string 'nnn' defines the region around each\n" " voxel that will be extracted for the statistics\n" " calculation. The format of the 'nnn' string are:\n" " * 'SPHERE(r)' where 'r' is the radius in mm;\n" " the neighborhood is all voxels whose center-to-\n" " center distance is less than or equal to 'r'.\n" " ** A negative value for 'r' means that the region\n" " is calculated using voxel indexes rather than\n" " voxel dimensions; that is, the neighborhood\n" " region is a \"sphere\" in voxel indexes of\n" " \"radius\" abs(r).\n" " * 'RECT(a,b,c)' is a rectangular block which\n" " proceeds plus-or-minus 'a' mm in the x-direction,\n" " 'b' mm in the y-direction, and 'c' mm in the\n" " z-direction. The correspondence between the\n" " dataset xyz axes and the actual spatial orientation\n" " can be determined by using program 3dinfo.\n" " ** A negative value for 'a' means that the region\n" " extends plus-and-minus abs(a) voxels in the\n" " x-direction, rather than plus-and-minus a mm.\n" " Mutatis mutandum for negative 'b' and/or 'c'.\n" " * 'RHDD(r)' is a rhombic dodecahedron of 'radius' r.\n" " * 'TOHD(r)' is a truncated octahedron of 'radius' r.\n" "\n" " -stat sss = Compute the statistic named 'sss' on the values\n" " extracted from the region around each voxel:\n" " * pearson = Pearson correlation coefficient\n" " * spearman = Spearman correlation coefficient\n" " * quadrant = Quadrant correlation coefficient\n" " * mutinfo = Mutual Information\n" " * normuti = Normalized Mutual Information\n" " * jointent = Joint entropy\n" " * hellinger= Hellinger metric\n" " * crU = Correlation ratio (Unsymmetric)\n" " * crM = Correlation ratio (symmetrized by Multiplication)\n" " * crA = Correlation ratio (symmetrized by Addition)\n" " * L2slope = slope of least-squares (L2) linear regression of\n" " the data from dataset1 vs. the dataset2\n" " (i.e., d2 = a + b*d1 ==> this is 'b')\n" " * L1slope = slope of least-absolute-sum (L1) linear regression\n" " of the data from dataset1 vs. the dataset2\n" " * num = number of the values in the region:\n" " with the use of -mask or -automask,\n" " the size of the region around any given\n" " voxel will vary; this option lets you\n" " map that size.\n" #if 0 " * ncd = Normalized Compression Distance (zlib; very slow)\n" #endif #if 0 /* activate after testing */ " * euclidian = Euclidian distance.\n" " * cityblock = City Block distance.\n" #endif " * ALL = all of the above, in that order\n" " More than one '-stat' option can be used.\n" "\n" " -mask mset = Read in dataset 'mset' and use the nonzero voxels\n" " therein as a mask. Voxels NOT in the mask will\n" " not be used in the neighborhood of any voxel. Also,\n" " a voxel NOT in the mask will have its statistic(s)\n" " computed as zero (0).\n" " -automask = Compute the mask as in program 3dAutomask.\n" " -mask and -automask are mutually exclusive: that is,\n" " you can only specify one mask.\n" " -weight ws = Use dataset 'ws' as a weight. Only applies to 'pearson'.\n" "\n" " -prefix ppp = Use string 'ppp' as the prefix for the output dataset.\n" " The output dataset is always stored as floats.\n" "\n" "ADVANCED OPTIONS\n" "----------------\n" " -histpow pp = By default, the number of bins in the histogram used\n" " for calculating the Hellinger, Mutual Information,\n" " and Correlation Ratio statistics is n^(1/3), where n\n" " is the number of data points in the -nbhd mask. You\n" " can change that exponent to 'pp' with this option.\n" " -histbin nn = Or you can just set the number of bins directly to 'nn'.\n" " -hclip1 a b = Clip dataset1 to lie between values 'a' and 'b'. If 'a'\n" " and 'b' end in '%%', then these values are percentage\n" " points on the cumulative histogram.\n" " -hclip2 a b = Similar to '-hclip1' for dataset2.\n" "\n" "-----------------------------\n" "Author: RWCox - October 2006.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dLocalBistat"); mainENTRY("3dLocalBistat main"); machdep(); AFNI_logger("3dLocalBistat",argc,argv) ; /*---- loop over options ----*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-hclip1") == 0 ){ char *cpt1, *cpt2 ; if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after -hclip1") ; hbot1 = (float)strtod(argv[iarg],&cpt1) ; iarg++ ; htop1 = (float)strtod(argv[iarg],&cpt2) ; if( hbot1 >= htop1 ) ERROR_exit("illegal values after -hclip1") ; if( *cpt1 == '%' ){ hbot1_perc = 1 ; hbot1 = (int)rint((double)hbot1) ; if( hbot1 < 0 || hbot1 > 99 ) ERROR_exit("illegal bot percentage after -hclip1") ; } if( *cpt2 == '%' ){ htop1_perc = 1 ; htop1 = (int)rint((double)htop1) ; if( htop1 < 1 || htop1 > 100 ) ERROR_exit("illegal top percentage after -hclip1") ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-hclip2") == 0 ){ char *cpt1, *cpt2 ; if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after -hclip2") ; hbot2 = (float)strtod(argv[iarg],&cpt1) ; iarg++ ; htop2 = (float)strtod(argv[iarg],&cpt2) ; if( hbot2 >= htop2 ) ERROR_exit("illegal values after -hclip2") ; if( *cpt1 == '%' ){ hbot2_perc = 1 ; hbot2 = (int)rint((double)hbot2) ; if( hbot2 < 0 || hbot2 > 99 ) ERROR_exit("illegal bot percentage after -hclip2") ; } if( *cpt2 == '%' ){ htop2_perc = 1 ; htop2 = (int)rint((double)htop2) ; if( htop2 < 1 || htop2 > 100 ) ERROR_exit("illegal top percentage after -hclip2") ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-histpow") == 0 ){ if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; hist_pow = strtod(argv[iarg],NULL) ; if( hist_pow <= 0.0 || hist_pow > 0.5 ){ WARNING_message("Illegal value after -histpow"); hist_pow = 0.33333; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-histbin") == 0 ){ if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ; hist_nbin = (int)strtod(argv[iarg],NULL) ; if( hist_nbin <= 1 ) WARNING_message("Illegal value after -histbin"); 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 name after '-prefix'") ; 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],"-weight") == 0 ){ /* 14 Aug 2007 */ if( ++iarg >= argc ) ERROR_exit("Need argument after '-weight'") ; if( wset != NULL ) ERROR_exit("Can't have two weight inputs") ; wset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(wset,argv[iarg]) ; DSET_load(wset) ; CHECK_LOAD_ERROR(wset) ; 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],"-stat") == 0 ){ char *cpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-stat'") ; cpt = argv[iarg] ; if( *cpt == '-' ) cpt++ ; if( strcasecmp(cpt,"pearson") == 0 ) code[ncode++] = NBISTAT_PEARSON_CORR ; else if( strcasecmp(cpt,"spearman") == 0 ) code[ncode++] = NBISTAT_SPEARMAN_CORR; else if( strcasecmp(cpt,"quadrant") == 0 ) code[ncode++] = NBISTAT_QUADRANT_CORR; else if( strcasecmp(cpt,"mutinfo") == 0 ) code[ncode++] = NBISTAT_MUTUAL_INFO ; else if( strcasecmp(cpt,"normuti") == 0 ) code[ncode++] = NBISTAT_NORMUT_INFO ; else if( strcasecmp(cpt,"jointent") == 0 ) code[ncode++] = NBISTAT_JOINT_ENTROPY; else if( strcasecmp(cpt,"hellinger")== 0 ) code[ncode++] = NBISTAT_HELLINGER ; else if( strcasecmp(cpt,"crU") == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_U ; else if( strcasecmp(cpt,"crM") == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_M ; else if( strcasecmp(cpt,"crA") == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_A ; else if( strcasecmp(cpt,"L2slope") == 0 ) code[ncode++] = NBISTAT_L2SLOPE ; else if( strcasecmp(cpt,"L1slope") == 0 ) code[ncode++] = NBISTAT_L1SLOPE ; else if( strcasecmp(cpt,"num") == 0 ) code[ncode++] = NBISTAT_NUM ; #if 0 else if( strcasecmp(cpt,"ncd") == 0 ) code[ncode++] = NBISTAT_NCD ; #endif #if 0 /* activate after testing */ else if( strcasecmp(cpt,"euclidian") == 0 ) code[ncode++] = NBISTAT_EUCLIDIAN_DIST ; else if( strcasecmp(cpt,"cityblock") == 0 ) code[ncode++] = NBISTAT_CITYBLOCK_DIST ; #endif else if( strcasecmp(cpt,"ALL") == 0 ){ code[ncode++] = NBISTAT_PEARSON_CORR ; code[ncode++] = NBISTAT_SPEARMAN_CORR; code[ncode++] = NBISTAT_QUADRANT_CORR; code[ncode++] = NBISTAT_MUTUAL_INFO ; code[ncode++] = NBISTAT_NORMUT_INFO ; code[ncode++] = NBISTAT_JOINT_ENTROPY; code[ncode++] = NBISTAT_HELLINGER ; code[ncode++] = NBISTAT_CORR_RATIO_U ; code[ncode++] = NBISTAT_CORR_RATIO_M ; code[ncode++] = NBISTAT_CORR_RATIO_A ; code[ncode++] = NBISTAT_L2SLOPE ; code[ncode++] = NBISTAT_L1SLOPE ; code[ncode++] = NBISTAT_NUM ; #if 0 code[ncode++] = NBISTAT_NCD ; #endif #if 0 /* activate after testing */ code[ncode++] = NBISTAT_EUCLIDIAN_DIST; code[ncode++] = NBISTAT_CITYBLOCK_DIST; #endif } else ERROR_exit("-stat '%s' is an unknown statistic type",argv[iarg]) ; 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,"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 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 { ERROR_exit("Unknown -nbhd shape: '%s'",cpt) ; } iarg++ ; continue ; } ERROR_exit("Unknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ /*---- check for stupid user inputs ----*/ if( ncode <= 0 ) ERROR_exit("No '-stat' options given?") ; if( ntype <= 0 ) ERROR_exit("No '-nbhd' option given?!") ; /*---- deal with input datasets ----*/ if( iarg > argc-1 ) ERROR_exit("No first input dataset on command line?") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; iarg++ ; if( iarg > argc-1 ) ERROR_exit("No second input dataset on command line?") ; jnset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(jnset,argv[iarg]) ; if( jnset == NULL ) ERROR_exit("Can't open dataset '%s'",argv[iarg]) ; if( DSET_NVOX(jnset) != DSET_NVOX(inset) ) ERROR_exit("Input datasets have different numbers of voxels!?"); if( DSET_NVALS(jnset) != DSET_NVALS(inset) ){ if( DSET_NVALS(inset) > 1 ){ ERROR_exit("Input datasets have different numbers of sub-bricks!?"); } else { INFO_message("first input dataset has 1 sub-brick, second has %d",DSET_NVALS(jnset)) ; } } DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; DSET_load(jnset) ; CHECK_LOAD_ERROR(jnset) ; 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 , nvox ; byte *jask ; mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset #1?") ; jask = THD_automask( jnset ) ; if( jask == NULL ) ERROR_message("Can't create -automask from input dataset #2?") ; nvox = DSET_NVOX(inset) ; for( ii=0 ; ii < nvox ; ii++ ) mask[ii] = (mask[ii] || jask[ii]) ; free(jask) ; mmm = THD_countmask( nvox , mask ) ; INFO_message("Number of voxels in dual automask = %d",mmm) ; if( mmm < 11 ) ERROR_exit("Automask is too small to process") ; } if( wset != NULL ){ /* 14 Aug 2007 */ MRI_IMAGE *wim ; float *war ; if( DSET_NVOX(wset) != DSET_NVOX(inset) ) ERROR_exit("-weight dataset mismatch with input datasets!") ; wim = mri_scale_to_float( DSET_BRICK_FACTOR(wset,0), DSET_BRICK(wset,0) ); war = MRI_FLOAT_PTR(wim) ; DSET_delete(wset) ; if( mask != NULL ){ int nvox = DSET_NVOX(inset) ; for( ii=0 ; ii < nvox ; ii++ ) if( !mask[ii] ) war[ii] = 0.0f ; } mri_bistat_setweight( wim ) ; mri_free(wim) ; } /*---- create neighborhood -----*/ switch( ntype ){ default: ERROR_exit("WTF? ntype=%d",ntype) ; case NTYPE_SPHERE:{ float dx , dy , dz ; 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_RHDD:{ float dx , dy , dz ; 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 ; case NTYPE_TOHD:{ float dx , dy , dz ; 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_tohdmask( 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(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 ; } INFO_message("Neighborhood comprises %d voxels",nbhd->num_pt) ; if( hist_nbin <= 1 ) hist_nbin = (int)pow((double)nbhd->num_pt,hist_pow) ; if( hist_nbin <= 1 ) hist_nbin = 2 ; INFO_message("2D histogram size = %d",hist_nbin) ; set_2Dhist_hbin( hist_nbin ) ; if( hbot1_perc || htop1_perc ){ MRI_IMAGE *fim ; float perc[101] ; fim = THD_median_brick(inset) ; mri_percents(fim,100,perc) ; mri_free(fim) ; if( hbot1_perc ) hbot1 = perc[(int)hbot1] ; if( htop1_perc ) htop1 = perc[(int)htop1] ; INFO_message("Clipping dataset '%s' between %g and %g" , DSET_BRIKNAME(inset),hbot1,htop1 ) ; } if( hbot2_perc || htop2_perc ){ MRI_IMAGE *fim ; float perc[101] ; fim = THD_median_brick(jnset) ; mri_percents(fim,100,perc) ; mri_free(fim) ; if( hbot2_perc ) hbot2 = perc[(int)hbot2] ; if( htop2_perc ) htop2 = perc[(int)htop2] ; INFO_message("Clipping dataset '%s' between %g and %g" , DSET_BRIKNAME(jnset),hbot2,htop2 ) ; } mri_nbistat_setclip( hbot1,htop1 , hbot2,htop2 ) ; /*---- actually do some work for a change ----*/ THD_localbistat_verb(1) ; outset = THD_localbistat( inset,jnset , mask , nbhd , ncode , code ) ; DSET_unload(inset) ; DSET_unload(jnset) ; if( outset == NULL ) ERROR_exit("Function THD_localbistat() fails?!") ; EDIT_dset_items( outset , ADN_prefix,prefix , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dLocalBistat" , argc,argv , outset ) ; #if 1 { char *lcode[66] , lll[66] ; lcode[0] = "Rank cor" ; lcode[1] = "Quad cor" ; lcode[2] = "Pear cor" ; lcode[3] = "MI" ; lcode[4] = "NMI" ; lcode[5] = "Jnt Entropy" ; lcode[6] = "Hlngr metric" ; lcode[7] = "CorRat Sym*" ; lcode[8] = "CorRat Sym+" ; lcode[9] = "CorRatUnsym" ; lcode[10]= "Number" ; lcode[11]= "NCD" ; lcode[12]= "Euclidian Dist"; lcode[13]= "CityBlock Dist"; if( DSET_NVALS(inset) == 1 ){ for( ii=0 ; ii < DSET_NVALS(outset) ; ii++ ) EDIT_dset_items( outset , ADN_brick_label_one+ii, lcode[code[ii%ncode]-NBISTAT_BASE], ADN_none ) ; } else { for( ii=0 ; ii < DSET_NVALS(outset) ; ii++ ){ sprintf(lll,"%s[%d]",lcode[code[ii%ncode]-NBISTAT_BASE],(ii/ncode)) ; EDIT_dset_items( outset , ADN_brick_label_one+ii,lll, ADN_none ) ; } } } #endif DSET_write( outset ) ; WROTE_DSET( outset ) ; exit(0) ; }
int main( int argc , char *argv[] ) { int iarg , ct , do_GM=0 ; int do_T2=0 ; float T2_uperc=98.5f ; byte *T2_mask=NULL ; char *prefix = "Unifized" ; THD_3dim_dataset *inset=NULL , *outset=NULL ; MRI_IMAGE *imin , *imout ; float clfrac=0.2f ; AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("\n" "Usage: 3dUnifize [options] inputdataset\n\n" "* The input dataset is supposed to be a T1-weighted volume,\n" " possibly already skull-stripped (e.g., via 3dSkullStrip).\n" " ++ However, this program can be a useful step to take BEFORE\n" " 3dSkullStrip, since the latter program can fail if the input\n" " volume is strongly shaded -- 3dUnifize will (mostly) remove\n" " such shading artifacts.\n" "* The output dataset has the white matter (WM) intensity approximately\n" " uniformized across space, and scaled to peak at about 1000.\n" "* The output dataset is always stored in float format!\n" "* If the input dataset has more than 1 sub-brick, only sub-brick\n" " #0 will be processed!\n" "* Method: Obi-Wan's personal variant of Ziad's sneaky trick.\n" " (If you want to know what his trick is, you'll have to ask him, or\n" " read Obi-Wan's source code, which is a world of ecstasy and exaltation,\n" " or just read all the way to the end of this help output.)\n" "* The principal motive for this program is for use in an image\n" " registration script, and it may or may not be useful otherwise.\n" "\n" "--------\n" "Options:\n" "--------\n" " -prefix pp = Use 'pp' for prefix of output dataset.\n" " -input dd = Alternative way to specify input dataset.\n" " -T2 = Treat the input as if it were T2-weighted, rather than\n" " T1-weighted. This processing is done simply by inverting\n" " the image contrast, processing it as if that result were\n" " T1-weighted, and then re-inverting the results.\n" " ++ This option is NOT guaranteed to be useful for anything!\n" " ++ Of course, nothing in AFNI comes with a guarantee :-)\n" " ++ If you want to be REALLY sneaky, giving this option twice\n" " will skip the second inversion step, so the result will\n" " look like a T1-weighted volume (except at the edges and\n" " near blood vessels).\n" " ++ Might be useful for skull-stripping T2-weighted datasets.\n" " ++ Don't try the '-T2 -T2' trick on FLAIR-T2-weighted datasets.\n" " The results aren't pretty!\n" " -GM = Also scale to unifize 'gray matter' = lower intensity voxels\n" " (to aid in registering images from different scanners).\n" " ++ This option is recommended for use with 3dQwarp when\n" " aligning 2 T1-weighted volumes, in order to make the\n" " WM-GM contrast about the same for the datasets, even\n" " if they don't come from the same scanner/pulse-sequence.\n" " ++ Note that standardizing the contrasts with 3dUnifize will help\n" " 3dQwarp match the source dataset to the base dataset. If you\n" " later want the original source dataset to be warped, you can\n" " do so using the 3dNwarpApply program.\n" " -Urad rr = Sets the radius (in voxels) of the ball used for the sneaky trick.\n" " ++ Default value is %.1f, and should be changed proportionally\n" " if the dataset voxel size differs significantly from 1 mm.\n" " -ssave ss = Save the scale factor used at each voxel into a dataset 'ss'.\n" " ++ This is the white matter scale factor, and does not include\n" " the factor from the '-GM' option (if that was included).\n" " ++ The input dataset is multiplied by the '-ssave' image\n" " (voxel-wise) to get the WM-unifized image.\n" " ++ Another volume (with the same grid dimensions) could be\n" " scaled the same way using 3dcalc, if that is needed.\n" " -quiet = Don't print the fun fun fun progress messages (but whyyyy?).\n" " ++ For the curious, the codes used are:\n" " A = Automask\n" " D = Duplo down (process a half-size volume)\n" " V = Voxel-wise histograms to get local scale factors\n" " U = duplo Up (convert local scale factors to full-size volume)\n" " W = multiply by White matter factors\n" " G = multiply by Gray matter factors [cf the -GM option]\n" " I = contrast inversion [cf the -T2 option]\n" " ++ 'Duplo down' means to scale the input volume to be half the\n" " grid size in each direction for speed when computing the\n" " voxel-wise histograms. The sub-sampling is done using the\n" " median of the central voxel value and its 6 nearest neighbors.\n" "\n" "------------------------------------------\n" "Special options for Jedi AFNI Masters ONLY:\n" "------------------------------------------\n" " -rbt R b t = Specify the 3 parameters for the algorithm, as 3 numbers\n" " following the '-rbt':\n" " R = radius; same as given by option '-Urad' [default=%.1f]\n" " b = bottom percentile of normalizing data range [default=%.1f]\n" " r = top percentile of normalizing data range [default=%.1f]\n" "\n" " -T2up uu = Set the upper percentile point used for T2-T1 inversion.\n" " The default value is 98.5 (for no good reason), and 'uu' is\n" " allowed to be anything between 90 and 100 (inclusive).\n" " ++ The histogram of the data is built, and the uu-th percentile\n" " point value is called 'U'. The contrast inversion is simply\n" " given by output_value = max( 0 , U - input_value ).\n" "\n" " -clfrac cc = Set the automask 'clip level fraction' to 'cc', which\n" " must be a number between 0.1 and 0.9.\n" " A small 'cc' means to make the initial threshold\n" " for clipping (a la 3dClipLevel) smaller, which\n" " will tend to make the mask larger. [default=0.1]\n" " ++ [22 May 2013] The previous version of this program used a\n" " clip level fraction of 0.5, which proved to be too large\n" " for some users, who had images with very strong shading issues.\n" " Thus, the default value for this parameter was lowered to 0.1.\n" " ++ [24 May 2016] The default value for this parameter was\n" " raised to 0.2, since the lower value often left a lot of\n" " noise outside the head on non-3dSkullStrip-ed datasets.\n" " You can still manually set -clfrac to 0.1 if you need to\n" " correct for very large shading artifacts.\n" " ++ If the results of 3dUnifize have a lot of noise outside the head,\n" " then using '-clfrac 0.5' value will probably help.\n" #ifndef USE_ALL_VALS "\n" " -useall = The 'old' way of operating was to use all dataset values\n" " in the local WM histogram. The 'new' way [May 2016] is to\n" " only use positive values. If you want to use the 'old' way,\n" " then this option is what you want.\n" #endif "\n" "-- Feb 2013 - by Obi-Wan Unifobi\n" #ifdef USE_OMP "-- This code uses OpenMP to speed up the slowest part (voxel-wise histograms).\n" #endif , Uprad , Uprad , Upbot , Uptop ) ; printf("\n" "----------------------------------------------------------------------------\n" "HOW IT WORKS (Ziad's sneaky trick is revealed at last! And more.)\n" "----------------------------------------------------------------------------\n" "The basic idea is that white matter in T1-weighted images is reasonably\n" "uniform in intensity, at least when averaged over 'large-ish' regions.\n" "\n" "The first step is to create a local white matter intensity volume.\n" "Around each voxel (inside the volume 'automask'), the ball of values\n" "within a fixed radius (default=18.3 voxels) is extracted and these\n" "numbers are sorted. The values in the high-intensity range of the\n" "histogram (default=70%% to 80%%) are averaged. The result from this\n" "step is a smooth 3D map of the 'white matter intensity' (WMI).\n" "\n" " [The parameters of the above process can be altered with the '-rbt' option.]\n" " [For speed, the WMI map is produced on an image that is half-size in all ]\n" " [directions ('Duplo down'), and then is expanded back to the full-size ]\n" " [volume ('Duplo up'). The automask procedure can be somewhat controlled ]\n" " [via the '-clfrac' option. The default setting is designed to deal with ]\n" " [heavily shaded images, where the WMI varies by a factor of 5 or more over ]\n" " [the image volume. ]\n" "\n" "The second step is to scale the value at every voxel location x in the input\n" "volume by the factor 1000/WMI(x), so that the 'white matter intensity' is\n" "now uniform-ized to be 1000 everywhere. (This is Ziad's 'trick'; it is easy,\n" "works well, and doesn't require fitting some spatial model to the data: the\n" "data provides its own model.)\n" "\n" "If the '-GM' option is used, then this scaled volume is further processed\n" "to make the lower intensity values (presumably gray matter) have a contrast\n" "similar to that from a collection of 3 Tesla MP-RAGE images that were\n" "acquired at the NIH. (This procedure is not Ziad's fault, and should be\n" "blamed on the reclusive Obi-Wan Unifobi.)\n" "\n" "From the WM-uniform-ized volume, the median of all values larger than 1000\n" "is computed; call this value P. P-1000 represents the upward dispersion\n" "of the high-intensity (white matter) voxels in the volume. This value is\n" "'reflected' below 1000 to Q = 1000 - 2*(P-1000), and Q is taken to be the\n" "upper bound for gray matter voxel intensities. A lower bound for gray\n" "matter voxel values is estimated via the 'clip fraction' algorithm as\n" "implemented in program 3dClipLevel; call this lower bound R. The median\n" "of all values between R and Q is computed; call this value G, which is taken\n" "to be a 'typical' gray matter voxel instensity. Then the values z in the\n" "entire volume are linearly scaled by the formula\n" " z_out = (1000-666)/(1000-G) * (z_in-1000) + 1000\n" "so that the WM uniform-ized intensity of 1000 remains at 1000, and the gray\n" "matter median intensity of G is mapped to 666. (Values z_out that end up\n" "negative are set to 0; as a result, some of CSF might end up as 0.)\n" "The value 666 was chosen because it gave results visually comparable to\n" "various NIH-generated 3 Tesla T1-weighted datasets. (Any suggestions that\n" "this value was chosen for other reasons will be treated as 'beastly'.)\n" "\n" "To recap: the WM uniform-ization process provides a linear scaling factor\n" "that varies for each voxel ('local'), while the GM normalization process\n" "uses a global linear scaling. The GM process is optional, and is simply\n" "designed to make the various T1-weighted images look similar.\n" "\n" "-----** CAVEAT **-----\n" "This procedure was primarily developed to aid in 3D registration, especially\n" "when using 3dQwarp, so that the registration algorithms are trying to match\n" "images that are alike. It is *NOT* intended to be used for quantification\n" "purposes, such as Voxel Based Morphometry! That would better be done via\n" "the 3dSeg program, which is far more complicated.\n" "----------------------------------------------------------------------------\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dUnifize main"); machdep(); AFNI_logger("3dUnifize",argc,argv); PRINT_VERSION("3dUnifize") ; ct = NI_clock_time() ; /*-- scan command line --*/ THD_automask_set_clipfrac(0.1f) ; /* 22 May 2013 */ THD_automask_extclip(1) ; /* 19 Dec 2014 */ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-clfrac") == 0 || strcmp(argv[iarg],"-mfrac") == 0 ){ /* 22 May 2013 */ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; clfrac = (float)strtod( argv[iarg] , NULL ) ; if( clfrac < 0.1f || clfrac > 0.9f ) ERROR_exit("-clfrac value %f is illegal!",clfrac) ; THD_automask_set_clipfrac(clfrac) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix!") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-ssave") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; sspref = strdup(argv[iarg]) ; if( !THD_filename_ok(sspref) ) ERROR_exit("Illegal value after -ssave!") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 || strcmp(argv[iarg],"-inset") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; if( inset != NULL ) ERROR_exit("Can't use '%s' twice" ,argv[iarg-1]) ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-Urad") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ; Uprad = (float)strtod(argv[iarg],NULL) ; if( Uprad < 5.0f || Uprad > 40.0f ) ERROR_exit("Illegal value %f after option -Urad",Uprad) ; iarg++ ; continue ; } #ifndef USE_ALL_VALS if( strcmp(argv[iarg],"-useall") == 0 ){ /* 17 May 2016 */ USE_ALL_VALS = 1 ; iarg++ ; continue ; } #else if( strcmp(argv[iarg],"-useall") == 0 ){ WARNING_message("-useall option is disabled in this version") ; iarg++ ; continue ; } #endif if( strcmp(argv[iarg],"-param") == 0 || /*--- HIDDEN OPTION ---*/ strcmp(argv[iarg],"-rbt" ) == 0 ){ if( ++iarg >= argc-2 ) ERROR_exit("Need 3 arguments (R pb pt) after '%s'",argv[iarg-1]) ; Uprad = (float)strtod(argv[iarg++],NULL) ; Upbot = (float)strtod(argv[iarg++],NULL) ; Uptop = (float)strtod(argv[iarg++],NULL) ; if( Uprad < 5.0f || Uprad > 40.0f || Upbot < 30.0f || Upbot > 80.0f || Uptop <= Upbot || Uptop > 90.0f ) ERROR_exit("Illegal values (R pb pt) after '%s'",argv[iarg-4]) ; continue ; } if( strcasecmp(argv[iarg],"-GM") == 0 ){ do_GM++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-T2") == 0 ){ /* 18 Dec 2014 */ do_T2++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-T2up") == 0 ){ /* 18 Dec 2014 */ T2_uperc = (float)strtod( argv[++iarg] , NULL ) ; if( T2_uperc < 90.0f || T2_uperc > 100.0f ) ERROR_exit("-T2up value is out of range 90..100 :-(") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-quiet") == 0 ){ verb = 0 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-verb") == 0 ){ verb++ ; iarg++ ; continue ; } ERROR_exit("Unknown option: %s\n",argv[iarg]); } /* read input dataset, if not already there */ if( inset == NULL ){ if( iarg >= argc ) ERROR_exit("No dataset name on command line?\n") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; } if( verb ) fprintf(stderr," + Pre-processing: ") ; /* load input from disk */ 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)) ; /* make a float copy for processing */ imin = mri_to_float( DSET_BRICK(inset,0) ) ; DSET_unload(inset) ; if( imin == NULL ) ERROR_exit("Can't copy input dataset brick?!") ; #if 0 THD_cliplevel_search(imin) ; exit(0) ; /* experimentation only */ #endif THD_automask_set_clipfrac(clfrac) ; /* invert T2? */ if( do_T2 ){ if( verb ) fprintf(stderr,"I") ; T2_mask = mri_automask_image(imin) ; mri_invertcontrast_inplace( imin , T2_uperc , T2_mask ) ; } /* do the actual work */ imout = mri_WMunifize(imin) ; /* local WM scaling */ free(imin) ; if( sspref != NULL && sclim != NULL ){ /* 25 Jun 2013 */ STATUS("output -ssave") ; outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , sspref , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(sclim) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dUnifize" , argc,argv , outset ) ; DSET_write(outset) ; outset = NULL ; } if( sclim != NULL ){ mri_free(sclim) ; sclim = NULL ; } if( imout == NULL ){ /* this is bad-ositiness */ if( verb ) fprintf(stderr,"\n") ; ERROR_exit("Can't compute Unifize-d dataset for some reason :-(") ; } if( do_GM ) mri_GMunifize(imout) ; /* global GM scaling */ if( do_T2 == 1 ){ /* re-invert T2? */ if( verb ) fprintf(stderr,"I") ; mri_invertcontrast_inplace( imout , T2_uperc , T2_mask ) ; } else if( do_T2 == 2 ){ /* don't re-invert, but clip off bright edges */ mri_clipedges_inplace( imout , PKVAL*1.111f , PKVAL*1.055f ) ; } if( verb ) fprintf(stderr,"\n") ; /* create output dataset, and write it into the historical record */ 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( "3dUnifize" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; DSET_delete(outset) ; DSET_delete(inset) ; /* vamoose the ranch */ if( verb ){ double cput = COX_cpu_time() ; if( cput > 0.05 ) INFO_message("===== CPU time = %.1f sec Elapsed = %.1f\n", COX_cpu_time() , 0.001*(NI_clock_time()-ct) ) ; else INFO_message("===== Elapsed = %.1f sec\n", 0.001*(NI_clock_time()-ct) ) ; } exit(0) ; }
int main( int argc , char *argv[] ) { int iarg=1 , ii,nvox , nvals ; THD_3dim_dataset *inset=NULL, *outset=NULL , *mset=NULL ; char *prefix="./blurinmask" ; float fwhm_goal=0.0f ; int fwhm_2D=0 ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0 , automask=0 , nmask=0 ; float dx,dy,dz=0.0f , *bar , val ; int floatize=0 ; /* 18 May 2009 */ MRI_IMAGE *immask=NULL ; /* 07 Oct 2009 */ short *mmask=NULL ; short *unval_mmask=NULL ; int nuniq_mmask=0 ; int do_preserve=0 , use_qsar ; /* 19 Oct 2009 */ THD_3dim_dataset *fwhmset=NULL ; MRI_IMAGE *fxim=NULL, *fyim=NULL, *fzim=NULL ; /* 13 Jun 2016 */ int niter_fxyz=0 ; float dmax=0.0f , dmin=0.0f ; /*------- help the pitifully ignorant luser? -------*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: ~1~\n" "3dBlurInMask [options]\n" "Blurs a dataset spatially inside a mask. That's all. Experimental.\n" "\n" "OPTIONS ~1~\n" "-------\n" " -input ddd = This required 'option' specifies the dataset\n" " that will be smoothed and output.\n" " -FWHM f = Add 'f' amount of smoothness to the dataset (in mm).\n" " **N.B.: This is also a required 'option'.\n" " -FWHMdset d = Read in dataset 'd' and add the amount of smoothness\n" " given at each voxel -- spatially variable blurring.\n" " ** EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL **\n" " -mask mmm = Mask dataset, if desired. Blurring will\n" " occur only within the mask. Voxels NOT in\n" " the mask will be set to zero in the output.\n" " -Mmask mmm = Multi-mask dataset -- each distinct nonzero\n" " value in dataset 'mmm' will be treated as\n" " a separate mask for blurring purposes.\n" " **N.B.: 'mmm' must be byte- or short-valued!\n" " -automask = Create an automask from the input dataset.\n" " **N.B.: only 1 masking option can be used!\n" " -preserve = Normally, voxels not in the mask will be\n" " set to zero in the output. If you want the\n" " original values in the dataset to be preserved\n" " in the output, use this option.\n" " -prefix ppp = Prefix for output dataset will be 'ppp'.\n" " **N.B.: Output dataset is always in float format.\n" " -quiet = Don't be verbose with the progress reports.\n" " -float = Save dataset as floats, no matter what the\n" " input data type is.\n" " **N.B.: If the input dataset is unscaled shorts, then\n" " the default is to save the output in short\n" " format as well. In EVERY other case, the\n" " program saves the output as floats. Thus,\n" " the ONLY purpose of the '-float' option is to\n" " force an all-shorts input dataset to be saved\n" " as all-floats after blurring.\n" "\n" "NOTES ~1~\n" "-----\n" " * If you don't provide a mask, then all voxels will be included\n" " in the blurring. (But then why are you using this program?)\n" " * Note that voxels inside the mask that are not contiguous with\n" " any other voxels inside the mask will not be modified at all!\n" " * Works iteratively, similarly to 3dBlurToFWHM, but without\n" " the extensive overhead of monitoring the smoothness.\n" " * But this program will be faster than 3dBlurToFWHM, and probably\n" " slower than 3dmerge.\n" " * Since the blurring is done iteratively, rather than all-at-once as\n" " in 3dmerge, the results will be slightly different than 3dmerge's,\n" " even if no mask is used here (3dmerge, of course, doesn't take a mask).\n" " * If the original FWHM of the dataset was 'S' and you input a value\n" " 'F' with the '-FWHM' option, then the output dataset's smoothness\n" " will be about sqrt(S*S+F*F). The number of iterations will be\n" " about (F*F/d*d) where d=grid spacing; this means that a large value\n" " of F might take a lot of CPU time!\n" " * The spatial smoothness of a 3D+time dataset can be estimated with a\n" " command similar to the following:\n" " 3dFWHMx -detrend -mask mmm+orig -input ddd+orig\n" ) ; printf( " * The minimum number of voxels in the mask is %d\n",MASK_MIN) ; printf( " * Isolated voxels will be removed from the mask!\n") ; PRINT_AFNI_OMP_USAGE("3dBlurInMask",NULL) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dBlurInMask"); mainENTRY("3dBlurInMask main"); machdep(); AFNI_logger("3dBlurInMask",argc,argv); AUTHOR("RW Cox") ; /*---- loop over options ----*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-preserve",5) == 0 ){ /* 19 Oct 2009 */ do_preserve = 1 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-qui",4) == 0 ){ verb = 0 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-ver",4) == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 || strcmp(argv[iarg],"-dset") == 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]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Bad name after '-prefix'") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-Mmask") == 0 ){ /* 07 Oct 2009 */ if( ++iarg >= argc ) ERROR_exit("Need argument after '-Mmask'") ; if( mmask != NULL || 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); #if 0 if( !MRI_IS_INT_TYPE(DSET_BRICK_TYPE(mset,0)) ) ERROR_exit("-Mmask dataset is not integer type!") ; #endif immask = mri_to_short( 1.0 , DSET_BRICK(mset,0) ) ; mmask = MRI_SHORT_PTR(immask) ; unval_mmask = UniqueShort( mmask, mask_nx*mask_ny*mask_nz, &nuniq_mmask, 0 ) ; if( unval_mmask == NULL || nuniq_mmask == 0 ) ERROR_exit("-Mmask dataset cannot be processed!?") ; if( nuniq_mmask == 1 && unval_mmask[0] == 0 ) ERROR_exit("-Mmask dataset is all zeros!?") ; if( verb ){ int qq , ww ; for( ii=qq=0 ; ii < nuniq_mmask ; ii++ ) if( unval_mmask[ii] != 0 ) qq++ ; for( ii=ww=0 ; ii < immask->nvox ; ii++ ) if( mmask[ii] != 0 ) ww++ ; INFO_message("%d unique nonzero values in -Mmask; %d nonzero voxels",qq,ww) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mmask != NULL || 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_unload(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ; ii = THD_mask_remove_isolas( mask_nx,mask_ny,mask_nz , mask ) ; if( verb && ii > 0 ) INFO_message("Removed %d isola%s from mask dataset",ii,(ii==1)?"\0":"s") ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < MASK_MIN ) ERROR_exit("Mask is too small to process") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-automask") == 0 ){ if( mmask != NULL || mask != NULL ) ERROR_exit("Can't have 2 mask inputs") ; automask = 1 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-FWHM") == 0 || strcasecmp(argv[iarg],"-FHWM") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); val = (float)strtod(argv[iarg],NULL) ; if( val <= 0.0f ) ERROR_exit("Illegal value after '%s': '%s'", argv[iarg-1],argv[iarg]) ; fwhm_goal = val ; fwhm_2D = 0 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-FWHMdset") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); if( fwhmset != NULL ) ERROR_exit("You can't use option '-FWHMdset' twice :(") ; fwhmset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(fwhmset,argv[iarg]) ; do_preserve = 1 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-float",6) == 0 ){ /* 18 May 2009 */ floatize = 1 ; iarg++ ; continue ; } #if 0 if( strcmp(argv[iarg],"-FWHMxy") == 0 || strcmp(argv[iarg],"-FHWMxy") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); val = (float)strtod(argv[iarg],NULL) ; if( val <= 0.0f ) ERROR_exit("Illegal value after '%s': '%s'", argv[iarg-1],argv[iarg]) ; fwhm_goal = val ; fwhm_2D = 1 ; iarg++ ; continue ; } #endif ERROR_exit("Uknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ /*----- check for stupid inputs, load datasets, et cetera -----*/ if( fwhmset == NULL && fwhm_goal == 0.0f ) ERROR_exit("No -FWHM option given! What do you want?") ; if( fwhmset != NULL && fwhm_goal > 0.0f ){ WARNING_message("-FWHMdset option replaces -FWHM value") ; fwhm_goal = 0.0f ; } if( fwhmset != NULL && mmask != NULL ) ERROR_exit("Sorry: -FWHMdset and -Mmask don't work together (yet)") ; 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]) ; } nvox = DSET_NVOX(inset) ; dx = fabs(DSET_DX(inset)) ; if( dx == 0.0f ) dx = 1.0f ; dy = fabs(DSET_DY(inset)) ; if( dy == 0.0f ) dy = 1.0f ; dz = fabs(DSET_DZ(inset)) ; if( dz == 0.0f ) dz = 1.0f ; dmax = MAX(dx,dy) ; if( dmax < dz ) dmax = dz ; /* 13 Jun 2016 */ dmin = MIN(dx,dy) ; if( dmin > dz ) dmin = dz ; if( !floatize ){ /* 18 May 2009 */ if( !THD_datum_constant(inset->dblk) || THD_need_brick_factor(inset) || DSET_BRICK_TYPE(inset,0) != MRI_short ){ if( verb ) INFO_message("forcing output to be stored in float format") ; floatize = 1 ; } else { if( verb ) INFO_message("output dataset will be stored as shorts") ; } } else { if( verb ) INFO_message("output dataset will be stored as floats") ; } #if 0 if( DSET_NZ(inset) == 1 && !fwhm_2D ){ WARNING_message("Dataset is 2D ==> switching from -FWHM to -FWHMxy") ; fwhm_2D = 1 ; } #endif /*--- deal with mask or automask ---*/ 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 ){ 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 < MASK_MIN ) ERROR_exit("Automask is too small to process") ; } else if( mmask != NULL ){ if( mask_nx != DSET_NX(inset) || mask_ny != DSET_NY(inset) || mask_nz != DSET_NZ(inset) ) ERROR_exit("-Mmask dataset grid doesn't match input dataset") ; } 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); } /*--- process FWHMdset [13 Jun 2016] ---*/ if( fwhmset != NULL ){ float *fxar,*fyar,*fzar , *fwar ; MRI_IMAGE *fwim ; float fwmax=0.0f , fsx,fsy,fsz ; int ii, nfpos=0 ; if( DSET_NX(inset) != DSET_NX(fwhmset) || DSET_NY(inset) != DSET_NY(fwhmset) || DSET_NZ(inset) != DSET_NZ(fwhmset) ) ERROR_exit("grid dimensions for FWHMdset and input dataset do not match :(") ; STATUS("get fwim") ; DSET_load(fwhmset) ; fwim = mri_scale_to_float(DSET_BRICK_FACTOR(fwhmset,0),DSET_BRICK(fwhmset,0)); fwar = MRI_FLOAT_PTR(fwim); DSET_unload(fwhmset) ; STATUS("process fwar") ; for( ii=0 ; ii < nvox ; ii++ ){ if( mask[ii] && fwar[ii] > 0.0f ){ nfpos++ ; if( fwar[ii] > fwmax ) fwmax = fwar[ii] ; } else { fwar[ii] = 0.0f ; mask[ii] = 0 ; } } if( nfpos < 100 ) ERROR_exit("Cannot proceed: too few (%d) voxels are positive in -FWHMdset!",nfpos) ; niter_fxyz = (int)rintf(2.0f*fwmax*fwmax*FFAC/(0.05f*dmin*dmin)) + 1 ; if( verb ) INFO_message("-FWHMdset: niter=%d npos=%d",niter_fxyz,nfpos) ; STATUS("create fxim etc.") ; fxim = mri_new_conforming(fwim,MRI_float); fxar = MRI_FLOAT_PTR(fxim); fyim = mri_new_conforming(fwim,MRI_float); fyar = MRI_FLOAT_PTR(fyim); fzim = mri_new_conforming(fwim,MRI_float); fzar = MRI_FLOAT_PTR(fzim); fsx = FFAC/(dx*dx*niter_fxyz) ; fsy = FFAC/(dy*dy*niter_fxyz) ; fsz = FFAC/(dz*dz*niter_fxyz) ; /** INFO_message("fsx=%g fsy=%g fsz=%g",fsx,fsy,fsz) ; **/ for( ii=0 ; ii < nvox ; ii++ ){ if( fwar[ii] > 0.0f ){ fxar[ii] = fwar[ii]*fwar[ii] * fsx ; fyar[ii] = fwar[ii]*fwar[ii] * fsy ; fzar[ii] = fwar[ii]*fwar[ii] * fsz ; } else { fxar[ii] = fyar[ii] = fzar[ii] = 0.0f ; } } STATUS("free(fwim)") ; mri_free(fwim) ; } /*--- process input dataset ---*/ STATUS("load input") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; outset = EDIT_empty_copy( inset ) ; /* moved here 04 Jun 2007 */ EDIT_dset_items( outset , ADN_prefix , prefix , ADN_none ) ; EDIT_dset_items( outset , ADN_brick_fac , NULL , ADN_none ) ; /* 11 Sep 2007 */ tross_Copy_History( inset , outset ) ; tross_Make_History( "3dBlurInMask" , argc,argv , outset ) ; nvals = DSET_NVALS(inset) ; use_qsar = (do_preserve || mmask != NULL) ; /* 19 Oct 20090 */ AFNI_OMP_START ; #pragma omp parallel if( nvals > 1 ) { MRI_IMAGE *dsim ; int ids,qit ; byte *qmask=NULL ; register int vv ; MRI_IMAGE *qim=NULL, *qsim=NULL; float *qar=NULL, *dsar, *qsar=NULL; #pragma omp critical (MALLOC) { if( use_qsar ){ qsim = mri_new_conforming(DSET_BRICK(inset,0),MRI_float); qsar = MRI_FLOAT_PTR(qsim); } if( mmask != NULL ){ qmask = (byte *)malloc(sizeof(byte)*nvox) ; qim = mri_new_conforming(immask,MRI_float); qar = MRI_FLOAT_PTR(qim); qim->dx = dx ; qim->dy = dy ; qim->dz = dz ; } } #pragma omp for for( ids=0 ; ids < nvals ; ids++ ){ #pragma omp critical (MALLOC) { dsim = mri_scale_to_float(DSET_BRICK_FACTOR(inset,ids),DSET_BRICK(inset,ids)); DSET_unload_one(inset,ids) ; } dsim->dx = dx ; dsim->dy = dy ; dsim->dz = dz ; dsar = MRI_FLOAT_PTR(dsim) ; /* if needed, initialize qsar with data to be preserved in output */ if( do_preserve ){ for( vv=0 ; vv < nvox ; vv++ ) qsar[vv] = dsar[vv] ; } else if( mmask != NULL ){ for( vv=0 ; vv < nvox ; vv++ ) qsar[vv] = 0.0f ; } if( fwhmset != NULL ){ /* 13 Jun 2016: spatially variable blurring */ for( qit=0 ; qit < niter_fxyz ; qit++ ){ mri_blur3D_variable( dsim , mask , fxim,fyim,fzim ) ; } if( do_preserve ){ for( vv=0 ; vv < nvox ; vv++ ) if( mask[vv] ) qsar[vv] = dsar[vv] ; } } else if( mmask != NULL ){ /* 07 Oct 2009: multiple masks */ int qq ; register short uval ; for( qq=0 ; qq < nuniq_mmask ; qq++ ){ uval = unval_mmask[qq] ; if( uval == 0 ) continue ; for( vv=0 ; vv < nvox ; vv++ ) qmask[vv] = (mmask[vv]==uval) ; /* make mask */ (void)THD_mask_remove_isolas( mask_nx,mask_ny,mask_nz , qmask ) ; nmask = THD_countmask( nvox , qmask ) ; if( verb && ids==0 ) ININFO_message("voxels in Mmask[%d] = %d",uval,nmask) ; if( nmask >= MASK_MIN ){ /* copy data from dataset to qar */ for( vv=0 ; vv < nvox ; vv++ ) if( qmask[vv] ) qar[vv] = dsar[vv] ; /* blur qar (output will be zero where qmask==0) */ mri_blur3D_addfwhm( qim , qmask , fwhm_goal ) ; /** the real work **/ /* copy results back to qsar */ for( vv=0 ; vv < nvox ; vv++ ) if( qmask[vv] ) qsar[vv] = qar[vv] ; } } } else { /* the olden way: 1 mask */ mri_blur3D_addfwhm( dsim , mask , fwhm_goal ) ; /** all the work **/ /* dsim will be zero where mask==0; if we want to preserve the input values, copy dsar into qsar now at all mask!=0 voxels, since qsar contains the original data values */ if( do_preserve ){ for( vv=0 ; vv < nvox ; vv++ ) if( mask[vv] ) qsar[vv] = dsar[vv] ; } } /* if necessary, copy combined results in qsar to dsar for output */ if( use_qsar ){ for( vv=0 ; vv < nvox ; vv++ ) dsar[vv] = qsar[vv] ; } if( floatize ){ EDIT_substitute_brick( outset , ids , MRI_float , dsar ) ; } else { #pragma omp critical (MALLOC) { EDIT_substscale_brick( outset , ids , MRI_float , dsar , MRI_short , 1.0f ) ; mri_free(dsim) ; } } } /* end of loop over sub-bricks */ #pragma omp critical (MALLOC) { if( qsim != NULL ) mri_free(qsim); if( immask != NULL ){ free(qmask); mri_free(qim); } } } /* end OpenMP */ AFNI_OMP_END ; if( mask != NULL ) free( mask) ; if( immask != NULL ) mri_free(immask) ; DSET_unload(inset) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *dset , *oset=NULL , *tset=NULL ; int nvals , iv , nxyz , ii,jj,kk , iarg , kz,kzold ; float cut1=2.5,cut2=4.0 , sq2p,sfac , fq ; MRI_IMAGE *flim ; char *prefix="despike" , *tprefix=NULL ; int corder=-1 , nref , ignore=0 , polort=2 , nuse , nomask=0 ; int nspike, nbig, nproc ; float **ref ; float c21,ic21 , pspike,pbig ; short *sar , *qar ; byte *tar , *mask=NULL ; float *zar , *yar ; int datum ; int localedit=0 ; /* 04 Apr 2007 */ int verb=1 ; int do_NEW = 0 ; /* 29 Nov 2013 */ MRI_IMAGE *NEW_psinv=NULL ; int dilate = 4 ; /* 04 Dec 2013 */ int ctim = 0 ; /*----- Read command line -----*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dDespike [options] dataset\n" "Removes 'spikes' from the 3D+time input dataset and writes\n" "a new dataset with the spike values replaced by something\n" "more pleasing to the eye.\n" "\n" "Method:\n" " * L1 fit a smooth-ish curve to each voxel time series\n" " [see -corder option for description of the curve]\n" " [see -NEW option for a different & faster fitting method]\n" " * Compute the MAD of the difference between the curve and\n" " the data time series (the residuals).\n" " * Estimate the standard deviation 'sigma' of the residuals\n" " as sqrt(PI/2)*MAD.\n" " * For each voxel value, define s = (value-curve)/sigma.\n" " * Values with s > c1 are replaced with a value that yields\n" " a modified s' = c1+(c2-c1)*tanh((s-c1)/(c2-c1)).\n" " * c1 is the threshold value of s for a 'spike' [default c1=2.5].\n" " * c2 is the upper range of the allowed deviation from the curve:\n" " s=[c1..infinity) is mapped to s'=[c1..c2) [default c2=4].\n" "\n" "Options:\n" " -ignore I = Ignore the first I points in the time series:\n" " these values will just be copied to the\n" " output dataset [default I=0].\n" " -corder L = Set the curve fit order to L:\n" " the curve that is fit to voxel data v(t) is\n" "\n" " k=L [ (2*PI*k*t) (2*PI*k*t) ]\n" " f(t) = a+b*t+c*t*t + SUM [ d * sin(--------) + e * cos(--------) ]\n" " k=1 [ k ( T ) k ( T ) ]\n" "\n" " where T = duration of time series;\n" " the a,b,c,d,e parameters are chosen to minimize\n" " the sum over t of |v(t)-f(t)| (L1 regression);\n" " this type of fitting is is insensitive to large\n" " spikes in the data. The default value of L is\n" " NT/30, where NT = number of time points.\n" "\n" " -cut c1 c2 = Alter default values for the spike cut values\n" " [default c1=2.5, c2=4.0].\n" " -prefix pp = Save de-spiked dataset with prefix 'pp'\n" " [default pp='despike']\n" " -ssave ttt = Save 'spikiness' measure s for each voxel into a\n" " 3D+time dataset with prefix 'ttt' [default=no save]\n" " -nomask = Process all voxels\n" " [default=use a mask of high-intensity voxels, ]\n" " [as created via '3dAutomask -dilate 4 dataset'].\n" " -dilate nd = Dilate 'nd' times (as in 3dAutomask). The default\n" " value of 'nd' is 4.\n" " -q[uiet] = Don't print '++' informational messages.\n" "\n" " -localedit = Change the editing process to the following:\n" " If a voxel |s| value is >= c2, then replace\n" " the voxel value with the average of the two\n" " nearest non-spike (|s| < c2) values; the first\n" " one previous and the first one after.\n" " Note that the c1 cut value is not used here.\n" "\n" " -NEW = Use the 'new' method for computing the fit, which\n" " should be faster than the L1 method for long time\n" " series (200+ time points); however, the results\n" " are similar but NOT identical. [29 Nov 2013]\n" " * You can also make the program use the 'new'\n" " method by setting the environment variable\n" " AFNI_3dDespike_NEW\n" " to the value YES; as in\n" " setenv AFNI_3dDespike_NEW YES (csh)\n" " export AFNI_3dDespike_NEW=YES (bash)\n" " * If this variable is set to YES, you can turn off\n" " the '-NEW' processing by using the '-OLD' option.\n" " -->>* For time series more than 500 points long, the\n" " '-OLD' algorithm is tremendously slow. You should\n" " use the '-NEW' algorith in such cases.\n" " ** At some indeterminate point in the future, the '-NEW'\n" " method will become the default!\n" " -->>* As of 29 Sep 2016, '-NEW' is the default if there\n" " is more than 500 points in the time series dataset.\n" "\n" " -NEW25 = A slightly more aggressive despiking approach than\n" " the '-NEW' method.\n" "\n" "Caveats:\n" "* Despiking may interfere with image registration, since head\n" " movement may produce 'spikes' at the edge of the brain, and\n" " this information would be used in the registration process.\n" " This possibility has not been explored or calibrated.\n" "* [LATER] Actually, it seems like the registration problem\n" " does NOT happen, and in fact, despiking seems to help!\n" "* Check your data visually before and after despiking and\n" " registration!\n" " [Hint: open 2 AFNI controllers, and turn Time Lock on.]\n" ) ; PRINT_AFNI_OMP_USAGE("3dDespike",NULL) ; PRINT_COMPILE_DATE ; exit(0) ; } /** AFNI package setup and logging **/ mainENTRY("3dDespike main"); machdep(); AFNI_logger("3dDespike",argc,argv); PRINT_VERSION("3dDespike") ; AUTHOR("RW Cox") ; /** parse options **/ if( AFNI_yesenv("AFNI_3dDespike_NEW") ) do_NEW = 1 ; /* 29 Nov 2013 */ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-q",2) == 0 ){ /* 04 Apr 2007 */ verb = 0 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-v",2) == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-NEW") == 0 ){ /* 29 Nov 2013 */ do_NEW = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-NEW25") == 0 ){ /* 29 Sep 2016 */ do_NEW = 1 ; use_des25 = 1 ; cut1 = 2.5f ; cut2 = 3.2f ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-OLD") == 0 ){ do_NEW = 0 ; iarg++ ; continue ; } /** -localedit **/ if( strcmp(argv[iarg],"-localedit") == 0 ){ /* 04 Apr 2007 */ localedit = 1 ; iarg++ ; continue ; } /** don't use masking **/ if( strcmp(argv[iarg],"-nomask") == 0 ){ nomask = 1 ; iarg++ ; continue ; } /** dilation count [04 Dec 2013] **/ if( strcmp(argv[iarg],"-dilate") == 0 ){ dilate = (int)strtod(argv[++iarg],NULL) ; if( dilate <= 0 ) dilate = 1 ; else if( dilate > 99 ) dilate = 99 ; iarg++ ; continue ; } /** output dataset prefix **/ if( strcmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("-prefix is not good"); iarg++ ; continue ; } /** ratio dataset prefix **/ if( strcmp(argv[iarg],"-ssave") == 0 ){ tprefix = argv[++iarg] ; if( !THD_filename_ok(tprefix) ) ERROR_exit("-ssave prefix is not good"); iarg++ ; continue ; } /** trigonometric polynomial order **/ if( strcmp(argv[iarg],"-corder") == 0 ){ corder = strtol( argv[++iarg] , NULL , 10 ) ; if( corder < 0 ) ERROR_exit("Illegal value of -corder"); iarg++ ; continue ; } /** how much to ignore at start **/ if( strcmp(argv[iarg],"-ignore") == 0 ){ ignore = strtol( argv[++iarg] , NULL , 10 ) ; if( ignore < 0 ) ERROR_exit("Illegal value of -ignore"); iarg++ ; continue ; } /** thresholds for s ratio **/ if( strcmp(argv[iarg],"-cut") == 0 ){ cut1 = strtod( argv[++iarg] , NULL ) ; cut2 = strtod( argv[++iarg] , NULL ) ; if( cut1 < 1.0 || cut2 < cut1+0.5 ) ERROR_exit("Illegal values after -cut"); iarg++ ; continue ; } ERROR_exit("Unknown option: %s",argv[iarg]) ; } c21 = cut2-cut1 ; ic21 = 1.0/c21 ; /*----- read input dataset -----*/ if( iarg >= argc ) ERROR_exit("No input dataset!!??"); dset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(dset,argv[iarg]) ; datum = DSET_BRICK_TYPE(dset,0) ; if( (datum != MRI_short && datum != MRI_float) || !DSET_datum_constant(dset) ) ERROR_exit("Can't process non-short, non-float dataset!") ; if( verb ) INFO_message("Input data type = %s\n",MRI_TYPE_name[datum]) ; nvals = DSET_NUM_TIMES(dset) ; nuse = nvals - ignore ; if( nuse < 15 ) ERROR_exit("Can't use dataset with < 15 time points per voxel!") ; if( nuse > 500 && !do_NEW ){ INFO_message("Switching to '-NEW' method since number of time points = %d > 500",nuse) ; do_NEW = 1 ; } if( use_des25 && nuse < 99 ) use_des25 = 0 ; if( verb ) INFO_message("ignoring first %d time points, using last %d",ignore,nuse); if( corder > 0 && 4*corder+2 > nuse ){ ERROR_exit("-corder %d is too big for NT=%d",corder,nvals) ; } else if( corder < 0 ){ corder = rint(nuse/30.0) ; if( corder > 50 && !do_NEW ) corder = 50 ; if( verb ) INFO_message("using %d time points => -corder %d",nuse,corder) ; } else { if( verb ) INFO_message("-corder %d set from command line",corder) ; } nxyz = DSET_NVOX(dset) ; if( verb ) INFO_message("Loading dataset %s",argv[iarg]) ; DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; /*-- create automask --*/ if( !nomask ){ mask = THD_automask( dset ) ; if( verb ){ ii = THD_countmask( DSET_NVOX(dset) , mask ) ; INFO_message("%d voxels in the automask [out of %d in dataset]",ii,DSET_NVOX(dset)) ; } for( ii=0 ; ii < dilate ; ii++ ) THD_mask_dilate( DSET_NX(dset), DSET_NY(dset), DSET_NZ(dset), mask, 3 ) ; if( verb ){ ii = THD_countmask( DSET_NVOX(dset) , mask ) ; INFO_message("%d voxels in the dilated automask [out of %d in dataset]",ii,DSET_NVOX(dset)) ; } } else { if( verb ) INFO_message("processing all %d voxels in dataset",DSET_NVOX(dset)) ; } /*-- create empty despiked dataset --*/ oset = EDIT_empty_copy( dset ) ; EDIT_dset_items( oset , ADN_prefix , prefix , ADN_brick_fac , NULL , ADN_datum_all , datum , ADN_none ) ; if( THD_deathcon() && THD_is_file(DSET_HEADNAME(oset)) ) ERROR_exit("output dataset already exists: %s",DSET_HEADNAME(oset)); tross_Copy_History( oset , dset ) ; tross_Make_History( "3dDespike" , argc , argv , oset ) ; /* create bricks (will be filled with zeros) */ for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( oset , iv , datum , NULL ) ; /* copy the ignored bricks */ switch( datum ){ case MRI_short: for( iv=0 ; iv < ignore ; iv++ ){ sar = DSET_ARRAY(oset,iv) ; qar = DSET_ARRAY(dset,iv) ; memcpy( sar , qar , DSET_BRICK_BYTES(dset,iv) ) ; DSET_unload_one(dset,iv) ; } break ; case MRI_float: for( iv=0 ; iv < ignore ; iv++ ){ zar = DSET_ARRAY(oset,iv) ; yar = DSET_ARRAY(dset,iv) ; memcpy( zar , yar , DSET_BRICK_BYTES(dset,iv) ) ; DSET_unload_one(dset,iv) ; } break ; } /*-- setup to save a threshold statistic dataset, if desired --*/ if( tprefix != NULL ){ float *fac ; tset = EDIT_empty_copy( dset ) ; fac = (float *) malloc( sizeof(float) * nvals ) ; for( ii=0 ; ii < nvals ; ii++ ) fac[ii] = TFAC ; EDIT_dset_items( tset , ADN_prefix , tprefix , ADN_brick_fac , fac , ADN_datum_all , MRI_byte , ADN_func_type , FUNC_FIM_TYPE , ADN_none ) ; free(fac) ; tross_Copy_History( tset , dset ) ; tross_Make_History( "3dDespike" , argc , argv , tset ) ; #if 0 if( THD_is_file(DSET_HEADNAME(tset)) ) ERROR_exit("-ssave dataset already exists"); #endif tross_Copy_History( tset , dset ) ; tross_Make_History( "3dDespike" , argc , argv , tset ) ; for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( tset , iv , MRI_byte , NULL ) ; } /*-- setup to find spikes --*/ sq2p = sqrt(0.5*PI) ; sfac = sq2p / 1.4826f ; /* make ref functions */ nref = 2*corder+3 ; ref = (float **) malloc( sizeof(float *) * nref ) ; for( jj=0 ; jj < nref ; jj++ ) ref[jj] = (float *) malloc( sizeof(float) * nuse ) ; /* r(t) = 1 */ for( iv=0 ; iv < nuse ; iv++ ) ref[0][iv] = 1.0 ; jj = 1 ; /* r(t) = t - tmid */ { float tm = 0.5 * (nuse-1.0) ; float fac = 2.0 / nuse ; for( iv=0 ; iv < nuse ; iv++ ) ref[1][iv] = (iv-tm)*fac ; jj = 2 ; /* r(t) = (t-tmid)**jj */ for( ; jj <= polort ; jj++ ) for( iv=0 ; iv < nuse ; iv++ ) ref[jj][iv] = pow( (iv-tm)*fac , (double)jj ) ; } for( kk=1 ; kk <= corder ; kk++ ){ fq = (2.0*PI*kk)/nuse ; /* r(t) = sin(2*PI*k*t/N) */ for( iv=0 ; iv < nuse ; iv++ ) ref[jj][iv] = sin(fq*iv) ; jj++ ; /* r(t) = cos(2*PI*k*t/N) */ for( iv=0 ; iv < nuse ; iv++ ) ref[jj][iv] = cos(fq*iv) ; jj++ ; } /****** setup for the NEW solution method [29 Nov 2013] ******/ if( do_NEW ){ NEW_psinv = DES_get_psinv(nuse,nref,ref) ; INFO_message("Procesing time series with NEW model fit algorithm") ; } else { INFO_message("Procesing time series with OLD model fit algorithm") ; } /*--- loop over voxels and do work ---*/ #define Laplace_t2p(val) ( 1.0 - nifti_stat2cdf( (val), 15, 0.0, 1.4427 , 0.0 ) ) if( verb ){ if( !localedit ){ INFO_message("smash edit thresholds: %.1f .. %.1f MADs",cut1*sq2p,cut2*sq2p) ; ININFO_message(" [ %.3f%% .. %.3f%% of normal distribution]", 200.0*qg(cut1*sfac) , 200.0*qg(cut2*sfac) ) ; ININFO_message(" [ %.3f%% .. %.3f%% of Laplace distribution]" , 100.0*Laplace_t2p(cut1) , 100.0*Laplace_t2p(cut2) ) ; } else { INFO_message("local edit threshold: %.1f MADS",cut2*sq2p) ; ININFO_message(" [ %.3f%% of normal distribution]", 200.0*qg(cut2*sfac) ) ; ININFO_message(" [ %.3f%% of Laplace distribution]", 100.0*Laplace_t2p(cut1) ) ; } INFO_message("%d slices to process",DSET_NZ(dset)) ; } kzold = -1 ; nspike = 0 ; nbig = 0 ; nproc = 0 ; ctim = NI_clock_time() ; AFNI_OMP_START ; #pragma omp parallel if( nxyz > 6666 ) { int ii , iv , iu , id , jj ; float *far , *dar , *var , *fitar , *ssp , *fit , *zar ; short *sar , *qar ; byte *tar ; float fsig , fq , cls , snew , val ; float *NEW_wks=NULL ; #pragma omp critical (DESPIKE_malloc) { far = (float *) malloc( sizeof(float) * nvals ) ; dar = (float *) malloc( sizeof(float) * nvals ) ; var = (float *) malloc( sizeof(float) * nvals ) ; fitar = (float *) malloc( sizeof(float) * nvals ) ; ssp = (float *) malloc( sizeof(float) * nvals ) ; fit = (float *) malloc( sizeof(float) * nref ) ; if( do_NEW ) NEW_wks = (float *)malloc(sizeof(float)*DES_workspace_size(nuse,nref)) ; } #ifdef USE_OMP INFO_message("start OpenMP thread #%d",omp_get_thread_num()) ; #endif #pragma omp for for( ii=0 ; ii < nxyz ; ii++ ){ /* ii = voxel index */ if( mask != NULL && mask[ii] == 0 ) continue ; /* skip this voxel */ #ifndef USE_OMP kz = DSET_index_to_kz(dset,ii) ; /* starting a new slice */ if( kz != kzold ){ if( verb ){ fprintf(stderr, "++ start slice %2d",kz ) ; if( nproc > 0 ){ pspike = (100.0*nspike)/nproc ; pbig = (100.0*nbig )/nproc ; fprintf(stderr, "; so far %d data points, %d edits [%.3f%%], %d big edits [%.3f%%]", nproc,nspike,pspike,nbig,pbig ) ; } fprintf(stderr,"\n") ; } kzold = kz ; } #else if( verb && ii % 2345 == 1234 ) fprintf(stderr,".") ; #endif /*** extract ii-th time series into far[] ***/ switch( datum ){ case MRI_short: for( iv=0 ; iv < nuse ; iv++ ){ qar = DSET_ARRAY(dset,iv+ignore) ; /* skip ignored data */ far[iv] = (float)qar[ii] ; } break ; case MRI_float: for( iv=0 ; iv < nuse ; iv++ ){ zar = DSET_ARRAY(dset,iv+ignore) ; far[iv] = zar[ii] ; } break ; } AAmemcpy(dar,far,sizeof(float)*nuse) ; /* copy time series into dar[] */ /*** solve for L1 fit ***/ if( do_NEW ) cls = DES_solve( NEW_psinv , far , fit , NEW_wks ) ; /* 29 Nov 2013 */ else cls = cl1_solve( nuse , nref , far , ref , fit,0 ) ; /* the slow part */ if( cls < 0.0f ){ /* fit failed! */ #if 0 fprintf(stderr,"curve fit fails at voxel %d %d %d\n", DSET_index_to_ix(dset,ii) , DSET_index_to_jy(dset,ii) , DSET_index_to_kz(dset,ii) ) ; #endif continue ; /* skip this voxel */ } for( iv=0 ; iv < nuse ; iv++ ){ /* detrend */ val = fit[0] + fit[1]*ref[1][iv] /* quadratic part of curve fit */ + fit[2]*ref[2][iv] ; for( jj=3 ; jj < nref ; jj++ ) /* rest of curve fit */ val += fit[jj] * ref[jj][iv] ; fitar[iv] = val ; /* save curve fit value */ var[iv] = dar[iv]-val ; /* remove fitted value = resid */ far[iv] = fabsf(var[iv]) ; /* abs value of resid */ } /*** compute estimate standard deviation of detrended data ***/ fsig = sq2p * qmed_float(nuse,far) ; /* also mangles far array */ /*** process time series for spikes, editing data in dar[] ***/ if( fsig > 0.0f ){ /* data wasn't fit perfectly */ /* find spikiness for each point in time */ fq = 1.0f / fsig ; for( iv=0 ; iv < nuse ; iv++ ){ ssp[iv] = fq * var[iv] ; /* spikiness s = how many sigma out */ } /* save spikiness in -ssave datset */ if( tset != NULL ){ for( iv=0 ; iv < nuse ; iv++ ){ tar = DSET_ARRAY(tset,iv+ignore) ; snew = ITFAC*fabsf(ssp[iv]) ; /* scale for byte storage */ tar[ii] = BYTEIZE(snew) ; /* cf. mrilib.h */ } } /* process values of |s| > cut1, editing dar[] */ for( iv=0 ; iv < nuse ; iv++ ){ /* loop over time points */ if( !localedit ){ /** classic 'smash' edit **/ if( ssp[iv] > cut1 ){ snew = cut1 + c21*mytanh((ssp[iv]-cut1)*ic21) ; /* edit s down */ dar[iv] = fitar[iv] + snew*fsig ; #pragma omp critical (DESPIKE_counter) { nspike++ ; if( ssp[iv] > cut2 ) nbig++ ; } } else if( ssp[iv] < -cut1 ){ snew = -cut1 + c21*mytanh((ssp[iv]+cut1)*ic21) ; /* edit s up */ dar[iv] = fitar[iv] + snew*fsig ; #pragma omp critical (DESPIKE_counter) { nspike++ ; if( ssp[iv] < -cut2 ) nbig++ ; } } } else { /** local edit: 04 Apr 2007 **/ if( ssp[iv] >= cut2 || ssp[iv] <= -cut2 ){ for( iu=iv+1 ; iu < nuse ; iu++ ) /* find non-spike above */ if( ssp[iu] < cut2 && ssp[iu] > -cut2 ) break ; for( id=iv-1 ; id >= 0 ; id-- ) /* find non-spike below */ if( ssp[id] < cut2 && ssp[id] > -cut2 ) break ; switch( (id>=0) + 2*(iu<nuse) ){ /* compute replacement val */ case 3: val = 0.5*(dar[iu]+dar[id]); break; /* iu and id OK */ case 2: val = dar[iu] ; break; /* only iu OK */ case 1: val = dar[id] ; break; /* only id OK */ default: val = fitar[iv] ; break; /* shouldn't be */ } dar[iv] = val ; #pragma omp critical (DESPIKE_counter) { nspike++ ; nbig++ ; } } } } /* end of loop over time points */ #pragma omp atomic nproc += nuse ; /* number data points processed */ } /* end of processing time series when fsig is positive */ /* put dar[] time series (possibly edited above) into output bricks */ switch( datum ){ case MRI_short: for( iv=0 ; iv < nuse ; iv++ ){ sar = DSET_ARRAY(oset,iv+ignore) ; /* output brick */ sar[ii] = (short)dar[iv] ; /* original or mutated data */ } break ; case MRI_float: for( iv=0 ; iv < nuse ; iv++ ){ zar = DSET_ARRAY(oset,iv+ignore) ; /* output brick */ zar[ii] = dar[iv] ; /* original or mutated data */ } break ; } } /* end of loop over voxels #ii */ #pragma omp critical (DESPIKE_malloc) { free(fit); free(ssp); free(fitar); free(var); free(dar); free(far); if( do_NEW ) free(NEW_wks) ; } } /* end OpenMP */ AFNI_OMP_END ; #ifdef USE_OMP if( verb ) fprintf(stderr,"\n") ; #endif ctim = NI_clock_time() - ctim ; INFO_message( "Elapsed despike time = %s" , nice_time_string(ctim) ) ; if( ctim > 345678 && !do_NEW ) ININFO_message("That was SLOW -- try the '-NEW' option for a speedup") ; #ifdef USE_OMP if( verb ) fprintf(stderr,"\n") ; #endif /*--- finish up ---*/ if( do_NEW ) mri_free(NEW_psinv) ; DSET_delete(dset) ; /* delete input dataset */ if( verb ){ if( nproc > 0 ){ pspike = (100.0*nspike)/nproc ; pbig = (100.0*nbig )/nproc ; INFO_message("FINAL: %d data points, %d edits [%.3f%%], %d big edits [%.3f%%]", nproc,nspike,pspike,nbig,pbig ) ; } else { INFO_message("FINAL: no good voxels found to process!!??") ; } } /* write results */ DSET_write(oset) ; if( verb ) WROTE_DSET(oset) ; DSET_delete(oset) ; if( tset != NULL ){ DSET_write(tset) ; if( verb ) WROTE_DSET(tset) ; DSET_delete(tset) ; } exit( THD_get_write_error_count() ) ; }
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) ; }
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 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[] ) { 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 iarg=1 , ii , do_iwarp=0 ; char *prefix = "NwarpCat" ; mat44 wmat , smat , qmat ; THD_3dim_dataset *oset=NULL ; char *cwarp_all=NULL ; int ntot=0 ; AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ) NWC_help() ; /*-- bureaucracy --*/ mainENTRY("3dNwarpCat"); machdep(); AFNI_logger("3dNwarpCat",argc,argv); PRINT_VERSION("3dNwarpCat"); AUTHOR("Zhark the Warper"); (void)COX_clock_time() ; putenv("AFNI_WSINC5_SILENT=YES") ; /*-- initialization --*/ CW_no_expad = 1 ; /* don't allow automatic padding of input warp */ Hverb = 0 ; /* don't be verbose inside mri_nwarp.c */ for( ii=0 ; ii < NWMAX ; ii++ ) cwarp[ii] = NULL ; /*-- scan args --*/ while( iarg < argc && argv[iarg][0] == '-' ){ /*---------------*/ if( strcasecmp(argv[iarg],"-iwarp") == 0 ){ do_iwarp = 1 ; iarg++ ; continue ; } /*---------------*/ if( strcasecmp(argv[iarg],"-space") == 0 ){ sname = strdup(argv[++iarg]) ; iarg++ ; continue ; } /*---------------*/ if( strcasecmp(argv[iarg],"-NN") == 0 || strncasecmp(argv[iarg],"-nearest",6) == 0 ){ WARNING_message("NN interpolation not legal here -- switched to linear") ; interp_code = MRI_LINEAR ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-linear",4)==0 || strncasecmp(argv[iarg],"-trilinear",6)==0 ){ interp_code = MRI_LINEAR ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-cubic",4)==0 || strncasecmp(argv[iarg],"-tricubic",6)==0 ){ WARNING_message("cubic interplation not legal here -- switched to quintic") ; interp_code = MRI_QUINTIC ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-quintic",4)==0 || strncasecmp(argv[iarg],"-triquintic",6)==0 ){ interp_code = MRI_QUINTIC ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-wsinc",5) == 0 ){ interp_code = MRI_WSINC5 ; iarg++ ; continue ; } /*---------------*/ if( strcasecmp(argv[iarg],"-expad") == 0 ){ int expad ; if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ; expad = (int)strtod(argv[iarg],NULL) ; if( expad < 0 ){ WARNING_message("-expad %d is illegal and is set to zero",expad) ; expad = 0 ; } CW_extra_pad = expad ; /* this is how we force extra padding */ iarg++ ; continue ; } /*---------------*/ if( strncasecmp(argv[iarg],"-interp",5)==0 ){ char *inam ; if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ; inam = argv[iarg] ; if( *inam == '-' ) inam++ ; if( strcasecmp(inam,"NN")==0 || strncasecmp(inam,"nearest",5)==0 ){ WARNING_message("NN interpolation not legal here -- changed to linear") ; interp_code = MRI_LINEAR ; } else if( strncasecmp(inam,"linear",3)==0 || strncasecmp(inam,"trilinear",5)==0 ){ interp_code = MRI_LINEAR ; } else if( strncasecmp(inam,"cubic",3)==0 || strncasecmp(inam,"tricubic",5)==0 ){ WARNING_message("cubic interplation not legal here -- changed to quintic") ; interp_code = MRI_QUINTIC ; } else if( strncasecmp(inam,"quintic",3)==0 || strncasecmp(inam,"triquintic",5)==0 ){ interp_code = MRI_QUINTIC ; } else if( strncasecmp(inam,"wsinc",4)==0 ){ interp_code = MRI_WSINC5 ; } else { ERROR_exit("Unknown code '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ; } iarg++ ; continue ; } /*---------------*/ if( strcasecmp(argv[iarg],"-verb") == 0 ){ verb++ ; NwarpCalcRPN_verb(verb) ; iarg++ ; continue ; } /*---------------*/ if( strcasecmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ; prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal name after '%s'",argv[iarg-1]) ; iarg++ ; continue ; } /*---------------*/ if( strncasecmp(argv[iarg],"-warp",5) == 0 ){ int nn ; if( iarg >= argc-1 ) ERROR_exit("no argument after '%s' :-(",argv[iarg]) ; if( !isdigit(argv[iarg][5]) ) ERROR_exit("illegal format for '%s' :-(",argv[iarg]) ; nn = (int)strtod(argv[iarg]+5,NULL) ; if( nn <= 0 || nn > NWMAX ) ERROR_exit("illegal warp index in '%s' :-(",argv[iarg]) ; if( cwarp[nn-1] != NULL ) ERROR_exit("'%s': you can't specify warp #%d more than once :-(",argv[iarg],nn) ; cwarp[nn-1] = strdup(argv[++iarg]) ; if( nn > nwtop ) nwtop = nn ; iarg++ ; continue ; } /*---------------*/ ERROR_message("Confusingly Unknown option '%s' :-(",argv[iarg]) ; suggest_best_prog_option(argv[0],argv[iarg]) ; exit(1) ; } /*-- load any warps left on the command line, after options --*/ for( ; iarg < argc && nwtop < NWMAX-1 ; iarg++ ) cwarp[nwtop++] = strdup(argv[iarg]) ; /*-- check if all warp strings are affine matrices --*/ #undef AFFINE_WARP_STRING #define AFFINE_WARP_STRING(ss) \ ( strstr((ss)," ") == NULL && \ ( strcasestr((ss),".1D") != NULL || strcasestr((ss),".txt") != NULL ) ) for( ntot=ii=0 ; ii < nwtop ; ii++ ){ if( cwarp[ii] == NULL ) continue ; ntot += strlen(cwarp[ii]) ; if( ! AFFINE_WARP_STRING(cwarp[ii]) ) break ; /* not affine */ } if( ntot == 0 ) ERROR_exit("No warps on command line?!") ; if( ii == nwtop ){ /* all are affine (this is for Ziad) */ char *fname = malloc(sizeof(char)*(strlen(prefix)+16)) ; FILE *fp ; float a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34 ; LOAD_IDENT_MAT44(wmat) ; for( ii=0 ; ii < nwtop ; ii++ ){ if( cwarp[ii] == NULL ) continue ; smat = CW_read_affine_warp_OLD(cwarp[ii]) ; qmat = MAT44_MUL(smat,wmat) ; wmat = qmat ; } if( strcmp(prefix,"-") == 0 || strncmp(prefix,"stdout",6) == 0 ){ fp = stdout ; strcpy(fname,"stdout") ; } else { strcpy(fname,prefix) ; if( strstr(fname,".1D") == NULL ) strcat(fname,".aff12.1D") ; fp = fopen(fname,"w") ; if( fp == NULL ) ERROR_exit("Can't open output matrix file %s",fname) ; } if( do_iwarp ){ qmat = MAT44_INV(wmat) ; wmat = qmat ; } UNLOAD_MAT44(wmat,a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34) ; fprintf(fp, " %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g\n", a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34 ) ; if( verb && fp != stdout ) INFO_message("Wrote matrix to %s",fname) ; if( fp != stdout ) fclose(fp) ; exit(0) ; } /*** at least one nonlinear warp ==> cat all strings, use library function to read ***/ cwarp_all = (char *)calloc(sizeof(char),(ntot+NWMAX)*2) ; for( ii=0 ; ii < nwtop ; ii++ ){ if( cwarp[ii] != NULL ){ strcat(cwarp_all,cwarp[ii]) ; strcat(cwarp_all," ") ; } } oset = IW3D_read_catenated_warp( cwarp_all ) ; /* process all of them at once */ if( do_iwarp ){ /* 18 Jul 2014 */ THD_3dim_dataset *qwarp ; if( verb ) fprintf(stderr,"Applying -iwarp option") ; qwarp = THD_nwarp_invert(oset) ; DSET_delete(oset) ; oset = qwarp ; if( verb ) fprintf(stderr,"\n") ; } tross_Make_History( "3dNwarpCat" , argc,argv , oset ) ; if( sname != NULL ) MCW_strncpy( oset->atlas_space , sname , THD_MAX_NAME ) ; EDIT_dset_items( oset , ADN_prefix,prefix , ADN_none ) ; DSET_write(oset) ; WROTE_DSET(oset) ; /*--- run away screaming into the night, never to be seen again ---*/ INFO_message("total CPU time = %.1f sec Elapsed = %.1f\n", COX_cpu_time() , COX_clock_time() ) ; 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[] ) { 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[] ) { 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) ; }
/*! Replace a voxel's value by the value's rank in the entire set of input datasets */ int main( int argc , char * argv[] ) { THD_3dim_dataset ** dsets_in = NULL, *dset=NULL; /*input and output datasets*/ int nopt=0, nbriks=0, nsubbriks=0, ib=0, isb=0; byte *cmask=NULL; int *all_uniques=NULL, **uniques=NULL, *final_unq=NULL, *N_uniques=NULL; int N_final_unq=0, iun=0, total_unq=0; INT_HASH_DATUM *rmap=NULL, *hd=NULL; int imax=0, iunq=0, ii=0, id = 0; long int off=0; char *prefix=NULL; char stmp[THD_MAX_PREFIX+1]={""}; FILE *fout=NULL; /*----- Read command line -----*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ Rank_help (); exit(0) ; } mainENTRY("3dRank main"); machdep(); AFNI_logger("3dRank",argc,argv); nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-ver") == 0 ){ PRINT_VERSION("3dRank"); AUTHOR("Ziad Saad"); nopt++; continue; } if( strcmp(argv[nopt],"-help") == 0 ){ Rank_help(); exit(0) ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ ++nopt; if (nopt>=argc) { fprintf(stderr,"**ERROR: Need string after -prefix\n"); exit(1); } prefix = argv[nopt] ; ++nopt; continue; } if( strcmp(argv[nopt],"-input") == 0 ){ dsets_in = (THD_3dim_dataset**) calloc(argc-nopt+1, sizeof(THD_3dim_dataset*)); ++nopt; nbriks=0; while (nopt < argc ) { dsets_in[nbriks] = THD_open_dataset( argv[nopt] ); if( !ISVALID_DSET(dsets_in[nbriks]) ){ fprintf(stderr,"**ERROR: can't open dataset %s\n",argv[nopt]) ; exit(1); } ++nopt; ++nbriks; } continue; } ERROR_exit( " Error - unknown option %s", argv[nopt]); } if (nopt < argc) { ERROR_exit( " Error unexplained trailing option: %s\n", argv[nopt]); } if (!nbriks) { ERROR_exit( " Error no volumes entered on command line?"); } /* some checks and inits*/ nsubbriks = 0; for (ib = 0; ib<nbriks; ++ib) { if (!is_integral_dset(dsets_in[ib], 0)) { ERROR_exit("Dset %s is not of an integral data type.", DSET_PREFIX(dsets_in[ib])); } nsubbriks += DSET_NVALS(dsets_in[ib]); } /* Now get unique arrays */ uniques = (int **)calloc(nsubbriks, sizeof(int*)); N_uniques = (int *)calloc(nsubbriks, sizeof(int)); total_unq = 0; iun = 0; for (ib = 0; ib<nbriks; ++ib) { DSET_mallocize(dsets_in[ib]); DSET_load(dsets_in[ib]); for (isb=0; isb<DSET_NVALS(dsets_in[ib]); ++isb) { uniques[iun] = THD_unique_vals(dsets_in[ib], isb, &(N_uniques[iun]), cmask); total_unq += N_uniques[iun]; ++iun; } } /* put all the arrays together and get the unique of the uniques */ all_uniques = (int *)calloc(total_unq, sizeof(int)); off=0; for (iun=0; iun<nsubbriks; ++iun) { memcpy(all_uniques+off, uniques[iun], N_uniques[iun]*sizeof(int)); off += N_uniques[iun]; } /* free intermediate unique arrays */ for (iun=0; iun<nsubbriks; ++iun) { free(uniques[iun]); } free(uniques); uniques=NULL; free(N_uniques); N_uniques=NULL; /* get unique of catenated array */ if (!(final_unq = UniqueInt (all_uniques, total_unq, &N_final_unq, 0 ))) { ERROR_exit( " Failed to get unique list (%d, %d, %d) ", total_unq, N_final_unq, nsubbriks); } free(all_uniques); all_uniques=NULL; if (prefix) { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "%s.rankmap.1D", prefix); } else { if (nbriks == 1) { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "%s.rankmap.1D", DSET_PREFIX(dsets_in[0])); } else { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "%s+.rankmap.1D", DSET_PREFIX(dsets_in[0])); } } if (stmp[0]) { if ((fout = fopen(stmp,"w"))) { fprintf(fout, "#Rank Map (%d unique values)\n", N_final_unq); fprintf(fout, "#Col. 0: Rank\n"); fprintf(fout, "#Col. 1: Input Dset Value\n"); } } /* get the maximum integer in the unique array */ imax = 0; for (iunq=0; iunq<N_final_unq; ++iunq) { if (final_unq[iunq] > imax) imax = final_unq[iunq]; if (fout) fprintf(fout, "%d %d\n", iunq, final_unq[iunq]); hd = (INT_HASH_DATUM*)calloc(1,sizeof(INT_HASH_DATUM)); hd->id = final_unq[iunq]; hd->index = iunq; HASH_ADD_INT(rmap, id, hd); } fclose(fout); fout=NULL; /* now cycle over all dsets and replace their voxel values with rank */ for (ib = 0; ib<nbriks; ++ib) { for (isb=0; isb<DSET_NVALS(dsets_in[ib]); ++isb) { EDIT_BRICK_LABEL( dsets_in[ib],isb, "rank" ) ; EDIT_BRICK_TO_NOSTAT( dsets_in[ib],isb ) ; EDIT_BRICK_FACTOR( dsets_in[ib],isb, 0.0);/* no factors for rank*/ switch (DSET_BRICK_TYPE(dsets_in[ib],isb) ){ default: fprintf(stderr, "** Bad dset type for unique operation.\n" "Only Byte, Short, and float dsets are allowed.\n"); break ; /* this should not happen here, so don't bother returning*/ case MRI_short:{ short *mar = (short *) DSET_ARRAY(dsets_in[ib],isb) ; if (imax > MRI_TYPE_maxval[MRI_short]) { WARNING_message("Maximum rank value of %d is\n" "than maximum value for dset datatype of %d\n", imax, MRI_TYPE_maxval[MRI_short]); } for( ii=0 ; ii < DSET_NVOX(dsets_in[ib]) ; ii++ ) if (!cmask || cmask[ii]) { id = (int)mar[ii]; HASH_FIND_INT(rmap,&id ,hd); if (hd) mar[ii] = (short)(hd->index); else ERROR_exit("** Failed to find key %d in hash table\n",id); } else mar[ii] = 0; } break ; case MRI_byte:{ byte *mar ; if (imax > MRI_TYPE_maxval[MRI_short]) { WARNING_message("Maximum rank value of %d is\n" "than maximum value for dset datatype of %d\n", imax, MRI_TYPE_maxval[MRI_byte]); } mar = (byte *) DSET_ARRAY(dsets_in[ib],isb) ; for( ii=0 ; ii < DSET_NVOX(dsets_in[ib]) ; ii++ ) if (!cmask || cmask[ii]) { id = (int)mar[ii]; HASH_FIND_INT(rmap,&id ,hd); if (hd) mar[ii] = (byte)(hd->index); else ERROR_exit("** Failed to find key %d in hash table\n",id); } else mar[ii] = 0; } break ; case MRI_float:{ float *mar = (float *) DSET_ARRAY(dsets_in[ib],isb) ; for( ii=0 ; ii < DSET_NVOX(dsets_in[ib]) ; ii++ ) if (!cmask || cmask[ii]) { id = (int)mar[ii]; /* Assuming float is integral valued */ HASH_FIND_INT(rmap,&id ,hd); if (hd) mar[ii] = (float)(hd->index); else ERROR_exit("** Failed to find key %d in hash table\n",id); } else mar[ii] = 0; } break ; } } /* update range, etc. */ THD_load_statistics(dsets_in[ib]); /* Now write the bricks */ if (prefix) { if (nbriks == 1) { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "%s", prefix); } else { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "r%02d.%s", ib, prefix); } } else { snprintf(stmp, sizeof(char)*THD_MAX_PREFIX, "rank.%s", DSET_PREFIX(dsets_in[ib])); } EDIT_dset_items( dsets_in[ib] , ADN_prefix , stmp , ADN_none ) ; /* change storage mode, this way prefix will determine format of output dset */ dsets_in[ib]->dblk->diskptr->storage_mode = STORAGE_BY_BRICK; tross_Make_History( "3dRank" , argc, argv , dsets_in[ib] ) ; if (DSET_IS_MASTERED(dsets_in[ib])) { /* THD_write_3dim_dataset won't write a mastered dude */ dset = EDIT_full_copy(dsets_in[ib],stmp); } else { dset = dsets_in[ib]; } /* New ID */ ZERO_IDCODE(dset->idcode); dset->idcode = MCW_new_idcode() ; if (!THD_write_3dim_dataset( NULL, stmp, dset,True )) { ERROR_message("Failed to write %s", stmp); exit(1); } else { WROTE_DSET(dsets_in[ib]); if (dset != dsets_in[ib]) DSET_deletepp(dset); DSET_deletepp(dsets_in[ib]); } } /* destroy hash */ while (rmap) { hd = rmap; HASH_DEL(rmap,hd); free(hd); } free(final_unq); final_unq=NULL; 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 ; 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) ; }
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 , *mask_dset=NULL ; MRI_IMAGE *fim=NULL ; float *far=NULL ; int iarg , ndset , nvox , ii , mcount=0 ; char *prefix = "rankizer" ; byte *mmm=NULL ; float brank=1.0f ; /*-- read command line arguments --*/ if( argc < 3 || strncmp(argv[1],"-help",5) == 0 ){ printf("Usage: 3dRankizer [options] dataset\n" "Output = Rank of each voxel as sorted into increasing value.\n" " - Ties get the average rank.\n" " - Not the same as 3dRank!\n" " - Only sub-brick #0 is processed at this time!\n" " - Ranks start at 1 and increase:\n" " Input = 0 3 4 4 7 9\n" " Output = 1 2 3.5 3.5 5 6\n" "Options:\n" " -brank bbb Set the 'base' rank to 'bbb' instead of 1.\n" " (You could also do this with 3dcalc.)\n" " -mask mset Means to use the dataset 'mset' as a mask:\n" " Only voxels with nonzero values in 'mset'\n" " will be used from 'dataset'. Voxels outside\n" " the mask will get rank 0.\n" " -prefix ppp Write results into float-format dataset 'ppp'\n" " Output is in float format to allow for\n" " non-integer ranks resulting from ties.\n" "\n" "Author: RW Cox [[a quick hack for his own purposes]]\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dRankizer"); mainENTRY("3dRankizer main"); machdep(); AFNI_logger("3dRankizer",argc,argv); AUTHOR("Zhark of the Ineffable Rank"); /*-- command line scan --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-brank",5) == 0 ){ if( iarg+1 >= argc ) ERROR_exit("-brank option requires a following argument!") ; brank = (float)strtod(argv[++iarg],NULL) ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mask",5) == 0 ){ if( mask_dset != NULL ) ERROR_exit("Cannot have two -mask options!") ; if( iarg+1 >= argc ) ERROR_exit("-mask option requires a following argument!") ; mask_dset = THD_open_dataset( argv[++iarg] ) ; if( mask_dset == NULL ) ERROR_exit("Cannot open mask dataset!") ; 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("Illegal value after '-prefix'") ; iarg++ ; continue ; } ERROR_exit("Unknown option: %s",argv[iarg]) ; } /* should have 1 more arg */ ndset = argc - iarg ; if( ndset < 1 ) ERROR_exit("No input dataset!?") ; else if( ndset > 1 ) WARNING_message("Too many input datasets!") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; fim = THD_extract_float_brick(0,inset) ; DSET_unload(inset) ; far = MRI_FLOAT_PTR(fim) ; nvox= DSET_NVOX(inset) ; /* make a byte mask from mask dataset */ if( mask_dset != NULL ){ if( DSET_NVOX(mask_dset) != nvox ) ERROR_exit("Input and mask datasets are not same dimensions!"); mmm = THD_makemask( mask_dset , 0 , 1.0f,-1.0f ) ; mcount = THD_countmask( nvox , mmm ) ; INFO_message("%d voxels in the mask",mcount) ; if( mcount <= 5 ) ERROR_exit("Mask is too small!") ; DSET_delete(mask_dset) ; } if( mmm == NULL ){ rank_order_float( nvox , far ) ; for( ii=0 ; ii < nvox ; ii++ ) far[ii] += brank ; } else { float fmin=far[0] ; for( ii=1 ; ii < nvox ; ii++ ) if( far[ii] < fmin ) fmin = far[ii] ; if( fmin > 0.0f ) fmin = 0.0f ; else if( fmin == 0.0f ) fmin = -1.0f ; else fmin = -2.0f*fmin-1.0f ; for( ii=0 ; ii < nvox ; ii++ ) if( !mmm[ii] ) far[ii] = fmin ; rank_order_float( nvox , far ) ; fmin = (nvox-mcount) - brank ; for( ii=0 ; ii < nvox ; ii++ ){ if( mmm[ii] ) far[ii] = far[ii] - fmin ; else far[ii] = 0.0f ; } } outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_brick_fac , NULL , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , far ) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }