/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /* This program generates a histogram for the input AFNI dataset. Mod: 2 June 1997 Added option to generate histogram for only those voxels which are above the operator specified threshold value. Mod: 5 Dec 2000, by Vinai Roopchansingh, to include -mask option Mod: 16 Feb 2005, RWCox: remove threshold stuff, and add -doall. Mod: 19 May 2005, dglen: added -min/-max options Mod: 15 Dec 2005, rickr: fixed use of sub-brick factors Mod: 28 Apr 2006, rickr: fixed min/max range setting kk outside array */ #include #include #include #include "mrilib.h" #include "thd_ttatlas_query.h" static EDIT_options HI_edopt ; #define NBIN_SPECIAL 65536 #define BIG_NUMBER 9.999e+37 static int HI_nopt ; static int HI_nbin = 100 ; static int HI_log = 0 ; static int HI_dind = -1 ; /* 23 Sep 1998 */ static int HI_nomit = 0 ; static float * HI_omit = NULL ; static int HI_notit = 0 ; static int HI_doall = 0 ; /* 16 Feb 2005 */ static byte * HI_mask = NULL ; static int HI_mask_nvox = 0 ; static int HI_mask_hits = 0 ; static double HI_min = BIG_NUMBER; static double HI_max = -BIG_NUMBER; static char * HI_unq = NULL; #define KEEP(x) ( (HI_nomit==0) ? 1 : \ (HI_nomit==1) ? ((x) != HI_omit[0]) : HI_keep(x) ) void HI_read_opts( int , char ** ) ; #define HI_syntax(str) \ do{ fprintf(stderr,"\n** ERROR: %s\a\n",str) ; exit(1) ; } while(0) /*---------------------------------------------------------------------------------*/ int HI_keep(float x) /* check if value x is in the omitted list */ { register int ii ; for( ii=0 ; ii < HI_nomit ; ii++ ) if( x == HI_omit[ii] ) return 0 ; return 1 ; } /*---------------------------------------------------------------------------------*/ int main( int argc , char * argv[] ) { int iarg ; THD_3dim_dataset *dset ; int nx,ny,nz , nxyz , ii , kk , nopt , nbin ; float fbot , ftop ; int ibot , itop , has_fac; /* to deal with multiple short sub-bricks */ int *fbin=NULL , *tbin=NULL ; float df , dfi ; float fval ; float fimfac; int iv_fim, fim_type; byte *bfim = NULL ; short *sfim = NULL ; float *ffim = NULL ; void *vfim = NULL ; long cumfbin, cumtbin; int iv_bot , iv_top ; float vbot , vtop ; FILE *fout = NULL; int n_unq=0; if( argc < 2 || strncmp(argv[1],"-help",4) == 0 ){ printf("Compute histogram of 3D Dataset\n" "Usage: 3dhistog [editing options] [histogram options] dataset\n" "\n" "The editing options are the same as in 3dmerge\n" " (i.e., the options starting with '-1').\n" "\n" "The histogram options are:\n" " -nbin # Means to use '#' bins [default=100]\n" " Special Case: for short or byte dataset bricks,\n" " set '#' to zero to have the number\n" " of bins set by the brick range.\n" " -dind i Means to take data from sub-brick #i, rather than #0\n" " -omit x Means to omit the value 'x' from the count;\n" " -omit can be used more than once to skip multiple values.\n" " -mask m Means to use dataset 'm' to determine which voxels to use\n" " -doall Means to include all sub-bricks in the calculation;\n" " otherwise, only sub-brick #0 (or that from -dind) is used.\n" " -notit Means to leave the title line off the output.\n" " -log10 Output log10() of the counts, instead of the count values.\n" " -min x Means specify minimum of histogram.\n" " -max x Means specify maximum of histogram.\n" " -unq U.1D Writes out the sorted unique values to file U.1D.\n" " This option is not allowed for float data\n" " If you have a problem with this, write\n" " Ziad S. Saad (saadz@mail.nih.gov)\n" "\n" "The histogram is written to stdout. Use redirection '>' if you\n" "want to save it to a file. The format is a title line, then\n" "three numbers printed per line:\n" " bottom-of-interval count-in-interval cumulative-count\n" "\n" "-- by RW Cox (V Roopchansingh added the -mask option)\n" ) ; printf("\n" MASTER_SHORTHELP_STRING ) ; exit(0) ; } HI_read_opts( argc , argv ) ; nopt = HI_nopt ; if( nopt >= argc ) HI_syntax("no dset argument?") ; fbin = (int *) calloc( sizeof(int) , HI_nbin ) ; if( fbin == NULL ) HI_syntax("can't allocate histogram array!") ; iarg = nopt ; dset = THD_open_dataset( argv[iarg] ) ; if( dset == NULL ){ fprintf(stderr,"** ERROR: Can't open dataset %s\n",argv[iarg]) ; exit(1) ; } if( (HI_mask_nvox > 0) && (HI_mask_nvox != DSET_NVOX(dset)) ) HI_syntax("mask and input dataset bricks don't match in size!") ; DSET_mallocize( dset ) ; DSET_load( dset ) ; CHECK_LOAD_ERROR(dset) ; EDIT_one_dataset( dset , &HI_edopt ) ; /* edit value in memory */ nx = dset->daxes->nxx ; ny = dset->daxes->nyy ; nz = dset->daxes->nzz ; nxyz = nx * ny * nz ; if( HI_doall ){ iv_bot = 0 ; iv_top = DSET_NVALS(dset)-1 ; if( !THD_datum_constant(dset->dblk) ){ fprintf(stderr, "** ERROR: Dataset %s doesn't have same datum type in all sub-bricks!\n", argv[iarg]) ; exit(1) ; } } else { iv_bot = (HI_dind >= 0) ? HI_dind : DSET_IS_MASTERED(dset) ? 0 : DSET_PRINCIPAL_VALUE(dset) ; iv_top = iv_bot ; if( iv_bot < 0 || iv_bot >= DSET_NVALS(dset) ){ fprintf(stderr,"*** Sub-brick index %d out of range for dataset %s\n", iv_bot , argv[iarg] ) ; exit(1) ; } } fim_type = DSET_BRICK_TYPE(dset,iv_bot) ; /* find global min and max of data in all used bricks */ fbot = BIG_NUMBER ; ftop = -fbot ; itop = -32768 ; ibot = 32767 ; has_fac = 0 ; for( iv_fim=iv_bot ; iv_fim <= iv_top ; iv_fim++ ){ vbot = mri_min( DSET_BRICK(dset,iv_fim) ) ; vtop = mri_max( DSET_BRICK(dset,iv_fim) ) ; fimfac = DSET_BRICK_FACTOR(dset,iv_fim) ; if (fimfac == 0.0) fimfac = 1.0; /* if short, get range before applying factor */ if( fim_type == MRI_short || fim_type == MRI_byte ){ if( fimfac != 1.0 ) has_fac = 1 ; if( vbot < ibot ) ibot = vbot ; if( vtop > itop ) itop = vtop ; } vbot *= fimfac ; vtop *= fimfac ; if( vbot < fbot ) fbot = vbot; if( vtop > ftop ) ftop = vtop; } if(HI_min != BIG_NUMBER) fbot = HI_min; if(HI_max != -BIG_NUMBER) ftop = HI_max; if( fbot >= ftop ){ fprintf(stderr,"** ERROR: all values in dataset are = %f!\n",fbot) ; exit(1) ; } switch( fim_type ){ default: fprintf(stderr,"** ERROR: can't process data of this type!\n") ; exit(1) ; case MRI_byte: case MRI_short: nbin = (int)(itop-ibot+1.0) ; /* ftop -> stop (for unscaled range) */ if( nbin > HI_nbin ) nbin = HI_nbin ; if( nbin < 2 ) nbin = 2 ; break ; case MRI_float: nbin = (HI_nbin==NBIN_SPECIAL) ? 100 : HI_nbin ; if (HI_unq) { fprintf(stderr,"** ERROR: Unique operation not allowed for float data.\n") ; exit(1) ; } break ; } df = (ftop-fbot) / (nbin-1) ; dfi = 1.0 / df ; /* loop over all bricks and accumulate histogram */ if (HI_unq) { fout = fopen(HI_unq,"r"); if (fout) { fclose(fout); fprintf(stderr,"** ERROR: Output file %s exists, will not overwrite.\n", HI_unq) ; exit(1) ; } fout = fopen(HI_unq,"w"); if (!fout) { fprintf(stderr,"** ERROR: Could not open %s for write operation.\nCheck your directory permissions\n", HI_unq) ; exit(1) ; } } if (!fout) HI_unq = NULL; /* safety valve */ for( iv_fim=iv_bot ; iv_fim <= iv_top ; iv_fim++ ){ fimfac = DSET_BRICK_FACTOR(dset,iv_fim) ; if (fimfac == 0.0) fimfac = 1.0; vfim = DSET_ARRAY(dset,iv_fim) ; switch( fim_type ){ case MRI_short:{ short *fim = (short *)vfim ; short *funq=NULL; for( ii=0 ; ii < nxyz ; ii++ ){ fval = fim[ii]*fimfac ; /* make sure we stay in range 28 Apr 2006 [rickr] */ if( (fval >= fbot && fval <= ftop) && KEEP(fval) && (HI_mask == NULL || HI_mask[ii]) ){ kk = (int)( (fval-fbot)*dfi ) ; /* use real value */ fbin[kk]++ ; } } if (HI_unq) { funq = UniqueShort(fim, nxyz, &n_unq, 0); if (!funq) { fprintf(stderr,"** ERROR: Failed to uniquate.\n") ; exit(1) ; } fprintf(fout,"# %d unique values in %s\n", n_unq, argv[iarg] ); for (ii=0; ii= fbot && fval <= ftop) && KEEP(fval) && (HI_mask == NULL || HI_mask[ii]) ){ kk = (int)( (fval-fbot)*dfi ) ; fbin[kk]++ ; } } if (HI_unq) { funq = UniqueByte(fim, nxyz, &n_unq, 0); if (!funq) { fprintf(stderr,"** ERROR: Failed to uniquate.\n") ; exit(1) ; } fprintf(fout,"# %d unique values in %s\n", n_unq, argv[iarg] ); for (ii=0; ii= fbot && fval <= ftop) && KEEP(fval) && (HI_mask == NULL || HI_mask[ii]) ){ kk = (int)( (fval-fbot)*dfi ) ; fbin[kk]++ ; } } } break ; } /* end of switch on data brick type */ DSET_unload_one(dset,iv_fim) ; } /*** print something ***/ cumfbin = 0; if( HI_log ){ if( ! HI_notit ) printf ("%12s %13s %13s\n", "#Magnitude", "Log_Freq", "Log_Cum_Freq"); for( kk=0 ; kk < nbin ; kk++ ){ cumfbin += fbin[kk]; printf ("%12.6f %13.6f %13.6f\n", fbot+kk*df, log10((double)fbin[kk]+1.0), log10((double)cumfbin+1.0)); } } else { if( ! HI_notit ) printf ("%12s %13s %13s\n", "#Magnitude", "Freq", "Cum_Freq"); for( kk=0 ; kk < nbin ; kk++ ){ cumfbin += fbin[kk]; printf ("%12.6f %13d %13ld\n", fbot+kk*df, fbin[kk], cumfbin); } } exit(0) ; } /*-------------------------------------------------------------------- read the arguments, and load the global variables ----------------------------------------------------------------------*/ #ifdef HIDEBUG # define DUMP1 fprintf(stderr,"ARG: %s\n",argv[nopt]) # define DUMP2 fprintf(stderr,"ARG: %s %s\n",argv[nopt],argv[nopt+1]) # define DUMP3 fprintf(stderr,"ARG: %s %s %s\n",argv[nopt],argv[nopt+1],argv[nopt+2]) #else # define DUMP1 # define DUMP2 # define DUMP3 #endif void HI_read_opts( int argc , char * argv[] ) { int nopt = 1 ; float val ; int ival , kk ; INIT_EDOPT( &HI_edopt ) ; HI_unq = NULL; while( nopt < argc && argv[nopt][0] == '-' ){ /**** check for editing options ****/ ival = EDIT_check_argv( argc , argv , nopt , &HI_edopt ) ; if( ival > 0 ){ nopt += ival ; continue ; } if( strncmp(argv[nopt],"-nbin",5) == 0 ){ HI_nbin = strtol( argv[++nopt] , NULL , 10 ) ; if( HI_nbin < 10 && HI_nbin != 0 ) HI_syntax("illegal value of -nbin!") ; if( HI_nbin == 0 ) HI_nbin = NBIN_SPECIAL ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-unq",4) == 0 ){ nopt++; if (nopt == argc) { HI_syntax("Need 1D filename after -unq"); } HI_unq = argv[nopt]; nopt++ ; continue ; } if( strncmp(argv[nopt],"-dind",5) == 0 ){ HI_dind = strtol( argv[++nopt] , NULL , 10 ) ; if( HI_dind < 0 ) HI_syntax("illegal value of -dind!") ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-doall",6) == 0 ){ HI_doall = 1 ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-omit",5) == 0 ){ char *cpt ; float val ; val = strtod( argv[++nopt] , &cpt ) ; if( cpt != NULL && *cpt != '\0' ) HI_syntax("illegal value of -omit!") ; HI_nomit++ ; if( HI_nomit == 1 ) HI_omit = (float *) malloc( sizeof(float) ) ; else HI_omit = (float *) realloc( HI_omit , sizeof(float)*HI_nomit ) ; HI_omit[HI_nomit-1] = val ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-notit",5) == 0 ){ HI_notit = 1 ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-log10",5) == 0 ){ HI_log = 1 ; nopt++ ; continue ; } /* ----- -mask ----- */ if( strncmp(argv[nopt],"-mask",5) == 0 ) { THD_3dim_dataset * mset ; int ii,mc ; nopt++ ; if( nopt >= argc ) HI_syntax("need argument after -mask!") ; mset = THD_open_dataset( argv[nopt] ) ; if( mset == NULL ) HI_syntax("can't open -mask dataset!") ; HI_mask = THD_makemask( mset , 0 , 1.0,0.0 ) ; if( HI_mask == NULL ) HI_syntax("can't use -mask dataset!") ; HI_mask_nvox = DSET_NVOX(mset) ; DSET_delete(mset) ; for( ii=mc=0 ; ii < HI_mask_nvox ; ii++ ) if( HI_mask[ii] ) mc++ ; if( mc == 0 ) HI_syntax("mask is all zeros!") ; fprintf(stderr,"++ %d voxels in mask\n",mc) ; HI_mask_hits = mc ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-min",4) == 0 ){ HI_min = strtod( argv[++nopt] , NULL ) ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-max",4) == 0 ){ HI_max = strtod( argv[++nopt] , NULL ) ; nopt++ ; continue ; } /**** unknown switch ****/ fprintf(stderr,"*** unrecognized option %s\a\n",argv[nopt]) ; exit(-1) ; } /* end of loop over options */ #ifdef HIDEBUG printf("*** finished with options\n") ; #endif if( HI_doall ){ if( HI_dind >= 0 ){ fprintf(stderr,"** WARNING: -dind ignored with -doall!\n") ; HI_dind = -1 ; } } HI_nopt = nopt ; return ; }