예제 #1
0
파일: nimel.c 프로젝트: Gilles86/afni
int main( int argc , char *argv[] )
{
   int nfl , ii , ct ;
   char *sspec ;
   NI_element *nel ;
   NI_stream ns ;
   float *flar ;

   if( argc < 3 || strcmp(argv[1],"-help") == 0 ){
     printf("Usage: nimel N streamspec\n") ; exit(0) ;
   }

   nfl = strtol( argv[1] , NULL , 10) ;
   if( nfl < 1 ) nfl = 100000 ;
   sspec = argv[2] ;
   ns = NI_stream_open( sspec , "w" ) ;
   if( ns == NULL ){
     fprintf(stderr,"NI_stream_open fails\n"); exit(1);
   }

   nel = NI_new_data_element( "Tester" , nfl ) ;
   flar = (float *)malloc(sizeof(float)*nfl) ;
   for( ii=0 ; ii < nfl ; ii++ ) flar[ii] = (float)ii ;
   NI_add_column( nel , NI_FLOAT , flar ) ;
   free((void *)flar) ;

   while(1){
     ii = NI_stream_writecheck( ns , 666 ) ;
     if( ii == 1 ){ fprintf(stderr,"!\n") ; break ; }
     if( ii <  0 ){ fprintf(stderr,"BAD writecheck\n"); exit(1); }
     fprintf(stderr,".") ;
   }

   ct = NI_clock_time() ;
   NI_write_element( ns , nel , NI_BINARY_MODE ) ;
   NI_stream_closenow( ns ) ;
   ct = NI_clock_time() - ct ;
   fprintf(stderr,"Wrote %d floats in %d ms\n",nfl,ct) ;
   exit(0) ;
}
예제 #2
0
MRI_IMAGE * mri_warp3D_align_one( MRI_warp3D_align_basis *bas, MRI_IMAGE *im )
{
   float *fit , *dfit , *qfit , *tol ;
   int iter , good,ngood , ii, pp , skip_first ;
   MRI_IMAGE *tim , *fim ;
   float *pmat=MRI_FLOAT_PTR(bas->imps) , /* pseudo inverse: n X m matrix */
         *tar , tv , sfit ;
   int n=bas->imps->nx ,          /* = nfree+1 */
       m=bas->imps->ny ,          /* = imap->nx = length of ima */
    npar=bas->nparam   ,          /* = number of warp parameters */
   nfree=bas->nfree    ,          /* = number of free warp parameters */
    *ima=MRI_INT_PTR(bas->imap) , /* = indexes in fim of voxels to use */
    *pma ;                        /* = map of free to total params */
   int ctstart ;
   int do_twopass=(bas->imps_blur != NULL && bas->twoblur > 0.0f) , passnum=1 ;
   int blur_pass ;
   char      *save_prefix ;
   static int save_index=0 ;

#define AITMAX  3.33
#define NMEM    5
   float *fitmem[NMEM] ;
   int mm , last_aitken , num_aitken=0 ;
   float  sdif , fitdif[NMEM] ;   /* 28 Sep 2005 */
   int    num_bad_diff ;
   float  best_dif , best_par[999] ;  /* 09 Jan 2006 */
   int    best_ite=0 ;

ENTRY("mri_warp3D_align_one") ;

   ctstart = NI_clock_time() ;

   save_prefix = getenv("AFNI_WARPDRIVE_SAVER") ;

   /** pma[k] = external parameter index for the k-th free parameter **/

   pma = (int *)malloc(sizeof(int) * nfree) ;
   for( pp=ii=0 ; ii < npar ; ii++ )
     if( !bas->param[ii].fixed ) pma[pp++] = ii ;

#if 0
fprintf(stderr,"pma=") ;
for(pp=0;pp<nfree;pp++)fprintf(stderr," %d",pma[pp]);
fprintf(stderr,"\n") ;
#endif

   fit  = (float *)malloc(sizeof(float) * npar ) ;
   dfit = (float *)malloc(sizeof(float) * npar ) ;
   qfit = (float *)malloc(sizeof(float) * nfree) ;
   tol  = (float *)malloc(sizeof(float) * npar ) ;

   for( mm=0 ; mm < NMEM ; mm++ ) fitmem[mm] = NULL ;
   for( mm=0 ; mm < NMEM ; mm++ ) fitdif[mm] = 3.e+33 ;

   /*--- loop back point for two pass alignment ---*/

   bas->num_iter = 0 ;
   mri_warp3D_set_womask( bas->imsk ) ;

 ReStart:

   best_dif  = -666.0f ;                     /* 09 Jan 2006 */
   blur_pass = (do_twopass && passnum==1) ;
   mri_warp3D_method( blur_pass ? MRI_LINEAR : bas->regmode ) ;

   /* load initial fit parameters;
      if they are all the identity transform value,
      then skip the first transformation of the fim volume */

   if( passnum == 1 ){
     skip_first = 1 ;
     for( pp=0 ; pp < npar ; pp++ ){
       if( bas->param[pp].fixed ){
         fit[pp] = bas->param[pp].val_fixed ;
       } else {
         fit[pp] = bas->param[pp].val_init ;
       }
       skip_first = skip_first && (fit[pp] == bas->param[pp].ident) ;
     }
   } else {
     skip_first = 0 ;  /* and fit[] is unchanged */
   }

   fitmem[0] = (float *)malloc(sizeof(float)*npar) ;
   memcpy( fitmem[0] , fit , sizeof(float)*npar ) ;

   for( pp=0 ; pp < npar ; pp++ ) tol[pp] = bas->param[pp].toler ;

   if( blur_pass ){
     float fac = (1.0f+bas->twoblur) ;
     if( fac < 3.0f ) fac = 3.0f ;
     for( pp=0 ; pp < npar ; pp++ ) tol[pp] *= fac ;
   }

   if( bas->verb )
     fprintf(stderr,"++ mri_warp3D_align_one: START PASS #%d\n",passnum) ;

   /* setup base image for registration into fim,
      and pseudo-inverse of base+derivative images into pmat */

   if( blur_pass ){             /* first pass ==> registering blurred images */
     float *far , blur=bas->twoblur ;
     int nx=im->nx , ny=im->ny , nz=im->nz ;
     fim = mri_to_float( im ) ; far = MRI_FLOAT_PTR(fim) ;
     EDIT_blur_volume_3d( nx,ny,nz ,       1.0f,1.0f,1.0f ,
                          MRI_float , far, blur,blur,blur  ) ;
     pmat = MRI_FLOAT_PTR(bas->imps_blur) ;
   } else {                           /* registering original image */
     if( im->kind == MRI_float ) fim = im ;
     else                        fim = mri_to_float( im ) ;
     pmat = MRI_FLOAT_PTR(bas->imps) ;
   }

   /******** iterate fit ********/

   iter = 0 ; good = 1 ; last_aitken = 3 ; num_bad_diff = 0 ;
   while( good ){
     if( skip_first ){
       tim = fim ; skip_first = 0 ;
     } else {
       bas->vwset( npar , fit ) ;                     /**************************/
       tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ; /* warp on current params */
     }                                                /**************************/
     tar = MRI_FLOAT_PTR(tim) ;

     sdif = mri_scaled_diff( bas->imbase , tim , bas->imsk ) ;
     if( bas->verb )
       fprintf(stderr,"++++++++++ Start iter=%d  RMS_diff=%g\n",iter+1,sdif) ;

     if( best_dif < 0.0f || sdif < best_dif ){        /* 09 Jan 2006 */
       best_dif = sdif ; best_ite = iter ;
       memcpy( best_par , fit , sizeof(float)*npar ) ;
     }

     /* find least squares fit of base + derivatives to warped image */

     sfit = 0.0f ;
     for( pp=0 ; pp < npar  ; pp++ ) dfit[pp] = 0.0f ;
     for( pp=0 ; pp < nfree ; pp++ ) qfit[pp] = 0.0f ;
     for( ii=0 ; ii < m ; ii++ ){
       tv = tar[ima[ii]] ; sfit += P(nfree,ii) * tv ;
       for( pp=0 ; pp < nfree ; pp++ ) qfit[pp] += P(pp,ii) * tv ;
     }
     if( tim != fim ) mri_free( tim ) ;
#if 0
fprintf(stderr,"qfit=");
for(pp=0;pp<nfree;pp++)fprintf(stderr," %g",qfit[pp]);
fprintf(stderr,"\n") ;
#endif
     for( pp=0 ; pp < nfree ; pp++ ) dfit[pma[pp]] = qfit[pp] ;
     for( pp=0 ; pp < npar  ; pp++ ){
       fit[pp] += dfit[pp] ;
            if( fit[pp] > bas->param[pp].max ) fit[pp] = bas->param[pp].max ;
       else if( fit[pp] < bas->param[pp].min ) fit[pp] = bas->param[pp].min ;
     }

     if( bas->verb ){
       fprintf(stderr,"+   Delta:") ;
       for( pp=0 ; pp < npar ; pp++ ) fprintf(stderr," %13.6g",dfit[pp]) ;
       fprintf(stderr,"\n") ;
       fprintf(stderr,"+   Total: scale factor=%g\n"
                      "+  #%5d:",sfit,iter+1) ;
       for( pp=0 ; pp < npar ; pp++ ) fprintf(stderr," %13.6g", fit[pp]) ;
       fprintf(stderr,"\n") ;
     }

     /* save fit results for a while into the past, and then maybe do Aitken */

     if( fitmem[NMEM-1] != NULL ) free((void *)fitmem[NMEM-1]) ;
     for( mm=NMEM-1 ; mm > 0 ; mm-- ) fitmem[mm] = fitmem[mm-1] ;
     fitmem[0] = (float *)malloc(sizeof(float)*npar) ;
     memcpy( fitmem[0] , fit , sizeof(float)*npar ) ;

     /* 28 Sep 2005: if RMS went up, back off the changes! */

     for( mm=NMEM-1 ; mm > 0 ; mm-- ) fitdif[mm] = fitdif[mm-1] ;
     fitdif[0] = sdif ;

     if( iter > 1          && num_bad_diff < 2                   &&
         fitmem[1] != NULL && fitdif[0]    > 1.0666f * fitdif[1]   ){
       for( pp=0 ; pp < npar ; pp++ )
         fit[pp] = 0.5 * ( fitmem[0][pp] + fitmem[1][pp] ) ;
       memcpy( fitmem[0] , fit , sizeof(float)*npar ) ;
       last_aitken = iter+1 ; num_bad_diff++ ;
       if( bas->verb )
         fprintf(stderr,"+++ RMS_diff changes too much! Shrinking!\n") ;
     } else {
       num_bad_diff = 0 ;
     }

     iter++ ;
     if( iter > last_aitken+NMEM && !AFNI_noenv("AFNI_WARPDRIVE_AITKEN") ){
       double s0,s1,s2 , dd , de,df ;
       num_aitken = 0 ;
       for( pp=0 ; pp < npar ; pp++ ){
         dd = fabs(fitmem[1][pp]-fit[pp]) ;
         if( dd <= tol[pp] ) continue ; /* done here */
         de = dd ;
         for( mm=2 ; mm < NMEM ; mm++ ){
           df = fabs(fitmem[mm][pp]-fitmem[mm-1][pp]) ;
           if( df <= de ) break ;
           de = df ;
         }
         if( mm == NMEM ){  /* do Aitken */
           s2 = fit[pp] ; s1 = fitmem[1][pp] ; s0 = fitmem[2][pp] ;
           de = ( (s2-s1) - (s1-s0) ) ;
           if( de != 0.0 ){
             de = -(s2-s1)*(s2-s1) / de ; dd *= AITMAX ;
             if( fabs(de) > dd ){ de = (de > 0.0) ? dd : -dd ; }
             fit[pp] += de ;
                  if( fit[pp] > bas->param[pp].max ) fit[pp] = bas->param[pp].max ;
             else if( fit[pp] < bas->param[pp].min ) fit[pp] = bas->param[pp].min ;
             num_aitken++ ;
           }
         }
       }
       if( num_aitken > 0 ) last_aitken = iter ;

       if( bas->verb && num_aitken > 0 ){
         fprintf(stderr,"+   Aitken on %d params:\n"
                        "+________:",num_aitken) ;
         for( pp=0 ; pp < npar ; pp++ ){
           if( fit[pp] != fitmem[0][pp] ){
             fprintf(stderr," %13.6g", fit[pp]) ; fitmem[0][pp] = fit[pp] ;
           } else {
             fprintf(stderr," _____________") ;
           }
         }
         fprintf(stderr,"\n") ;
       }
     }

     /* save intermediate image? */

     if( save_prefix != NULL ){
       char sname[THD_MAX_NAME] ; FILE *fp ;
       mri_warp3D_set_womask( NULL ) ;        /* must warp the whole thing */
       bas->vwset( npar , fit ) ;
       tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ;
       tar = MRI_FLOAT_PTR(tim) ;
       mri_warp3D_set_womask( bas->imsk ) ;
       sprintf(sname,"%s_%04d.mmm",save_prefix,save_index++) ;
       fprintf(stderr,"+   Saving intermediate image to binary file %s\n",sname) ;
       fp = fopen( sname , "w" ) ;
       if( fp != NULL ){
         fwrite( tar, tim->pixel_size, tim->nvox, fp ) ; fclose(fp) ;
       }

       if( bas->vwdet != NULL ){
         int i,j,k , nx=tim->nx,ny=tim->ny,nz=tim->nz ;
         for( k=0 ; k < nz ; k++ ){
          for( j=0 ; j < ny ; j++ ){
           for( i=0 ; i < nx ; i++ ){
             tar[i+(j+k*ny)*nx] = bas->vwdet( (float)i,(float)j,(float)k ) ;
         }}}
         sprintf(sname,"%s_%04d.ddd",save_prefix,save_index-1) ;
         fprintf(stderr,"+   Saving determinant image to binary file %s\n",sname) ;
         fp = fopen( sname , "w" ) ;
         if( fp != NULL ){
           fwrite( tar, tim->pixel_size, tim->nvox, fp ) ; fclose(fp) ;
         }
       }
       mri_free( tim ) ;
     }

     /* loop back for more iterations? */

     if( last_aitken == iter ) continue ;  /* don't test, just loop */
     if( fitmem[2]   == NULL ) continue ;

     ngood = 0 ;
     for( pp=0 ; pp < npar ; pp++ )
       if( !bas->param[pp].fixed )
         ngood += ( ( fabs(fitmem[1][pp]-fitmem[0][pp]) <= tol[pp] ) &&
                    ( fabs(fitmem[2][pp]-fitmem[1][pp]) <= tol[pp] )   ) ;

     good = (ngood < nfree) && (iter < bas->max_iter) ;

   } /******** end while loop for iteration of fitting procedure ********/

   for( mm=0 ; mm < NMEM ; mm++ )
     if( fitmem[mm] != NULL ){ free((void *)fitmem[mm]); fitmem[mm] = NULL; }

   /*--- 09 Jan 2006: if prior best fit was better than current, replace ---*/

   if( best_dif > 0.0f && 1.0666f*best_dif < sdif ){
     memcpy( fit , best_par , sizeof(float)*npar ) ;
     if( bas->verb )
       fprintf(stderr,"+++++ Replacing final fit with iter #%d's fit +++++\n",
               best_ite+1) ;
   }

   /*--- do the second pass? ---*/

   if( blur_pass ){
     if( bas->verb )
       fprintf(stderr,"+++++++++++++ Loop back for next pass +++++++++++++\n");
     mri_free(fim) ; fim = NULL ; passnum++ ; goto ReStart ;
   } else {
     if( bas->verb )
       fprintf(stderr,"+++++++++++++ Convergence test passed +++++++++++++\n");
   }

   /*--- done! ---*/

   bas->num_iter = iter ;

   for( pp=0 ; pp < npar ; pp++ ) bas->param[pp].val_out = fit[pp] ;

   /*-- do the actual realignment to get the output image --*/

   if( bas->regfinal > 0 ) mri_warp3D_method( bas->regfinal ) ;
   mri_warp3D_set_womask( NULL ) ;
   bas->vwset( npar , fit ) ;
   tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ;

   if( fim != im ) mri_free(fim) ;  /* if it was a copy, junk it */
   free((void *)dfit) ; free((void *)fit) ;
   free((void *)qfit) ; free((void *)pma) ; free((void *)tol) ;

   if( bas->verb ){
     double st = (NI_clock_time()-ctstart) * 0.001 ;
     fprintf(stderr,"++ mri_warp3D_align_one EXIT: %.2f seconds elapsed\n",st) ;
   }

   RETURN( tim ) ;
}
예제 #3
0
int mri_warp3D_align_setup( MRI_warp3D_align_basis *bas )
{
   MRI_IMAGE *cim , *fitim ;
   int nx, ny, nz, nxy, nxyz , ii,jj,kk , nmap, *im ;
   float *wf , *wtar , clip , clip2 ;
   int   *ima , pp , wtproc , npar , nfree ;
   byte  *msk ;
   int ctstart ;

ENTRY("mri_warp3D_align_setup") ;

   ctstart = NI_clock_time() ;

   /*- check for good inputs -*/

   if( bas == NULL     || bas->imbase == NULL ) RETURN(1) ;
   if( bas->nparam < 1 || bas->param  == NULL ) RETURN(1) ;
   if( bas->vwfor == NULL ||
       bas->vwinv == NULL || bas->vwset == NULL ) RETURN(1) ;

   /*- set defaults in bas, if values weren't set by user -*/

   if( bas->scale_init <= 0.0f ) bas->scale_init = 1.0f ;
   if( bas->delfac     <= 0.0f ) bas->delfac     = 1.0f ;
   if( bas->regmode    <= 0    ) bas->regmode    = MRI_LINEAR ;
   if( bas->max_iter   <= 0    ) bas->max_iter   = 9 ;

   /* process the weight image? */

   wtproc = (bas->imwt == NULL) ? 1 : bas->wtproc ;
   npar   = bas->nparam ;

   nfree = npar ;
   for( pp=0 ; pp < npar ; pp++ )
     if( bas->param[pp].fixed ) nfree-- ;
   if( nfree <= 0 ) RETURN(1) ;
   bas->nfree = nfree ;

   /*- clean out anything from last call -*/

   mri_warp3D_align_cleanup( bas ) ;

   /*-- need local copy of input base image --*/

   cim = mri_to_float( bas->imbase ) ;
   nx=cim->nx ; ny=cim->ny ; nz=cim->nz ; nxy = nx*ny ; nxyz=nxy*nz ;

   /*-- make weight image up from the base image if it isn't supplied --*/

   if( bas->verb ) fprintf(stderr,"++ mri_warp3D_align_setup ENTRY\n") ;

   if( bas->imwt == NULL   ||
       bas->imwt->nx != nx ||
       bas->imwt->ny != ny ||
       bas->imwt->nz != nz   ) bas->imww = mri_copy( cim ) ;
   else                        bas->imww = mri_to_float( bas->imwt ) ;

   if( bas->twoblur > 0.0f ){
     float bmax = cbrt((double)nxyz) * 0.03 ;
     if( bmax < bas->twoblur ){
       if( bas->verb )
         fprintf(stderr,"+   shrink bas->twoblur from %.3f to %.3f\n",
                        bas->twoblur , bmax ) ;
       bas->twoblur = bmax ;
     }
   }

   if( bas->verb ) fprintf(stderr,"+   processing weight:") ;

   /* make sure weight is non-negative */

   wf = MRI_FLOAT_PTR(bas->imww) ;
   for( ii=0 ; ii < nxyz ; ii++ ) wf[ii] = fabs(wf[ii]) ;

   /* trim off edges of weight */

   if( wtproc ){
     int ff ;
     int xfade=bas->xedge , yfade=bas->yedge , zfade=bas->zedge ;

     if( xfade < 0 || yfade < 0 || zfade < 0 )
       mri_warp3D_align_edging_default(nx,ny,nz,&xfade,&yfade,&zfade) ;

     if( bas->twoblur > 0.0f ){
       xfade += (int)rint(1.5*bas->twoblur) ;
       yfade += (int)rint(1.5*bas->twoblur) ;
       zfade += (int)rint(1.5*bas->twoblur) ;
     }

     if( 3*zfade >= nz ) zfade = (nz-1)/3 ;
     if( 3*xfade >= nx ) xfade = (nx-1)/3 ;
     if( 3*yfade >= ny ) yfade = (ny-1)/3 ;

     if( bas->verb ) fprintf(stderr," [edge(%d,%d,%d)]",xfade,yfade,zfade) ;

     for( jj=0 ; jj < ny ; jj++ )
      for( ii=0 ; ii < nx ; ii++ )
       for( ff=0 ; ff < zfade ; ff++ )
         WW(ii,jj,ff) = WW(ii,jj,nz-1-ff) = 0.0f ;

     for( kk=0 ; kk < nz ; kk++ )
      for( jj=0 ; jj < ny ; jj++ )
       for( ff=0 ; ff < xfade ; ff++ )
         WW(ff,jj,kk) = WW(nx-1-ff,jj,kk) = 0.0f ;

     for( kk=0 ; kk < nz ; kk++ )
      for( ii=0 ; ii < nx ; ii++ )
       for( ff=0 ; ff < yfade ; ff++ )
        WW(ii,ff,kk) = WW(ii,ny-1-ff,kk) = 0.0f ;

   }

   /* spatially blur weight a little */

   if( wtproc ){
     float blur ;
     blur = 1.0f + MAX(1.5f,bas->twoblur) ;
     if( bas->verb ) fprintf(stderr," [blur(%.1f)]",blur) ;
     EDIT_blur_volume_3d( nx,ny,nz ,       1.0f,1.0f,1.0f ,
                          MRI_float , wf , blur,blur,blur  ) ;
   }

   /* get rid of low-weight voxels */

   clip  = 0.035 * mri_max(bas->imww) ;
   clip2 = 0.5*THD_cliplevel(bas->imww,0.4) ;
   if( clip2 > clip ) clip = clip2 ;
   if( bas->verb ) fprintf(stderr," [clip(%.1f)]",clip) ;
   for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] < clip ) wf[ii] = 0.0f ;

   /* keep only the largest cluster of nonzero voxels */

   { byte *mmm = (byte *)malloc( sizeof(byte)*nxyz ) ;
     for( ii=0 ; ii < nxyz ; ii++ ) mmm[ii] = (wf[ii] > 0.0f) ;
     THD_mask_clust( nx,ny,nz, mmm ) ;
     THD_mask_erode( nx,ny,nz, mmm, 1 ) ;  /* cf. thd_automask.c */
     THD_mask_clust( nx,ny,nz, mmm ) ;
     for( ii=0 ; ii < nxyz ; ii++ ) if( !mmm[ii] ) wf[ii] = 0.0f ;
     free((void *)mmm) ;
   }

   if( bas->verb ) fprintf(stderr,"\n") ;

   /*-- make integer index map of weight > 0 voxels --*/

   nmap = 0 ;
   for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] > 0.0f ) nmap++ ;

   if( bas->verb )
     fprintf(stderr,"+   using %d [%.3f%%] voxels\n",nmap,(100.0*nmap)/nxyz);

   if( nmap < 7*nfree+13 ){
     fprintf(stderr,"** mri_warp3D_align error: weight image too zero-ish!\n") ;
     mri_warp3D_align_cleanup( bas ) ; mri_free(cim) ;
     RETURN(1) ;
   }

   bas->imap = mri_new( nmap , 1 , MRI_int ) ;
   ima       = MRI_INT_PTR(bas->imap) ;
   bas->imsk = mri_new_conforming( bas->imww , MRI_byte ) ;
   msk       = MRI_BYTE_PTR(bas->imsk) ;
   for( ii=jj=0 ; ii < nxyz ; ii++ ){
     if( wf[ii] > 0.0f ){ ima[jj++] = ii; msk[ii] = 1; }
   }

   /* make copy of sqrt(weight), but only at mapped indexes */

   wtar = (float *)malloc(sizeof(float)*nmap) ;
   for( ii=0 ; ii < nmap ; ii++ ) wtar[ii] = sqrt(wf[ima[ii]]) ;

   /*-- for parameters that don't come with a step size, find one --*/

   clip = bas->tolfac ; if( clip <= 0.0f ) clip = 0.03f ;

   for( ii=0 ; ii < npar ; ii++ ){
     if( bas->param[ii].fixed ) continue ; /* don't need this */
     if( bas->param[ii].delta <= 0.0f )
       mri_warp3D_get_delta( bas , ii ) ;  /* find step size */
     if( bas->param[ii].toler <= 0.0f ){   /* and set default tolerance */
       bas->param[ii].toler = clip * bas->param[ii].delta ;
       if( bas->verb )
         fprintf(stderr,"+   set toler param#%d [%s] = %f\n",
                 ii+1,bas->param[ii].name,bas->param[ii].toler) ;
     }
   }

   /* don't need the computed weight image anymore */

   mri_free(bas->imww) ; bas->imww = NULL ; wf = NULL ;

   /*-- create image containing basis columns, then pseudo-invert it --*/

   if( bas->verb ) fprintf(stderr,"+  Compute Derivatives of Base\n") ;
   fitim = mri_warp3D_align_fitim( bas , cim , bas->regmode , bas->delfac ) ;
   if( bas->verb ) fprintf(stderr,"+   calculate pseudo-inverse\n") ;
   bas->imps = mri_psinv( fitim , wtar ) ;
   mri_free(fitim) ;

   if( bas->imps == NULL ){  /* bad bad bad */
     fprintf(stderr,"** mri_warp3D_align error: can't invert Base matrix!\n") ;
     free((void *)wtar) ; mri_warp3D_align_cleanup( bas ) ; mri_free(cim) ;
     RETURN(1) ;
   }

   /*--- twoblur? ---*/

   if( bas->twoblur > 0.0f ){
     float *car=MRI_FLOAT_PTR(cim) ;
     float blur = bas->twoblur ;
     float bfac = blur ;
          if( bfac < 1.1234f ) bfac = 1.1234f ;
     else if( bfac > 1.3456f ) bfac = 1.3456f ;

     if( bas->verb ) fprintf(stderr,"+  Compute Derivatives of Blurred Base\n") ;
     EDIT_blur_volume_3d( nx,ny,nz ,       1.0f,1.0f,1.0f ,
                          MRI_float , car, blur,blur,blur  ) ;
     fitim = mri_warp3D_align_fitim( bas , cim , MRI_LINEAR , bfac*bas->delfac ) ;
     if( bas->verb ) fprintf(stderr,"+   calculate pseudo-inverse\n") ;
     bas->imps_blur = mri_psinv( fitim , wtar ) ;
     mri_free(fitim) ;
     if( bas->imps_blur == NULL ){  /* bad */
       fprintf(stderr,"** mri_warp3D_align error: can't invert Blur matrix!\n") ;
     }
   }

   /*--- done ---*/

   mri_free(cim) ; free((void *)wtar) ;

   if( bas->verb ){
     double st = (NI_clock_time()-ctstart) * 0.001 ;
     fprintf(stderr,"++ mri_warp3D_align_setup EXIT: %.2f seconds elapsed\n",st);
   }

   RETURN(0);
}
예제 #4
0
/* NIML workprocess.
    - Read and process any new data from open connection.
   
   The void * pointer thereiselvis is expected to point to a properly
   initialized communication structure.
   
  (If the return is True, that means don't call this workproc again.
   If the return is False, that means call this workproc again.......)
-------------------------------------------------------------------------*/
int Hallo_niml_workproc( void *thereiselvis )
{
   static char FuncName[]={"Hallo_niml_workproc"};
   int  nn, id;
   void *nini ;
   static int nwarn=0;
   char tmpcom[100], *nel_track;
   NI_element *nel ;
   int LocalHead = 0;
   COMM_STRUCT *cs=NULL;
   
   cs = (COMM_STRUCT *)thereiselvis;
      
  /* check if stream has gone bad */
  nn = NI_stream_goodcheck( cs->NimlStream , 1 ) ;

  if( nn < 0 ){
      /* first check in case we are dealing with the 
      intermittent AFNI disruption */
      if (1) {
         NI_stream_close( cs->NimlStream ) ;
         cs->NimlStream = NULL ;
         /* try again, a way to get around the weird disruption in 
            SHM connection*/
         fprintf(stderr,"Attempting recovery...\n");
         cs->Connected = 0;
         /* Retry calling function */ 
         if (!SendToSuma(cs, NULL, 0)) { /* buzz SUMA */
            fprintf (stderr,"Failed to re-initiate call suma\n");
         }
         nn = NI_stream_goodcheck( cs->NimlStream , 1 ) ;
      } else {
         fprintf(stderr,
                 "SUMA connection stream gone bad.\n" );
      }
  }

  if( nn < 0 ){                          /* is bad */
    if (cs->NimlStream) NI_stream_close( cs->NimlStream ) ;
    cs->NimlStream = NULL ; /* this will get checked next time */
    fprintf(stderr,"Stream gone bad. Stream closed. \n");
  } else if (nn == 0) { /* waiting, come back later */
    fprintf(stderr,"Waiting on stream\n");  
  } else {
   /* if here, stream is good;
      see if there is any data to be read */
      if (cs->NimlStream_flag & SUMA_FLAG_WAITING) {
         cs->NimlStream_flag = SUMA_FLAG_CONNECTED;
         fprintf(stderr, 
               "++ NIML connection opened from %s on port %d \n",
               NI_stream_name(cs->NimlStream), cs->TCP_port) ;
      }
      nn = NI_stream_hasinput( cs->NimlStream , 1 ) ;

      if( nn > 0 ){                                   /* has data */
         int ct = NI_clock_time() ;
         if (LocalHead)   
            fprintf(stderr,"%s: reading data stream", FuncName) ;

         nini = NI_read_element( cs->NimlStream , 1 ) ;  /* read it */

         if (LocalHead)   
            fprintf( stderr,
                     " time=%d ms\n",
                     NI_clock_time()-ct) ; ct = NI_clock_time() ;

         if( nini != NULL ) {
            nel = (NI_element *)nini ;

            if (LocalHead)   {
               fprintf( stderr,
                     "%s:     name=%s vec_len=%d vec_filled=%d, vec_num=%d\n", 
                     FuncName, nel->name, nel->vec_len, 
                     nel->vec_filled, nel->vec_num );
            }      
            if (!Hallo_process_NIML_data( nini )) {
               fprintf(stderr,
                  "Error %s: Failed in SUMA_process_NIML_data.\n", FuncName);
            }
         }

         NI_free_element( nini ) ;

         if (LocalHead)   
            fprintf(stderr,"processing time=%d ms\n",NI_clock_time()-ct) ;

      }
   } 
   
   /* Return flag for function calling the workprocess */
   if (!cs->NimlStream) {
      return(1); /* Don't call workprocess back */ 
   } else {
      return (0); /* Call workprocess back */
   }
}
예제 #5
0
파일: 3dUnifize.c 프로젝트: Gilles86/afni
int main( int argc , char *argv[] )
{
   int iarg , ct , do_GM=0 ;
   int do_T2=0 ; float T2_uperc=98.5f ; byte *T2_mask=NULL ;
   char *prefix = "Unifized" ;
   THD_3dim_dataset *inset=NULL , *outset=NULL ;
   MRI_IMAGE *imin , *imout ;
   float clfrac=0.2f ;

   AFNI_SETUP_OMP(0) ;  /* 24 Jun 2013 */

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
     printf("\n"
            "Usage: 3dUnifize [options] inputdataset\n\n"
            "* The input dataset is supposed to be a T1-weighted volume,\n"
            "  possibly already skull-stripped (e.g., via 3dSkullStrip).\n"
            "  ++ However, this program can be a useful step to take BEFORE\n"
            "     3dSkullStrip, since the latter program can fail if the input\n"
            "     volume is strongly shaded -- 3dUnifize will (mostly) remove\n"
            "     such shading artifacts.\n"
            "* The output dataset has the white matter (WM) intensity approximately\n"
            "  uniformized across space, and scaled to peak at about 1000.\n"
            "* The output dataset is always stored in float format!\n"
            "* If the input dataset has more than 1 sub-brick, only sub-brick\n"
            "  #0 will be processed!\n"
            "* Method: Obi-Wan's personal variant of Ziad's sneaky trick.\n"
            "  (If you want to know what his trick is, you'll have to ask him, or\n"
            "   read Obi-Wan's source code, which is a world of ecstasy and exaltation,\n"
            "   or just read all the way to the end of this help output.)\n"
            "* The principal motive for this program is for use in an image\n"
            "  registration script, and it may or may not be useful otherwise.\n"
            "\n"
            "--------\n"
            "Options:\n"
            "--------\n"
            "  -prefix pp = Use 'pp' for prefix of output dataset.\n"
            "  -input dd  = Alternative way to specify input dataset.\n"
            "  -T2        = Treat the input as if it were T2-weighted, rather than\n"
            "               T1-weighted. This processing is done simply by inverting\n"
            "               the image contrast, processing it as if that result were\n"
            "               T1-weighted, and then re-inverting the results.\n"
            "              ++ This option is NOT guaranteed to be useful for anything!\n"
            "              ++ Of course, nothing in AFNI comes with a guarantee :-)\n"
            "              ++ If you want to be REALLY sneaky, giving this option twice\n"
            "                 will skip the second inversion step, so the result will\n"
            "                 look like a T1-weighted volume (except at the edges and\n"
            "                 near blood vessels).\n"
            "              ++ Might be useful for skull-stripping T2-weighted datasets.\n"
            "              ++ Don't try the '-T2 -T2' trick on FLAIR-T2-weighted datasets.\n"
            "                 The results aren't pretty!\n"
            "  -GM        = Also scale to unifize 'gray matter' = lower intensity voxels\n"
            "               (to aid in registering images from different scanners).\n"
            "              ++ This option is recommended for use with 3dQwarp when\n"
            "                 aligning 2 T1-weighted volumes, in order to make the\n"
            "                 WM-GM contrast about the same for the datasets, even\n"
            "                 if they don't come from the same scanner/pulse-sequence.\n"
            "              ++ Note that standardizing the contrasts with 3dUnifize will help\n"
            "                 3dQwarp match the source dataset to the base dataset.  If you\n"
            "                 later want the original source dataset to be warped, you can\n"
            "                 do so using the 3dNwarpApply program.\n"
            "  -Urad rr   = Sets the radius (in voxels) of the ball used for the sneaky trick.\n"
            "               ++ Default value is %.1f, and should be changed proportionally\n"
            "                  if the dataset voxel size differs significantly from 1 mm.\n"
            "  -ssave ss  = Save the scale factor used at each voxel into a dataset 'ss'.\n"
            "               ++ This is the white matter scale factor, and does not include\n"
            "                  the factor from the '-GM' option (if that was included).\n"
            "               ++ The input dataset is multiplied by the '-ssave' image\n"
            "                  (voxel-wise) to get the WM-unifized image.\n"
            "               ++ Another volume (with the same grid dimensions) could be\n"
            "                  scaled the same way using 3dcalc, if that is needed.\n"
            "  -quiet     = Don't print the fun fun fun progress messages (but whyyyy?).\n"
            "               ++ For the curious, the codes used are:\n"
            "                   A = Automask\n"
            "                   D = Duplo down (process a half-size volume)\n"
            "                   V = Voxel-wise histograms to get local scale factors\n"
            "                   U = duplo Up (convert local scale factors to full-size volume)\n"
            "                   W = multiply by White matter factors\n"
            "                   G = multiply by Gray matter factors [cf the -GM option]\n"
            "                   I = contrast inversion              [cf the -T2 option]\n"
            "               ++ 'Duplo down' means to scale the input volume to be half the\n"
            "                  grid size in each direction for speed when computing the\n"
            "                  voxel-wise histograms.  The sub-sampling is done using the\n"
            "                  median of the central voxel value and its 6 nearest neighbors.\n"
            "\n"
            "------------------------------------------\n"
            "Special options for Jedi AFNI Masters ONLY:\n"
            "------------------------------------------\n"
            "  -rbt R b t = Specify the 3 parameters for the algorithm, as 3 numbers\n"
            "               following the '-rbt':\n"
            "                 R = radius; same as given by option '-Urad'     [default=%.1f]\n"
            "                 b = bottom percentile of normalizing data range [default=%.1f]\n"
            "                 r = top percentile of normalizing data range    [default=%.1f]\n"
            "\n"
            "  -T2up uu   = Set the upper percentile point used for T2-T1 inversion.\n"
            "               The default value is 98.5 (for no good reason), and 'uu' is\n"
            "               allowed to be anything between 90 and 100 (inclusive).\n"
            "               ++ The histogram of the data is built, and the uu-th percentile\n"
            "                  point value is called 'U'. The contrast inversion is simply\n"
            "                  given by output_value = max( 0 , U - input_value ).\n"
            "\n"
            "  -clfrac cc = Set the automask 'clip level fraction' to 'cc', which\n"
            "               must be a number between 0.1 and 0.9.\n"
            "               A small 'cc' means to make the initial threshold\n"
            "               for clipping (a la 3dClipLevel) smaller, which\n"
            "               will tend to make the mask larger.  [default=0.1]\n"
            "               ++ [22 May 2013] The previous version of this program used a\n"
            "                  clip level fraction of 0.5, which proved to be too large\n"
            "                  for some users, who had images with very strong shading issues.\n"
            "                  Thus, the default value for this parameter was lowered to 0.1.\n"
            "               ++ [24 May 2016] The default value for this parameter was\n"
            "                  raised to 0.2, since the lower value often left a lot of\n"
            "                  noise outside the head on non-3dSkullStrip-ed datasets.\n"
            "                  You can still manually set -clfrac to 0.1 if you need to\n"
            "                  correct for very large shading artifacts.\n"
            "               ++ If the results of 3dUnifize have a lot of noise outside the head,\n"
            "                  then using '-clfrac 0.5' value will probably help.\n"
#ifndef USE_ALL_VALS
            "\n"
            "  -useall    = The 'old' way of operating was to use all dataset values\n"
            "               in the local WM histogram.  The 'new' way [May 2016] is to\n"
            "               only use positive values.  If you want to use the 'old' way,\n"
            "               then this option is what you want.\n"
#endif
            "\n"
            "-- Feb 2013 - by Obi-Wan Unifobi\n"
#ifdef USE_OMP
            "-- This code uses OpenMP to speed up the slowest part (voxel-wise histograms).\n"
#endif
            , Uprad , Uprad , Upbot , Uptop ) ;

     printf("\n"
      "----------------------------------------------------------------------------\n"
      "HOW IT WORKS (Ziad's sneaky trick is revealed at last! And more.)\n"
      "----------------------------------------------------------------------------\n"
      "The basic idea is that white matter in T1-weighted images is reasonably\n"
      "uniform in intensity, at least when averaged over 'large-ish' regions.\n"
      "\n"
      "The first step is to create a local white matter intensity volume.\n"
      "Around each voxel (inside the volume 'automask'), the ball of values\n"
      "within a fixed radius (default=18.3 voxels) is extracted and these\n"
      "numbers are sorted.  The values in the high-intensity range of the\n"
      "histogram (default=70%% to 80%%) are averaged.  The result from this\n"
      "step is a smooth 3D map of the 'white matter intensity' (WMI).\n"
      "\n"
      " [The parameters of the above process can be altered with the '-rbt' option.]\n"
      " [For speed, the WMI map is produced on an image that is half-size in all   ]\n"
      " [directions ('Duplo down'), and then is expanded back to the full-size     ]\n"
      " [volume ('Duplo up').  The automask procedure can be somewhat controlled   ]\n"
      " [via the '-clfrac' option.  The default setting is designed to deal with   ]\n"
      " [heavily shaded images, where the WMI varies by a factor of 5 or more over ]\n"
      " [the image volume.                                                         ]\n"
      "\n"
      "The second step is to scale the value at every voxel location x in the input\n"
      "volume by the factor 1000/WMI(x), so that the 'white matter intensity' is\n"
      "now uniform-ized to be 1000 everywhere.  (This is Ziad's 'trick'; it is easy,\n"
      "works well, and doesn't require fitting some spatial model to the data: the\n"
      "data provides its own model.)\n"
      "\n"
      "If the '-GM' option is used, then this scaled volume is further processed\n"
      "to make the lower intensity values (presumably gray matter) have a contrast\n"
      "similar to that from a collection of 3 Tesla MP-RAGE images that were\n"
      "acquired at the NIH.  (This procedure is not Ziad's fault, and should be\n"
      "blamed on the reclusive Obi-Wan Unifobi.)\n"
      "\n"
      "From the WM-uniform-ized volume, the median of all values larger than 1000\n"
      "is computed; call this value P.  P-1000 represents the upward dispersion\n"
      "of the high-intensity (white matter) voxels in the volume.  This value is\n"
      "'reflected' below 1000 to Q = 1000 - 2*(P-1000), and Q is taken to be the\n"
      "upper bound for gray matter voxel intensities.  A lower bound for gray\n"
      "matter voxel values is estimated via the 'clip fraction' algorithm as\n"
      "implemented in program 3dClipLevel; call this lower bound R.  The median\n"
      "of all values between R and Q is computed; call this value G, which is taken\n"
      "to be a 'typical' gray matter voxel instensity.  Then the values z in the\n"
      "entire volume are linearly scaled by the formula\n"
      "   z_out = (1000-666)/(1000-G) * (z_in-1000) + 1000\n"
      "so that the WM uniform-ized intensity of 1000 remains at 1000, and the gray\n"
      "matter median intensity of G is mapped to 666.  (Values z_out that end up\n"
      "negative are set to 0; as a result, some of CSF might end up as 0.)\n"
      "The value 666 was chosen because it gave results visually comparable to\n"
      "various NIH-generated 3 Tesla T1-weighted datasets.  (Any suggestions that\n"
      "this value was chosen for other reasons will be treated as 'beastly'.)\n"
      "\n"
      "To recap: the WM uniform-ization process provides a linear scaling factor\n"
      "that varies for each voxel ('local'), while the GM normalization process\n"
      "uses a global linear scaling.  The GM process is optional, and is simply\n"
      "designed to make the various T1-weighted images look similar.\n"
      "\n"
      "-----** CAVEAT **-----\n"
      "This procedure was primarily developed to aid in 3D registration, especially\n"
      "when using 3dQwarp, so that the registration algorithms are trying to match\n"
      "images that are alike.  It is *NOT* intended to be used for quantification\n"
      "purposes, such as Voxel Based Morphometry!  That would better be done via\n"
      "the 3dSeg program, which is far more complicated.\n"
      "----------------------------------------------------------------------------\n"
     ) ;
     PRINT_COMPILE_DATE ; exit(0) ;
   }

   mainENTRY("3dUnifize main"); machdep(); AFNI_logger("3dUnifize",argc,argv);
   PRINT_VERSION("3dUnifize") ;
   ct = NI_clock_time() ;

   /*-- scan command line --*/

   THD_automask_set_clipfrac(0.1f) ;  /* 22 May 2013 */
   THD_automask_extclip(1) ;          /* 19 Dec 2014 */

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

     if( strcmp(argv[iarg],"-clfrac") == 0 || strcmp(argv[iarg],"-mfrac") == 0 ){    /* 22 May 2013 */
       if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ;
       clfrac = (float)strtod( argv[iarg] , NULL ) ;
       if( clfrac < 0.1f || clfrac > 0.9f )
         ERROR_exit("-clfrac value %f is illegal!",clfrac) ;
       THD_automask_set_clipfrac(clfrac) ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-prefix") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ;
       prefix = argv[iarg] ;
       if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix!") ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-ssave") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ;
       sspref = strdup(argv[iarg]) ;
       if( !THD_filename_ok(sspref) ) ERROR_exit("Illegal value after -ssave!") ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-input") == 0 || strcmp(argv[iarg],"-inset") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ;
       if( inset  != NULL ) ERROR_exit("Can't use '%s' twice"    ,argv[iarg-1]) ;
       inset = THD_open_dataset( argv[iarg] ) ;
       CHECK_OPEN_ERROR(inset,argv[iarg]) ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-Urad") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]) ;
       Uprad = (float)strtod(argv[iarg],NULL) ;
       if( Uprad <   5.0f || Uprad > 40.0f )
         ERROR_exit("Illegal value %f after option -Urad",Uprad) ;
       iarg++ ; continue ;
     }

