/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1999-2001, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Program to automatically segment the intracranial region. File: 3dIntracranial.c Author: B. Douglas Ward Date: 04 June 1999 Mod: Corrected initialization of PDF estimation flag. Date: 06 August 1999 Mod: Added changes for incorporating History notes. Date: 09 September 1999 Mod: Interface changes for new estpdf.c Date: 28 January 2000 Mod: Added call to AFNI_logger. Date: 15 August 2001 Mod: Added option to suppress spatial smoothing of segmentation mask. Date: 03 December 2001 Mod: Set MAX_STRING_LENGTH equal to THD_MAX_NAME. Date: 02 December 2002 Mod: Convert input from MRI_byte to MRI_short if needed. Date: 05 December 2002 Mod: Modified the -help menu -- P Christidis Date: 21 July 2005 */ /*---------------------------------------------------------------------------*/ #define PROGRAM_NAME "3dIntracranial" /* name of this program */ #define PROGRAM_AUTHOR "B. D. Ward" /* program author */ #define PROGRAM_INITIAL "04 June 1999" /* date of initial program release */ #define PROGRAM_LATEST "21 July 2005" /* date of latest program revision */ /*---------------------------------------------------------------------------*/ /* Include header files. */ #include "mrilib.h" #include "Intracranial.h" /*---------------------------------------------------------------------------*/ /* Global variables and constants. */ #define USE_QUIET static char * anat_filename = NULL; /* file name for input anat dataset */ static char * prefix_filename = NULL; /* prefix name for output dataset */ static RwcBoolean write_mask = FALSE; /* flag for generate 'fim' mask */ static RwcBoolean quiet = FALSE; /* flag for suppress screen output */ static char * commandline = NULL ; /* command line for history notes */ static RwcBoolean nosmooth = FALSE; /* flag to delete spatial smoothing */ /*---------------------------------------------------------------------------*/ /* Print error message and stop. */ void SI_error (char * message) { fprintf (stderr, "\n"); fprintf (stderr, "%s Error: %s \n", PROGRAM_NAME, message); exit(1); } /*---------------------------------------------------------------------------*/ /* Include source code. */ #include "estpdf3.c" /* code for PDF estimation */ #include "Intracranial.c" /* code for intracranial segmentation */ /*---------------------------------------------------------------------------*/ /* Routine to display 3dIntracranial help menu. */ void display_help_menu() { printf ( "3dIntracranial - performs automatic segmentation of intracranial region.\n" " \n" " This program will strip the scalp and other non-brain tissue from a \n" " high-resolution T1 weighted anatomical dataset. \n" " \n" "** Nota Bene: the newer program 3dSkullStrip should also be considered \n" "** for this functionality -- it usually works better. \n" " \n" "----------------------------------------------------------------------- \n" " \n" "Usage: \n" "----- \n" " \n" "3dIntracranial \n" " -anat filename => Filename of anat dataset to be segmented \n" " \n" " [-min_val a] => Minimum voxel intensity limit \n" " Default: Internal PDF estimate for lower bound \n" " \n" " [-max_val b] => Maximum voxel intensity limit \n" " Default: Internal PDF estimate for upper bound \n" " \n" " [-min_conn m] => Minimum voxel connectivity to enter \n" " Default: m=4 \n" " \n" " [-max_conn n] => Maximum voxel connectivity to leave \n" " Default: n=2 \n" " \n" " [-nosmooth] => Suppress spatial smoothing of segmentation mask \n" " \n" " [-mask] => Generate functional image mask (complement) \n" " Default: Generate anatomical image \n" " \n" " [-quiet] => Suppress output to screen \n" " \n" " -prefix pname => Prefix name for file to contain segmented image \n" " \n" " ** NOTE **: The newer program 3dSkullStrip will probably give \n" " better segmentation results than 3dIntracranial! \n" "----------------------------------------------------------------------- \n" " \n" "Examples: \n" "-------- \n" " \n" " 3dIntracranial -anat elvis+orig -prefix elvis_strip \n" " \n" " 3dIntracranial -min_val 30 -max_val 350 -anat elvis+orig -prefix strip\n" " \n" " 3dIntracranial -nosmooth -quiet -anat elvis+orig -prefix elvis_strip \n" " \n" "----------------------------------------------------------------------- \n" ); PRINT_COMPILE_DATE ; exit(0); } /*---------------------------------------------------------------------------*/ /* Routine to get user specified input options. */ void get_options ( int argc, /* number of input arguments */ char ** argv /* array of input arguments */ ) { int nopt = 1; /* input option argument counter */ int ival; /* integer input */ float fval; /* float input */ char message[MAX_STRING_LENGTH]; /* error message */ /*----- does user request help menu? -----*/ if (argc < 2 || strncmp(argv[1], "-help", 5) == 0) display_help_menu(); /*----- add to program log -----*/ AFNI_logger (PROGRAM_NAME,argc,argv); /*----- main loop over input options -----*/ while (nopt < argc ) { /*----- -anat filename -----*/ if (strncmp(argv[nopt], "-anat", 5) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -anat "); anat_filename = malloc (sizeof(char) * MAX_STRING_LENGTH); MTEST (anat_filename); strcpy (anat_filename, argv[nopt]); anat = THD_open_dataset (anat_filename); CHECK_OPEN_ERROR(anat,anat_filename) ; DSET_load(anat) ; CHECK_LOAD_ERROR(anat) ; /** RWCox [05 Dec 2002] If input is a byte dataset, make a short copy of it. **/ if( DSET_BRICK_TYPE(anat,0) == MRI_byte ){ THD_3dim_dataset *qset ; register byte *bar ; register short *sar ; register int ii,nvox ; fprintf(stderr,"++ WARNING: converting input dataset from byte to short\n") ; qset = EDIT_empty_copy(anat) ; nvox = DSET_NVOX(anat) ; bar = (byte *) DSET_ARRAY(anat,0) ; sar = (short *)malloc(sizeof(short)*nvox) ; for( ii=0 ; ii < nvox ; ii++ ) sar[ii] = (short) bar[ii] ; EDIT_substitute_brick( qset , 0 , MRI_short , sar ) ; DSET_delete(anat) ; anat = qset ; } nopt++; continue; } /*----- -min_val a -----*/ if (strncmp(argv[nopt], "-min_val", 8) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -min_val "); sscanf (argv[nopt], "%f", &fval); if (fval < 0.0) SI_error ("illegal argument after -min_val "); min_val_float = fval; min_val_int = 0; nopt++; continue; } /*----- -max_val b -----*/ if (strncmp(argv[nopt], "-max_val", 8) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -max_val "); sscanf (argv[nopt], "%f", &fval); if (fval < 0.0) SI_error ("illegal argument after -max_val "); max_val_float = fval; max_val_int = 0; nopt++; continue; } /*----- -min_conn m -----*/ if (strncmp(argv[nopt], "-min_conn", 9) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -min_conn "); sscanf (argv[nopt], "%d", &ival); if ((ival < 1) || (ival > 7)) SI_error ("illegal argument after -min_conn "); min_conn_int = ival; nopt++; continue; } /*----- -max_conn n -----*/ if (strncmp(argv[nopt], "-max_conn", 9) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -max_conn "); sscanf (argv[nopt], "%d", &ival); if ((ival < -1) || (ival > 5)) SI_error ("illegal argument after -max_conn "); max_conn_int = ival; nopt++; continue; } /*----- -nosmooth -----*/ if (strcmp(argv[nopt], "-nosmooth") == 0) { nosmooth = TRUE; nopt++; continue; } /*----- -mask -----*/ if (strncmp(argv[nopt], "-mask", 5) == 0) { write_mask = TRUE; nopt++; continue; } /*----- -quiet -----*/ if (strncmp(argv[nopt], "-quiet", 6) == 0) { quiet = TRUE; nopt++; continue; } /*----- -prefix prefixname -----*/ if (strncmp(argv[nopt], "-prefix", 7) == 0) { nopt++; if (nopt >= argc) SI_error ("need argument after -prefix "); prefix_filename = malloc (sizeof(char) * MAX_STRING_LENGTH); MTEST (prefix_filename); strcpy (prefix_filename, argv[nopt]); nopt++; continue; } /*----- unknown command -----*/ sprintf(message,"Unrecognized command line option: %s\n", argv[nopt]); SI_error (message); } } /*---------------------------------------------------------------------------*/ /* Routine to check whether one output file already exists. */ void check_one_output_file ( char * filename /* name of output file */ ) { char message[MAX_STRING_LENGTH]; /* error message */ THD_3dim_dataset * new_dset=NULL; /* output afni data set pointer */ int ierror; /* number of errors in editing data */ /*----- make an empty copy of input dataset -----*/ new_dset = EDIT_empty_copy ( anat ); ierror = EDIT_dset_items( new_dset , ADN_prefix , filename , ADN_label1 , filename , ADN_self_name , filename , ADN_none ) ; if( ierror > 0 ) { sprintf (message, "*** %d errors in attempting to create output dataset!\n", ierror); SI_error (message); } if( THD_is_file(new_dset->dblk->diskptr->header_name) ) { sprintf (message, "Output dataset file %s already exists" "--cannot continue!\a\n", new_dset->dblk->diskptr->header_name); SI_error (message); } /*----- deallocate memory -----*/ THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ; } /*---------------------------------------------------------------------------*/ /* Program initialization. */ void initialize_program ( int argc, /* number of input arguments */ char ** argv /* array of input arguments */ ) { float parameters [DIMENSION]; /* parameters for PDF estimation */ int nxyz; short * sfim; int ixyz, icount; short * rfim; int lower_cutoff = 25; /*----- save command line for history notes -----*/ commandline = tross_commandline( PROGRAM_NAME , argc,argv ) ; /*----- Get operator inputs -----*/ get_options (argc, argv); /*----- Verify that inputs are acceptable -----*/ verify_inputs(); /*----- Initialize local variables -----*/ if (anat == NULL) SI_error ("Unable to read anat dataset"); nxyz = DSET_NX(anat) * DSET_NY(anat) * DSET_NZ(anat); sfim = (short *) DSET_BRICK_ARRAY(anat,0) ; if (sfim == NULL) SI_error ("Unable to read anat dataset"); rfim = (short *) malloc (sizeof(short) * nxyz); MTEST (rfim); /*----- Just use voxels whose intensity is above the lower cutoff -----*/ icount = 0; for (ixyz = 0; ixyz < nxyz; ixyz++) if (sfim[ixyz] > lower_cutoff) { rfim[icount] = sfim[ixyz]; icount++; } if (! quiet) printf ("%d voxels above lower cutoff = %d \n", icount, lower_cutoff); /*----- Get PDF estimate and set voxel intensity limits -----*/ if (min_val_int || max_val_int) estpdf_short (icount, rfim, parameters); if (min_val_int) min_val_float = parameters[4] - 2.0*parameters[5]; if (max_val_int) max_val_float = parameters[7] + 2.0*parameters[8]; if (! quiet) { printf ("\n"); printf ("Control inputs: \n"); printf ("anat filename = %s \n", anat_filename); printf ("min value = %f \n", min_val_float); printf ("max value = %f \n", max_val_float); printf ("min conn = %d \n", min_conn_int); printf ("max conn = %d \n", max_conn_int); printf ("prefix filename = %s \n", prefix_filename); } } /*---------------------------------------------------------------------------*/ /* Perform initialization for automatic segmentation algorithm. */ int auto_initialize (short ** cv) { int nx, ny, nz, nxy, nxyz, ixyz; /* voxel counters */ /*----- Initialize local variables -----*/ nx = DSET_NX(anat); ny = DSET_NY(anat); nz = DSET_NZ(anat); nxy = nx*ny; nxyz = nxy*nz; /*----- Initialize voxel classification indicators -----*/ *cv = (short *) malloc (nxyz * sizeof(short)); MTEST (*cv); for (ixyz = 0; ixyz < nxyz; ixyz++) (*cv)[ixyz] = 0; /*----- Initialize random number generator -----*/ srand48 (1234567); return (1); } /*---------------------------------------------------------------------------*/ /* Put estimated target structure into output dataset. */ void target_into_dataset ( short * cv /* volume with 1's at target voxel locations */ ) { short * anat_data = NULL; /* data from anatomical image */ int nx, ny, nz, nxy, nxyz, ixyz; /* voxel counters */ /*----- Initialize local variables -----*/ anat_data = (short *) DSET_BRICK_ARRAY(anat,0) ; nx = DSET_NX(anat); ny = DSET_NY(anat); nz = DSET_NZ(anat); nxy = nx*ny; nxyz = nxy*nz; if (! write_mask) { /*----- Reset to zero those voxels which lie outside the brain -----*/ for (ixyz = 0; ixyz < nxyz; ixyz++) { if (cv[ixyz]) cv[ixyz] = 0; else cv[ixyz] = anat_data[ixyz]; } } /*----- deallocate memory -----*/ THD_delete_3dim_dataset (anat, False); anat = NULL; return; } /*---------------------------------------------------------------------------*/ /* Routine to write one AFNI dataset. The output is either a segmented anatomical dataset, or a mask 'fim' type dataset. */ void write_afni_data ( short * cv /* volume with 1's at target voxel locations */ ) { int nxyz; /* number of voxels */ int ii; /* voxel index */ THD_3dim_dataset * dset=NULL; /* input afni data set pointer */ THD_3dim_dataset * new_dset=NULL; /* output afni data set pointer */ int ierror; /* number of errors in editing data */ int ibuf[32]; /* integer buffer */ float fbuf[MAX_STAT_AUX]; /* float buffer */ float fimfac; /* scale factor for short data */ int output_datum; /* data type for output data */ char * filename; /* prefix filename for output */ /*----- initialize local variables -----*/ filename = prefix_filename; dset = THD_open_dataset (anat_filename); CHECK_OPEN_ERROR(dset,anat_filename); nxyz = DSET_NX(dset) * DSET_NY(dset) * DSET_NZ(dset); /*-- make an empty copy of this dataset, for eventual output --*/ new_dset = EDIT_empty_copy( dset ) ; /*----- Record history of dataset -----*/ tross_Copy_History( dset , new_dset ) ; if( commandline != NULL ) tross_Append_History( new_dset , commandline ) ; /*----- deallocate memory -----*/ THD_delete_3dim_dataset (dset, False); dset = NULL ; output_datum = MRI_short ; ibuf[0] = output_datum ; if (write_mask) { int func_type = FUNC_FIM_TYPE; ierror = EDIT_dset_items( new_dset , ADN_prefix , filename , ADN_label1 , filename , ADN_self_name , filename , ADN_type , ISHEAD(dset) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_func_type , func_type , ADN_nvals , FUNC_nvals[func_type] , ADN_datum_array , ibuf , ADN_malloc_type, DATABLOCK_MEM_MALLOC , ADN_none ) ; } else { ierror = EDIT_dset_items( new_dset , ADN_prefix , filename , ADN_label1 , filename , ADN_self_name , filename , ADN_datum_array , ibuf , ADN_malloc_type, DATABLOCK_MEM_MALLOC , ADN_none ) ; } if( ierror > 0 ){ fprintf(stderr, "*** %d errors in attempting to create output dataset!\n", ierror ) ; exit(1) ; } if( THD_deathcon() && THD_is_file(new_dset->dblk->diskptr->header_name) ){ fprintf(stderr, "*** Output dataset file %s already exists--cannot continue!\a\n", new_dset->dblk->diskptr->header_name ) ; exit(1) ; } /*----- attach bricks to new data set -----*/ mri_fix_data_pointer (cv, DSET_BRICK(new_dset,0)); fimfac = 1.0; /*----- write afni data set -----*/ if (! quiet) { if (write_mask) printf("\nWriting functional (mask) dataset: "); else printf ("\nWriting anatomical dataset: "); printf("%s\n", DSET_BRIKNAME(new_dset) ) ; } printf("NOTE: You will probably get better results by using\n" " 3dSkullStrip -input %s -prefix %s\n" , anat_filename , prefix_filename ) ; for( ii=0 ; ii < MAX_STAT_AUX ; ii++ ) fbuf[ii] = 0.0 ; (void) EDIT_dset_items( new_dset , ADN_stat_aux , fbuf , ADN_none ) ; fbuf[0] = (output_datum == MRI_short && fimfac != 1.0 ) ? fimfac : 0.0 ; (void) EDIT_dset_items( new_dset , ADN_brick_fac , fbuf , ADN_none ) ; THD_load_statistics( new_dset ) ; THD_write_3dim_dataset( NULL,NULL , new_dset , True ) ; /*----- deallocate memory -----*/ THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ; } /*---------------------------------------------------------------------------*/ /* Perform automatic image segmentation. */ void SEGMENT_auto () { short * cv = NULL; /* volume with 1's at target voxel locations */ int ok; /* binary, for successful operation */ /*----- Perform initialization for automatic segmentation algorithm -----*/ ok = auto_initialize (&cv); if (! ok) return; /*----- Segment intracranial voxels -----*/ segment_volume (cv); /*----- Perform voxel connectivity tests -----*/ connectivity_tests (cv); /*----- Put estimated target structure into output dataset -----*/ target_into_dataset (cv); /*----- Write out the segmented dataset -----*/ write_afni_data (cv); return ; } /*---------------------------------------------------------------------------*/ /* This is the main routine for program 3dIntracranial. */ int main ( int argc, /* number of input arguments */ char ** argv /* array of input arguments */ ) { int ii ; /*----- Identify software -----*/ #if 0 for( ii=1 ; ii < argc ; ii++ ) if( strncmp(argv[ii],"-quiet",6) == 0 ) break ; if( ii == argc ){ printf ("\n\n"); printf ("Program: %s \n", PROGRAM_NAME); printf ("Author: %s \n", PROGRAM_AUTHOR); printf ("Initial Release: %s \n", PROGRAM_INITIAL); printf ("Latest Revision: %s \n", PROGRAM_LATEST); printf ("\n"); } #endif mainENTRY("3dIntracranial:main") ; machdep() ; PRINT_VERSION("3dIntracranial") ; AUTHOR(PROGRAM_AUTHOR) ; WARNING_message("This program (3dIntracranial) is old, obsolete, and not maintained!") ; INFO_message("3dSkullStrip is almost always superior to 3dIntracranial :)") ; /*----- Program initialization -----*/ initialize_program (argc, argv); /*----- Perform automatic segmentation -----*/ SEGMENT_auto(); exit(0); } /*---------------------------------------------------------------------------*/