CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/scanner/sScannerManager.cc
Go to the documentation of this file.
1 
8 #include "sScannerManager.hh"
9 #include "sAddonManager.hh"
10 
11 // Singleton : set pointer to object to NULL
13 
14 // =====================================================================
15 // ---------------------------------------------------------------------
16 // ---------------------------------------------------------------------
17 // =====================================================================
18 /*
19  \brief sScannerManager constructor.
20  \details It is private at this class is singleton.
21  This class should be instanciated using the GetInstance() function
22  Initialize the member variables to their default values.
23 */
25 {
26  mp_Scanner = NULL;
27  mp_ID = NULL;
28  m_verbose = -1;
30  m_scannerName = "";
31  m_hasUserScannerFile = false;
33  m_allParametersChecked = false;
34  m_saveLUTFlag = false;
35 }
36 
37 // =====================================================================
38 // ---------------------------------------------------------------------
39 // ---------------------------------------------------------------------
40 // =====================================================================
41 /*
42  \brief sScannerManager destructor.
43 */
45 {
46  if (mp_Scanner != NULL) delete mp_Scanner;
47 }
48 
49 // =====================================================================
50 // ---------------------------------------------------------------------
51 // ---------------------------------------------------------------------
52 // =====================================================================
53 /*
54  \fn CheckParameters
55  \brief Check if all parameters have been correctly initialized, and call the CheckParameters function of the scanner object
56  \return 0 if success. Positive value otherwise
57 */
59 {
61  // Check mandatory parameters
62  if (mp_Scanner == NULL)
63  {
64  Cerr("***** sScannerManager::CheckParameters() -> Scanner object not initialized !" << endl);
65  return 1;
66  }
68  {
69  Cerr("***** sScannerManager::CheckParameters() -> Scanner file type (generic or user provided) not initialized !" << endl);
70  return 1;
71  }
72  if (m_scannerName.empty())
73  {
74  Cerr("***** sScannerManager::CheckParameters() -> Scanner name not initialized" << endl);
75  return 1;
76  }
77  if (m_pathToScannerFile.empty())
78  {
79  Cerr("***** sScannerManager::CheckParameters() -> Path to scanner file not initialized !" << endl);
80  return 1;
81  }
82  if (m_verbose<0)
83  {
84  Cerr("***** sScannerManager::CheckParameters() -> Verbosity level not initialized !" << endl);
85  return 1;
86  }
87  // Check parameters of the scanner object
89  {
90  Cerr("***** sScannerManager::CheckParameters() -> A problem occurred while checking Scanner Object parameters !" << endl);
91  return 1;
92  }
93  // All parameters are checked
95  // End
96  return 0;
97 }
98 
99 
100 
101 // =====================================================================
102 // ---------------------------------------------------------------------
103 // ---------------------------------------------------------------------
104 // =====================================================================
110 {
112 
113  if (mp_Scanner == NULL)
114  {
115  Cerr("***** WARNING: sScannerManager::Describe() -> Trying to describe the scanner object while it is not initialized !" << endl);
116  }
117  else
118  {
119  Cout(endl << "---------------------------------------------------------------------------" << endl);
120  Cout("sScannerManager::Describe() -> Here is some generic content of the scanner:" << endl);
121  Cout(" --> Scanner name: " << m_scannerName << endl);
122  Cout(" --> Scanner file: " << m_pathToScannerFile << endl);
123  mp_Scanner->Describe();
124  }
125 }
126 
127 
128 
129 
130 // =====================================================================
131 // ---------------------------------------------------------------------
132 // ---------------------------------------------------------------------
133 // =====================================================================
134 /*
135  \fn Initialize
136  \brief Initialization :
137  - check if all parameters of the manager have been checked
138  - call the initialization function of the scanner object
139  \return 0 if success. Positive value otherwise
140 */
142 {
144  // Parameters checked ?
146  {
147  Cerr("***** sScannerManager::Initialize() -> Parameters have not been checked !" << endl);
148  return 1;
149  }
150  // Verbose
151  if (m_verbose>=VERBOSE_LIGHT) Cout("sScannerManager::Initialize() -> From scanner " << m_scannerName << endl);
152  // Initialize the scanner object
153  if (mp_Scanner->Initialize())
154  {
155  Cerr("***** sScannerManager::Initialize() -> A problem occurred while initializing Scanner Object !" << endl);
156  return 1;
157  }
158  // End
159  return 0;
160 }
161 
162 // =====================================================================
163 // ---------------------------------------------------------------------
164 // ---------------------------------------------------------------------
165 // =====================================================================
166 /*
167  \fn ShowScannersDescription
168  \brief Get the description associated to the different scanners and print all on screen.
169  Walk through the scanner repository and look for the keyword "description" in .geom file and .hscan file.
170  \return 0 if success, positive value otherwise
171  \todo Check everything output correctly for all implemented scanners
172 */
174 {
176 
177  // Return when using MPI and mpi_rank is not 0
178  #ifdef CASTOR_MPI
179  int mpi_rank = 0;
180  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
181  if (mpi_rank!=0) return 0;
182  #endif
183 
184  // Verbose
185  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::ShowScannersDescription ..."<< endl);
186 
187  // Gather all the available scanner from the repository
188  vector<string> list_scanner_names;
189  if (GetAvailableScanners(&list_scanner_names))
190  {
191  Cerr("***** sScannerManager::ShowScannersDescription() -> A problem occurred while recovering scanner names from the scanner repository !" << endl);
192  return 1;
193  }
194 
195  // Print-out descriptions
196  cout << endl << "Here is the list of all available scanners in the repository along with their options:" << endl << endl;
197  for (unsigned int iter = 0; iter!=list_scanner_names.size(); iter++)
198  {
199  // Get the actual scanner in temporary local variable
200  string scanner_file = sOutputManager::GetInstance()->GetPathToConfigDir() + "scanner" + OS_SEP;
201  // Print out the name of this scanner
202  cout << "------------------------------------------------------------------" << endl;
203  cout << "----- \"" << list_scanner_names[iter] << "\"" << endl;
204  cout << "------------------------------------------------------------------" << endl;
205  // Proceed
206  scanner_file.append(list_scanner_names[iter]);
207  // Look for the "description" keyword in the .geom or .hscan file
208  string description;
209  ReadDataASCIIFile(scanner_file, "description", &description, 1, 1);
210  // Print out description
211  cout << description << endl << endl;
212  }
213  return 0;
214 }
215 
216 // =====================================================================
217 // ---------------------------------------------------------------------
218 // ---------------------------------------------------------------------
219 // =====================================================================
220 /*
221  \fn FindScannerSystem
222  \param a_scannerName : string containing name of the required scanner
223  \brief Look for a file matching with the scanner name in parameter inside the scanner repository
224  \return 0 if success (scanner found). Positive value otherwise
225 */
226 int sScannerManager::FindScannerSystem(string a_scannerName)
227 {
229 
230  // Check emptiness
231  if (a_scannerName.empty())
232  {
233  Cerr("***** sScannerManager::FindScannerSystem() -> scanner name is empty !" << endl);
234  return 1;
235  }
236 
237  // Verbose
238  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::FindScannerSystem() -> Search for scanner " << a_scannerName << " in the configuration directory" << endl);
239 
240  // Get the list of scanner from the repository
241  vector<string> repository_scanner_names;
242  if (GetAvailableScanners(&repository_scanner_names))
243  {
244  Cerr("***** sScannerManager::FindScannerSystem() -> A problem occurred while recovering scanner names from the scanner repository !" << endl);
245  return 1;
246  }
247 
248  // Set the scanner name
249  m_scannerName = a_scannerName;
251 
252  // String to recover generic/user-made scanner file
253  string generic_scanner_file, user_scanner_file;
254 
255  // Loop over the scanner available in the repository, and check if the scanner name match with any of these
256  for (unsigned int index_name=0 ; index_name<repository_scanner_names.size() ; index_name++)
257  {
258  string gfile = a_scannerName;
259  string ufile = a_scannerName;
260  // Check if the scanner match a geom file (generic_scanner_file)
261  if (gfile.append(".geom") == repository_scanner_names[index_name])
262  {
263  generic_scanner_file = a_scannerName;
264  generic_scanner_file.append(".geom");
266  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Matched generic file for the scanner system: " << repository_scanner_names[index_name] << endl);
267  }
268  // Check if the scanner match an user file (user provided LUT)
269  if (ufile.append(".hscan") == repository_scanner_names[index_name])
270  {
271  user_scanner_file = a_scannerName;
272  user_scanner_file.append(".hscan");
273  m_hasUserScannerFile = true;
274  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> matched custom LUT for the scanner system: " << repository_scanner_names[index_name] << endl);
275  }
276  }
277 
278  // When both a generic file and user-provided LUT exist for this system, the generic file is selected by default
280  {
282  {
283  Cerr("***** WARNING sScannerManager::FindScannerSystem() -> Both a generic file and user-provided LUT have been detected for the " << a_scannerName << " system." << endl);
284  Cerr(" The generic file (*.geom) will be selected by default." << endl);
285  }
286  m_hasUserScannerFile = false;
287  }
288 
289  // Initialize m_pathToScannerFile member variable
290  if (m_hasGenericScannerFile) m_pathToScannerFile.append(generic_scanner_file.c_str());
291  else if (m_hasUserScannerFile) m_pathToScannerFile.append(user_scanner_file.c_str());
292  // Unknown scanner, output scanner description and throw error
293  else
294  {
295  Cerr("***** sScannerManager::FindScannerSystem() -> Scanner '"<< a_scannerName <<
296  "' is not known in the scanner repository. Please provide a LUT/generic file for this scanner in the scanner repository in: " <<
297  sOutputManager::GetInstance()->GetPathToConfigDir() << "scanner" << OS_SEP << endl << endl;);
299  return 1;
300  }
301  // End
302  return 0;
303 }
304 
305 
306 
307 
308 // =====================================================================
309 // ---------------------------------------------------------------------
310 // ---------------------------------------------------------------------
311 // =====================================================================
312 /*
313  \fn int sScannerManager::InitScannerWithFile()
314  \param a_pathScanFile : string containing the path to the scanner file
315  \param a_scannerName : string containing the name of the required scanner
316  \param a_fileTypeFlag : string containing the type of the scanner file (0=lut, 1=geom)
317  \brief Initialize member variables (file path, file type, and scanner name) with the provided arguments
318  \return 0 if success (scanner found). Positive value otherwise
319 */
320 int sScannerManager::InitScannerWithFile(string a_pathScanFile, string a_scannerName, int a_fileTypeFlag)
321 {
323  // Verbose
324  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::InitScannerWithFile()" << endl);
325 
326  // Set the scanner name
327  m_scannerName = a_scannerName;
328  m_pathToScannerFile = a_pathScanFile;
329 
330  if( a_fileTypeFlag == 0 )
331  m_hasUserScannerFile = true;
332  else if ( a_fileTypeFlag == 1 )
334  else
335  {
336  Cerr("***** sScannerManager::InitScannerWithFile() -> Error : File type provided in argument must be == 0 (lut) or == 1 (geom). Current value is '" << a_fileTypeFlag << " !" << endl);
337  return 1;
338  }
339 
340  // End
341  return 0;
342 }
343 
344 // =====================================================================
345 // ---------------------------------------------------------------------
346 // ---------------------------------------------------------------------
347 // =====================================================================
348 /*
349  \fn BuildScannerObject()
350  \brief Instantiate the specific scanner object related to the modality, and set verbosity of scanner object
351  \todo delete the check on modality once all scanner classes will be completely implemented ?
352  \return 0 if success. Positive value otherwise
353 */
355 {
357 
358  // Verbose
359  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::BuildScannerObject() -> Start building"<< endl);
360 
361  // Check scanner modality
362  string scanner_type;
363  typedef vScanner *(*maker_scanner) ();
364 
365  // Get the system type from the value of the modality field inside the scanner header
366  if (ReadDataASCIIFile(m_pathToScannerFile, "modality", &scanner_type, 1, KEYWORD_MANDATORY) == 1)
367  {
368  Cerr("***** sScannerManager::BuildScannerObject() -> 'Modality' field not found in the header of the scanner configuration file at :"<< endl);
369  Cerr("***** " << m_pathToScannerFile << endl);
370  return 1;
371  }
372 
373  // Get scanner's list from addon manager
374  std::map <string,maker_scanner> list = sAddonManager::GetInstance()->mp_listOfScannerTypes;
375 
376  // Instanciate the scanner class corresponding to the modality, throw error if no match
377  if (list[scanner_type]) mp_Scanner = list[scanner_type]();
378  else
379  {
380  Cerr("***** sScannerManager::BuildScannerObject() -> Modality '" << scanner_type << "' is unknown !" << endl);
382  return 1;
383  }
384 
385  // Set scanner verbosity
387 
388  // Set scanner image dimensions and quantification pointer
390 
391  // End
392  return 0;
393 }
394 
395 // =====================================================================
396 // ---------------------------------------------------------------------
397 // ---------------------------------------------------------------------
398 // =====================================================================
399 /*
400  \fn GetGeometricInfoFromDataFile
401  \param a_path : string containing the path to datafile header
402  \brief Call the specialized function of the scanner object in order to
403  get geometric informations from the datafile header
404  \return 0 if success. Positive value otherwise
405 */
407 {
409 
410  // Verbose
411  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::GetGeometricInfoFromDataFile() -> Look for acquisition specific settings into datafile header"<< endl);
412 
413  // Get information
415  {
416  Cerr("***** sScannerManager::GetGeometricInfoFromDataFile() -> An error occurred while getting information from the datafile." << endl);
417  return 1;
418  }
419 
420  // End
421  return 0;
422 }
423 
424 // =====================================================================
425 // ---------------------------------------------------------------------
426 // ---------------------------------------------------------------------
427 // =====================================================================
428 /*
429  \fn InstantiateScanner
430  \brief Instantiate scanner using the related function in the scanner classes
431  \todo delete the check on scanner type once all scanner classes will be completely implemented.
432  \return 0 if success. Positive value otherwise
433 */
435 {
437 
438  // Verbose
439  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::InstantiateScanner() -> Instantiate the scanner geometry structure"<< endl);
440 
441  // Check if the scanner object is known (TODO : delete this check once all scanner classes will be completely implemented)
442  if (mp_Scanner->GetScannerType()<0)
443  {
444  Cerr("***** sScannerManager::BuildScannerObject() -> Unknow scanner type !" << endl);
445  return 1;
446  }
447 
448  // Instantiate geometry
450  {
451  Cerr("***** sScannerManager::InstantiateScanner() -> An error occurred while instanciating the Scanner object !" << endl);
452  return 1;
453  }
454 
455  // End
456  return 0;
457 }
458 
459 // =====================================================================
460 // ---------------------------------------------------------------------
461 // ---------------------------------------------------------------------
462 // =====================================================================
463 /*
464  \fn BuildLUT()
465  \brief Call the eponym function of the scanner class
466  \return 0 if success. Positive value otherwise
467 */
469 {
471 
472  // Verbose
473  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::BuildLUT() -> Generate the geometric Look-Up Table"<< endl);
474 
475  // Generate LUT
477  {
478  Cerr("***** sScannerManager::BuildLUT() -> A problem occurred while generating/reading the LUT !" << endl);
479  return 1;
480  }
481 
482  // End
483  return 0;
484 }
485 
486 // =====================================================================
487 // ---------------------------------------------------------------------
488 // ---------------------------------------------------------------------
489 // =====================================================================
490 /*
491  \fn GetAvailableScanners
492  \param ap_scannerNames : vector list of string to recover the available scanner names
493  \brief Gather all the names of the header files (.geom & .hscan)
494  in the repository folder in the vector<string> passed in parameter
495  \return 0 if sucess, positive value otherwise
496 */
497 int sScannerManager::GetAvailableScanners(vector<string> *ap_scannerNames)
498 {
500 
501  // Verbose
502  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetAvailableScanners() -> Scan the scanner configuration directory"<< endl);
503 
504  // Initialize directory
505  DIR *respository_dir;
506  struct dirent *ent;
507  string str_geom(".geom"), str_hscan(".hscan");
508  string scanner_repository = sOutputManager::GetInstance()->GetPathToConfigDir() + "scanner" + OS_SEP;
509 
510  // Open directory
511  if ((respository_dir = opendir(scanner_repository.c_str())) != NULL)
512  {
513  // Print all the files and directories within the repository directory
514  while ((ent = readdir (respository_dir)) != NULL)
515  {
516  string scanner_name = ent->d_name;
517  // Get rid of backup files in linux
518  if(scanner_name.at(scanner_name.size()-1) != '~')
519  // .geom or .hscan file found
520  if(scanner_name.find(str_geom)!=string::npos || scanner_name.find(str_hscan)!=string::npos )
521  {
522  ap_scannerNames->push_back(scanner_name);
523  }
524  }
525  // Close directory
526  closedir (respository_dir);
527  }
528  else
529  {
530  Cerr("***** sScannerManager::GetAvailableScanners() -> Could not open the repository directory at: " << scanner_repository << endl);
531  return 1;
532  }
533 
534  // End
535  return 0;
536 }
537 
538 
539 
540 
541 // =====================================================================
542 // ---------------------------------------------------------------------
543 // ---------------------------------------------------------------------
544 // =====================================================================
552 int sScannerManager::GetModalityFromString(string a_systemStr)
553 {
554  if( a_systemStr == "PET" )
555  return SCANNER_PET;
556  else if( a_systemStr == "SPECT_PINHOLE" )
557  return SCANNER_SPECT_PINHOLE;
558  else if( a_systemStr == "SPECT_CONVERGENT" )
560  else if( a_systemStr == "CT" )
561  return SCANNER_CT;
562  else if( a_systemStr == "SINOGRAM" )
563  return SCANNER_SINOGRAM;
564  else
565  return SCANNER_UNKNOWN;
566 
567  return SCANNER_UNKNOWN;
568 }
569 
570 
571 
572 
573 // =====================================================================
574 // ---------------------------------------------------------------------
575 // ---------------------------------------------------------------------
576 // =====================================================================
577 /*
578  \fn GetScannerLayerNbRings
579  \param a_layer : layer index
580  \brief Ask the number of rings to the scanner object for a specific layer.
581  Returns an error if this information is not available for the scanner type of the object (eg : SPECT systems)
582  \return The number of rings in the system if success. NEGATIVE value otherwise
583 
584 int sScannerManager::GetScannerLayerNbRings(int a_layer)
585 {
586  DEBUG_VERBOSE(m_verbose,VERBOSE_DEBUG_LIGHT)
587 
588  // Verbose
589  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetScannerLayerNbRings() -> For layer " << a_layer << endl);
590 
591  // Works only for PET scanners
592  if (mp_Scanner->GetScannerType() == SCANNER_PET)
593  {
594  // Get the number of rings
595  int nb_rings = mp_Scanner->GetScannerLayerNbRings(a_layer);
596  // Check for error
597  if (nb_rings <= 0)
598  {
599  Cerr("***** sScannerManager::GetScannerLayerNbRings() -> Error when trying to get the number of rings in the system for the crystal layer " << a_layer+1 << " !" << endl);
600  return -1;
601  }
602  else return nb_rings;
603  }
604  else
605  {
606  Cerr("***** sScannerManager::GetScannerLayerNbRings() -> This function is only available for PET scanners !" << endl);
607  return -1;
608  }
609 }
610 */
611 
612 // =====================================================================
613 // ---------------------------------------------------------------------
614 // ---------------------------------------------------------------------
615 // =====================================================================
616 
617 int sScannerManager::GetSPECTSpecificParameters(uint16_t* ap_nbOfProjections,
618  uint16_t* ap_nbHeads,
619  FLTNB* ap_acquisitionZoom,
620  uint16_t* ap_nbOfBins,
621  FLTNB* ap_pixSizeXY,
622  FLTNB*& ap_angles,
623  FLTNB*& ap_CORtoDetectorDistance,
624  int* ap_headRotDirection)
625 {
627 
628  // Verbose
629  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetSPECTSpecificParameters() -> Get acquisition dependent parameters"<< endl);
630 
631  // Check modality
633  {
634  Cerr("***** sScannerManager::GetSPECTSpecificParameters()-> The scanner object is not of SPECT type !" << endl);
635  return 1;
636  }
637  else
638  {
639  // TODO: SS: remove this function from the vScanner, let it be specific to the SPECT scanner and then do a dynamic_cast here
640  // and do the same for all functions declared in vScanner as virtual but that are entirely specific !
641  if (mp_Scanner->GetSPECTSpecificParameters(ap_nbOfProjections, ap_nbHeads, ap_acquisitionZoom, ap_nbOfBins, ap_pixSizeXY, ap_angles, ap_CORtoDetectorDistance, ap_headRotDirection) )
642  {
643  Cerr("***** sScannerManager::GetSPECTSpecificParameters()-> A problem occurred while retrieving SPECT parameters from the scanner object !" << endl);
644  return 1;
645  }
646  }
647  return 0;
648 }
649 
650 // =====================================================================
651 // ---------------------------------------------------------------------
652 // ---------------------------------------------------------------------
653 // =====================================================================
654 /*
655  \fn GetCTSpecificParameters (Reconstruction)
656  \param ap_nbOfProjections : number of views/projections
657  \param ap_angles : an array containing angles for each view
658  \param ap_headRotDirection : head rotation direction
659  \brief Transfer geometric information recovered from the datafile to the scanner object, by copy of pointers
660  \return 0 if success, positive value otherwise
661 */
662 int sScannerManager::GetCTSpecificParameters(uint16_t* ap_nbOfProjections,
663  FLTNB*& ap_angles,
664  int* ap_headRotDirection)
665 {
667 
668  // Verbose
669  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetCTSpecificParameters() -> Get acquisition dependent parameters"<< endl);
670 
671  // Check modality
673  {
674  Cerr("***** sScannerManager::GetCTSpecificParameters()-> The scanner object is not of CT type !" << endl);
675  return 1;
676  }
677  else
678  {
679  // TODO: SS: remove this function from the vScanner, let it be specific to the SPECT scanner and then do a dynamic_cast here
680  // and do the same for all functions declared in vScanner as virtual but that are entirely specific !
681  if (mp_Scanner->GetCTSpecificParameters(ap_nbOfProjections, ap_angles, ap_headRotDirection) )
682  {
683  Cerr("***** sScannerManager::GetCTSpecificParameters()-> A problem occurred while retrieving CT parameters from the scanner object !" << endl);
684  return 1;
685  }
686  }
687  return 0;
688 }
689 
690 // =====================================================================
691 // ---------------------------------------------------------------------
692 // ---------------------------------------------------------------------
693 // =====================================================================
694 /*
695  \fn PROJ_GetModalityStopValueMainLoop
696  \brief Get the stop value for the main loop of analytic projection depending on the modality
697  \return the required stop value if success, NEGATIVE value otherwise
698  \todo Cases for CT and sinogram scanner types
699 */
701 {
703 
704  if (m_verbose>=VERBOSE_DEBUG_NORMAL) Cout("sScannerManager::PROJ_GetModalityStopValueMainLoop ..."<< endl);
705 
707  return mp_Scanner->GetSystemNbElts();
710  return (int64_t)mp_Scanner->PROJ_GetSPECTNbProjections(); // cast from uint16_t to int
711  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
712  {
713  // TODO
714  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for CT yet!" << endl);
715  return -1;
716  }
718  {
719  // TODO + should call a GetType() like function for scanner defined as a sinogram
720  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for Sinogram scanner yet!" << endl);
721  return -1;
722  }
723  else
724  {
725  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Unknown scanner type!" << endl);
726  return -1;
727  }
728 
729  return 0;
730 }
731 
732 // =====================================================================
733 // ---------------------------------------------------------------------
734 // ---------------------------------------------------------------------
735 // =====================================================================
736 /*
737  \fn PROJ_GetModalityStartValueInnerLoop
738  \param a_elt1 : Current nb of processed crystals (PET), projections (SPECT)
739  \brief Get the start value for the inner loop of analytic projection depending on the modality
740  \return the required stop value if success, NEGATIVE value otherwise
741  \todo Cases for CT and sinogram scanner types
742  \todo Precise with SS on which index SPECT inner loop should be done
743 */
745 {
747 
749  {
750  return a_elt1+1;
751  }
754  {
755  return 0; // (first crystal)
756  // TODO SS: here the inner loop should be done on the number of views
757  }
758  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
759  {
760  // TODO
761  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for CT yet!" << endl);
762  return -1;
763  }
765  {
766  // TODO + should call a GetType() like function for scanner defined as a sinogram
767  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for Sinogram scanner yet!" << endl);
768  return -1;
769  }
770  else
771  {
772  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Unknown scanner type!" << endl);
773  return -1;
774  }
775 
776  return 0;
777 }
778 
779 // =====================================================================
780 // ---------------------------------------------------------------------
781 // ---------------------------------------------------------------------
782 // =====================================================================
783 /*
784  \fn PROJ_GetCurrentProgression
785  \param a_elt1 : Current nb of processed #1 crystals (PET), projections (SPECT)
786  \param a_elt2 : Current nb of processed #2 crystals (PET), crystals (SPECT)
787  \param ap_nbEltsArray : Total number of elements processed for each #1 crystals (PET/CT systems)
788  \param a_nbDynImgProcessed
789  \brief Get numerator value according to the modality to compute percent progression during the analytical projection process
790  \return the required progression value if success, negative value otherwise
791  \todo Cases for CT and sinogram scanner types
792  \todo Optimize this, for now it's quite a lot of operation for each couple of elements
793  \todo Check everything is ok for 3D/4D PET and SPECT
794 */
795 int64_t sScannerManager::PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t* ap_nbEltsArray, uint16_t a_nbDynImgProcessed)
796 {
798 
799  // TODO : optimization, maybe too much operations for each couple of elements
801  {
802  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
803 
804  return ap_nbEltsArray[a_elt1]+a_elt2+1 +
805  (int64_t)(a_nbDynImgProcessed)* nb_total_elts*nb_total_elts/2;
806 
807  }
810  {
811  return a_elt2
812  + a_elt1*mp_Scanner->GetSystemNbElts()
813  + (int64_t)(a_nbDynImgProcessed) * mp_Scanner->GetSystemNbElts();
814  }
815  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
816  {
817  //TODO
818  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for CT yet!" << endl);
819  return -1;
820  }
822  {
823  //TODO + should call a GetType() like function for scanner defined as a sinogram
824  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for Sinogram scanner yet!" << endl);
825  return -1;
826  }
827  else
828  {
829  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Unknown scanner type!" << endl);
830  return -1;
831  }
832 }
833 
834 // =====================================================================
835 // ---------------------------------------------------------------------
836 // ---------------------------------------------------------------------
837 // =====================================================================
838 /*
839  \fn PROJ_GetProgressionFinalValue
840  \brief Get numerator value according to the modality to compute percent progression during the projection process
841  \return the required progression value if success, negative value otherwise
842  \todo Cases for CT and sinogram scanner types
843 */
845 {
847 
849  {
850  //return mp_Scanner->GetSystemNbElts();
851  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
852  return nb_total_elts*nb_total_elts/2;
853  }
856  {
857  return (int64_t)mp_Scanner->PROJ_GetSPECTNbProjections()*mp_Scanner->GetSystemNbElts(); // cast from uint16_t to int
858  }
859  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
860  {
861  //TODO
862  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for CT yet!" << endl);
863  return -1;
864  }
866  {
867  //TODO + should call a GetType() like function for scanner defined as a sinogram
868  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for Sinogram scanner yet!" << endl);
869  return -1;
870  }
871  else
872  {
873  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Unknown scanner type!" << endl);
874  return -1;
875  }
876 }
877 
878 // =====================================================================
879 // ---------------------------------------------------------------------
880 // ---------------------------------------------------------------------
881 // =====================================================================
882 /*
883  \fn PROJ_SetPETSpecificParameters (Analytic Projection)
884  \param a_maxAxialDiffmm : max axial difference in mm between 2 crystals forming a lor
885  \brief Deliver to the PET scanner object all informations provided from the datafile header
886  \return 0 if success, positive value otherwise
887  \todo How to handle systems with several layer of rings ?
888 */
890 {
892 
893  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetPETSpecificParameters ..."<< endl);
894 
896  {
897  Cerr("***** sScannerManager::SetPETSpecificParameters() -> The scanner object is not of PET type !" << endl);
898  return 1;
899  }
900  else
901  {
902  mp_Scanner->SetPETMaxAxialDiffmm(a_maxAxialDiffmm);
903  }
904 
905  return 0;
906 }
907 
908 // =====================================================================
909 // ---------------------------------------------------------------------
910 // ---------------------------------------------------------------------
911 // =====================================================================
912 /*
913  \fn PROJ_GetPETSpecificParameters (Analytic Projection)
914  \param ap_maxRingDiff : maximal axial difference in mm between 2 crystals forming a lor
915  \brief Transfer addresses to each geometric parameter of the PET scanner objets to the corresponding pointer of the datafile passed as argument
916  \return 0 if success, positive value otherwise
917  \todo How to handle systems with several layer of rings ?
918 */
920 {
922 
923  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_GetPETSpecificParameters ..."<< endl);
924 
926  {
927  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
928  return 1;
929  }
930  else
931  {
932  // Negative value means no ring diff restriction
933  FLTNB max_ring_diff = -1.;
934 
935  if (mp_Scanner->PROJ_GetPETSpecificParameters(&max_ring_diff) )
936  {
937  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> A problem occurred while retrieving PET parameters from the scanner object !" << endl);
938  return 1;
939  }
940 
941  *ap_maxRingDiff = max_ring_diff;
942  }
943  return 0;
944 }
945 
946 // =====================================================================
947 // ---------------------------------------------------------------------
948 // ---------------------------------------------------------------------
949 // =====================================================================
950 /*
951  \fn PROJ_SetSPECTSpecificParameters (Analytic Projection)
952  \param ap_nbOfBins : 2 elements array containing transaxial number of bins
953  \param a_nbOfProjections : number of views/projections
954  \param a_firstAngle : angle of the first view
955  \param a_lastAngle : angle of the last view
956  \param ap_projectionAngles : an array containing angles for each view
957  \param a_CORtoDetectorDistance : a distance between the center of rotation and the detector
958  \param a_RotDirection : Rotation direction of the head (clockwise/counter-clockwise)
959  \brief Deliver to the SPECT scanner object all informations provided from the acquisition parameters
960  \details For analytical projection, this data is provided from the command-line options
961  \return 0 if success, positive value otherwise
962 */
963 int sScannerManager::PROJ_SetSPECTSpecificParameters(uint16_t* ap_nbOfBins,
964  uint32_t a_nbOfProjections,
965  FLTNB a_firstAngle,
966  FLTNB a_stepAngle,
967  FLTNB* ap_projectionAngles,
968  FLTNB a_CORtoDetectorDistance,
969  string a_rotDirection)
970 {
972 
973  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetSPECTSpecificParameters ..."<< endl);
974 
975  // Return error if wrong modality
977  {
978  Cerr("***** sScannerManager::SetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
979  return 1;
980  }
981  else
982  {
983  // Nb bins
984  mp_Scanner->PROJ_SetSPECTNbBins(ap_nbOfBins);
985 
986  // Nb projections
987  if(a_nbOfProjections == 0)
988  {
989  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT analytic projection requires an user-specified number of projections !" << endl);
990  return 1;
991  }
992 
993  mp_Scanner->PROJ_SetSPECTNbProjections(a_nbOfProjections);
994 
995 
996  // Projection angles initialized with either each angles, or calculated from first/last angle
997  // By default, we chose the user-provided custom initialization for SPECT projection angles
998  // If not initialized, we computed them from first/last angle
999  if(ap_projectionAngles == NULL)
1000  {
1001  // If no custom initialization have been provided, then we check if we have first and last angles values for automatic initialization of the projection angles
1002  if(a_firstAngle<0 || a_stepAngle<0)
1003  {
1004  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT projection requires to set the projection angles using either the '-SPECT_ang' or '-SPECT_c_ang' options !" << endl);
1005  return 1;
1006  }
1007  else
1008  {
1009  // Fill the SPECT_projection_angles array
1010  ap_projectionAngles = new FLTNB[a_nbOfProjections];
1011  ap_projectionAngles[0] = a_firstAngle;
1012 
1013  for(uint32_t a=1 ; a<a_nbOfProjections ; a++)
1014  ap_projectionAngles[a] = ap_projectionAngles[a-1] + a_stepAngle;
1015  }
1016  }
1017 
1018  if(mp_Scanner->PROJ_SetSPECTAngles(ap_projectionAngles) )
1019  {
1020  Cerr("***** sScannerManager::SetSPECTAngles() -> An error occurred while trying to initialize SPECT projection angles !" << endl);
1021  return 1;
1022  }
1023 
1024  // CORtoDetectorDistance
1025  if(mp_Scanner->PROJ_SetSPECTCORtoDetectorDistance(a_CORtoDetectorDistance) )
1026  {
1027  Cerr("***** sScannerManager::SetPETSpecificParameters() -> An error occurred while trying to initialize SPECT distance between center of rotation to detectors !" << endl);
1028  return 1;
1029  }
1030 
1031  // Set rotation direction
1032  mp_Scanner->SetRotDirection(a_rotDirection);
1033  }
1034 
1035  return 0;
1036 }
virtual int PROJ_SetSPECTNbBins(uint16_t *ap_nbOfBins)
int GetAvailableScanners(vector< string > *ap_scannerNames)
virtual int PROJ_SetSPECTNbProjections(uint32_t a_nbOfProjections)
int64_t PROJ_GetModalityStartValueInnerLoop(int64_t a_elt1)
virtual int PROJ_GetPETSpecificParameters(FLTNB *ap_maxRingDiff)
virtual int SetPETMaxAxialDiffmm(FLTNB a_maxAxialDiffmm)
#define Cerr(MESSAGE)
int FindScannerSystem(string a_scannerName)
virtual int PROJ_SetSPECTAngles(FLTNB *ap_projectionAngles)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
static struct dirent * readdir(DIR *dirp)
std::map< string, maker_scanner > mp_listOfScannerTypes
int64_t PROJ_GetProgressionFinalValue()
Get numerator value according to the modality to compute percent progression during the projection pr...
int GetModalityFromString(string a_systemStr)
static sScannerManager * mp_Instance
virtual uint16_t PROJ_GetSPECTNbProjections()
return the total number of projections for a SPECT acquisition
virtual int GetGeometricInfoFromDataFile(string a_path)=0
virtual int CheckParameters()=0
This function is implemented in child classes. Check that all parameters have been correctly initia...
virtual int BuildLUT(bool a_scannerFileIsLUT)=0
int GetSPECTSpecificParameters(uint16_t *ap_nbOfProjections, uint16_t *ap_nbHeads, FLTNB *ap_acquisitionZoom, uint16_t *ap_nbOfBins, FLTNB *ap_pixSizeXY, FLTNB *&ap_angles, FLTNB *&ap_CORtoDetectorDistance, int *ap_headRotDirection)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
virtual int Initialize()=0
This function is implemented in child classes. Check initialization and set several parameters to t...
static DIR * opendir(const char *dirname)
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.
sScannerManager()
sScannerManager constructor.
static sAddonManager * GetInstance()
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ID)
#define SCANNER_SPECT_CONVERGENT
virtual int SetRotDirection(string a_rotDirection)
int BuildLUT()
Call the eponym function of the scanner class.
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
Singleton class that Instantiate and initialize the scanner object.
void Describe()
A function used to describe the generic parts of the datafile.
int PROJ_SetPETSpecificParameters(FLTNB a_maxAxialDiffmm)
int64_t PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t *ap_nbEltsArray, uint16_t a_nbDynImgProcessed)
int ShowScannersDescription()
Get the description associated to the different scanners and print all on screen. Walk through the ...
~sScannerManager()
sScannerManager destructor.
#define KEYWORD_MANDATORY
int PROJ_SetSPECTSpecificParameters(uint16_t *ap_nbOfBins, uint32_t a_nbOfProjections, FLTNB a_firstAngle, FLTNB a_stepAngle, FLTNB *ap_projectionAngles, FLTNB a_CORtoDetectorDistance, string a_rotDirection)
virtual int GetSPECTSpecificParameters(uint16_t *ap_nbOfProjections, uint16_t *ap_nbHeads, FLTNB *ap_acquisitionZoom, uint16_t *ap_nbOfBins, FLTNB *ap_pixSizeXY, FLTNB *&ap_angles, FLTNB *&ap_CORtoDetectorDistance, int *ap_headRotDirection)
void SetVerbose(int a_verboseLevel)
oImageDimensionsAndQuantification * mp_ID
int Initialize()
Initialization : .
virtual int PROJ_SetSPECTCORtoDetectorDistance(FLTNB a_CORtoDetectorDistance)
virtual int GetSystemNbElts()=0
This is a pure virtual method that must be implemented by children.
void ShowHelpScanner()
Show help about all implemented scanners.
static int closedir(DIR *dirp)
void Describe()
Call the eponym function from the Scanner object (if initialized)
int64_t PROJ_GetModalityStopValueMainLoop()
Get the stop value for the main loop of analytic projection depending on the modality.
virtual int Instantiate(bool a_scannerFileIsLUT)=0
int GetCTSpecificParameters(uint16_t *ap_nbOfProjections, FLTNB *&ap_angles, int *ap_headRotDirection)
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)
int PROJ_GetPETSpecificParameters(FLTNB *ap_maxAxialDiffmm)
#define Cout(MESSAGE)
virtual int GetCTSpecificParameters(uint16_t *ap_nbOfProjections, FLTNB *&ap_angles, int *ap_detectorRotDirection)
Generic class for scanner objects.
int InitScannerWithFile(string a_pathScanFile, string a_scannerName, int a_fileTypeFlag)