21 #ifndef otbPCAImageFilter_hxx
22 #define otbPCAImageFilter_hxx
27 #include <vnl/vnl_matrix.h>
28 #include <vnl/algo/vnl_symmetric_eigensystem.h>
29 #include <vnl/algo/vnl_generalized_eigensystem.h>
34 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
37 this->SetNumberOfRequiredInputs(1);
39 m_NumberOfPrincipalComponentsRequired = 0;
41 m_UseNormalization =
false;
42 m_UseVarianceForNormalization =
false;
43 m_GivenMeanValues =
false;
44 m_GivenStdDevValues =
false;
46 m_GivenCovarianceMatrix =
false;
47 m_GivenTransformationMatrix =
false;
48 m_IsTransformationMatrixForward =
true;
50 m_CovarianceEstimator = CovarianceEstimatorFilterType::New();
51 m_Transformer = TransformFilterType::New();
52 m_Transformer->MatrixByVectorOn();
53 m_Normalizer = NormalizeFilterType::New();
56 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
59 Superclass::GenerateOutputInformation();
61 switch (
static_cast<int>(DirectionOfTransformation))
65 if (m_NumberOfPrincipalComponentsRequired == 0 || m_NumberOfPrincipalComponentsRequired > this->GetInput()->GetNumberOfComponentsPerPixel())
67 m_NumberOfPrincipalComponentsRequired = this->GetInput()->GetNumberOfComponentsPerPixel();
70 this->GetOutput()->SetNumberOfComponentsPerPixel(m_NumberOfPrincipalComponentsRequired);
75 unsigned int theOutputDimension = 0;
76 if (m_GivenTransformationMatrix)
78 theOutputDimension = m_TransformationMatrix.Rows() >= m_TransformationMatrix.Cols() ? m_TransformationMatrix.Rows() : m_TransformationMatrix.Cols();
80 else if (m_GivenCovarianceMatrix)
82 theOutputDimension = m_CovarianceMatrix.Rows() >= m_CovarianceMatrix.Cols() ? m_CovarianceMatrix.Rows() : m_CovarianceMatrix.Cols();
86 throw itk::ExceptionObject(__FILE__, __LINE__,
"Covariance or transformation matrix required to know the output size", ITK_LOCATION);
89 this->GetOutput()->SetNumberOfComponentsPerPixel(theOutputDimension);
94 throw itk::ExceptionObject(__FILE__, __LINE__,
"Class should be templeted with FORWARD or INVERSE only...", ITK_LOCATION);
98 switch (
static_cast<int>(DirectionOfTransformation))
102 ForwardGenerateOutputInformation();
107 ReverseGenerateOutputInformation();
113 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
116 typename InputImageType::Pointer inputImgPtr =
const_cast<InputImageType*
>(this->GetInput());
118 if (!m_GivenTransformationMatrix)
120 if (!m_GivenCovarianceMatrix)
122 if (m_UseNormalization)
124 m_Normalizer->SetInput(inputImgPtr);
125 m_Normalizer->SetUseStdDev(m_UseVarianceForNormalization);
127 if (m_GivenMeanValues)
128 m_Normalizer->SetMean(m_MeanValues);
130 if (m_GivenStdDevValues)
131 m_Normalizer->SetStdDev(m_StdDevValues);
133 m_Normalizer->GetOutput()->UpdateOutputInformation();
135 if (!m_GivenMeanValues)
137 m_MeanValues = m_Normalizer->GetCovarianceEstimator()->GetMean();
139 m_Normalizer->SetMean(m_MeanValues);
141 if (!m_GivenStdDevValues)
143 m_StdDevValues = m_Normalizer->GetFunctor().GetStdDev();
145 if (m_UseVarianceForNormalization)
148 m_Normalizer->SetStdDev(m_StdDevValues);
154 m_CovarianceMatrix = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
156 auto cov = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
157 auto numberOfComponent = this->GetInput()->GetNumberOfComponentsPerPixel();
159 for (
unsigned int r = 0; r < numberOfComponent; ++r)
161 for (
unsigned int c = 0; c < numberOfComponent; ++c)
163 m_CovarianceMatrix(r, c) = cov(r, c) / std::sqrt(cov(r, r) * cov(c, c));
169 m_Normalizer->SetUseStdDev(
false);
170 m_CovarianceMatrix = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
175 m_CovarianceEstimator->SetInput(m_Normalizer->GetOutput());
176 m_CovarianceEstimator->UpdateOutputInformation();
177 m_CovarianceMatrix = m_CovarianceEstimator->GetCovariance();
180 m_Transformer->SetInput(m_Normalizer->GetOutput());
184 m_CovarianceEstimator->SetInput(inputImgPtr);
185 m_CovarianceEstimator->Update();
187 m_CovarianceMatrix = m_CovarianceEstimator->GetCovariance();
189 m_Transformer->SetInput(inputImgPtr);
194 m_Transformer->SetInput(inputImgPtr);
197 GenerateTransformationMatrix();
199 else if (!m_IsTransformationMatrixForward)
202 m_TransformationMatrix = m_TransformationMatrix.GetInverse();
204 m_Transformer->SetInput(inputImgPtr);
207 if (m_TransformationMatrix.GetVnlMatrix().empty())
209 throw itk::ExceptionObject(__FILE__, __LINE__,
"Empty transformation matrix", ITK_LOCATION);
213 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
216 if (!m_GivenTransformationMatrix)
218 if (!m_GivenCovarianceMatrix)
220 throw itk::ExceptionObject(__FILE__, __LINE__,
"No Covariance nor Transformation matrix given", ITK_LOCATION);
223 GenerateTransformationMatrix();
225 m_TransformationMatrix = m_TransformationMatrix.GetInverse();
227 else if (m_IsTransformationMatrixForward)
230 m_IsTransformationMatrixForward =
false;
232 m_TransformationMatrix = m_TransformationMatrix.GetInverse();
235 if (m_TransformationMatrix.GetVnlMatrix().empty())
237 throw itk::ExceptionObject(__FILE__, __LINE__,
"Empty transformation matrix", ITK_LOCATION);
240 m_Transformer->SetInput(this->GetInput());
241 m_Transformer->SetMatrix(m_TransformationMatrix.GetVnlMatrix());
242 m_Normalizer->SetInput(m_Transformer->GetOutput());
244 if (m_GivenStdDevValues || m_GivenMeanValues)
246 if (m_GivenStdDevValues)
249 for (
unsigned int i = 0; i < m_StdDevValues.Size(); ++i)
250 revStdDev[i] = 1. / m_StdDevValues[i];
251 m_Normalizer->SetStdDev(revStdDev);
254 if (m_GivenMeanValues)
257 if (m_GivenStdDevValues)
259 for (
unsigned int i = 0; i < m_MeanValues.Size(); ++i)
260 revMean[i] = -m_MeanValues[i] / m_StdDevValues[i];
261 m_Normalizer->SetUseStdDev(
true);
265 for (
unsigned int i = 0; i < m_MeanValues.Size(); ++i)
266 revMean[i] = -m_MeanValues[i];
267 m_Normalizer->SetUseStdDev(
false);
269 m_Normalizer->SetMean(revMean);
274 m_Normalizer->SetUseMean(
false);
275 m_Normalizer->SetUseStdDev(
false);
280 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
283 switch (
static_cast<int>(DirectionOfTransformation))
286 return ForwardGenerateData();
288 return ReverseGenerateData();
290 throw itk::ExceptionObject(__FILE__, __LINE__,
"Class should be templated with FORWARD or INVERSE only...", ITK_LOCATION);
294 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
297 m_Transformer->SetMatrix(m_TransformationMatrix.GetVnlMatrix());
298 m_Transformer->GraftOutput(this->GetOutput());
299 m_Transformer->Update();
300 this->GraftOutput(m_Transformer->GetOutput());
303 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
307 if (m_GivenStdDevValues || m_GivenMeanValues)
309 m_Normalizer->GraftOutput(this->GetOutput());
310 m_Normalizer->Update();
311 this->GraftOutput(m_Normalizer->GetOutput());
315 m_Transformer->GraftOutput(this->GetOutput());
316 m_Transformer->Update();
317 this->GraftOutput(m_Transformer->GetOutput());
321 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
325 vnl_vector<double> vectValP;
326 vnl_symmetric_eigensystem_compute(m_CovarianceMatrix.GetVnlMatrix(), transf, vectValP);
329 m_EigenValues.SetSize(m_NumberOfPrincipalComponentsRequired);
330 for (
unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i)
331 m_EigenValues[m_NumberOfPrincipalComponentsRequired - 1 - i] =
static_cast<RealType>(vectValP[i]);
336 for (
unsigned int i = 0; i < vectValP.size(); ++i)
337 valP(i, i) = vectValP[i];
339 for (
unsigned int i = 0; i < valP.rows(); ++i)
341 if (valP(i,i) != 0.0)
342 valP(i,i) = 1.0 / std::sqrt(std::abs(valP(i,i)));
344 throw itk::ExceptionObject(__FILE__, __LINE__,
"Null Eigen value !!", ITK_LOCATION);
346 transf = valP * transf.transpose();
349 transf = transf.transpose();
354 if (m_NumberOfPrincipalComponentsRequired != this->GetInput()->GetNumberOfComponentsPerPixel())
355 m_TransformationMatrix = transf.get_n_rows(0, m_NumberOfPrincipalComponentsRequired);
357 m_TransformationMatrix = transf;
361 template <
class TInputImage,
class TOutputImage, Transform::TransformDirection TDirectionOfTransformation>
364 Superclass::PrintSelf(os, indent);
366 os << indent <<
"m_UseNormalization = ";
367 if (m_UseNormalization)
372 if (m_GivenMeanValues)
373 os << indent <<
"Given Mean : " << m_MeanValues <<
"\n";
375 if (m_GivenStdDevValues)
376 os << indent <<
"Given StdDev : " << m_StdDevValues <<
"\n";
378 if (!m_CovarianceMatrix.GetVnlMatrix().empty())
380 os << indent <<
"Covariance matrix";
381 if (m_GivenCovarianceMatrix)
385 m_CovarianceMatrix.GetVnlMatrix().print(os);
387 if (m_GivenCovarianceMatrix)
388 m_CovarianceEstimator->Print(os, indent.GetNextIndent());
391 if (!m_TransformationMatrix.GetVnlMatrix().empty())
394 if (!m_IsTransformationMatrixForward)
396 os <<
"Transformation matrix";
397 if (m_GivenTransformationMatrix)
401 m_TransformationMatrix.GetVnlMatrix().print(os);
404 if (m_EigenValues.Size() > 0)
406 os << indent <<
"Eigen value :";
407 for (
unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i)
408 os <<
" " << m_EigenValues[i];
415 #endif // otbPCAImageFilter_hxx