CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/optimizer/iOptimizerLandweber.cc
Go to the documentation of this file.
1 
8 #include "iOptimizerLandweber.hh"
9 #include "sOutputManager.hh"
10 
11 // =====================================================================
12 // ---------------------------------------------------------------------
13 // ---------------------------------------------------------------------
14 // =====================================================================
15 
17 {
18  // ---------------------------
19  // Mandatory member parameters
20  // ---------------------------
21 
22  // Initial value at 0
23  m_initialValue = 0.;
24  // Only one backward image for Landweber
26  // Landweber is not compatible with listmode data
28  // Landweber is compatible with histogram data only
30  // Landweber is compatible with both emission and transmission data
33 
34  // --------------------------
35  // Specific member parameters
36  // --------------------------
37 
38  // The custom relaxation parameter
39  m_relaxationFactor = -1.;
40  // Non-negativity constraint
42 }
43 
44 // =====================================================================
45 // ---------------------------------------------------------------------
46 // ---------------------------------------------------------------------
47 // =====================================================================
48 
50 {
51 }
52 
53 // =====================================================================
54 // ---------------------------------------------------------------------
55 // ---------------------------------------------------------------------
56 // =====================================================================
57 
59 {
60  cout << "This optimizer implements the standard Landweber algorithm for least-squares optimization." << endl;
61  cout << "With transmission data, it uses the log-converted model to derive the update." << endl;
62  cout << "Be aware that the relaxation parameter is not automatically set, so it often requires some" << endl;
63  cout << "trials and errors to find an optimal setting. Also, remember that this algorithm is particularly" << endl;
64  cout << "slow to converge." << endl;
65  cout << "The following options can be used (in this particular order when provided as a list):" << endl;
66  cout << " initial image value: to set the uniform voxel value for the initial image" << endl;
67  cout << " relaxation factor: to set the relaxation factor applied to the update" << endl;
68  cout << " non-negativity constraint: 0 if no constraint or 1 in order to apply the constraint during the image update" << endl;
69 }
70 
71 // =====================================================================
72 // ---------------------------------------------------------------------
73 // ---------------------------------------------------------------------
74 // =====================================================================
75 
76 int iOptimizerLandweber::ReadConfigurationFile(const string& a_configurationFile)
77 {
78  string key_word = "";
79  // Read the initial image value option
80  key_word = "initial image value";
81  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_initialValue, 1, KEYWORD_MANDATORY))
82  {
83  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
84  return 1;
85  }
86  // Read the relaxation factor option
87  key_word = "relaxation factor";
88  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_relaxationFactor, 1, KEYWORD_MANDATORY))
89  {
90  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
91  return 1;
92  }
93  // Read the non-negativity constraint option
94  key_word = "non-negativity constraint";
95  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_nonNegativityConstraint, 1, KEYWORD_MANDATORY))
96  {
97  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
98  return 1;
99  }
100  // Normal end
101  return 0;
102 }
103 
104 // =====================================================================
105 // ---------------------------------------------------------------------
106 // ---------------------------------------------------------------------
107 // =====================================================================
108 
109 int iOptimizerLandweber::ReadOptionsList(const string& a_optionsList)
110 {
111  // There are 3 floating point variables as options
112  const int nb_options = 3;
113  FLTNB options[nb_options];
114  // Read them
115  if (ReadStringOption(a_optionsList, options, nb_options, ",", "Landweber configuration"))
116  {
117  Cerr("***** iOptimizerLandweber::ReadOptionsList() -> Failed to correctly read the list of options !" << endl);
118  return 1;
119  }
120  // Affect options
121  m_initialValue = options[0];
122  m_relaxationFactor = options[1];
123  if (options[2]==0.) m_nonNegativityConstraint = false;
124  else m_nonNegativityConstraint = true;
125  // Normal end
126  return 0;
127 }
128 
129 // =====================================================================
130 // ---------------------------------------------------------------------
131 // ---------------------------------------------------------------------
132 // =====================================================================
133 
135 {
136  // Check that relaxation factor value is strictly positive
137  if (m_relaxationFactor<=0.)
138  {
139  Cerr("***** iOptimizerLandweber->CheckSpecificParameters() -> Provided relaxation factor (" << m_relaxationFactor << ") must be strictly positive !" << endl);
140  return 1;
141  }
142  // Normal end
143  return 0;
144 }
145 
146 // =====================================================================
147 // ---------------------------------------------------------------------
148 // ---------------------------------------------------------------------
149 // =====================================================================
150 
152 {
153  // Verbose
155  {
156  Cout("iOptimizerLandweber::InitializeSpecific() -> Use the Landweber algorithm" << endl);
158  {
159  Cout(" --> Initial image value: " << m_initialValue << endl);
160  Cout(" --> Relaxation factor: " << m_relaxationFactor << endl);
161  if (m_nonNegativityConstraint) Cout(" --> Apply a non-negativity constraint during image update" << endl);
162  }
163  }
164  // Normal end
165  return 0;
166 }
167 
168 // =====================================================================
169 // ---------------------------------------------------------------------
170 // ---------------------------------------------------------------------
171 // =====================================================================
172 
173 int iOptimizerLandweber::SensitivitySpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_weight,
174  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
175  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
176 {
177  // Line weight here is simply 1
178  *ap_weight = 1.;
179  // That's all
180  return 0;
181 }
182 
183 // =====================================================================
184 // ---------------------------------------------------------------------
185 // ---------------------------------------------------------------------
186 // =====================================================================
187 
188 int iOptimizerLandweber::DataSpaceSpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_backwardValues,
189  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
190  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
191 {
192  // Case for emission tomography
194  {
195  // Simply subtract the model from the data
196  *ap_backwardValues = (a_data - a_forwardModel);
197  }
198  // Case for transmission tomography
199  else if (m_dataSpec==SPEC_TRANSMISSION)
200  {
201  // Subtract scatters
202  a_data -= a_additiveCorrections;
203  a_forwardModel -= a_additiveCorrections;
204  // Safely ignore this data if data or model is less than 1 (set backward value to 0 and return)
205  if (a_data<1. || a_forwardModel<1.) *ap_backwardValues = 0.;
206  // Otherwise, proceed to subtraction of log converted data and model
207  *ap_backwardValues = log( a_forwardModel / a_data );
208  }
209  // That's all
210  return 0;
211 }
212 
213 // =====================================================================
214 // ---------------------------------------------------------------------
215 // ---------------------------------------------------------------------
216 // =====================================================================
217 
218 int iOptimizerLandweber::ImageSpaceSpecificOperations( FLTNB a_currentImageValue, FLTNB* ap_newImageValue,
219  FLTNB a_sensitivity, FLTNB* ap_correctionValues,
220  INTNB a_voxel, int a_tbf, int a_rbf, int a_cbf )
221 {
222  // Compute image update factor
223  FLTNB image_update_factor = *ap_correctionValues * m_relaxationFactor / a_sensitivity;
224  // Update image
225  *ap_newImageValue = a_currentImageValue + image_update_factor;
226  // Apply non-negativity constraint if asked for
227  if (m_nonNegativityConstraint && *ap_newImageValue<0.) *ap_newImageValue = 0.;
228  // End
229  return 0;
230 }
231 
232 // =====================================================================
233 // ---------------------------------------------------------------------
234 // ---------------------------------------------------------------------
235 // =====================================================================
int ReadOptionsList(const string &a_optionsList)
int ImageSpaceSpecificOperations(FLTNB a_currentImageValue, FLTNB *ap_newImageValue, FLTNB a_sensitivity, FLTNB *ap_correctionValues, INTNB a_voxel, int a_tbf=-1, int a_rbf=-1, int a_cbf=-1)
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)
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the &#39;a_input&#39; string corresponding to the &#39;a_option&#39; into &#39;a_nbElts&#39; elements, using the &#39;sep&#39; separator. The results are returned in the templated &#39;ap_return&#39; dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
void ShowHelpSpecific()
A function used to show help about the child optimizer.
#define Cerr(MESSAGE)
int ReadConfigurationFile(const string &a_configurationFile)
~iOptimizerLandweber()
The destructor of iOptimizerLandweber.
int InitializeSpecific()
This function is used to initialize specific stuff to the child optimizer.
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child optimizer.
#define KEYWORD_MANDATORY
#define SPEC_TRANSMISSION
This class is designed to generically described any iterative optimizer.
This class is designed to manage and store system matrix elements associated to a vEvent...
iOptimizerLandweber()
The constructor of iOptimizerLandweber.
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...
#define Cout(MESSAGE)
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)