CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
castor-mergeBedPositions.cc
Go to the documentation of this file.
1 
9 #include "gVariables.hh"
10 #include "gOptions.hh"
11 #include "oIterativeAlgorithm.hh"
12 #include "oSensitivityGenerator.hh"
14 #include "iDataFilePET.hh"
15 #include "iDataFileSPECT.hh"
16 #include "sOutputManager.hh"
17 #include "sScannerManager.hh"
19 #include "iScannerPET.hh"
20 #include "sAddonManager.hh"
21 
22 // =============================================================================================================================================
23 // =============================================================================================================================================
24 // =============================================================================================================================================
25 // H E L P F U N C T I O N S
26 // =============================================================================================================================================
27 // =============================================================================================================================================
28 // =============================================================================================================================================
29 
30 
35 void ShowHelp()
36 {
37  // Show help
38  cout << endl;
39  cout << "Usage: castor-mergeBedPositions -img image1.hdr -img image2.hdr -(f/d)out output [settings]" << endl;
40  cout << endl;
41  cout << "This program can be used to merge several images corresponding to multiple bed positions of the same acquisition. The slices of any image" << endl;
42  cout << "are weighted during merging. By default, these weights are uniform (1 for all slices of all images). The -sens option can be used to provide" << endl;
43  cout << "a sensitivity image for each image to be merged, where the voxels' value of the sensitivity images are used as weights." << endl;
44  cout << "The bed displacement between two successive bed positions is recovered from the image headers as 'multiple bed displacement'." << endl;
45  cout << "If not found, the default one from the scanner is used." << endl;
46  cout << "Important note: this program assumes the provided images exactly match the axial FOV of the scanner; if bigger or smaller results will be wrong." << endl;
47  cout << endl;
48  cout << "[Mandatory parameters]:" << endl;
49  cout << " -img imageX.hdr : Give an image corresponding to a bed position (must give at least two images; the provided order defines the order" << endl;
50  cout << " in which bed positions are merged)" << endl;
51  cout << " -fout name : Give the root name for all output files (no default, alternative to -dout)" << endl;
52  cout << " -dout name : Give the name of the output directory where all output files will be written (no default, alternative to -fout)" << endl;
53  cout << endl;
54  cout << "[Options]:" << endl;
55  cout << " -sens sensX.hdr : Give the sensitivity image to weight the imageX.hdr while merging the bed positions (must provide as many sensitivity" << endl;
56  cout << " images as images to be merged; the association of sensitivity images to the images is done with respect to the order" << endl;
57  cout << " both images are provided)" << endl;
58  cout << " -oweight : Also save the global weights" << endl;
59  cout << " -inv : Virtually inverse the order of the provided images (and sensitivity images)" << endl;
60  cout << " -vb : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
61  cout << " -conf : Give the path to the CASToR config directory (default: located through the CASTOR_CONFIG environment variable)." << endl;
62  cout << " --help,-h,-help : Print out this help page." << endl; // managed by main
63  cout << endl;
64  #ifdef BUILD_DATE
65  cout << " Build date: " << BUILD_DATE << endl;
66  cout << endl;
67  #endif
68  #ifdef CASTOR_VERSION
69  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
70  cout << endl;
71  #endif
72 }
73 
74 // =============================================================================================================================================
75 // =============================================================================================================================================
76 // =============================================================================================================================================
77 // M A I N P R O G R A M
78 // =============================================================================================================================================
79 // =============================================================================================================================================
80 // =============================================================================================================================================
81 
82 int main(int argc, char** argv)
83 {
84  // ============================================================================================================
85  // MPI stuff (we make all instances except the first one returning 0 directly)
86  // ============================================================================================================
87  int mpi_rank = 0;
88  #ifdef CASTOR_MPI
89  int mpi_size = 1;
90  MPI_Init(&argc, &argv);
91  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
92  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
93  if (mpi_rank!=0) return 0;
94  #endif
95 
96  // No argument, then show help
97  if (argc==1)
98  {
99  ShowHelp();
100  Exit(EXIT_SUCCESS);
101  }
102 
103  // ============================================================================================================
104  // Parameterized variables with their default values
105  // ============================================================================================================
106 
107  // --------------------------------------------------------------------------------
108  // Input settings
109  // --------------------------------------------------------------------------------
110 
111  // Number of bed position
112  uint32_t nb_beds = 0;
113  // Vector containing string pointing to the images to be merged
114  vector<string> path_to_image_filename;
115  // Vector containing string pointing to the sensitivity images used as weights
116  vector<string> path_to_sens_filename;
117  // Invert bed datafile names order
118  bool invert_order_flag = false;
119 
120  // --------------------------------------------------------------------------------
121  // Output settings
122  // --------------------------------------------------------------------------------
123 
124  // Output directory name.
125  string path_dout = "";
126  // Or root name
127  string path_fout = "";
128  // Save global weight
129  bool save_weights = false;
130 
131  // --------------------------------------------------------------------------------
132  // Miscellaneous settings
133  // --------------------------------------------------------------------------------
134 
135  // Verbose level
136  int verbose = 1;
137  // Path to config directory
138  string path_to_config_dir = "";
139 
140  // ============================================================================================================
141  // Read command-line parameters
142  // ============================================================================================================
143 
144  // Must manually increment the option index when an argument is needed after an option
145  for (int i=1; i<argc; i++)
146  {
147  // Get the option as a string
148  string option = (string)argv[i];
149 
150  // --------------------------------------------------------------------------------
151  // Miscellaneous settings
152  // --------------------------------------------------------------------------------
153 
154  // Show help
155  if (option=="-h" || option=="--help" || option=="-help")
156  {
157  ShowHelp();
158  Exit(EXIT_SUCCESS);
159  }
160  // General verbosity level
161  else if (option=="-vb")
162  {
163  if (i>=argc-1)
164  {
165  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
166  Exit(EXIT_FAILURE);
167  }
168  if (ConvertFromString(argv[i+1], &verbose))
169  {
170  Cerr("***** castor-mergeBedPositions() -> Exception when trying to read provided verbosity level '" << verbose << " for option: " << option << endl);
171  Exit(EXIT_FAILURE);
172  }
173  i++;
174  }
175  // Path to config directory
176  else if (option=="-conf")
177  {
178  if (i>=argc-1)
179  {
180  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
181  Exit(EXIT_FAILURE);
182  }
183  path_to_config_dir = (string)argv[i+1];
184  i++;
185  }
186 
187  // --------------------------------------------------------------------------------
188  // Input settings
189  // --------------------------------------------------------------------------------
190 
191  // Images
192  else if (option=="-img") // This is a mandatory option
193  {
194  if (i>=argc-1)
195  {
196  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
197  Exit(EXIT_FAILURE);
198  }
199  string file_name = (string)argv[i+1];
200  path_to_image_filename.push_back(file_name);
201  nb_beds++;
202  i++;
203  }
204  // Sensitivity images
205  else if (option=="-sens")
206  {
207  if (i>=argc-1)
208  {
209  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
210  Exit(EXIT_FAILURE);
211  }
212  string file_name = (string)argv[i+1];
213  path_to_sens_filename.push_back(file_name);
214  i++;
215  }
216  // Invert bed positions order
217  else if (option=="-inv")
218  {
219  invert_order_flag = true;
220  }
221 
222  // --------------------------------------------------------------------------------
223  // Output settings
224  // --------------------------------------------------------------------------------
225 
226  // Name of the output directory
227  else if (option=="-dout") // This is a mandatory option
228  {
229  if (i>=argc-1)
230  {
231  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
232  Exit(EXIT_FAILURE);
233  }
234  path_dout = argv[i+1];
235  i++;
236  }
237  // Base name of the output files
238  else if (option=="-fout") // This is a mandatory option
239  {
240  if (i>=argc-1)
241  {
242  Cerr("***** castor-mergeBedPositions() -> Argument missing for option: " << option << endl);
243  Exit(EXIT_FAILURE);
244  }
245  path_fout = argv[i+1];
246  i++;
247  }
248  // Save global weights
249  else if (option=="-oweight")
250  {
251  save_weights = true;
252  }
253 
254  // --------------------------------------------------------------------------------
255  // Unknown option!
256  // --------------------------------------------------------------------------------
257 
258  else
259  {
260  Cerr("***** castor-mergeBedPositions() -> Unknown option '" << option << "' !" << endl);
261  Exit(EXIT_FAILURE);
262  }
263  }
264 
265  // ============================================================================================================
266  // Some checks
267  // ============================================================================================================
268 
269  // Data files
270  if (nb_beds < 2)
271  {
272  Cerr("***** castor-mergeBedPositions() -> Please provide at least two image filename !" << endl);
273  Exit(EXIT_FAILURE);
274  }
275  // Output files
276  if (path_fout.empty() && path_dout.empty())
277  {
278  Cerr("***** castor-mergeBedPositions() -> Please provide an output option for output files (-fout or -dout) !" << endl);
279  Exit(EXIT_FAILURE);
280  }
281  // Check that only one option has been provided
282  if (!path_fout.empty() && !path_dout.empty())
283  {
284  Cerr("***** castor-mergeBedPositions() -> Please provide either output option -fout or -dout but not both !" << endl);
285  Exit(EXIT_FAILURE);
286  }
287  // If sensitivity is provided, then check that there are as many files as input images
288  if (path_to_sens_filename.size()>0 && path_to_sens_filename.size()!=path_to_image_filename.size())
289  {
290  Cerr("***** castor-mergeBedPositions() -> If using sensitivity images as weights, please provide as many sensitivity images as input images !" << endl);
291  Exit(EXIT_FAILURE);
292  }
293 
294  // ============================================================================================================
295  // Create sOutputManager
296  // ============================================================================================================
297  sOutputManager* p_OutputManager = sOutputManager::GetInstance();
298  // Set verbose level
299  p_OutputManager->SetVerbose(verbose);
300  // Set MPI rank
301  p_OutputManager->SetMPIRank(mpi_rank);
302  // Set path to the config directory
303  if (p_OutputManager->CheckConfigDir(path_to_config_dir))
304  {
305  Cerr("***** castor-mergeBedPositions() -> A problem occured while checking for the config directory path !" << endl);
306  Exit(EXIT_FAILURE);
307  }
308  // Initialize output directory and base name
309  if (p_OutputManager->InitOutputDirectory(path_fout, path_dout))
310  {
311  Cerr("***** castor-mergeBedPositions() -> A problem occured while initializing output directory !" << endl);
312  Exit(EXIT_FAILURE);
313  }
314  // Log command line
315  if (p_OutputManager->LogCommandLine(argc,argv))
316  {
317  Cerr("***** castor-mergeBedPositions() -> A problem occured while logging command line arguments !" << endl);
318  Exit(EXIT_FAILURE);
319  }
320 
321  // ============================================================================================================
322  // Create sScannerManager
323  // ============================================================================================================
324  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
325  p_ScannerManager->SetVerbose(verbose);
326 
327  // ============================================================================================================
328  // Read all input images
329  // ============================================================================================================
330 
331  // Verbose
332  if (verbose>=1) Cout("castor-mergeBedPositions() -> Load input images" << endl);
333 
334  // Get user endianness (interfile I/O)
336 
337  // Create interfile image fields and image pointers
338  Intf_fields** p_image_fields = (Intf_fields**)malloc(nb_beds*sizeof(Intf_fields*));
339  FLTNB** p_images = (FLTNB**)malloc(nb_beds*sizeof(FLTNB*));
340 
341  // Read interfile images
342  for (uint32_t bed=0; bed<nb_beds; bed++)
343  {
344  // Create the image fields
345  p_image_fields[bed] = new Intf_fields;
346  // Read the image
347  if (invert_order_flag) p_images[bed] = IntfLoadImageFromScratch(path_to_image_filename[nb_beds-1-bed],p_image_fields[bed],verbose);
348  else p_images[bed] = IntfLoadImageFromScratch(path_to_image_filename[bed],p_image_fields[bed],verbose);
349  // Check reading
350  if (p_images[bed]==NULL)
351  {
352  Cerr("***** castor-mergeBedPositions() -> A problem occured while reading image for bed " << bed+1 << " !" << endl);
353  return 1;
354  }
355  }
356 
357  // Check dimensions consistency between all image fields, as well as originating system and bed displacement
358  for (uint32_t bed=1; bed<nb_beds; bed++)
359  {
360  if (IntfCheckDimensionsConsistency(*p_image_fields[0],*p_image_fields[bed]))
361  {
362  Cerr("***** castor-mergeBedPositions() -> Inconsistency between image dimensions !" << endl);
363  Exit(EXIT_FAILURE);
364  }
365  }
366 
367  // Get dimensions locally
368  uint32_t dim_x = p_image_fields[0]->mtx_size[0];
369  uint32_t dim_y = p_image_fields[0]->mtx_size[1];
370  uint32_t dim_z = p_image_fields[0]->mtx_size[2];
371  uint32_t dim_xyz = dim_x * dim_y * dim_z;
372 
373  // ============================================================================================================
374  // Recover the bed displacement if not present in the image headers
375  // ============================================================================================================
376 
377  // The bed displacement
378  FLTNB multiple_bed_displacement = p_image_fields[0]->multiple_bed_displacement;
379 
380  // If not found in the interfile header, then try into the scanner configuration file
381  if (multiple_bed_displacement<=0.)
382  {
383  // Verbose
384  if (verbose>=1) Cout("castor-mergeBedPositions() -> Bed displacement not found in image headers, search for it in the scanner configuration file" << endl);
385  // Find scanner configuration file
386  if (p_ScannerManager->FindScannerSystem(p_image_fields[0]->originating_system) )
387  {
388  Cerr("***** castor-mergeBedPositions() -> A problem occurred while searching for scanner system !" << endl);
389  Exit(EXIT_FAILURE);
390  }
391  // Get the bed displacement from the scanner configuration file
392  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "multiple bed displacement", &multiple_bed_displacement, 1, KEYWORD_MANDATORY))
393  {
394  Cerr("***** castor-mergeBedPositions() -> Multiple bed displacement field not found in the scanner configuration file '" <<
395  p_ScannerManager->GetPathToScannerFile() << " !" << endl);
396  Exit(EXIT_FAILURE);
397  }
398  }
399 
400  // Verbose
401  if (verbose>=1) Cout("castor-mergeBedPositions() -> Use a bed displacement of " << multiple_bed_displacement << " mm" << endl);
402 
403  // ============================================================================================================
404  // Check that the bed displacement is compatible with the slice thickness
405  // ============================================================================================================
406 
407  // Define the tolerance associated to the rounding
408  FLTNB tolerance = 1.e-4;
409  // Compute floating point number of slices
410  FLTNB nb_slices_fltnb = multiple_bed_displacement / p_image_fields[0]->vox_size[2];
411  // Compute integer number of slices
412  FLTNB nb_slices_intnb = ((FLTNB)((uint32_t)nb_slices_fltnb));
413  // The number of slices defining the displacement
414  uint32_t displacement_slices = 0;
415  // Case where the floating number minus the integer number is less than 0.5; this means that
416  // the closest integer to the floating number of slices is below it.
417  if (nb_slices_fltnb-nb_slices_intnb<0.5)
418  {
419  // If the difference is below the tolerance, we are ok taking the 'integerized' number of slices as the displacement
420  if (nb_slices_fltnb-nb_slices_intnb<tolerance) displacement_slices = ((uint32_t)nb_slices_fltnb);
421  // Otherwise, the displacement is not compatible with the slice thickness
422  else
423  {
424  Cerr("***** castor-mergeBedPositions() -> Bed displacement is not compatible with the slice thickness of " << p_image_fields[0]->vox_size[2] << " mm !" << endl);
425  Exit(EXIT_FAILURE);
426  }
427  }
428  // Case where the floating number minus the integer number is more than 0.5; this means that
429  // the closest integer to the floating number of slices is above it.
430  else
431  {
432  // If the minus the difference + 1 is below the tolerance, we are of taking the 'integerized' number of slices + 1 as the displacement
433  if (nb_slices_intnb+1.-nb_slices_fltnb<tolerance) displacement_slices = ((uint32_t)nb_slices_fltnb) + 1;
434  // Otherwise, the displacement is not compatible with the slice thickness
435  else
436  {
437  Cerr("***** castor-mergeBedPositions() -> Bed displacement is not compatible with the slice thickness of " << p_image_fields[0]->vox_size[2] << " mm !" << endl);
438  Exit(EXIT_FAILURE);
439  }
440  }
441 
442  // Still check that the displacement slices makes sense
443  if (displacement_slices==0 || displacement_slices>dim_z)
444  {
445  Cerr("***** castor-mergeBedPositions() -> Computed displacement of " << displacement_slices << " slices makes no sense !" << endl);
446  Exit(EXIT_FAILURE);
447  }
448 
449  // Verbose
450  if (verbose>=1) Cout("castor-mergeBedPositions() -> Bed displacement corresponds to " << displacement_slices << " slices" << endl);
451 
452  // Compute the number of slices (this is one full image + the number of beds - 1 times the displacement)
453  uint32_t whole_dim_z = dim_z + ((uint32_t)(nb_beds-1)) * displacement_slices;
454  uint32_t whole_dim_xyz = dim_x * dim_y * whole_dim_z;
455 
456  // Verbose
457  if (verbose>=1) Cout("castor-mergeBedPositiosn() -> Output merged image has " << whole_dim_z << " slices" << endl);
458 
459  // ============================================================================================================
460  // If sensitivity, then load it as weights, otherwise set everything to 1
461  // ============================================================================================================
462 
463  // Create the weights matrix
464  FLTNB** p_weights = (FLTNB**)malloc(nb_beds*sizeof(FLTNB*));
465  for (uint32_t bed=0; bed<nb_beds; bed++) p_weights[bed] = NULL;
466 
467  // If we have sensitivity
468  if (path_to_sens_filename.size()>0)
469  {
470  // Verbose
471  if (verbose>=1) Cout("castor-mergeBedPositions() -> Load sensitivity images" << endl);
472  // Create interfile image fields and image pointers for sensitivity
473  Intf_fields** p_sens_fields = (Intf_fields**)malloc(nb_beds*sizeof(Intf_fields*));
474  // Read interfile images
475  for (uint32_t bed=0; bed<nb_beds; bed++)
476  {
477  // Create the image fields
478  p_sens_fields[bed] = new Intf_fields;
479  // Read the image
480  if (invert_order_flag) p_weights[bed] = IntfLoadImageFromScratch(path_to_sens_filename[nb_beds-1-bed],p_sens_fields[bed],verbose);
481  else p_weights[bed] = IntfLoadImageFromScratch(path_to_sens_filename[bed],p_sens_fields[bed],verbose);
482  // Check reading
483  if (p_weights[bed]==NULL)
484  {
485  Cerr("***** castor-mergeBedPositions() -> A problem occured while reading sensitivity for bed " << bed+1 << " !" << endl);
486  return 1;
487  }
488  }
489  // Check dimensions consistency between all image fields, as well as originating system and bed displacement
490  for (uint32_t bed=1; bed<nb_beds; bed++)
491  {
492  if (IntfCheckDimensionsConsistency(*p_sens_fields[0],*p_sens_fields[bed]))
493  {
494  Cerr("***** castor-mergeBedPositions() -> Inconsistency between sensitivity dimensions !" << endl);
495  Exit(EXIT_FAILURE);
496  }
497  }
498  // Check dimensions consistency, etc, between input images and sensitivity images
499  for (uint32_t bed=0; bed<nb_beds; bed++)
500  {
501  if (IntfCheckDimensionsConsistency(*p_image_fields[bed],*p_sens_fields[bed]))
502  {
503  Cerr("***** castor-mergeBedPositions() -> Inconsistency between input image and sensitivity dimensions for bed " << bed+1 << " !" << endl);
504  Exit(EXIT_FAILURE);
505  }
506  }
507  }
508  // If we do not have sensitivity
509  else
510  {
511  // Verbose
512  if (verbose>=1) Cout("castor-mergeBedPositions() -> Initialize weights to 1." << endl);
513  // We set everything to 1.
514  for (uint32_t bed=0; bed<nb_beds; bed++)
515  {
516  p_weights[bed] = (FLTNB*)malloc(dim_xyz*sizeof(FLTNB));
517  for (uint32_t v=0; v<dim_xyz; v++) p_weights[bed][v] = 1.;
518  }
519  }
520 
521  // ============================================================================================================
522  // Compute the whole body image
523  // ============================================================================================================
524 
525  // Verbose
526  if (verbose>=1) Cout("castor-mergeBedPositiosn() -> Compute whole image" << endl);
527  // Allocate whole image
528  FLTNB* p_whole_image = (FLTNB*)malloc(whole_dim_xyz*sizeof(FLTNB));
529  for (uint32_t v=0; v<whole_dim_xyz; v++) p_whole_image[v] = 0.;
530  // Allocate whole weights
531  FLTNB* p_whole_weight = (FLTNB*)malloc(whole_dim_xyz*sizeof(FLTNB));
532  for (uint32_t v=0; v<whole_dim_xyz; v++) p_whole_weight[v] = 0.;
533 
534  // Loop on all beds
535  for (uint32_t bed=0; bed<nb_beds; bed++)
536  {
537  // Loop on all slices
538  for (uint32_t z=0; z<dim_z; z++)
539  {
540  // Compute whole z index
541  uint32_t whole_z = z + bed * displacement_slices;
542  // For efficiency
543  uint32_t base_z = z * dim_x * dim_y;
544  uint32_t whole_base_z = whole_z * dim_x * dim_y;
545  // Loop on all voxels inside the slice
546  for (uint32_t xy=0; xy<dim_x*dim_y; xy++)
547  {
548  // Add the contribution of this bed to the whole image
549  p_whole_image[whole_base_z+xy] += p_images[bed][base_z+xy] * p_weights[bed][base_z+xy];
550  // Add the weights to the global weights
551  p_whole_weight[whole_base_z+xy] += p_weights[bed][base_z+xy];
552  }
553  }
554  }
555  // Normalize the whole image with respect to the weights
556  for (uint32_t v=0; v<whole_dim_xyz; v++)
557  {
558  if (p_whole_weight[v]>0.) p_whole_image[v] /= p_whole_weight[v];
559  else p_whole_image[v] = 0.;
560  }
561 
562  // ============================================================================================================
563  // Save output image
564  // ============================================================================================================
565 
566  // Verbose
567  if (verbose>=1) Cout("castor-mergeBedPositions() -> Write output image(s)" << endl);
568 
569  // Build interfile fields (we use first one of the input images and modify the relevant fields)
570  // Set header metadata using Image Dimensions object
571  p_image_fields[0]->mtx_size[2] = whole_dim_z;
572  p_image_fields[0]->nb_total_imgs = whole_dim_z;
573  p_image_fields[0]->nb_bytes_pixel = sizeof(FLTNB);
574  /* TODO: UPDATE TIME START AND DURATION BUT WILL HAVE TO WRITE THEM IN THE HEADERS OF IMAGES WRITTEN DURING ITERATIONS
575  ap_IF->study_duration = ap_ID->GetFinalTimeStopInSec(0) -
576  ap_ID->GetFrameTimeStartInSec(0,0);
577  for(int fr=0 ; fr<ap_ID->GetNbTimeFrames() ; fr++)
578  {
579  ap_IF->image_duration.push_back(ap_ID->GetFrameDurationInSec(0, fr));
580  ap_IF->frame_group_pause.push_back((fr == 0) ? 0
581  : ap_ID->GetFrameTimeStartInSec(0,fr) - ap_ID->GetFrameTimeStopInSec(0,fr-1));
582  }
583  */
584  // File name
585  string whole_image_filename = p_OutputManager->GetPathName() + p_OutputManager->GetBaseName() + "_whole";
586  // Write the image
587  if (IntfWriteImageFromIntfFields(whole_image_filename, p_whole_image, *p_image_fields[0], verbose))
588  {
589  Cerr("***** castor-mergeBedPositions() -> A problem occured while writing output whole image !" << endl);
590  Exit(EXIT_FAILURE);
591  }
592 
593  // Save global weights if asked for
594  if (save_weights)
595  {
596  // File name
597  string whole_weight_filename = p_OutputManager->GetPathName() + p_OutputManager->GetBaseName() + "_weights";
598  // Write the image
599  if (IntfWriteImageFromIntfFields(whole_weight_filename, p_whole_weight, *p_image_fields[0], verbose))
600  {
601  Cerr("***** castor-mergeBedPositions() -> A problem occured while writing global weights image !" << endl);
602  Exit(EXIT_FAILURE);
603  }
604  }
605 
606  // ============================================================================================================
607  // Free memory properly
608  // ============================================================================================================
609 
610  // Input images
611  if (p_images)
612  {
613  for (uint32_t bed=0; bed<nb_beds; bed++) if (p_images[bed]) free(p_images[bed]);
614  free(p_images);
615  }
616  // Weights
617  if (p_weights)
618  {
619  for (uint32_t bed=0; bed<nb_beds; bed++) if (p_weights[bed]) free(p_weights[bed]);
620  free(p_weights);
621  }
622  // Whole image
623  if (p_whole_image) free(p_whole_image);
624  // Whole image
625  if (p_whole_weight) free(p_whole_weight);
626 
627  // Ending
628  if (verbose>=1) Cout(endl);
629  #ifdef CASTOR_MPI
630  MPI_Finalize();
631  #endif
632  return EXIT_SUCCESS;
633 }
This header file is mainly used to declare some macro definitions and all includes needed from the st...
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
Declaration of class oImageDimensionsAndQuantification.
void SetVerbose(int a_verbose)
set verbosity
uint8_t nb_bytes_pixel
FLTNB vox_size[3]
#define FLTNB
Definition: gVariables.hh:55
uint32_t nb_total_imgs
int FindScannerSystem(string a_scannerName)
Look for a file matching with the scanner name in parameter inside the scanner repository.
int IntfCheckDimensionsConsistency(Intf_fields ImgFields1, Intf_fields ImgFields2)
string GetPathToScannerFile()
int main(int argc, char **argv)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
Declaration of class iDataFilePET.
Declaration of class oIterativeAlgorithm.
Declaration of class iDataFileSPECT.
void Exit(int code)
Declaration of class iScannerPET.
int LogCommandLine(int argc, char **argv)
Write log file header with the provided command line options and different informations.
int ConvertFromString(const string &a_str, string *a_result)
Copy the 'a_str' string in the position pointed by 'a_result'.
Definition: gOptions.cc:749
int CheckConfigDir(const string &a_path)
Set the path to the CASTOR config directory from the given path if not empty or through the existence...
#define Cerr(MESSAGE)
const string & GetPathName()
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:111
Singleton class that Instantiate and initialize the scanner object.
FLTNB * IntfLoadImageFromScratch(const string &a_pathToHeaderFile, Intf_fields *ap_ImgFields, int vb)
Declaration of class sScannerManager.
uint32_t mtx_size[7]
void SetMPIRank(int a_mpiRank)
Initialize the machine index for MPI.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:25
Declaration of class sRandomNumberGenerator.
const string & GetBaseName()
void ShowHelp()
Declaration of class oSensitivityGenerator.
Interfile fields. This structure contains all the Interfile keys currently managed by CASToR Decl...
FLTNB multiple_bed_displacement
Declaration of class sOutputManager.
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
Create the output directory if any, extract the base name and create the log file.
This file is used for all kind of different functions designed for options parsing and ASCII file rea...
void SetVerbose(int a_verboseLevel)
set verbosity
#define Cout(MESSAGE)
#define CASTOR_VERSION
Definition: gVariables.hh:44
Declaration of class sAddonManager.
void GetUserEndianness()
Check user/host computer endianness and write it to the global variable User_Endianness.
string originating_system
int IntfWriteImageFromIntfFields(const string &a_pathToImg, FLTNB *ap_ImgMatrix, Intf_fields Img_fields, int vb)