#ifndef USE_ALL_VALS
     if( strcmp(argv[iarg],"-useall") == 0 ){   /* 17 May 2016 */
       USE_ALL_VALS = 1 ; iarg++ ; continue ;
     }
#else
     if( strcmp(argv[iarg],"-useall") == 0 ){
       WARNING_message("-useall option is disabled in this version") ;
       iarg++ ; continue ;
     }
#endif

     if( strcmp(argv[iarg],"-param") == 0 ||      /*--- HIDDEN OPTION ---*/
         strcmp(argv[iarg],"-rbt"  ) == 0    ){
       if( ++iarg >= argc-2 ) ERROR_exit("Need 3 arguments (R pb pt) after '%s'",argv[iarg-1]) ;
       Uprad = (float)strtod(argv[iarg++],NULL) ;
       Upbot = (float)strtod(argv[iarg++],NULL) ;
       Uptop = (float)strtod(argv[iarg++],NULL) ;
       if( Uprad <   5.0f || Uprad > 40.0f ||
           Upbot <  30.0f || Upbot > 80.0f ||
           Uptop <= Upbot || Uptop > 90.0f   )
         ERROR_exit("Illegal values (R pb pt) after '%s'",argv[iarg-4]) ;
       continue ;
     }

     if( strcasecmp(argv[iarg],"-GM") == 0 ){
       do_GM++ ; iarg++ ; continue ;
     }

     if( strcasecmp(argv[iarg],"-T2") == 0 ){  /* 18 Dec 2014 */
       do_T2++ ; iarg++ ; continue ;
     }

     if( strcasecmp(argv[iarg],"-T2up") == 0 ){  /* 18 Dec 2014 */
       T2_uperc = (float)strtod( argv[++iarg] , NULL ) ;
       if( T2_uperc < 90.0f || T2_uperc > 100.0f )
         ERROR_exit("-T2up value is out of range 90..100 :-(") ;
       iarg++ ; continue ;
     }

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

     ERROR_exit("Unknown option: %s\n",argv[iarg]);
   }

   /* read input dataset, if not already there */

   if( inset == NULL ){
     if( iarg >= argc ) ERROR_exit("No dataset name on command line?\n") ;
     inset = THD_open_dataset( argv[iarg] ) ;
     CHECK_OPEN_ERROR(inset,argv[iarg]) ;
   }

   if( verb ) fprintf(stderr," + Pre-processing: ") ;

   /* load input from disk */

   DSET_load( inset ) ; CHECK_LOAD_ERROR(inset) ;
   if( DSET_NVALS(inset) > 1 )
     WARNING_message("Only processing sub-brick #0 (out of %d)",DSET_NVALS(inset)) ;

   /* make a float copy for processing */

   imin = mri_to_float( DSET_BRICK(inset,0) ) ; DSET_unload(inset) ;
   if( imin == NULL ) ERROR_exit("Can't copy input dataset brick?!") ;

