OTB  9.0.0
Orfeo Toolbox
otbVcaImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
4  *
5  * This file is part of Orfeo Toolbox
6  *
7  * https://www.orfeo-toolbox.org/
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifndef otbVCAImageFilter_hxx
23 #define otbVCAImageFilter_hxx
24 
25 #include "otbVcaImageFilter.h"
27 
28 namespace otb
29 {
30 
31 template <class TImage>
32 VCAImageFilter<TImage>::VCAImageFilter() : m_NumberOfEndmembers(0)
33 {
34 }
35 
36 template <class TImage>
38 {
39 }
40 
41 template <class TImage>
43 {
44  // call the superclass' implementation of this method
45  Superclass::GenerateOutputInformation();
46 
47  // get pointers to the input and output
48  typename VectorImageType::ConstPointer inputPtr = this->GetInput();
49  typename VectorImageType::Pointer outputPtr = this->GetOutput();
50 
51  if (!inputPtr || !outputPtr)
52  {
53  return;
54  }
55 
56  const unsigned int numberOfBands = inputPtr->GetNumberOfComponentsPerPixel();
57  RegionType outputRegion;
58  IndexType outputOrigin;
59  SizeType outputSize;
60 
61  outputOrigin.Fill(0);
62  outputSize[0] = m_NumberOfEndmembers;
63  outputSize[1] = 1;
64  outputRegion.SetIndex(outputOrigin);
65  outputRegion.SetSize(outputSize);
66 
67  outputPtr->SetLargestPossibleRegion(outputRegion);
68  outputPtr->SetNumberOfComponentsPerPixel(numberOfBands);
69 }
70 
71 template <class TImage>
73 {
74  typedef typename ForwardPCAImageFilterType::NormalizeFilterType NormalizeFilterType;
75 
76  VectorImageType* input = const_cast<VectorImageType*>(this->GetInput());
77  const unsigned int nbBands = this->GetInput()->GetNumberOfComponentsPerPixel();
78 
79 
80  otbMsgDevMacro("Computing image stats") typename StreamingStatisticsVectorImageFilterType::Pointer statsInput =
81  StreamingStatisticsVectorImageFilterType::New();
82 
83  statsInput->SetInput(input);
84  statsInput->SetEnableMinMax(false);
85  statsInput->Update();
86 
87  double SNR, SNRth;
88  vnl_matrix<PrecisionType> Ud;
89 
90  // SNR computation
91  {
92  vnl_matrix<PrecisionType> R = statsInput->GetCorrelation().GetVnlMatrix();
93  vnl_svd<PrecisionType> svd(R);
94  vnl_matrix<PrecisionType> U = svd.U();
95  Ud = U.get_n_columns(0, m_NumberOfEndmembers);
96  vnl_matrix<PrecisionType> Udt = Ud.transpose();
97 
98  // To remove the mean
99  typename NormalizeFilterType::Pointer normalize = NormalizeFilterType::New();
100  normalize->SetInput(input);
101  normalize->SetMean(statsInput->GetMean());
102  normalize->SetUseMean(true);
103  normalize->SetUseStdDev(false);
104 
105  typename MatrixImageFilterType::Pointer mulUd = MatrixImageFilterType::New();
106  mulUd->MatrixByVectorOn();
107  mulUd->SetInput(normalize->GetOutput());
108  mulUd->SetMatrix(Udt);
109  mulUd->UpdateOutputInformation();
110 
111  typename StreamingStatisticsVectorImageFilterType::Pointer transformedStats = StreamingStatisticsVectorImageFilterType::New();
112 
113  transformedStats->SetInput(mulUd->GetOutput());
114  transformedStats->SetEnableMinMax(false);
115  transformedStats->Update();
116 
117  double P_R = nbBands * statsInput->GetComponentCorrelation();
118  double P_Rp = m_NumberOfEndmembers * transformedStats->GetComponentCorrelation() + statsInput->GetMean().GetSquaredNorm();
119  // const double qL = static_cast<double>(m_NumberOfEndmembers) / nbBands;
120  SNR = std::abs(10 * std::log10((P_Rp - (m_NumberOfEndmembers / nbBands) * P_R) / (P_R - P_Rp)));
121  }
122 
123  SNRth = 15.0 + 10.0 * std::log(static_cast<double>(m_NumberOfEndmembers)) + 8.0;
124 
125  typename VectorImageType::Pointer Xd;
126  typename VectorImageType::Pointer Y;
127 
128  std::vector<itk::ProcessObject::Pointer> refHolder;
129  typename ForwardPCAImageFilterType::Pointer pca = ForwardPCAImageFilterType::New();
130  typename NormalizeFilterType::Pointer normalize = NormalizeFilterType::New();
131 
132  if (SNR > SNRth)
133  {
134  otbMsgDevMacro("Using projective projection for dimensionnality reduction")
135 
136  otbMsgDevMacro("Computing SVD of correlation matrix")
137  // Take the correlation matrix
138  vnl_matrix<PrecisionType>
139  R = statsInput->GetCorrelation().GetVnlMatrix();
140 
141  // Apply SVD
142  vnl_svd<PrecisionType> svd(R);
143  vnl_matrix<PrecisionType> U = svd.U();
144  Ud = U.get_n_columns(0, m_NumberOfEndmembers);
145  vnl_matrix<PrecisionType> UdT = Ud.transpose();
146 
147  otbMsgDevMacro("Apply dimensionality reduction")
148  // Xd = Ud.'*M;
149  typename MatrixImageFilterType::Pointer mulUd = MatrixImageFilterType::New();
150  mulUd->MatrixByVectorOn();
151  mulUd->SetInput(this->GetInput());
152  mulUd->SetMatrix(UdT);
153  mulUd->UpdateOutputInformation();
154  refHolder.push_back(mulUd.GetPointer());
155 
156  Xd = mulUd->GetOutput();
157 
158  // Compute mean(Xd)
159  otbMsgDevMacro("Compute mean(Xd)") typename StreamingStatisticsVectorImageFilterType::Pointer statsXd = StreamingStatisticsVectorImageFilterType::New();
160  statsXd->SetEnableSecondOrderStats(false);
161  statsXd->SetInput(Xd);
162  // statsXd->GetStreamer()->SetNumberOfDivisionsStrippedStreaming(10);
163  statsXd->Update();
164  typename VectorImageType::PixelType Xdmean = statsXd->GetMean();
165  otbMsgDevMacro("mean(Xd) = " << Xdmean)
166 
167  // Projective projection
168  // Xd ./ repmat( sum( Xd .* repmat(u, [1 N]) ) , [d 1]);
169  otbMsgDevMacro("Compute projective projection") typename ProjectiveProjectionImageFilterType::Pointer proj = ProjectiveProjectionImageFilterType::New();
170  proj->SetInput(Xd);
171  proj->GetModifiableFunctor().SetProjectionDirection(Xdmean);
172  refHolder.push_back(proj.GetPointer());
173 
174  Xd = proj->GetOutput();
175  Y = Xd;
176  }
177  else
178  {
179  otbMsgDevMacro("Using PCA for dimensionnality reduction")
180 
181  normalize->SetInput(input);
182  normalize->SetMean(statsInput->GetMean());
183  normalize->SetUseMean(true);
184  normalize->SetUseStdDev(false);
185 
186  // Take the correlation matrix
187  vnl_matrix<PrecisionType> R = statsInput->GetCovariance().GetVnlMatrix();
188 
189  // Apply SVD
190  vnl_svd<PrecisionType> svd(R);
191  vnl_matrix<PrecisionType> U = svd.U();
192  Ud = U.get_n_columns(0, m_NumberOfEndmembers - 1);
193  vnl_matrix<PrecisionType> UdT = Ud.transpose();
194 
195  typename MatrixImageFilterType::Pointer mulUd = MatrixImageFilterType::New();
196  mulUd->MatrixByVectorOn();
197  mulUd->SetInput(normalize->GetOutput());
198  mulUd->SetMatrix(UdT);
199  mulUd->UpdateOutputInformation();
200  refHolder.push_back(mulUd.GetPointer());
201 
202  Xd = mulUd->GetOutput();
203 
204  typename VectorImageToAmplitudeImageFilterType::Pointer normComputer = VectorImageToAmplitudeImageFilterType::New();
205  normComputer->SetInput(Xd);
206 
207  typename StreamingMinMaxImageFilterType::Pointer maxNormComputer = StreamingMinMaxImageFilterType::New();
208  maxNormComputer->SetInput(normComputer->GetOutput());
209  maxNormComputer->Update();
210  typename ImageType::PixelType maxNorm = maxNormComputer->GetMaximum();
211  otbMsgDevMacro("maxNorm : " << maxNorm)
212 
213  typename ConcatenateScalarValueImageFilterType::Pointer concat = ConcatenateScalarValueImageFilterType::New();
214  concat->SetInput(Xd);
215  concat->SetScalarValue(maxNorm);
216  refHolder.push_back(concat.GetPointer());
217 
218  Y = concat->GetOutput();
219  Y->UpdateOutputInformation();
220  }
221 
222  // E : result, will contain the endmembers
223  vnl_matrix<PrecisionType> E(nbBands, m_NumberOfEndmembers);
224 
225  // A = zeros(q, q)
226  // A(q, 1) = 1
227  vnl_matrix<PrecisionType> A(m_NumberOfEndmembers, m_NumberOfEndmembers);
228  A.fill(0);
229  A(m_NumberOfEndmembers - 1, 0) = 1;
230  typename RandomVariateGeneratorType::Pointer randomGen = RandomVariateGeneratorType::GetInstance();
231 
232  for (unsigned int i = 0; i < m_NumberOfEndmembers; ++i)
233  {
234  otbMsgDevMacro("----------------------------------------") otbMsgDevMacro("Iteration " << i)
235 
236  // w = rand(q, 1)
237  otbMsgDevMacro("Random vector generation ") vnl_vector<PrecisionType>
238  w(m_NumberOfEndmembers);
239  for (unsigned int j = 0; j < w.size(); ++j)
240  {
241  w(j) = randomGen->GetVariateWithOpenRange();
242  }
243 
244  // f = ((I - A*pinv(A))*w) / (norm(I - A*pinv(A))*w))
245  otbMsgDevMacro("f = ((I - A*pinv(A))*w) /(norm(I - A*pinv(A))*w))") vnl_matrix<PrecisionType> tmpMat(m_NumberOfEndmembers, m_NumberOfEndmembers);
246  tmpMat.set_identity();
247  otbMsgDevMacro("A" << std::endl << A) vnl_svd<PrecisionType> Asvd(A);
248  tmpMat -= A * Asvd.inverse();
249 
250  vnl_vector<PrecisionType> tmpNumerator = tmpMat * w;
251  vnl_vector<PrecisionType> f = tmpNumerator / tmpNumerator.two_norm();
252 
253  // v = f.'*Y
254  otbMsgDevMacro("f = " << f);
255  otbMsgDevMacro("v = f.'*Y");
256  typename DotProductImageFilterType::Pointer dotfY = DotProductImageFilterType::New();
257  dotfY->SetInput(Y);
258 
259  typename VectorImageType::PixelType fV(f.data_block(), f.size());
260  dotfY->GetModifiableFunctor().SetVector(typename VectorImageType::PixelType(fV));
261  typename ImageType::Pointer v = dotfY->GetOutput();
262 
263  // abs(v)
264  otbMsgDevMacro("abs(v)");
265  typename AbsImageFilterType::Pointer absVFilter = AbsImageFilterType::New();
266  absVFilter->SetInput(v);
267 
268  // max(abs(v))
269  otbMsgDevMacro("max(abs(v))");
270  typename StreamingMinMaxImageFilterType::Pointer maxAbs = StreamingMinMaxImageFilterType::New();
271  maxAbs->SetInput(absVFilter->GetOutput());
272  maxAbs->Update();
273 
274  // k = arg_max( max(abs(v)) )
275  otbMsgDevMacro("k = arg_max( max(abs(v)) )") IndexType maxIdx = maxAbs->GetMaximumIndex();
276  otbMsgDevMacro("max : " << maxAbs->GetMaximum()) otbMsgDevMacro("maxIdx : " << maxIdx)
277 
278  // extract Y(:, k)
279  otbMsgDevMacro("Y(:, k)") RegionType region;
280  region.SetIndex(maxIdx);
281  SizeType size;
282  size.Fill(1);
283  region.SetSize(size);
284  Y->SetRequestedRegion(region);
285  Y->Update();
286 
287  // store new endmember in A
288  // A(:, i) = Y(:, k)
289  otbMsgDevMacro("A(:, i) = Y(:, k)") typename VectorImageType::PixelType e = Y->GetPixel(maxIdx);
290  otbMsgDevMacro("e = " << e) A.set_column(i, e.GetDataPointer());
291 
292  otbMsgDevMacro("A" << std::endl
293  << A)
294 
295  // reproject new endmember in original space
296  vnl_vector<PrecisionType>
297  u;
298  if (SNR > SNRth)
299  {
300  // u = Ud * Xd(:, k)
301  otbMsgDevMacro("u = Ud * Xd(:, k)") Xd->SetRequestedRegion(region);
302  Xd->Update();
303  typename VectorImageType::PixelType xd = Xd->GetPixel(maxIdx);
304  vnl_vector<PrecisionType> xdV(xd.GetDataPointer(), xd.GetSize());
305  u = Ud * xdV;
306  }
307  else
308  {
309  // u = invPCA( Xd(:, k) )
310  otbMsgDevMacro("u = Ud * Xd(:, k)") Xd->SetRequestedRegion(region);
311  Xd->Update();
312  typename VectorImageType::PixelType xd = Xd->GetPixel(maxIdx);
313  vnl_vector<PrecisionType> xdV(xd.GetDataPointer(), xd.GetSize());
314  // Ud = pca->GetTransformationMatrix().GetVnlMatrix().transpose();
315 
316  vnl_vector<PrecisionType> mean(statsInput->GetMean().GetDataPointer(), statsInput->GetMean().GetSize());
317  u = Ud * xdV + mean;
318  }
319 
320  // E(:, i) = u
321  otbMsgDevMacro("E(:, i) = u") otbMsgDevMacro("u = " << u) E.set_column(i, u);
322  }
323 
324  typename VectorImageType::Pointer output = this->GetOutput();
325  output->SetRegions(output->GetLargestPossibleRegion());
326  // output->SetNumberOfComponentsPerPixel(input->GetNumberOfComponentsPerPixel());
327  output->Allocate();
328 
329  itk::ImageRegionIteratorWithIndex<VectorImageType> it(output, output->GetLargestPossibleRegion());
330  unsigned int i;
331  for (it.GoToBegin(), i = 0; !it.IsAtEnd(); ++it, ++i)
332  {
333  vnl_vector<PrecisionType> e = E.get_column(i);
334  typename VectorImageType::PixelType pixel(input->GetNumberOfComponentsPerPixel());
335  for (unsigned int j = 0; j < e.size(); ++j)
336  {
337  pixel[j] = E(j, i);
338  }
339  it.Set(pixel);
340  }
341 }
342 
346 template <class TImage>
347 void VCAImageFilter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
348 {
349  Superclass::PrintSelf(os, indent);
350 }
351 
352 } // end namespace otb
353 
354 #endif
otb::VectorImageToAmplitudeImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbVectorImageToAmplitudeImageFilter.h:73
otb::StreamingMinMaxImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbStreamingMinMaxImageFilter.h:200
otb::mean
Definition: otbParserXPlugins.h:261
otb::ConcatenateScalarValueImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbConcatenateScalarValueImageFilter.h:112
otb::VCAImageFilter::GenerateOutputInformation
void GenerateOutputInformation() override
Definition: otbVcaImageFilter.hxx:42
otb::StreamingStatisticsVectorImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbStreamingStatisticsVectorImageFilter.h:304
otb::VCAImageFilter::IndexType
VectorImageType::IndexType IndexType
Definition: otbVcaImageFilter.h:76
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::FunctorImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbFunctorImageFilter.h:329
otb::VCAImageFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbVcaImageFilter.hxx:347
otb::VCAImageFilter::SizeType
VectorImageType::SizeType SizeType
Definition: otbVcaImageFilter.h:77
otb::VCAImageFilter::VectorImageType
TVectorImage VectorImageType
Definition: otbVcaImageFilter.h:75
otb::VCAImageFilter::~VCAImageFilter
~VCAImageFilter() override
Definition: otbVcaImageFilter.hxx:37
otb::MatrixImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbMatrixImageFilter.h:67
otb::VCAImageFilter::RegionType
VectorImageType::RegionType RegionType
Definition: otbVcaImageFilter.h:78
otbMsgDevMacro
#define otbMsgDevMacro(x)
Definition: otbMacro.h:64
otb::PCAImageFilter::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbPCAImageFilter.h:59
otb::VCAImageFilter::VCAImageFilter
VCAImageFilter()
Definition: otbVcaImageFilter.hxx:32
otb::Image::PixelType
Superclass::PixelType PixelType
Definition: otbImage.h:107
otb::NormalizeVectorImageFilter
Normalize an VectorImage by setting its mean to zero and possibly variance to one (band by band).
Definition: otbNormalizeVectorImageFilter.h:132
otb::Image::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbImage.h:97
otb::VCAImageFilter::GenerateData
void GenerateData() override
Definition: otbVcaImageFilter.hxx:72
otbStandardWriterWatcher.h
otbVcaImageFilter.h