CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
oImageConvolverManager.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class oImageConvolverManager
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 convolver objects and associated bool
34  m2p_ImageConvolvers = NULL;
35  mp_applyForward = NULL;
36  mp_applyBackward = NULL;
37  mp_applyIntra = NULL;
38  mp_applyPost = NULL;
39  // Booleans
40  m_checked = false;
41  m_initialized = false;
42  // Verbosity
43  m_verbose = -1;
44 }
45 
46 // =====================================================================
47 // ---------------------------------------------------------------------
48 // ---------------------------------------------------------------------
49 // =====================================================================
50 
52 {
53  // Delete object
55  {
56  for (int c=0; c<m_nbImageConvolvers; c++) if (m2p_ImageConvolvers[c]) delete m2p_ImageConvolvers[c];
57  free(m2p_ImageConvolvers);
58  }
59 }
60 
61 // =====================================================================
62 // ---------------------------------------------------------------------
63 // ---------------------------------------------------------------------
64 // =====================================================================
65 
67 {
68  // Check image dimensions
70  {
71  Cerr("***** oImageConvolverManager::CheckParameters() -> No image dimensions provided !" << endl);
72  return 1;
73  }
74  // Check verbosity
75  if (m_verbose<0)
76  {
77  Cerr("***** oImageConvolverManager::CheckParameters() -> Wrong verbosity level provided !" << endl);
78  return 1;
79  }
80  // All set
81  m_checked = true;
82  // Normal end
83  return 0;
84 }
85 
86 // =====================================================================
87 // ---------------------------------------------------------------------
88 // ---------------------------------------------------------------------
89 // =====================================================================
90 
92 {
93  // Return when using MPI and mpi_rank is not 0
94  #ifdef CASTOR_MPI
95  int mpi_rank = 0;
96  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
97  if (mpi_rank!=0) return;
98  #endif
99  // Show help
100  cout << "------------------------------------------------------------------" << endl;
101  cout << "----- How to use an image convolver" << endl;
102  cout << "------------------------------------------------------------------" << endl;
103  cout << endl;
104  cout << "An image convolver is called through the -conv option. The provided argument describes the convolver to be used, its options," << endl;
105  cout << "and when to include it within the algorithm. The syntax of the argument must obey one of the three following options:" << endl;
106  cout << " conv::when (in this case, the default configuration file of the convolver is used to set the options values)" << endl;
107  cout << " conv:file.conf::when (in this case, the provided configuration is used)" << endl;
108  cout << " conv,param1,param2,...::when (in this case, the options values are directly provided in the argument)" << endl;
109  cout << "In any case, the description of the options specific to each convolver, their order in the list and their configuration" << endl;
110  cout << "files syntax are provided in the specific help of each convolver." << endl;
111  cout << "The 'when' parameter is an argument describing when to include the convolver within the algorithm. It is a list of keywords" << endl;
112  cout << "separating by commas. The following keywords can be used:" << endl;
113  cout << " forward (include convolver into forward model; a convolution of the current estimate is forward-projected)" << endl;
114  cout << " backward (include convolver into backward model; a convolution of the correction terms is used for the update)" << endl;
115  cout << " post (apply convolver before saving the image; the convolved image is not put back as the estimate for the next update)" << endl;
116  cout << " psf (include both 'forward' and 'backward'; the standard image-based PSF modelling)" << endl;
117  cout << " sieve (include both 'psf' and 'post'; the standard method of sieve)" << endl;
118  cout << " intra (apply convolver to the updated image and use it as the current estimate for the next update)" << endl;
119  cout << endl;
120 }
121 
122 // =====================================================================
123 // ---------------------------------------------------------------------
124 // ---------------------------------------------------------------------
125 // =====================================================================
126 
128 {
129  // Check if parameters have been checked
130  if (!m_checked)
131  {
132  Cerr("***** oImageConvolverManager::Initialize() -> Parameters have not been checked ! Please call CheckParameters() before." << endl);
133  return 1;
134  }
135  // Case with no options (no convolver)
136  if (m_options.size()==0)
137  {
138  m_initialized = true;
139  return 0;
140  }
141  // Verbose
142  if (m_verbose>=1) Cout("oImageConvolverManager::Initialize() -> Initialize image convolvers" << endl);
143  // Parse image convolver options and initialize them
145  {
146  Cerr("***** oImageConvolverManager::Initialize() -> A problem occured while parsing image convolvers options and initializing them !" << endl);
147  return 1;
148  }
149  // All set
150  m_initialized = true;
151  // Normal end
152  return 0;
153 }
154 
155 // =====================================================================
156 // ---------------------------------------------------------------------
157 // ---------------------------------------------------------------------
158 // =====================================================================
159 
161 {
162  // ==============================================================
163  // First get the number of convolvers from the list of options
164  // ==============================================================
165 
167 
168  // Allocate the tables
170  mp_applyForward = (bool*)malloc(m_nbImageConvolvers*sizeof(bool));
171  mp_applyBackward = (bool*)malloc(m_nbImageConvolvers*sizeof(bool));
172  mp_applyIntra = (bool*)malloc(m_nbImageConvolvers*sizeof(bool));
173  mp_applyPost = (bool*)malloc(m_nbImageConvolvers*sizeof(bool));
174 
175  // ==============================================================
176  // Then we loop over all convolvers, read options and initialize
177  // ==============================================================
178 
179  // This is for the automatic initialization of the convolvers
180  typedef vImageConvolver *(*maker_image_convolver) ();
181  // Get image convolver's list from addon manager
182  std::map <string,maker_image_convolver> list = sAddonManager::GetInstance()->mp_listOfImageConvolvers;
183 
184  // Start the loop
185  for (int c=0; c<m_nbImageConvolvers; c++)
186  {
187  // Default initializations
188  m2p_ImageConvolvers[c] = NULL;
189  mp_applyForward[c] = false;
190  mp_applyBackward[c] = false;
191  mp_applyIntra[c] = false;
192  mp_applyPost[c] = false;
193 
194  // ___________________________________________________________________________________
195  // Search for a double-colon and isolate the convolver's options from the 'when' actions
196 
197  size_t double_colon = m_options[c].find_first_of("::");
198 
199  // Send an error if no double-colon
200  if (double_colon==string::npos)
201  {
202  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> Wrong syntax in the " << c+1 << "th image convolver !" << endl);
203  Cerr(" No double-colon \"::\" found." << endl);
204  ShowCommonHelp();
205  return 1;
206  }
207 
208  // Separate the two arguments
209  string conv_part_options = m_options[c].substr(0,double_colon);
210  string when_part_options = m_options[c].substr(double_colon+2);
211 
212  // ___________________________________________________________________________________
213  // Get the image convolver name in the options and isolate the actual image convolver's options
214 
215  // Useful strings
216  string convolver = "";
217  string list_options = "";
218  string file_options = "";
219 
220  // Search for a colon ":", this indicates that a configuration file is provided after the image convolver name
221  size_t colon = conv_part_options.find_first_of(":");
222  size_t comma = conv_part_options.find_first_of(",");
223 
224  // Case 1: we have a colon
225  if (colon!=string::npos)
226  {
227  // Get the image convolver name before the colon
228  convolver = conv_part_options.substr(0,colon);
229  // Get the configuration file after the colon
230  file_options = conv_part_options.substr(colon+1);
231  // List of options is empty
232  list_options = "";
233  }
234  // Case 2: we have a comma
235  else if (comma!=string::npos)
236  {
237  // Get the image convolver name before the first comma
238  convolver = conv_part_options.substr(0,comma);
239  // Get the list of options after the first comma
240  list_options = conv_part_options.substr(comma+1);
241  // Configuration file is empty
242  file_options = "";
243  }
244  // Case 3: no colon and no comma (a single image convolver name)
245  else
246  {
247  // Get the image convolver name
248  convolver = conv_part_options;
249  // List of options is empty
250  list_options = "";
251  // Build the default configuration file
252  file_options = sOutputManager::GetInstance()->GetPathToConfigDir() + "/convolver/" + convolver + ".conf";
253  }
254 
255  // ___________________________________________________________________________________
256  // Read the 'when' actions
257 
258  // Loop while commas are found
259  while ((comma=when_part_options.find_first_of(",")) != string::npos)
260  {
261  // Extract the first option
262  string option = when_part_options.substr(0,comma);
263  // Extract the rest
264  when_part_options = when_part_options.substr(comma+1);
265  // Check the meaning of the option
266  if (option=="forward") {mp_applyForward[c] = true;}
267  else if (option=="backward") {mp_applyBackward[c] = true;}
268  else if (option=="post") {mp_applyPost[c] = true;}
269  else if (option=="psf") {mp_applyForward[c] = true; mp_applyBackward[c] = true;}
270  else if (option=="sieve") {mp_applyForward[c] = true; mp_applyBackward[c] = true; mp_applyPost[c] = true;}
271  else if (option=="intra") {mp_applyIntra[c] = true;}
272  else
273  {
274  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> Unknown keyword '" << option << "' provided in options list !" << endl);
275  ShowCommonHelp();
276  return 1;
277  }
278  }
279  // Last option
280  if (when_part_options=="forward") {mp_applyForward[c] = true;}
281  else if (when_part_options=="backward") {mp_applyBackward[c] = true;}
282  else if (when_part_options=="post") {mp_applyPost[c] = true;}
283  else if (when_part_options=="psf") {mp_applyForward[c] = true; mp_applyBackward[c] = true;}
284  else if (when_part_options=="sieve") {mp_applyForward[c] = true; mp_applyBackward[c] = true; mp_applyPost[c] = true;}
285  else if (when_part_options=="intra") {mp_applyIntra[c] = true;}
286  else
287  {
288  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> Unknown keyword '" << when_part_options << "' provided in options list !" << endl);
289  ShowCommonHelp();
290  return 1;
291  }
292 
293  // ______________________________________________________________________________
294  // Create convolver and call associated functions
295 
296  // Create the image convolver
297  if (list[convolver]) m2p_ImageConvolvers[c] = list[convolver]();
298  else
299  {
300  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> Image convolver '" << convolver << "' does not exist !" << endl);
302  return 1;
303  }
304  // Set parameters
307  // Provide configuration file if any
308  if (file_options!="" && m2p_ImageConvolvers[c]->ReadConfigurationFile(file_options))
309  {
310  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> A problem occured while reading and checking configuration file for image convolver '" << convolver << "' !" << endl);
311  return 1;
312  }
313  // Provide options if any
314  if (list_options!="" && m2p_ImageConvolvers[c]->ReadOptionsList(list_options))
315  {
316  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> A problem occured while parsing and reading options list for image convolver '" << convolver << "' !" << endl);
317  return 1;
318  }
319  // Check parameters
321  {
322  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> A problem occured while checking parameters for image convolver '" << convolver << "' !" << endl);
323  return 1;
324  }
325  // Initialize the image convolver
327  {
328  Cerr("***** oImageConvolverManager::ParseOptionsAndInitializeImageConvolvers() -> A problem occured while initializing image convolver '" << convolver << "' !" << endl);
329  return 1;
330  }
331  }
332 
333  // Normal end
334  return 0;
335 }
336 
337 // =====================================================================
338 // ---------------------------------------------------------------------
339 // ---------------------------------------------------------------------
340 // =====================================================================
341 
343 {
344  #ifdef CASTOR_DEBUG
345  // Check if initialized
346  if (!m_initialized)
347  {
348  Cerr("***** oImageConvolverManager::ConvolveForward() -> Called while not initialized !" << endl);
349  return 1;
350  }
351  #endif
352  // Loop on convolvers
353  for (int c=0; c<m_nbImageConvolvers; c++)
354  {
355  // Apply it only if asked for
356  if (mp_applyForward[c])
357  {
358  // Verbose
359  if (m_verbose>=2)
360  {
361  if (m_nbImageConvolvers>1) Cout("oImageConvolverManager::ConvolveForward() -> Apply convolution " << c+1 << " to forward image" << endl);
362  else Cout("oImageConvolverManager::ConvolveForward() -> Apply convolution to forward image" << endl);
363  }
364  // Loop on basis functions
366  {
368  {
370  {
371  // Get the pointer to the image
372  FLTNB* image = ap_ImageSpace->m4p_forwardImage[tb][rb][cb];
373  // Apply convolution
375  }
376  }
377  }
378  }
379  }
380  // Normal end
381  return 0;
382 }
383 
384 // =====================================================================
385 // ---------------------------------------------------------------------
386 // ---------------------------------------------------------------------
387 // =====================================================================
388 
390 {
391  #ifdef CASTOR_DEBUG
392  // Check if initialized
393  if (!m_initialized)
394  {
395  Cerr("***** oImageConvolverManager::ConvolveBackward() -> Called while not initialized !" << endl);
396  return 1;
397  }
398  #endif
399  // Loop on convolvers
400  for (int c=0; c<m_nbImageConvolvers; c++)
401  {
402  // Apply it only if asked for
403  if (mp_applyBackward[c])
404  {
405  // Verbose
406  if (m_verbose>=2)
407  {
408  if (m_nbImageConvolvers>1)
409  {
410  if (ap_ImageSpace->IsLoadedSensitivity()) Cout("oImageConvolverManager::ConvolveBackward() -> Apply convolution " << c+1 << " to backward image" << endl);
411  else Cout("oImageConvolverManager::ConvolveBackward() -> Apply convolution " << c+1 << " to backward and sensitivity images" << endl);
412  }
413  else
414  {
415  if (ap_ImageSpace->IsLoadedSensitivity()) Cout("oImageConvolverManager::ConvolveBackward() -> Apply convolution to backward image" << endl);
416  else Cout("oImageConvolverManager::ConvolveBackward() -> Apply convolution to backward and sensitivity images" << endl);
417  }
418  }
419  // Deal with backward images, loop on number of images
420  for (int img=0; img<ap_ImageSpace->GetNbBackwardImages(); img++)
421  {
422  // Loop on basis functions
424  {
426  {
428  {
429  // Get the pointer to the image
430  int thread_0 = 0;
431  FLTNB* image = ap_ImageSpace->m6p_backwardImage[img][thread_0][tb][rb][cb];
432  // Apply convolution
434  }
435  }
436  }
437  }
438  // Deal with sensitivity images for histogram reconstructions
439  if (!ap_ImageSpace->IsLoadedSensitivity())
440  {
441  // Loop on frames and gates
442  for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++)
443  {
444  for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetSensNbRespGates(); rg++)
445  {
446  for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetSensNbCardGates(); cg++)
447  {
448  // Get the pointer to the image
449  int thread_0 = 0;
450  FLTNB* image = ap_ImageSpace->m5p_sensitivity[thread_0][fr][rg][cg];
451  // Apply convolution
453  }
454  }
455  }
456  }
457  }
458  }
459  // Normal end
460  return 0;
461 }
462 
463 // =====================================================================
464 // ---------------------------------------------------------------------
465 // ---------------------------------------------------------------------
466 // =====================================================================
467 
469 {
470  #ifdef CASTOR_DEBUG
471  // Check if initialized
472  if (!m_initialized)
473  {
474  Cerr("***** oImageConvolverManager::ConvolveIntra() -> Called while not initialized !" << endl);
475  return 1;
476  }
477  #endif
478  // Loop on convolvers
479  for (int c=0; c<m_nbImageConvolvers; c++)
480  {
481  // Apply it only if asked for
482  if (mp_applyIntra[c])
483  {
484  // Verbose
485  if (m_verbose>=2)
486  {
487  if (m_nbImageConvolvers>1) Cout("oImageConvolverManager::ConvolveIntra() -> Apply convolution " << c+1 << " to current image" << endl);
488  else Cout("oImageConvolverManager::ConvolveIntra() -> Apply convolution to current image" << endl);
489  }
490  // Loop on basis functions
492  {
494  {
496  {
497  // Get the pointer to the image
498  FLTNB* image = ap_ImageSpace->m4p_image[tb][rb][cb];
499  // Apply convolution
501  }
502  }
503  }
504  }
505  }
506  // Normal end
507  return 0;
508 }
509 
510 // =====================================================================
511 // ---------------------------------------------------------------------
512 // ---------------------------------------------------------------------
513 // =====================================================================
514 
516 {
517  #ifdef CASTOR_DEBUG
518  // Check if initialized
519  if (!m_initialized)
520  {
521  Cerr("***** oImageConvolverManager::ConvolveSensitivity() -> Called while not initialized !" << endl);
522  return 1;
523  }
524  #endif
525  // Loop on convolvers
526  for (int c=0; c<m_nbImageConvolvers; c++)
527  {
528  // Apply it only if asked for
529  if (mp_applyBackward[c])
530  {
531  // Verbose
532  if (m_verbose>=2)
533  {
534  if (m_nbImageConvolvers>1) Cout("oImageConvolverManager::ConvolveSensitivity() -> Apply convolution " << c+1 << " to sensitivity image" << endl);
535  else Cout("oImageConvolverManager::ConvolveSensitivity() -> Apply convolution to sensitivity image" << endl);
536  }
537  // Loop on frames and gates
538  for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++)
539  {
540  for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetSensNbRespGates(); rg++)
541  {
542  for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetSensNbCardGates(); cg++)
543  {
544  // Get the pointer to the image
545  int thread_0 = 0;
546  FLTNB* image = ap_ImageSpace->m5p_sensitivity[thread_0][fr][rg][cg];
547  // Apply convolution
549  }
550  }
551  }
552  }
553  }
554  // Normal end
555  return 0;
556 }
557 
558 // =====================================================================
559 // ---------------------------------------------------------------------
560 // ---------------------------------------------------------------------
561 // =====================================================================
562 
564 {
565  #ifdef CASTOR_DEBUG
566  // Check if initialized
567  if (!m_initialized)
568  {
569  Cerr("***** oImageConvolverManager::ConvolvePost() -> Called while not initialized !" << endl);
570  return 1;
571  }
572  #endif
573  // Loop on convolvers
574  for (int c=0; c<m_nbImageConvolvers; c++)
575  {
576  // Apply it only if asked for
577  if (mp_applyPost[c])
578  {
579  // Verbose
580  if (m_verbose>=2)
581  {
582  if (m_nbImageConvolvers>1) Cout("oImageConvolverManager::ConvolvePost() -> Apply convolution " << c+1 << " to output image" << endl);
583  else Cout("oImageConvolverManager::ConvolvePost() -> Apply convolution to output image" << endl);
584  }
585 
586  // Loop on frames and respiratory/cardiac gates
587  for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++)
588  {
589  for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++)
590  {
591  for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++)
592  {
593  // Get the pointer to the output image
594  FLTNB* image = ap_ImageSpace->m4p_outputImage[fr][rg][cg];
595  // Apply convolution
597  }
598  }
599  }
600  }
601  }
602  // Normal end
603  return 0;
604 }
605 
606 // =====================================================================
607 // ---------------------------------------------------------------------
608 // ---------------------------------------------------------------------
609 // =====================================================================
int ParseOptionsAndInitializeImageConvolvers()
A function used to parse options and initialize image convolvers.
FLTNB **** m4p_forwardImage
Definition: oImageSpace.hh:68
int GetNbCardBasisFunctions()
Get the number of cardiac basis functions.
#define FLTNB
Definition: gVariables.hh:55
bool IsLoadedSensitivity()
Definition: oImageSpace.hh:565
int ConvolveForward(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the forward image of the oImageSpace.
int CheckParameters()
A function used to check the parameters settings.
oImageConvolverManager()
The constructor of oImageConvolverManager.
int GetNbTimeBasisFunctions()
Get the number of time basis functions.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int ConvolvePost(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the output image of the oImageSpace.
int ConvolveIntra(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the current image of the oImageSpace.
static sAddonManager * GetInstance()
Declaration of class oImageConvolverManager.
#define Cerr(MESSAGE)
FLTNB ****** m6p_backwardImage
Definition: oImageSpace.hh:75
FLTNB **** m4p_image
Definition: oImageSpace.hh:61
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
int GetSensNbRespGates()
call the eponym function from the oDynamicDataManager object
FLTNB **** m4p_outputImage
Definition: oImageSpace.hh:115
int GetNbBackwardImages()
Definition: oImageSpace.hh:559
int ConvolveBackward(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the backward images of the oImageSpace.
int ApplyConvolutionTranspose(FLTNB *ap_image)
A public function used to apply the transpose convolution module on the provided image.
static void ShowCommonHelp()
This function does not take any parameter and is used to display some help about the syntax of the op...
~oImageConvolverManager()
The destructor of oImageConvolverManager.
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
int ApplyConvolution(FLTNB *ap_image)
A public function used to apply the convolution module on the provided image.
int GetNbCardGates()
Get the number of cardiac gates.
This class holds all the matrices in the image domain that can be used in the algorithm: image...
Definition: oImageSpace.hh:41
std::map< string, maker_image_convolver > mp_listOfImageConvolvers
int GetNbTimeFrames()
Get the number of time frames.
void SetVerbose(int a_verbose)
Set the member m_verboseLevel to the provided value.
int GetNbRespGates()
Get the number of respiratory gates.
#define Cout(MESSAGE)
int ConvolveSensitivity(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the sensitivity image of the oImageSpace.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Set the member mp_ImageDimensionsAndQuantification to the provided value.
vImageConvolver ** m2p_ImageConvolvers
int GetNbRespBasisFunctions()
Get the number of respiratory basis functions.
FLTNB ***** m5p_sensitivity
Definition: oImageSpace.hh:85
Declaration of class sAddonManager.
This abstract class is the generic image convolver class used by the oImageConvolverManager.
int Initialize()
A function used to initialize the manager and all image convolvers it manages.
void ShowHelpImageConvolver()
Show help about all implemented image convolvers.