#if 0
THD_cliplevel_search(imin) ; exit(0) ;  /* experimentation only */
#endif

   THD_automask_set_clipfrac(clfrac) ;

   /* invert T2? */

   if( do_T2 ){
     if( verb ) fprintf(stderr,"I") ;
     T2_mask = mri_automask_image(imin) ;
     mri_invertcontrast_inplace( imin , T2_uperc , T2_mask ) ;
   }

   /* do the actual work */

   imout = mri_WMunifize(imin) ;          /* local WM scaling */
   free(imin) ;

   if( sspref != NULL && sclim != NULL ){  /* 25 Jun 2013 */
     STATUS("output -ssave") ;
     outset = EDIT_empty_copy( inset )  ;
     EDIT_dset_items( outset ,
                         ADN_prefix , sspref ,
                         ADN_nvals  , 1 ,
                         ADN_ntt    , 0 ,
                      ADN_none ) ;
     EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(sclim) ) ;
     tross_Copy_History( inset , outset ) ;
     tross_Make_History( "3dUnifize" , argc,argv , outset ) ;
     DSET_write(outset) ; outset = NULL ;
   }
   if( sclim != NULL ){ mri_free(sclim) ; sclim = NULL ; }

   if( imout == NULL ){                   /* this is bad-ositiness */
     if( verb ) fprintf(stderr,"\n") ;
     ERROR_exit("Can't compute Unifize-d dataset for some reason :-(") ;
   }

   if( do_GM ) mri_GMunifize(imout) ;     /* global GM scaling */

   if( do_T2 == 1 ){          /* re-invert T2? */
     if( verb ) fprintf(stderr,"I") ;
     mri_invertcontrast_inplace( imout , T2_uperc , T2_mask ) ;
   } else if( do_T2 == 2 ){   /* don't re-invert, but clip off bright edges */
     mri_clipedges_inplace( imout , PKVAL*1.111f , PKVAL*1.055f ) ;
   }

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

   /* create output dataset, and write it into the historical record */

   outset = EDIT_empty_copy( inset )  ;
   EDIT_dset_items( outset ,
                       ADN_prefix , prefix ,
                       ADN_nvals  , 1 ,
                       ADN_ntt    , 0 ,
                    ADN_none ) ;
   EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(imout) ) ;
   tross_Copy_History( inset , outset ) ;
   tross_Make_History( "3dUnifize" , argc,argv , outset ) ;
   DSET_write(outset) ;
   WROTE_DSET(outset) ;
   DSET_delete(outset) ; DSET_delete(inset) ;

   /* vamoose the ranch */

   if( verb ){
     double cput = COX_cpu_time() ;
     if( cput > 0.05 )
       INFO_message("===== CPU time = %.1f sec  Elapsed = %.1f\n",
                             COX_cpu_time() , 0.001*(NI_clock_time()-ct) ) ;
     else
       INFO_message("===== Elapsed = %.1f sec\n", 0.001*(NI_clock_time()-ct) ) ;
   }
   exit(0) ;
}
예제 #6
0
파일: 3dDespike.c 프로젝트: ccraddock/afni
int main( int argc , char *argv[] )
{
   THD_3dim_dataset *dset , *oset=NULL , *tset=NULL ;
   int nvals , iv , nxyz , ii,jj,kk , iarg , kz,kzold ;
   float cut1=2.5,cut2=4.0 , sq2p,sfac , fq ;
   MRI_IMAGE *flim ;
   char *prefix="despike" , *tprefix=NULL ;

   int corder=-1 , nref , ignore=0 , polort=2 , nuse , nomask=0 ;
   int nspike, nbig, nproc ;
   float **ref ;
   float  c21,ic21 , pspike,pbig ;
   short  *sar , *qar ;
   byte   *tar , *mask=NULL ;
   float  *zar , *yar ;
   int     datum ;
   int     localedit=0 ;  /* 04 Apr 2007 */
   int     verb=1 ;

   int     do_NEW = 0 ;   /* 29 Nov 2013 */
   MRI_IMAGE *NEW_psinv=NULL ;
   int     dilate = 4 ;   /* 04 Dec 2013 */
   int     ctim   = 0 ;

   /*----- Read command line -----*/

   AFNI_SETUP_OMP(0) ;  /* 24 Jun 2013 */

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
      printf("Usage: 3dDespike [options] dataset\n"
             "Removes 'spikes' from the 3D+time input dataset and writes\n"
             "a new dataset with the spike values replaced by something\n"
             "more pleasing to the eye.\n"
             "\n"
             "Method:\n"
             " * L1 fit a smooth-ish curve to each voxel time series\n"
             "    [see -corder option for description of the curve]\n"
             "    [see -NEW option for a different & faster fitting method]\n"
             " * Compute the MAD of the difference between the curve and\n"
             "    the data time series (the residuals).\n"
             " * Estimate the standard deviation 'sigma' of the residuals\n"
             "    as sqrt(PI/2)*MAD.\n"
             " * For each voxel value, define s = (value-curve)/sigma.\n"
             " * Values with s > c1 are replaced with a value that yields\n"
             "    a modified s' = c1+(c2-c1)*tanh((s-c1)/(c2-c1)).\n"
             " * c1 is the threshold value of s for a 'spike' [default c1=2.5].\n"
             " * c2 is the upper range of the allowed deviation from the curve:\n"
             "    s=[c1..infinity) is mapped to s'=[c1..c2)   [default c2=4].\n"
             "\n"
             "Options:\n"
             " -ignore I  = Ignore the first I points in the time series:\n"
             "               these values will just be copied to the\n"
             "               output dataset [default I=0].\n"
             " -corder L  = Set the curve fit order to L:\n"
             "               the curve that is fit to voxel data v(t) is\n"
             "\n"
             "                       k=L [        (2*PI*k*t)          (2*PI*k*t) ]\n"
             " f(t) = a+b*t+c*t*t + SUM  [ d * sin(--------) + e * cos(--------) ]\n"
             "                       k=1 [  k     (    T   )    k     (    T   ) ]\n"
             "\n"
             "               where T = duration of time series;\n"
             "               the a,b,c,d,e parameters are chosen to minimize\n"
             "               the sum over t of |v(t)-f(t)| (L1 regression);\n"
             "               this type of fitting is is insensitive to large\n"
             "               spikes in the data.  The default value of L is\n"
             "               NT/30, where NT = number of time points.\n"
             "\n"
             " -cut c1 c2 = Alter default values for the spike cut values\n"
             "               [default c1=2.5, c2=4.0].\n"
             " -prefix pp = Save de-spiked dataset with prefix 'pp'\n"
             "               [default pp='despike']\n"
             " -ssave ttt = Save 'spikiness' measure s for each voxel into a\n"
             "               3D+time dataset with prefix 'ttt' [default=no save]\n"
             " -nomask    = Process all voxels\n"
             "               [default=use a mask of high-intensity voxels, ]\n"
             "               [as created via '3dAutomask -dilate 4 dataset'].\n"
             " -dilate nd = Dilate 'nd' times (as in 3dAutomask).  The default\n"
             "               value of 'nd' is 4.\n"
             " -q[uiet]   = Don't print '++' informational messages.\n"
             "\n"
             " -localedit = Change the editing process to the following:\n"
             "                If a voxel |s| value is >= c2, then replace\n"
             "                the voxel value with the average of the two\n"
             "                nearest non-spike (|s| < c2) values; the first\n"
             "                one previous and the first one after.\n"
             "                Note that the c1 cut value is not used here.\n"
             "\n"
             " -NEW       = Use the 'new' method for computing the fit, which\n"
             "              should be faster than the L1 method for long time\n"
             "              series (200+ time points); however, the results\n"
             "              are similar but NOT identical. [29 Nov 2013]\n"
             "              * You can also make the program use the 'new'\n"
             "                method by setting the environment variable\n"
             "                  AFNI_3dDespike_NEW\n"
             "                to the value YES; as in\n"
             "                  setenv AFNI_3dDespike_NEW YES  (csh)\n"
             "                  export AFNI_3dDespike_NEW=YES  (bash)\n"
             "              * If this variable is set to YES, you can turn off\n"
             "                the '-NEW' processing by using the '-OLD' option.\n"
             "          -->>* For time series more than 500 points long, the\n"
             "                '-OLD' algorithm is tremendously slow.  You should\n"
             "                use the '-NEW' algorith in such cases.\n"
             "             ** At some indeterminate point in the future, the '-NEW'\n"
             "                method will become the default!\n"
             "          -->>* As of 29 Sep 2016, '-NEW' is the default if there\n"
             "                is more than 500 points in the time series dataset.\n"
             "\n"
             " -NEW25     = A slightly more aggressive despiking approach than\n"
             "              the '-NEW' method.\n"
             "\n"
             "Caveats:\n"
             "* Despiking may interfere with image registration, since head\n"
             "   movement may produce 'spikes' at the edge of the brain, and\n"
             "   this information would be used in the registration process.\n"
             "   This possibility has not been explored or calibrated.\n"
             "* [LATER] Actually, it seems like the registration problem\n"
             "   does NOT happen, and in fact, despiking seems to help!\n"
             "* Check your data visually before and after despiking and\n"
             "   registration!\n"
             "   [Hint: open 2 AFNI controllers, and turn Time Lock on.]\n"
            ) ;

      PRINT_AFNI_OMP_USAGE("3dDespike",NULL) ;
      PRINT_COMPILE_DATE ; exit(0) ;
   }

   /** AFNI package setup and logging **/

   mainENTRY("3dDespike main"); machdep(); AFNI_logger("3dDespike",argc,argv);
   PRINT_VERSION("3dDespike") ; AUTHOR("RW Cox") ;

   /** parse options **/

   if( AFNI_yesenv("AFNI_3dDespike_NEW") ) do_NEW = 1 ;  /* 29 Nov 2013 */

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

      if( strncmp(argv[iarg],"-q",2) == 0 ){       /* 04 Apr 2007 */
        verb = 0 ; iarg++ ; continue ;
      }
      if( strncmp(argv[iarg],"-v",2) == 0 ){
        verb++ ; iarg++ ; continue ;
      }

      if( strcmp(argv[iarg],"-NEW") == 0 ){       /* 29 Nov 2013 */
        do_NEW = 1 ; iarg++ ; continue ;
      }
      if( strcmp(argv[iarg],"-NEW25") == 0 ){     /* 29 Sep 2016 */
        do_NEW = 1 ; use_des25 = 1 ; cut1 = 2.5f ; cut2 = 3.2f ; iarg++ ; continue ;
      }
      if( strcmp(argv[iarg],"-OLD") == 0 ){
        do_NEW = 0 ; iarg++ ; continue ;
      }

      /** -localedit **/

      if( strcmp(argv[iarg],"-localedit") == 0 ){  /* 04 Apr 2007 */
        localedit = 1 ; iarg++ ; continue ;
      }

      /** don't use masking **/

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

      /** dilation count [04 Dec 2013] **/

      if( strcmp(argv[iarg],"-dilate") == 0 ){
        dilate = (int)strtod(argv[++iarg],NULL) ;
             if( dilate <=  0 ) dilate = 1 ;
        else if( dilate >  99 ) dilate = 99 ;
        iarg++ ; continue ;
      }

      /** output dataset prefix **/

      if( strcmp(argv[iarg],"-prefix") == 0 ){
        prefix = argv[++iarg] ;
        if( !THD_filename_ok(prefix) ) ERROR_exit("-prefix is not good");
        iarg++ ; continue ;
      }

      /** ratio dataset prefix **/

      if( strcmp(argv[iarg],"-ssave") == 0 ){
        tprefix = argv[++iarg] ;
        if( !THD_filename_ok(tprefix) ) ERROR_exit("-ssave prefix is not good");
        iarg++ ; continue ;
      }

      /** trigonometric polynomial order **/

      if( strcmp(argv[iarg],"-corder") == 0 ){
        corder = strtol( argv[++iarg] , NULL , 10 ) ;
        if( corder < 0 ) ERROR_exit("Illegal value of -corder");
        iarg++ ; continue ;
      }

      /** how much to ignore at start **/

      if( strcmp(argv[iarg],"-ignore") == 0 ){
        ignore = strtol( argv[++iarg] , NULL , 10 ) ;
        if( ignore < 0 ) ERROR_exit("Illegal value of -ignore");
        iarg++ ; continue ;
      }

      /** thresholds for s ratio **/

      if( strcmp(argv[iarg],"-cut") == 0 ){
        cut1 = strtod( argv[++iarg] , NULL ) ;
        cut2 = strtod( argv[++iarg] , NULL ) ;
        if( cut1 < 1.0 || cut2 < cut1+0.5 )
          ERROR_exit("Illegal values after -cut");
        iarg++ ; continue ;
      }

      ERROR_exit("Unknown option: %s",argv[iarg]) ;
   }

   c21 = cut2-cut1 ; ic21 = 1.0/c21 ;

   /*----- read input dataset -----*/

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

   dset = THD_open_dataset( argv[iarg] ) ;
   CHECK_OPEN_ERROR(dset,argv[iarg]) ;
   datum = DSET_BRICK_TYPE(dset,0) ;
   if( (datum != MRI_short && datum != MRI_float) || !DSET_datum_constant(dset) )
     ERROR_exit("Can't process non-short, non-float dataset!") ;

   if( verb ) INFO_message("Input data type = %s\n",MRI_TYPE_name[datum]) ;
   nvals = DSET_NUM_TIMES(dset) ; nuse = nvals - ignore ;
   if( nuse < 15 )
     ERROR_exit("Can't use dataset with < 15 time points per voxel!") ;

   if( nuse > 500 && !do_NEW ){
     INFO_message("Switching to '-NEW' method since number of time points = %d > 500",nuse) ;
     do_NEW = 1 ;
   }
   if( use_des25 && nuse < 99 ) use_des25 = 0 ;

   if( verb ) INFO_message("ignoring first %d time points, using last %d",ignore,nuse);
   if( corder > 0 && 4*corder+2 > nuse ){
     ERROR_exit("-corder %d is too big for NT=%d",corder,nvals) ;
   } else if( corder < 0 ){
     corder = rint(nuse/30.0) ; if( corder > 50 && !do_NEW ) corder = 50 ;
     if( verb ) INFO_message("using %d time points => -corder %d",nuse,corder) ;
   } else {
     if( verb ) INFO_message("-corder %d set from command line",corder) ;
   }
   nxyz = DSET_NVOX(dset) ;
   if( verb ) INFO_message("Loading dataset %s",argv[iarg]) ;
   DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ;

   /*-- create automask --*/

   if( !nomask ){
     mask = THD_automask( dset ) ;
     if( verb ){
       ii = THD_countmask( DSET_NVOX(dset) , mask ) ;
       INFO_message("%d voxels in the automask [out of %d in dataset]",ii,DSET_NVOX(dset)) ;
     }
     for( ii=0 ; ii < dilate ; ii++ )
       THD_mask_dilate( DSET_NX(dset), DSET_NY(dset), DSET_NZ(dset), mask, 3 ) ;
     if( verb ){
       ii = THD_countmask( DSET_NVOX(dset) , mask ) ;
       INFO_message("%d voxels in the dilated automask [out of %d in dataset]",ii,DSET_NVOX(dset)) ;
     }
   } else {
     if( verb ) INFO_message("processing all %d voxels in dataset",DSET_NVOX(dset)) ;
   }

   /*-- create empty despiked dataset --*/

   oset = EDIT_empty_copy( dset ) ;
   EDIT_dset_items( oset ,
                      ADN_prefix    , prefix ,
                      ADN_brick_fac , NULL ,
                      ADN_datum_all , datum ,
                    ADN_none ) ;

   if( THD_deathcon() && THD_is_file(DSET_HEADNAME(oset)) )
     ERROR_exit("output dataset already exists: %s",DSET_HEADNAME(oset));

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

   /* create bricks (will be filled with zeros) */

   for( iv=0 ; iv < nvals ; iv++ )
     EDIT_substitute_brick( oset , iv , datum , NULL ) ;

   /* copy the ignored bricks */

   switch( datum ){
     case MRI_short:
       for( iv=0 ; iv < ignore ; iv++ ){
         sar = DSET_ARRAY(oset,iv) ;
         qar = DSET_ARRAY(dset,iv) ;
         memcpy( sar , qar , DSET_BRICK_BYTES(dset,iv) ) ;
         DSET_unload_one(dset,iv) ;
       }
     break ;
     case MRI_float:
       for( iv=0 ; iv < ignore ; iv++ ){
         zar = DSET_ARRAY(oset,iv) ;
         yar = DSET_ARRAY(dset,iv) ;
         memcpy( zar , yar , DSET_BRICK_BYTES(dset,iv) ) ;
         DSET_unload_one(dset,iv) ;
       }
     break ;
   }

   /*-- setup to save a threshold statistic dataset, if desired --*/

   if( tprefix != NULL ){
     float *fac ;
     tset = EDIT_empty_copy( dset ) ;
     fac  = (float *) malloc( sizeof(float) * nvals ) ;
     for( ii=0 ; ii < nvals ; ii++ ) fac[ii] = TFAC ;
     EDIT_dset_items( tset ,
                        ADN_prefix    , tprefix ,
                        ADN_brick_fac , fac ,
                        ADN_datum_all , MRI_byte ,
                        ADN_func_type , FUNC_FIM_TYPE ,
                      ADN_none ) ;
     free(fac) ;

     tross_Copy_History( tset , dset ) ;
     tross_Make_History( "3dDespike" , argc , argv , tset ) ;

#if 0
     if( THD_is_file(DSET_HEADNAME(tset)) )
       ERROR_exit("-ssave dataset already exists");
#endif

     tross_Copy_History( tset , dset ) ;
     tross_Make_History( "3dDespike" , argc , argv , tset ) ;

     for( iv=0 ; iv < nvals ; iv++ )
       EDIT_substitute_brick( tset , iv , MRI_byte , NULL ) ;
   }

   /*-- setup to find spikes --*/

   sq2p  = sqrt(0.5*PI) ;
   sfac  = sq2p / 1.4826f ;

   /* make ref functions */

   nref = 2*corder+3 ;
   ref  = (float **) malloc( sizeof(float *) * nref ) ;
   for( jj=0 ; jj < nref ; jj++ )
     ref[jj] = (float *) malloc( sizeof(float) * nuse ) ;

   /* r(t) = 1 */

   for( iv=0 ; iv < nuse ; iv++ ) ref[0][iv] = 1.0 ;
   jj = 1 ;

   /* r(t) = t - tmid */

   { float tm = 0.5 * (nuse-1.0) ; float fac = 2.0 / nuse ;
     for( iv=0 ; iv < nuse ; iv++ ) ref[1][iv] = (iv-tm)*fac ;
     jj = 2 ;

     /* r(t) = (t-tmid)**jj */

     for( ; jj <= polort ; jj++ )
       for( iv=0 ; iv < nuse ; iv++ )
         ref[jj][iv] = pow( (iv-tm)*fac , (double)jj ) ;
   }

   for( kk=1 ; kk <= corder ; kk++ ){
     fq = (2.0*PI*kk)/nuse ;

     /* r(t) = sin(2*PI*k*t/N) */

     for( iv=0 ; iv < nuse ; iv++ )
       ref[jj][iv] = sin(fq*iv) ;
     jj++ ;

     /* r(t) = cos(2*PI*k*t/N) */

     for( iv=0 ; iv < nuse ; iv++ )
       ref[jj][iv] = cos(fq*iv) ;
     jj++ ;
   }

   /****** setup for the NEW solution method [29 Nov 2013] ******/

   if( do_NEW ){
     NEW_psinv = DES_get_psinv(nuse,nref,ref) ;
     INFO_message("Procesing time series with NEW model fit algorithm") ;
   } else {
     INFO_message("Procesing time series with OLD model fit algorithm") ;
   }

   /*--- loop over voxels and do work ---*/

