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