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