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