00001 #include "mrilib.h"
00002 
00003 #define USE_DILATE
00004 #define USE_FILLIN
00005 
00006 #undef DEBUG
00007 
00008 static int verb = 0 ;                            
00009 void THD_automask_verbose( int v ){ verb = v ; }
00010 
00011 static int exterior_clip = 0 ;
00012 void THD_automask_extclip( int e ){ exterior_clip = e ; }
00013 
00014 static int dall = 0 ;
00015 
00016 
00017 
00018 static int mask_count( int nvox , byte *mmm )
00019 {
00020    int ii , nn ;
00021    for( nn=ii=0 ; ii < nvox ; ii++ ) nn += (mmm[ii] != 0) ;
00022    return nn ;
00023 }
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 byte * THD_automask( THD_3dim_dataset *dset )
00032 {
00033    MRI_IMAGE *medim ;
00034    byte *mmm ;
00035 
00036 ENTRY("THD_automask") ;
00037 
00038    
00039 
00040    medim = THD_median_brick(dset) ; if( medim == NULL ) RETURN(NULL);
00041 
00042    mmm = mri_automask_image( medim ) ;
00043 
00044    mri_free(medim) ; RETURN(mmm) ;
00045 }
00046 
00047 
00048 
00049 
00050 
00051 
00052 byte * mri_automask_imarr( MRI_IMARR *imar )  
00053 {
00054    MRI_IMAGE *avim , *tim , *qim ;
00055    byte *mmm ;
00056    int ii , jj , nvox,nim ;
00057    float fac , *avar , *qar ;
00058 
00059 ENTRY("mri_automask_imarr") ;
00060 
00061    if( imar == NULL || IMARR_COUNT(imar) < 1 ) RETURN(NULL) ;
00062 
00063    nim = IMARR_COUNT(imar) ;
00064    if( nim == 1 ){
00065      mmm = mri_automask_image( IMARR_SUBIMAGE(imar,0) ) ;
00066      RETURN(mmm) ;
00067    }
00068 
00069    avim = mri_new_conforming( IMARR_SUBIMAGE(imar,0) , MRI_float ) ;
00070    avar = MRI_FLOAT_PTR(avim) ;
00071    nvox = avim->nvox ;
00072    for( jj=0 ; jj < nim ; jj++ ){
00073      tim = IMARR_SUBIMAGE(imar,jj) ;
00074      if( tim->kind != MRI_float ) qim = mri_to_float(tim) ;
00075      else                         qim = tim ;
00076      qar = MRI_FLOAT_PTR(qim) ;
00077      for( ii=0 ; ii < nvox ; ii++ ) avar[ii] += qar[ii] ;
00078      if( qim != tim ) mri_free(qim) ;
00079    }
00080    fac = 1.0f / (float)nim ;
00081    for( ii=0 ; ii < nvox ; ii++ ) avar[ii] *= fac ;
00082    mmm = mri_automask_image( avim ) ;
00083    mri_free(avim) ;
00084    RETURN(mmm) ;
00085 }
00086 
00087 
00088 
00089 
00090 
00091 
00092 byte * mri_automask_image( MRI_IMAGE *im )
00093 {
00094    float clip_val , *mar ;
00095    byte *mmm = NULL ;
00096    int nvox , ii,jj , nmm , nx,ny,nz ;
00097    MRI_IMAGE *medim ;
00098 
00099 ENTRY("mri_automask_image") ;
00100 
00101    if( im == NULL ) return NULL ;
00102 
00103    if( im->kind != MRI_float ) medim = mri_to_float(im) ;
00104    else                        medim = im ;
00105 
00106    
00107 
00108    clip_val = THD_cliplevel(medim,0.5) ;
00109 
00110    if( verb ) ININFO_message("Clip level = %f\n",clip_val) ;
00111 
00112    
00113 
00114    nvox = medim->nvox ;
00115    mar  = MRI_FLOAT_PTR(medim) ;
00116    mmm  = (byte *) calloc( sizeof(byte), nvox ) ;
00117    for( nmm=ii=0 ; ii < nvox ; ii++ )
00118      if( mar[ii] >= clip_val ){ mmm[ii] = 1; nmm++; }
00119 
00120    if( AFNI_yesenv("TOPCLIP") ){
00121      float tclip = 3.1*clip_val ;
00122      if( verb ) ININFO_message("Top clip = %f\n",tclip) ;
00123      for( ii=0 ; ii < nvox ; ii++ )
00124        if( mar[ii] > tclip ) mmm[ii] = 0 ;
00125      for( nmm=ii=0 ; ii < nvox ; ii++ ) if( mmm[ii] ) nmm++ ;
00126    }
00127 
00128    if( verb ) ININFO_message("Number voxels above clip level = %d\n",nmm) ;
00129    if( im != medim && (!exterior_clip || nmm==0) ){ mri_free(medim); medim=NULL; }
00130    if( nmm == 0 ) RETURN(mmm) ;  
00131 
00132    
00133 
00134    nx = im->nx ; ny = im->ny ; nz = im->nz ;
00135    dall = (nx*ny*nz)/128 ;  
00136 
00137    if( verb ) ININFO_message("Clustering voxels above clip level ...\n") ;
00138    THD_mask_clust( nx,ny,nz, mmm ) ;
00139 
00140    
00141 
00142 
00143    THD_mask_erode( nx,ny,nz, mmm ) ;
00144 
00145    
00146 
00147    THD_mask_clust( nx,ny,nz, mmm ) ;
00148 
00149 #ifdef USE_FILLIN
00150    
00151 
00152    jj = ii = THD_mask_fillin_once( nx,ny,nz , mmm , 1 ) ;
00153    if( ii > 0 ){
00154      jj += ii = THD_mask_fillin_once( nx,ny,nz , mmm , 1 ) ;
00155      if( ii > 0 ){
00156        jj += ii = THD_mask_fillin_once( nx,ny,nz , mmm , 1 ) ;
00157      }
00158    }
00159    if( jj > 0 && verb )
00160     ININFO_message("Filled   %d voxels in small holes; now have %d voxels\n",
00161             jj , mask_count(nvox,mmm) ) ;
00162 
00163    if( AFNI_yesenv("PEEL") ){
00164      jj = THD_peel_mask( nx,ny,nz , mmm , 7 ) ;
00165      if( jj > 0 ){
00166        ININFO_message("Peeled %d voxels from surface\n",jj) ;
00167        THD_mask_erode( nx,ny,nz, mmm ) ;
00168        THD_mask_clust( nx,ny,nz, mmm ) ;
00169      }
00170    }
00171 
00172    nmm = 1 ;
00173    jj  = rint(0.016*nx) ; nmm = MAX(nmm,jj) ;
00174    jj  = rint(0.016*ny) ; nmm = MAX(nmm,jj) ;
00175    jj  = rint(0.016*nz) ; nmm = MAX(nmm,jj) ;
00176 
00177    if( nmm > 1 || jj > 0 ){
00178      for( jj=0,ii=2 ; ii < nmm ; ii++ )
00179        jj += THD_mask_fillin_once( nx,ny,nz , mmm , ii ) ;
00180      jj += THD_mask_fillin_completely( nx,ny,nz, mmm , nmm ) ;
00181      if( jj > 0 && verb )
00182       ININFO_message("Filled   %d voxels in large holes; now have %d voxels\n",
00183               jj , mask_count(nvox,mmm) ) ;
00184    }
00185 
00186    THD_mask_erode( nx,ny,nz, mmm ) ;
00187    THD_mask_clust( nx,ny,nz, mmm ) ;
00188 #endif
00189 
00190    
00191 
00192 
00193 
00194 
00195 
00196    for( ii=0 ; ii < nvox ; ii++ ) mmm[ii] = !mmm[ii] ;
00197 
00198    if( verb ) ININFO_message("Clustering non-brain voxels ...\n") ;
00199    THD_mask_clust( nx,ny,nz, mmm ) ;
00200 
00201    
00202 
00203 
00204 
00205    if( exterior_clip ){
00206      float tclip ;
00207      tclip = AFNI_yesenv("TOPCLIP") ? 3.1*clip_val : 9999.9*clip_val ;;
00208      jj = THD_mask_clip_neighbors( nx,ny,nz , mmm , clip_val,tclip,mar ) ;
00209      if( im != medim ) mri_free(medim) ;
00210      if( jj > 0 && verb )
00211        ININFO_message("Removed  %d exterior voxels below clip level\n",jj);
00212    } else {
00213      jj = 0 ;
00214    }
00215 
00216    
00217 
00218    for( ii=0 ; ii < nvox ; ii++ ) mmm[ii] = !mmm[ii] ;
00219    if( verb ) ININFO_message("Mask now has %d voxels\n",mask_count(nvox,mmm)) ;
00220 
00221    if( exterior_clip && jj > 0 ){
00222      THD_mask_erode( nx,ny,nz, mmm ) ;
00223      THD_mask_clust( nx,ny,nz, mmm ) ;
00224    }
00225 
00226    RETURN(mmm) ;
00227 }
00228 
00229 
00230 
00231 
00232 
00233 
00234 
00235 int THD_mask_clip_neighbors( int nx, int ny, int nz ,
00236                             byte *mmm, float clip_val, float tclip, float *mar )
00237 {
00238    int ii,jj,kk , ntot=0,nnew , jm,jp,j3 , km,kp,k3 , im,ip,i3 , nxy=nx*ny ;
00239 
00240    if( mmm == NULL || mar == NULL ) return 0 ;
00241 
00242    do{
00243     nnew = 0 ;
00244     for( kk=1 ; kk < nz-1 ; kk++ ){
00245      k3 = kk*nxy ;
00246      for( jj=1 ; jj < ny-1 ; jj++ ){
00247       j3 = k3 + jj*nx ;
00248       for( ii=1 ; ii < nx-1 ; ii++ ){
00249        i3 = ii+j3 ;
00250        if( mmm[i3] ||                                             
00251            (mar[i3] >= clip_val && mar[i3] <= tclip) ) continue ; 
00252 
00253        
00254 
00255 
00256        if( mmm[i3-1]   || mmm[i3+1]   ||
00257            mmm[i3-nx]  || mmm[i3+nx]  ||
00258            mmm[i3-nxy] || mmm[i3+nxy]   ){ mmm[i3] = 1; nnew++; }
00259     }}}
00260     ntot += nnew ;
00261    } while( nnew > 0 ) ;
00262 
00263    return ntot ;
00264 }
00265 
00266 
00267 
00268 
00269 
00270 
00271 
00272 
00273 
00274 
00275 
00276 
00277 int THD_mask_fillin_once( int nx, int ny, int nz, byte *mmm, int nside )
00278 {
00279    int ii,jj,kk , nsx,nsy,nsz , nxy,nxyz , iv,jv,kv,ll , nfill ;
00280    byte *nnn ;
00281    int nx2,nx3,nx4 , nxy2,nxy3,nxy4 ;
00282 
00283 ENTRY("THD_mask_fillin_once") ;
00284 
00285    if( mmm == NULL || nside <= 0 ) RETURN(0) ;
00286 
00287    nsx = (nx-1)/2 ; if( nsx > nside ) nsx = nside ;
00288    nsy = (ny-1)/2 ; if( nsy > nside ) nsy = nside ;
00289    nsz = (nz-1)/2 ; if( nsz > nside ) nsz = nside ;
00290 
00291    if( nsx == 0 && nsy == 0 && nsz == 0 ) RETURN(0) ;
00292 
00293 #ifdef DEBUG
00294    fprintf(stderr,"THD_mask_fillin_once: nsx=%d nsy=%d nsz=%d\n",nsx,nsy,nsz);
00295 #endif
00296 
00297    nxy = nx*ny ; nxyz = nxy*nz ; nfill = 0 ;
00298 
00299    nx2  = 2*nx  ; nx3  = 3*nx  ; nx4  = 4*nx  ;
00300    nxy2 = 2*nxy ; nxy3 = 3*nxy ; nxy4 = 4*nxy ;
00301 
00302    nnn = AFMALL(byte, nxyz) ;  
00303 
00304    
00305 
00306 #define FILLVOX                                     \
00307  do{ nnn[iv] = 1; nfill++; goto NextVox; } while(0)
00308 
00309    for( kk=nsz ; kk < nz-nsz ; kk++ ){
00310      kv = kk*nxy ;
00311      for( jj=nsy ; jj < ny-nsy ; jj++ ){
00312        jv = jj*nx + kv ;
00313        for( ii=nsx ; ii < nx-nsx ; ii++ ){
00314          iv = ii+jv ;
00315          if( mmm[iv] ) continue ;     
00316 
00317          
00318 
00319          switch( nsx ){
00320            case 1:
00321              if( mmm[iv+1] && mmm[iv-1] ) FILLVOX;
00322            break ;
00323 
00324            case 2:
00325              if( (mmm[iv+1]||mmm[iv+2]) &&
00326                  (mmm[iv-1]||mmm[iv-2])   ) FILLVOX;
00327            break ;
00328 
00329            case 3:
00330              if( (mmm[iv+1]||mmm[iv+2]||mmm[iv+3]) &&
00331                  (mmm[iv-1]||mmm[iv-2]||mmm[iv-3])   ) FILLVOX;
00332            break ;
00333 
00334            case 4:
00335              if( (mmm[iv+1]||mmm[iv+2]||mmm[iv+3]||mmm[iv+4]) &&
00336                  (mmm[iv-1]||mmm[iv-2]||mmm[iv-3]||mmm[iv-4])   ) FILLVOX;
00337            break ;
00338 
00339            default:
00340              for( ll=1 ; ll <= nsx ; ll++ ) if( mmm[iv+ll] ) break ;
00341              if( ll <= nsx ){
00342                for( ll=1 ; ll <= nsx ; ll++ ) if( mmm[iv-ll] ) break ;
00343                if( ll <= nsx ) FILLVOX;
00344              }
00345            break ;
00346          }
00347 
00348          
00349 
00350          switch( nsy ){
00351            case 1:
00352              if( mmm[iv+nx] && mmm[iv-nx] ) FILLVOX;
00353            break ;
00354 
00355            case 2:
00356              if( (mmm[iv+nx]||mmm[iv+nx2]) &&
00357                  (mmm[iv-nx]||mmm[iv-nx2])   ) FILLVOX;
00358            break ;
00359 
00360            case 3:
00361              if( (mmm[iv+nx]||mmm[iv+nx2]||mmm[iv+nx3]) &&
00362                  (mmm[iv-nx]||mmm[iv-nx2]||mmm[iv-nx3])   ) FILLVOX;
00363            break ;
00364 
00365            case 4:
00366              if( (mmm[iv+nx]||mmm[iv+nx2]||mmm[iv+nx3]||mmm[iv+nx4]) &&
00367                  (mmm[iv-nx]||mmm[iv-nx2]||mmm[iv-nx3]||mmm[iv-nx4])   ) FILLVOX;
00368            break ;
00369 
00370            default:
00371              for( ll=1 ; ll <= nsy ; ll++ ) if( mmm[iv+ll*nx] ) break ;
00372              if( ll <= nsy ){
00373                for( ll=1 ; ll <= nsy ; ll++ ) if( mmm[iv-ll*nx] ) break ;
00374                if( ll <= nsy ) FILLVOX;
00375              }
00376            break ;
00377          }
00378 
00379          
00380 
00381          switch( nsz ){
00382            case 1:
00383              if( mmm[iv+nxy] && mmm[iv-nxy] ) FILLVOX;
00384            break ;
00385 
00386            case 2:
00387              if( (mmm[iv+nxy]||mmm[iv+nxy2]) &&
00388                  (mmm[iv-nxy]||mmm[iv-nxy2])   ) FILLVOX;
00389            break ;
00390 
00391            case 3:
00392              if( (mmm[iv+nxy]||mmm[iv+nxy2]||mmm[iv+nxy3]) &&
00393                  (mmm[iv-nxy]||mmm[iv-nxy2]||mmm[iv-nxy3])   ) FILLVOX;
00394            break ;
00395 
00396            case 4:
00397              if( (mmm[iv+nxy]||mmm[iv+nxy2]||mmm[iv+nxy3]||mmm[iv+nxy4]) &&
00398                  (mmm[iv-nxy]||mmm[iv-nxy2]||mmm[iv-nxy3]||mmm[iv-nxy4])   ) FILLVOX;
00399            break ;
00400 
00401            default:
00402              for( ll=1 ; ll <= nsz ; ll++ ) if( mmm[iv+ll*nxy] ) break ;
00403              if( ll <= nsz ){
00404                for( ll=1 ; ll <= nsz ; ll++ ) if( mmm[iv-ll*nxy] ) break ;
00405                if( ll <= nsz ) FILLVOX;
00406              }
00407            break ;
00408          }
00409 
00410          NextVox: ; 
00411    } } }
00412 
00413    
00414 
00415    if( nfill > 0 ){
00416      for( iv=0 ; iv < nxyz ; iv++ ) if( nnn[iv] ) mmm[iv] = 1 ;
00417    }
00418 
00419 #ifdef DEBUG
00420    fprintf(stderr,"THD_mask_fillin_once: nfill=%d\n",nfill) ;
00421 #endif
00422 
00423    free(nnn) ; RETURN(nfill) ;
00424 }
00425 
00426 
00427 
00428 
00429 
00430 
00431 int THD_mask_fillin_completely( int nx, int ny, int nz, byte *mmm, int nside )
00432 {
00433    int nfill=0 , kfill ;
00434 
00435 ENTRY("THD_mask_fillin_completely") ;
00436 
00437    do{
00438       kfill = THD_mask_fillin_once( nx,ny,nz , mmm , nside ) ;
00439       nfill += kfill ;
00440    } while( kfill > 0 ) ;
00441 
00442    RETURN(nfill) ;
00443 }
00444 
00445 
00446 
00447 # define DALL 1024  
00448 
00449 
00450 
00451 # define CPUT(i,j,k)                                            \
00452   do{ ijk = THREE_TO_IJK(i,j,k,nx,nxy) ;                        \
00453       if( mmm[ijk] ){                                           \
00454         if( nnow == nall ){         \
00455           nall += dall ;                                        \
00456           inow = (short *) realloc(inow,sizeof(short)*nall) ;   \
00457           jnow = (short *) realloc(jnow,sizeof(short)*nall) ;   \
00458           know = (short *) realloc(know,sizeof(short)*nall) ;   \
00459         }                                                       \
00460         inow[nnow] = i ; jnow[nnow] = j ; know[nnow] = k ;      \
00461         nnow++ ; mmm[ijk] = 0 ;                                 \
00462       } } while(0)
00463 
00464 
00465 
00466 
00467 
00468 void THD_mask_clust( int nx, int ny, int nz, byte *mmm )
00469 {
00470    int ii,jj,kk, icl ,  nxy,nxyz , ijk , ijk_last , mnum ;
00471    int ip,jp,kp , im,jm,km ;
00472    int nbest ; short *ibest, *jbest , *kbest ;
00473    int nnow  ; short *inow , *jnow  , *know  ; int nall ;
00474 
00475    if( mmm == NULL ) return ;
00476 
00477    nxy = nx*ny ; nxyz = nxy * nz ;
00478 
00479    nbest = 0 ;
00480    ibest = AFMALL(short, sizeof(short)) ;
00481    jbest = AFMALL(short, sizeof(short)) ;
00482    kbest = AFMALL(short, sizeof(short)) ;
00483 
00484    
00485 
00486    ijk_last = 0 ; if( dall < DALL ) dall = DALL ;
00487    while(1) {
00488      
00489 
00490      for( ijk=ijk_last ; ijk < nxyz ; ijk++ ) if( mmm[ijk] ) break ;
00491      if( ijk == nxyz ) break ;  
00492 
00493      ijk_last = ijk+1 ;         
00494 
00495      
00496 
00497      mmm[ijk] = 0 ;                                
00498      nall = DALL ;                                 
00499      nnow = 1 ;                                    
00500      inow = (short *) malloc(sizeof(short)*DALL) ; 
00501      jnow = (short *) malloc(sizeof(short)*DALL) ;
00502      know = (short *) malloc(sizeof(short)*DALL) ;
00503      IJK_TO_THREE(ijk, inow[0],jnow[0],know[0] , nx,nxy) ;
00504 
00505      
00506 
00507 
00508 
00509 
00510 
00511 
00512 
00513      for( icl=0 ; icl < nnow ; icl++ ){
00514        ii = inow[icl] ; jj = jnow[icl] ; kk = know[icl] ;
00515        im = ii-1      ; jm = jj-1      ; km = kk-1 ;
00516        ip = ii+1      ; jp = jj+1      ; kp = kk+1 ;
00517 
00518        if( im >= 0 ) CPUT(im,jj,kk) ;
00519        if( ip < nx ) CPUT(ip,jj,kk) ;
00520        if( jm >= 0 ) CPUT(ii,jm,kk) ;
00521        if( jp < ny ) CPUT(ii,jp,kk) ;
00522        if( km >= 0 ) CPUT(ii,jj,km) ;
00523        if( kp < nz ) CPUT(ii,jj,kp) ;
00524      }
00525 
00526      
00527 
00528      if( nnow > nbest ){                         
00529        free(ibest) ; free(jbest) ; free(kbest) ; 
00530        nbest = nnow ; ibest = inow ;             
00531        jbest = jnow ; kbest = know ;
00532      } else {                                    
00533        free(inow) ; free(jnow) ; free(know) ;    
00534      }
00535 
00536    } 
00537 
00538    
00539 
00540    for( icl=0 ; icl < nbest ; icl++ ){
00541       ijk = THREE_TO_IJK(ibest[icl],jbest[icl],kbest[icl],nx,nxy) ;
00542       mmm[ijk] = 1 ;
00543    }
00544    free(ibest) ; free(jbest) ; free(kbest) ;
00545 
00546    if( verb ) ININFO_message("Largest cluster has %d voxels\n",nbest) ;
00547 
00548    return ;
00549 }
00550 
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 void THD_mask_erode( int nx, int ny, int nz, byte *mmm )
00559 {
00560    int ii,jj,kk , jy,kz, im,jm,km , ip,jp,kp , num ;
00561    int nxy=nx*ny , nxyz=nxy*nz ;
00562    byte *nnn ;
00563 
00564    if( mmm == NULL ) return ;
00565 
00566    nnn = (byte*)calloc(sizeof(byte),nxyz) ;  
00567 
00568    
00569 
00570    for( kk=0 ; kk < nz ; kk++ ){
00571     kz = kk*nxy ; km = kz-nxy ; kp = kz+nxy ;
00572          if( kk == 0    ) km = kz ;
00573     else if( kk == nz-1 ) kp = kz ;
00574 
00575     for( jj=0 ; jj < ny ; jj++ ){
00576      jy = jj*nx ; jm = jy-nx ; jp = jy+nx ;
00577           if( jj == 0    ) jm = jy ;
00578      else if( jj == ny-1 ) jp = jy ;
00579 
00580      for( ii=0 ; ii < nx ; ii++ ){
00581        if( mmm[ii+jy+kz] ){           
00582          im = ii-1 ; ip = ii+1 ;
00583               if( ii == 0    ) im = 0 ;
00584          else if( ii == nx-1 ) ip = ii ;
00585          num =  mmm[im+jy+km]
00586               + mmm[ii+jm+km] + mmm[ii+jy+km] + mmm[ii+jp+km]
00587               + mmm[ip+jy+km]
00588               + mmm[im+jm+kz] + mmm[im+jy+kz] + mmm[im+jp+kz]
00589               + mmm[ii+jm+kz]                 + mmm[ii+jp+kz]
00590               + mmm[ip+jm+kz] + mmm[ip+jy+kz] + mmm[ip+jp+kz]
00591               + mmm[im+jy+kp]
00592               + mmm[ii+jm+kp] + mmm[ii+jy+kp] + mmm[ii+jp+kp]
00593               + mmm[ip+jy+kp] ;
00594          if( num < 17 ) nnn[ii+jy+kz] = 1 ;  
00595        }
00596    } } }
00597 
00598    for( jj=ii=0 ; ii < nxyz ; ii++ )            
00599      if( nnn[ii] ){ mmm[ii] = 0 ; jj++ ; }
00600 
00601    if( verb && jj > 0 ) ININFO_message("Eroded   %d voxels\n",jj) ;
00602 
00603    
00604 
00605 #ifdef USE_DILATE
00606    for( kk=0 ; kk < nz ; kk++ ){
00607     kz = kk*nxy ; km = kz-nxy ; kp = kz+nxy ;
00608          if( kk == 0    ) km = kz ;
00609     else if( kk == nz-1 ) kp = kz ;
00610 
00611     for( jj=0 ; jj < ny ; jj++ ){
00612      jy = jj*nx ; jm = jy-nx ; jp = jy+nx ;
00613           if( jj == 0    ) jm = jy ;
00614      else if( jj == ny-1 ) jp = jy ;
00615 
00616      for( ii=0 ; ii < nx ; ii++ ){
00617        if( nnn[ii+jy+kz] ){           
00618          im = ii-1 ; ip = ii+1 ;
00619               if( ii == 0    ) im = 0 ;
00620          else if( ii == nx-1 ) ip = ii ;
00621          nnn[ii+jy+kz] =              
00622                mmm[im+jy+km]
00623             || mmm[ii+jm+km] || mmm[ii+jy+km] || mmm[ii+jp+km]
00624             || mmm[ip+jy+km]
00625             || mmm[im+jm+kz] || mmm[im+jy+kz] || mmm[im+jp+kz]
00626             || mmm[ii+jm+kz]                  || mmm[ii+jp+kz]
00627             || mmm[ip+jm+kz] || mmm[ip+jy+kz] || mmm[ip+jp+kz]
00628             || mmm[im+jy+kp]
00629             || mmm[ii+jm+kp] || mmm[ii+jy+kp] || mmm[ii+jp+kp]
00630             || mmm[ip+jy+kp] ;
00631        }
00632    } } }
00633 
00634    
00635 
00636    for( jj=ii=0 ; ii < nxyz ; ii++ )
00637      if( nnn[ii] ){ mmm[ii] = 1 ; jj++ ; }
00638 
00639    if( verb && jj > 0 ) ININFO_message("Restored %d eroded voxels\n",jj) ;
00640 #endif
00641 
00642    free(nnn) ; return ;
00643 }
00644 
00645 
00646 
00647 
00648 
00649 
00650 
00651 void THD_mask_dilate( int nx, int ny, int nz, byte *mmm , int ndil )
00652 {
00653    int ii,jj,kk , jy,kz, im,jm,km , ip,jp,kp , num ;
00654    int nxy=nx*ny , nxyz=nxy*nz ;
00655    byte *nnn ;
00656 
00657    if( mmm == NULL ) return ;
00658         if( ndil < 1  ) ndil =  1 ;
00659    else if( ndil > 17 ) ndil = 17 ;
00660 
00661    nnn = (byte*)calloc(sizeof(byte),nxyz) ;  
00662 
00663    
00664 
00665    for( kk=0 ; kk < nz ; kk++ ){
00666     kz = kk*nxy ; km = kz-nxy ; kp = kz+nxy ;
00667          if( kk == 0    ) km = kz ;
00668     else if( kk == nz-1 ) kp = kz ;
00669 
00670     for( jj=0 ; jj < ny ; jj++ ){
00671      jy = jj*nx ; jm = jy-nx ; jp = jy+nx ;
00672           if( jj == 0    ) jm = jy ;
00673      else if( jj == ny-1 ) jp = jy ;
00674 
00675      for( ii=0 ; ii < nx ; ii++ ){
00676        if( mmm[ii+jy+kz] == 0 ){           
00677          im = ii-1 ; ip = ii+1 ;
00678               if( ii == 0    ) im = 0 ;
00679          else if( ii == nx-1 ) ip = ii ;
00680          num =  mmm[im+jy+km]
00681               + mmm[ii+jm+km] + mmm[ii+jy+km] + mmm[ii+jp+km]
00682               + mmm[ip+jy+km]
00683               + mmm[im+jm+kz] + mmm[im+jy+kz] + mmm[im+jp+kz]
00684               + mmm[ii+jm+kz]                 + mmm[ii+jp+kz]
00685               + mmm[ip+jm+kz] + mmm[ip+jy+kz] + mmm[ip+jp+kz]
00686               + mmm[im+jy+kp]
00687               + mmm[ii+jm+kp] + mmm[ii+jy+kp] + mmm[ii+jp+kp]
00688               + mmm[ip+jy+kp] ;
00689          if( num >= ndil ) nnn[ii+jy+kz] = 1 ;  
00690        }
00691    } } }
00692 
00693    for( ii=0 ; ii < nxyz ; ii++ )            
00694      if( nnn[ii] ) mmm[ii] = 1 ;
00695 
00696    free(nnn) ; return ;
00697 }
00698 
00699 
00700 
00701 
00702 
00703 
00704 void THD_autobbox( THD_3dim_dataset *dset ,
00705                    int *xm, int *xp , int *ym, int *yp , int *zm, int *zp )
00706 {
00707    MRI_IMAGE *medim ;
00708    float clip_val , *mar ;
00709    int nvox , ii ;
00710 
00711 ENTRY("THD_autobbox") ;
00712 
00713    medim = THD_median_brick(dset) ; if( medim == NULL ) EXRETURN ;
00714 
00715    mar  = MRI_FLOAT_PTR(medim) ;
00716    nvox = medim->nvox ;
00717    for( ii=0 ; ii < nvox ; ii++ ) mar[ii] = fabs(mar[ii]) ;
00718 
00719    clip_val = THD_cliplevel(medim,0.5) ;
00720    for( ii=0 ; ii < nvox ; ii++ )
00721      if( mar[ii] < clip_val ) mar[ii] = 0.0 ;
00722 
00723    MRI_autobbox( medim , xm,xp , ym,yp , zm,zp ) ;
00724 
00725    mri_free(medim) ; EXRETURN ;
00726 }
00727 
00728 
00729 
00730 void MRI_autobbox( MRI_IMAGE *qim ,
00731                    int *xm, int *xp , int *ym, int *yp , int *zm, int *zp )
00732 {
00733    MRI_IMAGE *fim ;
00734    float *mar ;
00735    byte *mmm = NULL ;
00736    int nvox , ii,jj,kk , nmm , nx,ny,nz,nxy ;
00737 
00738 ENTRY("MRI_autobbox") ;
00739 
00740    
00741 
00742    if( qim->kind != MRI_float ) fim = mri_to_float(qim) ;
00743    else                         fim = qim ;
00744 
00745    nvox = fim->nvox ;
00746    mar  = MRI_FLOAT_PTR(fim) ;
00747    mmm  = (byte *) calloc( sizeof(byte) , nvox ) ;
00748    for( nmm=ii=0 ; ii < nvox ; ii++ )
00749      if( mar[ii] != 0.0 ){ mmm[ii] = 1; nmm++; }
00750 
00751    if( fim != qim ) mri_free(fim) ;
00752 
00753    if( nmm == 0 ){ free(mmm); EXRETURN; }
00754 
00755    nx = qim->nx; ny = qim->ny; nz = qim->nz; nxy = nx*ny;
00756 
00757    THD_mask_clust( nx,ny,nz, mmm ) ;
00758    THD_mask_erode( nx,ny,nz, mmm ) ;
00759    THD_mask_clust( nx,ny,nz, mmm ) ;
00760 
00761    
00762 
00763 
00764    if( xm != NULL ){
00765      for( ii=0 ; ii < nx ; ii++ )
00766        for( kk=0 ; kk < nz ; kk++ )
00767          for( jj=0 ; jj < ny ; jj++ )
00768            if( mmm[ii+jj*nx+kk*nxy] ) goto CP5 ;
00769      CP5: *xm = ii ;
00770    }
00771 
00772    if( xp != NULL ){
00773      for( ii=nx-1 ; ii >= 0 ; ii-- )
00774        for( kk=0 ; kk < nz ; kk++ )
00775          for( jj=0 ; jj < ny ; jj++ )
00776            if( mmm[ii+jj*nx+kk*nxy] ) goto CP6 ;
00777      CP6: *xp = ii ;
00778    }
00779 
00780    if( ym != NULL ){
00781      for( jj=0 ; jj < ny ; jj++ )
00782        for( kk=0 ; kk < nz ; kk++ )
00783          for( ii=0 ; ii < nx ; ii++ )
00784            if( mmm[ii+jj*nx+kk*nxy] ) goto CP3 ;
00785      CP3: *ym = jj ;
00786    }
00787 
00788    if( yp != NULL ){
00789      for( jj=ny-1 ; jj >= 0 ; jj-- )
00790        for( kk=0 ; kk < nz ; kk++ )
00791          for( ii=0 ; ii < nx ; ii++ )
00792            if( mmm[ii+jj*nx+kk*nxy] ) goto CP4 ;
00793      CP4: *yp = jj ;
00794    }
00795 
00796    if( zm != NULL ){
00797      for( kk=0 ; kk < nz ; kk++ )
00798        for( jj=0 ; jj < ny ; jj++ )
00799          for( ii=0 ; ii < nx ; ii++ )
00800            if( mmm[ii+jj*nx+kk*nxy] ) goto CP1 ;
00801      CP1: *zm = kk ;
00802    }
00803 
00804    if( zp != NULL ){
00805      for( kk=nz-1 ; kk >= 0 ; kk-- )
00806        for( jj=0 ; jj < ny ; jj++ )
00807          for( ii=0 ; ii < nx ; ii++ )
00808            if( mmm[ii+jj*nx+kk*nxy] ) goto CP2 ;
00809      CP2: *zp = kk ;
00810    }
00811 
00812    free(mmm) ; EXRETURN ;
00813 }
00814 
00815 
00816 
00817 int THD_peel_mask( int nx, int ny, int nz , byte *mmm, int pdepth )
00818 {
00819    int nxy=nx*ny , ii,jj,kk , ijk , bot,top , pd=pdepth ;
00820    int nxp=nx-pd , nyp=ny-pd , nzp=nz-pd ;
00821    int num=0 , dnum , nite ;
00822 
00823    for( nite=0 ; nite < pd ; nite++ ){
00824     dnum = 0 ;
00825 
00826     for( kk=0 ; kk < nz ; kk++ ){
00827      for( jj=0 ; jj < ny ; jj++ ){
00828        ijk = jj*nx + kk*nxy ;
00829        for( bot=0 ; bot < nx && !mmm[bot+ijk]; bot++ ) ;
00830        top = bot+pd ; if( top >= nx ) continue ;
00831        for( ii=bot+1 ; ii <= top && mmm[ii+ijk] ; ii++ ) ;
00832        if( ii <= top ){ mmm[bot+ijk] = 0; dnum++; }
00833     }}
00834 
00835     for( kk=0 ; kk < nz ; kk++ ){
00836      for( jj=0 ; jj < ny ; jj++ ){
00837        ijk = jj*nx + kk*nxy ;
00838        for( top=nx-1 ; top >= 0 && !mmm[top+ijk]; top-- ) ;
00839        bot = top-pd ; if( bot < 0 ) continue ;
00840        for( ii=top-1 ; ii >= bot && mmm[ii+ijk] ; ii-- ) ;
00841        if( ii >= bot ){ mmm[top+ijk] = 0; dnum++; }
00842     }}
00843 
00844     for( kk=0 ; kk < nz ; kk++ ){
00845      for( ii=0 ; ii < nx ; ii++ ){
00846        ijk = ii + kk*nxy ;
00847        for( bot=0 ; bot < ny && !mmm[bot*nx+ijk] ; bot++ ) ;
00848        top = bot+pd ;
00849        if( top >= ny ) continue ;
00850        for( jj=bot+1 ; jj <= top && mmm[jj*nx+ijk] ; jj++ ) ;
00851        if( jj <= top ){ mmm[bot*nx+ijk] = 0; dnum++; }
00852     }}
00853 
00854     for( kk=0 ; kk < nz ; kk++ ){
00855      for( ii=0 ; ii < nx ; ii++ ){
00856        ijk = ii + kk*nxy ;
00857        for( top=ny-1 ; top >= 0 && !mmm[top*nx+ijk] ; top-- ) ;
00858        bot = top-pd ; if( bot < 0 ) continue ;
00859        for( jj=top-1 ; jj >= bot && mmm[jj*nx+ijk] ; jj-- ) ;
00860        if( jj >= bot ){ mmm[top*nx+ijk] = 0; dnum++; }
00861     }}
00862 
00863     for( jj=0 ; jj < ny ; jj++ ){
00864      for( ii=0 ; ii < nx ; ii++ ){
00865        ijk = ii + jj*nx ;
00866        for( top=nz-1 ; top >= 0 && !mmm[top*nxy+ijk] ; top-- ) ;
00867        bot = top-pd ; if( bot < 0 ) continue ;
00868        for( kk=top-1 ; kk >= bot && mmm[kk*nxy+ijk] ; kk-- ) ;
00869        if( kk >= bot ){ mmm[top*nxy+ijk] = 0; dnum++; }
00870     }}
00871 
00872     num += dnum ;
00873     if( dnum == 0 ) break ;
00874    }
00875 
00876    return num ;
00877 }