1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2001, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 /*---------------------------------------------------------------------------*/
8 /*
9   Program to correct for image intensity nonuniformity.
10 
11   File:    3dUniformize.c
12   Author:  B. Douglas Ward
13   Date:    28 January 2000
14 
15   Mod:     Added call to AFNI_logger.
16   Date:    15 August 2001
17 
18 */
19 
20 /*---------------------------------------------------------------------------*/
21 
22 #define PROGRAM_NAME "3dUniformize"                  /* name of this program */
23 #define PROGRAM_AUTHOR "B. D. Ward"                        /* program author */
24 #define PROGRAM_INITIAL "28 January 2000" /* date of initial program release */
25 #define PROGRAM_LATEST  "03 January 2010 [zss]" /* date of latest program revision */
26 
27 /*---------------------------------------------------------------------------*/
28 /*
29   Include header files.
30 */
31 
32 #include "mrilib.h"
33 #include "matrix.h"
34 
35 
36 /*---------------------------------------------------------------------------*/
37 /*
38   Global variables, constants, and data structures.
39 */
40 
41 #define MAX_STRING_LENGTH THD_MAX_NAME
42 
43 static THD_3dim_dataset * anat_dset = NULL;     /* input anatomical dataset  */
44 char * commandline = NULL ;                /* command line for history notes */
45 
46 int input_datum = MRI_short ;              /* 16 Apr 2003 - RWCox */
47 int quiet       = 0 ;                      /* ditto */
48 #define USE_QUIET
49 
50 typedef struct UN_options
51 {
52   char * anat_filename;       /* file name for input anat dataset */
53   char * prefix_filename;     /* prefix name for output dataset */
54   RwcBoolean quiet;              /* flag for suppress screen output */
55   int lower_limit;    /* lower limit for voxel intensity */
56   int upper_limit;    /* upper limit for voxel intensity 0 for ignoring this parameter*/
57   int rpts;           /* #voxels in sub-sampled image (for pdf) */
58   int spts;           /* #voxels in subsub-sampled image (for field poly.) */
59   int nbin;           /* #bins for pdf estimation */
60   int npar;           /* #parameters for field polynomial */
61   int niter;          /* #number of iterations */
62   THD_3dim_dataset * new_dset;   /* output afni data set pointer */
63 } UN_options;
64 
65 
66 /*---------------------------------------------------------------------------*/
67 /*
68   Include source code files.
69 */
70 
71 #include "estpdf3.c"
72 
73 
74 /*---------------------------------------------------------------------------*/
75 /*
76    Print error message and stop.
77 */
78 
UN_error(char * message)79 void UN_error (char * message)
80 {
81   fprintf (stderr, "%s Error: %s \n", PROGRAM_NAME, message);
82   exit(1);
83 }
84 
85 
86 /*---------------------------------------------------------------------------*/
87 
88 /** macro to test a malloc-ed pointer for validity **/
89 
90 #define MTEST(ptr) \
91 if((ptr)==NULL) \
92 ( UN_error ("Cannot allocate memory") )
93 
94 
95 /*---------------------------------------------------------------------------*/
96 /*
97    Routine to display 3dUniformize help menu.
98 */
99 
display_help_menu()100 void display_help_menu()
101 {
102   printf
103     (
104      "   ***** NOTES *********************************************\n"
105      "   1) This program is superseded by 3dUnifize, and we don't\n"
106      "      recommend that you use it.\n"
107      "   2) This program will crash if you give it a multi-volume\n"
108      "      dataset.\n"
109      "   3) Neither 3dUniformize nor 3dUnifize can properly deal\n"
110      "      with EPI datasets at this time.\n"
111      "   *********************************************************\n"
112      "\n"
113      "This program corrects for T1-weighted image intensity nonuniformity.\n\n"
114      "\n"
115      "Usage: \n"
116      "3dUniformize  \n"
117      "-anat filename    Filename of anat dataset to be corrected            \n"
118      "                                                                      \n"
119      "[-clip_low LOW]   Use LOW as the voxel intensity separating           \n"
120      "                  brain from air.                                     \n"
121      "   NOTE: The historic clip_low value was 25.                          \n"
122      "      But that only works for certain types of input data and can     \n"
123      "      result in bad output depending on the range of values in        \n"
124      "      the input dataset.                                              \n"
125      "      The new default sets -clip_low via -auto_clip option.           \n"
126      "[-clip_high HIGH] Do not include voxels with intensity higher         \n"
127      "                  than HIGH in calculations.                          \n"
128      "[-auto_clip]      Automatically set the clip levels.                  \n"
129      "                  LOW in a procedure similar to 3dClipLevel,          \n"
130      "                  HIGH is set to 3*LOW. (Default since Jan. 2011)     \n"
131      "[-niter NITER]    Set the number of iterations for concentrating PDF  \n"
132      "                  Default is 5.                                       \n"
133      "[-quiet]          Suppress output to screen                           \n"
134      "                                                                      \n"
135      "-prefix pname     Prefix name for file to contain corrected image     \n"
136      "\n"
137      "Versions of this program postdating Jan. 3rd 2010 can handle byte, short\n"
138      "or float input and output the result in the data type as the input\n"
139       );
140 
141   printf("\n" MASTER_SHORTHELP_STRING ) ;
142   PRINT_COMPILE_DATE ; exit(0);
143 }
144 
145 
146 /*---------------------------------------------------------------------------*/
147 /*
148   Routine to initialize the input options.
149 */
150 
initialize_options(UN_options * option_data)151 void initialize_options
152 (
153   UN_options * option_data    /* uniformization program options */
154 )
155 
156 {
157 
158   /*----- initialize default values -----*/
159   option_data->anat_filename = NULL;    /* file name for input anat dataset */
160   option_data->prefix_filename = NULL;  /* prefix name for output dataset */
161   option_data->quiet = FALSE;           /* flag for suppress screen output */
162   option_data->lower_limit = -1;        /* voxel intensity lower limit,
163                                            used to be 25
164                                            -1 is default flag for auto_clip
165                                                        ZSS Jan 2011 */
166   option_data->upper_limit = 0;
167   option_data->rpts = 200000;   /* #voxels in sub-sampled image (for pdf) */
168   option_data->spts = 10000;    /* #voxels in subsub-sampled image
169                        (for field polynomial estimation) */
170   option_data->nbin = 250;      /* #bins for pdf estimation */
171   option_data->npar = 35;       /* #parameters for field polynomial */
172   option_data->niter = 5;       /* #number of iterations  */
173   option_data->new_dset = NULL;
174 }
175 
176 
177 /*---------------------------------------------------------------------------*/
178 /*
179   Routine to get user specified input options.
180 */
181 
get_options(int argc,char ** argv,UN_options * option_data)182 void get_options
183 (
184   int argc,                        /* number of input arguments */
185   char ** argv,                    /* array of input arguments */
186   UN_options * option_data         /* uniformization program options */
187 )
188 
189 {
190   int nopt = 1;                     /* input option argument counter */
191   int ival, index;                  /* integer input */
192   float fval;                       /* float input */
193   char message[MAX_STRING_LENGTH];  /* error message */
194 
195 
196   /*----- does user request help menu? -----*/
197   if (argc < 2 || strncmp(argv[1], "-help", 5) == 0)  display_help_menu();
198 
199 
200   /*----- add to program log -----*/
201   AFNI_logger (PROGRAM_NAME,argc,argv);
202 
203 
204   /*----- main loop over input options -----*/
205   while (nopt < argc )
206     {
207 
208       /*-----   -anat filename   -----*/
209       if (strncmp(argv[nopt], "-anat", 5) == 0)
210      {
211        nopt++;
212        if (nopt >= argc)  UN_error ("need argument after -anat ");
213        option_data->anat_filename =
214          malloc (sizeof(char) * MAX_STRING_LENGTH);
215        MTEST (option_data->anat_filename);
216        strcpy (option_data->anat_filename, argv[nopt]);
217 
218        anat_dset = THD_open_dataset (option_data->anat_filename);
219        if (!ISVALID_3DIM_DATASET (anat_dset))
220          {
221            sprintf (message, "Can't open dataset: %s\n",
222                  option_data->anat_filename);
223            UN_error (message);
224          }
225        DSET_load(anat_dset) ; CHECK_LOAD_ERROR(anat_dset) ;
226 
227      if( DSET_NVALS(anat_dset) > 1 )
228       WARNING_message("3dUniformize cannot process multi-volume datasets :(") ;
229 
230       /* if input is not float, float it */
231      input_datum = DSET_BRICK_TYPE(anat_dset,0);
232      if( input_datum != MRI_float ){
233          THD_3dim_dataset *qset ;
234          register float *far ;
235          register int ii,nvox ;
236          MRI_IMAGE *imf=NULL;
237 
238          INFO_message("converting input dataset to float") ;
239          qset = EDIT_empty_copy(anat_dset) ;
240          nvox = DSET_NVOX(anat_dset) ;
241          imf = THD_extract_float_brick(0,anat_dset) ;
242          far = (float *)malloc(sizeof(float)*nvox) ;
243          memcpy(far, MRI_FLOAT_PTR(imf), sizeof(float)*nvox) ;
244          mri_free(imf); imf=NULL;
245          EDIT_substitute_brick( qset , 0 , MRI_float, far);
246          DSET_delete(anat_dset) ; anat_dset = qset ;
247      }
248 
249 
250      nopt++;
251        continue;
252      }
253 
254       /*-----   -clip_low  -----*/
255       if (strncmp(argv[nopt], "-clip_low", 9) == 0)
256      {
257        nopt++;
258        if (nopt >= argc)  UN_error ("need value after -clip_low ");
259      /* compare with -1 noted by A Waite     29 Jul 2011 [rickr] */
260      if (option_data->lower_limit >= 0) {
261       UN_error ("lower clip value already set, check your options");
262      }
263      option_data->lower_limit = atoi(argv[nopt]); /* ZSS Sept 26 05 */
264        nopt++;
265        continue;
266      }
267 
268       /*-----   -clip_high  -----*/
269       if (strncmp(argv[nopt], "-clip_high", 9) == 0)
270      {
271        nopt++;
272        if (nopt >= argc)  UN_error ("need value after -clip_high ");
273      if (option_data->upper_limit) {
274       UN_error ("upper clip value already set, check your options");
275      }
276      option_data->upper_limit = atoi(argv[nopt]); /* ZSS Sept 26 05 */
277        nopt++;
278        continue;
279      }
280 
281    if (strncmp(argv[nopt], "-auto_clip", 8) == 0)
282      {
283      if (option_data->lower_limit >= 0) {
284       UN_error ("lower clip value already set, check your options");
285      }
286      option_data->lower_limit = -1; /* flag for auto_clip ZSS Sept 26 05 */
287        nopt++;
288        continue;
289      }
290 
291    if (strncmp(argv[nopt], "-niter", 6) == 0)
292      {
293      nopt++;
294        if (nopt >= argc)  UN_error ("need value after -niter ");
295      option_data->niter = atoi(argv[nopt]); /* flag for auto_clip ZSS Sept 26 05 */
296        nopt++;
297        continue;
298      }
299 
300       /*-----   -quiet  -----*/
301       if (strncmp(argv[nopt], "-quiet", 6) == 0)
302      {
303        option_data->quiet = TRUE;
304           quiet = 1 ;                /* 16 Apr 2003 */
305        nopt++;
306        continue;
307      }
308 
309 
310       /*-----   -prefix prefixname   -----*/
311       if (strncmp(argv[nopt], "-prefix", 7) == 0)
312      {
313        nopt++;
314        if (nopt >= argc)  UN_error ("need argument after -prefix ");
315        option_data->prefix_filename =
316          malloc (sizeof(char) * MAX_STRING_LENGTH);
317        MTEST (option_data->prefix_filename);
318        strcpy (option_data->prefix_filename, argv[nopt]);
319        nopt++;
320        continue;
321      }
322 
323 
324       /*----- unknown command -----*/
325       sprintf(message,"Unrecognized command line option: %s\n", argv[nopt]);
326       UN_error (message);
327 
328     }
329 
330    if (option_data->lower_limit < 0) { /* ZSS Sept 26 05 */
331       option_data->lower_limit = (int) THD_cliplevel( DSET_BRICK(anat_dset,0) , 0.0 ) ;
332       option_data->upper_limit = 3*option_data->lower_limit;
333       if (!quiet) {
334          printf ( "\n"
335                   "Lower limit set with THD_cliplevel at %d\n"
336                   "Upper limit set to %d\n", option_data->lower_limit, option_data->upper_limit);
337       }
338    } else if (option_data->lower_limit == 0) {
339       option_data->lower_limit = 25; /* The olde value */
340       if (!quiet) {
341          if (!option_data->upper_limit) {
342             printf ( "\n"
343                   "Lower limit set to historic default of %d\n"
344                   "No upper limit used.\n", option_data->lower_limit);
345          } else {
346             printf ( "\n"
347                   "Lower limit set to historic default of %d\n"
348                   "Upper limit set to %d.\n", option_data->lower_limit, option_data->upper_limit);
349          }
350          printf ( "\n"
351                "WARNING:\n"
352                "Using the default clip value of 25\n"
353                "might cause bad output depending\n"
354                "on the range of values in your input\n"
355                "dataset.\n"
356                "You are better off using -auto_clip\n"
357                "or -clip_low options instead.\n"
358                "\n" );
359       }
360    } else {
361       if (!quiet) {
362          if (option_data->upper_limit) {
363             printf ( "\n"
364                   "Lower limit set by user to %d\n"
365                   "Upper limit set to %d\n", option_data->lower_limit, option_data->upper_limit);
366          } else {
367             printf ( "\n"
368                   "Lower limit set by user to %d\n"
369                   "Upper limit not set.\n", option_data->lower_limit);
370          }
371       }
372    }
373 
374 
375 }
376 
377 
378 /*---------------------------------------------------------------------------*/
379 /*
380   Routine to check whether one output file already exists.
381 */
382 
check_one_output_file(char * filename)383 void check_one_output_file
384 (
385   char * filename                   /* name of output file */
386 )
387 
388 {
389   char message[MAX_STRING_LENGTH];    /* error message */
390   THD_3dim_dataset * new_dset=NULL;   /* output afni data set pointer */
391   int ierror;                         /* number of errors in editing data */
392 
393 
394   /*----- make an empty copy of input dataset -----*/
395   new_dset = EDIT_empty_copy ( anat_dset );
396 
397 
398   ierror = EDIT_dset_items( new_dset ,
399                    ADN_prefix , filename ,
400                    ADN_label1 , filename ,
401                    ADN_self_name , filename ,
402                    ADN_none ) ;
403 
404   if( ierror > 0 )
405     {
406       sprintf (message,
407             "*** %d errors in attempting to create output dataset!\n",
408             ierror);
409       UN_error (message);
410     }
411 
412   if( THD_deathcon() && THD_is_file(new_dset->dblk->diskptr->header_name) )
413     {
414       sprintf (message,
415             "Output dataset file %s already exists"
416             "--cannot continue!\a\n",
417             new_dset->dblk->diskptr->header_name);
418       UN_error (message);
419     }
420 
421   /*----- deallocate memory -----*/
422   THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ;
423 
424 }
425 
426 
427 /*---------------------------------------------------------------------------*/
428 
verify_inputs(UN_options * option_data)429 void verify_inputs
430 (
431   UN_options * option_data         /* uniformization program options */
432 )
433 
434 {
435   char *filename;
436   int ierror;
437 
438   filename = option_data->prefix_filename;
439   /*-- make an empty copy of this dataset, for eventual output --*/
440   option_data->new_dset =  EDIT_empty_copy( anat_dset ) ;
441 
442   /* check if output name is OK */
443   ierror = EDIT_dset_items( option_data->new_dset ,
444                    ADN_prefix , filename ,
445                    ADN_label1 , filename ,
446                    ADN_self_name , filename ,
447                    ADN_none ) ;
448   if( ierror > 0 ){
449     fprintf(stderr,
450          "*** %d errors in attempting to create output dataset!\n",
451          ierror ) ;
452     exit(1) ;
453   }
454 
455 
456   if( THD_deathcon() && THD_is_file(option_data->new_dset->dblk->diskptr->header_name) ){
457     fprintf(stderr,
458          "*** Output dataset file %s already exists--cannot continue!\a\n",
459          option_data->new_dset->dblk->diskptr->header_name ) ;
460     exit(1) ;
461   }
462 
463 
464 
465 }
466 
467 
468 /*---------------------------------------------------------------------------*/
469 /*
470   Program initialization.
471 */
472 
initialize_program(int argc,char ** argv,UN_options ** option_data,float ** ffim)473 void initialize_program
474 (
475   int argc,                        /* number of input arguments */
476   char ** argv,                    /* array of input arguments */
477   UN_options ** option_data,       /* uniformization program options */
478   float ** ffim                    /* output image volume */
479 )
480 
481 {
482   int nxyz;                        /* #voxels in input dataset */
483 
484 
485   /*----- Save command line for history notes -----*/
486   commandline = tross_commandline( PROGRAM_NAME , argc,argv ) ;
487 
488 
489   /*----- Allocate memory for input options -----*/
490   *option_data = (UN_options *) malloc (sizeof(UN_options));
491   MTEST (*option_data);
492 
493 
494   /*----- Initialize the input options -----*/
495   initialize_options (*option_data);
496 
497 
498   /*----- Get operator inputs -----*/
499   get_options (argc, argv, *option_data);
500 
501 
502   /*----- Verify that inputs are acceptable -----*/
503   verify_inputs (*option_data);
504 
505 
506   /*----- Initialize random number generator -----*/
507   rand_initialize (1234567);
508 
509 
510   /*----- Allocate memory for output volume -----*/
511   nxyz = DSET_NX(anat_dset) * DSET_NY(anat_dset) * DSET_NZ(anat_dset);
512   *ffim = (float *) calloc (nxyz, sizeof(float));
513   MTEST (*ffim);
514 }
515 
516 
517 /*---------------------------------------------------------------------------*/
518 /*
519   Write time series data to specified file.
520 */
521 
ts_write(char * filename,int ts_length,float * data)522 void ts_write (char * filename, int ts_length, float * data)
523 {
524   int it;
525   FILE * outfile = NULL;
526 
527   outfile = fopen (filename, "w");
528 
529 
530   for (it = 0;  it < ts_length;  it++)
531     {
532       fprintf (outfile, "%f ", data[it]);
533       fprintf (outfile, " \n");
534     }
535 
536   fclose (outfile);
537 }
538 
539 
540 /*---------------------------------------------------------------------------*/
541 /*
542   Resample the original image at randomly selected voxels (whose intensity
543   value is greater than the specified lower limit, to exclude voxels outside
544   the brain).  Take the logarithm of the intensity values for the selected
545   voxels.
546 */
547 
resample(UN_options * option_data,int * ir,float * vr)548 void resample
549 (
550   UN_options * option_data,
551   int * ir,                         /* voxel indices for resampled image */
552   float * vr                        /* resampled image data (logarithms) */
553 )
554 
555 {
556   float * anat_data = NULL;
557   int nxyz;
558   int rpts;
559   int lower_limit;
560   int it, k;
561 
562 
563   /*----- Initialize local variables -----*/
564   nxyz = DSET_NX(anat_dset) * DSET_NY(anat_dset) * DSET_NZ(anat_dset);
565   anat_data = (float *) DSET_BRICK_ARRAY(anat_dset,0);
566   lower_limit = option_data->lower_limit;
567   rpts = option_data->rpts;
568 
569   it = 0;
570   while (it < rpts)
571     {
572       k = rand_uniform (0, nxyz);
573       /* okay if no upper_limit, or data < upper_limit   16 Dec 2005 [rickr] */
574       if ( (k >= 0) && (k < nxyz) && (anat_data[k] > lower_limit) &&
575            ( ! option_data->upper_limit ||
576                (anat_data[k] < option_data->upper_limit) ) )
577      {
578        ir[it] = k;
579        vr[it] = log (anat_data[k] + rand_uniform (0.0,1.0));
580        it++;
581      }
582     }
583 
584   return;
585 }
586 
587 
588 /*---------------------------------------------------------------------------*/
589 /*
590   Create intensity map that will tend to concentrate values around the
591   means of the gray and white matter distributions.
592 */
593 
create_map(pdf vpdf,float * pars,float * vtou)594 void create_map (pdf vpdf, float * pars, float * vtou)
595 
596 {
597   int ibin;
598   float v;
599 
600   for (ibin = 0;  ibin < vpdf.nbin;  ibin++)
601     {
602       v = PDF_ibin_to_xvalue (vpdf, ibin);
603 
604       if ((v > pars[4]-2.0*pars[5]) && (v < 0.5*(pars[4]+pars[7])))
605      vtou[ibin] = pars[4];
606       else if ((v > 0.5*(pars[4]+pars[7])) && (v < pars[7]+2.0*pars[8]))
607      vtou[ibin] = pars[7];
608       else
609      vtou[ibin] = v;
610 
611     }
612 
613 }
614 
615 
616 /*---------------------------------------------------------------------------*/
617 /*
618   Use the intensity map to transform values of voxel intensities.
619 */
620 
map_vtou(pdf vpdf,int rpts,float * vr,float * vtou,float * ur)621 void map_vtou (pdf vpdf, int rpts, float * vr, float * vtou, float * ur)
622 
623 {
624   int i, ibin;
625   float v;
626 
627 
628   for (i = 0;  i < rpts;  i++)
629     {
630       v = vr[i];
631       ibin = PDF_xvalue_to_ibin (vpdf, v);
632 
633       if ((ibin >= 0) && (ibin < vpdf.nbin))
634      ur[i] = vtou[ibin];
635       else
636      ur[i] = v;
637     }
638 
639 }
640 
641 
642 /*---------------------------------------------------------------------------*/
643 
subtract(int rpts,float * a,float * b,float * c)644 void subtract (int rpts, float * a, float * b, float * c)
645 
646 {
647   int i;
648 
649 
650   for (i = 0;  i < rpts;  i++)
651     {
652       c[i] = a[i] - b[i];
653     }
654 
655 }
656 
657 
658 /*---------------------------------------------------------------------------*/
659 /*
660   Create one row of the X matrix.
661 */
662 
create_row(int ixyz,int nx,int ny,int nz,float * xrow)663 void create_row (int ixyz, int nx, int ny, int nz, float * xrow)
664 
665 {
666   int ix, jy, kz;
667   float x, y, z, x2, y2, z2, x3, y3, z3, x4, y4, z4;
668 
669 
670   IJK_TO_THREE (ixyz, ix, jy, kz, nx, nx*ny);
671 
672 
673   x = (float) ix / (float) nx - 0.5;
674   y = (float) jy / (float) ny - 0.5;
675   z = (float) kz / (float) nz - 0.5;
676 
677   x2 = x*x;   x3 = x*x2;   x4 = x2*x2;
678   y2 = y*y;   y3 = y*y2;   y4 = y2*y2;
679   z2 = z*z;   z3 = z*z2;   z4 = z2*z2;
680 
681 
682   xrow[0] = 1.0;
683   xrow[1] = x;
684   xrow[2] = y;
685   xrow[3] = z;
686   xrow[4] = x*y;
687   xrow[5] = x*z;
688   xrow[6] = y*z;
689   xrow[7] = x2;
690   xrow[8] = y2;
691   xrow[9] = z2;
692   xrow[10] = x*y*z;
693   xrow[11] = x2*y;
694   xrow[12] = x2*z;
695   xrow[13] = y2*x;
696   xrow[14] = y2*z;
697   xrow[15] = z2*x;
698   xrow[16] = z2*y;
699   xrow[17] = x3;
700   xrow[18] = y3;
701   xrow[19] = z3;
702   xrow[20] = x2*y*z;
703   xrow[21] = x*y2*z;
704   xrow[22] = x*y*z2;
705   xrow[23] = x2*y2;
706   xrow[24] = x2*z2;
707   xrow[25] = y2*z2;
708   xrow[26] = x3*y;
709   xrow[27] = x3*z;
710   xrow[28] = x*y3;
711   xrow[29] = y3*z;
712   xrow[30] = x*z3;
713   xrow[31] = y*z3;
714   xrow[32] = x4;
715   xrow[33] = y4;
716   xrow[34] = z4;
717 
718 
719   return;
720 }
721 
722 
723 /*---------------------------------------------------------------------------*/
724 /*
725   Approximate the distortion field with a polynomial function in 3 dimensions.
726 */
727 
poly_field(int nx,int ny,int nz,int rpts,int * ir,float * fr,int spts,int npar,float * fpar)728 void poly_field (int nx, int ny, int nz, int rpts, int * ir, float * fr,
729            int spts, int npar, float * fpar)
730 
731 {
732   int p;                   /* number of parameters in the full model */
733   int i, j, k;
734   matrix x;                      /* independent variable matrix */
735   matrix xtxinv;                 /* matrix:  1/(X'X)       */
736   matrix xtxinvxt;               /* matrix:  (1/(X'X))X'   */
737   vector y;
738   vector coef;
739   float * xrow = NULL;
740   int ip;
741   int iter;
742   float f;
743 
744 
745   p = npar;
746 
747 
748   /*----- Initialize matrices and vectors -----*/
749   matrix_initialize (&x);
750   matrix_initialize (&xtxinv);
751   matrix_initialize (&xtxinvxt);
752   vector_initialize (&y);
753   vector_initialize (&coef);
754 
755 
756   /*----- Allocate memory -----*/
757   matrix_create (spts, p, &x);
758   vector_create (spts, &y);
759   xrow = (float *) malloc (sizeof(float) * p);
760 
761 
762   /*----- Set up the X matrix and Y vector -----*/
763   for (i = 0;  i < spts;  i++)
764     {
765       k = rand_uniform (0, rpts);
766       create_row (ir[k], nx, ny, nz, xrow);
767 
768       for (j = 0;  j < p;  j++)
769      x.elts[i][j] = xrow[j];
770       y.elts[i] = fr[k];
771     }
772 
773 
774   /*
775       matrix_sprint ("X matrix = ", x);
776       vector_sprint ("Y vector = ", y);
777   */
778 
779 
780   {
781     /*----- calculate various matrices which will be needed later -----*/
782     matrix xt, xtx;            /* temporary matrix calculation results */
783     int ok;                    /* flag for successful matrix inversion */
784 
785 
786     /*----- initialize matrices -----*/
787     matrix_initialize (&xt);
788     matrix_initialize (&xtx);
789 
790     matrix_transpose (x, &xt);
791     matrix_multiply (xt, x, &xtx);
792     ok = matrix_inverse (xtx, &xtxinv);
793 
794     if (ok)
795       matrix_multiply (xtxinv, xt, &xtxinvxt);
796     else
797       {
798      matrix_sprint ("X matrix = ", x);
799      matrix_sprint ("X'X matrix = ", xtx);
800      UN_error ("Improper X matrix  (cannot invert X'X) ");
801       }
802 
803     /*----- dispose of matrices -----*/
804     matrix_destroy (&xtx);
805     matrix_destroy (&xt);
806 
807   }
808 
809 
810   /*
811     matrix_sprint ("1/(X'X)     = ", xtxinv);
812     matrix_sprint ("(1/(X'X))X' = ", xtxinvxt);
813     vector_sprint ("Y data  = ", y);
814   */
815 
816   vector_multiply (xtxinvxt, y, &coef);
817   /*
818     vector_sprint ("Coef    = ", coef);
819   */
820 
821 
822   for (ip = 0;  ip < p;  ip++)
823     {
824      fpar[ip] = coef.elts[ip];
825     }
826 
827 
828   /*----- Dispose of matrices and vectors -----*/
829   matrix_destroy (&x);
830   matrix_destroy (&xtxinv);
831   matrix_destroy (&xtxinvxt);
832   vector_destroy (&y);
833   vector_destroy (&coef);
834 
835 
836 }
837 
838 
839 /*---------------------------------------------------------------------------*/
840 /*
841   Use the 3-dimensional polynomial function to estimate the distortion field
842   at each point.
843 */
844 
warp_image(int npar,float * fpar,int nx,int ny,int nz,int rpts,int * ir,float * fs)845 float warp_image (int npar, float * fpar, int nx, int ny, int nz,
846             int rpts, int * ir, float * fs)
847 {
848   int i, j;
849   float x;
850   float * xrow;
851   float max_warp;
852 
853 
854   xrow = (float *) malloc (sizeof(float) * npar);
855 
856 
857   max_warp = 0.0;
858 
859   for (i = 0;  i < rpts;  i++)
860     {
861       create_row (ir[i], nx, ny, nz, xrow);
862 
863       fs[i] = 0.0;
864 
865       for (j = 1;  j < npar;  j++)
866      fs[i] += fpar[j] * xrow[j];
867 
868       if (fabs(fs[i]) > max_warp)
869      max_warp = fabs(fs[i]);
870     }
871 
872 
873   free (xrow);   xrow = NULL;
874 
875 
876   return (max_warp);
877 }
878 
879 
880 /*---------------------------------------------------------------------------*/
881 /*
882   Find polynomial approximation to the distortion field.
883 */
884 
estimate_field(UN_options * option_data,int * ir,float * vr,float * fpar)885 void estimate_field (UN_options * option_data,
886                int * ir, float * vr, float * fpar)
887 {
888   float * ur = NULL, * us = NULL, * fr = NULL, * fs = NULL, * wr = NULL;
889   float * vtou = NULL;
890   float * gpar;
891   int iter = 0, itermax=5;
892   int ip;
893   int it;
894   int nx, ny, nz, nxy, nxyz;
895   int rpts, spts, nbin, npar;
896   float parameters [DIMENSION];    /* parameters for PDF estimation */
897   char filename[MAX_STRING_LENGTH];
898 
899 
900   /*----- Initialize local variables -----*/
901   nx = DSET_NX(anat_dset);  ny = DSET_NY(anat_dset);  nz = DSET_NZ(anat_dset);
902   nxy = nx*ny;   nxyz = nxy*nz;
903   rpts = option_data->rpts;
904   spts = option_data->spts;
905   nbin = option_data->nbin;
906   npar = option_data->npar;
907   itermax = option_data->niter;
908 
909 
910   /*----- Allocate memory -----*/
911   ur   = (float *) malloc (sizeof(float) * rpts);   MTEST (ur);
912   us   = (float *) malloc (sizeof(float) * rpts);   MTEST (us);
913   fr   = (float *) malloc (sizeof(float) * rpts);   MTEST (fr);
914   fs   = (float *) malloc (sizeof(float) * rpts);   MTEST (fs);
915   wr   = (float *) malloc (sizeof(float) * rpts);   MTEST (wr);
916   gpar = (float *) malloc (sizeof(float) * npar);   MTEST (gpar);
917   vtou = (float *) malloc (sizeof(float) * nbin);   MTEST (vtou);
918 
919 
920   /*----- Initialize polynomial coefficients -----*/
921   for (ip = 0;  ip < npar;  ip++)
922     {
923       fpar[ip] = 0.0;
924       gpar[ip] = 0.0;
925     }
926 
927 
928   /*----- Estimate pdf for resampled data -----*/
929   if( 0 && !quiet ){
930    fprintf (stderr,"       PDF_Initializing... \n");
931   }
932   PDF_initialize (&p);
933   if( 0 && !quiet ){
934    fprintf (stderr,"       float to pdf... \n");
935   }
936   PDF_float_to_pdf (rpts, vr, nbin, &p);
937 
938   if( !quiet ){
939    sprintf (filename, "p%d.1D", iter);
940    fprintf (stderr,"       Writing pdf output to %s... \n", filename);
941    PDF_write_file (filename, p);
942   }
943 
944 
945   /*----- Estimate gross field distortion -----*/
946   if( 0 && !quiet ){
947    fprintf (stderr,"       Estimating gross distortions... \n");
948   }
949   poly_field (nx, ny, nz, rpts, ir, vr, spts, npar, fpar);
950   warp_image (npar, fpar, nx, ny, nz, rpts, ir, fs);
951   subtract (rpts, vr, fs, ur);
952 
953 
954   for (ip = 0;  ip < rpts;  ip++)
955     vr[ip] = ur[ip];
956 
957 
958   /*----- Iterate over field distortion for concentrating the PDF -----*/
959   for (iter = 1;  iter <= itermax;  iter++)
960     {
961       /*----- Estimate pdf for perturbed image ur -----*/
962       estpdf_float (rpts, ur, nbin, parameters);
963       PDF_sprint ("p", p);
964       if( !quiet ){
965        sprintf (filename, "p%d.1D", iter);
966        PDF_write_file (filename, p);
967       }
968 
969       /*----- Sharpen the pdf and produce modified image wr -----*/
970       create_map (p, parameters, vtou);
971       if( !quiet ){
972        sprintf (filename, "vtou%d.1D", iter);
973        ts_write (filename, p.nbin, vtou);
974       }
975       map_vtou (p, rpts, ur, vtou, wr);
976 
977       /*----- Estimate smooth distortion field fs -----*/
978       subtract (rpts, vr, wr, fr);
979       poly_field (nx, ny, nz, rpts, ir, fr, spts, npar, gpar);
980       warp_image (npar, gpar, nx, ny, nz, rpts, ir, fs);
981 
982       /*----- Create perturbed image ur -----*/
983       subtract (rpts, vr, fs, ur);
984     }
985 
986 
987   /*----- Accumulate distortion field polynomial coefficients -----*/
988   for (ip = 0;  ip < npar;  ip++)
989     fpar[ip] += gpar[ip];
990 
991 
992   /*----- Deallocate memory -----*/
993   free (ur);     ur = NULL;
994   free (us);     us = NULL;
995   free (fr);     fr = NULL;
996   free (fs);     fs = NULL;
997   free (wr);     wr = NULL;
998   free (gpar);   gpar = NULL;
999   free (vtou);   vtou = NULL;
1000 
1001 
1002   return;
1003 }
1004 
1005 
1006 /*---------------------------------------------------------------------------*/
1007 /*
1008   Remove the nonuniformity field.
1009 */
1010 
remove_field(UN_options * option_data,float * fpar,float * ffim)1011 void remove_field (UN_options * option_data, float * fpar, float * ffim)
1012 {
1013   float * anat_data = NULL;
1014   int rpts;
1015   int npar;
1016   int lower_limit;
1017   int nx, ny, nz, nxyz;
1018   int ixyz, jpar;
1019   float x;
1020   float * xrow;
1021   float f;
1022 
1023 
1024   /*----- Initialize local variables -----*/
1025   nx = DSET_NX(anat_dset);  ny = DSET_NY(anat_dset);  nz = DSET_NZ(anat_dset);
1026   nxyz = nx*ny*nz;
1027   anat_data = (float *) DSET_BRICK_ARRAY(anat_dset,0);
1028   rpts = option_data->rpts;
1029   npar = option_data->npar;
1030   lower_limit = option_data->lower_limit;
1031 
1032   xrow = (float *) malloc (sizeof(float) * npar);
1033 
1034 
1035   for (ixyz = 0;  ixyz < nxyz;  ixyz++)
1036     {
1037         {
1038           create_row (ixyz, nx, ny, nz, xrow);
1039 
1040           f = 0.0;
1041           for (jpar = 1;  jpar < npar;  jpar++)
1042             f += fpar[jpar] * xrow[jpar];
1043 
1044           ffim[ixyz] = exp( log(anat_data[ixyz]) - f);
1045         }
1046 
1047     }
1048 
1049 
1050   return;
1051 }
1052 
1053 
1054 /*---------------------------------------------------------------------------*/
1055 /*
1056   Correct for image intensity nonuniformity.
1057 */
1058 
uniformize(UN_options * option_data,float * ffim)1059 void uniformize (UN_options * option_data, float * ffim)
1060 
1061 {
1062   int * ir = NULL;
1063   float * vr = NULL;
1064   float * fpar = NULL;
1065   int rpts, npar;
1066 
1067 
1068   /*----- Initialize local variables -----*/
1069   rpts = option_data->rpts;
1070   npar = option_data->npar;
1071 
1072 
1073   /*----- Allocate memory -----*/
1074   ir = (int *) malloc (sizeof(int) * rpts);         MTEST(ir);
1075   vr = (float *) malloc (sizeof(float) * rpts);     MTEST(vr);
1076   fpar = (float *) malloc (sizeof(float) * npar);   MTEST(fpar);
1077 
1078 
1079   /*----- Resample the data -----*/
1080   if( 0 && !quiet ){
1081    fprintf (stderr,"     resampling... \n");
1082   }
1083   resample (option_data, ir, vr);
1084 
1085 
1086   /*----- Estimate the nonuniformity field -----*/
1087   if( 0 && !quiet ){
1088    fprintf (stderr,"     estimating field... \n");
1089   }
1090   estimate_field (option_data, ir, vr, fpar);
1091 
1092 
1093   /*----- Remove the nonuniformity field -----*/
1094   if( 0 && !quiet ){
1095    fprintf (stderr,"     removing field... \n");
1096   }
1097 
1098 
1099   remove_field (option_data, fpar, ffim);
1100 
1101 
1102   /*----- Deallocate memory -----*/
1103   free (ir);     ir = NULL;
1104   free (vr);     vr = NULL;
1105   free (fpar);   fpar = NULL;
1106 
1107 }
1108 
1109 
1110 /*---------------------------------------------------------------------------*/
1111 /*
1112   Routine to write one AFNI dataset.
1113 
1114 
1115 */
1116 
write_afni_data(UN_options * option_data,float * ffim)1117 void write_afni_data
1118 (
1119   UN_options * option_data,
1120   float * ffim
1121 )
1122 
1123 {
1124   int nxyz;                           /* number of voxels */
1125   int ii;                             /* voxel index */
1126   int ierror;                         /* number of errors in editing data */
1127   int ibuf[32];                       /* integer buffer */
1128   float fbuf[MAX_STAT_AUX];           /* float buffer */
1129   int output_datum;                   /* data type for output data */
1130   char * filename;                    /* prefix filename for output */
1131   byte *bfim = NULL ;                 /* 16 Apr 2003 */
1132 
1133   /*----- initialize local variables -----*/
1134   nxyz = DSET_NX(anat_dset) * DSET_NY(anat_dset) * DSET_NZ(anat_dset);
1135 
1136 
1137   /*----- Record history of dataset -----*/
1138   tross_Copy_History( anat_dset , option_data->new_dset ) ;
1139   if( commandline != NULL )
1140      tross_Append_History( option_data->new_dset , commandline ) ;
1141 
1142 
1143   /*----- deallocate memory -----*/
1144   THD_delete_3dim_dataset (anat_dset, False);   anat_dset = NULL ;
1145 
1146   output_datum = input_datum ;
1147 
1148 
1149   /*-- we now return control to your regular programming --*/
1150   ibuf[0] = output_datum ;
1151 
1152   ierror = EDIT_dset_items( option_data->new_dset ,
1153                    ADN_datum_array , ibuf ,
1154                    ADN_malloc_type, DATABLOCK_MEM_MALLOC ,
1155                    ADN_none ) ;
1156 
1157 
1158   if( ierror > 0 ){
1159     fprintf(stderr,
1160          "*** %d errors in attempting to create output dataset!\n",
1161          ierror ) ;
1162     exit(1) ;
1163   }
1164 
1165 
1166   if( THD_is_file(option_data->new_dset->dblk->diskptr->header_name) ){
1167     fprintf(stderr,
1168          "*** Output dataset file %s already exists--cannot continue!\a\n",
1169          option_data->new_dset->dblk->diskptr->header_name ) ;
1170     exit(1) ;
1171   }
1172 
1173 
1174   EDIT_substscale_brick(option_data->new_dset,0,
1175                         MRI_float,ffim , output_datum, -1.0 );
1176 
1177   THD_load_statistics( option_data->new_dset ) ;
1178   THD_write_3dim_dataset( NULL,NULL , option_data->new_dset , True ) ;
1179 
1180 
1181   /*----- deallocate memory -----*/
1182   THD_delete_3dim_dataset( option_data->new_dset , False ) ; option_data->new_dset = NULL ;
1183 
1184 }
1185 
1186 
1187 /*---------------------------------------------------------------------------*/
1188 /*
1189   This is the main routine for program 3dUniformize.
1190 */
1191 
main(int argc,char ** argv)1192 int main
1193 (
1194   int argc,                /* number of input arguments */
1195   char ** argv             /* array of input arguments */
1196 )
1197 
1198 {
1199   UN_options * option_data = NULL;     /* uniformization program options */
1200   float * ffim = NULL;                 /* output uniformized image */
1201 
1202 
1203   { int ii ;                           /* 16 Apr 2003 */
1204     for( ii=1 ; ii < argc ; ii++ ){
1205       if( strcmp(argv[ii],"-quiet") == 0 ){ quiet = 1; break; }
1206     }
1207   }
1208 
1209   /*----- Identify software -----*/
1210 #if 0
1211   if( !quiet ){
1212    printf ("\n\n");
1213    printf ("Program: %s \n", PROGRAM_NAME);
1214    printf ("Author:  %s \n", PROGRAM_AUTHOR);
1215    printf ("Initial Release:  %s \n", PROGRAM_INITIAL);
1216    printf ("Latest Revision:  %s \n", PROGRAM_LATEST);
1217    printf ("\n");
1218   }
1219 #endif
1220 
1221    PRINT_VERSION("3dUniformize") ; AUTHOR(PROGRAM_AUTHOR);
1222    mainENTRY("3dUniformize main") ; machdep() ;
1223 
1224 
1225   /*----- Program initialization -----*/
1226   if( !quiet ){
1227    fprintf (stderr,"  Initializing... \n");
1228   }
1229   initialize_program (argc, argv, &option_data, &ffim);
1230 
1231   WARNING_message(" ") ;
1232   WARNING_message("Please use 3dUnifize instead of 3dUniformize!") ;
1233   WARNING_message(" ") ;
1234 
1235 
1236   /*----- Perform uniformization -----*/
1237 
1238   if( !quiet ){
1239    fprintf (stderr,"  Uniformizing... \n");
1240   }
1241   uniformize (option_data, ffim);
1242 
1243 
1244   /*----- Write out the results -----*/
1245   if( !quiet ){
1246    fprintf (stderr,"  Writing results... \n");
1247   }
1248   write_afni_data (option_data, ffim);
1249 
1250 
1251   exit(0);
1252 
1253 }
1254 
1255 /*---------------------------------------------------------------------------*/
1256 
1257 
1258 
1259 
1260 
1261 
1262