RTK  2.6.0
Reconstruction Toolkit
rtkProjectionsDecompositionNegativeLogLikelihood.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright RTK Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 
19 #ifndef rtkProjectionsDecompositionNegativeLogLikelihood_h
20 #define rtkProjectionsDecompositionNegativeLogLikelihood_h
21 
23 #include <itkVectorImage.h>
25 #include <itkVariableSizeMatrix.h>
26 #include "rtkMacro.h"
27 
28 namespace rtk
29 {
38 // We have to define the cost function first
40 {
41 public:
42  ITK_DISALLOW_COPY_AND_MOVE(ProjectionsDecompositionNegativeLogLikelihood);
43 
48  itkNewMacro(Self);
49 #ifdef itkOverrideGetNameOfClassMacro
50  itkOverrideGetNameOfClassMacro(ProjectionsDecompositionNegativeLogLikelihood);
51 #else
53 #endif
54 
55  // enum { SpaceDimension=m_NumberOfMaterials };
56 
60 
61  using DetectorResponseType = vnl_matrix<double>;
62  using MaterialAttenuationsType = vnl_matrix<double>;
63  using IncidentSpectrumType = vnl_matrix<float>;
67 
68  // Constructor
70  {
73  m_Initialized = false;
74  }
75 
76  // Destructor
78 
80  GetValue(const ParametersType & itkNotUsed(parameters)) const override
81  {
82  long double measure = 0;
83  return measure;
84  }
85  void
86  GetDerivative(const ParametersType & itkNotUsed(lineIntegrals),
87  DerivativeType & itkNotUsed(derivatives)) const override
88  {
89  itkExceptionMacro(<< "Not implemented");
90  }
91  virtual void
93  {}
94 
97  {
98  // Return the inverses of the diagonal components (i.e. the inverse variances, to be used directly in WLS
99  // reconstruction)
101  diag.SetSize(m_NumberOfMaterials);
102  diag.Fill(0);
103 
104  for (unsigned int mat = 0; mat < m_NumberOfMaterials; mat++)
105  diag[mat] = 1. / m_Fischer.GetInverse()[mat][mat];
106  return diag;
107  }
108 
111  {
112  // Return the inverses of the diagonal components (i.e. the inverse variances, to be used directly in WLS
113  // reconstruction)
115  diag.SetSize(m_NumberOfMaterials);
116  diag.Fill(0);
117 
118  for (unsigned int mat = 0; mat < m_NumberOfMaterials; mat++)
119  diag[mat] = m_Fischer.GetInverse()[mat][mat];
120  return diag;
121  }
122 
125  {
126  // Return the whole Fischer information matrix
128  fischer.SetSize(m_NumberOfMaterials * m_NumberOfMaterials);
129  fischer.Fill(0);
130 
131  for (unsigned int i = 0; i < m_NumberOfMaterials; i++)
132  for (unsigned int j = 0; j < m_NumberOfMaterials; j++)
133  fischer[i * m_NumberOfMaterials + j] = m_Fischer[i][j];
134  return fischer;
135  }
136 
137  virtual void
138  ComputeFischerMatrix(const ParametersType & itkNotUsed(lineIntegrals))
139  {}
140 
141  unsigned int
142  GetNumberOfParameters() const override
143  {
144  return m_NumberOfMaterials;
145  }
146 
147  virtual vnl_vector<double>
148  ForwardModel(const ParametersType & lineIntegrals) const
149  {
150  vnl_vector<double> attenuationFactors;
151  attenuationFactors.set_size(m_NumberOfEnergies);
152  GetAttenuationFactors(lineIntegrals, attenuationFactors);
153 
154  // Apply detector response, getting the lambdas
155  return (m_IncidentSpectrumAndDetectorResponseProduct * attenuationFactors);
156  }
157 
158  void
159  GetAttenuationFactors(const ParametersType & lineIntegrals, vnl_vector<double> & attenuationFactors) const
160  {
161  // Apply attenuation at each energy
162  vnl_vector<double> vnlLineIntegrals;
163 
164  // Initialize the line integrals vnl vector
165  vnlLineIntegrals.set_size(m_NumberOfMaterials);
166  for (unsigned int m = 0; m < m_NumberOfMaterials; m++)
167  vnlLineIntegrals[m] = lineIntegrals[m];
168 
169  // Apply the material attenuations matrix
170  attenuationFactors = this->m_MaterialAttenuations * vnlLineIntegrals;
171 
172  // Compute the negative exponential
173  for (unsigned int energy = 0; energy < m_NumberOfEnergies; energy++)
174  {
175  attenuationFactors[energy] = std::exp(-attenuationFactors[energy]);
176  }
177  }
178 
181  {
183  initialGuess.SetSize(m_NumberOfMaterials);
184 
185  // Compute the mean attenuation in each bin, weighted by the input spectrum
186  // Needs to be done for each pixel, since the input spectrum is variable
187  MeanAttenuationInBinType MeanAttenuationInBin;
188  MeanAttenuationInBin.SetSize(this->m_NumberOfMaterials, this->m_NumberOfSpectralBins);
189  MeanAttenuationInBin.Fill(0);
190 
191  for (unsigned int mat = 0; mat < this->m_NumberOfMaterials; mat++)
192  {
193  for (unsigned int bin = 0; bin < m_NumberOfSpectralBins; bin++)
194  {
195  double accumulate = 0;
196  double accumulateWeights = 0;
197  for (int energy = m_Thresholds[bin] - 1;
198  (energy < m_Thresholds[bin + 1]) && (energy < (int)(this->m_MaterialAttenuations.rows()));
199  energy++)
200  {
201  accumulate += this->m_MaterialAttenuations[energy][mat] * this->m_IncidentSpectrum[0][energy];
202  accumulateWeights += this->m_IncidentSpectrum[0][energy];
203  }
204  MeanAttenuationInBin[mat][bin] = accumulate / accumulateWeights;
205  }
206  }
207 
208  for (unsigned int mat = 0; mat < m_NumberOfMaterials; mat++)
209  {
210  // Initialise to a very high value
211  initialGuess[mat] = 1e10;
212  for (unsigned int bin = 0; bin < m_NumberOfSpectralBins; bin++)
213  {
214  // Compute the length of current material required to obtain the attenuation
215  // observed in current bin. Keep only the minimum among all bins
216  double requiredLength = this->BinwiseLogTransform()[bin] / MeanAttenuationInBin[mat][bin];
217  if (initialGuess[mat] > requiredLength)
218  initialGuess[mat] = requiredLength;
219  }
220  }
221 
222  return initialGuess;
223  }
224 
227  {
228  itk::VariableLengthVector<double> logTransforms;
229  logTransforms.SetSize(m_NumberOfSpectralBins);
230 
231  vnl_vector<double> ones, nonAttenuated;
232  ones.set_size(m_NumberOfEnergies);
233  ones.fill(1.0);
234 
235  // The way m_IncidentSpectrumAndDetectorResponseProduct works is
236  // it is mutliplied by the vector of attenuations factors (here
237  // filled with ones, since we want the non-attenuated signal)
238  nonAttenuated = m_IncidentSpectrumAndDetectorResponseProduct * ones;
239 
240  for (unsigned int i = 0; i < m_MeasuredData.GetSize(); i++)
241  {
242  // Divide by the actually measured photon counts and apply log
243  if (m_MeasuredData[i] > 0)
244  logTransforms[i] = log(nonAttenuated[i] / m_MeasuredData[i]);
245  }
246 
247  return logTransforms;
248  }
249 
250  virtual vnl_vector<double>
251  GetVariances(const ParametersType & itkNotUsed(lineIntegrals)) const
252  {
253  vnl_vector<double> meaninglessResult;
254  meaninglessResult.set_size(m_NumberOfSpectralBins);
255  meaninglessResult.fill(0.);
256  return (meaninglessResult);
257  }
258 
259  itkSetMacro(MeasuredData, MeasuredDataType);
260  itkGetMacro(MeasuredData, MeasuredDataType);
261 
262  itkSetMacro(DetectorResponse, DetectorResponseType);
263  itkGetMacro(DetectorResponse, DetectorResponseType);
264 
265  itkSetMacro(MaterialAttenuations, MaterialAttenuationsType);
266  itkGetMacro(MaterialAttenuations, MaterialAttenuationsType);
267 
268  itkSetMacro(NumberOfEnergies, unsigned int);
269  itkGetMacro(NumberOfEnergies, unsigned int);
270 
271  itkSetMacro(NumberOfMaterials, unsigned int);
272  itkGetMacro(NumberOfMaterials, unsigned int);
273 
274  itkSetMacro(IncidentSpectrum, IncidentSpectrumType);
275  itkGetMacro(IncidentSpectrum, IncidentSpectrumType);
276 
277  itkSetMacro(NumberOfSpectralBins, unsigned int);
278  itkGetMacro(NumberOfSpectralBins, unsigned int);
279 
280  itkSetMacro(Thresholds, ThresholdsType);
281  itkGetMacro(Thresholds, ThresholdsType);
282 
283 protected:
290  unsigned int m_NumberOfEnergies;
291  unsigned int m_NumberOfMaterials;
295 };
296 
297 } // namespace rtk
298 
299 #endif
virtual vnl_vector< double > ForwardModel(const ParametersType &lineIntegrals) const
void GetAttenuationFactors(const ParametersType &lineIntegrals, vnl_vector< double > &attenuationFactors) const
void GetDerivative(const ParametersType &, DerivativeType &) const override
#define itkSetMacro(name, type)
Superclass::ParametersType ParametersType
Array< ParametersValueType > DerivativeType
virtual vnl_vector< double > GetVariances(const ParametersType &) const