CASToR  2.0
Tomographic Reconstruction (PET/SPECT/CT)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
oImageProcessingManager.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2018 all CASToR contributors listed below:
18 
19  --> current contributors: Thibaut MERLIN, Simon STUTE, Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Mael MILLARDET
20  --> past contributors: Valentin VIELZEUF
21 
22 This is CASToR version 2.0.
23 */
24 
32 #include "sAddonManager.hh"
33 
34 // =====================================================================
35 // ---------------------------------------------------------------------
36 // ---------------------------------------------------------------------
37 // =====================================================================
38 
40 {
41  // Image dimensions
43  // Options
44  m_options = {};
45  // Image processing objects and associated bool
48  mp_applyForward = NULL;
49  mp_applyIntra = NULL;
50  mp_applyPost = NULL;
51  // Booleans
52  m_checked = false;
53  m_initialized = false;
54  // Verbosity
55  m_verbose = -1;
56 }
57 
58 // =====================================================================
59 // ---------------------------------------------------------------------
60 // ---------------------------------------------------------------------
61 // =====================================================================
62 
64 {
65  // Delete object
67  {
70  }
71 }
72 
73 // =====================================================================
74 // ---------------------------------------------------------------------
75 // ---------------------------------------------------------------------
76 // =====================================================================
77 
79 {
80  // Check image dimensions
82  {
83  Cerr("***** oImageProcessingManager::CheckParameters() -> No image dimensions provided !" << endl);
84  return 1;
85  }
86  // Check verbosity
87  if (m_verbose<0)
88  {
89  Cerr("***** oImageProcessingManager::CheckParameters() -> Wrong verbosity level provided !" << endl);
90  return 1;
91  }
92  // All set
93  m_checked = true;
94  // Normal end
95  return 0;
96 }
97 
98 // =====================================================================
99 // ---------------------------------------------------------------------
100 // ---------------------------------------------------------------------
101 // =====================================================================
102 
104 {
105  // Return when using MPI and mpi_rank is not 0
106  #ifdef CASTOR_MPI
107  int mpi_rank = 0;
108  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
109  if (mpi_rank!=0) return;
110  #endif
111  // Show help
112  cout << "------------------------------------------------------------------" << endl;
113  cout << "----- How to use an image processing module" << endl;
114  cout << "------------------------------------------------------------------" << endl;
115  cout << endl;
116  cout << "An image processing module is called through the -proc option. The provided argument describes the processing module to be used," << endl;
117  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;
118  cout << " proc::when (in this case, the default configuration file of the processing module is used to set the options values)" << endl;
119  cout << " proc:file.conf::when (in this case, the provided configuration is used)" << endl;
120  cout << " proc,param1,param2,...::when (in this case, the options values are directly provided in the argument)" << endl;
121  cout << "In any case, the description of the options specific to each processing module, their order in the list and their configuration" << endl;
122  cout << "files syntax are provided in the specific help of each module." << endl;
123  cout << "The 'when' parameter is an argument describing when to include the processing module within the algorithm. It is a list of keywords" << endl;
124  cout << "separating by commas. The following keywords can be used:" << endl;
125  cout << " forward (include module into forward model; the processed current estimate is forward-projected)" << endl;
126  cout << " post (apply module before saving the image; the processed image is not put back as the estimate for the next update)" << endl;
127  cout << " intra (apply module to the updated image use it as the current estimate for the next update)" << endl;
128  cout << endl;
129 }
130 
131 // =====================================================================
132 // ---------------------------------------------------------------------
133 // ---------------------------------------------------------------------
134 // =====================================================================
135 
137 {
138  // Check if parameters have been checked
139  if (!m_checked)
140  {
141  Cerr("***** oImageProcessingManager::Initialize() -> Parameters have not been checked ! Please call CheckParameters() before." << endl);
142  return 1;
143  }
144  // Case with no options (no image processing module)
145  if (m_options.size()==0)
146  {
147  m_initialized = true;
148  return 0;
149  }
150  // Verbose
151  if (m_verbose>=1) Cout("oImageProcessingManager::Initialize() -> Initialize image processing modules" << endl);
152  // Parse image processing modules options and initialize them
154  {
155  Cerr("***** oImageProcessingManager::Initialize() -> A problem occured while parsing image processing modules options and initializing them !" << endl);
156  return 1;
157  }
158  // All set
159  m_initialized = true;
160  // Normal end
161  return 0;
162 }
163 
164 // =====================================================================
165 // ---------------------------------------------------------------------
166 // ---------------------------------------------------------------------
167 // =====================================================================
168 
170 {
171  // ===================================================================
172  // First get the number of processing modules from the list of options
173  // ===================================================================
174 
176 
177  // Allocate the tables
179  mp_applyForward = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
180  mp_applyIntra = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
181  mp_applyPost = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool));
182 
183  // ===================================================================
184  // Then we loop over all modules, read options and initialize them
185  // ===================================================================
186 
187  // This is for the automatic initialization of the processing modules
188  typedef vImageProcessingModule *(*maker_image_processing_module) ();
189  // Get image processing modules list from addon manager
190  std::map <string,maker_image_processing_module> list = sAddonManager::GetInstance()->mp_listOfImageProcessingModules;
191 
192  // Start the loop
193  for (int c=0; c<m_nbImageProcessingModules; c++)
194  {
195  // Default initializations
196  m2p_ImageProcessingModules[c] = NULL;
197  mp_applyForward[c] = false;
198  mp_applyIntra[c] = false;
199  mp_applyPost[c] = false;
200 
201  // ___________________________________________________________________________________
202  // Search for a double-colon and isolate the module's options from the 'when' actions
203 
204  size_t double_colon = m_options[c].find_first_of("::");
205 
206  // Send an error if no double-colon
207  if (double_colon==string::npos)
208  {
209  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Wrong syntax in the " << c+1 << "th image processing module !" << endl);
210  Cerr(" No double-colon \"::\" found." << endl);
211  ShowCommonHelp();
212  return 1;
213  }
214 
215  // Separate the two arguments
216  string proc_part_options = m_options[c].substr(0,double_colon);
217  string when_part_options = m_options[c].substr(double_colon+2);
218 
219  // ___________________________________________________________________________________
220  // Get the module name in the options and isolate the actual module's options
221 
222  // Useful strings
223  string module = "";
224  string list_options = "";
225  string file_options = "";
226 
227  // Search for a colon ":", this indicates that a configuration file is provided after the module's name
228  size_t colon = proc_part_options.find_first_of(":");
229  size_t comma = proc_part_options.find_first_of(",");
230 
231  // Case 1: we have a colon
232  if (colon!=string::npos)
233  {
234  // Get the image processing module name before the colon
235  module = proc_part_options.substr(0,colon);
236  // Get the configuration file after the colon
237  file_options = proc_part_options.substr(colon+1);
238  // List of options is empty
239  list_options = "";
240  }
241  // Case 2: we have a comma
242  else if (comma!=string::npos)
243  {
244  // Get the image processing module name before the first comma
245  module = proc_part_options.substr(0,comma);
246  // Get the list of options after the first comma
247  list_options = proc_part_options.substr(comma+1);
248  // Configuration file is empty
249  file_options = "";
250  }
251  // Case 3: no colon and no comma (a single image processing module name)
252  else
253  {
254  // Get the image processing module name
255  module = proc_part_options;
256  // List of options is empty
257  list_options = "";
258  // Build the default configuration file
259  file_options = sOutputManager::GetInstance()->GetPathToConfigDir() + "/processing/" + module + ".conf";
260  }
261 
262  // ___________________________________________________________________________________
263  // Read the 'when' actions
264 
265  // Loop while commas are found
266  while ((comma=when_part_options.find_first_of(",")) != string::npos)
267  {
268  // Extract the first option
269  string option = when_part_options.substr(0,comma);
270  // Extract the rest
271  when_part_options = when_part_options.substr(comma+1);
272  // Check the meaning of the option
273  if (option=="forward") {mp_applyForward[c] = true;}
274  else if (option=="post") {mp_applyPost[c] = true;}
275  else if (option=="intra") {mp_applyIntra[c] = true;}
276  else
277  {
278  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << option << "' provided in options list !" << endl);
279  ShowCommonHelp();
280  return 1;
281  }
282  }
283  // Last option
284  if (when_part_options=="forward") {mp_applyForward[c] = true;}
285  else if (when_part_options=="post") {mp_applyPost[c] = true;}
286  else if (when_part_options=="intra") {mp_applyIntra[c] = true;}
287  else
288  {
289  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << when_part_options << "' provided in options list !" << endl);
290  ShowCommonHelp();
291  return 1;
292  }
293 
294  // ______________________________________________________________________________
295  // Create processing module and call associated functions
296 
297  // Create the image processing module
298  if (list[module]) m2p_ImageProcessingModules[c] = list[module]();
299  else
300  {
301  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Image processing module '" << module << "' does not exist !" << endl);
303  return 1;
304  }
305  // Set parameters
308  // Provide configuration file if any
309  if (file_options!="" && m2p_ImageProcessingModules[c]->ReadConfigurationFile(file_options))
310  {
311  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while reading and checking configuration file for image processing module '" << module << "' !" << endl);
312  return 1;
313  }
314  // Provide options if any
315  if (list_options!="" && m2p_ImageProcessingModules[c]->ReadOptionsList(list_options))
316  {
317  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while parsing and reading options list for image processing module '" << module << "' !" << endl);
318  return 1;
319  }
320  // Check parameters
322  {
323  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while checking parameters for image processing module '" << module << "' !" << endl);
324  return 1;
325  }
326  // Initialize the image processing module
328  {
329  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while initializing image processing module '" << module << "' !" << endl);
330  return 1;
331  }
332  // 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')
333  bool intra_reconstruction = mp_applyForward[c] || mp_applyIntra[c];
337  if (intra_reconstruction && (condition1 || condition2 || condition3))
338  {
339  Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Cannot use dynamic image processing module '" << module << "' along with dynamic basis functions inside the reconstruction !" << endl);
340  return 1;
341  }
342  }
343 
344  // Normal end
345  return 0;
346 }
347 
348 // =====================================================================
349 // ---------------------------------------------------------------------
350 // ---------------------------------------------------------------------
351 // =====================================================================
352 
354 {
355  #ifdef CASTOR_DEBUG
356  // Check if initialized
357  if (!m_initialized)
358  {
359  Cerr("***** oImageProcessingManager::ApplyProcessingForward() -> Called while not initialized !" << endl);
360  return 1;
361  }
362  #endif
363  // Loop on processing modules
364  for (int c=0; c<m_nbImageProcessingModules; c++)
365  {
366  // Apply it only if asked for
367  if (mp_applyForward[c])
368  {
369  // Verbose
370  if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingForward() -> Apply image processing module " << c+1 << " to forward image" << endl);
371  // Get the pointer to the image
372  FLTNB**** image = ap_ImageSpace->m4p_forwardImage;
373  // Apply convolution
375  }
376  }
377  // Normal end
378  return 0;
379 }
380 
381 // =====================================================================
382 // ---------------------------------------------------------------------
383 // ---------------------------------------------------------------------
384 // =====================================================================
385 
387 {
388  #ifdef CASTOR_DEBUG
389  // Check if initialized
390  if (!m_initialized)
391  {
392  Cerr("***** oImageProcessingManager::ApplyProcessingIntra() -> Called while not initialized !" << endl);
393  return 1;
394  }
395  #endif
396  // Loop on processing modules
397  for (int c=0; c<m_nbImageProcessingModules; c++)
398  {
399  // Apply it only if asked for
400  if (mp_applyIntra[c])
401  {
402  // Verbose
403  if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingIntra() -> Apply image processing module " << c+1 << " to current image" << endl);
404  // Get the pointer to the image
405  FLTNB**** image = ap_ImageSpace->m4p_image;
406  // Apply processing module
408  }
409  }
410  // Normal end
411  return 0;
412 }
413 
414 // =====================================================================
415 // ---------------------------------------------------------------------
416 // ---------------------------------------------------------------------
417 // =====================================================================
418 
420 {
421  #ifdef CASTOR_DEBUG
422  // Check if initialized
423  if (!m_initialized)
424  {
425  Cerr("***** oImageProcessingManager::ApplyProcessingPost() -> Called while not initialized !" << endl);
426  return 1;
427  }
428  #endif
429  // Loop on processing modules
430  for (int c=0; c<m_nbImageProcessingModules; c++)
431  {
432  // Apply it only if asked for
433  if (mp_applyPost[c])
434  {
435  // Verbose
436  if (m_verbose>=2) Cout("oImageProcessingManager::ApplyProcessingPost() -> Apply image processing module " << c+1 << " to output image" << endl);
437  // Get the pointer to the output image
438  FLTNB**** image = ap_ImageSpace->m4p_outputImage;
439  // Apply processing module
441  }
442  }
443  // Normal end
444  return 0;
445 }
446 
447 // =====================================================================
448 // ---------------------------------------------------------------------
449 // ---------------------------------------------------------------------
450 // =====================================================================
int ApplyProcessingForward(oImageSpace *ap_ImageSpace)
FLTNB **** m4p_forwardImage
Definition: oImageSpace.hh:88
#define FLTNB
Definition: gVariables.hh:81
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:81
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:144
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:61
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.