#define Laplace_t2p(val) ( 1.0 - nifti_stat2cdf( (val), 15, 0.0, 1.4427 , 0.0 ) )

   if( verb ){
    if( !localedit ){
      INFO_message("smash edit thresholds: %.1f .. %.1f MADs",cut1*sq2p,cut2*sq2p) ;
      ININFO_message("  [ %.3f%% .. %.3f%% of normal distribution]",
                     200.0*qg(cut1*sfac) , 200.0*qg(cut2*sfac) ) ;
      ININFO_message("  [ %.3f%% .. %.3f%% of Laplace distribution]" ,
                   100.0*Laplace_t2p(cut1) , 100.0*Laplace_t2p(cut2) ) ;
    } else {
      INFO_message("local edit threshold:  %.1f MADS",cut2*sq2p) ;
      ININFO_message("  [ %.3f%% of normal distribution]",
                    200.0*qg(cut2*sfac) ) ;
      ININFO_message("  [ %.3f%% of Laplace distribution]",
                   100.0*Laplace_t2p(cut1) ) ;
    }
    INFO_message("%d slices to process",DSET_NZ(dset)) ;
   }
   kzold  = -1 ;
   nspike =  0 ; nbig = 0 ; nproc = 0 ; ctim = NI_clock_time() ;

 AFNI_OMP_START ;
