CASToR  2.0
Tomographic Reconstruction (PET/SPECT/CT)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iOptimizerMLEM.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 
31 #include "iOptimizerMLEM.hh"
32 #include "sOutputManager.hh"
33 
34 // =====================================================================
35 // ---------------------------------------------------------------------
36 // ---------------------------------------------------------------------
37 // =====================================================================
38 
40 {
41  // ---------------------------
42  // Mandatory member parameters
43  // ---------------------------
44 
45  // Initial value at 1
46  m_initialValue = 1.;
47  // Only one backward image for MLEM
49  // MLEM does not accept penalties
50  //m_penaltyEnergyFunctionDerivativesOrder = 0;
51  // MLEM is compatible with listmode and histogram data
54  // MLEM is compatible with both emission and log-converted transmission data
57 
58  // --------------------------
59  // Specific member parameters
60  // --------------------------
61 
65 }
66 
67 // =====================================================================
68 // ---------------------------------------------------------------------
69 // ---------------------------------------------------------------------
70 // =====================================================================
71 
73 {
74 }
75 
76 // =====================================================================
77 // ---------------------------------------------------------------------
78 // ---------------------------------------------------------------------
79 // =====================================================================
80 
82 {
83  cout << "This optimizer is the standard MLEM (for Maximum Likelihood Expectation Maximization)." << endl;
84  cout << "If subsets are used, it naturally becomes the OSEM optimizer." << endl;
85  cout << "With transmission data, the log-converted pre-corrected data are used as in J. Nuyts et al: \"Iterative reconstruction" << endl;
86  cout << "for helical CT: a simulation study\", Phys. Med. Biol., vol. 43, pp. 729-737, 1998." << endl;
87  cout << "The following options can be used (in this particular order when provided as a list):" << endl;
88  cout << " initial image value: to set the uniform voxel value for the initial image" << endl;
89  cout << " denominator threshold: to set the threshold of the data space denominator under which the ratio is set to 1" << endl;
90  cout << " minimum image update: to set the minimum of the image update factor under which it stays constant (0 or a negative value" << endl;
91  cout << " means no minimum thus allowing a 0 update)" << endl;
92  cout << " maximum image update: to set the maximum of the image update factor over which it stays constant (0 or a negative value means" << endl;
93  cout << " no maximum)" << endl;
94 }
95 
96 // =====================================================================
97 // ---------------------------------------------------------------------
98 // ---------------------------------------------------------------------
99 // =====================================================================
100 
101 int iOptimizerMLEM::ReadConfigurationFile(const string& a_configurationFile)
102 {
103  string key_word = "";
104  // Read the initial image value option
105  key_word = "initial image value";
106  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_initialValue, 1, KEYWORD_MANDATORY))
107  {
108  Cerr("***** iOptimizerMLEM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
109  return 1;
110  }
111  // Read the denominator threshold option
112  key_word = "denominator threshold";
113  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_dataSpaceDenominatorThreshold, 1, KEYWORD_MANDATORY))
114  {
115  Cerr("***** iOptimizerMLEM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
116  return 1;
117  }
118  // Read the minimum image update option
119  key_word = "minimum image update";
120  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_minimumImageUpdateFactor, 1, KEYWORD_MANDATORY))
121  {
122  Cerr("***** iOptimizerMLEM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
123  return 1;
124  }
125  // Read the maximum image update option
126  key_word = "maximum image update";
127  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_maximumImageUpdateFactor, 1, KEYWORD_MANDATORY))
128  {
129  Cerr("***** iOptimizerMLEM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
130  return 1;
131  }
132  // Normal end
133  return 0;
134 }
135 
136 // =====================================================================
137 // ---------------------------------------------------------------------
138 // ---------------------------------------------------------------------
139 // =====================================================================
140 
141 int iOptimizerMLEM::ReadOptionsList(const string& a_optionsList)
142 {
143  // There are 4 floating point variables as options
144  const int nb_options = 4;
145  FLTNB options[nb_options];
146 
147  // Read them
148  if (ReadStringOption(a_optionsList, options, nb_options, ",", "MLEM configuration"))
149  {
150  Cerr("***** iOptimizerMLEM::ReadOptionsList() -> Failed to correctly read the list of options !" << endl);
151  return 1;
152  }
153  // Affect options
154  m_initialValue = options[0];
155  m_dataSpaceDenominatorThreshold = options[1];
156  m_minimumImageUpdateFactor = options[2];
157  m_maximumImageUpdateFactor = options[3];
158 
159  // Normal end
160  return 0;
161 }
162 
163 // =====================================================================
164 // ---------------------------------------------------------------------
165 // ---------------------------------------------------------------------
166 // =====================================================================
167 
169 {
170  // Check that initial image value is strictly positive
171  if (m_initialValue<=0.)
172  {
173  Cerr("***** iOptimizerMLEM->CheckSpecificParameters() -> Provided initial image value (" << m_initialValue << ") must be strictly positive !" << endl);
174  return 1;
175  }
176  // Check that denominator threshold value is strictly positive
178  {
179  Cerr("***** iOptimizerMLEM->CheckSpecificParameters() -> Provided data space denominator threshold (" << m_dataSpaceDenominatorThreshold << ") must be strictly positive !" << endl);
180  return 1;
181  }
182  // Check that maximum image update factor is higher than the minimum
184  {
185  Cerr("***** iOptimizerMLEM->CheckSpecificParameters() -> Provided minimum/maximum (" << m_minimumImageUpdateFactor << "/" << m_maximumImageUpdateFactor << " are inconsistent !" << endl);
186  return 1;
187  }
188  // Cannot deal with list-mode transmission data
190  {
191  Cerr("***** iOptimizerMLEM->CheckSpecificParameters() -> Cannot reconstruct list-mode transmission data !" << endl);
192  return 1;
193  }
194  // Normal end
195  return 0;
196 }
197 
198 // =====================================================================
199 // ---------------------------------------------------------------------
200 // ---------------------------------------------------------------------
201 // =====================================================================
202 
204 {
205  // Verbose
207  {
208  Cout("iOptimizerMLEM::InitializeSpecific() -> Use the MLEM optimizer" << endl);
210  {
211  Cout(" --> Initial image value: " << m_initialValue << endl);
212  Cout(" --> Data space denominator threshold: " << m_dataSpaceDenominatorThreshold << endl);
213  if (m_minimumImageUpdateFactor>0.) Cout(" --> Minimum image update factor: " << m_minimumImageUpdateFactor << endl);
214  else Cerr("!!!!! The minimum update value is not set, if using subsets, voxels could be trapped in 0 value causing some negative bias !" << endl);
215  if (m_maximumImageUpdateFactor>0.) Cout(" --> Maximum image update factor: " << m_maximumImageUpdateFactor << endl);
216  }
217  }
218  // Normal end
219  return 0;
220 }
221 
222 // =====================================================================
223 // ---------------------------------------------------------------------
224 // ---------------------------------------------------------------------
225 // =====================================================================
226 
227 int iOptimizerMLEM::SensitivitySpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_weight,
228  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
229  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
230 {
231  // Line weight here is simply 1
232  *ap_weight = 1.;
233  // That's all
234  return 0;
235 }
236 
237 // =====================================================================
238 // ---------------------------------------------------------------------
239 // ---------------------------------------------------------------------
240 // =====================================================================
241 
242 int iOptimizerMLEM::DataSpaceSpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_backwardValues,
243  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
244  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
245 {
246  // Case for emission tomography
248  {
249  // Truncate data to 0 if negative
250  if (a_data<0.) a_data = 0.;
251  // If the foward model is to close to zero, then ignore this data (set to 1 and not 0 because this line is taken into account in the sensitivity)
252  if (a_forwardModel>m_dataSpaceDenominatorThreshold) *ap_backwardValues = a_data / a_forwardModel;
253  else *ap_backwardValues = 1.;
254  }
255  // Case for transmission tomography (equivalent of log-converted MLEM from Nuyts et al 1998)
256  else if (m_dataSpec==SPEC_TRANSMISSION)
257  {
258  // Subtract scatters
259  a_data -= a_additiveCorrections;
260  a_forwardModel -= a_additiveCorrections;
261  // Truncate data and model to 1 if inferior
262  if (a_data<1.) a_data = 1.;
263  if (a_forwardModel<1.) a_forwardModel = 1.;
264  // Log-convert the data and the model
265  a_data = log(a_blankValue/a_data);
266  a_forwardModel = log(a_blankValue/a_forwardModel);
267  // If the foward model is to close to zero, then ignore this data (set to 1 and not 0 because this line is taken into account in the sensitivity)
268  if (a_forwardModel>m_dataSpaceDenominatorThreshold) *ap_backwardValues = a_data / a_forwardModel;
269  else *ap_backwardValues = 1.;
270  }
271 
272  // That's all
273  return 0;
274 }
275 
276 // =====================================================================
277 // ---------------------------------------------------------------------
278 // ---------------------------------------------------------------------
279 // =====================================================================
280 
281 int iOptimizerMLEM::ImageSpaceSpecificOperations( FLTNB a_currentImageValue, FLTNB* ap_newImageValue,
282  FLTNB a_sensitivity, FLTNB* ap_correctionValues, INTNB a_voxel )
283 {
284  // Compute image update factor
285  FLTNB image_update_factor = *ap_correctionValues / a_sensitivity;
286  // Apply minimum image update factor
287  if ( m_minimumImageUpdateFactor > 0. && image_update_factor < m_minimumImageUpdateFactor ) image_update_factor = m_minimumImageUpdateFactor;
288  // Apply maximum image update factor
289  if ( m_maximumImageUpdateFactor > 0. && image_update_factor > m_maximumImageUpdateFactor ) image_update_factor = m_maximumImageUpdateFactor;
290  // Update image
291  *ap_newImageValue = a_currentImageValue * image_update_factor;
292  // End
293  return 0;
294 }
295 
296 // =====================================================================
297 // ---------------------------------------------------------------------
298 // ---------------------------------------------------------------------
299 // =====================================================================
FLTNB m_dataSpaceDenominatorThreshold
#define MODE_LIST
Definition: vDataFile.hh:57
#define FLTNB
Definition: gVariables.hh:81
int ImageSpaceSpecificOperations(FLTNB a_currentImageValue, FLTNB *ap_newImageValue, FLTNB a_sensitivity, FLTNB *ap_correctionValues, INTNB a_voxel)
This function perform the image update step specific to the optimizer.
FLTNB m_initialValue
Definition: vOptimizer.hh:619
bool m_listmodeCompatibility
Definition: vOptimizer.hh:620
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
int DataSpaceSpecificOperations(FLTNB a_data, FLTNB a_forwardModel, FLTNB *ap_backwardValues, FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue, FLTNB a_quantificationFactor, oProjectionLine *ap_Line)
This function performs the data space operations specific to the optimizer (computes the values to be...
#define VERBOSE_DETAIL
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child optimizer.
int m_dataMode
Definition: vOptimizer.hh:627
int m_dataSpec
Definition: vOptimizer.hh:629
#define Cerr(MESSAGE)
int InitializeSpecific()
This function is used to initialize specific stuff to the child optimizer.
bool m_emissionCompatibility
Definition: vOptimizer.hh:622
int m_nbBackwardImages
Definition: vOptimizer.hh:615
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:123
bool m_histogramCompatibility
Definition: vOptimizer.hh:621
#define VERBOSE_NORMAL
iOptimizerMLEM()
The constructor of iOptimizerMLEM.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:48
Declaration of class iOptimizerMLEM.
#define SPEC_TRANSMISSION
Definition: vDataFile.hh:93
FLTNB m_maximumImageUpdateFactor
#define INTNB
Definition: gVariables.hh:92
bool m_transmissionCompatibility
Definition: vOptimizer.hh:623
This class is designed to generically described any iterative optimizer.
Definition: vOptimizer.hh:59
This class is designed to manage and store system matrix elements associated to a vEvent...
~iOptimizerMLEM()
The destructor of iOptimizerMLEM.
int ReadConfigurationFile(const string &a_configurationFile)
A function used to read options from a configuration file.
FLTNB m_minimumImageUpdateFactor
Declaration of class sOutputManager.
#define SPEC_EMISSION
Definition: vDataFile.hh:91
int SensitivitySpecificOperations(FLTNB a_data, FLTNB a_forwardModel, FLTNB *ap_weight, FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue, FLTNB a_quantificationFactor, oProjectionLine *ap_Line)
This function compute the weight associated to the provided event (for sensitivity computation) ...
#define Cout(MESSAGE)
void ShowHelpSpecific()
A function used to show help about the child optimizer.
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the 'a_input' string corresponding to the 'a_option' into 'a_nbElts' elements, using the 'sep' separator. The results are returned in the templated 'ap_return' dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
Definition: gOptions.cc:62