Пример #1
0
void mri_GMunifize( MRI_IMAGE *gim )
{
   float *gar=MRI_FLOAT_PTR(gim) , *pval , pupper,plower,pmid,pfac ;
   int ii,jj , npval , nvox=gim->nvox ;

ENTRY("mri_GMunifize") ;

   /* extract all values above the WM-unifized peak value */

   for( npval=ii=0 ; ii < nvox ; ii++ )
     if( gar[ii] > PKVAL ) npval++ ;
   if( npval < 111 ) EXRETURN ;   /* 1/6 of being beastly bad */

   pval = (float *)malloc(sizeof(float)*npval) ;
   for( ii=jj=0 ; ii < nvox ; ii++ )
     if( gar[ii] > PKVAL ) pval[jj++] = gar[ii] ;

   /* get the median of these large values */

   pupper = qmed_float(npval,pval) ; free(pval) ;

   /* reflect below the peak value to get the upper cutoff for GM */

   pupper = PKVAL - 1.987654321f * (pupper-PKVAL) ;

   /* set the lower cutoff for GM from the AFNI auto-clip level */

   plower = THD_cliplevel(gim,0.4321f) ;

   /* extract all values between these 2 cutoffs */

   for( npval=ii=0 ; ii < nvox ; ii++ )
     if( gar[ii] >= plower && gar[ii] <= pupper) npval++ ;
   if( npval < 111 ) EXRETURN ;    /* badly bad */

   pval = (float *)malloc(sizeof(float)*npval) ;
   for( ii=jj=0 ; ii < nvox ; ii++ )
     if( gar[ii] >= plower && gar[ii] <= pupper) pval[jj++] = gar[ii] ;

   /* compute the median of these intermediate-value 'GM' voxels */

   pmid = qmed_float(npval,pval) ; free(pval) ;

   /* scale globally to put this pmid value at a standard value for GM */

   pfac = (PKVAL-PKMID) / (PKVAL-pmid) ;

   for( ii=0 ; ii < nvox ; ii++ ){
     if( gar[ii] > 0.0f ){
       gar[ii] = pfac * (gar[ii]-PKVAL) + PKVAL ;
       if( gar[ii] < 0.0f ) gar[ii] = 0.0f ;
     } else {
       gar[ii] = 0.0f ;
     }
   }

   if( verb ) fprintf(stderr,"G") ;
   EXRETURN ;
}
Пример #2
0
MRI_IMAGE * THD_median_brick( THD_3dim_dataset *dset )
{
   int nvox , nvals , ii ;
   MRI_IMAGE *tsim , *medim ;
   float *medar ;
   float *tsar ;  /* 05 Nov 2001 */

ENTRY("THD_median_brick") ;

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

   nvals = DSET_NVALS(dset) ;
   tsim  = DSET_BRICK(dset,0) ;

   if( nvals == 1 ){
     medim = mri_scale_to_float( DSET_BRICK_FACTOR(dset,0), tsim ) ;
     RETURN(medim) ;
   }

   medim = mri_new_conforming( tsim , MRI_float ) ;
   medar = MRI_FLOAT_PTR(medim) ;
   nvox  = DSET_NVOX(dset) ;

   tsar = (float *) calloc( sizeof(float),nvals+1 ) ; /* 05 Nov 2001 */
   for( ii=0 ; ii < nvox ; ii++ ){
     THD_extract_array( ii , dset , 0 , tsar ) ;     /* 05 Nov 2001 */
     medar[ii] = qmed_float( nvals , tsar ) ;
   }

   free(tsar) ; RETURN(medim) ;
}
Пример #3
0
static int DES_despike9( int num , float *vec , float *wks )
{
   int ii , nsp ; float *zma,*zme , med,mad,val ;

   if( num < 9 || vec == NULL ) return 0 ;

   if( wks != NULL ) zme = wks ;
   else              zme = (float *)malloc(sizeof(float)*(2*num)) ;
   zma = zme + num ;

   DES9_init ; /* 18 Apr 2019 */

   for( ii=0 ; ii < num ; ii++ ){
     mead9(ii) ; zme[ii] = med ; zma[ii] = mad ;
   }
   mad = qmed_float(num,zma) ;
   if( mad <= 0.0f ){ if( wks == NULL ) free(zme); return 0; }  /* should not happen */
   mad *= 6.789f ;  /* threshold value */

   for( nsp=ii=0 ; ii < num ; ii++ )
     if( fabsf(vec[ii]-zme[ii]) > mad ){ vec[ii] = zme[ii]; nsp++; }

   if( wks == NULL ) free(zme) ;
   return nsp ;
}
Пример #4
0
float extreme_proj( int n , float *ar )  /* 02 Feb 2002 */
{
   float vv,ww , med=qmed_float(n,ar) ;
   int ii , jj ;

   jj = 0 ; vv = fabs(ar[0]-med) ;      /* Find the value */
   for( ii=1 ; ii < n ; ii++ ){         /* furthest from */
     ww = fabs(ar[ii]-med) ;            /* the median.  */
     if( ww > vv ){ vv=ww; jj=ii; }
   }
   return ar[jj] ;
}
Пример #5
0
void median21_box_func( int nx , int ny , double dx, double dy, float *ar )
{
   int ii , jj , nxy , joff ;
   float aa[21] ;
   float *ajj , *ajm , *ajp , *ajmm , *ajpp ;

   if( nx < 5 || ny < 5 ) return ;

   /** make space and copy input into it **/

   nxy = nx * ny ;
   MAKE_ATEMP(nxy) ; if( atemp == NULL ) return ;
   memcpy(atemp,ar,sizeof(float)*nxy) ;

   /** process copy of input back into the input array **/

   for( jj=1 ; jj < ny-1 ; jj++ ){

      joff = jj * nx ;      /* offset into this row */
      ajj  = atemp + joff ; /* pointer to this row */

      ajm  = ajj-nx ;  /* pointer to last row */
      ajp  = ajj+nx ;  /* pointer to next row */

      ajmm = (jj == 1  ) ? ajm : ajm-nx ;  /* to last last row */
      ajpp = (jj ==ny-2) ? ajp : ajp+nx ;  /* to next next row */

      /* do interior points of this row */

      for( ii=2 ; ii < nx-2 ; ii++ ){
         aa[0]=ajmm[ii-1]; aa[1]=ajmm[ii]; aa[2]=ajmm[ii+1];

         aa[ 3]=ajm[ii-2]; aa[ 4]=ajm[ii-1]; aa[ 5]=ajm[ii]; aa[ 6]=ajm[ii+1]; aa[ 7]=ajm[ii+2];
         aa[ 8]=ajj[ii-2]; aa[ 9]=ajj[ii-1]; aa[10]=ajj[ii]; aa[11]=ajj[ii+1]; aa[12]=ajj[ii+2];
         aa[13]=ajp[ii-2]; aa[14]=ajp[ii-1]; aa[15]=ajp[ii]; aa[16]=ajp[ii+1]; aa[17]=ajp[ii+2];

         aa[18]=ajpp[ii-1]; aa[19]=ajpp[ii]; aa[20]=ajpp[ii+1];

#if 0
         isort_float( 21 , aa ) ; ar[ii+joff] = aa[10] ;
#else
         ar[ii+joff] = qmed_float(21,aa) ; /* 25 Oct 2000 */
#endif
      }

   }
   return ;
}
Пример #6
0
MRI_IMAGE * mri_sharpness( MRI_IMAGE *inim )
{
   int nx,ny , ii,ip,im , jj,jp,jm ;
   float *innar , *outar , avv,qvv ;
   MRI_IMAGE *outim , *innim ;

   if( inim == NULL ) return NULL ;

   innim = mri_to_float(inim) ;
   innar = MRI_FLOAT_PTR(innim) ; nx = innim->nx ; ny = innim->ny ;

   outim = mri_new_conforming( innim , MRI_float ) ; /* all zero */
   outar = MRI_FLOAT_PTR(outim) ;

   { float *qar = (float *)malloc(sizeof(float)*nx*ny) ; int nq=0 ;
     for( ii=0 ; ii < nx*ny ; ii++ )
       if( innar[ii] != 0.0f ) qar[nq++] = fabsf(innar[ii]) ;
     if( nq < 32 ) qvv = 0.0f ;
     else          qvv = 0.18f * qmed_float(nq,qar) ;
     free(qar) ;
   }
   if( qvv == 0.0f ){ mri_free(innim) ; return outim ; }  /* input is all 0! */

   for( jj=0 ; jj < ny ; jj++ ){
     jm = jj-1 ; if( jm <  0  ) jm++ ;
     jp = jj+1 ; if( jp >= ny ) jp-- ;
     for( ii=0 ; ii < nx ; ii++ ){
       im = ii-1 ; if( im <  0  ) im++ ;
       ip = ii+1 ; if( ip >= nx ) ip-- ;
       avv =  fabsf(IAR(im,jm)) + fabsf(IAR(im,jp)) + fabsf(IAR(ip,jm)) + fabsf(IAR(ip,jp))
            + fabsf(IAR(ii,jm)) + fabsf(IAR(ii,jp)) + fabsf(IAR(im,jj)) + fabsf(IAR(ip,jj))
            + fabsf(IAR(ii,jj)) ;
       if( avv < qvv ) avv = qvv ;
       OAR(ii,jj) = fabsf(            IAR(im,jm) + IAR(im,jp) + IAR(ip,jm) + IAR(ip,jp)
                          +  4.0f * ( IAR(ii,jm) + IAR(ii,jp) + IAR(im,jj) + IAR(ip,jj) )
                          - 20.0f * IAR(ii,jj) ) / avv ;
      }
    }

    innim = mri_median21(outim) ;
    mri_free(outim) ; return innim ;
}
Пример #7
0
void despike9_func( int num , double to,double dt , float *vec )
{
   int ii ; float *zma,*zme , med,mad,val ;

   if( num < 9 ) return ;
   zme = (float *)malloc(sizeof(float)*num) ;
   zma = (float *)malloc(sizeof(float)*num) ;

   for( ii=0 ; ii < num ; ii++ ){
     mmm9(ii) ; zme[ii] = med ; zma[ii] = mad ;
   }
   mad = qmed_float(num,zma) ; free(zma) ;
   if( mad <= 0.0f ){ free(zme) ; return ; }  /* should not happen */
   mad *= MTHR ;  /* threshold value */

   for( ii=0 ; ii < num ; ii++ )
     if( fabsf(vec[ii]-zme[ii]) > mad ) vec[ii] = zme[ii] ;

   free(zme) ; return ;
}
Пример #8
0
int DES_despike9( int num , float *vec , float *wks )
{
   int ii , nsp ; float *zma,*zme , med,mad,val ;

   if( num < 9 || vec == NULL ) return 0 ;

   zme = wks ; zma = zme + num ;

   for( ii=0 ; ii < num ; ii++ ){
     mead9(ii) ; zme[ii] = med ; zma[ii] = mad ;
   }
   mad = qmed_float(num,zma) ;
   if( mad <= 0.0f ){ if( wks == NULL ) free(zme); return 0; }  /* should not happen */
   mad *= 6.789f ;  /* threshold value */

   for( nsp=ii=0 ; ii < num ; ii++ )
     if( fabsf(vec[ii]-zme[ii]) > mad ){ vec[ii] = zme[ii]; nsp++; }

   return nsp ;
}
Пример #9
0
int THD_despike9( int num , float *vec )
{
   int ii , nsp ; float *zma,*zme , med,mad,val ;

   if( num < 9 || vec == NULL ) return 0 ;
   zme = (float *)malloc(sizeof(float)*num) ;
   zma = (float *)malloc(sizeof(float)*num) ;

   for( ii=0 ; ii < num ; ii++ ){
     mead9(ii) ; zme[ii] = med ; zma[ii] = mad ;
   }
   mad = qmed_float(num,zma) ; free(zma) ;
   if( mad <= 0.0f ){ free(zme); return 0; }  /* should not happen */
   mad *= 6.789f ;  /* threshold value */

   for( nsp=ii=0 ; ii < num ; ii++ )
     if( fabsf(vec[ii]-zme[ii]) > mad ){ vec[ii] = zme[ii]; nsp++; }

   free(zme) ; return nsp ;
}
Пример #10
0
void DES_despike9( int num , float *vec )
{
   int ii , nsp ; float *zma,*zme , med,mad,val ;

   if( num < 9 || vec == NULL ) return ;

   if( deswks == NULL ) deswks = (float *)malloc(sizeof(float *)*(4*num)) ;

   zme = deswks ; zma = zme + num ;

   for( ii=0 ; ii < num ; ii++ ){
     mead9(ii) ; zme[ii] = med ; zma[ii] = mad ;
   }
   mad = qmed_float(num,zma) ;
   if( mad <= 0.0f ) return ;
   mad *= 6.789f ;  /* threshold value */

   for( nsp=ii=0 ; ii < num ; ii++ )
     if( fabsf(vec[ii]-zme[ii]) > mad ){ vec[ii] = zme[ii]; nsp++; }

   return ;
}
Пример #11
0
MRI_IMAGE * mri_median21( MRI_IMAGE *innim )
{
   float *innar , *outar , qar[21] ;
   MRI_IMAGE *outim ;
   int ii,ip,iq,im,in , jj,jp,jq,jm,jn , kk , nx,ny ;

   if( innim == NULL || innim->kind != MRI_float ) return NULL ;

   innar = MRI_FLOAT_PTR(innim) ; nx = innim->nx ; ny = innim->ny ;
   outim = mri_new_conforming( innim , MRI_float ) ;
   outar = MRI_FLOAT_PTR(outim) ;

   for( jj=0 ; jj < ny ; jj++ ){
     jm = jj-1 ; if( jm <  0  ) jm++ ;
     jn = jm-1 ; if( jn <  0  ) jn++ ;
     jp = jj+1 ; if( jp >= ny ) jp-- ;
     jq = jp+1 ; if( jq >= ny ) jq-- ;
     for( ii=0 ; ii < nx ; ii++ ){
       im = ii-1 ; if( im <  0  ) im++ ;
       in = im-1 ; if( in <  0  ) in++ ;
       ip = ii+1 ; if( ip >= nx ) ip-- ;
       iq = ip+1 ; if( iq >= nx ) iq-- ;

       kk = 0 ;
       qar[kk++] = IAR(im,jn); qar[kk++] = IAR(ii,jn); qar[kk++] = IAR(ip,jn);
       qar[kk++] = IAR(in,jm); qar[kk++] = IAR(im,jm); qar[kk++] = IAR(ii,jm); qar[kk++] = IAR(ip,jm); qar[kk++] = IAR(iq,jm);
       qar[kk++] = IAR(in,jj); qar[kk++] = IAR(im,jj); qar[kk++] = IAR(ii,jj); qar[kk++] = IAR(ip,jj); qar[kk++] = IAR(iq,jj);
       qar[kk++] = IAR(in,jp); qar[kk++] = IAR(im,jp); qar[kk++] = IAR(ii,jp); qar[kk++] = IAR(ip,jp); qar[kk++] = IAR(iq,jp);
       qar[kk++] = IAR(im,jq); qar[kk++] = IAR(ii,jq); qar[kk++] = IAR(ip,jq);

       OAR(ii,jj) = qmed_float(21,qar) ;
     }
   }

   return outim ;
}
Пример #12
0
void median9_box_func( int nx , int ny , double dx, double dy, float *ar )
{
   int ii , jj , nxy , joff ;
   float aa[9] ;
   float *ajj , *ajm , *ajp ;

   if( nx < 3 || ny < 3 ) return ;

   /** make space and copy input into it **/

   nxy = nx * ny ;
   MAKE_ATEMP(nxy) ; if( atemp == NULL ) return ;
   memcpy(atemp,ar,sizeof(float)*nxy) ;

   /** process copy of input back into the input array **/

   for( jj=0 ; jj < ny ; jj++ ){

      joff = jj * nx ;      /* offset into this row */
      ajj  = atemp + joff ; /* pointer to this row */

      ajm  = (jj==0   ) ? ajj : ajj-nx ;  /* pointer to last row */
      ajp  = (jj==ny-1) ? ajj : ajj+nx ;  /* pointer to next row */

      /* do interior points of this row */

      for( ii=1 ; ii < nx-1 ; ii++ ){
         aa[0] = ajm[ii-1] ; aa[1] = ajm[ii] ; aa[2] = ajm[ii+1] ;
         aa[3] = ajj[ii-1] ; aa[4] = ajj[ii] ; aa[5] = ajj[ii+1] ;
         aa[6] = ajp[ii-1] ; aa[7] = ajp[ii] ; aa[8] = ajp[ii+1] ;
#if 0
         isort_float( 9 , aa ) ; ar[ii+joff] = aa[4] ;
#else
         ar[ii+joff] = qmed_float(9,aa) ;  /* 25 Oct 2000 */
#endif
      }

      /* do leading edge point (ii=0) */

      aa[0] = ajm[0] ; aa[1] = ajm[0] ; aa[2] = ajm[1] ;
      aa[3] = ajj[0] ; aa[4] = ajj[0] ; aa[5] = ajj[1] ;
      aa[6] = ajp[0] ; aa[7] = ajp[0] ; aa[8] = ajp[1] ;
#if 0
      isort_float( 9 , aa ) ; ar[joff] = aa[4] ;
#else
      ar[joff] = qmed_float(9,aa) ;  /* 25 Oct 2000 */
#endif

      /* do trailing edge point (ii=nx-1) */

      aa[0] = ajm[nx-2] ; aa[1] = ajm[nx-1] ; aa[2] = ajm[nx-1] ;
      aa[3] = ajj[nx-2] ; aa[4] = ajj[nx-1] ; aa[5] = ajj[nx-1] ;
      aa[6] = ajp[nx-2] ; aa[7] = ajp[nx-1] ; aa[8] = ajp[nx-1] ;
#if 0
      isort_float( 9 , aa ) ; ar[nx-1+joff] = aa[4] ;
#else
      ar[nx-1+joff] = qmed_float(9,aa) ;  /* 25 Oct 2000 */
#endif
   }
   return ;
}
Пример #13
0
MRI_IMAGE *mri_medianfilter( MRI_IMAGE *imin, float irad, byte *mask, int verb )
{
   MRI_IMAGE *imout ;
   float *fin=NULL , *fout , *tmp ;
   short *sin=NULL ; byte *bin=NULL ; void *vin ;
   short *di , *dj , *dk ;
   int nd, ii,jj,kk, ip,jp,kp, nx,ny,nz, nxy, ijk, dd,nt=0,pjk, kd=0  ;
   MCW_cluster *cl ;
   float dz ;

ENTRY("mri_medianfilter") ;

   if( imin == NULL || irad <= 0.0f ) RETURN(NULL) ;

   /** deal with vector-valued images [15 Dec 2008] -- see mrilib.h **/

#undef  CALLME
#define CALLME(inn,out) (out) = mri_medianfilter( (inn), irad,mask,verb )
    if( ISVECTIM(imin) ){ VECTORME(imin,imout) ; RETURN(imout) ; }

   /** if not a good input data type, floatize and try again **/

   if( imin->kind != MRI_float &&
       imin->kind != MRI_short &&
       imin->kind != MRI_byte    ){

     MRI_IMAGE *qim ;
     qim = mri_to_float( imin ) ;
     imout = mri_medianfilter( qim , irad , mask , verb ) ;
     mri_free( qim ) ;
     RETURN(imout) ;
   }

   /** build cluster of points for median-izing **/

   if( !use_dxyz ){
     if( irad < 1.01f ) irad = 1.01f ;
     dz = (imin->nz == 1) ? 6666.0f : 1.0f ;
     cl = MCW_build_mask( 1.0f,1.0f,dz , irad ) ;
   } else {
     float dm ;
     dz = (imin->nz == 1) ? 6666.0f : imin->dz ;
     dm = MIN(imin->dx,imin->dy) ; dm = MIN(dm,dz) ;
     dm *= 1.01f ; if( irad < dm ) irad = dm ;
     cl = MCW_build_mask( imin->dx,imin->dy,dz , irad ) ;
   }

   if( cl == NULL || cl->num_pt < 6 ){ KILL_CLUSTER(cl); RETURN(NULL); }

   ADDTO_CLUSTER(cl,0,0,0,0) ;

   di = cl->i    ; dj = cl->j    ; dk = cl->k    ; nd  = cl->num_pt ;
   nx = imin->nx ; ny = imin->ny ; nz = imin->nz ; nxy = nx*ny ;

   if( verb ){
     ININFO_message(" Median filter mask has %d voxels",nd) ;
     if( mask != NULL )
       ININFO_message(" Data mask has %d voxels",THD_countmask(nxy*nz,mask)) ;
   }

   imout = mri_new_conforming( imin , MRI_float ) ;
   fout  = MRI_FLOAT_PTR( imout ) ;
   vin   = mri_data_pointer( imin ) ;
   tmp   = (float *) malloc(sizeof(float)*nd) ;
   switch( imin->kind ){
     default:                              break ;
     case MRI_float:  fin = (float *)vin ; break ;
     case MRI_short:  sin = (short *)vin ; break ;
     case MRI_byte :  bin = (byte  *)vin ; break ;
   }

   if( verb ){
     kd = (int)rint(0.03*nz); if( kd < 1 ) kd = 1;
     fprintf(stderr," + Median filter loop") ;
   }

   for( kk=0 ; kk < nz ; kk++ ){
    if( verb && kk%kd == 0 ) fprintf(stderr,".") ;
    for( jj=0 ; jj < ny ; jj++ ){
      for( ii=0 ; ii < nx ; ii++ ){
        ijk = ii + jj*nx + kk*nxy ;
        if( SKIPVOX(ijk) ) continue ;

        /* extract neighborhood values */

        switch( imin->kind ){
          default: break ;
          case MRI_float:
            for( nt=dd=0 ; dd < nd ; dd++ ){
              ip = ii+di[dd] ; if( ip < 0 || ip >= nx ) continue ;
              jp = jj+dj[dd] ; if( jp < 0 || jp >= ny ) continue ;
              kp = kk+dk[dd] ; if( kp < 0 || kp >= nz ) continue ;
              pjk = ip+jp*nx+kp*nxy ;
              if( SKIPVOX(pjk) ) continue ;
              tmp[nt++] = fin[pjk] ;
            }
          break ;
          case MRI_short:
            for( nt=dd=0 ; dd < nd ; dd++ ){
              ip = ii+di[dd] ; if( ip < 0 || ip >= nx ) continue ;
              jp = jj+dj[dd] ; if( jp < 0 || jp >= ny ) continue ;
              kp = kk+dk[dd] ; if( kp < 0 || kp >= nz ) continue ;
              pjk = ip+jp*nx+kp*nxy ;
              if( SKIPVOX(pjk) ) continue ;
              tmp[nt++] = sin[pjk] ;
            }
          break ;
          case MRI_byte:
            for( nt=dd=0 ; dd < nd ; dd++ ){
              ip = ii+di[dd] ; if( ip < 0 || ip >= nx ) continue ;
              jp = jj+dj[dd] ; if( jp < 0 || jp >= ny ) continue ;
              kp = kk+dk[dd] ; if( kp < 0 || kp >= nz ) continue ;
              pjk = ip+jp*nx+kp*nxy ;
              if( SKIPVOX(pjk) ) continue ;
              tmp[nt++] = bin[pjk] ;
            }
          break ;
        }

        fout[ijk] = qmed_float( nt , tmp ) ;  /* the actual median-izing */
   }}}
   if( verb ) fprintf(stderr,"\n") ;

   KILL_CLUSTER(cl); free((void *)tmp);  /* toss the trash */
   RETURN(imout) ;
}
Пример #14
0
MRI_IMARR * THD_time_fit_dataset( THD_3dim_dataset *dset ,
                                  int nref , float **ref , int meth , byte *mask )
{
   int ii , nvox,nval , qq,tt ;
   float *far , *fit , *var , val ;
   MRI_IMARR *imar ; MRI_IMAGE *qim ; float **fitar ;

ENTRY("THD_time_fit_dataset") ;

   if( !ISVALID_DSET(dset) ||
       nref < 1 || nref >= DSET_NVALS(dset) || ref == NULL ) RETURN(NULL) ;
   DSET_load(dset) ; if( !DSET_LOADED(dset) ) RETURN(NULL) ;

   /* construct output images */

   INIT_IMARR(imar) ;
   fitar = (float **)malloc(sizeof(float *)*nref) ;
   for( qq=0 ; qq < nref ; qq++ ){
     qim = mri_new_conforming( DSET_BRICK(dset,0) , MRI_float ) ;
     fitar[qq] = MRI_FLOAT_PTR(qim) ;
     ADDTO_IMARR(imar,qim) ;
   }
   qim = mri_new_conforming( DSET_BRICK(dset,0) , MRI_float ) ;
   var = MRI_FLOAT_PTR(qim) ; ADDTO_IMARR(imar,qim) ;

   nvox = DSET_NVOX(dset) ; nval = DSET_NVALS(dset) ;
   far  = (float *)malloc(sizeof(float)*nval) ;
   fit  = (float *)malloc(sizeof(float)*nref) ;
   for( ii=0 ; ii < nvox ; ii++ ){
     if( !INMASK(ii) ) continue ;
     qq = THD_extract_array( ii , dset , 0 , far ) ;  /* get data */
     if( qq == 0 ){
       switch(meth){                                  /* get fit */
         default:
         case 2: THD_generic_detrend_LSQ( nval, far, -1, nref,ref, fit ); break;
         case 1: THD_generic_detrend_L1 ( nval, far, -1, nref,ref, fit ); break;
       }
       for( qq=0 ; qq < nref ; qq++ ) fitar[qq][ii] = fit[qq] ; /* save fit */

       /* at this point, far[] contains the residuals */

       switch(meth){                    /* get stdev or MAD */
         default:
         case 2:{
           float mm,vv ;
           for( mm=0.0,tt=0 ; tt < nval ; tt++ ) mm += far[tt] ;
           mm /= nval ;
           for( vv=0.0,tt=0 ; tt < nval ; tt++ ) vv += (far[tt]-mm)*(far[tt]-mm) ;
           var[ii] = sqrtf( vv/(nval-1.0) ) ;
         }
         break ;

         case 1:{
           for( tt=0 ; tt < nval ; tt++ ) far[tt] = fabsf(far[tt]) ;
           var[ii] = qmed_float( nval , far ) ;
         }
         break ;
       }
     }
   }

   free(fit); free(far); free(fitar); RETURN(imar);
}
Пример #15
0
static void STATS_tsfunc( double tzero, double tdelta ,
                          int npts, float *ts ,
                          double ts_mean, double ts_slope,
                          void *ud, int nbriks, float *val          )
{
   static int ncall ;
   int meth_index, ii , out_index, nzpts, onset, offset, duration;
   float *ts_det, *ts_dif=NULL ;

   /** is this a "notification"? **/

   if( val == NULL ){

      if( npts > 0 ){  /* the "start notification" */

         ncall = 0 ;                          /* number of calls */

      } else {  /* the "end notification" */

         /* nothing to do here */

      }
      return ;
   }

   /* RWC: first difference here [25 May 2011] */

   if( do_tdiff ){
     float tsm , tss ;
     ts_dif = (float*)calloc(npts, sizeof(float)) ;
	  for( ii=1 ; ii < npts ; ii++ ) ts_dif[ii-1] = ts[ii]-ts[ii-1] ;
     get_linear_trend( npts-1 , ts_dif , &tsm , &tss ) ;
     ts_mean = (double)tsm ; ts_slope = (double)tss ;
     npts-- ; ts = ts_dif ;
   }

   /* KRH make copy and detrend it right here.
      Use ts_mean and ts_slope for detrend-ization. */

   ts_det = (float*)calloc(npts, sizeof(float));
   memcpy( ts_det, ts, npts * sizeof(float));

   for( ii = 0; ii < npts; ii++)
     ts_det[ii] -=
       (ts_mean - (ts_slope * (npts - 1) * tdelta/2) + ts_slope * tdelta * ii) ;

   /** OK, actually do some work **/

   /* This main loop now uses meth_index AND out_index as loop variables,     */
   /* mainly to avoid rewriting code that worked.                             */

   /* meth_index is an index into the static method array, which contains the */
   /* list of methods to be executed (and will also contain an integer        */
   /* parameter specifying the number of return values if -autocorr n and/or  */
   /* -autoreg p have been requested).                                        */
   /* out_index is an index into the output array.                            */

   for(meth_index=out_index=0 ; meth_index < nmeths; meth_index++,out_index++){
    switch( meth[meth_index] ){

      default:
      case METH_MEAN:  val[out_index] = ts_mean  ; break ;

      case METH_SUM:   val[out_index] = ts_mean * npts; break; /* 24 Apr 2006 */

      case METH_ABSSUM:{              /* 18 Jun 2006 */
        register int ii ;
        register float sum ;
        sum = 0.0;
        for(ii=0; ii< npts; ii++) sum += fabs(ts[ii]);
        val[out_index] = sum;
      }
      break;

      case METH_L2_NORM:                /* 07 Jan 2013 [rickr] */
      case METH_SUM_SQUARES:{           /* 18 Dec 2008 */
        register int ii ;
        register float sum ;
        sum = 0.0;
        for(ii=0; ii< npts; ii++) sum += ts[ii]*ts[ii];

        /* check multiple methods here */
        if ( meth[meth_index] == METH_SUM_SQUARES )
           val[out_index] = sum;
        else if ( meth[meth_index] == METH_L2_NORM ) {
           /* theory and practice do not always seem to agree, so... */
           if( sum >= 0.0 ) val[out_index] = sqrt(sum);
           else             val[out_index] = 0.0;
        }
      }
      break;

      case METH_SLOPE: val[out_index] = ts_slope ; break ;

      case METH_CVAR_NOD:     /* methods that depend on the mean and stdev */
      case METH_SIGMA_NOD:
      case METH_CVARINVNOD:
      case METH_CVAR:
      case METH_CVARINV:
      case METH_SIGMA:{
        register int ii ;
        register double sum ;

        int mm = meth[meth_index] ;
        int nod = (mm == METH_CVAR_NOD)  ||   /* no detrend flag */
                  (mm == METH_SIGMA_NOD) ||
                  (mm == METH_CVARINVNOD)  ;

        sum = 0.0 ;
        if( !nod ){   /* not no detrend ==> use detrended data */
          for( ii=0 ; ii < npts ; ii++ ) sum += ts_det[ii] * ts_det[ii] ;
        } else {      /* use data as God gave it to us */
          for( ii=0 ; ii < npts ; ii++ ) sum += (ts[ii]-ts_mean)
                                               *(ts[ii]-ts_mean) ;
        }

        sum = sqrt( sum/(npts-1.0) ) ;  /* stdev */

        if( mm == METH_SIGMA ||  mm == METH_SIGMA_NOD )
          val[out_index] = sum ;
        else if( mm == METH_CVAR || mm == METH_CVAR_NOD )
          val[out_index] = (ts_mean != 0.0) ? sum/fabs(ts_mean) : 0.0 ;
        else
          val[out_index] = (sum     != 0.0) ? fabs(ts_mean)/sum : 0.0 ;
      }
      break ;

      /* 14 Feb 2000: these 2 new methods disturb the array ts[]       */
      /* 18 Dec 2002: these 2 methods no longer disturb the array ts[] */

      case METH_MEDIAN:{
        float* ts_copy;
        ts_copy = (float*)calloc(npts, sizeof(float));
        memcpy( ts_copy, ts, npts * sizeof(float));
        val[out_index] = qmed_float( npts , ts_copy ) ;
        free(ts_copy);
      }
      break ;

      case METH_NZMEDIAN:{      /* 27 Jun 2012 [rickr] */
        float* ts_copy;
        int    lind, lnzcount;
        ts_copy = (float*)calloc(npts, sizeof(float));
        /* replace memcpy with non-zero copy */
        lnzcount=0;
        for (lind=0; lind < npts; lind++)
           if( ts[lind] ) ts_copy[lnzcount++] = ts[lind];
        /* and get the result from the possibly shortened array */
        if( lnzcount > 0 ) val[out_index] = qmed_float( lnzcount , ts_copy ) ;
        else               val[out_index] = 0.0 ;
        free(ts_copy);
      }
      break ;

      case METH_CENTROMEAN:{  /* 01 Nov 2010 */
        float* ts_copy;
        ts_copy = (float*)calloc(npts, sizeof(float));
        memcpy( ts_copy, ts, npts * sizeof(float));
        val[out_index] = centromean_float( npts , ts_copy ) ;
        free(ts_copy);
      }
      break ;

      case METH_MAD:{
         float* ts_copy;
         register int ii ;
         register float vm ;
         ts_copy = (float*)calloc(npts, sizeof(float));
         memcpy( ts_copy, ts, npts * sizeof(float));
         vm = qmed_float( npts , ts_copy ) ;
         for( ii=0 ; ii < npts ; ii++ ) ts_copy[ii] = fabs(ts_copy[ii]-vm) ;
         val[out_index] = qmed_float( npts , ts_copy ) ;
         free(ts_copy);
      }
      break ;

      case METH_BMV:{  /* 16 Oct 2009 */
        float bmv ;
        qmedmadbmv_float( npts , ts , NULL,NULL , &bmv ) ;
        val[out_index] = bmv ;
      }
      break ;

      case METH_ARGMIN:
      case METH_ARGMIN1:
      case METH_MIN:{
         register int ii,outdex=0 ;
         register float vm=ts[0] ;
         for( ii=1 ; ii < npts ; ii++ ) if( ts[ii] < vm ) {
           vm = ts[ii] ;
           outdex = ii ;
         }
         if (meth[meth_index] == METH_MIN) {
           val[out_index] = vm ;
         } else if (meth[meth_index] == METH_ARGMIN) {
            val[out_index] = outdex ;
         } else {
            val[out_index] = outdex +1;
         }
      }
      break ;

      case METH_ZCOUNT:{  /* 05 Apr 2012 */
        int ii , zc ;
        for( ii=zc=0 ; ii < npts ; ii++ ) if( ts[ii] == 0.0f ) zc++ ;
        val[out_index] = zc ;
      }
      break ;

      case METH_NZCOUNT:{  /* Turkey 2014 */
        int ii , zc ;
        for( ii=zc=0 ; ii < npts ; ii++ ) if( ts[ii] == 0.0f ) zc++ ;
        val[out_index] = npts-zc ;
      }
      break ;

      case METH_DW:{
         register int ii ;
         register float den=ts[0]*ts[0] ;
         register float num=0 ;
         for( ii=1 ; ii < npts ; ii++ ) {
           num = num + (ts_det[ii] - ts_det[ii-1])
                      *(ts_det[ii] - ts_det[ii-1]);
           den = den + ts_det[ii] * ts_det[ii];
         }
         if (den == 0) {
           val[out_index] = 0 ;
         } else {
           val[out_index] = num/den ;
         }
      }
      break ;

      case METH_ONSET:
      case METH_OFFSET:
      case METH_DURATION:
      case METH_ABSMAX:
      case METH_SIGNED_ABSMAX:
      case METH_ARGMAX:
      case METH_ARGMAX1:
      case METH_ARGABSMAX:
      case METH_ARGABSMAX1:
      case METH_MAX:
      case METH_CENTDURATION:
      case METH_CENTROID:{
         register int ii, outdex=0 ;
         register float vm=ts[0];
         if ( (meth[meth_index] == METH_ABSMAX) ||
               (meth[meth_index] == METH_ARGABSMAX) ||
               (meth[meth_index] == METH_ARGABSMAX1)  ) {
           vm = fabs(vm) ;
           for( ii=1 ; ii < npts ; ii++ ) {
             if( fabs(ts[ii]) > vm ) {
               vm = fabs(ts[ii]) ;
               outdex = ii ;
             }
           }
         } else if ( meth[meth_index] == METH_SIGNED_ABSMAX ) {
           /* for P Hamilton    31 Aug 2012 [rickr] */
           register float avm=fabs(vm);
           for( ii=1 ; ii < npts ; ii++ ) {
             if( fabs(ts[ii]) > avm ) {
               vm = ts[ii] ;
               avm = fabs(vm) ;
               outdex = ii ;
             }
           }
         } else {
           for( ii=1 ; ii < npts ; ii++ ) {
             if( ts[ii] > vm ) {
               vm = ts[ii] ;
               outdex = ii ;
             }
           }
         }
       switch( meth[meth_index] ){
            default:
            case METH_ABSMAX:
            case METH_SIGNED_ABSMAX:
            case METH_MAX:
               val[out_index] = vm ;
            break;

            case METH_ONSET:
            case METH_OFFSET:
            case METH_DURATION:
               duration = Calc_duration(ts, npts, vm, outdex,
                                    &onset,&offset);
               switch(meth[meth_index]) {
                  case METH_ONSET: val[out_index] = onset; break;
                  case METH_OFFSET: val[out_index] = offset; break;
                  case METH_DURATION: val[out_index] = duration; break;
               }

            break;

            case METH_ARGMAX:
            case METH_ARGABSMAX:
              val[out_index] = outdex ;
            break;

            case METH_ARGMAX1:
            case METH_ARGABSMAX1:
              val[out_index] = outdex +1;
            break;

            case METH_CENTROID:
            case METH_CENTDURATION: {
              float cm;
              cm = Calc_centroid(ts, npts);
              if(meth[meth_index]== METH_CENTDURATION)
                 val[out_index] = Calc_duration(ts, npts, vm, (int) cm,
                                &onset,&offset);
              else
                 val[out_index] = cm;
            }
            break;
         }
      }
      break ;

      case METH_NZMEAN: {
        register int ii ;
        register float sum ;
           sum = 0.0;
           nzpts = 0;
           for( ii=0 ; ii < npts ; ii++ ) {
             if( ts[ii] != 0.0 ) {
               sum += ts[ii] ;
               nzpts++;
             }
           }
           if(npts>0)
              val[out_index] = sum / nzpts;
           else
              val[out_index] = 0.0;
      }
      break;

      case METH_AUTOCORR:{
        int numVals;
        float *ts_corr;
        /* for these new methods, the extra, needed integer */
        /* parameter is stored in the static array "meth",  */
        /* in the element right after the indicator for     */
        /* this method.  This parameter indicates the number*/
        /* of values to return, or 0 for the same length as */
        /* the input array.                                 */
        numVals = meth[meth_index + 1];
        if (numVals == 0) numVals = npts - 1;
        ts_corr = (float*)calloc(numVals,sizeof(float));
        /* Call the autocorrelation function, in this file. */
        autocorr(npts,ts,numVals,ts_corr);
        /* Copy the values into the output array val, which */
        /* will be returned to the fbuc MAKER caller to     */
        /* populate the appropriate BRIKs with the data.    */
        for( ii = 0; ii < numVals; ii++) {
          val[out_index + ii] = ts_corr[ii];
        }
        /* Although meth_index will be incremented by the   */
        /* for loop, it needs to be incremented an extra    */
        /* time to account for the extra parameter we       */
        /* pulled from the meth array.                      */
        meth_index++;
        /* Similarly, though the out_index will be incremented */
        /* by the for loop, we have added potentially several  */
        /* values to the output array, and we need to account  */
        /* for that here.                                      */
        out_index+=(numVals - 1);
        free(ts_corr);
      }
      break ;

      case METH_AUTOREGP:{
        int numVals,kk,mm;
        float *ts_corr, *y, *z;
        float alpha, beta, tmp;

        /* For these new methods, the extra, needed integer */
        /* parameter is stored in the static array "meth",  */
        /* in the element right after the indicator for     */
        /* this method.  This parameter indicates the number*/
        /* of values to return, or 0 for the same length as */
        /* the input array.                                 */
        numVals = meth[meth_index + 1];
        if (numVals == 0) numVals = npts - 1;

        /* Allocate space for the autocorrelation coefficients, */
        /* result, and a temp array for calculations.           */
        /* Correlation coeff array is larger, because we must   */
        /* disregard the r0, which is identically 1.            */
        /* Might fix this in autocorr function                  */
        ts_corr = (float*)malloc((numVals) * sizeof(float));
        y = (float*)malloc(numVals * sizeof(float));
        z = (float*)malloc(numVals * sizeof(float));

        /* Call autocorr function to generate the autocorrelation  */
        /* coefficients.                                           */
        autocorr(npts,ts,numVals,ts_corr);

        /* Durbin algorithm for solving Yule-Walker equations.        */
        /* The Yule-Walker equations specify the autoregressive       */
        /* coefficients in terms of the autocorrelation coefficients. */
        /* R*Phi = r, where r is vector of correlation coefficients,  */
        /* R is Toeplitz matrix formed from r, and Phi is a vector of */
        /* the autoregression coefficients.                           */

        /* In this implementation, 'y' is 'Phi' above and 'ts_corr' is 'r'    */

        y[0] = -ts_corr[0];
        alpha = -ts_corr[0];
        beta = 1;
        for (kk = 0 ; kk < (numVals - 1) ; kk++ ) {
          beta = (1 - alpha * alpha ) * beta ;
          tmp = 0;
          for ( mm = 0 ; mm <= kk ; mm++) {
            tmp = tmp + ts_corr[kk - mm] * y[mm];
          }
          alpha = - ( ts_corr[kk+1] + tmp ) / beta ;
          for ( mm = 0 ; mm <= kk ; mm++ ) {
            z[mm] = y[mm] + alpha * y[kk - mm];
          }
          for ( mm = 0 ; mm <= kk ; mm++ ) {
            y[mm] = z[mm];
          }
          y[kk+1] = alpha ;
        }

        /* Copy the values into the output array val, which */
        /* will be returned to the fbuc MAKER caller to     */
        /* populate the appropriate BRIKs with the data.    */
        for( ii = 0; ii < numVals; ii++) {
          val[out_index + ii] = y[ii];
          if (!finite(y[ii])){
            WARNING_message("BAD FLOAT y[%d]=%f; Call#%d\n",ii,y[ii],ncall);
            val[out_index + ii] = 0.0f ;
          }
        }
        /* Although meth_index will be incremented by the   */
        /* for loop, it needs to be incremented an extra    */
        /* time to account for the extra parameter we       */
        /* pulled from the meth array.                      */
        meth_index++;
        /* Similarly, though the out_index will be incremented */
        /* by the for loop, we have added potentially several  */
        /* values to the output array, and we need to account  */
        /* for that here.                                      */
        out_index+=(numVals - 1);
        free(ts_corr);
        free(y);
        free(z);
      }
      break ;

      case METH_ACCUMULATE:{
        register double sum = 0.0 ;
        register int    ii ;

        meth_index++;   /* go past dummy zero */

        for( ii = 0; ii < npts; ii++) {
          sum += ts[ii];  /* keep track as double */
          val[out_index + ii] = sum;
        }

        out_index+=(npts - 1);
      }
      break ;

    }
   }

   free(ts_det); if( ts_dif == ts ) free(ts_dif) ;
   ncall++ ; return ;
}
Пример #16
0
int main( int argc , char *argv[] )
{
   THD_3dim_dataset *dset , *oset=NULL , *tset=NULL ;
   int nvals , iv , nxyz , ii,jj,kk , iarg , kz,kzold ;
   float cut1=2.5,cut2=4.0 , sq2p,sfac , fq ;
   MRI_IMAGE *flim ;
   char *prefix="despike" , *tprefix=NULL ;

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

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

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

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

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

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

   /** AFNI package setup and logging **/

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

   /** parse options **/

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

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

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

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

      /** -localedit **/

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

      /** don't use masking **/

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

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

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

      /** output dataset prefix **/

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

      /** ratio dataset prefix **/

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

      /** trigonometric polynomial order **/

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

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

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

      /** thresholds for s ratio **/

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

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

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

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

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

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

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

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

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

   /*-- create automask --*/

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

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

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

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

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

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

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

   /* copy the ignored bricks */

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

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

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

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

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

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

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

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

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

   /* make ref functions */

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

   /* r(t) = 1 */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        /* find spikiness for each point in time */

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

        /* save spikiness in -ssave datset */

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

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

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

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

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

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

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

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

 } /* end OpenMP */
 AFNI_OMP_END ;

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

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

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

   if( do_NEW ) mri_free(NEW_psinv) ;

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

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

   /* write results */

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

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

   exit( THD_get_write_error_count() ) ;
}