00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include "mrilib.h"
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <math.h>
00015 
00016 
00017 void errorExit(char *message) { 
00018         
00019         fprintf(stderr, "\n\nError in 3dEdge:\n%s\n\nTry 3dEdge -help\n",message);
00020         exit(1);
00021 }
00022 
00023 
00024 void helpMessage()
00025 
00026 {
00027   printf(
00028          "Generates an edge-detected mask from the input dataset.\n"
00029          "Usage: 3dEdge [options] dataset\n"
00030          "Where the options are:\n"
00031          "  -prefix name     The prefix for the filename of the edge-masked\n"
00032          "                   dataset.\n"
00033          "  -mask name       The filename for the separately output mask.\n"
00034          "  -rms float       The floating point value (0 <= rms <= 1) for RMS\n"
00035          "                   threshhold. Voxels in the time-averaged volume with\n"
00036          "                   >= this fraction of the peak RMS for that volume\n"
00037          "                   are provisionally part of the mask, though other\n"
00038          "                   tests may subsequently remove them.\n"
00039          "  -neighbor float  The floating point value for the neighbor\n"
00040          "                   threshhold. Voxels in the RMS-derived mask are\n"
00041          "                   removed if less than this fraction of their nearest\n"
00042          "                   neighbors are included in the RMS-derived mask,\n"
00043          "                   else they are added.\n"
00044   );
00045 }
00046 
00047 
00048 int edgeCount(int l, int nxx, int nyy, int nvox)
00049 
00050 
00051 
00052 
00053 {
00054   int count=0;
00055   if (l < (nxx*nyy)) count++;
00056   if (l < (nxx*nyy + 1)) count++;
00057 
00058   if (l > (nvox - (nxx*nyy))) count++;
00059   if (l > (nvox - (nxx*nyy) - 1)) count++;
00060 
00061 
00062   if (l % (nxx*nyy) < nxx) count++;
00063   if (l % (nxx*nyy) < (nxx + 1)) count++;
00064 
00065   if (l % (nxx*nyy) > (nxx * (nyy - 1))) count++;
00066   if (l % (nxx*nyy) > (nxx * (nyy - 1) - 1)) count++;
00067 
00068 
00069   if (((l % (nxx*nyy)) %  nxx) == 0) count++;
00070   if (((l % (nxx*nyy)) %  nxx) == 1) count++;
00071 
00072   if (((l % (nxx*nyy)) %  nxx) == (nxx - 1)) count++;
00073   if (((l % (nxx*nyy)) %  nxx) == (nxx - 2)) count++;
00074  
00075   return (count*25) - (count*count)-1;
00076 }
00077 
00078 
00079 float neighborCount(unsigned char *mask, int location, int nxx, int nyy, int nvox)
00080 {
00081   int c=0; 
00082   int i, j, k; 
00083   int tmpLocation;
00084   float percent;  
00085   for (i=-2 ; i <= 2 ; i++)
00086     for (j=-2 ; j <= 2 ; j++)
00087       for (k=-2 ; k <= 2 ; k++)
00088 
00089 
00090 
00091 
00092         if (i | j | k)
00093           {
00094             tmpLocation = location;
00095             tmpLocation += i;
00096             tmpLocation += (j * nxx);
00097             if (location < (nxx*nyy)) 
00098               {
00099                 if (k < 0) continue;
00100                   tmpLocation += (k * nxx * nyy);
00101               }
00102             else if (location < ((nxx*nyy) + 1))
00103               {
00104                 if (k < -1) continue;
00105                   tmpLocation += (k * nxx * nyy);
00106               }
00107             else if (location > (nvox - (nxx*nyy)))
00108               {
00109                 if (k > 0) continue;
00110                   tmpLocation += (k * nxx * nyy);
00111               }
00112             else if (location > (nvox - (nxx*nyy) - 1))
00113               {
00114                 if (k > 1) continue;
00115                   tmpLocation += (k * nxx * nyy);
00116               }
00117             if (mask[tmpLocation]) 
00118               c++;
00119           }
00120   percent = ( (float) c / (124 - edgeCount(location, nxx, nyy, nvox)));
00121   return percent;
00122 }
00123 
00124 
00125 void recurseSelect(unsigned char *mask, int nxx, int nyy, int nvox, int i)
00126 {
00127   float x;
00128   float y;
00129   float z;
00130 
00131   if (mask[i] == 1)
00132     {
00133       mask[i] = 2;
00134         {
00135           recurseSelect(mask, nxx, nyy, nvox, (i + 1));
00136           recurseSelect(mask, nxx, nyy, nvox, (i - 1));
00137       
00138           recurseSelect(mask, nxx, nyy, nvox, (i + nxx));
00139           recurseSelect(mask, nxx, nyy, nvox, (i - nxx));
00140       
00141           recurseSelect(mask, nxx, nyy, nvox, (i + (nxx * nyy)));
00142           recurseSelect(mask, nxx, nyy, nvox, (i - (nxx * nyy)));
00143         }
00144     }
00145   else
00146     return;
00147 }
00148 
00149 
00150 int centerOfMass(unsigned char *mask, int nxx, int nyy, int nvox)
00151 {
00152   int i;
00153   float xMass=0;
00154   float yMass=0;
00155   float zMass=0;
00156   int mass=0;
00157 
00158   for(i=0 ; i < nvox ; i++)
00159     {
00160       if (mask[i])
00161         {
00162           xMass += (i % (nxx * nyy) % nxx);
00163           yMass += (i % (nxx * nyy) / nxx);
00164           zMass += (i / (nxx * nyy));
00165           mass++;
00166         }
00167     }
00168   xMass /= mass;
00169   yMass /= mass;
00170   zMass /= mass;
00171   return (int) ((int) (xMass+0.49) + ((int) (yMass+0.49) * nxx) + ((int) (zMass+0.49) * (nxx * nyy))); 
00172 }
00173 
00174 
00175 unsigned char* edgeDetect(THD_3dim_dataset *inputDataset, float rmsThresh, float neighbors)
00176 {
00177   int nvox, ntimes;
00178   int nxx, nyy;
00179   int i,j;
00180   unsigned char *inputTimeStep_b;  
00181   short *inputTimeStep_s;  
00182   float *inputTimeStep_f;
00183   unsigned char *mask;
00184   double *sums;
00185   double rms=0;
00186   unsigned char *newMask; 
00187   THD_3dim_dataset *outputDataset=NULL;
00188 
00189   DSET_load(inputDataset);
00190   
00191   ntimes = DSET_NUM_TIMES(inputDataset);
00192   nvox = DSET_NVOX(inputDataset);
00193 
00194   nxx=inputDataset->daxes->nxx;
00195   nyy=inputDataset->daxes->nyy;
00196  
00197   sums = (double *) malloc(nvox * sizeof(double));
00198   mask = (unsigned char *) malloc(nvox * sizeof(unsigned char));
00199   newMask = (unsigned char *) malloc(nvox * sizeof(unsigned char));
00200 
00201 
00202 
00203 
00204 
00205   for (j=0 ; j < ntimes ; j++)
00206     {
00207       switch (DSET_BRICK_TYPE(inputDataset, j))
00208         {
00209         case MRI_byte:
00210           {
00211             inputTimeStep_b = (unsigned char *) DSET_ARRAY(inputDataset, j);
00212             for (i=0 ; i < nvox ; i++)
00213               {  
00214                 sums[i] += inputTimeStep_b[i]; 
00215               }
00216             break;
00217           }
00218         case MRI_short:
00219           {
00220             inputTimeStep_s = (short *) DSET_ARRAY(inputDataset, j);
00221             for (i=0 ; i < nvox ; i++)
00222               {  
00223                 sums[i] += inputTimeStep_s[i]; 
00224               }
00225             break;
00226           }
00227         case MRI_float:
00228           {
00229             inputTimeStep_f = (float *) DSET_ARRAY(inputDataset, j);
00230             for (i=0 ; i < nvox ; i++)
00231               {  
00232                 sums[i] += inputTimeStep_f[i];
00233               }
00234             break;
00235           }
00236         default:
00237           errorExit("Dataset sub-brick is of unrecognized type.");
00238         }
00239 
00240         
00241     } 
00242   for (i=0 ; i < nvox ; i++)
00243     {
00244       sums[i] /= ntimes;
00245       rms += sums[i]*sums[i];
00246     }
00247   rms /= nvox;
00248   rms = sqrt(rms);
00249   
00250 
00251   for (i=0 ; i < nvox ; i++)
00252     {
00253       mask[i] = (sums[i] >= (rms * rmsThresh));
00254     }
00255 
00256    for (i = 0 ; i < nvox ; i++)  
00257      if (neighborCount(mask, i, nxx, nyy, nvox) < neighbors) newMask[i]=0;
00258      else
00259        newMask[i]=mask[i];
00260    for (i = 0 ; i < nvox ; i++) 
00261      mask[i] = newMask[i];
00262    for (i = 0 ; i < nvox ; i++)  
00263       if (neighborCount(mask, i, nxx, nyy, nvox) > neighbors) newMask[i]=1;
00264    for (i = 0 ; i < nvox ; i++) 
00265      mask[i] = newMask[i];
00266 
00267    i = centerOfMass(mask, nxx, nyy, nvox);
00268 
00269    recurseSelect(mask, nxx, nyy, nvox, i);
00270 
00271    for (i = 0 ; i < nvox ; i++) 
00272      mask[i] = mask[i]==2;
00273    
00274    free(sums);
00275    free(newMask);
00276    return mask;
00277 }
00278 
00279 
00280 int applyMask(THD_3dim_dataset *inputDataset, unsigned char *mask, char *prefix, int argc, char *argv[])
00281 
00282 {
00283   int ierr;
00284   int i,j;
00285   int ntimes, nvox;
00286   double* timeStep;
00287   THD_3dim_dataset *outputDataset;
00288 
00289   unsigned char *inputTimeStep_b;  
00290   short *inputTimeStep_s;  
00291   float *inputTimeStep_f;
00292 
00293   unsigned char *outputTimeStep_b;  
00294   short *outputTimeStep_s;  
00295   float *outputTimeStep_f;
00296 
00297   ntimes = DSET_NUM_TIMES(inputDataset);
00298   nvox = DSET_NVOX(inputDataset);
00299   outputDataset = EDIT_empty_copy(inputDataset);
00300 
00301   ierr = EDIT_dset_items(outputDataset,
00302                            ADN_type, HEAD_ANAT_TYPE,     
00303                            ADN_func_type, FUNC_FIM_TYPE, 
00304                            ADN_prefix, prefix,
00305                          ADN_none);
00306 
00307   for (j=0 ; j < ntimes ; j++)
00308     {
00309       switch (DSET_BRICK_TYPE(inputDataset, j))
00310         {
00311         case MRI_byte:
00312           {
00313             inputTimeStep_b = (unsigned char *) DSET_ARRAY(inputDataset, j);
00314             outputTimeStep_b = (unsigned char *) malloc(sizeof(unsigned char) * nvox);
00315             for (i=0 ; i < nvox ; i++)
00316               {  
00317                 if (mask[i])
00318                   outputTimeStep_b[i] = inputTimeStep_b[i];
00319                 else
00320                   outputTimeStep_b[i] = 0;
00321               }
00322             EDIT_substitute_brick(outputDataset, j, DSET_BRICK_TYPE(inputDataset, j), outputTimeStep_b);
00323             break;
00324           }
00325         case MRI_short:
00326           {
00327             inputTimeStep_s = (short *) DSET_ARRAY(inputDataset, j);
00328             outputTimeStep_s = (short *) malloc(sizeof(short) * nvox);
00329             for (i=0 ; i < nvox ; i++)
00330               {  
00331                 if (mask[i])
00332                   outputTimeStep_s[i] = inputTimeStep_s[i];
00333                 else
00334                   outputTimeStep_s[i] = 0;
00335               }
00336             EDIT_substitute_brick(outputDataset, j, DSET_BRICK_TYPE(inputDataset, j), outputTimeStep_s);
00337             break;
00338           }
00339         case MRI_float:
00340           {
00341             inputTimeStep_f = (float *) DSET_ARRAY(inputDataset, j);
00342             outputTimeStep_f = (float *) malloc(sizeof(inputTimeStep_f));
00343             for (i=0 ; i < nvox ; i++)
00344               {  
00345                 if (mask[i])
00346                   outputTimeStep_f[i] = inputTimeStep_f[i];
00347                 else
00348                   outputTimeStep_f[i] = 0;
00349               }
00350             EDIT_substitute_brick(outputDataset, j, DSET_BRICK_TYPE(inputDataset, j), outputTimeStep_f);
00351             break;
00352           }
00353         default:
00354           errorExit("Dataset sub-brick is of unrecognized type.");
00355         }
00356     } 
00357     tross_Copy_History( inputDataset, outputDataset );
00358     tross_Make_History( "3dedge" , argc, argv, outputDataset) ;
00359     DSET_write(outputDataset);  
00360 
00361 
00362 }
00363 
00364 void saveMask(THD_3dim_dataset *inputDataset, unsigned char *mask, char *prefix)
00365 {
00366   int ierr;
00367   THD_3dim_dataset *outputDataset;
00368   
00369   outputDataset = EDIT_empty_copy(inputDataset);
00370   ierr = EDIT_dset_items(outputDataset,
00371                            ADN_prefix, prefix,      
00372                            ADN_datum_all, MRI_byte,      
00373                            ADN_nvals, 1,                 
00374                            ADN_type, HEAD_FUNC_TYPE,     
00375                            ADN_func_type, FUNC_FIM_TYPE, 
00376                            ADN_ntt, 1,                   
00377                          ADN_none);
00378   EDIT_substitute_brick(outputDataset, 0, MRI_byte, mask);
00379   DSET_write(outputDataset);
00380 }
00381 
00382 
00383 THD_3dim_dataset* openDataset(char *name)
00384 {
00385   THD_3dim_dataset *newDataset = THD_open_dataset(name);
00386 
00387 
00388   if (newDataset == NULL)
00389     errorExit("Cannot open new dataset!");
00390   if (DSET_BRICK_TYPE(newDataset, 0) == MRI_complex)
00391     errorExit("I can't deal with complex datasets.");
00392   if (DSET_BRICK_FACTOR(newDataset, 0))
00393     errorExit("I can't deal with datasets containing scaling factors");
00394 
00395   return newDataset; 
00396 }
00397 
00398 
00399 int main(int argc, char *argv[])
00400 {
00401   int narg=1;
00402   int stringLength;
00403   float rms=1.0;
00404   float neighbors=0.5;
00405   char *prefix = "masked";
00406   char *maskName = "mask";
00407   unsigned char *mask;
00408   THD_3dim_dataset *inputDataset=NULL;
00409   
00410   if (argc < 2 || (strcmp(argv[1], "-help") == 0))
00411     {
00412       helpMessage();
00413       exit(1);
00414     }
00415 
00416   while((narg < argc) && (argv[narg][0] == '-'))
00417     {
00418       if (strcmp(argv[narg], "-prefix") == 0)
00419         {
00420           narg++;
00421           stringLength = strlen(argv[narg]);
00422           prefix = (char *) malloc((stringLength + 1) * sizeof(char));
00423           strcpy(prefix, argv[narg++]);
00424 
00425           continue;
00426         }
00427       if (strcmp(argv[narg], "-mask") == 0)
00428         {
00429           narg++;
00430           stringLength = strlen(argv[narg]);
00431           maskName = (char *) malloc((stringLength + 1) * sizeof(char));
00432           strcpy(maskName, argv[narg++]);
00433 
00434           continue;
00435         }
00436       if (strcmp(argv[narg], "-rms") == 0)
00437         {
00438           narg++;
00439           rms = (float)atof(argv[narg++]);
00440 
00441           continue;
00442         }
00443       if (strcmp(argv[narg], "-neighbor") == 0)
00444         {
00445           narg++;
00446           neighbors = (float)atof(argv[narg++]);
00447 
00448           continue;
00449         }
00450       else
00451         {
00452           printf("*** unrecognized option, %s\n", argv[narg]);
00453           narg++;
00454         }
00455     }
00456   inputDataset = openDataset(argv[narg]);
00457   mask = edgeDetect(inputDataset, rms, neighbors);
00458   if (strcmp(maskName, "mask") != 0)
00459         saveMask(inputDataset, mask, maskName);
00460   applyMask(inputDataset, mask, prefix, argc, argv);
00461   return 0;
00462 }
00463 
00464 
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484