CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/dynamic/oDynamicModelManager.cc
Go to the documentation of this file.
1 
8 #include "oDynamicModelManager.hh"
9 #include "sAddonManager.hh"
10 
11 // =====================================================================
12 // ---------------------------------------------------------------------
13 // ---------------------------------------------------------------------
14 // =====================================================================
15 /*
16  \fn oDynamicModelManager
17  \brief Constructor of oDynamicModelManager. Simply set all data members to default values.
18 */
20 {
21  // Image dimensions
22  mp_ID = NULL;
23  // Options for each model type
24  m_options = "";
25 
26  // Model object and associated bool
27  mp_DynamicModel = NULL;
28  m_useModel = false;
30 
31  // Diagonal basis functions
35 
39 
40  // Verbosity
41  m_verbose = -1;
42  m_checked = false;
43  m_initialized = false;
44 }
45 
46 // =====================================================================
47 // ---------------------------------------------------------------------
48 // ---------------------------------------------------------------------
49 // =====================================================================
50 /*
51  \fn ~oDynamicModelManager
52  \brief Destructor of oDynamicModelManager. Free memory from all allocated tabs.
53 */
55 {
56  // Delete model objects
57  if (mp_DynamicModel) delete mp_DynamicModel;
58 }
59 
60 // =====================================================================
61 // ---------------------------------------------------------------------
62 // ---------------------------------------------------------------------
63 // =====================================================================
64 /*
65  \fn CheckParameters
66  \brief This function is used to check parameters after the latter
67  have been all set using Set functions.
68  \return 0 if success, positive value otherwise.
69 */
71 #ifdef CASTOR_VERBOSE
72  if (m_verbose>=2) Cout("oDynamicModelManager::CheckParameters() ..."<< endl);
73 #endif
74 
75  // Check image dimensions
76  if (mp_ID == NULL) {
77  Cerr("***** oDynamicModelManager::CheckParameters() -> No image dimensions provided !" << endl);
78  return 1;
79  }
80  // Check if any options have been provided
81  //if (m_options =="")
82  //{
83  // Cerr("***** oDynamicModelManager::CheckParameters() -> No options provided !" << endl);
84  //return 1;
85  // }
86  // Check verbosity
87  if (m_verbose<0)
88  {
89  Cerr("***** oDynamicModelManager::CheckParameters() -> Wrong verbosity level provided !" << endl);
90  return 1;
91  }
92 
93  // Normal end
94  m_checked = true;
95  return 0;
96 }
97 
98 // =====================================================================
99 // ---------------------------------------------------------------------
100 // ---------------------------------------------------------------------
101 // =====================================================================
102 /*
103  \fn Initialize
104  \brief Set the dynamic model flag and instanciate/initialize model objects
105  through the ParseOptionsAndInitializeDeformations() private function.
106  \return 0 if success, positive value otherwise.
107 */
109 {
110  // Forbid initialization without check
111  if (!m_checked)
112  {
113  Cerr("***** oDynamicModelManager::Initialize() -> Must call CheckParameters() before Initialize() !" << endl);
114  return 1;
115  }
116  // Check options
117  if (m_options=="")
118  {
119  // If no options have been provided then no dynamic model will be used
120  m_initialized = true;
121  m_useModel = false;
122  // Set default diagonal Basis Functions.
124  mp_ID->SetTimeStaticFlag(true);
127  // Exit the dynamic manager after that
128  return 2;
129  }
130 
131  // Else we have some model options
132  m_useModel = true;
133 
134  // Verbose
135  if (m_verbose>=1) Cout("oDynamicModelManager::Initialize() -> Initialize models" << endl);
136 
137  // Parse model options and initialize them
139  {
140  Cerr("***** oDynamicModelManager::Initialize() -> A problem occurred while parsing model options and initializing them !" << endl);
141  return 1;
142  }
143 
144  // Normal end
145  m_initialized = true;
146  return 0;
147 
148 }
149 
150 // =====================================================================
151 // ---------------------------------------------------------------------
152 // ---------------------------------------------------------------------
153 // =====================================================================
154 /*
155  \fn ParseOptionsAndInitializeProjectors
156  \brief Parse dynamic model options contained in the previously provided
157  strings. This function is called inside the Initialize() function.
158  \details Manage the options reading and initialize specific vDynamicModel
159  Options are a string containing first the name of the model,
160  then either a ':' and a configuration file specific to the model
161  - or - as many ',' as needed parameters for this model.
162  Specific pure virtual functions of the vDynamicModel are used to read parameters and initialize them.
163  \return 0 if success, positive value otherwise
164 */
166 {
167  #ifdef CASTOR_VERBOSE
168  if (m_verbose>=3) Cout("oDynamicModelManager::ParseOptionsAndInitializeModel ..."<< endl);
169  #endif
170 
171  string dynamic_model = "";
172  string list_options = "";
173  string file_options = "";
174 
175  // This is for the automatic initialization of the models
176  typedef vDynamicModel *(*maker_dynamic_model) ();
177 
178  // Get model's list from addon manager
179  std::map <string,maker_dynamic_model> list = sAddonManager::GetInstance()->mp_listOfDynamicModels;
180 
181  size_t colon, comma;
182 
183  // ---------------------------------------------------------------------------------------------------
184  // Manage model for respiratory motion
185  // ---------------------------------------------------------------------------------------------------
186 
187  // First, check if we have dynamic data
188  if (mp_ID->GetNbTimeFrames() <= 1 &&
189  mp_ID->GetNbRespGates() <= 1 &&
190  mp_ID->GetNbCardGates() <= 1)
191  {
192  Cerr("***** oDynamicModelManager::CheckParameters() -> Dynamic model should be used with more than one time frame/dynamic gate !" << endl);
193  return 1;
194  }
195 
196  // ______________________________________________________________________________
197  // Get the model name in the options and isolate the real model's options
198 
199  // Search for a colon ":", this indicates that a configuration file is provided after the model name
200  colon = m_options.find_first_of(":");
201  comma = m_options.find_first_of(",");
202 
203  // Case 1: we have a colon
204  if (colon!=string::npos)
205  {
206  // Get the model name before the colon
207  dynamic_model = m_options.substr(0,colon);
208  // Get the configuration file after the colon
209  file_options = m_options.substr(colon+1);
210  // List of options is empty
211  list_options = "";
212  }
213  // Case 2: we have a comma
214  else if (comma!=string::npos)
215  {
216  // Get the model name before the first comma
217  dynamic_model = m_options.substr(0,comma);
218  // Get the list of options after the first comma
219  list_options = m_options.substr(comma+1);
220  // Configuration file is empty
221  file_options = "";
222  }
223  // Case 3: no colon and no comma (a single model name)
224  else
225  {
226  // Get the model name
227  dynamic_model = m_options;
228  // Configuration file is empty
229  file_options = "";
230  // List of options is empty
231  list_options = "";
232  }
233 
234  // Create the model
235  if (list[dynamic_model]) mp_DynamicModel = list[dynamic_model]();
236  else
237  {
238  Cerr("***** oDynamicModelManager::ParseOptionsAndInitializeModel() -> Model '" << dynamic_model << "' does not exist !" << endl);
240  return 1;
241  }
244  // Provide configuration file if any
245  if (file_options!="" && mp_DynamicModel->ReadAndCheckConfigurationFile(file_options))
246  {
247  Cerr("***** oDynamicModelManager::ParseOptionsAndInitializeModel() -> A problem occurred while reading and checking frame dynamic model's configuration file !" << endl);
248  return 1;
249  }
250  // Provide options if any
251  if (list_options!="" && mp_DynamicModel->ReadAndCheckOptionsList(list_options))
252  {
253  Cerr("***** oDynamicModelManager::ParseOptionsAndInitializeModel() -> A problem occurred while parsing and reading frame dynamic model's options !" << endl);
254  return 1;
255  }
256  // Provide flag to know if the model has been called for use in reconstruction or post-reconstruction
258  // Check parameters
260  {
261  Cerr("***** oDynamicModelManager::ParseOptionsAndInitializeModel() -> A problem occurred while checking frame dynamic model parameters !" << endl);
262  return 1;
263  }
264  // Initialize the model
266  {
267  Cerr("***** oDynamicModelManager::ParseOptionsAndInitializeModel() -> A problem occurred while initializing frame dynamic model !" << endl);
268  return 1;
269  }
270  // Check if model specific BasisFunctions are required for the ImageDimensionsAndQuantification object (normaly the case for non-nested recons )
271  // if there is no requirement for model specific basis functions -> Set Diagonal Basis Functions (normaly the case for nested recons )
273  {
274  if(m_verbose>=2) Cout("oDynamicModelManager:: Setting Diagonal basis functions for the tomographic update "<< endl);
278 
279  }
280  // Case where specific basis functions are required
281  else
282  {
283  if(m_verbose>=2) Cout("oDynamicModelManager:: Seting model specific Time basis functions "<< endl);
286 
287  // At the moment all dynamic models relate to kinetic modeling, so seting other basis functions to diagonal
290 
291  // TODO: Validate this
292  // When the basis functions have been set in oImageDimensionsAndQuantification there is no further need for the dynamic model
293  m_useModel=false;
294  }
295 
296  // Normal end
297  return 0;
298 }
299 
300 // =====================================================================
301 // ---------------------------------------------------------------------
302 // ---------------------------------------------------------------------
303 // =====================================================================
304 /*
305  \fn ApplyDynamicModel
306  \param ap_ImageS : pointer to the ImageSpace
307  \param a_iteration : index of the actual iteration
308  \param a_subset : index of the actual subset
309  \brief Call successively EstimateModelParameters() ans EstimateImageWithModel()
310  functions of the dynamic model object if 'm_useModel' is on.
311  \return 0 if success, positive value otherwise
312 */
313 int oDynamicModelManager::ApplyDynamicModel(oImageSpace* ap_ImageS, int a_iteration, int a_subset)
314 {
315  #ifdef CASTOR_DEBUG
316  if (!m_initialized)
317  {
318  Cerr("***** oDynamicModelManager::ApplyDynamicModel() -> Called while not initialized !" << endl);
319  Exit(EXIT_DEBUG);
320  }
321  #endif
322 
323  if (m_useModel)
324  {
325  // Verbose
326  if(m_verbose>=2) Cout("oDynamicModelManager::ApplyDynamicModel ..."<< endl);
327 
328  // Estimate model parameters
329  if( mp_DynamicModel->EstimateModel(ap_ImageS, a_iteration, a_subset) )
330  {
331  Cerr("***** oDynamicModelManager::StepPostProcessInsideSubsetLoop() -> A problem occurred while applying dynamic model to current estimate images !" << endl);
332  return 1;
333  }
334 
335  // Generate the serie of dynamic images using the model parameters
336  if( mp_DynamicModel->EstimateImage(ap_ImageS, a_iteration, a_subset) )
337  {
338  Cerr("***** oDynamicModelManager::StepPostProcessInsideSubsetLoop() -> A problem occurred while applying dynamic model to current estimate images !" << endl);
339  return 1;
340  }
341  }
342 
343  return 0;
344 }
345 
346 // =====================================================================
347 // ---------------------------------------------------------------------
348 // ---------------------------------------------------------------------
349 // =====================================================================
350 /*
351  \fn SaveParametricImages
352  \param a_iteration : current iteration index
353  \param a_subset : current number of subsets (or -1 by default)
354  \brief Call SaveCoeffImages() function of the dynamic model object is
355  'm_useModel' is on, in order to save any parameter image
356  \return 0 if success, positive value otherwise
357 */
358 int oDynamicModelManager::SaveParametricImages(int a_iteration, int a_subset)
359 {
360  if (m_useModel)
361  {
362  // Verbose
363  if(m_verbose>=2) Cout("oDynamicModelManager::SaveParametricImages ..."<< endl);
364 
365  // Write output parametric images if required
367 
368  // Apply Masking if required
370  {
371  Cerr("***** oDynamicModelManager::SaveParametricImages() -> A problem occurred while trying to apply FOV masking on parametric images !" << endl);
372  return 1;
373  }
374 
375  // Save images
376  if (mp_DynamicModel->SaveParametricImages(a_iteration, a_subset))
377  {
378  Cerr("***** oDynamicModelManager::SaveParametricImages() -> A problem occurred while trying to save image coefficients !" << endl);
379  return 1;
380  }
381  }
382  return 0;
383 }
384 
386 {
387  // This function is used to set the BasisFunctions in ImageDimensionsAndQuantification to diagonal values
388  // Set the number of time basis functions to the number of frames
390  // Allocate the conversion matrix from basis functions to frames
391  m2p_timeBasisFunctions = (FLTNB **) malloc(m_nbTimeBasisFunctions * sizeof(FLTNB *));
392  for (int tbf = 0; tbf < m_nbTimeBasisFunctions; tbf++) {
393  m2p_timeBasisFunctions[tbf] = (FLTNB *) malloc(mp_ID->GetNbTimeFrames() * sizeof(FLTNB));
394  for (int fr = 0; fr < mp_ID->GetNbTimeFrames(); fr++) {
395  // Set diagonal to 1, the rest to 0
396  if (tbf == fr) m2p_timeBasisFunctions[tbf][fr] = 1.;
397  else m2p_timeBasisFunctions[tbf][fr] = 0.;
398  }
399  }
400  // In the diagonal case the number of time basis functions is always equal to the number of frames
401  mp_ID->SetNbTimeBasisFunctions(m_nbTimeBasisFunctions);
403  // Exit
404  return 0;
405 }
406 
408 {
409 
410  // This function is used to set the BasisFunctions in ImageDimensionsAndQuantification to diagonal values
411  // Set the number of respiratory basis functions to the number of frames
413  // Allocate the conversion matrix from basis functions to frames
414  m2p_respBasisFunctions = (FLTNB **) malloc(m_nbRespBasisFunctions * sizeof(FLTNB *));
415  for (int rbf = 0; rbf < m_nbRespBasisFunctions; rbf++) {
416  m2p_respBasisFunctions[rbf] = (FLTNB *) malloc(mp_ID->GetNbRespGates() * sizeof(FLTNB));
417  for (int rg = 0; rg < mp_ID->GetNbRespGates(); rg++) {
418  // Set diagonal to 1, the rest to 0
419  if (rbf == rg) m2p_respBasisFunctions[rbf][rg] = 1.;
420  else m2p_respBasisFunctions[rbf][rg] = 0.;
421  }
422  }
423  // Set the static flag to true, the number of basis functions and the basis functions
424  // TODO: Do I realy need to set this flag ?
425  mp_ID->SetRespStaticFlag(true);
426  mp_ID->SetNbRespBasisFunctions(m_nbRespBasisFunctions);
428  // Exit
429  return 0;
430 }
431 
433 {
434 //-------------------------------------------------------------------------------
435  // Diagonal Cardiac Basis Function - for the provided number of respiratory gates
436  // Set the number of cardiac basis functions to the number of cardiac gates
438  // Allocate the conversion matrix from cardiac basis functions to cardiac gates
439  m2p_cardBasisFunctions = (FLTNB**)malloc(mp_ID->GetNbCardGates()*sizeof(FLTNB*));
440  for (int cbf=0; cbf<m_nbCardBasisFunctions; cbf++)
441  {
442  m2p_cardBasisFunctions[cbf] = (FLTNB*)malloc(mp_ID->GetNbCardGates()*sizeof(FLTNB));
443  for (int cg=0; cg<mp_ID->GetNbCardGates(); cg++)
444  {
445  // Set diagonal to 1, the rest to 0
446  if (cbf==cg) m2p_cardBasisFunctions[cbf][cg] = 1.;
447  else m2p_cardBasisFunctions[cbf][cg] = 0.;
448  }
449  }
450  // Set the static flag to true, the number of basis functions and the basis functions
451  // TODO: Do I realy need to set this flag ?
452  mp_ID->SetCardStaticFlag(true);
453  mp_ID->SetNbCardBasisFunctions(m_nbCardBasisFunctions);
455  // Exit
456  return 0;
457 }
458 
459 // =====================================================================
460 // ---------------------------------------------------------------------
461 // ---------------------------------------------------------------------
462 // =====================================================================
int SetDiagonalCardBasisFunctions()
Set diagonal Cardiac Basis Functions for regular gated reconstruction.
virtual int CheckParameters()
This function is used to check parameters after the latter have been all set using Set functions...
void ShowHelpDynamicModel()
Show help about all implemented dynamic models.
#define Cerr(MESSAGE)
int ReadAndCheckConfigurationFile(string a_fileOptions)
std::map< string, maker_dynamic_model > mp_listOfDynamicModels
This is the mother class of dynamic model classes.
oImageDimensionsAndQuantification * mp_ID
virtual int ApplyOutputFOVMaskingOnParametricImages()
Mask the outside of the transaxial FOV based on the m_fovOutPercent.
void Exit(int code)
oDynamicModelManager()
Constructor of oDynamicModelManager. Simply set all data members to default values.
int Initialize()
Set the dynamic model flag and instanciate/initialize model objects through the ParseOptionsAndInitia...
static sAddonManager * GetInstance()
virtual int EstimateImage(oImageSpace *ap_Image, int a_ite, int a_sset)
int ParseOptionsAndInitializeModel()
Parse dynamic model options contained in the previously provided strings. This function is called ins...
virtual int EstimateModel(oImageSpace *ap_Image, int a_ite, int a_sset)
void SetUseModelInReconstruction(bool a_useModelInReconstruction)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
int SaveParametricImages(int a_iteration, int a_subset=-1)
int Initialize()
A public function used to initialize the dynamic model.
virtual int ReadAndCheckOptionsList(string a_listOptions)=0
int CheckParameters()
This function is used to check parameters after the latter have been all set using Set functions...
int SetDiagonalRespBasisFunctions()
Set diagonal Respiratory Basis Functions for regular gated reconstruction.
This class holds all the matrices in the image domain that can be used in the algorithm: image...
virtual void ComputeOutputParImage()
Compute output image using the m2p_parametricImages matrix Store the result in the m2p_outputParImage...
~oDynamicModelManager()
Destructor of oDynamicModelManager. Free memory from all allocated tabs.
int SetDiagonalTimeBasisFunctions()
Set diagonal Time Basis Functions for regular frame-by-frame reconstruction.
#define Cout(MESSAGE)
int SaveParametricImages(int a_iteration, int a_subset=-1)
int ApplyDynamicModel(oImageSpace *ap_ImageS, int a_iteration, int a_subset)