Exemple #1
0
int main( int argc , char *argv[] )
{
   THD_3dim_dataset *dset ;
   MRI_IMAGE *im ;
   int iarg=1 ;

   if( strcmp(argv[1],"-nper") == 0 ){
      nper = strtol( argv[2] , NULL , 10 ) ;
      iarg = 3 ;
   }

   for( ; iarg < argc ; iarg++ ){
     printf("======= dataset %s  nper=%d ========\n",argv[iarg],nper) ;
     dset = THD_open_dataset(argv[iarg]) ;
     if( dset == NULL ) continue ;
     DSET_load(dset) ;
     im = DSET_BRICK(dset,0) ;
     im->dx = DSET_DX(dset) ;
     im->dy = DSET_DY(dset) ;
     im->dz = DSET_DZ(dset) ;
     (void) THD_orient_guess( im ) ;

     printf( "Data Axes Orientation:\n"
             "  first  (x) = %s\n"
             "  second (y) = %s\n"
             "  third  (z) = %s\n" ,
        ORIENT_typestr[dset->daxes->xxorient] ,
        ORIENT_typestr[dset->daxes->yyorient] ,
        ORIENT_typestr[dset->daxes->zzorient]  ) ;
     DSET_delete(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) ;
}
Exemple #3
0
int main( int argc , char *argv[] )
{
   THD_3dim_dataset *dset=NULL;
   int iarg , verbose = -1 ;
   char *outbuf, *stmp=NULL;
   char *labelName = NULL;
   char *sbdelim = {"|"};
   char *NAflag = {"NA"};
   char *atrdelim = {"\t"}, *form=NULL;
   INFO_FIELDS sing[512];
   int iis=0, N_sing = 0, isb=0, withhead = 0, itmp=0;
   int ip=0, needpair = 0, namelen=0, monog_pairs = 0;
   THD_3dim_dataset *tttdset=NULL, *dsetp=NULL;
   char *tempstr = NULL;
   int extinit = 0;
   float RL_AP_IS[6];

   mainENTRY("3dinfo main") ; machdep() ;

   if( argc < 2) { Syntax(TXT,1) ; RETURN(0); }

   iarg = 1 ;
   while (iarg < argc && argv[iarg][0] == '-') {
      CHECK_HELP(argv[iarg],Syntax);
           if( strncmp(argv[iarg],"-verb" ,5) == 0 ){
            verbose =  0; iarg++; continue; }
      else if( strncmp(argv[iarg],"-VERB" ,5) == 0 ){
            verbose =  1; iarg++; continue; }
      else if( strncmp(argv[iarg],"-short",5) == 0 ){
            verbose = -1; iarg++; continue; }
      else if( strcasecmp(argv[iarg],"-header_line") == 0 ||
               strcasecmp(argv[iarg],"-hdr") == 0 ){
            withhead = 1; iarg++; continue; }
      else if( strcasecmp(argv[iarg],"-monog_pairs") == 0 ){
            monog_pairs = 1; iarg++; continue; }
      else if ( strncmp(argv[iarg],"-label2",7) == 0 )
      {
        iarg++;
        if (iarg >= argc)
           ERROR_exit( "3dinfo needs an argument after -label2number\n");
        labelName = malloc(sizeof(char) * 2048);
        strcpy(labelName, argv[iarg]);
        iarg++; continue;
      }
      else if( strcasecmp(argv[iarg],"-sb_delim") == 0) {
         iarg++;
         if (iarg >= argc)
           ERROR_exit( "3dinfo needs a string after -sb_delim\n");
         sbdelim = argv[iarg];
         iarg++; continue;
      }
      else if( strcasecmp(argv[iarg],"-NA_flag") == 0) {
         iarg++;
         if (iarg >= argc)
           ERROR_exit( "3dinfo needs a string after -NA_flag\n");
         NAflag = argv[iarg];
         iarg++; continue;
      }
      else if( strcasecmp(argv[iarg],"-atr_delim") == 0) {
         iarg++;
         if (iarg >= argc)
           ERROR_exit( "3dinfo needs a string after -atr_delim\n");
         atrdelim = argv[iarg];
         iarg++; continue;
      }
      else if( strcasecmp(argv[iarg],"-space") == 0) {
         sing[N_sing++] = DSET_SPACE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-av_space") == 0) {
         sing[N_sing++] = AV_DSET_SPACE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-gen_space") == 0) {
         sing[N_sing++] = DSET_GEN_SPACE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-is_nifti") == 0) {
         sing[N_sing++] = IS_NIFTI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-is_atlas") == 0) {
         sing[N_sing++] = IS_ATLAS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-exists") == 0) {
         sing[N_sing++] = DSET_EXISTS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-is_oblique") == 0) {
         sing[N_sing++] = IS_OBLIQUE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-obliquity") == 0) {
         sing[N_sing++] = OBLIQUITY; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-handedness") == 0) {
         sing[N_sing++] = HANDEDNESS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-prefix") == 0) {
         sing[N_sing++] = PREFIX; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-prefix_noext") == 0) {
         sing[N_sing++] = PREFIX_NOEXT; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-ni") == 0) {
         sing[N_sing++] = NI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nj") == 0) {
         sing[N_sing++] = NJ; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nk") == 0) {
         sing[N_sing++] = NK; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-n4") == 0) {
         sing[N_sing++] = NI;
         sing[N_sing++] = NJ;
         sing[N_sing++] = NK;
         sing[N_sing++] = NV; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-Rextent") == 0) {
         sing[N_sing++] = EXTENT_R; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-Lextent") == 0) {
         sing[N_sing++] = EXTENT_L; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-Aextent") == 0) {
         sing[N_sing++] = EXTENT_A; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-Pextent") == 0) {
         sing[N_sing++] = EXTENT_P; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-Iextent") == 0) {
         sing[N_sing++] = EXTENT_I; iarg++;
         continue;
      }  else if( strcasecmp(argv[iarg],"-Sextent") == 0) {
         sing[N_sing++] = EXTENT_S; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-extent") == 0) {
         sing[N_sing++] = EXTENT_R;
         sing[N_sing++] = EXTENT_L;
         sing[N_sing++] = EXTENT_A;
         sing[N_sing++] = EXTENT_P;
         sing[N_sing++] = EXTENT_I;
         sing[N_sing++] = EXTENT_S;
         iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-di") == 0) {
         sing[N_sing++] = DI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dj") == 0) {
         sing[N_sing++] = DJ; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dk") == 0) {
         sing[N_sing++] = DK; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-d3") == 0) {
         sing[N_sing++] = DI;
         sing[N_sing++] = DJ;
         sing[N_sing++] = DK; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-adi") == 0) {
         sing[N_sing++] = ADI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-adj") == 0) {
         sing[N_sing++] = ADJ; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-adk") == 0) {
         sing[N_sing++] = ADK; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-ad3") == 0) {
         sing[N_sing++] = ADI;
         sing[N_sing++] = ADJ;
         sing[N_sing++] = ADK; iarg++;
         continue;
      } else if( strcasecmp(argv[iarg],"-voxvol") == 0) {
         sing[N_sing++] = VOXVOL; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-iname") == 0) {
         sing[N_sing++] = INAME; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-oi") == 0) {
         sing[N_sing++] = OI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-oj") == 0) {
         sing[N_sing++] = OJ; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-ok") == 0) {
         sing[N_sing++] = OK; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-o3") == 0) {
         sing[N_sing++] = OI;
         sing[N_sing++] = OJ;
         sing[N_sing++] = OK; iarg++;
         continue;
      }else if( strcasecmp(argv[iarg],"-nt") == 0) {
         sing[N_sing++] = NT; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nti") == 0) {
         sing[N_sing++] = NTI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nv") == 0) {
         sing[N_sing++] = NV; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nvi") == 0) {
         sing[N_sing++] = NVI; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-ntimes") == 0) {
         sing[N_sing++] = NTIMES; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-max_node") == 0) {
         sing[N_sing++] = MAX_NODE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-nijk") == 0) {
         sing[N_sing++] = NIJK; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-labeltable") == 0) {
         sing[N_sing++] = LTABLE; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-labeltable_as_atlas_points") == 0) {
         sing[N_sing++] = LTABLE_AS_ATLAS_POINT_LIST; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-atlas_points") == 0) {
         sing[N_sing++] = ATLAS_POINTS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-fac") == 0) {
         sing[N_sing++] = FAC; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-datum") == 0) {
         sing[N_sing++] = DATUM; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-label") == 0) {
         sing[N_sing++] = LABEL; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-min") == 0) {
         sing[N_sing++] = MIN; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-max") == 0) {
         sing[N_sing++] = MAX; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-minus") == 0) {
         sing[N_sing++] = MINUS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-maxus") == 0) {
         sing[N_sing++] = MAXUS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dmin") == 0) {
         sing[N_sing++] = DMIN; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dmax") == 0) {
         sing[N_sing++] = DMAX; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dminus") == 0) {
         sing[N_sing++] = DMINUS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-dmaxus") == 0) {
         sing[N_sing++] = DMAXUS; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-TR") == 0) {
         sing[N_sing++] = TR; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-header_name") == 0) {
         sing[N_sing++] = HEADER_NAME; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-brick_name") == 0) {
         sing[N_sing++] = BRICK_NAME; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-history") == 0) {
         sing[N_sing++] = HISTORY; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-all_names") == 0) {
         sing[N_sing++] = ALL_NAMES; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-orient") == 0) {
         sing[N_sing++] = ORIENT; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_grid") == 0) {
         sing[N_sing++] = SAME_GRID; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_dim") == 0) {
         sing[N_sing++] = SAME_DIM; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_delta") == 0) {
         sing[N_sing++] = SAME_DELTA; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_orient") == 0) {
         sing[N_sing++] = SAME_ORIENT; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_center") == 0) {
         sing[N_sing++] = SAME_CENTER; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_obl") == 0) {
         sing[N_sing++] = SAME_OBL; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-slice_timing") == 0) {
         sing[N_sing++] = SLICE_TIMING; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-sval_diff") == 0) {
         sing[N_sing++] = SVAL_DIFF; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-val_diff") == 0) {
         sing[N_sing++] = VAL_DIFF; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-same_all_grid") == 0) {
         sing[N_sing++] = SAME_DIM;
         sing[N_sing++] = SAME_DELTA;
         sing[N_sing++] = SAME_ORIENT;
         sing[N_sing++] = SAME_CENTER;
         sing[N_sing++] = SAME_OBL; needpair = 1; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-id") == 0) {
         sing[N_sing++] = ID; iarg++; continue;
      } else if( strcasecmp(argv[iarg],"-smode") == 0) {
         sing[N_sing++] = SMODE; iarg++; continue;
      } else {
         ERROR_message("Option %s unknown", argv[iarg]);
         suggest_best_prog_option(argv[0], argv[iarg]);
         exit(1);
      }
   }

   if (N_sing == 0) {
      sing[N_sing++] = CLASSIC;
   }

   if (sing[iis] == CLASSIC) PRINT_VERSION("3dinfo") ;

   THD_allow_empty_dataset(1) ;  /* 21 Mar 2007 */

   if (iarg == argc) {
      ERROR_message("No dsets on command line? I have nothing to do.\n");
      exit(1);
   }

   if (needpair && monog_pairs) needpair = 2; /* pair each couple separately */

   if (needpair==2 && (argc-iarg) % 2) {
      ERROR_message("Using options requiring dset pairs but have odd number\n"
                    "of dsets (%d) on command line.\n", (argc-iarg));
      exit (1);
   } else if (needpair==1 && (argc-iarg) < 2) {
      ERROR_message("Using options requiring dset pairs but have less than\n"
                    "two dsets (%d) on command line.\n", (argc-iarg));
      exit (1);
   }

   ip = 0;
   for( ; iarg < argc ; iarg++ ){
      if (ip == 0) {
         int kkk, nml; char *etr;
         namelen = 0;
         for (kkk=iarg; kkk<argc; ++kkk) {
            if ((etr = THD_trailname(argv[kkk],0))) {
               nml=strlen(etr);
               if (nml < 48 && nml > namelen) namelen = nml;
            }
         }
         if (namelen < 6) namelen = 6;
         if (withhead) {
            int havenew=0;
            for (iis = 0; iis < N_sing; ++iis) {
               if (sing[iis] != CLASSIC) {
                  ++havenew;
                  form = PrintForm(sing[iis], namelen, 1);
                  /*fprintf(stderr,"ZSS: %d %s >%s<\n",
                           sing[iis], Field_Names[sing[iis]], form);*/

                  fprintf(stdout, form, Field_Names[sing[iis]]);
               }
               if (havenew) {
                  if (N_sing > 1 && iis < N_sing-1)
                           fprintf(stdout,"%s",atrdelim);
                  else fprintf(stdout,"\n");
               }
            }
         }
      }
     if( argv[iarg][0] == '\0' ) continue ;  /* bad filename */

     set_obliquity_report(0); /* silence obliquity */

     if (!needpair) {
      if (!(dset = load_3dinfo_dataset(argv[iarg]))) {
        /* exit(1); */
      }
     } else {
      if (needpair == 2) { /* Crazy idea of comparing each pair separately */
         if (ip % 2 == 0) {
            if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
               /* exit(1); */
            }
            if (iarg+1==argc || argv[iarg+1][0] == '\0') {
               ERROR_message("Bad dset pair for %s\n", argv[iarg]);
               exit(1);
            }
            if (!(dsetp = load_3dinfo_dataset(argv[iarg+1] ))) {
               /* exit(1); */
            }
         } else { /* swap the pair - this allows non pair requiring functions
                     to work as before.*/
            tttdset = dsetp;
            dsetp = dset;
            dset = tttdset; tttdset=NULL;
         }
      } else { /* always compare to very first dset */
         if (ip==0) {
            if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
               /*exit(1);*/
            }
            if (!(dsetp = load_3dinfo_dataset(argv[iarg+1] ))) {
               /*exit(1);*/
            }
         } else if (ip==1) { /* switch order of first two */
            tttdset = dsetp;
            dsetp = dset; /* now dsetp is the very first dset */
            dset = tttdset; tttdset=NULL;
         } else { /* pair with very first, which is dsetp */
            if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
               /*exit(1);*/
            }
         }
      }
     }
     ++ip;

     if (0 && !dset) { /* allow for DSET_EXISTS option */
         ERROR_exit("Should not get here");
     }

     /* we should re-capture this per dataset   5 Feb 2019 [rickr] */
     extinit = 0;

     for (iis = 0; iis < N_sing; ++iis) {
        if (!dset) {
         if (sing[iis] == CLASSIC) {
            if( dset == NULL ){  /* still not open? */
               ERROR_exit("Can't open dataset %s\n", argv[iarg]) ;
            }
         } else if (sing[iis] != DSET_EXISTS && sing[iis] != INAME) {
            fprintf(stdout, "NO-DSET");
            SPIT_DELIM(iis, N_sing, atrdelim);
            continue;
         }
        }
        switch (sing[iis]) {
         case CLASSIC:
            if (labelName == NULL )  /*** get and output info ***/
            {
             outbuf = THD_dataset_info( dset , verbose ) ;
             if( outbuf != NULL ){
               printf("\n") ;
               puts(outbuf) ;
               free(outbuf) ; outbuf = NULL ;
             } else {
               ERROR_exit("Can't get info for dataset %s",argv[iarg]) ;
             }
            }
            else   /*** get and output label ***/
            {
             int nval_per = dset->dblk->nvals;
             int foundLabel = 0;
             int ival=0;

             for (ival=0 ; ival < nval_per && !foundLabel; ival++ )
             {
               if (strcmp(DSET_BRICK_LAB(dset,ival), labelName) == 0)
               {
                 printf("%d\n", ival); foundLabel = 1;
               }
             } /* end of for (ival=0 ; ival < nval_per ; ival++ ) */
             if (!foundLabel) printf("\n");
            }

            THD_delete_3dim_dataset( dset , False ) ;
            free(labelName);
            break;
         case DSET_EXISTS:
            fprintf(stdout, "%d", dset ? 1:0);
            break;
         case DSET_SPACE:
            tempstr = THD_get_space(dset);
            if(tempstr==NULL)
                  fprintf(stdout, "-----");
            else
                  fprintf(stdout, "%s", tempstr);
            break;
         case DSET_GEN_SPACE:
            tempstr = THD_get_generic_space(dset);
            if(tempstr==NULL)
                  fprintf(stdout, "-----");
            else
                  fprintf(stdout, "%s", tempstr);
            break;
         case AV_DSET_SPACE:
            /* don't allow anything but the three AFNI views */
            tempstr = THD_get_view_space(dset);
            if(tempstr==NULL)
                  fprintf(stdout, "+orig");
            else if (!strncasecmp(tempstr,"ORIG",4))
                  fprintf(stdout, "+orig");
            else if (!strncasecmp(tempstr,"ACPC",4))
                  fprintf(stdout, "+acpc");
            else if (!strncasecmp(tempstr,"TLRC",4))
                  fprintf(stdout, "+tlrc");
            else  /* shouldn't get here */
                  fprintf(stdout, "+orig");
            break;
         case IS_NIFTI:
            if (  dset->dblk->diskptr &&
                  dset->dblk->diskptr->storage_mode == STORAGE_BY_NIFTI ) {
               fprintf(stdout,"1");
            } else {
               fprintf(stdout,"0");
            }
            break;
         case IS_ATLAS:
            if (  is_Dset_Atlasy(dset, NULL) ) {
               fprintf(stdout,"1");
            } else {
               fprintf(stdout,"0");
            }
            break;
         case IS_OBLIQUE:
            if (dset_obliquity(dset,NULL) > 0) {
               fprintf(stdout,"1");
            } else {
               fprintf(stdout,"0");
            }
            break;
         case HANDEDNESS:
            if (THD_handedness(dset) > 0) {
               fprintf(stdout,"R");
            } else {
               fprintf(stdout,"L");
            }
            break;
         case OBLIQUITY:
            fprintf(stdout,"%.3f",
                  THD_compute_oblique_angle(dset->daxes->ijk_to_dicom_real, 0));
            break;
         case PREFIX:
            form = PrintForm(sing[iis], namelen, 1);
            fprintf(stdout,form, DSET_PREFIX(dset));
            break;
         case PREFIX_NOEXT:
            {
               form = PrintForm(sing[iis], namelen, 1);
               stmp=DSET_prefix_noext(dset);
               fprintf(stdout,form, stmp);
               free(stmp); stmp=NULL;
            }
            break;
         case HEADER_NAME:
            fprintf(stdout,"%s", dset->dblk->diskptr->header_name);
            break;
         case BRICK_NAME:
            fprintf(stdout,"%s", dset->dblk->diskptr->brick_name);
            break;
         case ALL_NAMES:
            THD_show_dataset_names(dset, "FOR_3DINFO", stdout);
            break;
         case HISTORY:
            stmp = tross_Get_History(dset);
            fprintf(stdout,"%s", stmp ? stmp:NAflag);
            if (stmp) free(stmp); stmp=NULL;
            break;
         case NI:
            fprintf(stdout,"%d", DSET_NX(dset));
            break;
         case NJ:
            fprintf(stdout,"%d", DSET_NY(dset));
            break;
         case NK:
            fprintf(stdout,"%d", DSET_NZ(dset));
            break;
         case NIJK:
            fprintf(stdout,"%d", DSET_NVOX(dset));
            break;
         case NTIMES:
            fprintf(stdout,"%d", DSET_NUM_TIMES(dset));
            break;
         case MAX_NODE:
            DSET_MAX_NODE(dset,itmp);
            fprintf(stdout,"%d", itmp);
            break;
         case NT:
         case NV:
            fprintf(stdout,"%d", DSET_NVALS(dset));
            break;
         case NTI:
         case NVI:
            fprintf(stdout,"%d", DSET_NVALS(dset)-1);
            break;
         case DI:
            fprintf(stdout,"%f", DSET_DX(dset));
            break;
         case DJ:
            fprintf(stdout,"%f", DSET_DY(dset));
            break;
         case DK:
            fprintf(stdout,"%f", DSET_DZ(dset));
            break;
         case OI:
            fprintf(stdout,"%f", DSET_XORG(dset));
            break;
         case OJ:
            fprintf(stdout,"%f", DSET_YORG(dset));
            break;
         case OK:
            fprintf(stdout,"%f", DSET_ZORG(dset));
            break;
         case ADI:
            fprintf(stdout,"%f", fabs(DSET_DX(dset)));
            break;
         case EXTENT_R:
         case EXTENT_L:
         case EXTENT_A:
         case EXTENT_P:
         case EXTENT_I:
         case EXTENT_S:
            {
               if (!extinit) {
                  THD_dset_extent(dset, '-', RL_AP_IS);
                  extinit = 1;
               }
               fprintf(stdout,"%f", RL_AP_IS[sing[iis]-EXTENT_R]);
            }
            break;

         case ADJ:
            fprintf(stdout,"%f", fabs(DSET_DY(dset)));
            break;
         case ADK:
            fprintf(stdout,"%f", fabs(DSET_DZ(dset)));
            break;
         case VOXVOL:
            fprintf(stdout,"%f", fabs(DSET_DX(dset))*
                                 fabs(DSET_DY(dset))*fabs(DSET_DZ(dset)));
            break;
         case INAME:
            fprintf(stdout,"%s", argv[iarg]);
            break;
         case LTABLE:
            {
               char *str;
               if ((str = Dtable_to_nimlstring(DSET_Label_Dtable(dset),                                                          "VALUE_LABEL_DTABLE"))) {
                  fprintf(stdout,"%s", str);
                  free(str);
               } else {
                  fprintf(stdout,"NO_LABEL_TABLE");
               }
            }
            break;
         case LTABLE_AS_ATLAS_POINT_LIST:
            {
               ATLAS_POINT_LIST *apl=NULL;
               if ((apl =
                     label_table_to_atlas_point_list(DSET_Label_Dtable(dset)))) {
                  atlas_list_to_niml(apl,NULL);
                  free_atlas_point_list(apl);
               } else {
                  fprintf(stdout,"NO_LABEL_TABLE");
               }
            }
            break;
         case  ATLAS_POINTS:
            {
               ATR_string *atr =
                  THD_find_string_atr( dset->dblk, "ATLAS_LABEL_TABLE");
               if (atr) {
                  fprintf(stdout,"%s", atr->ch);
               }  else {
                  fprintf(stdout,"NO_APL");
               }
            }
            break;
         case FAC:
            {
               for (isb=0; isb<DSET_NVALS(dset); ++isb) {
                  fprintf(stdout,"%f%s",
                        DSET_BRICK_FACTOR(dset,isb),
                        (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
               }
               break;
            }
         case DATUM:
            {
               for (isb=0; isb<DSET_NVALS(dset); ++isb) {
                  fprintf(stdout,"%s%s",
                        MRI_TYPE_name[DSET_BRICK_TYPE(dset,isb)],
                        (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
               }
               break;
            }
         case LABEL:
            {
               for (isb=0; isb<DSET_NVALS(dset); ++isb) {
                  fprintf(stdout,"%s%s",
               DSET_BRICK_LABEL(dset,isb) ? DSET_BRICK_LABEL(dset,isb):NAflag,
                        (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
               }
               break;
            }
         case MIN:
         case MINUS:
         case MAX:
         case MAXUS:
            {
               float vv=0.0, min, max;
               for (isb=0; isb<DSET_NVALS(dset); ++isb) {
                  if (!THD_subbrick_minmax(dset, isb,
                        (sing[iis] == MINUS || sing[iis] == MAXUS) ? 0:1,
                        &min, &max)) {
                     fprintf(stdout,"%s%s",
                        NAflag,
                        (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
                  } else {
                          if (sing[iis] == MINUS)
                        vv = min;
                     else if (sing[iis] == MAXUS)
                        vv = max;
                     else if (sing[iis] == MIN)
                        vv = min;
                     else if (sing[iis] == MAX)
                        vv = max;
                     fprintf(stdout,"%g%s",
                        vv,
                        (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
                  }
               }
               break;
            }
         case DMIN:
         case DMINUS:
         case DMAX:
         case DMAXUS:
            {
               float vv=0.0, min, max;
               if (!THD_dset_minmax(dset,
                     (sing[iis] == DMINUS || sing[iis] == DMAXUS) ? 0:1,
                     &min, &max)) {
                  fprintf(stdout,"%s%s",
                     NAflag,
                     (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
               } else {
                       if (sing[iis] == DMINUS)
                     vv = min;
                  else if (sing[iis] == DMAXUS)
                     vv = max;
                  else if (sing[iis] == DMIN)
                     vv = min;
                  else if (sing[iis] == DMAX)
                     vv = max;
                  fprintf(stdout,"%g%s",
                     vv,
                     (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
               }
               break;
            }
         case TR:
#if 0
            fprintf(stdout,"%f", DSET_TR_SEC(dset));
#else
            fprintf(stdout,"%f", DSET_TR(dset));
#endif
            break;
         case ORIENT:
            {
               /* fprintf(stdout,"%c%c%c",
                *         ORIENT_typestr[dset->daxes->xxorient][0], ... ); */
               char ostr[4];    /* just to show        23 Jan 2013 [rickr] */
               THD_fill_orient_str_3(dset->daxes, ostr);
               fprintf(stdout,"%3s", ostr);
            }
            break;
         case SAME_GRID:
            fprintf(stdout,"%d",
               !THD_dataset_mismatch( dset , dsetp ));
            break;
         case SAME_DIM:
            fprintf(stdout,"%d",
               !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_DIMEN));
            break;
         case SAME_DELTA:
            fprintf(stdout,"%d",
               !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_DELTA));
            break;
         case SAME_ORIENT:
            fprintf(stdout,"%d",
               !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_ORIENT));
            break;
         case SAME_CENTER:
            fprintf(stdout,"%d",
               !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_CENTER));
            break;
         case SAME_OBL:
            fprintf(stdout,"%d",
               !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_OBLIQ));
            break;
         case SLICE_TIMING:     /* 6 May 2013 [rickr] */
            {
               if( DSET_HAS_SLICE_TIMING(dset) ) {
                  DSET_UNMSEC(dset); /* make sure times are in seconds */
                  for (isb=0; isb<dset->taxis->nsl; ++isb) {
                     fprintf(stdout,"%s%f",
                           (isb > 0) ? sbdelim : "",
                           dset->taxis->toff_sl[isb]);
                  }
               } else { /* all slices times are at t=0.0 */
                  for (isb=0; isb<DSET_NZ(dset); ++isb) {
                     fprintf(stdout,"%s%f", (isb > 0) ? sbdelim : "", 0.0);
                  }
               }
            }
            break;
         case SVAL_DIFF:
            fprintf(stdout,"%f",THD_diff_vol_vals(dset, dsetp, 1));
            break;
         case VAL_DIFF:
            fprintf(stdout,"%f",THD_diff_vol_vals(dset, dsetp, 0));
            break;
         case ID:
            fprintf(stdout,"%s", DSET_IDCODE_STR(dset));
            break;
         case SMODE:
            fprintf(stdout,"%s", DSET_STORAGE_MODE_STR(dset));
            break;
         default:
            ERROR_message("Info field not set properly (%d)\n", sing[iis]);
            exit(1);
        }
        if (sing[iis] != CLASSIC) {
         SPIT_DELIM(iis, N_sing, atrdelim);
        }
      }
   }

   exit(0) ;
}
/*!
   A function version of the program mc by Thomas Lewiner
   see main.c in ./MarchingCubes
*/
SUMA_SurfaceObject *SUMA_MarchingCubesSurface(
                        SUMA_GENERIC_PROG_OPTIONS_STRUCT * Opt)
{
   static char FuncName[]={"SUMA_MarchingCubesSurface"};
   SUMA_SurfaceObject *SO=NULL;
   int nxx, nyy, nzz, cnt, i, j, k, *FaceSetList=NULL;
   float *NodeList=NULL;
   SUMA_NEW_SO_OPT *nsoopt = NULL;
   THD_fvec3 fv, iv;
   MCB *mcp ;
   
   SUMA_ENTRY;
   
   if (Opt->obj_type < 0) {
      nxx = DSET_NX(Opt->in_vol);
      nyy = DSET_NY(Opt->in_vol);
      nzz = DSET_NZ(Opt->in_vol);

      if (Opt->debug) {
         fprintf(SUMA_STDERR,
                 "%s:\nNxx=%d\tNyy=%d\tNzz=%d\n", FuncName, nxx, nyy, nzz);
      }

      mcp = MarchingCubes(-1, -1, -1);
      set_resolution( mcp, nxx, nyy, nzz ) ;
      init_all(mcp) ;
      if (Opt->debug) fprintf(SUMA_STDERR,"%s:\nSetting data...\n", FuncName);
      cnt = 0;
      for(  k = 0 ; k < mcp->size_z ; k++ ) {
         for(  j = 0 ; j < mcp->size_y ; j++ ) {
            for(  i = 0 ; i < mcp->size_x ; i++ ) {
               SUMA_SET_MC_DATA ( mcp, Opt->mcdatav[cnt], i, j, k); 
               ++cnt;
            }
         }
      }

   } else {
      /* built in */
      nxx = nyy = nzz = Opt->obj_type_res;
      mcp = MarchingCubes(-1, -1, -1);
      set_resolution( mcp, nxx, nyy, nzz) ;
      init_all(mcp) ;
      compute_data( *mcp , Opt->obj_type) ;
   }

   
   if (Opt->debug) 
      fprintf(SUMA_STDERR,"%s:\nrunning MarchingCubes...\n", FuncName);
   run(mcp) ;
   clean_temps(mcp) ;

   if (Opt->debug > 1) {
      fprintf(SUMA_STDERR,"%s:\nwriting out NodeList and FaceSetList...\n", 
                         FuncName);
      write1Dmcb(mcp);
   }

   if (Opt->debug) {
      fprintf(SUMA_STDERR,"%s:\nNow creating SO...\n", FuncName);
   }

   NodeList = (float *)SUMA_malloc(sizeof(float)*3*mcp->nverts);
   FaceSetList = (int *)SUMA_malloc(sizeof(int)*3*mcp->ntrigs);
   if (!NodeList || !FaceSetList)  {
      SUMA_SL_Crit("Failed to allocate!");
      SUMA_RETURN(SO);
   }
   
   nsoopt = SUMA_NewNewSOOpt();
   if (Opt->obj_type < 0) {
      nsoopt->LargestBoxSize = -1;
      if (Opt->debug) {
         fprintf(SUMA_STDERR,
                  "%s:\nCopying vertices, changing to DICOM \n"
                  "Orig:(%f %f %f) \nD:(%f %f %f)...\n", 
            FuncName, 
            DSET_XORG(Opt->in_vol), 
            DSET_YORG(Opt->in_vol), DSET_ZORG(Opt->in_vol),
            DSET_DX(Opt->in_vol), 
            DSET_DY(Opt->in_vol), DSET_DZ(Opt->in_vol));
      }
      for ( i = 0; i < mcp->nverts; i++ ) {
         j = 3*i; /* change from index coordinates to mm DICOM, next three lines are equivalent of SUMA_THD_3dfind_to_3dmm*/
         fv.xyz[0] = DSET_XORG(Opt->in_vol) + mcp->vertices[i].x * DSET_DX(Opt->in_vol);
         fv.xyz[1] = DSET_YORG(Opt->in_vol) + mcp->vertices[i].y * DSET_DY(Opt->in_vol);
         fv.xyz[2] = DSET_ZORG(Opt->in_vol) + mcp->vertices[i].z * DSET_DZ(Opt->in_vol);
         /* change mm to RAI coords */
		   iv = SUMA_THD_3dmm_to_dicomm( Opt->in_vol->daxes->xxorient, Opt->in_vol->daxes->yyorient, Opt->in_vol->daxes->zzorient, fv );
         NodeList[j  ] = iv.xyz[0];
         NodeList[j+1] = iv.xyz[1];
         NodeList[j+2] = iv.xyz[2];
      }
      for ( i = 0; i < mcp->ntrigs; i++ ) {
         j = 3*i;
         FaceSetList[j  ] = mcp->triangles[i].v3;
         FaceSetList[j+1] = mcp->triangles[i].v2;
         FaceSetList[j+2] = mcp->triangles[i].v1;
      }
   } else {
      nsoopt->LargestBoxSize = 100;
      /* built in */
      for ( i = 0; i < mcp->nverts; i++ ) {
         j = 3*i;
         NodeList[j  ] = mcp->vertices[i].x;
         NodeList[j+1] = mcp->vertices[i].y;
         NodeList[j+2] = mcp->vertices[i].z;
      }   
      for ( i = 0; i < mcp->ntrigs; i++ ) {
         j = 3*i;
         FaceSetList[j  ] = mcp->triangles[i].v3;
         FaceSetList[j+1] = mcp->triangles[i].v2;
         FaceSetList[j+2] = mcp->triangles[i].v1;
      }
   }
   

   SO = SUMA_NewSO(&NodeList, mcp->nverts, &FaceSetList, mcp->ntrigs, nsoopt);
   if (Opt->obj_type < 0) {
      /* not sure if anything needs to be done here ...*/
   } else {
      if (Opt->obj_type == 0) SO->normdir = 1;
      else SO->normdir = -1;
   }
   
   if (Opt->debug) {
      fprintf(SUMA_STDERR,"%s:\nCleaning mcp...\n", FuncName);
   }
   clean_all(mcp) ;
   free(mcp);
   nsoopt=SUMA_FreeNewSOOpt(nsoopt); 

   SUMA_RETURN(SO);
}
Exemple #5
0
int AFNI_vedit( THD_3dim_dataset *dset , VEDIT_settings vednew , byte *mask )
{
   THD_datablock *dblk ;
   int ival ;
   MRI_IMAGE *dim ;

ENTRY("AFNI_vedit") ;

   if( !ISVALID_DSET(dset) ) RETURN(0) ;

   dblk = dset->dblk ;

   /*--- check if we are to clear any existing edits,
         and also set future editing status to 'do nothing' ---*/

   if( vednew.code <= 0 || vednew.code > VEDIT_LASTCODE ){
     if( dblk->vedim != NULL ){ mri_free(dblk->vedim); dblk->vedim=NULL; }
     dblk->vedset.code = 0; dblk->vedset.ival = -1; dblk->vedset.exinfo = NULL;
     RETURN(0) ;
   }

   /* if we have existing editing results,
      and they correspond to the same parameters as before, then are done.
      otherwise, we clear out the existing results so they can be replaced. */

   if( dblk->vedim != NULL && (vednew.flags&1) == 0 ){
     if( memcmp(&(dblk->vedset),&vednew,sizeof(VEDIT_settings)) == 0 )
       RETURN(0) ;                            /* exactly the same as before */

     mri_free(dblk->vedim); dblk->vedim=NULL; /* clear old results */
   }

   /*--- at this point, must edit dataset brick ---*/

   dblk->vedset = vednew ;  /* save settings for next time in */
   dblk->vedset.flags = 0 ;

   /*--- create edited volume ---*/

   if( vednew.code == VEDIT_CLUST ){  /*----- Clusterize -----*/

     MRI_IMAGE *tim=NULL ;
     float thr,rmm,vmul,thb,tht ;
     int thrsign,posfunc,ithr ;

     ival = vednew.ival ;
     if( ival < 0 || ival > DSET_NVALS(dset) ) RETURN(0) ;
     dim = DBLK_BRICK(dblk,ival) ;
     if( dim == NULL || mri_data_pointer(dim) == NULL ){
       DSET_load(dset) ;
       dim = DBLK_BRICK(dblk,ival) ;
       if( dim == NULL || mri_data_pointer(dim) == NULL ) RETURN(0) ;
     }
     dim->dx = fabs(DSET_DX(dset));
     dim->dy = fabs(DSET_DY(dset));
     dim->dz = fabs(DSET_DZ(dset));

     ithr    = (int)vednew.param[0] ;
     thrsign = (int)vednew.param[4] ;
     posfunc = (int)vednew.param[5] ;
     if( ithr >= 0 && ithr < DSET_NVALS(dset) )
       tim = DBLK_BRICK(dblk,ithr) ;
     thr = vednew.param[1] ;
     if( DSET_BRICK_FACTOR(dset,ithr) > 0.0f )
       thr /= DSET_BRICK_FACTOR(dset,ithr) ;
     thb = THBOT(thr) ; tht = THTOP(thr) ;
     rmm  = vednew.param[2] ; vmul = vednew.param[3] ;
     dblk->vedim = mri_clusterize( rmm,vmul,dim,thb,tht,tim,posfunc , mask );

   }

   /*--- done ---*/

   RETURN(1) ;
}
Exemple #6
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[] )
{
   char *aname ;
   THD_3dim_dataset *dset ;
   int ii , scl ;
   MRI_IMAGE *im , *qim ;
   char *fname ;
   float fac ;

   int do_4D=0 , iarg=1 ;    /* 30 Sep 2002 */
   FILE *ifp=NULL ;

   int xxor=-1,yyor=0,zzor=0 , xdir=0,ydir=0,zdir=0;  /* 19 Mar 2003 */
   float                   xdel=0.0  ,ydel=0.0,zdel=0.0;
   char orient_code[4] ;

   /*-- help me if you can --*/

WARNING_message("This program (3dAFNItoANALYZE) is old, not maintained, and probably useless!") ;

   if( argc < 3 || strcmp(argv[1],"-help") == 0 ){
      printf("Usage: 3dAFNItoANALYZE [-4D] [-orient code] aname dset\n"
             "Writes AFNI dataset 'dset' to 1 or more ANALYZE 7.5 format\n"
             ".hdr/.img file pairs (one pair for each sub-brick in the\n"
             "AFNI dataset).  The ANALYZE files will be named\n"
             "  aname_0000.hdr aname_0000.img   for sub-brick #0\n"
             "  aname_0001.hdr aname_0001.img   for sub-brick #1\n"
             "and so forth.  Each file pair will contain a single 3D array.\n"
             "\n"
             "* If the AFNI dataset does not include sub-brick scale\n"
             "  factors, then the ANALYZE files will be written in the\n"
             "  datum type of the AFNI dataset.\n"
             "* If the AFNI dataset does have sub-brick scale factors,\n"
             "  then each sub-brick will be scaled to floating format\n"
             "  and the ANALYZE files will be written as floats.\n"
             "* The .hdr and .img files are written in the native byte\n"
             "  order of the computer on which this program is executed.\n"
             "\n"
             "Options\n"
             "-------\n"
             "-4D [30 Sep 2002]:\n"
             " If you use this option, then all the data will be written to\n"
             " one big ANALYZE file pair named aname.hdr/aname.img, rather\n"
             " than a series of 3D files.  Even if you only have 1 sub-brick,\n"
             " you may prefer this option, since the filenames won't have\n"
             " the '_0000' appended to 'aname'.\n"
             "\n"
             "-orient code [19 Mar 2003]:\n"
             " This option lets you flip the dataset to a different orientation\n"
             " when it is written to the ANALYZE files.  The orientation code is\n"
             " formed as follows:\n"
             "   The code must be 3 letters, one each from the\n"
             "   pairs {R,L} {A,P} {I,S}.  The first letter gives\n"
             "   the orientation of the x-axis, the second the\n"
             "   orientation of the y-axis, the third the z-axis:\n"
             "      R = Right-to-Left          L = Left-to-Right\n"
             "      A = Anterior-to-Posterior  P = Posterior-to-Anterior\n"
             "      I = Inferior-to-Superior   S = Superior-to-Inferior\n"
             "   For example, 'LPI' means\n"
             "      -x = Left       +x = Right\n"
             "      -y = Posterior  +y = Anterior\n"
             "      -z = Inferior   +z = Superior\n"
             " * For display in SPM, 'LPI' or 'RPI' seem to work OK.\n"
             "    Be careful with this: you don't want to confuse L and R\n"
             "    in the SPM display!\n"
             " * If you DON'T use this option, the dataset will be written\n"
             "    out in the orientation in which it is stored in AFNI\n"
             "    (e.g., the output of '3dinfo dset' will tell you this.)\n"
             " * The dataset orientation is NOT stored in the .hdr file.\n"
             " * AFNI and ANALYZE data are stored in files with the x-axis\n"
             "    varying most rapidly and the z-axis most slowly.\n"
             " * Note that if you read an ANALYZE dataset into AFNI for\n"
             "    display, AFNI assumes the LPI orientation, unless you\n"
             "    set environment variable AFNI_ANALYZE_ORIENT.\n"
            ) ;
      PRINT_COMPILE_DATE; exit(0) ;
   }

   mainENTRY("3dAFNItoANALYZE main"); machdep(); PRINT_VERSION("3dAFNItoANALYZE");

   /*-- read inputs --*/

   while( iarg < argc && argv[iarg][0] == '-' ){

     if( strcmp(argv[iarg],"-4D") == 0 ){    /* 30 Sep 2002 */
       do_4D = 1 ; iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-orient") == 0 ){ /* 19 Mar 2003 */
       char acod ;

       if( iarg+1 >= argc ){
         fprintf(stderr,"** Need something after -orient!\n"); exit(1);
       }

       MCW_strncpy(orient_code,argv[++iarg],4) ;
       if( strlen(orient_code) != 3 ){
         fprintf(stderr,"** Illegal code '%s' after -orient!\n",argv[iarg]); exit(1);
       }

       acod = toupper(orient_code[0]) ; xxor = ORCODE(acod) ;
       acod = toupper(orient_code[1]) ; yyor = ORCODE(acod) ;
       acod = toupper(orient_code[2]) ; zzor = ORCODE(acod) ;

       if( xxor<0 || yyor<0 || zzor<0 || !OR3OK(xxor,yyor,zzor) ){
         fprintf(stderr,"** Unusable code after -orient!\n"); exit(1);
       }
       iarg++ ; continue ;
     }

     fprintf(stderr,"** Illegal option: %s\n",argv[iarg]); exit(1);
   }

   if( iarg >= argc-1 ){
     fprintf(stderr,"** Not enough arguments on command line!\n"); exit(1);
   }

   aname = argv[iarg++] ;
   if( !THD_filename_ok(aname) ){
     fprintf(stderr,"** Illegal aname string %s\n",aname) ;
     exit(1) ;
   }
   fname = malloc( strlen(aname)+16 ) ;

   dset = THD_open_dataset( argv[iarg++] ); CHECK_OPEN_ERROR(dset,argv[iarg-1]);

   if( xxor >= 0 ){  /* 19 Mar 2003: figure how to flip */
     xdir = THD_get_axis_direction( dset->daxes , xxor ) ;
     ydir = THD_get_axis_direction( dset->daxes , yyor ) ;
     zdir = THD_get_axis_direction( dset->daxes , zzor ) ;
     if(              ydir == 0 || zdir == 0 ) xdir = 0 ;
     if( xdir == 1 && ydir == 2 && zdir == 3 ) xdir = 0 ;
   }
   if( xdir != 0 ){
     float dx=fabs(DSET_DX(dset)) ,
           dy=fabs(DSET_DY(dset)) ,
           dz=fabs(DSET_DZ(dset))  ;
     DSET_mallocize(dset) ;
     switch( xdir ){
       case 1: case -1: xdel = dx ; break ;
       case 2: case -2: xdel = dy ; break ;
       case 3: case -3: xdel = dz ; break ;
     }
     switch( ydir ){
       case 1: case -1: ydel = dx ; break ;
       case 2: case -2: ydel = dy ; break ;
       case 3: case -3: ydel = dz ; break ;
     }
     switch( zdir ){
       case 1: case -1: zdel = dx ; break ;
       case 2: case -2: zdel = dy ; break ;
       case 3: case -3: zdel = dz ; break ;
     }
   } else {
     xdel = fabs(DSET_DX(dset)) ;
     ydel = fabs(DSET_DY(dset)) ;
     zdel = fabs(DSET_DZ(dset)) ;
   }

   DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ;

   /* determine if we scale to floats */

   scl = THD_need_brick_factor( dset ) ;

   /* 30 Sep 2002: if doing a 4D file, write single .hdr now */

   if( do_4D ){
     im = mri_empty_conforming( DSET_BRICK(dset,0) ,
                                (scl) ? MRI_float
                                      : DSET_BRICK_TYPE(dset,0) ) ;

     if( xdir != 0 ){
       qim = mri_flip3D( xdir,ydir,zdir , im ) ;
       if( qim == NULL){
         fprintf(stderr,"mri_flip3D fails?!\n"); exit(1);
       }
       mri_free(im); im = qim;
     }

     im->dx = xdel ;                    /* load voxel sizes */
     im->dy = ydel ;
     im->dz = zdel ;
     im->dw = 1.0 ;

     if( AFNI_yesenv("AFNI_ANALYZE_ORIGINATOR") ){
       im->xo = dset->daxes->xxorg ;                    /* load voxel origin */
       im->yo = dset->daxes->yyorg ;                    /* 03/11/04 KRH added this bit for SPM */
       im->zo = dset->daxes->zzorg ;
       if( ORIENT_sign[dset->daxes->xxorient] == '-' ){
         im->dx = -im->dx ;
         /* im->xo = -im->xo ; */
       }
       if( ORIENT_sign[dset->daxes->yyorient] == '-' ){
         im->dy = -im->dy ;
         /* im->yo = -im->yo ; */
       }
       if( ORIENT_sign[dset->daxes->zzorient] == '-' ){
         im->dz = -im->dz ;
         /* im->zo = -im->zo ; */
       }
     }

     im->nt = DSET_NVALS(dset) ;        /* add a time axis */
     im->dt = DSET_TR(dset) ;
     if( im->dt <= 0.0 ) im->dt = 1.0 ;
     if( DSET_TIMEUNITS(dset) == UNITS_MSEC_TYPE ) im->dt *= 0.001 ; /* 05 Jul 2005 */

     mri_write_analyze( aname , im ) ;  /* output 4D .hdr file */
     mri_free(im) ;

     sprintf(fname,"%s.img",aname) ;    /* open output .img file */
     ifp = fopen( fname , "wb" ) ;
     if( ifp == NULL ){
       fprintf(stderr,"** Can't open file %s for output!\n",fname) ;
       exit(1) ;
     }
   }

   /* loop over sub-bricks */

   for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ){

      im = DSET_BRICK(dset,ii) ;             /* get the sub-brick */

      if( scl ){                             /* scale it to floats */
        fac = DSET_BRICK_FACTOR(dset,ii) ;
        if( fac == 0.0 ) fac = 1.0 ;
        qim = mri_scale_to_float( fac , im ) ;
      } else {
        qim = im ;
      }

      if( xdir != 0 ){                       /* 19 Mar 2003: flip it */
        MRI_IMAGE *fim ;
        fim = mri_flip3D( xdir,ydir,zdir , qim ) ;
        if( fim == NULL ){
          fprintf(stderr,"mri_flip3D fails at ii=%d ?!\n",ii); exit(1);
        }
        if( qim != im ) mri_free(qim) ;
        qim = fim ;
      }

      if( do_4D ){                           /* 30 Sep 2002: write into 4D .img file */

        fwrite( mri_data_pointer(qim) , qim->nvox , qim->pixel_size , ifp ) ;

      } else {                               /* write separate 3D .hdr/.img files */

        qim->dx = xdel ;    /* load voxel sizes */
        qim->dy = ydel ;
        qim->dz = zdel ;
        qim->dw = 1.0 ;

        if( AFNI_yesenv("AFNI_ANALYZE_ORIGINATOR") ){
          qim->xo = dset->daxes->xxorg ;                    /* load voxel origin */
          qim->yo = dset->daxes->yyorg ;                    /* 03/11/04 KRH added this bit for SPM */
          qim->zo = dset->daxes->zzorg ;

          if( ORIENT_sign[dset->daxes->xxorient] == '-' ){
            qim->dx   = -qim->dx   ;
            /* qim->xo = -qim->xo ; */
          }
          if( ORIENT_sign[dset->daxes->yyorient] == '-' ){
            qim->dy   = -qim->dy   ;
            /* qim->yo = -qim->yo ; */
          }
          if( ORIENT_sign[dset->daxes->zzorient] == '-' ){
            qim->dz   = -qim->dz   ;
            /* qim->zo = -qim->zo ; */
          }
        }

        sprintf(fname,"%s_%04d",aname,ii) ;  /* make up a filename */
        mri_write_analyze( fname , qim ) ;   /* do the real work */
      }

      if( qim != im ) mri_free(qim) ;
      DSET_unload_one(dset,ii) ;             /* clean up the trash */
   }

   if( ifp != NULL ) fclose(ifp) ;           /* 30 Sep 2002 */

   free(fname) ; exit(0) ;
}
int main( int argc , char * argv[] )
{
   THD_dfvec3 *xx , *yy , dv ;
   int nvec=0 , ii,jj, iarg ;
   THD_dvecmat rt , rtinv ;
   THD_dmat33  pp,ppt , rr ;
   THD_dfvec3  tt ;

   THD_3dim_dataset *mset=NULL , *dset=NULL ;
   double *ww=NULL ;
   int     nww=0 ;
   int keeptags=1 , wtval=0 , verb=0 , dummy=0 ;
   char * prefix = "tagalign" , *mfile=NULL ;

   float *fvol , cbot,ctop , dsum ;
   int nval , nvox , clipit , ival, RMETH=MRI_CUBIC;

   float matar[12] ;

   int use_3dWarp=1 , matrix_type=ROTATION ;

   mainENTRY("3dTagalign main");
   
   /*--- help? ---*/

   /*- scan args -*/
   iarg = 1 ; RMETH=MRI_CUBIC;
   while( iarg < argc && argv[iarg][0] == '-' ){

      /*-----*/

      if( strcmp(argv[iarg],"-h") == 0 ||
          strcmp(argv[iarg],"-help") == 0){   /* 22 Apr 2003 */
        usage_3dTagalign(strlen(argv[iarg]) > 3 ? 2:1);
        exit(0);
      }
      
     /*-----*/

     if( strcmp(argv[iarg],"-NN")     == 0 ){
       RMETH = MRI_NN ; iarg++ ; continue ;
     }
     if( strcmp(argv[iarg],"-linear") == 0 ){
       RMETH = MRI_LINEAR ; iarg++ ; continue ;
     }
     if( strcmp(argv[iarg],"-cubic")  == 0 ){
       RMETH = MRI_CUBIC ; iarg++ ; continue ;
     }
     if( strcmp(argv[iarg],"-quintic") == 0 ){
       RMETH = MRI_QUINTIC ; iarg++ ; continue ;  
     }

      /*-----*/

      if( strcmp(argv[iarg],"-rotate") == 0 ){   /* 22 Apr 2003 */
        matrix_type = ROTATION ; use_3dWarp = 1 ;
        iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-affine") == 0 ){   /* 21 Apr 2003 */
        matrix_type = AFFINE ; use_3dWarp = 1 ;
        iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-rotscl") == 0 ){   /* 22 Apr 2003 */
        matrix_type = ROTSCL ; use_3dWarp = 1 ;
        iarg++ ; continue ;
      }

#if 0
      /*-----*/

      if( strcmp(argv[iarg],"-3dWarp") == 0 ){   /* 21 Apr 2003 */
        use_3dWarp = 1 ;
        iarg++ ; continue ;
      }
#endif

      /*-----*/

      if( strcmp(argv[iarg],"-master") == 0 ){
         if( mset != NULL )                    ERREX("Can only have one -master option") ;
         if( ++iarg >= argc )                  ERREX("Need an argument after -master") ;

         mset = THD_open_dataset( argv[iarg] ) ;

         if( mset == NULL )                    ERREX("Can't open -master dataset") ;
         if( mset->tagset == NULL )            ERREX("No tags in -master dataset") ;
         if( TAGLIST_COUNT(mset->tagset) < 3 ) ERREX("Not enough tags in -master dataset") ;

         for( nvec=ii=0 ; ii < TAGLIST_COUNT(mset->tagset) ; ii++ )
            if( TAG_SET(TAGLIST_SUBTAG(mset->tagset,ii)) ) nvec++ ;

         if( nvec < 3 )                        ERREX("Not enough tags set in -master dataset") ;

         if( nvec < TAGLIST_COUNT(mset->tagset) )
            fprintf(stderr,"++ WARNING: not all tags are set in -master dataset\n") ;

         if( verb ) fprintf(stderr,"++ Found %d tags in -master dataset\n",nvec) ;

         iarg++ ; continue ;
      }

#if 0
      /*-----*/

      if( strcmp(argv[iarg],"-wtval") == 0 ){
         if( ww != NULL )                      ERREX("Can't have -wtval after -wt1D") ;
         wtval++ ;
         iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-wt1D") == 0 ){
         MRI_IMAGE * wtim ; float * wtar ;

         if( wtval )                           ERREX("Can't have -wt1D after -wtval") ;
         if( ww != NULL )                      ERREX("Can't have two -wt1D options!") ;
         if( ++iarg >= argc )                  ERREX("Need an argument after -wt1D") ;

         wtim = mri_read_1D( argv[iarg] ) ;

         if( wtim == NULL )                    ERREX("Can't read -wtim file") ;
         if( wtim->ny > 1 )                    ERREX("-wtim file has more than one columm") ;

         wtar = MRI_FLOAT_PTR(wtim) ;
         ww   = (double *) malloc(sizeof(double)*wtim->nx) ; nww = wtim->nx ;
         for( ii=0 ; ii < nww ; ii++ ){
            ww[ii] = (double) wtar[ii] ;
            if( ww[ii] < 0.0 )                 ERREX("Negative value found in -wt1D file") ;
         }

         mri_free(wtim) ;
         iarg++ ; continue ;
      }
#endif

      /*-----*/

      if( strcmp(argv[iarg],"-nokeeptags") == 0 ){
         keeptags = 0 ;
         iarg++ ; continue ;
      }

      /*-----*/

      if( strncmp(argv[iarg],"-verb",5) == 0 ){
         verb++ ;
         iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-dummy") == 0 ){
         dummy++ ;
         iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-prefix") == 0 ){
         if( ++iarg >= argc )                  ERREX("Need an argument after -prefix") ;
         prefix = argv[iarg] ;
         if( !THD_filename_ok(prefix) )        ERREX("-prefix string is illegal") ;
         iarg++ ; continue ;
      }

      /*-----*/

      if( strcmp(argv[iarg],"-matvec") == 0 ){
         if( ++iarg >= argc )                  ERREX("Need an argument after -matvec") ;
         mfile = argv[iarg] ;
         if( !THD_filename_ok(mfile) )         ERREX("-matvec string is illegal") ;
         iarg++ ; continue ;
      }


      /*-----*/

      fprintf(stderr,"** Unknown option: %s\n",argv[iarg]) ; 
      suggest_best_prog_option(argv[0], argv[iarg]);
      exit(1) ;

   } /* end of scanning command line for options */

   if( argc < 2 ){
      ERROR_message("Too few options");
      usage_3dTagalign(0);
      exit(1) ;
   }


   if( mset == NULL )                    ERREX("No -master option found on command line") ;

#if 0
   if( ww != NULL && nww < nvec )        ERREX("Not enough weights found in -wt1D file") ;

   /*-- if -wtval, setup weights from master tag values --*/

   if( wtval ){
      ww = (double *) malloc(sizeof(double)*nvec) ; nww = nvec ;
      for( ii=jj=0 ; ii < TAGLIST_COUNT(mset->tagset) ; ii++ ){
         if( TAG_SET(TAGLIST_SUBTAG(mset->tagset,ii)) ){
            ww[jj] = (double) TAG_VAL(TAGLIST_SUBTAG(mset->tagset,ii)) ;

            if( ww[jj] < 0.0 )           ERREX("Negative value found in -master tag values") ;
            jj++ ;
         }
      }
   }
#endif

   /*-- read input dataset (to match to master dataset) --*/

   if( iarg >= argc )                    ERREX("No input dataset?") ;

   dset = THD_open_dataset( argv[iarg] ) ;

   if( dset == NULL )                    ERREX("Can't open input dataset") ;
   if( dset->tagset == NULL )            ERREX("No tags in input dataset") ;
   if( TAGLIST_COUNT(dset->tagset) !=
       TAGLIST_COUNT(mset->tagset)   )   ERREX("Tag counts don't match in -master and input") ;

   /* check if set tags match exactly */

   for( ii=0 ; ii < TAGLIST_COUNT(mset->tagset) ; ii++ ){
      if( TAG_SET(TAGLIST_SUBTAG(mset->tagset,ii)) !=
          TAG_SET(TAGLIST_SUBTAG(dset->tagset,ii))    )
                                         ERREX("Set tags don't match in -master and input") ;
   }

   /*-- load vector lists: xx=master, yy=input --*/

   xx = (THD_dfvec3 *) malloc( sizeof(THD_dfvec3) * nvec ) ;
   yy = (THD_dfvec3 *) malloc( sizeof(THD_dfvec3) * nvec ) ;
   dsum = 0.0 ;
   for( ii=jj=0 ; ii < nvec ; ii++ ){
      if( TAG_SET(TAGLIST_SUBTAG(mset->tagset,ii)) ){

         LOAD_DFVEC3( xx[jj] ,                                      /* N.B.:     */
                     TAG_X( TAGLIST_SUBTAG(mset->tagset,ii) ) ,     /* these are */
                     TAG_Y( TAGLIST_SUBTAG(mset->tagset,ii) ) ,     /* in Dicom  */
                     TAG_Z( TAGLIST_SUBTAG(mset->tagset,ii) )  ) ;  /* order now */

         LOAD_DFVEC3( yy[jj] ,
                     TAG_X( TAGLIST_SUBTAG(dset->tagset,ii) ) ,
                     TAG_Y( TAGLIST_SUBTAG(dset->tagset,ii) ) ,
                     TAG_Z( TAGLIST_SUBTAG(dset->tagset,ii) )  ) ;

         dv    = SUB_DFVEC3( xx[jj] , yy[jj] ) ;
         dsum += dv.xyz[0]*dv.xyz[0] + dv.xyz[1]*dv.xyz[1] + dv.xyz[2]*dv.xyz[2] ;

         jj++ ;
      }
   }

   dsum = sqrt(dsum/nvec) ;
   fprintf(stderr,"++ RMS distance between tags before = %.2f mm\n" , dsum ) ;

   /*-- compute best transformation from mset to dset coords --*/

   switch( matrix_type ){
     default:
     case ROTATION:
       rt = DLSQ_rot_trans( nvec , yy , xx , ww ) ;  /* in thd_rot3d.c */
     break ;

     case AFFINE:
       rt = DLSQ_affine   ( nvec , yy , xx ) ;       /* 21 Apr 2003 */
     break ;

     case ROTSCL:
       rt = DLSQ_rotscl   ( nvec , yy , xx , (DSET_NZ(dset)==1) ? 2 : 3 ) ;
     break ;
   }
   rtinv = INV_DVECMAT(rt) ;

   /*-- check for floating point legality --*/

   nval = 0 ;
   for( ii=0 ; ii < 3 ; ii++ ){
      dsum = rt.vv.xyz[ii] ; nval += thd_floatscan(1,&dsum) ;
      for( jj=0 ; jj < 3 ; jj++ ){
         dsum = rt.mm.mat[ii][jj] ; nval += thd_floatscan(1,&dsum) ;
      }
   }
   if( nval > 0 ){
      fprintf(stderr,"** Floating point errors during calculation\n"
                     "** of transform matrix and translation vector\n" ) ;
      exit(1) ;
   }

   /*-- check for rotation matrix legality --*/

   dsum = DMAT_DET(rt.mm) ;

   if( dsum == 0.0 || (matrix_type == ROTATION && fabs(dsum-1.0) > 0.01) ){
     fprintf(stderr,"** Invalid transform matrix computed: tags dependent?\n"
                    "** computed [matrix] and [vector] follow:\n" ) ;

     for( ii=0 ; ii < 3 ; ii++ )
       fprintf(stderr,"  [ %10.5f %10.5f %10.5f ]   [ %10.5f ] \n",
               rt.mm.mat[ii][0],rt.mm.mat[ii][1],rt.mm.mat[ii][2],rt.vv.xyz[ii] );

     exit(1) ;
   }

   /*-- print summary --*/

   if( verb ){
     fprintf(stderr,"++ Matrix & Vector [Dicom: x=R-L; y=A-P; z=I-S]\n") ;
     for( ii=0 ; ii < 3 ; ii++ )
       fprintf(stderr,"    %10.5f %10.5f %10.5f   %10.5f\n",
               rt.mm.mat[ii][0],rt.mm.mat[ii][1],rt.mm.mat[ii][2],rt.vv.xyz[ii] );
   }

   if( matrix_type == ROTATION || matrix_type == ROTSCL ){
     double theta, costheta , dist , fac=1.0 ;

     if( matrix_type == ROTSCL ){
       fac = DMAT_DET(rt.mm); fac = fabs(fac);
       if( DSET_NZ(dset) == 1 ) fac = sqrt(fac) ;
       else                     fac = cbrt(fac) ;
     }

     costheta = 0.5 * sqrt(1.0 + DMAT_TRACE(rt.mm)/fac ) ;
     theta    = 2.0 * acos(costheta) * 180/3.14159265 ;
     dist     = SIZE_DFVEC3(rt.vv) ;

     fprintf(stderr,"++ Total rotation=%.2f degrees; translation=%.2f mm; scaling=%.2f\n",
             theta,dist,fac) ;
   }

   if( mfile ){
      FILE * mp ;

      if( THD_is_file(mfile) )
         fprintf(stderr,"++ Warning: -matvec will overwrite file %s\n",mfile) ;

      mp = fopen(mfile,"w") ;
      if( mp == NULL ){
         fprintf(stderr,"** Can't write to -matvec %s\n",mfile) ;
      } else {
        for( ii=0 ; ii < 3 ; ii++ )
          fprintf(mp,"    %10.5f %10.5f %10.5f   %10.5f\n",
                  rt.mm.mat[ii][0],rt.mm.mat[ii][1],rt.mm.mat[ii][2],rt.vv.xyz[ii] );
        fclose(mp) ;
        if( verb ) fprintf(stderr,"++ Wrote matrix+vector to %s\n",mfile) ;
      }
   }

   if( dummy ){
      fprintf(stderr,"++ This was a -dummy run: no output dataset\n") ; exit(0) ;
   }

   /*-- 21 Apr 2003: transformation can be done the old way (a la 3drotate),
                     or the new way (a la 3dWarp).                          --*/

#if 0
   if( !use_3dWarp ){          /**** the old way ****/

     /*-- now must scramble the rotation matrix and translation
          vector from Dicom coordinate order to dataset brick order --*/

     pp  = DBLE_mat_to_dicomm( dset ) ;
     ppt = TRANSPOSE_DMAT(pp) ;
     rr  = DMAT_MUL(ppt,rt.mm) ; rr = DMAT_MUL(rr,pp) ; tt = DMATVEC(ppt,rt.vv) ;

     /*-- now create the output dataset by screwing with the input dataset
          (this code is adapted from 3drotate.c)                           --*/

     DSET_mallocize(dset) ;
     DSET_load( dset ) ;  CHECK_LOAD_ERROR(dset) ;
     dset->idcode = MCW_new_idcode() ;
     dset->dblk->diskptr->storage_mode = STORAGE_BY_BRICK ; /* 14 Jan 2004 */
     EDIT_dset_items( dset ,
                         ADN_prefix , prefix ,
                         ADN_label1 , prefix ,
                      ADN_none ) ;

     if( !THD_ok_overwrite() && 
         (THD_deathcon() && THD_is_file(dset->dblk->diskptr->header_name) )){
        fprintf(stderr,
                "** Output file %s already exists -- cannot continue!\n",
                dset->dblk->diskptr->header_name ) ;
        exit(1) ;
     }

     tross_Make_History( "3dTagalign" , argc,argv , dset ) ;

     /*-- if desired, keep old tagset --*/

     if( keeptags ){
        THD_dfvec3 rv ;

        dsum = 0.0 ;
        for( jj=ii=0 ; ii < TAGLIST_COUNT(dset->tagset) ; ii++ ){
           if( TAG_SET(TAGLIST_SUBTAG(dset->tagset,ii)) ){
              rv = DMATVEC( rt.mm , yy[jj] ) ;                     /* operating on */
              rv = ADD_DFVEC3( rt.vv , rv ) ;                      /* Dicom order  */

              dv    = SUB_DFVEC3( xx[jj] , rv ) ;
              dsum += dv.xyz[0]*dv.xyz[0] + dv.xyz[1]*dv.xyz[1]
                                          + dv.xyz[2]*dv.xyz[2] ;

              UNLOAD_DFVEC3( rv , TAG_X( TAGLIST_SUBTAG(dset->tagset,ii) ) ,
                                  TAG_Y( TAGLIST_SUBTAG(dset->tagset,ii) ) ,
                                  TAG_Z( TAGLIST_SUBTAG(dset->tagset,ii) )  ) ;

              jj++ ;
           }
        }
        dsum = sqrt(dsum/nvec) ;
        fprintf(stderr,"++ RMS distance between tags after  = %.2f mm\n" , dsum ) ;

     } else {
        myXtFree(dset->tagset) ;  /* send it to the dustbin */
     }

     /*-- rotate sub-bricks --*/

     if( verb ) fprintf(stderr,"++ computing output BRIK") ;

     nvox = DSET_NVOX(dset) ;
     nval = DSET_NVALS(dset) ;
     fvol = (float *) malloc( sizeof(float) * nvox ) ;

     THD_rota_method( MRI_HEPTIC ) ;
     clipit = 1 ;

     for( ival=0 ; ival < nval ; ival++ ){

        /*- get sub-brick out of dataset -*/

        EDIT_coerce_type( nvox ,
                          DSET_BRICK_TYPE(dset,ival),DSET_ARRAY(dset,ival) ,
                          MRI_float,fvol ) ;

        if( clipit ){
           register int ii ; register float bb,tt ;
           bb = tt = fvol[0] ;
           for( ii=1 ; ii < nvox ; ii++ ){
                   if( fvol[ii] < bb ) bb = fvol[ii] ;
              else if( fvol[ii] > tt ) tt = fvol[ii] ;
           }
           cbot = bb ; ctop = tt ;
        }

        if( verb && nval < 5 ) fprintf(stderr,".") ;

        /*- rotate it -*/

        THD_rota_vol_matvec( DSET_NX(dset) , DSET_NY(dset) , DSET_NZ(dset) ,
                             fabs(DSET_DX(dset)) , fabs(DSET_DY(dset)) ,
                                                   fabs(DSET_DZ(dset)) ,
                             fvol , rr , tt ) ;

        if( verb ) fprintf(stderr,".") ;

        if( clipit ){
           register int ii ; register float bb,tt ;
           bb = cbot ; tt = ctop ;
           for( ii=0 ; ii < nvox ; ii++ ){
                   if( fvol[ii] < bb ) fvol[ii] = bb ;
              else if( fvol[ii] > tt ) fvol[ii] = tt ;
           }
        }

        if( verb && nval < 5 ) fprintf(stderr,".") ;

        /*- put it back into dataset -*/

        EDIT_coerce_type( nvox, MRI_float,fvol ,
                                DSET_BRICK_TYPE(dset,ival),DSET_ARRAY(dset,ival) );

     } /* end of loop over sub-brick index */

     if( verb ) fprintf(stderr,":") ;

     /* save matrix+vector into dataset, too */

     UNLOAD_DMAT(rt.mm,matar[0],matar[1],matar[2],
                       matar[4],matar[5],matar[6],
                       matar[8],matar[9],matar[10] ) ;
     UNLOAD_DFVEC3(rt.vv,matar[3],matar[7],matar[11]) ;
     THD_set_atr( dset->dblk, "TAGALIGN_MATVEC", ATR_FLOAT_TYPE, 12, matar ) ;

     /* write dataset to disk */

     dset->dblk->master_nvals = 0 ;  /* in case this was a mastered dataset */
     DSET_write(dset) ;

     if( verb ) fprintf(stderr,"\n") ;

   } else
#endif
   {   /**** the new way: use 3dWarp type transformation ****/

     THD_3dim_dataset *oset ;
     THD_vecmat tran ;

#if 0
     DFVEC3_TO_FVEC3( rt.vv , tran.vv ) ;
     DMAT_TO_MAT    ( rt.mm , tran.mm ) ;
#else
     DFVEC3_TO_FVEC3( rtinv.vv , tran.vv ) ;
     DMAT_TO_MAT    ( rtinv.mm , tran.mm ) ;
#endif

     mri_warp3D_method( RMETH ) ;
     oset = THD_warp3D_affine( dset, tran, mset, prefix, 0, WARP3D_NEWDSET ) ;
     if( oset == NULL ){
       fprintf(stderr,"** ERROR: THD_warp3D() fails!\n"); exit(1);
     }

     tross_Copy_History( dset , oset ) ;
     tross_Make_History( "3dTagalign" , argc,argv , oset ) ;

     UNLOAD_DMAT(rt.mm,matar[0],matar[1],matar[2],
                       matar[4],matar[5],matar[6],
                       matar[8],matar[9],matar[10] ) ;
     UNLOAD_DFVEC3(rt.vv,matar[3],matar[7],matar[11]) ;
     THD_set_atr( oset->dblk, "TAGALIGN_MATVEC", ATR_FLOAT_TYPE, 12, matar ) ;

     /*-- if desired, keep old tagset --*/

     if( keeptags ){
        THD_dfvec3 rv ;

        oset->tagset = myXtNew(THD_usertaglist) ;
        *(oset->tagset) = *(dset->tagset) ;

        dsum = 0.0 ;
        for( jj=ii=0 ; ii < TAGLIST_COUNT(oset->tagset) ; ii++ ){
          if( TAG_SET(TAGLIST_SUBTAG(oset->tagset,ii)) ){
            rv = DMATVEC( rt.mm , yy[jj] ) ;
            rv = ADD_DFVEC3( rt.vv , rv ) ;

            dv    = SUB_DFVEC3( xx[jj] , rv ) ;
            dsum += dv.xyz[0]*dv.xyz[0] + dv.xyz[1]*dv.xyz[1]
                                        + dv.xyz[2]*dv.xyz[2] ;

            UNLOAD_DFVEC3( rv , TAG_X( TAGLIST_SUBTAG(oset->tagset,ii) ) ,
                                TAG_Y( TAGLIST_SUBTAG(oset->tagset,ii) ) ,
                                TAG_Z( TAGLIST_SUBTAG(oset->tagset,ii) )  ) ;

            jj++ ;
          }
        }
        dsum = sqrt(dsum/nvec) ;
        fprintf(stderr,"++ RMS distance between tags after  = %.2f mm\n" , dsum ) ;
     }

     DSET_write(oset) ;

   } /* end of 3dWarp-like work */

   exit(0) ;
}
Exemple #9
0
MRI_vectim * THD_2dset_to_vectim( THD_3dim_dataset *dset1, byte *mask1 ,
                                  THD_3dim_dataset *dset2, byte *mask2 ,
                                  int ignore )
{
   byte *mmmv[2]={NULL, NULL}, *mmmt=NULL;
   THD_3dim_dataset *dsetv[2]={NULL, NULL};
   MRI_vectim *mrv=NULL ;
   int kk2, kk,iv,id, nvals , nvoxv[2]={0,0} , nmaskv[2]={0,0} ;
   int *ivvectmp=NULL;

ENTRY("THD_2dset_to_vectim") ;
   mmmv[0] = mask1;
   mmmv[1] = mask2;
   dsetv[0] = dset1;
   dsetv[1] = dset2;
   for (id=0; id<2;++id) {
                             if( !ISVALID_DSET(dsetv[id]) ) RETURN(NULL) ;
      DSET_load(dsetv[id]) ; if( !DSET_LOADED(dsetv[id])  ) RETURN(NULL) ;
      nvoxv[id] = DSET_NVOX(dsetv[id]) ;
   }
   if (DSET_NVALS(dsetv[0]) != DSET_NVALS(dsetv[1])) {
      RETURN(NULL) ;
   }

   if( ignore < 0 ) ignore = 0 ;
   nvals  = DSET_NVALS(dsetv[0]) - ignore ; if( nvals <= 0 ) RETURN(NULL) ;

   for (id=0; id<2; ++id) {
      if( mmmv[id] != NULL ){
         nmaskv[id] = THD_countmask( nvoxv[id] , mmmv[id] ) ;/* number to keep */
         if( nmaskv[id] <= 0 ) RETURN(NULL) ;
      } else {
         nmaskv[id] = nvoxv[id] ;                         /* keep them all */
#pragma omp critical (MALLOC)
         mmmv[id]   = (byte *)malloc(sizeof(byte)*nmaskv[id]) ;
         if( mmmv[id] == NULL ){
            ERROR_message("THD_2dset_to_vectim: out of memory") ;
            RETURN(NULL) ;
         }
         memset( mmmv[id] , 1 , sizeof(byte)*nmaskv[id] ) ;
      }
   }

#pragma omp critical (MALLOC)
   mrv = (MRI_vectim *)malloc(sizeof(MRI_vectim)) ;

   mrv->nvec   = nmaskv[0]+nmaskv[1] ;
   mrv->nvals  = nvals ;
   mrv->ignore = ignore ;
#pragma omp critical (MALLOC)
   mrv->ivec   = (int *)malloc(sizeof(int)*(nmaskv[0]+nmaskv[1])) ;
#pragma omp critical (MALLOC)
   ivvectmp    = (int *)malloc(sizeof(int)*(nmaskv[1])) ;
   if( mrv->ivec == NULL || ivvectmp == NULL){
     ERROR_message("THD_2dset_to_vectim: out of memory") ;
     if (mrv->ivec) free(mrv->ivec) ;
     if (ivvectmp)  free(ivvectmp) ;
     free(mrv) ;
     if( mmmv[0] != mask1 ) free(mmmv[0]) ;
     if( mmmv[1] != mask2 ) free(mmmv[1]) ;
     RETURN(NULL) ;
   }
#pragma omp critical (MALLOC)
   mrv->fvec  = (float *)malloc(sizeof(float)*(nmaskv[0]+nmaskv[1])*(size_t)nvals) ;
   if( mrv->fvec == NULL ){
     ERROR_message("THD_2dset_to_vectim: out of memory") ;
     if (ivvectmp)  free(ivvectmp) ;
     free(mrv->ivec) ; free(mrv) ;
     if( mmmv[0] != mask1 ) free(mmmv[0]) ;
     if( mmmv[1] != mask2 ) free(mmmv[1]) ;
     RETURN(NULL) ;
   }

   /* store desired voxel time series */

   mmmt = mmmv[0];
   for( kk=iv=0 ; iv < nvoxv[0] ; iv++ ){
     if( mmmt[iv] ) mrv->ivec[kk++] = iv ;  /* build index list to 1st dset */
   }
   mmmt = mmmv[1]; kk2 = 0;
   for(    iv=0 ; iv < nvoxv[1] ; iv++ ){
     if( mmmt[iv] ) {
                        mrv->ivec[kk++] = iv + nvoxv[0] ;
                                             /* build index list to 2nd dset*/
                        ivvectmp[kk2++] = iv;
     }
   }

   if( ignore > 0 ){  /* extract 1 at a time, save what we want */

#pragma omp critical (MALLOC)
     float *var = (float *)malloc(sizeof(float)*(nvals+ignore)) ;
     mmmt = mmmv[0];
     for( kk=iv=0 ; iv < nvoxv[0] ; iv++ ){
       if( mmmt[iv] == 0 ) continue ;
       (void)THD_extract_array( iv , dsetv[0] , 0 , var ) ;
       AAmemcpy( VECTIM_PTR(mrv,kk) , var+ignore , sizeof(float)*nvals ) ;
       kk++ ;
     }
     mmmt = mmmv[1];
     for(    iv=0 ; iv < nvoxv[1] ; iv++ ){
       if( mmmt[iv] == 0 ) continue ;
       (void)THD_extract_array( iv , dsetv[1] , 0 , var ) ;
       AAmemcpy( VECTIM_PTR(mrv,kk) , var+ignore , sizeof(float)*nvals ) ;
       kk++ ;
     }

     free(var) ;

   } else {  /* do all at once: this way is a lot faster */

     THD_extract_many_arrays( nmaskv[0] ,  mrv->ivec  ,
                               dsetv[0] ,   mrv->fvec  ) ;
     THD_extract_many_arrays( nmaskv[1] ,  ivvectmp,
                               dsetv[1] ,  (mrv->fvec+(size_t)nmaskv[0]*(size_t)mrv->nvals) ) ;

   }

   mrv->nx = DSET_NX(dsetv[0]) + DSET_NX(dsetv[1]);
   mrv->dx = fabs(DSET_DX(dsetv[0])) ;
   mrv->ny = DSET_NY(dsetv[0]) ; mrv->dy = fabs(DSET_DY(dsetv[0])) ;
   mrv->nz = DSET_NZ(dsetv[0]) ; mrv->dz = fabs(DSET_DZ(dsetv[0])) ;

   DSET_UNMSEC(dsetv[0]) ; mrv->dt = DSET_TR(dsetv[0]) ;
   if( mrv->dt <= 0.0f ) mrv->dt = 1.0f ;

   if( mmmv[0] != mask1 ) free(mmmv[0]) ;
   if( mmmv[1] != mask2 ) free(mmmv[1]) ;
   if (ivvectmp)  free(ivvectmp) ;

   if (0) {
     int ShowThisTs=38001;
     float *fff=NULL;
     fprintf(stderr,"++ ZSS mrv->nvec = %d, mrv->nvals = %d\n",
                    mrv->nvec, mrv->nvals);
     for( kk=0 ; kk < mrv->nvals; ++kk) {
      fff=mrv->fvec+((size_t)mrv->nvals*(size_t)ShowThisTs);
      fprintf(stderr," %f \t", *(fff+kk));
     }
   }

   VECTIM_scan(mrv) ; /* 09 Nov 2010 */
   RETURN(mrv) ;
}
Exemple #10
0
MRI_vectim * THD_dset_to_vectim_stend( THD_3dim_dataset *dset, byte *mask , int start, int end )
{
   byte *mmm=mask ;
   MRI_vectim *mrv=NULL ;
   int kk,iv , nvals , nvox , nmask ;

ENTRY("THD_dset_to_vectim_stend") ;

                     if( !ISVALID_DSET(dset) ) RETURN(NULL) ;
   DSET_load(dset) ; if( !DSET_LOADED(dset)  ) RETURN(NULL) ;

   if( start < 0     ) start = 0 ;
   if( end   < start ) end   = DSET_NVALS(dset)-1 ;
   nvals = end - start + 1 ; if( nvals <= 0 ) RETURN(NULL) ;
   nvox  = DSET_NVOX(dset) ;

   if( mmm != NULL ){
     nmask = THD_countmask( nvox , mmm ) ;  /* number to keep */
     if( nmask <= 0 ) RETURN(NULL) ;
   } else {
     nmask = nvox ;                         /* keep them all */
#pragma omp critical (MALLOC)
     mmm   = (byte *)malloc(sizeof(byte)*nmask) ;
     if( mmm == NULL ){
       ERROR_message("THD_dset_to_vectim: out of memory") ;
       RETURN(NULL) ;
     }
     memset( mmm , 1 , sizeof(byte)*nmask ) ;
   }

#pragma omp critical (MALLOC)
   mrv = (MRI_vectim *)malloc(sizeof(MRI_vectim)) ;

   mrv->nvec   = nmask ;
   mrv->nvals  = nvals ;
   mrv->ignore = start ;
#pragma omp critical (MALLOC)
   mrv->ivec   = (int *)malloc(sizeof(int)*nmask) ;
   if( mrv->ivec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory") ;
     free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   }
#pragma omp critical (MALLOC)
   mrv->fvec  = (float *)malloc(sizeof(float)*(size_t)nmask*(size_t)nvals) ;
   if( mrv->fvec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory") ;
     free(mrv->ivec) ; free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   }

   /* store desired voxel time series */

   for( kk=iv=0 ; iv < nvox ; iv++ ){
     if( mmm[iv] ) mrv->ivec[kk++] = iv ;  /* build index list */
   }

   if( nvals < DSET_NVALS(dset) ){ /* extract 1 at a time, save what we want */

#pragma omp critical (MALLOC)
     float *var = (float *)malloc(sizeof(float)*(DSET_NVALS(dset))) ;
     for( kk=iv=0 ; iv < nvox ; iv++ ){
       if( mmm[iv] == 0 ) continue ;
       (void)THD_extract_array( iv , dset , 0 , var ) ;
       AAmemcpy( VECTIM_PTR(mrv,kk) , var+start , sizeof(float)*nvals ) ;
       kk++ ;
     }
     free(var) ;

   } else {  /* do all at once: this way is a lot faster */

     THD_extract_many_arrays( nmask , mrv->ivec , dset , mrv->fvec ) ;

   }

   mrv->nx = DSET_NX(dset) ; mrv->dx = fabs(DSET_DX(dset)) ;
   mrv->ny = DSET_NY(dset) ; mrv->dy = fabs(DSET_DY(dset)) ;
   mrv->nz = DSET_NZ(dset) ; mrv->dz = fabs(DSET_DZ(dset)) ;

   DSET_UNMSEC(dset) ; mrv->dt = DSET_TR(dset) ;
   if( mrv->dt <= 0.0f ) mrv->dt = 1.0f ;

   if( mmm != mask ) free(mmm) ;
   VECTIM_scan(mrv) ; /* 09 Nov 2010 */
   RETURN(mrv) ;
}
Exemple #11
0
MRI_vectim * THD_dset_to_vectim( THD_3dim_dataset *dset, byte *mask , int ignore )
{
   byte *mmm=mask ;
   MRI_vectim *mrv=NULL ;
   int kk,iv , nvals , nvox , nmask ;
   size_t ntot ;

ENTRY("THD_dset_to_vectim") ;

                     if( !ISVALID_DSET(dset) ) RETURN(NULL) ;
   DSET_load(dset) ; if( !DSET_LOADED(dset)  ) RETURN(NULL) ;

   if( ignore < 0 ) ignore = 0 ;
   nvals = DSET_NVALS(dset) - ignore ; if( nvals <= 0 ) RETURN(NULL) ;
   nvox  = DSET_NVOX(dset) ;

   if( mmm != NULL ){
     nmask = THD_countmask( nvox , mmm ) ;  /* number to keep */
     if( nmask <= 0 ) RETURN(NULL) ;
   } else {
     nmask = nvox ;                         /* keep them all */
#pragma omp critical (MALLOC)
     mmm   = (byte *)malloc(sizeof(byte)*nmask) ;
     if( mmm == NULL ){
       ERROR_message("THD_dset_to_vectim: out of memory") ;
       RETURN(NULL) ;
     }
     memset( mmm , 1 , sizeof(byte)*nmask ) ;
   }

#pragma omp critical (MALLOC)
   mrv = (MRI_vectim *)malloc(sizeof(MRI_vectim)) ;

   mrv->nvec   = nmask ;
   mrv->nvals  = nvals ;
   mrv->ignore = ignore ;
#pragma omp critical (MALLOC)
   mrv->ivec   = (int *)malloc(sizeof(int)*nmask) ;
   if( mrv->ivec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory") ;
     free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   }
   ntot = sizeof(float)*(size_t)nmask*(size_t)nvals ;
#pragma omp critical (MALLOC)
   mrv->fvec  = (float *)malloc(ntot) ;
   if( mrv->fvec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory -- tried to get %lld bytes",(long long)ntot) ;
     free(mrv->ivec) ; free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   } else if( ntot > 1000000000 ){
     INFO_message("THD_dset_to_vectim: allocated %lld bytes",(long long)ntot) ;
   }

   /* store desired voxel time series */

STATUS("create index list") ;
   for( kk=iv=0 ; iv < nvox ; iv++ ){
     if( mmm[iv] ) mrv->ivec[kk++] = iv ;  /* build index list */
   }

   if( ignore > 0 ){  /* extract 1 at a time, save what we want */

#pragma omp critical (MALLOC)
     float *var = (float *)malloc(sizeof(float)*(nvals+ignore)) ;
STATUS("ignore > 0 --> extracting one at a time") ;
     for( kk=iv=0 ; iv < nvox ; iv++ ){
       if( mmm[iv] == 0 ) continue ;
       (void)THD_extract_array( iv , dset , 0 , var ) ;
       AAmemcpy( VECTIM_PTR(mrv,kk) , var+ignore , sizeof(float)*nvals ) ;
       kk++ ;
     }
     free(var) ;

   } else {  /* do all at once: this way is a lot faster */

STATUS("ignore==0 --> extracting all at once") ;
     THD_extract_many_arrays( nmask , mrv->ivec , dset , mrv->fvec ) ;

   }

STATUS("setting parameters in vectim header") ;

   mrv->nx = DSET_NX(dset) ; mrv->dx = fabs(DSET_DX(dset)) ;
   mrv->ny = DSET_NY(dset) ; mrv->dy = fabs(DSET_DY(dset)) ;
   mrv->nz = DSET_NZ(dset) ; mrv->dz = fabs(DSET_DZ(dset)) ;

   DSET_UNMSEC(dset) ; mrv->dt = DSET_TR(dset) ;
   if( mrv->dt <= 0.0f ) mrv->dt = 1.0f ;


   if( mmm != mask ){
STATUS("free(mmm)") ;
     free(mmm) ;
   }

STATUS("VECTIM_scan()") ;
   VECTIM_scan(mrv) ; /* 09 Nov 2010 */
   RETURN(mrv) ;
}
Exemple #12
0
MRI_vectim * THD_dset_censored_to_vectim( THD_3dim_dataset *dset,
                                          byte *mask , int nkeep , int *keep )
{
   byte *mmm=mask ;
   MRI_vectim *mrv=NULL ;
   int kk,iv,jj , nvals , nvox , nmask ;

ENTRY("THD_dset_censored_to_vectim") ;

   if( !ISVALID_DSET(dset) ) RETURN(NULL) ;

   if( nkeep <= 0 || keep == NULL ){
     mrv = THD_dset_to_vectim( dset , mask , 0 ) ;
     RETURN(mrv) ;
   }

   if( ! THD_subset_loaded(dset,nkeep,keep) ){
     DSET_load(dset) ; if( !DSET_LOADED(dset)  ) RETURN(NULL) ;
   }

   nvals = nkeep ;
   nvox  = DSET_NVOX(dset) ;

   if( mmm != NULL ){
     nmask = THD_countmask( nvox , mmm ) ;  /* number to keep */
     if( nmask <= 0 ) RETURN(NULL) ;
   } else {
     nmask = nvox ;                         /* keep them all */
#pragma omp critical (MALLOC)
     mmm   = (byte *)malloc(sizeof(byte)*nmask) ;
     if( mmm == NULL ){
       ERROR_message("THD_dset_to_vectim: out of memory") ;
       RETURN(NULL) ;
     }
     memset( mmm , 1 , sizeof(byte)*nmask ) ;
   }

#pragma omp critical (MALLOC)
   mrv = (MRI_vectim *)malloc(sizeof(MRI_vectim)) ;

   mrv->nvec   = nmask ;
   mrv->nvals  = nvals ;
   mrv->ignore = 0 ;
#pragma omp critical (MALLOC)
   mrv->ivec   = (int *)malloc(sizeof(int)*nmask) ;
   if( mrv->ivec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory") ;
     free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   }
#pragma omp critical (MALLOC)
   mrv->fvec  = (float *)malloc(sizeof(float)*(size_t)nmask*(size_t)nvals) ;
   if( mrv->fvec == NULL ){
     ERROR_message("THD_dset_to_vectim: out of memory") ;
     free(mrv->ivec) ; free(mrv) ; if( mmm != mask ) free(mmm) ;
     RETURN(NULL) ;
   }

   /* store desired voxel time series */

   for( kk=iv=0 ; iv < nvox ; iv++ ){
     if( mmm[iv] ) mrv->ivec[kk++] = iv ;  /* build index list */
   }

#pragma omp critical (MALLOC)
  { float *var = (float *)malloc(sizeof(float)*DSET_NVALS(dset)) ;
    float *vpt ;
     for( kk=iv=0 ; iv < nvox ; iv++ ){
       if( mmm[iv] == 0 ) continue ;
       vpt = VECTIM_PTR(mrv,kk) ; kk++ ;
       if( nkeep > 1 ){
         (void)THD_extract_array( iv , dset , 0 , var ) ;
         for( jj=0 ; jj < nkeep ; jj++ ) vpt[jj] = var[keep[jj]] ;
       } else {
         vpt[0] = THD_get_float_value(iv,keep[0],dset) ;
       }
     }
     free(var) ;
   }

   mrv->nx = DSET_NX(dset) ; mrv->dx = fabs(DSET_DX(dset)) ;
   mrv->ny = DSET_NY(dset) ; mrv->dy = fabs(DSET_DY(dset)) ;
   mrv->nz = DSET_NZ(dset) ; mrv->dz = fabs(DSET_DZ(dset)) ;

   DSET_UNMSEC(dset) ; mrv->dt = DSET_TR(dset) ;
   if( mrv->dt <= 0.0f ) mrv->dt = 1.0f ;

   if( mmm != mask ) free(mmm) ;
   VECTIM_scan(mrv) ; /* 09 Nov 2010 */
   RETURN(mrv) ;
}
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=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) ;
}
Exemple #15
0
int main(int argc, char *argv[]) {
	int i,j,k,m,n,aa,ii,jj,kk,mm,rr;
	int iarg;
	int nmask1=0;
	int nmask2=0;
	THD_3dim_dataset *insetFA = NULL, *insetV1 = NULL, 
		*insetMD = NULL, *insetL1 = NULL;
	THD_3dim_dataset *insetEXTRA=NULL; 
	THD_3dim_dataset *mset2=NULL; 
	THD_3dim_dataset *mset1=NULL; 
	THD_3dim_dataset *outsetMAP=NULL, *outsetMASK=NULL;
	char *prefix="tracky";
	int LOG_TYPE=0;
	char in_FA[300];
	char in_V1[300];
	char in_MD[300];
	char in_L1[300];
	int EXTRAFILE=0; // switch for whether other file is input as WM map

	char OUT_bin[300];
	char OUT_tracstat[300];
	char prefix_mask[300];
	char prefix_map[300];

	// FACT algopts
	FILE *fout0;
	float MinFA=0.2,MaxAngDeg=45,MinL=20.0;
	float MaxAng;
	int SeedPerV[3]={2,2,2};
	int ArrMax=0;
	float tempvmagn;
  
	int Nvox=-1;   // tot number vox
	int Dim[3]={0,0,0}; // dim in each dir
	int Nseed=0,M=30,bval=1000;
	int DimSeed[3]; // number of seeds there will be
	float Ledge[3]; // voxel edge lengths

	int *ROI1, *ROI2;
	short int *temp_arr;
	char *temp_byte; 
	int **Tforw, **Tback;
	int **Ttot;
	float **flTforw, **flTback;
	float ****coorded;
	int ****INDEX;
	int len_forw, len_back; // int count of num of squares through
	float phys_forw[1], phys_back[1];
	int idx;

	float ave_tract_len, ave_tract_len_phys;
	int inroi1, inroi2, KEEPIT; // switches for detecting
	int in[3]; // to pass to trackit
	float physin[3]; // also for trackit, physical loc, 
	int totlen; 
	float totlen_phys;
	int Numtract;

	int READS_in;
	float READS_fl;
	int end[2][3];
	int test_ind[2][3];

	int  roi3_ct=0, id=0;
	float roi3_mu_MD = 0.,roi3_mu_RD = 0.,roi3_mu_L1 = 0.,roi3_mu_FA = 0.;  
	float roi3_sd_MD = 0.,roi3_sd_RD = 0.,roi3_sd_L1 = 0.,roi3_sd_FA = 0.;  
	float tempMD,tempFA,tempRD,tempL1;
	char dset_or[4] = "RAI";
	THD_3dim_dataset *dsetn;
	int TV_switch[3] = {0,0,0};
	TAYLOR_BUNDLE *tb=NULL;
	TAYLOR_TRACT *tt=NULL;
	char *mode = "NI_fast_binary";
	NI_element *nel=NULL;
	int dump_opts=0;

	tv_io_header header1 = {.id_string = "TRACK\0", 
				.origin = {0,0,0},   
				.n_scalars = 3,
				.scal_n[0] = "FA",
				.scal_n[1] = "MD",
				.scal_n[2] = "L1",
				.n_properties = 0,
				.vox_to_ras = {{0.,0.,0.,0.},{0.,0.,0.,0.},
					       {0.,0.,0.,0.},{0.,0.,0.,0.}},
				// reset this later based on actual data set
				.voxel_order = "RAI\0", 
				.invert_x = 0,
				.invert_y = 0,
				.invert_z = 0,
				.swap_xy = 0,
				.swap_yz = 0,
				.swap_zx = 0,
				.n_count = 0,
				.version = 2,
				.hdr_size = 1000};
	
  	// for testing names...
	char *postfix[4]={"+orig.HEAD\0",".nii.gz\0",".nii\0","+tlrc.HEAD\0"};
  	int FOUND =-1;
	int RECORD_ORIG = 0; 
	float Orig[3] = {0.0,0.0,0.0};

	mainENTRY("3dTrackID"); machdep(); 
  
	// ****************************************************************
	// ****************************************************************
	//                    load AFNI stuff
	// ****************************************************************
	// ****************************************************************

	INFO_message("version: MU");

	/** scan args **/
	if (argc == 1) { usage_TrackID(1); exit(0); }
	iarg = 1;
	while( iarg < argc && argv[iarg][0] == '-' ){
		if( strcmp(argv[iarg],"-help") == 0 || 
			 strcmp(argv[iarg],"-h") == 0 ) {
			usage_TrackID(strlen(argv[iarg])>3 ? 2:1);
			exit(0);
		}
    
		if( strcmp(argv[iarg],"-verb") == 0) {
			if( ++iarg >= argc ) 
				ERROR_exit("Need argument after '-verb'") ;
			set_tract_verb(atoi(argv[iarg]));
			iarg++ ; continue ;
		}

		if( strcmp(argv[iarg],"-write_opts") == 0) {
			dump_opts=1;
			iarg++ ; continue ;
		}
    
		if( strcmp(argv[iarg],"-rec_orig") == 0) {
			RECORD_ORIG=1;
			iarg++ ; continue ;
		}
    
		if( strcmp(argv[iarg],"-tract_out_mode") == 0) {
			if( ++iarg >= argc ) 
				ERROR_exit("Need argument after '-tract_out_mode'") ;
			if (strcmp(argv[iarg], "NI_fast_binary") &&
				 strcmp(argv[iarg], "NI_fast_text") &&
				 strcmp(argv[iarg], "NI_slow_binary") &&
				 strcmp(argv[iarg], "NI_slow_text") ) {
				ERROR_message("Bad value (%s) for -tract_out_mode",argv[iarg]);
				exit(1);
			}  
			mode = argv[iarg];
			iarg++ ; continue ;
		}
    
		if( strcmp(argv[iarg],"-mask1") == 0 ){
			if( ++iarg >= argc ) 
				ERROR_exit("Need argument after '-mask1'") ;
			mset1 = THD_open_dataset( argv[iarg] ) ;
			if( mset1 == NULL ) 
				ERROR_exit("Can't open mask1 dataset '%s'", argv[iarg]) ;
			DSET_load(mset1) ; CHECK_LOAD_ERROR(mset1) ;
			nmask1 = DSET_NVOX(mset1) ;

			iarg++ ; continue ;
		}
		if( strcmp(argv[iarg],"-mask2") == 0 ){
			if( ++iarg >= argc ) 
				ERROR_exit("Need argument after '-mask2'") ;
			mset2 = THD_open_dataset( argv[iarg] ) ;
			if( mset2 == NULL ) 
				ERROR_exit("Can't open mask2 dataset '%s'",
							  argv[iarg]) ;
			DSET_load(mset2) ; CHECK_LOAD_ERROR(mset2) ;
			nmask2 = DSET_NVOX(mset2) ;
		
			iarg++ ; continue ;
		}
	 
		if( strcmp(argv[iarg],"-prefix") == 0 ){
			iarg++ ; if( iarg >= argc ) 
							ERROR_exit("Need argument after '-prefix'");
			prefix = strdup(argv[iarg]) ;
			if( !THD_filename_ok(prefix) ) 
				ERROR_exit("Illegal name after '-prefix'");
			iarg++ ; continue ;
		}
	 
		if( strcmp(argv[iarg],"-input") == 0 ){
			iarg++ ; if( iarg >= argc ) 
							ERROR_exit("Need argument after '-input'");

			for( i=0 ; i<4 ; i++) {
				sprintf(in_FA,"%s_FA%s", argv[iarg],postfix[i]); 
				if(THD_is_ondisk(in_FA)) {
					FOUND = i;
					break;
				}
			}
			insetFA = THD_open_dataset(in_FA) ;
			if( (insetFA == NULL ) || (FOUND==-1))
				ERROR_exit("Can't open dataset '%s': for FA.",in_FA);
			
			DSET_load(insetFA) ; CHECK_LOAD_ERROR(insetFA) ;
			Nvox = DSET_NVOX(insetFA) ;
			Dim[0] = DSET_NX(insetFA); Dim[1] = DSET_NY(insetFA); 
			Dim[2] = DSET_NZ(insetFA); 
			Ledge[0] = fabs(DSET_DX(insetFA)); Ledge[1] = fabs(DSET_DY(insetFA)); 
			Ledge[2] = fabs(DSET_DZ(insetFA)); 
			Orig[0] = DSET_XORG(insetFA); Orig[1] = DSET_YORG(insetFA);
			Orig[2] = DSET_ZORG(insetFA);

			// check tot num vox match (as proxy for dims...)
			if( (Nvox != nmask1) || (Nvox != nmask2) )
				ERROR_exit("Input dataset does not match both mask volumes!");
		
      
			// this stores the original data file orientation for later use,
			// as well since we convert everything to RAI temporarily, as
			// described below
			header1.voxel_order[0]=ORIENT_typestr[insetFA->daxes->xxorient][0];
			header1.voxel_order[1]=ORIENT_typestr[insetFA->daxes->yyorient][0];
			header1.voxel_order[2]=ORIENT_typestr[insetFA->daxes->zzorient][0];
			for( i=0 ; i<3 ; i++) {
				header1.dim[i] = Dim[i];
				header1.voxel_size[i] = Ledge[i];
				// will want this when outputting file later for TrackVis.
				TV_switch[i] = !(dset_or[i]==header1.voxel_order[i]);
			}
			dset_or[3]='\0';
      
			FOUND = -1;
			for( i=0 ; i<4 ; i++) {
				sprintf(in_V1,"%s_V1%s", argv[iarg],postfix[i]); 
				if(THD_is_ondisk(in_V1)) {
					FOUND = i;
					break;
				}
			}
			insetV1 = THD_open_dataset(in_V1);
			if( insetV1 == NULL ) 
				ERROR_exit("Can't open dataset '%s':V1",in_V1);
			DSET_load(insetV1) ; CHECK_LOAD_ERROR(insetV1) ;
		
			FOUND = -1;
			for( i=0 ; i<4 ; i++) {
				sprintf(in_L1,"%s_L1%s", argv[iarg],postfix[i]); 
				if(THD_is_ondisk(in_L1)) {
					FOUND = i;
					break;
				}
			}
			insetL1 = THD_open_dataset(in_L1);
			if( insetL1 == NULL ) 
				ERROR_exit("Can't open dataset '%s':L1",in_L1);
			DSET_load(insetL1) ; CHECK_LOAD_ERROR(insetL1) ;

			FOUND = -1;
			for( i=0 ; i<4 ; i++) {
				sprintf(in_MD,"%s_MD%s", argv[iarg],postfix[i]); 
				if(THD_is_ondisk(in_MD)) {
					FOUND = i;
					break;
				}
			}
			insetMD = THD_open_dataset(in_MD);
			if( insetMD == NULL ) 
				ERROR_exit("Can't open dataset '%s':MD",in_MD);
			DSET_load(insetMD) ; CHECK_LOAD_ERROR(insetMD) ;

			iarg++ ; continue ;
		}

		if( strcmp(argv[iarg],"-algopt") == 0 ){
			iarg++ ; 
			if( iarg >= argc ) 
				ERROR_exit("Need argument after '-algopt'");
		
			if (!(nel = ReadTractAlgOpts(argv[iarg]))) {
				ERROR_message("Failed to read options in %s\n", argv[iarg]);
				exit(19);
			}
			if (NI_getTractAlgOpts(nel, &MinFA, &MaxAngDeg, &MinL, 
										  SeedPerV, &M, &bval)) {
				ERROR_message("Failed to get options");
				exit(1);
			}
			NI_free_element(nel); nel=NULL;
      
			iarg++ ; continue ;
		}

		if( strcmp(argv[iarg],"-logic") == 0 ){
			iarg++ ; if( iarg >= argc ) 
							ERROR_exit("Need argument after '-logic'");

			INFO_message("ROI logic type is: %s",argv[iarg]);
			if( strcmp(argv[iarg],"AND") == 0 ) 
				LOG_TYPE = 1;
			else if( strcmp(argv[iarg],"OR") == 0 ) 
				LOG_TYPE = 0;
			else if( strcmp(argv[iarg],"ALL") == 0 )
				LOG_TYPE = -1;
			else 
				ERROR_exit("Illegal after '-logic': need 'OR' or 'AND'");
			iarg++ ; continue ;
		}
    
		//@@
		if( strcmp(argv[iarg],"-extra_set") == 0) {
			if( ++iarg >= argc ) 
				ERROR_exit("Need argument after '-extra_set'");
			EXTRAFILE = 1; // switch on

			insetEXTRA = THD_open_dataset(argv[iarg]);
			if( (insetEXTRA == NULL ) )
				ERROR_exit("Can't open dataset '%s': for extra set.",argv[iarg]);
			DSET_load(insetEXTRA) ; CHECK_LOAD_ERROR(insetEXTRA) ;

			if( !((Dim[0] == DSET_NX(insetEXTRA)) && (Dim[1] == DSET_NY(insetEXTRA)) && (Dim[2] == DSET_NZ(insetEXTRA))))
				ERROR_exit("Dimensions of extra set '%s' don't match those of the DTI prop ones ('%s', etc.).",argv[iarg], in_FA);
			
			iarg++ ; continue ;
		}


		ERROR_message("Bad option '%s'\n",argv[iarg]) ;
		suggest_best_prog_option(argv[0], argv[iarg]);
		exit(1);
	}
	 
	if (iarg < 4) {
		ERROR_message("Too few options. Try -help for details.\n");
		exit(1);
	}
	 
	if (dump_opts) {
      nel = NI_setTractAlgOpts(NULL, &MinFA, &MaxAngDeg, &MinL, 
										 SeedPerV, &M, &bval);
      WriteTractAlgOpts(prefix, nel);
      NI_free_element(nel); nel=NULL;
	}
	 
        
	// Process the options a little 
	for( i=0 ; i<3 ; i++)
		DimSeed[i] = Dim[i]*SeedPerV[i];
	Nseed = Nvox*SeedPerV[0]*SeedPerV[1]*SeedPerV[2];
	 
	// convert to cos of rad value for comparisons, instead of using acos()
	MaxAng = cos(CONV*MaxAngDeg); 
	 
	// switch to add header-- option for now, added Sept. 2012
	// for use with map_TrackID to map tracks to different space
	if(RECORD_ORIG) {
		for( i=0 ; i<3 ; i++)
			header1.origin[i] = Orig[i];
	}
	 
	// at some point, we will have to convert indices into
	// pseudo-locations; being forced into this choice means that
	// different data set orientations would be represented differently
	// and incorrectly in some instances... so, for now, we'll resample
	// everything to RAI, and then resample back later.  guess this will
	// just slow things down slightly.
	 
	// have all be RAI for processing here
	if(TV_switch[0] || TV_switch[1] || TV_switch[2]) {
		dsetn = r_new_resam_dset(insetFA, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(insetFA); 
		insetFA=dsetn;
		dsetn=NULL;
		
		dsetn = r_new_resam_dset(insetMD, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(insetMD); 
		insetMD=dsetn;
		dsetn=NULL;
		
		dsetn = r_new_resam_dset(insetV1, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(insetV1); 
		insetV1=dsetn;
		dsetn=NULL;
		
		dsetn = r_new_resam_dset(insetL1, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(insetL1); 
		insetL1=dsetn;
		dsetn=NULL;
		
		dsetn = r_new_resam_dset(mset1, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(mset1); 
		mset1=dsetn;
		dsetn=NULL;
		
		dsetn = r_new_resam_dset(mset2, NULL, 0.0, 0.0, 0.0,
										 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
		DSET_delete(mset2); 
		mset2=dsetn;
		dsetn=NULL;

		if(EXTRAFILE) {
			dsetn = r_new_resam_dset(insetEXTRA, NULL, 0.0, 0.0, 0.0,
											 dset_or, RESAM_NN_TYPE, NULL, 1, 0);
			DSET_delete(insetEXTRA); 
			insetEXTRA=dsetn;
			dsetn=NULL;
		}


	}
	 
	 

	// ****************************************************************
	// ****************************************************************
	//                    make arrays for tracking
	// ****************************************************************
	// ****************************************************************

	// for temp storage array, just a multiple of longest dimension!
	if(Dim[0] > Dim[1])
		ArrMax = Dim[0] * 4;
	else
		ArrMax = Dim[1] * 4;
	if(4*Dim[2] > ArrMax)
		ArrMax = Dim[2] * 4;

	ROI1 = (int *)calloc(Nvox, sizeof(int)); 
	ROI2 = (int *)calloc(Nvox, sizeof(int)); 
	temp_arr = (short int *)calloc(Nvox, sizeof(short int)); 
	temp_byte = (char *)calloc(Nvox, sizeof(char)); 
	// temp storage whilst tracking
	Tforw = calloc(ArrMax, sizeof(Tforw)); 
	for(i=0 ; i<ArrMax ; i++) 
		Tforw[i] = calloc(3, sizeof(int)); 
	Ttot = calloc(2*ArrMax , sizeof(Ttot)); 
	for(i=0 ; i<2*ArrMax ; i++) 
		Ttot[i] = calloc(3, sizeof(int)); 
	Tback = calloc(ArrMax, sizeof(Tback)); 
	for(i=0 ; i<ArrMax ; i++) 
		Tback[i] = calloc(3, sizeof(int)); 
	// temp storage whilst tracking, physical loc
	flTforw = calloc(ArrMax, sizeof(flTforw)); 
	for(i=0 ; i<ArrMax ; i++) 
		flTforw[i] = calloc(3, sizeof(int)); 
	flTback = calloc(ArrMax,sizeof(flTback)); 
	for(i=0 ; i<ArrMax ; i++) 
		flTback[i] = calloc(3, sizeof(int)); 
	if( (ROI1 == NULL) || (ROI2 == NULL) || (temp_arr == NULL) 
		 || (Tforw == NULL) || (Tback == NULL) || (flTforw == NULL) 
		 || (flTback == NULL) || (Ttot == NULL)) {
		fprintf(stderr, "\n\n MemAlloc failure.\n\n");
		exit(12);
	}
  
	coorded = (float ****) calloc( Dim[0], sizeof(float ***) );
	for ( i = 0 ; i < Dim[0] ; i++ ) 
		coorded[i] = (float ***) calloc( Dim[1], sizeof(float **) );
	for ( i = 0 ; i < Dim[0] ; i++ ) 
		for ( j = 0 ; j < Dim[1] ; j++ ) 
			coorded[i][j] = (float **) calloc( Dim[2], sizeof(float *) );
	for ( i=0 ; i<Dim[0] ; i++ ) 
		for ( j=0 ; j<Dim[1] ; j++ ) 
			for ( k= 0 ; k<Dim[2] ; k++ ) //3 comp of V1 and FA
				coorded[i][j][k] = (float *) calloc( 4, sizeof(float) ); 
  
	INDEX = (int ****) calloc( Dim[0], sizeof(int ***) );
	for ( i = 0 ; i < Dim[0] ; i++ ) 
		INDEX[i] = (int ***) calloc( Dim[1], sizeof(int **) );
	for ( i = 0 ; i < Dim[0] ; i++ ) 
		for ( j = 0 ; j < Dim[1] ; j++ ) 
			INDEX[i][j] = (int **) calloc( Dim[2], sizeof(int *) );
	for ( i=0 ; i<Dim[0] ; i++ ) 
		for ( j=0 ; j<Dim[1] ; j++ ) 
			for ( k= 0 ; k<Dim[2] ; k++ ) 
				INDEX[i][j][k] = (int *) calloc( 4,  sizeof(int) );

	// this statement will never be executed if allocation fails above
	if( (INDEX == NULL) || (coorded == NULL) ) { 
		fprintf(stderr, "\n\n MemAlloc failure.\n\n");
		exit(122);
	}
  
	for(i=0 ; i<Nvox ; i++) {
		if(THD_get_voxel( mset1, i, 0) >0.5){
			ROI1[i] = 1;
		}
		if(THD_get_voxel( mset2, i, 0) >0.5)
			ROI2[i] = 1;
	}

	// set up eigvecs in 3D coord sys,
	// mark off where ROIs are and keep index handy
	idx=0;
	for( k=0 ; k<Dim[2] ; k++ ) 
		for( j=0 ; j<Dim[1] ; j++ ) 
			for( i=0 ; i<Dim[0] ; i++ ) {
				for( m=0 ; m<3 ; m++ ) 
					coorded[i][j][k][m] = THD_get_voxel(insetV1, idx, m);
				if(EXTRAFILE)
					coorded[i][j][k][3] = THD_get_voxel(insetEXTRA, idx, 0); 
				else
					coorded[i][j][k][3] = THD_get_voxel(insetFA, idx, 0); 
   
				// make sure that |V1| == 1 for all eigenvects, otherwise it's
				/// a problem in the tractography; currently, some from
				// 3dDWItoDT do not have this property...
				tempvmagn = sqrt(coorded[i][j][k][0]*coorded[i][j][k][0]+
									  coorded[i][j][k][1]*coorded[i][j][k][1]+
									  coorded[i][j][k][2]*coorded[i][j][k][2]);
				if( tempvmagn<0.99 ) 
					for( m=0 ; m<3 ; m++ ) 
						coorded[i][j][k][m]/= tempvmagn;
   
				INDEX[i][j][k][0] =idx; // first value is the index itself
				if( ROI1[idx]==1 ) 
					INDEX[i][j][k][1]=1; // second value identifies ROI1 mask
				else
					INDEX[i][j][k][1]=0;
				if( ROI2[idx]==1 )
					INDEX[i][j][k][2]=1; // third value identifies ROI2 mask
				else
					INDEX[i][j][k][2]=0;

				// fourth value will be counter for number of kept tracks
				// passing through
				INDEX[i][j][k][3] = 0;  
				idx+= 1;
			}
  
	// *************************************************************
	// *************************************************************
	//                    Beginning of main loop
	// *************************************************************
	// *************************************************************

	Numtract = 0;
	ave_tract_len = 0.;
	ave_tract_len_phys = 0.;
 
	sprintf(OUT_bin,"%s.trk",prefix);
	if( (fout0 = fopen(OUT_bin, "w")) == NULL) {
		fprintf(stderr, "Error opening file %s.",OUT_bin);
		exit(16);
	}
	fwrite(&header1,sizeof(tv_io_header),1,fout0);
  
	if (get_tract_verb()) {
		INFO_message("Begin tracking...");
	}

	tb = AppCreateBundle(NULL, 0, NULL, insetFA); // start bundle
	id = 0;
	for( k=0 ; k<Dim[2] ; k++ ) 
		for( j=0 ; j<Dim[1] ; j++ ) 
			for( i=0 ; i<Dim[0] ; i++ ) 
				if(coorded[i][j][k][3] >= MinFA) { 
					for( ii=0 ; ii<SeedPerV[0] ; ii++ ) 
						for( jj=0 ; jj<SeedPerV[1] ; jj++ ) 
							for( kk=0 ; kk<SeedPerV[2] ; kk++ ) {

								in[0] = i;
								in[1] = j;
								in[2] = k;
								physin[0] = ((float) in[0] + 
												 (0.5 + (float) ii)/SeedPerV[0])*Ledge[0];
								physin[1] = ((float) in[1] + 
												 (0.5 + (float) jj)/SeedPerV[1])*Ledge[1];
								physin[2] = ((float) in[2] + 
												 (0.5 + (float) kk)/SeedPerV[2])*Ledge[2];
      
								len_forw = TrackIt(coorded, in, physin, Ledge, Dim, 
														 MinFA, MaxAng, ArrMax, Tforw, 
														 flTforw, 1, phys_forw);
      
								// reset, because it's changed in TrackIt func
								in[0] = i; 
								in[1] = j;
								in[2] = k;

								physin[0] = ((float) in[0] + 
												 (0.5 + (float) ii)/SeedPerV[0])*Ledge[0];
								physin[1] = ((float) in[1] + 
												 (0.5 + (float) jj)/SeedPerV[1])*Ledge[1];
								physin[2] = ((float) in[2] + 
												 (0.5 + (float) kk)/SeedPerV[2])*Ledge[2];

								len_back = TrackIt(coorded, in, physin, Ledge, Dim, 
														 MinFA, MaxAng, ArrMax, Tback, 
														 flTback, -1, phys_back);
            
								KEEPIT = 0; // a simple switch

								totlen = len_forw+len_back-1; // NB: overlap of starts
								totlen_phys = phys_forw[0] + phys_back[0];
		
								if( totlen_phys >= MinL ) {
		  
									// glue together for simpler notation later
									for( n=0 ; n<len_back ; n++) { // all of this
										rr = len_back-n-1; // read in backward
										for(m=0;m<3;m++)
											Ttot[rr][m] = Tback[n][m];
									}
									for( n=1 ; n<len_forw ; n++){// skip first->overlap
										rr = n+len_back-1; // put after
										for(m=0;m<3;m++)
											Ttot[rr][m] = Tforw[n][m];
									}
									// <<So close and orthogonal condition>>:
									// test projecting ends, to see if they abut ROI.  
									for(m=0;m<3;m++) { 
										//actual projected ends
										end[1][m] = 2*Ttot[totlen-1][m]-Ttot[totlen-2][m];
										end[0][m] = 2*Ttot[0][m]-Ttot[1][m];
										// default choice, just retest known ends 
										// as default
										test_ind[1][m] = test_ind[0][m] = Ttot[0][m];
									}
		  
									tt = Create_Tract(len_back, flTback, len_forw, 
															flTforw, id, insetFA); ++id; 
        
									if (LOG_TYPE == -1) {
										KEEPIT = 1; 
									} else {
										inroi1 = 0;
										// check forw
										for( n=0 ; n<len_forw ; n++) {
											if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][1]==1){
												inroi1 = 1;
												break;
											} else
												continue;
										}
										if( inroi1==0 ){// after 1st half, check 2nd half
											for( m=0 ; m<len_back ; m++) {
												if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][1]==1){
													inroi1 = 1;
													break;
												} else
													continue;
											}
										}
										// after 1st&2nd halves, check bound/neigh
										if( inroi1==0 ) {
											if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][1]==1)
												inroi1 = 1;
											if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][1]==1)
												inroi1 = 1;
										}
			 
										if( ((LOG_TYPE ==0) && (inroi1 ==0)) || 
											 ((LOG_TYPE ==1) && (inroi1 ==1))) {
											// have to check in ROI2
				
											inroi2 = 0;
											// check forw
											for( n=0 ; n<len_forw ; n++) {
												if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][2]==1){
													inroi2 = 1;
													break;
												} else
													continue;
											}
											//after 1st half, check 2nd half
											if( inroi2==0 ) { 
												for( m=0 ; m<len_back ; m++) {
													if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][2]==1){
														inroi2 = 1;
														break;
													} else
														continue;
												}
											}
											// after 1st&2nd halves, check bound/neigh
											if( inroi2==0 ) { 
												if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][2]==1)
													inroi2 = 1;
												if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][2]==1)
													inroi2 = 1;
											}
				
											// for both cases, need to see it here to keep
											if( inroi2 ==1 )
												KEEPIT = 1; // otherwise, it's gone
				
										} else if((LOG_TYPE ==0) && (inroi1 ==1))
											KEEPIT = 1;
									}
								}
      
								// by now, we *know* if we're keeping this or not.
								if( KEEPIT == 1 ) {
									tb = AppCreateBundle(tb, 1, tt, NULL); 
									tt = Free_Tracts(tt, 1);
        
									READS_in = totlen;
									fwrite(&READS_in,sizeof(READS_in),1,fout0);
									for( n=0 ; n<len_back ; n++) {
										//put this one in backwords, to make it connect
										m = len_back - 1 - n; 
										for(aa=0 ; aa<3 ; aa++) {
											// recenter phys loc for trackvis, if nec...
											// just works this way (where they define 
											// origin)
											READS_fl = flTback[m][aa];
											if(!TV_switch[aa])
												READS_fl = Ledge[aa]*Dim[aa]-READS_fl;
											fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										}
										mm = INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][0];
										READS_fl =THD_get_voxel(insetFA, mm, 0); // FA
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										READS_fl =THD_get_voxel(insetMD, mm, 0); // MD
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										READS_fl =THD_get_voxel(insetL1, mm, 0); // L1
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										// count this voxel for having a tract
										INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][3]+= 1; 
									}
        
									for( m=1 ; m<len_forw ; m++) {
										for(aa=0 ; aa<3 ; aa++) {
											// recenter phys loc for trackvis, if nec...
											READS_fl = flTforw[m][aa];
											if(!TV_switch[aa])
												READS_fl = Ledge[aa]*Dim[aa]-READS_fl;
											fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										}
										mm = INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][0];
										READS_fl =THD_get_voxel(insetFA, mm, 0); // FA
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										READS_fl =THD_get_voxel(insetMD, mm, 0); // MD
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										READS_fl =THD_get_voxel(insetL1, mm, 0); // L1 
										fwrite(&READS_fl,sizeof(READS_fl),1,fout0);
										// count this voxel for having a tract
										INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][3]+= 1; 
									}
        
									ave_tract_len+= totlen;
									ave_tract_len_phys+= totlen_phys;
									Numtract+=1;
								}   
							}
				}
	fclose(fout0); 
  
	if (get_tract_verb()) {
		INFO_message("Done tracking, have %d tracks.", tb->N_tracts);
		Show_Taylor_Bundle(tb, NULL, 3);
	}

	if (!Write_Bundle(tb,prefix,mode)) {
		ERROR_message("Failed to write the bundle");
	}
   
	// **************************************************************
	// **************************************************************
	//                    Some simple stats on ROIs and outputs
	// **************************************************************
	// **************************************************************

	for( k=0 ; k<Dim[2] ; k++ ) 
		for( j=0 ; j<Dim[1] ; j++ ) 
			for( i=0 ; i<Dim[0] ; i++ ) {
				if( INDEX[i][j][k][3]>=1 ) {
					tempMD = THD_get_voxel(insetMD,INDEX[i][j][k][0],0);
					tempFA = THD_get_voxel(insetFA,INDEX[i][j][k][0],0);
					tempL1 = THD_get_voxel(insetL1,INDEX[i][j][k][0],0);
					tempRD = 0.5*(3*tempMD-tempL1);
					roi3_mu_MD+= tempMD;
					roi3_mu_FA+= tempFA;
					roi3_mu_L1+= tempL1;
					roi3_mu_RD+= tempRD;
					roi3_sd_MD+= tempMD*tempMD;
					roi3_sd_FA+= tempFA*tempFA;
					roi3_sd_L1+= tempL1*tempL1;
					roi3_sd_RD+= tempRD*tempRD;
					roi3_ct+= 1;
				}
			}
  
	if(roi3_ct > 0 ) { // !!!! make into afni file
		roi3_mu_MD/= (float) roi3_ct; 
		roi3_mu_FA/= (float) roi3_ct;
		roi3_mu_L1/= (float) roi3_ct;
		roi3_mu_RD/= (float) roi3_ct;
    
		roi3_sd_MD-= roi3_ct*roi3_mu_MD*roi3_mu_MD;
		roi3_sd_FA-= roi3_ct*roi3_mu_FA*roi3_mu_FA;
		roi3_sd_L1-= roi3_ct*roi3_mu_L1*roi3_mu_L1;
		roi3_sd_RD-= roi3_ct*roi3_mu_RD*roi3_mu_RD;
		roi3_sd_MD/= (float) roi3_ct-1; 
		roi3_sd_FA/= (float) roi3_ct-1;
		roi3_sd_L1/= (float) roi3_ct-1;
		roi3_sd_RD/= (float) roi3_ct-1;
		roi3_sd_MD = sqrt(roi3_sd_MD); 
		roi3_sd_FA = sqrt(roi3_sd_FA);
		roi3_sd_L1 = sqrt(roi3_sd_L1);
		roi3_sd_RD = sqrt(roi3_sd_RD);
  
		sprintf(OUT_tracstat,"%s.stats",prefix);
		if( (fout0 = fopen(OUT_tracstat, "w")) == NULL) {
			fprintf(stderr, "Error opening file %s.",OUT_tracstat);
			exit(19);
		}
		fprintf(fout0,"%d\t%d\n",Numtract,roi3_ct);
		fprintf(fout0,"%.3f\t%.3f\n",ave_tract_len/Numtract,
				  ave_tract_len_phys/Numtract);
		// as usual, these next values would have to be divided by the
		// bval to get their actual value in standard phys units
		fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_FA,roi3_sd_FA);
		fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_MD,roi3_sd_MD);
		fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_RD,roi3_sd_RD);
		fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_L1,roi3_sd_L1);
		fclose(fout0);

		sprintf(prefix_map,"%s_MAP",prefix); 
		sprintf(prefix_mask,"%s_MASK",prefix); 

		outsetMAP = EDIT_empty_copy( mset1 ) ;
		EDIT_dset_items( outsetMAP ,
							  ADN_datum_all , MRI_short , 
							  ADN_prefix    , prefix_map ,
							  ADN_none ) ;
		if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) )
			ERROR_exit("Can't overwrite existing dataset '%s'",
						  DSET_HEADNAME(outsetMAP));
    
		outsetMASK = EDIT_empty_copy( mset1 ) ;
		EDIT_dset_items( outsetMASK ,
							  ADN_datum_all , MRI_byte , 
							  ADN_prefix    , prefix_mask ,
							  ADN_none ) ;
		if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) )
			ERROR_exit("Can't overwrite existing dataset '%s'",
						  DSET_HEADNAME(outsetMASK));
    
		m=0;
		for( k=0 ; k<Dim[2] ; k++ ) 
			for( j=0 ; j<Dim[1] ; j++ ) 
				for( i=0 ; i<Dim[0] ; i++ ) {
					temp_arr[m]=INDEX[i][j][k][3];
					if(temp_arr[m]>0.5)
						temp_byte[m]=1;
					else
						temp_byte[m]=0;
					m++;
				}
    
		// re-orient the data as original inputs 
		// (this function copies the pointer)
		EDIT_substitute_brick(outsetMAP, 0, MRI_short, temp_arr); 
		temp_arr=NULL;
		if(TV_switch[0] || TV_switch[1] || TV_switch[2]) {
			dsetn = r_new_resam_dset(outsetMAP, NULL, 0.0, 0.0, 0.0,
											 header1.voxel_order, RESAM_NN_TYPE, 
											 NULL, 1, 0);
			DSET_delete(outsetMAP); 
			outsetMAP=dsetn;
			dsetn=NULL;
		}
		EDIT_dset_items( outsetMAP ,
							  ADN_prefix , prefix_map ,
							  ADN_none ) ;
		THD_load_statistics(outsetMAP );
		if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) )
			ERROR_exit("Can't overwrite existing dataset '%s'",
						  DSET_HEADNAME(outsetMAP));
		tross_Make_History( "3dTrackID" , argc , argv ,  outsetMAP) ;
		THD_write_3dim_dataset(NULL, NULL, outsetMAP, True);
		// re-orient the data as original inputs
		EDIT_substitute_brick(outsetMASK, 0, MRI_byte, temp_byte);
		temp_byte=NULL;
		if(TV_switch[0] || TV_switch[1] || TV_switch[2]) {
			dsetn = r_new_resam_dset(outsetMASK, NULL, 0.0, 0.0, 0.0,
											 header1.voxel_order, RESAM_NN_TYPE, 
											 NULL, 1, 0);
			DSET_delete(outsetMASK); 
			outsetMASK=dsetn;
			dsetn=NULL;
		}
		EDIT_dset_items( outsetMASK ,
							  ADN_prefix , prefix_mask ,
							  ADN_none ) ;
		THD_load_statistics(outsetMASK);
		if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) )
			ERROR_exit("Can't overwrite existing dataset '%s'",
						  DSET_HEADNAME(outsetMASK));
		tross_Make_History( "3dTrackID" , argc , argv ,  outsetMASK) ;
		THD_write_3dim_dataset(NULL, NULL, outsetMASK, True);

		INFO_message("Number of tracts found = %d",Numtract) ;
	}
	else 
		INFO_message("\n No Tracts Found!!!\n");
  

	// ************************************************************
	// ************************************************************
	//                    Freeing
	// ************************************************************
	// ************************************************************

	// !!! need to free afni-sets?
	DSET_delete(insetFA);
	DSET_delete(insetMD);
	DSET_delete(insetL1);
	DSET_delete(insetV1);
	DSET_delete(insetEXTRA);
	//DSET_delete(outsetMAP);  
	//DSET_delete(outsetMASK);
	DSET_delete(mset2);
	DSET_delete(mset1);

	free(prefix);
	free(insetV1);
	free(insetFA);
	free(mset1);
	free(mset2);
  	free(insetEXTRA);

	free(ROI1);
	free(ROI2);
	free(temp_byte);
  
	for( i=0 ; i<ArrMax ; i++) {
		free(Tforw[i]);
		free(Tback[i]);
		free(flTforw[i]);
		free(flTback[i]);
	}
	free(Tforw);
	free(Tback);
	free(flTforw);
	free(flTback);
  
	for( i=0 ; i<Dim[0] ; i++) 
		for( j=0 ; j<Dim[1] ; j++) 
			for( k=0 ; k<Dim[2] ; k++) 
				free(coorded[i][j][k]);
	for( i=0 ; i<Dim[0] ; i++) 
		for( j=0 ; j<Dim[1] ; j++) 
			free(coorded[i][j]);
	for( i=0 ; i<Dim[0] ; i++) 
		free(coorded[i]);
	free(coorded);

	for( i=0 ; i<Dim[0] ; i++) 
		for( j=0 ; j<Dim[1] ; j++) 
			for( k=0 ; k<Dim[2] ; k++) 
				free(INDEX[i][j][k]);
	for( i=0 ; i<Dim[0] ; i++) 
		for( j=0 ; j<Dim[1] ; j++) 
			free(INDEX[i][j]);
	for( i=0 ; i<Dim[0] ; i++) 
		free(INDEX[i]);
	free(INDEX);

	free(temp_arr); // need to free
	for( i=0 ; i<2*ArrMax ; i++) 
		free(Ttot[i]);
	free(Ttot);

	//free(mode);
	
	return 0;
}
int main( int argc , char *argv[] )
{
   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) ;
}
Exemple #17
0
/*!
   A function to call SUMA_qhull_wrap or SUMA_qdelaunay_wrap
*/
SUMA_SurfaceObject *SUMA_ConvexHullSurface(
               SUMA_GENERIC_PROG_OPTIONS_STRUCT * Opt)
{
   static char FuncName[]={"SUMA_ConvexHullSurface"};
   SUMA_SurfaceObject *SO=NULL;
   float *xyz=NULL, *xyzp=NULL, *txyz=NULL;
   int npt, *ijk=NULL, nf=0, cnt, i, j, k, nxx, nyy, nzz,N_txyz=-1;
   FILE *fid=NULL;
   THD_fvec3 fv, iv;
   SUMA_Boolean LocalHead = NOPE;
   
   SUMA_ENTRY;
   
   npt = 0;
   N_txyz=-1;
   if (Opt->UseThisBrain) {
      MRI_IMAGE *im = NULL;
      float *far=NULL;
      int nx2, i3;

      /* load the 1D file */
      im = mri_read_1D (Opt->UseThisBrain);
      if (!im) {
         SUMA_S_Err("Failed to read file");
         SUMA_RETURN(NULL);
      }   

      far = MRI_FLOAT_PTR(im);
      if (im->nx == 0) {
         SUMA_S_Errv("Empty file %s.\n", Opt->UseThisBrain);
         SUMA_RETURN(NULL);
      }
      if (im->ny != 3) {
         SUMA_S_Errv("Found %d columns in %s. Expecting 3\n", 
                     im->ny, Opt->UseThisBrain);
         SUMA_RETURN(NULL);
      }

      /* copy the columns */
      N_txyz = im->nx;
      txyz = (float *)SUMA_malloc(im->nx*im->ny*sizeof(float));
      if (!txyz) {
         SUMA_S_Crit("Failed to allocate.");
         SUMA_RETURN(NULL);
      }
      nx2 = 2*im->nx;
      for (i=0; i<N_txyz; ++i) {
         i3 = 3*i;
         txyz[i3  ] = far[i];
         txyz[i3+1] = far[i+im->nx];
         txyz[i3+2] = far[i+nx2];
      }

      /* done, clean up and out you go */
      if (im) mri_free(im); im = NULL;       
   }
   
   if (Opt->in_vol) {
      cnt = 0; npt = 0;
      nxx = (DSET_NX(Opt->in_vol)); 
      nyy = (DSET_NY(Opt->in_vol));
      nzz = (DSET_NZ(Opt->in_vol));

      if (Opt->debug) fprintf(SUMA_STDERR,"%s:\nRunning qhull...\n", FuncName);
      xyz = (float *)SUMA_malloc(3*nxx*nyy*nzz*sizeof(float));
      if (!xyz) {
         SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NULL);
      }
      for(  k = 0 ; k < nzz ; k++ ) {
         for(  j = 0 ; j < nyy ; j++ ) {
            for(  i = 0 ; i < nxx ; i++ ) {
               if (Opt->mcdatav[cnt] == 1) {
                  fv.xyz[0] = DSET_XORG(Opt->in_vol) + i * DSET_DX(Opt->in_vol);
                  fv.xyz[1] = DSET_YORG(Opt->in_vol) + j * DSET_DY(Opt->in_vol);
                  fv.xyz[2] = DSET_ZORG(Opt->in_vol) + k * DSET_DZ(Opt->in_vol);
                  /* change mm to RAI coords */
		            iv = SUMA_THD_3dmm_to_dicomm( Opt->in_vol->daxes->xxorient, 
                                                Opt->in_vol->daxes->yyorient, 
                                                Opt->in_vol->daxes->zzorient, 
                                                fv );
                  xyz[3*npt] = iv.xyz[0]; 
                  xyz[3*npt+1] = iv.xyz[1]; xyz[3*npt+2] = iv.xyz[2]; 
                  npt++;
               }
               ++cnt;
            }
         }
      }
   } else if (Opt->XYZ) {
      xyz = (float *)SUMA_malloc(3*Opt->N_XYZ*sizeof(float));
      if (!xyz) {
         SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NULL);
      }
      for(  k = 0 ; k < 3*Opt->N_XYZ ; k++ ) {  
         xyz[k] = Opt->XYZ[k]; npt = Opt->N_XYZ; 
      }   
   } else {
      SUMA_S_Err("No input");
      goto CLEANUP; 
   }
   
   if (Opt->corder) {
      SUMA_PC_XYZ_PROJ *pcp=NULL;
      if (Opt->geom==1) {
         SUMA_S_Warn("PCA projection makes no sense for usual convex hull");
      }
      if (!(pcp = SUMA_Project_Coords_PCA (xyz, npt, npt/2, NULL,
                                            E3_PLN_PRJ, ROT_2_Z,0))) {
         SUMA_S_Err("Failed to project");
         goto CLEANUP;   
      }
      xyzp = pcp->xyzp; pcp->xyzp = NULL;
      pcp = SUMA_Free_PC_XYZ_Proj(pcp);
   } else {
      xyzp = xyz;
   }

   if (N_txyz >= 0 && N_txyz != npt) {
      SUMA_S_Errv("Mismatch between number of coordinates for convex hull\n"
                  "and number of coordinates to adopt in the end.\n"
                  " %d, versus %d in -these_coords\n",
                  npt, N_txyz);
      goto CLEANUP;            
   }  
   
   if (Opt->geom == 1) { /* convex hull */
      if (! (nf = SUMA_qhull_wrap(npt, xyzp, &ijk, 1, Opt->s)) ) {
         fprintf(SUMA_STDERR,"%s:\nFailed in SUMA_qhull_wrap\n", FuncName);
         goto CLEANUP; 
      }
      
      /* Other than unif==0 make no sense here, but leave it to the user */
      switch (Opt->unif) {
         case 0:  /* coordinates as passed to qhull, 
                     could be projected ones*/
            SO = SUMA_Patch2Surf(xyzp, npt, ijk, nf, 3);
            break;
         case 1:  /* Original corrdinates passed to qhull
                     (pre-projections, if any) */
            SO = SUMA_Patch2Surf(xyz, npt, ijk, nf, 3);
            break;
         case 2: /* special coordinates passed by user, 
                    never passed in any form to qhull */
            SUMA_S_Warn("Makes no sense to mess with coords for convex hull...");
            SO = SUMA_Patch2Surf(txyz, npt, ijk, nf, 3);
            break;
         default:
            SUMA_S_Err("pit of despair");
            goto CLEANUP; 
      }
            
      if (Opt->debug) fprintf(SUMA_STDERR,"%s:\n%d triangles.\n", FuncName, nf);
   } else if (Opt->geom == 2) { /* triangulation */
      if (! (nf = SUMA_qdelaunay_wrap(npt, xyzp, &ijk, 1, Opt->s)) ) {
         fprintf(SUMA_STDERR,"%s:\nFailed in SUMA_qdelaunay_wrap\n", FuncName);
         goto CLEANUP;    
      }
      switch (Opt->unif) {
         case 0:  /* coordinates as passed to qdelaunay, 
                     could be projected ones*/
            if (xyz == xyzp) xyz=NULL; /* xyzp will be set to 
                                         null in next call, 
                                         so xyz is treated 
                                         the same here */
            SO = SUMA_NewSO(&xyzp, npt, &ijk, nf, NULL);
            SUMA_LHv("xyzp %p, ijk %p\n", txyz, ijk);
           break;
         case 1:  /* Original corrdinates passed to qdelaunay
                     (pre-projections, if any) */
            SO = SUMA_NewSO(&xyz, npt, &ijk, nf, NULL);
            SUMA_LHv("xyz %p, ijk %p\n", txyz, ijk);
            break;
         case 2:  /* special coordinates passed by user, 
                     never passed in any form to qdelaunay */
            SO = SUMA_NewSO(&txyz, npt, &ijk, nf, NULL);
            SUMA_LHv("txyz %p, ijk %p\n", txyz, ijk);
            break;
         default:
            SUMA_S_Err("pit of despair, again");
            goto CLEANUP; 
      }
   } else {
      SUMA_S_Errv("Opt->geom = %d not valid\n", Opt->geom);
      goto CLEANUP;      
   }  
   
   CLEANUP:
   if (ijk) SUMA_free(ijk); ijk=NULL;
   if(txyz) SUMA_free(txyz); txyz=NULL;
   if (xyzp != xyz && xyzp != NULL) SUMA_free(xyzp); xyzp = NULL;
   if (xyz) SUMA_free(xyz); xyz = NULL;

   SUMA_RETURN(SO);
}