CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
oImageProcessingManager.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class oImageProcessingManager
4 
5  - separators: done
6  - doxygen: done
7  - default initialization: done
8  - CASTOR_DEBUG:
9  - CASTOR_VERBOSE:
10 */
11 
19 #include "sAddonManager.hh"
20 
21 // =====================================================================
22 // ---------------------------------------------------------------------
23 // ---------------------------------------------------------------------
24 // =====================================================================
25 
27 {
28  // Image dimensions
30  // Options
31  m_options = {};
32  // Image processing objects and associated bool
35  mp_applyForward = NULL;
36  mp_applyIntra = NULL;
37  mp_applyPost = NULL;
38  // Booleans
39  m_checked = false;
40  m_initialized = false;
41  // Verbosity
42  m_verbose = -1;
43 }
44 
45 // =====================================================================
46 // ---------------------------------------------------------------------
47 // ---------------------------------------------------------------------
48 // =====================================================================
49 
51 {
52  // Delete object
54  {
57  }
58 }
59 
60 // =====================================================================
61 // ---------------------------------------------------------------------
62 // ---------------------------------------------------------------------
63 // =====================================================================
64 
66 {
67  // Check image dimensions
69  {
70  Cerr("***** oImageProcessingManager::CheckParameters() -> No image dimensions provided !" << endl);
71  return 1;
72  }
73  // Check verbosity
74  if (m_verbose<0)
75  {
76  Cerr("***** oImageProcessingManager::CheckParameters() -> Wrong verbosity level provided !" << endl);
77  return 1;
78  }
79  // All set
80  m_checked = true;
81  // Normal end
82  return 0;
83 }
84 
85 // =====================================================================
86 // ---------------------------------------------------------------------
87 // ---------------------------------------------------------------------
88 // =====================================================================
89 
91 {
92  // Return when using MPI and mpi_rank is not 0
93  #ifdef CASTOR_MPI
94  int mpi_rank = 0;
95  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
96  if (mpi_rank!=0) return;
97  #endif
98  // Show help
99  cout << "------------------------------------------------------------------" << endl;
100  cout << "----- How to use an image processing module" << endl;
101  cout << "------------------------------------------------------------------" << endl;
102  cout << endl;
103  cout << "An image processing module is called through the -proc option. The provided argument describes the processing module to be used," << endl;
104  cout << "its options, and when to include it within the algorithm. The syntax of the argument must obey one of the three following options:" << endl;
105  cout << " proc::when (in this case, the default configuration file of the processing module is used to set the options values)" << endl;
106  cout << " proc:file.conf::when (in this case, the provided configuration is used)" << endl;
107  cout << " proc,param1,param2,...::when (in this case, the options values are directly provided in the argument)" << endl;
108  cout << "In any case, the description of the options specific to each processing module, their order in the list and their configuration" << endl;
109  cout << "files syntax are provided in the specific help of each module." << endl;
110  cout << "The 'when' parameter is an argument describing when to include the processing module within the algorithm. It is a list of keywords" << endl;
111  cout << "separating by commas. The following keywords can be used:" << endl;
112  cout << " forward (include module into forward model; the processed current estimate is forward-projected)" << endl;
113  cout << " post (apply module before saving the image; the processed image is not put back as the estimate for the next update)" << endl;
114  cout << " intra (apply module to the updated image use it as the current estimate for the next update)" << endl;
115  cout << endl;
116 }
117 
118 // =====================================================================
119 // ---------------------------------------------------------------------
120 // ---------------------------------------------------------------------
121 // =====================================================================
122 
124 {
125  // Check if parameters have been checked
126  if (!m_checked)
127  {
128  Cerr("***** oImageProcessingManager::Initialize() -> Parameters have not been checked ! Please call CheckParameters() before." << endl);
129  return 1;
130  }
131  // Case with no options (no image processing module)
132  if (m_options.size()==0)
133  {
134  m_initialized = true;
135  return 0;
136  }
137  // Verbose
138  if (m_verbose>=1) Cout("oImageProcessingManager::Initialize() -> Initialize image processing modules" << endl);
139  // Parse image processing modules options and initialize them
141  {
142  Cerr("***** oImageProcessingManager::Initialize() -> A problem occured while parsing image processing modules options and initializing them !" << endl);
143  return 1;
144  }
145  // All set
146  m_initialized = true;
147  // Normal end
148  return 0;
149 }
150 
151 // =====================================================================
152 // ---------------------------------------------------------------------
153 // ---------------------------------------------------------------------
154 // =====================================================================
155 
157 {
158  // ===================================================================
159  // First get the number of processing modules from the list of options
160  // ===================================================================
161 
163 
164  // Allocate the tables
166  mp_applyForward = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
167  mp_applyIntra = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
168  mp_applyPost = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
169 
170  // ===================================================================
171  // Then we loop over all modules, read options and initialize them
172  // ===================================================================
173 
174  // This is for the automatic initialization of the processing modules
175  typedef vImageProcessingModule *(*maker_image_processing_module) ();
176  // Get image processing modules list from addon manager
177  std::map <string,maker_image_processing_module> list = sAddonManager::GetInstance()->mp_listOfImageProcessingModules;
178 
179  // Start the loop
180  for (int c=0; c<m_nbImageProcessingModules; c++)
181  {
182  // Default initializations
183  m2p_ImageProcessingModules[c] = NULL;
184  mp_applyForward[c] = false;
185  mp_applyIntra[c] = false;
186  mp_applyPost[c] = false;
187 
188  // ___________________________________________________________________________________
189  // Search for a double-colon and isolate the module's options from the 'when' actions
190 
191  size_t double_colon = m_options[c].find_first_of("::");
192 
193  // Send an error if no double-colon
194  if (double_colon==string::npos)
195  {
196  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Wrong syntax in the " << c+1 << "th image processing module !" << endl);
197  Cerr(" No double-colon \"::\" found." << endl);
198  ShowCommonHelp();
199  return 1;
200  }
201 
202  // Separate the two arguments
203  string proc_part_options = m_options[c].substr(0,double_colon);
204  string when_part_options = m_options[c].substr(double_colon+2);
205 
206  // ___________________________________________________________________________________
207  // Get the module name in the options and isolate the actual module's options
208 
209  // Useful strings
210  string module = "";
211  string list_options = "";
212  string file_options = "";
213 
214  // Search for a colon ":", this indicates that a configuration file is provided after the module's name
215  size_t colon = proc_part_options.find_first_of(":");
216  size_t comma = proc_part_options.find_first_of(",");
217 
218  // Case 1: we have a colon
219  if (colon!=string::npos)
220  {
221  // Get the image processing module name before the colon
222  module = proc_part_options.substr(0,colon);
223  // Get the configuration file after the colon
224  file_options = proc_part_options.substr(colon+1);
225  // List of options is empty
226  list_options = "";
227  }
228  // Case 2: we have a comma
229  else if (comma!=string::npos)
230  {
231  // Get the image processing module name before the first comma
232  module = proc_part_options.substr(0,comma);
233  // Get the list of options after the first comma
234  list_options = proc_part_options.substr(comma+1);
235  // Configuration file is empty
236  file_options = "";
237  }
238  // Case 3: no colon and no comma (a single image processing module name)
239  else
240  {
241  // Get the image processing module name
242  module = proc_part_options;
243  // List of options is empty
244  list_options = "";
245  // Build the default configuration file
246  file_options = sOutputManager::GetInstance()->GetPathToConfigDir() + "/processing/" + module + ".conf";
247  }
248 
249  // ___________________________________________________________________________________
250  // Read the 'when' actions
251 
252  // Loop while commas are found
253  while ((comma=when_part_options.find_first_of(",")) != string::npos)
254  {
255  // Extract the first option
256  string option = when_part_options.substr(0,comma);
257  // Extract the rest
258  when_part_options = when_part_options.substr(comma+1);
259  // Check the meaning of the option
260  if (option=="forward") {mp_applyForward[c] = true;}
261  else if (option=="post") {mp_applyPost[c] = true;}
262  else if (option=="intra") {mp_applyIntra[c] = true;}
263  else
264  {
265  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << option << "' provided in options list !" << endl);
266  ShowCommonHelp();
267  return 1;
268  }
269  }
270  // Last option
271  if (when_part_options=="forward") {mp_applyForward[c] = true;}
272  else if (when_part_options=="post") {mp_applyPost[c] = true;}
273  else if (when_part_options=="intra") {mp_applyIntra[c] = true;}
274  else
275  {
276  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << when_part_options << "' provided in options list !" << endl);
277  ShowCommonHelp();
278  return 1;
279  }
280 
281  // ______________________________________________________________________________
282  // Create processing module and call associated functions
283 
284  // Create the image processing module
285  if (list[module]) m2p_ImageProcessingModules[c] = list[module]();
286  else
287  {
288  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Image processing module '" << module << "' does not exist !" << endl);
290  return 1;
291  }
292  // Set parameters
295  // Provide configuration file if any
296  if (file_options!="" && m2p_ImageProcessingModules[c]->ReadConfigurationFile(file_options))
297  {
298  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while reading and checking configuration file for image processing module '" << module << "' !" << endl);
299  return 1;
300  }
301  // Provide options if any
302  if (list_options!="" && m2p_ImageProcessingModules[c]->ReadOptionsList(list_options))
303  {
304  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while parsing and reading options list for image processing module '" << module << "' !" << endl);
305  return 1;
306  }
307  // Check parameters
309  {
310  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while checking parameters for image processing module '" << module << "' !" << endl);
311  return 1;
312  }
313  // Initialize the image processing module
315  {
316  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while initializing image processing module '" << module << "' !" << endl);
317  return 1;
318  }
319  // Check if processing module is dynamic and if dynamic basis functions are used, then it is not compatible if used inside the reconstruction (all but 'post')
320  bool intra_reconstruction = mp_applyForward[c] || mp_applyIntra[c];
324  if (intra_reconstruction && (condition1 || condition2 || condition3))
325  {
326  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Cannot use dynamic image processing module '" << module << "' along with dynamic basis functions inside the reconstruction !" << endl);
327  return 1;
328  }
329  }
330 
331  // Normal end
332  return 0;
333 }
334 
335 // =====================================================================
336 // ---------------------------------------------------------------------
337 // ---------------------------------------------------------------------
338 // =====================================================================
339 
341 {
342  #ifdef CASTOR_DEBUG
343  // Check if initialized
344  if (!m_initialized)
345  {
346  Cerr("***** oImageProcessingManager::ApplyProcessingForward() -> Called while not initialized !" << endl);
347  return 1;
348  }
349  #endif
350  // Loop on processing modules
351  for (int c=0; c<m_nbImageProcessingModules; c++)
352  {
353  // Apply it only if asked for
354  if (mp_applyForward[c])
355  {
356  // Verbose
357  if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingForward() -> Apply image processing module " << c+1 << " to forward image" << endl);
358  // Get the pointer to the image
359  FLTNB**** image = ap_ImageSpace->m4p_forwardImage;
360  // Apply convolution
362  }
363  }
364  // Normal end
365  return 0;
366 }
367 
368 // =====================================================================
369 // ---------------------------------------------------------------------
370 // ---------------------------------------------------------------------
371 // =====================================================================
372 
374 {
375  #ifdef CASTOR_DEBUG
376  // Check if initialized
377  if (!m_initialized)
378  {
379  Cerr("***** oImageProcessingManager::ApplyProcessingIntra() -> Called while not initialized !" << endl);
380  return 1;
381  }
382  #endif
383  // Loop on processing modules
384  for (int c=0; c<m_nbImageProcessingModules; c++)
385  {
386  // Apply it only if asked for
387  if (mp_applyIntra[c])
388  {
389  // Verbose
390  if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingIntra() -> Apply image processing module " << c+1 << " to current image" << endl);
391  // Get the pointer to the image
392  FLTNB**** image = ap_ImageSpace->m4p_image;
393  // Apply processing module
395  }
396  }
397  // Normal end
398  return 0;
399 }
400 
401 // =====================================================================
402 // ---------------------------------------------------------------------
403 // ---------------------------------------------------------------------
404 // =====================================================================
405 
407 {
408  #ifdef CASTOR_DEBUG
409  // Check if initialized
410  if (!m_initialized)
411  {
412  Cerr("***** oImageProcessingManager::ApplyProcessingPost() -> Called while not initialized !" << endl);
413  return 1;
414  }
415  #endif
416  // Loop on processing modules
417  for (int c=0; c<m_nbImageProcessingModules; c++)
418  {
419  // Apply it only if asked for
420  if (mp_applyPost[c])
421  {
422  // Verbose
423  if (m_verbose>=2) Cout("oImageProcessingManager::ApplyProcessingPost() -> Apply image processing module " << c+1 << " to output image" << endl);
424  // Get the pointer to the output image
425  FLTNB**** image = ap_ImageSpace->m4p_outputImage;
426  // Apply processing module
428  }
429  }
430  // Normal end
431  return 0;
432 }
433 
434 // =====================================================================
435 // ---------------------------------------------------------------------
436 // ---------------------------------------------------------------------
437 // =====================================================================
int ApplyProcessingForward(oImageSpace *ap_ImageSpace)
FLTNB **** m4p_forwardImage
Definition: oImageSpace.hh:68
#define FLTNB
Definition: gVariables.hh:55
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Set the member mp_ImageDimensionsAndQuantification to the provided value.
static void ShowCommonHelp()
This function does not take any parameter and is used to display some help about the syntax of the op...
bool GetAffectCardDimensionFlag()
Return the boolean value of m_affectCardDimensionFlag member.
bool GetAffectTimeDimensionFlag()
Return the boolean value of m_affectTimeDimensionFlag member.
void ShowHelpImageProcessingModule()
Show help about all implemented image processing modules.
int Initialize()
A function used to initialize the manager and all image processing modules it manages.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
~oImageProcessingManager()
The destructor of oImageProcessingManager.
int ApplyProcessingPost(oImageSpace *ap_ImageSpace)
bool GetRespStaticFlag()
Get the respiratory static flag that says if the reconstruction has only one respiratory gate or not...
static sAddonManager * GetInstance()
#define Cerr(MESSAGE)
bool GetCardStaticFlag()
Get the cardiac static flag that says if the reconstruction has only one cardiac gate or not...
FLTNB **** m4p_image
Definition: oImageSpace.hh:61
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
This abstract class is the generic image processing module class used by the oImageProcessingManager...
int CheckParameters()
A function used to check the parameters settings.
FLTNB **** m4p_outputImage
Definition: oImageSpace.hh:115
oImageProcessingManager()
The constructor of oImageProcessingManager.
bool GetTimeStaticFlag()
Get the time static flag that says if the reconstruction has only one frame or not.
bool GetAffectRespDimensionFlag()
Return the boolean value of m_affectRespDimensionFlag member.
int ApplyProcessingIntra(oImageSpace *ap_ImageSpace)
std::map< string, maker_image_processing_module > mp_listOfImageProcessingModules
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
Declaration of class oImageProcessingManager.
This class holds all the matrices in the image domain that can be used in the algorithm: image...
Definition: oImageSpace.hh:41
void SetVerbose(int a_verbose)
Set the member m_verboseLevel to the provided value.
vImageProcessingModule ** m2p_ImageProcessingModules
#define Cout(MESSAGE)
virtual int Process(FLTNB ****a4p_image)=0
A function used to actually perform the processing.
Declaration of class sAddonManager.
int ParseOptionsAndInitializeImageProcessingModules()
A function used to parse options and initialize image processing modules.