#pragma omp parallel if( nxyz > 6666 )
 { int ii , iv , iu , id , jj ;
   float *far , *dar , *var , *fitar , *ssp , *fit , *zar ;
   short *sar , *qar ; byte *tar ;
   float fsig , fq , cls , snew , val ;
   float *NEW_wks=NULL ;

#pragma omp critical (DESPIKE_malloc)
  { far   = (float *) malloc( sizeof(float) * nvals ) ;
    dar   = (float *) malloc( sizeof(float) * nvals ) ;
    var   = (float *) malloc( sizeof(float) * nvals ) ;
    fitar = (float *) malloc( sizeof(float) * nvals ) ;
    ssp   = (float *) malloc( sizeof(float) * nvals ) ;
    fit   = (float *) malloc( sizeof(float) * nref  ) ;
    if( do_NEW ) NEW_wks = (float *)malloc(sizeof(float)*DES_workspace_size(nuse,nref)) ;
  }

#ifdef USE_OMP
   INFO_message("start OpenMP thread #%d",omp_get_thread_num()) ;
#endif

#pragma omp for
   for( ii=0 ; ii < nxyz ; ii++ ){   /* ii = voxel index */

      if( mask != NULL && mask[ii] == 0 ) continue ;   /* skip this voxel */

#ifndef USE_OMP
      kz = DSET_index_to_kz(dset,ii) ;       /* starting a new slice */
      if( kz != kzold ){
        if( verb ){
          fprintf(stderr, "++ start slice %2d",kz ) ;
          if( nproc > 0 ){
            pspike = (100.0*nspike)/nproc ;
            pbig   = (100.0*nbig  )/nproc ;
            fprintf(stderr,
                    "; so far %d data points, %d edits [%.3f%%], %d big edits [%.3f%%]",
                    nproc,nspike,pspike,nbig,pbig ) ;
          }
          fprintf(stderr,"\n") ;
        }
        kzold = kz ;
      }
#else
      if( verb && ii % 2345 == 1234 ) fprintf(stderr,".") ;
#endif

      /*** extract ii-th time series into far[] ***/

      switch( datum ){
        case MRI_short:
          for( iv=0 ; iv < nuse ; iv++ ){
            qar = DSET_ARRAY(dset,iv+ignore) ;   /* skip ignored data */
            far[iv] = (float)qar[ii] ;
          }
        break ;
        case MRI_float:
          for( iv=0 ; iv < nuse ; iv++ ){
            zar = DSET_ARRAY(dset,iv+ignore) ;
            far[iv] = zar[ii] ;
          }
        break ;
      }

      AAmemcpy(dar,far,sizeof(float)*nuse) ;   /* copy time series into dar[] */

      /*** solve for L1 fit ***/

      if( do_NEW )
        cls = DES_solve( NEW_psinv , far , fit , NEW_wks ) ; /* 29 Nov 2013 */
      else
        cls = cl1_solve( nuse , nref , far , ref , fit,0 ) ; /* the slow part */

      if( cls < 0.0f ){                      /* fit failed! */
#if 0
        fprintf(stderr,"curve fit fails at voxel %d %d %d\n",
                DSET_index_to_ix(dset,ii) ,
                DSET_index_to_jy(dset,ii) ,
                DSET_index_to_kz(dset,ii)  ) ;
#endif
        continue ;                           /* skip this voxel */
      }

      for( iv=0 ; iv < nuse ; iv++ ){        /* detrend */
        val =  fit[0]
             + fit[1]*ref[1][iv]             /* quadratic part of curve fit */
             + fit[2]*ref[2][iv] ;
        for( jj=3 ; jj < nref ; jj++ )       /* rest of curve fit */
          val += fit[jj] * ref[jj][iv] ;

        fitar[iv] = val ;                    /* save curve fit value */
        var[iv]   = dar[iv]-val ;            /* remove fitted value = resid */
        far[iv]   = fabsf(var[iv]) ;         /* abs value of resid */
      }

      /*** compute estimate standard deviation of detrended data ***/

      fsig = sq2p * qmed_float(nuse,far) ;   /* also mangles far array */

      /*** process time series for spikes, editing data in dar[] ***/

      if( fsig > 0.0f ){                     /* data wasn't fit perfectly */

        /* find spikiness for each point in time */

        fq = 1.0f / fsig ;
        for( iv=0 ; iv < nuse ; iv++ ){
          ssp[iv] = fq * var[iv] ;           /* spikiness s = how many sigma out */
        }

        /* save spikiness in -ssave datset */

        if( tset != NULL ){
          for( iv=0 ; iv < nuse ; iv++ ){
            tar     = DSET_ARRAY(tset,iv+ignore) ;
            snew    = ITFAC*fabsf(ssp[iv]) ;  /* scale for byte storage */
            tar[ii] = BYTEIZE(snew) ;         /* cf. mrilib.h */
          }
        }

        /* process values of |s| > cut1, editing dar[] */

        for( iv=0 ; iv < nuse ; iv++ ){ /* loop over time points */
          if( !localedit ){             /** classic 'smash' edit **/
            if( ssp[iv] > cut1 ){
              snew = cut1 + c21*mytanh((ssp[iv]-cut1)*ic21) ;   /* edit s down */
              dar[iv] = fitar[iv] + snew*fsig ;
#pragma omp critical (DESPIKE_counter)
              { nspike++ ; if( ssp[iv] > cut2 ) nbig++ ; }
            } else if( ssp[iv] < -cut1 ){
              snew = -cut1 + c21*mytanh((ssp[iv]+cut1)*ic21) ;  /* edit s up */
              dar[iv] = fitar[iv] + snew*fsig ;
#pragma omp critical (DESPIKE_counter)
              { nspike++ ; if( ssp[iv] < -cut2 ) nbig++ ; }
            }
          } else {                      /** local edit: 04 Apr 2007 **/
            if( ssp[iv] >= cut2 || ssp[iv] <= -cut2 ){
              for( iu=iv+1 ; iu < nuse ; iu++ )  /* find non-spike above */
                if( ssp[iu] < cut2 && ssp[iu] > -cut2 ) break ;
              for( id=iv-1 ; id >= 0   ; id-- )  /* find non-spike below */
                if( ssp[id] < cut2 && ssp[id] > -cut2 ) break ;
              switch( (id>=0) + 2*(iu<nuse) ){   /* compute replacement val */
                case 3: val = 0.5*(dar[iu]+dar[id]); break; /* iu and id OK */
                case 2: val =      dar[iu]         ; break; /* only iu OK   */
                case 1: val =              dar[id] ; break; /* only id OK   */
               default: val = fitar[iv]            ; break; /* shouldn't be */
              }
              dar[iv] = val ;
#pragma omp critical (DESPIKE_counter)
              { nspike++ ; nbig++ ; }
            }
          }
        } /* end of loop over time points */
#pragma omp atomic
        nproc += nuse ;  /* number data points processed */

      } /* end of processing time series when fsig is positive */

      /* put dar[] time series (possibly edited above) into output bricks */

      switch( datum ){
        case MRI_short:
          for( iv=0 ; iv < nuse ; iv++ ){
            sar = DSET_ARRAY(oset,iv+ignore) ; /* output brick */
            sar[ii] = (short)dar[iv] ;         /* original or mutated data */
          }
        break ;
        case MRI_float:
          for( iv=0 ; iv < nuse ; iv++ ){
            zar = DSET_ARRAY(oset,iv+ignore) ; /* output brick */
            zar[ii] = dar[iv] ;                /* original or mutated data */
          }
        break ;
      }

   } /* end of loop over voxels #ii */

#pragma omp critical (DESPIKE_malloc)
   { free(fit); free(ssp); free(fitar); free(var); free(dar); free(far);
     if( do_NEW ) free(NEW_wks) ; }

 } /* end OpenMP */
 AFNI_OMP_END ;

