CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
toolkits/castor-scannerLUTExplorer.cc
Go to the documentation of this file.
1 
10 #include "gVariables.hh"
11 #include "gOptions.hh"
12 #include "oImageDimensionsAndQuantification.hh"
13 #include "iDataFilePET.hh"
14 #include "iDataFileSPECT.hh"
15 #include "iDataFileCT.hh"
16 #include "sOutputManager.hh"
17 #include "sScannerManager.hh"
18 #include "sRandomNumberGenerator.hh"
19 #include "iScannerPET.hh"
20 #include "sAddonManager.hh"
21 
22 
31 #define IF_TYPE_UNKNOWN -1
32 
33 #define IF_TYPE_LUT 0
34 
35 #define IF_TYPE_GEOM 1
36 
39 // =============================================================================================================================================
40 // =============================================================================================================================================
41 // =============================================================================================================================================
42 // H E L P F U N C T I O N S
43 // =============================================================================================================================================
44 // =============================================================================================================================================
45 // =============================================================================================================================================
46 
47 
52 void ShowHelp()
53 {
54  // Show help
55  cout << endl;
56  cout << "Usage: castor-scannerLUTExplorer -df datafile.cdh [settings]" << endl;
57  cout << endl;
58  cout << "This program can be used to explore a datafile and get some info about it. By default, it simply prints general information recovered" << endl;
59  cout << "from the reader. If the '-e' option is supply, an element-by-element exploration will be performed: information about each element will be" << endl;
60  cout << "displayed." << endl;
61  cout << "For CT scanners or SPECT cameras described by a .geom file, a datafile must also be provided in order to get information regarding the projection angles." << endl;
62  cout << endl;
63  cout << "[Mandatory parameters]:" << endl;
64  cout << " -sf scan_file : Give the path to the header of a single lut file, or to a geom file." << endl;
65  cout << endl;
66  cout << "[Options]:" << endl;
67  cout << " -e : Flag for scanner element by element exploration (will list the content of each element)." << endl;
68  cout << " -g : Flag for global exploration (geometric characteristics of all elements will be displayed)." << endl;
69  cout << " -o path_out_file : Path to an output file in which the data will be printed." << endl;
70  cout << " -df data_file : For CT or SPECT system, using a .geom file as input. Give the path to the header of a datafile in order to get projection informations." << endl;
71  cout << " -vb value : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
72  cout << " --help,-h,-help : Print out this help page." << endl; // managed by main
73  cout << endl;
74  #ifdef BUILD_DATE
75  cout << " Build date: " << BUILD_DATE << endl;
76  cout << endl;
77  #endif
78  #ifdef CASTOR_VERSION
79  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
80  cout << endl;
81  #endif
82 }
83 
84 
85 
86 
95 void GetInputFileType(string& ap_pathToScanFilename, string& ap_pathToBinary, int a_modality, int& ap_inputFileType)
96 {
97  // Check if we have a LUT or GEOM file
98 
99  // checking for LUT
100  if(ap_pathToBinary.find(".hscan") != string::npos
101  || ap_pathToBinary.find(".lut") != string::npos)
102  {
103  ap_inputFileType = IF_TYPE_LUT;
104  if( ap_pathToBinary.find_last_of(".hscan") != string::npos ) // header has been provided
105  ap_pathToBinary = ap_pathToBinary.substr(ap_pathToBinary.find_last_of(".hscan")) + ".lut";
106  else // lut has been provided
107  ap_pathToScanFilename = ap_pathToBinary.substr(ap_pathToBinary.find_last_of(".lut")) + ".hscan";
108 
109  Cout(" A scanner LUT binary file has been provided " << endl);
110  }
111  // Checking for GEOM (look for a mandatory key)
112  else
113  {
114  // Try to recover a mandatory geom file key, to check whether we have a geom scanner file
115  FLTNB key = 0.;
116  string key_str = "";
117 
118  // Get a key specific to the modality
119  if (a_modality == SCANNER_PET)
120  key_str = "number of rsectors";
121  else if (a_modality == SCANNER_SPECT_CONVERGENT)
122  key_str = "number of detector heads";
123  else if (a_modality == SCANNER_CT)
124  key_str = "detector radius";
125  else
126  {
127  Cerr("***** castor-scannerLUTExplorer() -> Error, this modality is not implemented yet !" << endl);
128  Exit(EXIT_FAILURE);
129  }
130 
131  int rvalue = ReadDataASCIIFile(ap_pathToScanFilename, key_str, &key, 1, KEYWORD_MANDATORY);
132 
133  if (rvalue > 1)
134  {
135  Cerr("***** castor-scannerLUTExplorer() -> An error occurred while trying to read a mandatory parameter for a .geom file in the scanner header file !" << endl);
136  Exit(EXIT_FAILURE);
137  }
138  else if (rvalue == 1)
139  {
140  Cerr("***** castor-scannerLUTExplorer() -> The provided file has not been identified as a scanner binary file (no .hscan or .lut extension), nor a .geom file (a mandatory key is missing) !" << endl);
141  Exit(EXIT_FAILURE);
142  }
143  else
144  {
145  ap_inputFileType = IF_TYPE_GEOM;
146  Cout(" A generic geometry file has been provided " << endl);
147  }
148  }
149 }
150 
151 
152 
153 
154 // =============================================================================================================================================
155 // =============================================================================================================================================
156 // =============================================================================================================================================
157 // M A I N P R O G R A M
158 // =============================================================================================================================================
159 // =============================================================================================================================================
160 // =============================================================================================================================================
161 
162 int main(int argc, char** argv)
163 {
164  // ============================================================================================================
165  // MPI stuff (we make all instances but the first one returning 0 directly)
166  // ============================================================================================================
167  #ifdef CASTOR_MPI
168  int mpi_rank = 0;
169  int mpi_size = 1;
170  MPI_Init(&argc, &argv);
171  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
172  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
173  if (mpi_rank!=0) return 0;
174  #endif
175 
176  // No argument, then show help
177  if (argc==1)
178  {
179  ShowHelp();
180  Exit(EXIT_SUCCESS);
181  }
182 
183  // ============================================================================================================
184  // The few parameters
185  // ============================================================================================================
186 
187  // String of a single path to a scanner file name
188  string path_to_scan_filename = "";
189 
190  // String of a single path to a data file name (required for SPECT/CT with geom)
191  string path_to_data_filename = "";
192 
193  // Modality
194  int modality = SCANNER_UNKNOWN;
195 
196  // General verbose level
197  int verbose = 1;
198  // Flag for element-by-element exploration
199  bool elt_by_elt_flag = false;
200  // Flag for global exploration
201  bool global_flag = false;
202  // Flag for input file type
203  int input_file_type = IF_TYPE_UNKNOWN;
204  // Output file (log) string
205  string path_fout = "";
206 
207 
208  // ============================================================================================================
209  // Read command-line parameters
210  // ============================================================================================================
211 
212  // Must manually increment the option index when an argument is needed after an option
213  for (int i=1; i<argc; i++)
214  {
215  // Get the option as a string
216  string option = (string)argv[i];
217  // Show help
218  if (option=="-h" || option=="--help" || option=="-help")
219  {
220  ShowHelp();
221  Exit(EXIT_SUCCESS);
222  }
223  // General verbosity level
224  else if (option=="-vb")
225  {
226  if (i>=argc-1)
227  {
228  Cerr("***** castor-scannerLUTExplorer() -> Argument missing for option: " << option << endl);
229  Exit(EXIT_FAILURE);
230  }
231  if (ConvertFromString(argv[i+1], &verbose))
232  {
233  Cerr("***** castor-scannerLUTExplorer() -> Exception when trying to read provided verbosity level '" << verbose << " for option: " << option << endl);
234  Exit(EXIT_FAILURE);
235  }
236  i++;
237  }
238  // ScannerFile
239  else if (option=="-sf") // This is a mandatory option
240  {
241  if (i>=argc-1)
242  {
243  Cerr("***** castor-scannerLUTExplorer() -> Argument missing for option: " << option << endl);
244  Exit(EXIT_FAILURE);
245  }
246  path_to_scan_filename = (string)argv[i+1];
247  i++;
248  }
249  // DataFile
250  else if (option=="-df") // This is a mandatory option
251  {
252  if (i>=argc-1)
253  {
254  Cerr("***** castor-scannerLUTExplorer() -> Argument missing for option: " << option << endl);
255  Exit(EXIT_FAILURE);
256  }
257  path_to_data_filename = (string)argv[i+1];
258  i++;
259  }
260  // Element by element exploration
261  else if (option=="-e")
262  {
263  elt_by_elt_flag = true;
264  }
265  // Global exploration
266  else if (option=="-g")
267  {
268  global_flag = true;
269  }
270  else if (option=="-o")
271  {
272  if (i>=argc-1)
273  {
274  Cerr("***** castor-scannerLUTExplorer()) -> Argument missing for option: " << option << endl);
275  Exit(EXIT_FAILURE);
276  }
277  path_fout = argv[i+1];
278  i++;
279  }
280 
281  // Unknown option!
282  else
283  {
284  Cerr("***** castor-scannerLUTExplorer() -> Unknown option '" << option << "' !" << endl);
285  Exit(EXIT_FAILURE);
286  }
287  }
288 
289  // ============================================================================================================
290  // Some checks
291  // ============================================================================================================
292 
293  // Check for a datafile name
294  if (path_to_scan_filename=="")
295  {
296  Cerr("***** castor-scannerLUTExplorer() -> Please provide a datafile name !" << endl);
297  Exit(EXIT_FAILURE);
298  }
299  // Verbose
300  if (verbose<=0)
301  {
302  Cerr("***** castor-scannerLUTExplorer() -> Verbose less than 1 has no sense for a program used to solely print out information on screen !" << endl);
303  Exit(EXIT_FAILURE);
304  }
305  // Restrict verbose level to 2 to avoid having to much useless information during initialization
306  if (verbose>2) verbose = 2;
307  // Cannot have element-by-element and global both enables
308  if (global_flag && elt_by_elt_flag)
309  {
310  Cerr("***** castor-scannerLUTExplorer() -> Cannot use global and element-by-element mode at the same time !" << endl);
311  Exit(EXIT_FAILURE);
312  }
313 
314  // ----------------------------------------------------------------------------------------
315  // Check input file type if LUT or geom
316  // ----------------------------------------------------------------------------------------
317 
318 
319  // Check if we have two files for the scanner basename (.hscan/.lut) -> we have a lut
320  // Get scanner basename
321  string path_to_binary = path_to_scan_filename;
322 
323 
324  // ============================================================================================================
325  // Initializations
326  // ============================================================================================================
327 
328  // Verbose (we know it is at least 1 so we don't check it)
329  Cout("==============================================================" << endl);
330  Cout("castor-scannerLUTExplorer() -> Initialization starts" << endl);
331 
332  // Get user endianness (interfile I/O)
334 
335  // ----------------------------------------------------------------------------------------
336  // Create sScannerManager
337  // ----------------------------------------------------------------------------------------
338 
339  // Create the scanner manager
340  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
341  p_ScannerManager->SetVerbose(verbose);
342 
343  // First, recover the modality
344  string modality_str = "";
345 
346  if( ReadDataASCIIFile(path_to_scan_filename, "modality", &modality_str, 1, KEYWORD_MANDATORY) )
347  {
348  Cerr("***** castor-scannerLUTExplorer() -> Error when trying to read the 'modality' key in the scanner file !" << endl);
349  Exit(EXIT_FAILURE);
350  }
351 
352  modality = p_ScannerManager->GetModalityFromString(modality_str);
353 
354  // Identify input file type and system
355  GetInputFileType(path_to_scan_filename, path_to_binary, modality, input_file_type);
356 
357  // Initialized output Manager, if output log is enabled
358  if(path_fout != "")
359  {
360  sOutputManager* p_outputManager;
361  p_outputManager = sOutputManager::GetInstance();
362 
363  p_outputManager->SetVerbose(verbose);
364 
365  //p_outputManager->SetDataFileName(vpath_to_initial_img);
366 
367  // Set path to the config directory
368  if (p_outputManager->CheckConfigDir(""))
369  {
370  Cerr("***** castor-proj() -> A problem occurred while checking for the config directory path !" << endl);
371  Exit(EXIT_FAILURE);
372  }
373 
374  // Initialize output directory and base name
375  if (p_outputManager->InitOutputDirectory(path_fout, ""))
376  {
377  Cerr("***** castor-proj() -> A problem occurred while initializing output directory !" << endl);
378  Exit(EXIT_FAILURE);
379  }
380  // Log command line
381  if (p_outputManager->LogCommandLine(argc,argv))
382  {
383  Cerr("***** castor-proj() -> A problem occurred while logging command line arguments !" << endl);
384  Exit(EXIT_FAILURE);
385  }
386  }
387 
388 
389 
390 
391  // Get system name from the dataFile
392  string scanner_name = "";
393  if (ReadDataASCIIFile(path_to_scan_filename, "scanner name", &scanner_name, 1, KEYWORD_MANDATORY))
394  {
395  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while trying to find the system name in the datafile header !" << endl);
396  Exit(EXIT_FAILURE);
397  }
398 
399 
400  if (p_ScannerManager->InitScannerWithFile(path_to_scan_filename, scanner_name, input_file_type) )
401  {
402  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred during scanner object initialization ! !" << endl);
403  Exit(EXIT_FAILURE);
404  }
405 
406  if (p_ScannerManager->BuildScannerObject() )
407  {
408  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred during scanner object construction ! !" << endl);
409  Exit(EXIT_FAILURE);
410  }
411  if (p_ScannerManager->InstantiateScanner() )
412  {
413  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while creating Scanner object !" << endl);
414  Exit(EXIT_FAILURE);
415  }
416 
417  // For SPECT / CT with geom, check that a datafile has been provide (mandatory)
418  if(input_file_type == IF_TYPE_GEOM && p_ScannerManager->GetScannerType() != SCANNER_PET )
419  {
420  if(path_to_data_filename == "")
421  {
422  Cerr("***** castor-scannerLUTExplorer() -> Error : For SPECT / CT systems, a datafile is required to compute the look-up-table from a geom file (i.e projection angles) !" << endl);
423  Exit(EXIT_FAILURE);
424  }
425  else if (p_ScannerManager->GetGeometricInfoFromDataFile(path_to_data_filename))
426  {
427  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while retrieving scanner fields from the datafile header !" << endl);
428  Exit(EXIT_FAILURE);
429  }
430  }
431  if (p_ScannerManager->BuildLUT() )
432  {
433  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while generating/reading the LUT !" << endl);
434  Exit(EXIT_FAILURE);
435  }
436  if (p_ScannerManager->CheckParameters())
437  {
438  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while checking scanner manager parameters !" << endl);
439  Exit(EXIT_FAILURE);
440  }
441  if (p_ScannerManager->Initialize())
442  {
443  Cerr("***** castor-scannerLUTExplorer() -> A problem occurred while initializing scanner !" << endl);
444  Exit(EXIT_FAILURE);
445  }
446 
447  // Verbose
448  Cout("castor-scannerLUTExplorer() -> End of initialization" << endl);
449  Cout("==============================================================" << endl);
450 
451  // ============================================================================================================
452  // Actions
453  // ============================================================================================================
454 
455  // -------------------------------------------------------------------
456  // Ask the scanner to describe itself
457  // -------------------------------------------------------------------
458  p_ScannerManager->Describe();
459  Cout("==============================================================" << endl);
460 
461  // -------------------------------------------------------------------
462  // Then if the element-by-element option is on, describe each element
463  // -------------------------------------------------------------------
464 
465  if (elt_by_elt_flag)
466  {
467  Cout("castor-scannerLUTExplorer() -> Start exploration of all scanner elements" << endl);
468  // Get index start and stop
469  int64_t index_start = 0; int64_t index_stop = p_ScannerManager->GetSystemNbElts();
470 
471  // Launch the loop on all elements
472  int64_t index = index_start;
473  while (index>=index_start && index<index_stop)
474  {
475  // Verbose
476  Cout("------------------------- Element index " << index << " -------------------------" << endl);
477 
478  // Get the current element
479  FLTNB position1[3], position2[3];
480  FLTNB orientation1[3], orientation2[3];
481 
482  p_ScannerManager->GetScannerObject()->GetPositionsAndOrientations(0, index, position1, position2, orientation1, orientation2);
483 
484  // Describe the element
485  Cout("Scanner element center location (x,y,z): "<< position2[0] << " ; " << position2[1] << " ; " << position2[2] << " ." ;);
486  Cout("Orientation (x,y,z): "<< orientation2[0] << " ; " << orientation2[1] << " ; " << orientation2[2] << endl;);
487 
488  // The user may provide a specific element index or simply press enter to get to the next
489  cout << "--------> Give an element index or simply press enter for next element: " << flush;
490  // Read the answer
491  string answer = ""; getline(cin,answer);
492  cout << endl;
493  // If empty answer, then go to the next element
494  if (answer=="") index++;
495  // Otherwise
496  else
497  {
498  // Convert the answer to int64_t
499  int64_t next_index = stoll(answer);
500  if (next_index<index_start || next_index>=index_stop)
501  {
502  Cerr("***** castor-scannerLUTExplorer() -> The provided element index (" << next_index << ") is out of datafile range"
503  << " [" << index_start << ":" << index_stop << "[ !" << endl);
504  break;
505  }
506  else index = next_index;
507  }
508 
509  }
510  Cout("==============================================================" << endl);
511  }
512 
513  // -------------------------------------------------------------------
514  // Or perform a global exploration
515  // -------------------------------------------------------------------
516 
517  else if (global_flag)
518  {
519  // Verbose
520  Cout("castor-scannerLUTExplorer() -> Start global exploration of all elements" << endl);
521 
522  // Get index start and stop
523  int64_t index_start = 0; int64_t index_stop = p_ScannerManager->GetSystemNbElts();
524 
525  // Launch the loop on all elements
526  for (int64_t index=index_start ; index<index_stop ; index++)
527  {
528  // Get the current element
529  FLTNB position1[3], position2[3];
530  FLTNB orientation1[3], orientation2[3];
531 
532  p_ScannerManager->GetScannerObject()->GetPositionsAndOrientations(0, index, position1, position2, orientation1, orientation2);
533 
534  Cout("Scanner element center location (x,y,z): "<< position2[0] << " ; " << position2[1] << " ; " << position2[2] << " ." ;);
535  Cout("Orientation (x,y,z): "<< orientation2[0] << " ; " << orientation2[1] << " ; " << orientation2[2] << endl;);
536  }
537 
538  Cout("==============================================================" << endl);
539 
540  // -------------------------------------------------------------------
541  // Ask the scanner to describe itself
542  // -------------------------------------------------------------------
543  p_ScannerManager->Describe();
544  Cout("==============================================================" << endl);
545  }
546 
547  // ============================================================================================================
548  // End
549  // ============================================================================================================
550 
551  // Ending
552  #ifdef CASTOR_MPI
553  MPI_Finalize();
554  #endif
555  return EXIT_SUCCESS;
556 }
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define Cerr(MESSAGE)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int GetModalityFromString(string a_systemStr)
void GetInputFileType(string &ap_pathToScanFilename, string &ap_pathToBinary, int a_modality, int &ap_inputFileType)
void Exit(int code)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int CheckParameters()
Check if all parameters have been correctly initialized, and call the CheckParameters function of the...
int InstantiateScanner()
Instantiate scanner using the related function in the scanner classes.
int LogCommandLine(int argc, char **argv)
int CheckConfigDir(const string &a_path)
#define SCANNER_SPECT_CONVERGENT
int BuildLUT()
Call the eponym function of the scanner class.
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
Singleton class that Instantiate and initialize the scanner object.
int main(int argc, char **argv)
#define KEYWORD_MANDATORY
int Initialize()
Initialization : .
void GetUserEndianness()
Check user/host computer endianness and write it to the global variable User_Endianness.
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
int ConvertFromString(const string &a_str, string *a_result)
Copy the &#39;a_str&#39; string in the position pointed by &#39;a_result&#39;.
void Describe()
Call the eponym function from the Scanner object (if initialized)
void SetVerbose(int a_verboseLevel)
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...
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)
#define Cout(MESSAGE)
virtual int GetPositionsAndOrientations(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3], FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3], FLTNB *ap_POI1=NULL, FLTNB *ap_POI2=NULL)=0
int InitScannerWithFile(string a_pathScanFile, string a_scannerName, int a_fileTypeFlag)