OTB  9.0.0
Orfeo Toolbox
otbMNFImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbMNFImageFilter_hxx
22 #define otbMNFImageFilter_hxx
23 #include "otbMNFImageFilter.h"
24 
25 #include "itkMacro.h"
26 
27 #include <vnl/vnl_matrix.h>
28 #include <vnl/algo/vnl_cholesky.h>
29 #include <vnl/algo/vnl_matrix_inverse.h>
30 #include <vnl/algo/vnl_symmetric_eigensystem.h>
31 #include <vnl/algo/vnl_generalized_eigensystem.h>
32 
33 namespace otb
34 {
35 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
37 {
38  this->SetNumberOfRequiredInputs(1);
39 
40  m_NumberOfPrincipalComponentsRequired = 0;
41 
42  m_UseNormalization = false;
43  m_GivenMeanValues = false;
44  m_GivenStdDevValues = false;
45 
46  m_GivenCovarianceMatrix = false;
47  m_GivenNoiseCovarianceMatrix = false;
48  m_GivenTransformationMatrix = false;
49  m_IsTransformationMatrixForward = true;
50 
51  m_Normalizer = NormalizeFilterType::New();
52  m_NoiseImageFilter = NoiseImageFilterType::New();
53  m_CovarianceEstimator = CovarianceEstimatorFilterType::New();
54  m_NoiseCovarianceEstimator = CovarianceEstimatorFilterType::New();
55  m_Transformer = TransformFilterType::New();
56  m_Transformer->MatrixByVectorOn();
57 }
58 
59 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
61 // throw itk::ExceptionObject
62 {
63  Superclass::GenerateOutputInformation();
64 
65  switch (static_cast<int>(DirectionOfTransformation))
66  {
67  case static_cast<int>(Transform::FORWARD):
68  {
69  if (m_NumberOfPrincipalComponentsRequired == 0 || m_NumberOfPrincipalComponentsRequired > this->GetInput()->GetNumberOfComponentsPerPixel())
70  {
71  m_NumberOfPrincipalComponentsRequired = this->GetInput()->GetNumberOfComponentsPerPixel();
72  }
73 
74  this->GetOutput()->SetNumberOfComponentsPerPixel(m_NumberOfPrincipalComponentsRequired);
75  break;
76  }
77  case static_cast<int>(Transform::INVERSE):
78  {
79  unsigned int theOutputDimension = 0;
80  if (m_GivenTransformationMatrix)
81  {
82  theOutputDimension = m_TransformationMatrix.Rows() >= m_TransformationMatrix.Cols() ? m_TransformationMatrix.Rows() : m_TransformationMatrix.Cols();
83  }
84  else if (m_GivenCovarianceMatrix)
85  {
86  theOutputDimension = m_CovarianceMatrix.Rows() >= m_CovarianceMatrix.Cols() ? m_CovarianceMatrix.Rows() : m_CovarianceMatrix.Cols();
87  }
88  else
89  {
90  throw itk::ExceptionObject(__FILE__, __LINE__, "Covariance or transformation matrix required to know the output size", ITK_LOCATION);
91  }
92 
93  m_NumberOfPrincipalComponentsRequired = 0;
94  this->GetOutput()->SetNumberOfComponentsPerPixel(theOutputDimension);
95  break;
96  }
97  default: // should not go so far...
98  throw itk::ExceptionObject(__FILE__, __LINE__, "Class should be templeted with FORWARD or INVERSE only...", ITK_LOCATION);
99  }
100 
101 
102  switch (static_cast<int>(DirectionOfTransformation))
103  {
104  case static_cast<int>(Transform::FORWARD):
105  {
106  ForwardGenerateOutputInformation();
107  break;
108  }
109  case static_cast<int>(Transform::INVERSE):
110  {
111  ReverseGenerateOutputInformation();
112  break;
113  }
114  }
115 }
116 
117 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
119 {
120  typename InputImageType::Pointer inputImgPtr = const_cast<InputImageType*>(this->GetInput());
121 
122  if (m_GivenMeanValues)
123  m_Normalizer->SetMean(this->GetMeanValues());
124 
125  if (m_UseNormalization)
126  {
127  m_Normalizer->SetUseStdDev(true);
128  if (m_GivenStdDevValues)
129  m_Normalizer->SetStdDev(this->GetStdDevValues());
130  }
131  else
132  m_Normalizer->SetUseStdDev(false);
133 
134  m_Normalizer->SetInput(inputImgPtr);
135  m_Normalizer->GetOutput()->UpdateOutputInformation();
136 
137  if (!m_GivenMeanValues)
138  m_MeanValues = m_Normalizer->GetCovarianceEstimator()->GetMean();
139 
140  if (m_UseNormalization)
141  {
142  if (!m_GivenStdDevValues)
143  m_StdDevValues = m_Normalizer->GetFunctor().GetStdDev();
144  }
145 
146  if (!m_GivenTransformationMatrix)
147  {
148  if (!m_GivenNoiseCovarianceMatrix)
149  {
150  m_NoiseImageFilter->SetInput(m_Normalizer->GetOutput());
151  m_NoiseCovarianceEstimator->SetInput(m_NoiseImageFilter->GetOutput());
152  m_NoiseCovarianceEstimator->Update();
153 
154  m_NoiseCovarianceMatrix = m_NoiseCovarianceEstimator->GetCovariance();
155  }
156 
157  if (!m_GivenCovarianceMatrix)
158  {
159  m_CovarianceEstimator->SetInput(m_Normalizer->GetOutput());
160  m_CovarianceEstimator->Update();
161 
162  m_CovarianceMatrix = m_CovarianceEstimator->GetCovariance();
163  }
164 
165  GenerateTransformationMatrix();
166  }
167  else if (!m_IsTransformationMatrixForward)
168  {
169  // Prevents from multiple transpose in pipeline
170  m_IsTransformationMatrixForward = true;
171  if (m_TransformationMatrix.Rows() == m_TransformationMatrix.Cols())
172  {
173  m_TransformationMatrix = m_TransformationMatrix.GetInverse();
174  }
175  else
176  {
177  vnl_svd<MatrixElementType> invertor(m_TransformationMatrix.GetVnlMatrix());
178  m_TransformationMatrix = invertor.pinverse();
179  }
180  }
181 
182  if (m_TransformationMatrix.GetVnlMatrix().empty())
183  {
184  throw itk::ExceptionObject(__FILE__, __LINE__, "Empty transformation matrix", ITK_LOCATION);
185  }
186 
187  m_Transformer->SetInput(m_Normalizer->GetOutput());
188  m_Transformer->SetMatrix(m_TransformationMatrix.GetVnlMatrix());
189 }
190 
191 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
193 {
194  if (!m_GivenTransformationMatrix)
195  {
196  if (!m_GivenCovarianceMatrix)
197  {
198  throw itk::ExceptionObject(__FILE__, __LINE__, "Inverse Transformation or at least Covariance matrix is required to invert MNF", ITK_LOCATION);
199  }
200 
201  if (!m_GivenNoiseCovarianceMatrix)
202  {
203  throw itk::ExceptionObject(__FILE__, __LINE__, "Inverse Transformation or at least Noise Covariance matrix is required to invert MNF", ITK_LOCATION);
204  }
205 
206  GenerateTransformationMatrix();
207 
208  m_IsTransformationMatrixForward = false;
209  if (m_TransformationMatrix.Rows() == m_TransformationMatrix.Cols())
210  m_TransformationMatrix = vnl_matrix_inverse<MatrixElementType>(m_TransformationMatrix.GetVnlMatrix());
211  else
212  {
213  vnl_svd<MatrixElementType> invertor(m_TransformationMatrix.GetVnlMatrix());
214  m_TransformationMatrix = invertor.inverse();
215  }
216  }
217  else if (m_IsTransformationMatrixForward)
218  {
219  // Prevent from multiple transpose in pipeline
220  m_IsTransformationMatrixForward = false;
221  if (m_TransformationMatrix.Rows() == m_TransformationMatrix.Cols())
222  {
223  m_TransformationMatrix = vnl_matrix_inverse<MatrixElementType>(m_TransformationMatrix.GetVnlMatrix());
224  }
225  else
226  {
227  vnl_svd<MatrixElementType> invertor(m_TransformationMatrix.GetVnlMatrix());
228  m_TransformationMatrix = invertor.pinverse();
229  }
230  }
231 
232  if (m_TransformationMatrix.GetVnlMatrix().empty())
233  {
234  throw itk::ExceptionObject(__FILE__, __LINE__, "Empty transformation matrix", ITK_LOCATION);
235  }
236 
237  m_Transformer->SetInput(this->GetInput());
238  m_Transformer->SetMatrix(m_TransformationMatrix.GetVnlMatrix());
239 
240  if (!m_GivenMeanValues)
241  {
242  throw itk::ExceptionObject(__FILE__, __LINE__, "Initial means required for correct data centering", ITK_LOCATION);
243  }
244  if (m_UseNormalization)
245  {
246  if (!m_GivenStdDevValues)
247  {
248  throw itk::ExceptionObject(__FILE__, __LINE__, "Initial StdDevs required for de-normalization", ITK_LOCATION);
249  }
250 
251  VectorType revStdDev(m_StdDevValues.Size());
252  for (unsigned int i = 0; i < m_StdDevValues.Size(); ++i)
253  revStdDev[i] = 1. / m_StdDevValues[i];
254  m_Normalizer->SetStdDev(revStdDev);
255 
256  VectorType revMean(m_MeanValues.Size());
257  for (unsigned int i = 0; i < m_MeanValues.Size(); ++i)
258  revMean[i] = -m_MeanValues[i] / m_StdDevValues[i];
259  m_Normalizer->SetMean(revMean);
260  }
261  else
262  {
263  VectorType revMean(m_MeanValues.Size());
264  for (unsigned int i = 0; i < m_MeanValues.Size(); ++i)
265  revMean[i] = -m_MeanValues[i];
266  m_Normalizer->SetMean(revMean);
267  m_Normalizer->SetUseStdDev(false);
268  }
269 
270  m_Normalizer->SetInput(m_Transformer->GetOutput());
271 }
272 
273 
274 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
276 {
277  switch (static_cast<int>(DirectionOfTransformation))
278  {
279  case static_cast<int>(Transform::FORWARD):
280  return ForwardGenerateData();
281  case static_cast<int>(Transform::INVERSE):
282  return ReverseGenerateData();
283  default: // should not go so far
284  throw itk::ExceptionObject(__FILE__, __LINE__, "Class should be templated with FORWARD or INVERSE only...", ITK_LOCATION);
285  }
286 }
287 
288 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
290 {
291  m_Transformer->GraftOutput(this->GetOutput());
292  m_Transformer->Update();
293  this->GraftOutput(m_Transformer->GetOutput());
294 }
295 
296 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
298 {
299  m_Normalizer->GraftOutput(this->GetOutput());
300  m_Normalizer->Update();
301  this->GraftOutput(m_Normalizer->GetOutput());
302 }
303 
304 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
306 {
307  vnl_cholesky choleskySolver(m_NoiseCovarianceMatrix.GetVnlMatrix(), vnl_cholesky::estimate_condition);
308  InternalMatrixType Rn = choleskySolver.lower_triangle();
309  InternalMatrixType Rn_inv = vnl_matrix_inverse<MatrixElementType>(Rn.transpose());
310  InternalMatrixType C = Rn_inv.transpose() * m_CovarianceMatrix.GetVnlMatrix() * Rn_inv;
311 
312  vnl_svd<MatrixElementType> solver(C);
313  InternalMatrixType U = solver.U();
314  InternalMatrixType valP = solver.W();
315 
316  InternalMatrixType transf = Rn_inv * U;
317 
318  transf.inplace_transpose();
319 
320  if (m_NumberOfPrincipalComponentsRequired != this->GetInput()->GetNumberOfComponentsPerPixel())
321  m_TransformationMatrix = transf.get_n_rows(0, m_NumberOfPrincipalComponentsRequired);
322  else
323  m_TransformationMatrix = transf;
324 
325  m_EigenValues.SetSize(m_NumberOfPrincipalComponentsRequired);
326  for (unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i)
327  m_EigenValues[i] = static_cast<RealType>(valP(i, i));
328 }
329 
330 template <class TInputImage, class TOutputImage, class TNoiseImageFilter, Transform::TransformDirection TDirectionOfTransformation>
332 {
333  Superclass::PrintSelf(os, indent);
334 
335  if (m_UseNormalization)
336  {
337  os << indent << "Normalisation with :\n" << indent << "Mean: ";
338  for (unsigned int i = 0; i < m_MeanValues.Size(); ++i)
339  os << m_MeanValues[i] << " ";
340  os << "\n" << indent << "StdDev: ";
341  for (unsigned int i = 0; i < m_StdDevValues.Size(); ++i)
342  os << m_StdDevValues[i] << " ";
343  os << "\n";
344  }
345  else
346  os << indent << "No normalisation\n";
347 
348  if (!m_NoiseCovarianceMatrix.GetVnlMatrix().empty())
349  {
350  os << indent << "Noise Covariance matrix";
351  if (m_GivenNoiseCovarianceMatrix)
352  os << " (given)";
353  os << "\n";
354 
355  m_NoiseCovarianceMatrix.GetVnlMatrix().print(os);
356  }
357 
358  if (!m_CovarianceMatrix.GetVnlMatrix().empty())
359  {
360  os << indent << "Covariance matrix";
361  if (m_GivenCovarianceMatrix)
362  os << " (given)";
363  os << "\n";
364 
365  m_CovarianceMatrix.GetVnlMatrix().print(os);
366  }
367 
368  if (!m_TransformationMatrix.GetVnlMatrix().empty())
369  {
370  os << indent << "Transformation matrix";
371  if (m_GivenTransformationMatrix)
372  os << " (given)";
373  os << "\n";
374 
375  m_TransformationMatrix.GetVnlMatrix().print(os);
376  }
377 
378  if (m_EigenValues.Size() > 0)
379  {
380  os << indent << "RMS value :";
381  for (unsigned int i = 0; i < m_EigenValues.Size(); ++i)
382  os << " " << m_EigenValues[i];
383  os << "\n";
384  }
385 }
386 
387 } // end of namespace otb
388 
389 #endif // otbMNFImageFilter_hxx
otb::MNFImageFilter::GenerateOutputInformation
void GenerateOutputInformation() override
Definition: otbMNFImageFilter.hxx:60
otb::MNFImageFilter::ForwardGenerateOutputInformation
void ForwardGenerateOutputInformation()
Definition: otbMNFImageFilter.hxx:118
otb::MNFImageFilter::MNFImageFilter
MNFImageFilter()
Definition: otbMNFImageFilter.hxx:36
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::Transform::FORWARD
@ FORWARD
Definition: otbPCAImageFilter.h:36
otb::MNFImageFilter::GenerateData
void GenerateData() override
Definition: otbMNFImageFilter.hxx:275
otb::MNFImageFilter::ForwardGenerateData
virtual void ForwardGenerateData()
Definition: otbMNFImageFilter.hxx:289
otb::MNFImageFilter::InternalMatrixType
MatrixType::InternalMatrixType InternalMatrixType
Definition: otbMNFImageFilter.h:82
otb::MNFImageFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbMNFImageFilter.hxx:331
otb::MNFImageFilter::InputImageType
TInputImage InputImageType
Definition: otbMNFImageFilter.h:71
otb::Transform::INVERSE
@ INVERSE
Definition: otbPCAImageFilter.h:37
otb::MNFImageFilter::ReverseGenerateOutputInformation
void ReverseGenerateOutputInformation()
Definition: otbMNFImageFilter.hxx:192
otb::MNFImageFilter::RealType
CovarianceEstimatorFilterType::RealType RealType
Definition: otbMNFImageFilter.h:78
otb::MNFImageFilter::ReverseGenerateData
virtual void ReverseGenerateData()
Definition: otbMNFImageFilter.hxx:297
otb::MNFImageFilter::VectorType
CovarianceEstimatorFilterType::RealPixelType VectorType
Definition: otbMNFImageFilter.h:79
otb::MNFImageFilter::GenerateTransformationMatrix
virtual void GenerateTransformationMatrix()
Definition: otbMNFImageFilter.hxx:305
otbMNFImageFilter.h