#ifdef USE_OMP
   if( verb ) fprintf(stderr,"\n") ;
#endif
   ctim = NI_clock_time() - ctim ;
   INFO_message( "Elapsed despike time = %s" , nice_time_string(ctim) ) ;
   if( ctim > 345678 && !do_NEW )
     ININFO_message("That was SLOW -- try the '-NEW' option for a speedup") ;

#ifdef USE_OMP
   if( verb ) fprintf(stderr,"\n") ;
#endif

   /*--- finish up ---*/

   if( do_NEW ) mri_free(NEW_psinv) ;

   DSET_delete(dset) ; /* delete input dataset */

   if( verb ){
     if( nproc > 0 ){
       pspike = (100.0*nspike)/nproc ;
       pbig   = (100.0*nbig  )/nproc ;
       INFO_message("FINAL: %d data points, %d edits [%.3f%%], %d big edits [%.3f%%]",
               nproc,nspike,pspike,nbig,pbig ) ;
     } else {
       INFO_message("FINAL: no good voxels found to process!!??") ;
     }
   }

   /* write results */

   DSET_write(oset) ;
   if( verb ) WROTE_DSET(oset) ;
   DSET_delete(oset) ;

   if( tset != NULL ){
     DSET_write(tset) ;
     if( verb ) WROTE_DSET(tset) ;
     DSET_delete(tset) ;
   }

   exit( THD_get_write_error_count() ) ;
}
예제 #7
0
파일: nicat.c 프로젝트: Gilles86/afni
int main( int argc , char *argv[] )
{
   NI_stream ns ;
   char lbuf[NBUF] , *reop=NULL ;
   int nn , nl=0 , jj , ntot=0 , ct , ech , iarg=1 ;

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
     printf("Usage: nicat [-reopen rr] [-rR] streamspec\n"
            "Copies stdin to the NIML stream, which will be opened\n"
            "for writing.\n"
            "\n"
            "-reopen rr == reopen the stream after connection\n"
            "               to the stream specified by 'rr'\n"
            "-r         == Copy the stream to stdout instead; the\n"
            "               'streamspec' will be opened for reading.\n"
            "-R         == Read the stream but don't copy to stdout.\n"
            "\n"
            "Intended for testing other programs that use NIML for\n"
            "various services.  Example:\n"
            "  aiv -p 4444 &\n"
            "  im2niml zork.jpg | nicat tcp:localhost:4444\n"
            "Starts aiv listening on TCP/IP port 444, then sends image\n"
            "file zork.jpg to that port for display.\n"
           ) ;
     exit(0) ;
   }

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

   /** write stdin to the stream **/

   if( toupper(argv[iarg][1]) != 'R' ){
     ns = NI_stream_open( argv[iarg] , "w" ) ;
     if( ns == NULL ){
        fprintf(stderr,"** NI_stream_open fails\n") ; exit(1) ;
     }
     while(1){
       nn = NI_stream_writecheck( ns , 400 ) ;
       if( nn == 1 ){ fprintf(stderr,"!\n") ; break ; }
       if( nn <  0 ){ fprintf(stderr,"BAD\n"); exit(1) ; }
       fprintf(stderr,"-") ;
     }
     if( reop ){                                 /* 23 Aug 2002 */
       fprintf(stderr,"++ reopening") ;
       nn = NI_stream_reopen( ns , reop ) ;
       if( nn == 0 ) fprintf(stderr,".BAD") ;
       else          fprintf(stderr,".GOOD") ;
       fprintf(stderr,"\n") ;
     }
     ct = NI_clock_time() ;
     while(1){
       jj = fread(lbuf,1,NBUF,stdin) ; if( jj <= 0 ) break ;
       nn = NI_stream_write( ns , lbuf , jj ) ;
       if( nn < 0 ){
          fprintf(stderr,"** NI_stream_write fails\n"); break ;
       } else if( nn < jj ){
          fprintf(stderr,"++ nl=%d: wrote %d/%d bytes\n",nl,nn,jj) ;
       }
       nl++ ; ntot += jj ;
     }
     NI_sleep(1) ; NI_stream_close(ns) ;
     ct = NI_clock_time()-ct ;
     fprintf(stderr,"++ Wrote %d bytes in %d ms: %.3f Mbytes/s\n",
                    ntot,ct,(9.5367e-7*ntot)/(1.e-3*ct)       ) ;
     sleep(1) ; exit(0) ;
   }

   /** write the stream to stdout */

   if( argc < iarg+2 ){
     fprintf(stderr,"** %s needs argv[%d]\n",argv[1],iarg+1); exit(1);
   }

   ech = (argv[iarg][1] == 'r') ;

   ns = NI_stream_open( argv[iarg+1], (argv[iarg][2]=='\0') ? "r" : "w" ) ;
   if( ns == NULL ){
     fprintf(stderr,"** NI_stream_open fails\n") ; exit(1) ;
   }
   while(1){
     nn = NI_stream_readcheck( ns , 400 ) ;
     if( nn == 1 ){ fprintf(stderr,"!\n") ; break ; }
     if( nn <  0 ){ fprintf(stderr,"BAD\n"); exit(1) ; }
     fprintf(stderr,"-") ;
   }
   if( reop ){                                 /* 23 Aug 2002 */
     fprintf(stderr,"++ reopening") ;
     nn = NI_stream_reopen( ns , reop ) ;
     if( nn == 0 ) fprintf(stderr,".BAD") ;
     else          fprintf(stderr,".GOOD") ;
     fprintf(stderr,"\n") ;
   }
   ct = NI_clock_time() ;
   while(1){
      nn = NI_stream_read( ns , lbuf , NBUF ) ;
      if( nn < 0 ){
         fprintf(stderr,"\nNI_stream_read fails\n"); break;
      } else {
         ntot += nn ;
      }
      if( ech && nn > 0 ){
         printf("%.*s",nn,lbuf) ; nl++ ;
      }
   }
   ct = NI_clock_time()-ct ;
   fprintf(stderr,"Read %d bytes in %d ms: %.3f Mbytes/s\n",
                   ntot,ct,(9.5367e-7*ntot)/(1.e-3*ct)       ) ;
   sleep(1) ; exit(0) ;
}
예제 #8
0
파일: niml_feedme.c 프로젝트: Gilles86/afni
int main( int argc , char *argv[] )
{
   char *drive_afni[128] ;
   int   ndrive=0 , iarg=1 ;

   char host[1024]="localhost", nsname[2048], *geomstr, *cpt, temp[32] ;
   int dt=1000 , ctold,ctnew , ctzero ;
   int verbose=0 , kk,nn , nvox,nval , do_accum=0 ;
   THD_3dim_dataset *dset ;
   NI_element *nel ;
   MRI_IMAGE *fim ; float *far ;
   char *targname="niml_feedme" ;

   /*-- help the ignorant user --*/

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
      printf(
        "Usage: niml_feedme [options] dataset\n"
        "\n"
        "* Sends volumes from the dataset to AFNI via the NIML socket interface.\n"
        "* You must run AFNI with the command 'afni -niml' so that the program\n"
        "  will be listening for the socket connection.\n"
        "* Inside AFNI, the transmitted dataset will be named 'niml_feedme'.\n"
        "* For another way to send image data to AFNI, see progam rtfeedme.\n"
        "* At present, there is no way to attach statistical parameters to\n"
        "  a transmitted volume.\n"
        "* This program sends all volumes in float format, simply because\n"
        "  that's easy for me.  But you can also send byte, short, and\n"
        "  complex valued volumes.\n"
        "* This program is really just a demo; it has little practical use.\n"
        "\n"
        "OPTIONS:\n"
        "  -host sname =  Send data, via TCP/IP, to AFNI running on the\n"
        "                 computer system 'sname'.  By default, uses the\n"
        "                 current system (localhost), if you don't use this\n"
        "                 option.\n"
        "\n"
        "  -dt ms      =  Tries to maintain an inter-transmit interval of 'ms'\n"
        "                 milliseconds.  The default is 1000 msec per volume.\n"
        "\n"
        "  -verb       =  Be (very) talkative about actions.\n"
        "\n"
        "  -accum      =  Send sub-bricks so that they accumulate in AFNI.\n"
        "                 The default is to create only a 1 volume dataset\n"
        "                 inside AFNI, and each sub-brick just replaces\n"
        "                 that one volume when it is received.\n"
        "\n"
        "  -target nam =  Change the dataset name transmitted to AFNI from\n"
        "                 'niml_feedme' to 'nam'.\n"
        "\n"
        "  -drive cmd  =  Send 'cmd' as a DRIVE_AFNI command.\n"
        "                * If cmd contains blanks, it must be in 'quotes'.\n"
        "                * Multiple -drive options may be used.\n"
        "                * These commands will be sent to AFNI just after\n"
        "                  the first volume is transmitted.\n"
        "                * See file README.driver for a list of commands.\n"
        "\n"
        "EXAMPLE: Send volumes from a 3D+time dataset to AFNI:\n"
        "\n"
        "  niml_feedme -dt 1000 -verb -accum -target Elvis \\\n"
        "              -drive 'OPEN_WINDOW axialimage'     \\\n"
        "              -drive 'OPEN_WINDOW axialgraph'     \\\n"
        "              -drive 'SWITCH_UNDERLAY Elvis'      \\\n"
        "              timeseries+orig\n"
        "\n"
        "Author: RW Cox -- July 2009\n"
      ) ;
      PRINT_COMPILE_DATE ;
      exit(0) ;
   }

   mainENTRY("niml_feedme") ;

   /*-- scan arguments --*/

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

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

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

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

      if( strcmp(argv[iarg],"-dt") == 0 ){
        dt = (int)strtod(argv[++iarg],NULL) ; if( dt < 9 ) dt = 9 ;
        iarg++ ; continue ;
      }

      if( strncmp(argv[iarg],"-verbose",4) == 0 ){
        verbose = 1 ; iarg++ ; continue ;
      }

      if( strncmp(argv[iarg],"-accum",4) == 0 ){
        do_accum = 1 ; iarg++ ; continue ;
      }

      ERROR_exit("Unrecognized option: %s",argv[iarg]) ;
   }

   if( iarg >= argc ) ERROR_exit("No dataset on command line?!") ;

   /*-- read in the dataset --*/

   dset = THD_open_dataset( argv[iarg] ) ;
   if( dset == NULL ) ERROR_exit("Can't open dataset '%s'",argv[iarg]) ;
   DSET_load(dset) ;
   if( !DSET_LOADED(dset) ) ERROR_exit("Can't load dataset '%s'",argv[iarg]) ;

   cpt     = EDIT_get_geometry_string(dset) ;
   geomstr = strdup(cpt) ;  /* describes geometry of dataset grid */

   if( verbose ) INFO_message("geometry string = '%s'",geomstr) ;

   nvox = DSET_NVOX(dset);  /* number of voxels in dataset */
   nval = DSET_NVALS(dset); /* number of sub-bricks in dataset */

   /*-- this stuff is one-time-only setup of the I/O to AFNI --*/

   atexit(NF_exit) ;             /* call this when program ends */

   signal(SIGINT ,NF_sigfunc) ;  /* setup signal handler */
   signal(SIGBUS ,NF_sigfunc) ;  /* for fatal errors */
   signal(SIGSEGV,NF_sigfunc) ;
   signal(SIGTERM,NF_sigfunc) ;

   /* name of NIML stream (socket) to open */

   sprintf( nsname , "tcp:%s:%d" , host , get_port_named("AFNI_DEFAULT_LISTEN_NIML"));

   /* open the socket (i.e., dial the telephone call) */

   fprintf(stderr,"opening NIML stream '%s' ",nsname) ;
   NF_stream = NI_stream_open( nsname , "w" ) ;

   /* loop until AFNI connects (answers the call),
      printing a '.' every 1/2 second to keep the user happy */

   while(1){
     kk = NI_stream_writecheck( NF_stream , 500 ) ;
     if( kk == 1 ){ fprintf(stderr," connected!\n") ; break ; }
     if( kk <  0 ){ fprintf(stderr," ** connection fails **\n") ; exit(1) ; }
     fprintf(stderr,".") ;
   }

   /*-- Create VOLUME_DATA NIML element to hold the brick data --*/

   nel = NI_new_data_element( "VOLUME_DATA" , nvox ) ;

   /* add attributes to the element to help AFNI construct the dataset */

     /* define the grid of the dataset */
   NI_set_attribute( nel , "geometry_string" , geomstr ) ;

     /* define the name of the dataset */
   NI_set_attribute( nel , "target_name"     , targname ) ;

     /* all sub-bricks in the input dataset will be sent to be
        sub-brick #0 in the dataset inside AFNI
        -- if you don't want this behavior, and want the dataset
           inside AFNI to keep growing, then don't set this attribute! */

   if( !do_accum ) NI_set_attribute( nel , "index" , "0" ) ;

     /* +tlrc view?  [default in AFNI is +orig view] */
   if( dset->view_type == VIEW_TALAIRACH_TYPE )
     NI_set_attribute( nel , "view" , "tlrc" ) ;

   /**-- loop over sub-bricks and send them to AFNI --*/

   ctzero = NI_clock_time() ;  /* for later reference */

   if( verbose ) INFO_message("Starting sub-brick loop") ;

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

     ctold = NI_clock_time() ;   /* clock time at start of work (ms) */

     /* get a float copy of the kk-th sub-brick */

     fim = THD_extract_float_brick( kk , dset ) ;

     DSET_unload_one(dset,kk) ;  /* unload this sub-brick now */

     if( fim == NULL ){  /* should never happen */
       ERROR_message("Can't get sub-brick #%d?? -- skipping",kk) ;
       NI_sleep(dt) ; continue ;
     }

     /* copy the float data into the NIML element for transmission */

     far = MRI_FLOAT_PTR(fim) ;
     if( kk == 0 )               /* first time: create data column in element */
       NI_add_column( nel , NI_FLOAT , far ) ;
     else                        /* later times: overwrite nel data column */
       memcpy( nel->vec[0] , far , sizeof(float)*nvox ) ;

     mri_free(fim) ;  /* done with this now [data all copied to nel] */

     /* set sub-brick index in AFNI if doing accumulation */

     if( do_accum ){
       sprintf(temp,"%d",kk) ; NI_set_attribute( nel , "index" , temp ) ;
     }

     /*** send the data element to AFNI ***/

     nn = NI_write_element( NF_stream , nel , NI_BINARY_MODE ) ;

     /* if something bad happened in the transmission, report it */

     if( nn <= 0 ){
       ERROR_message("Can't write sub-brick #%d to AFNI!",kk) ; break ;
     }

     /*** first time through ==>
          do the '-drive' commands now by sending processing instructions ***/

     if( kk == 0 && ndrive > 0 ){
       int ii ; NI_procins *npi ;
       if( verbose )
         ININFO_message("Sending %d 'drive_afni' elements now",ndrive) ;
       npi = NI_new_processing_instruction( "DRIVE_AFNI" ) ;
       NI_sleep(1) ;    /* give AFNI a msec to digest the data */
       for( ii=0 ; ii < ndrive ; ii++ ){
         NI_set_attribute( npi , "cmd" , drive_afni[ii] ) ;
         (void)NI_write_element( NF_stream , npi , NI_TEXT_MODE ) ;
       }
       NI_free_element(npi) ; /* delete this struct from the world! */
     }

     ctnew = NI_clock_time() ;  /* clock time now */

     if( verbose ) ININFO_message("Sent %d bytes for sub-brick #%d in %d ms",
                                  nn , kk , ctnew-ctold ) ;

     NI_sleep( dt - (ctnew-ctold) ) ;  /* sleep so that time delay is right */

   } /* end of loop over sub-bricks */

   /** summarize, do some cleanup, and exit stage left **/

   if( verbose && kk > 0 ){
     float dtav = (NI_clock_time()-ctzero) / (float)kk ;
     INFO_message("Transmission finished: %.1f ms = average time per volume",dtav) ;
   }

   NI_free_element(nel) ;  /* destroy the data element */
   DSET_delete(dset) ;     /* destroy the dataset */

   exit(0) ;
}