OTB  9.0.0
Orfeo Toolbox
otbKullbackLeiblerDistanceImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
3  * Copyright (C) 2007-2012 Institut Mines Telecom / Telecom Bretagne
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 otbKullbackLeiblerDistanceImageFilter_hxx
23 #define otbKullbackLeiblerDistanceImageFilter_hxx
24 
26 #include <vector>
27 
28 #include "itkImageRegionConstIterator.h"
29 
30 #include "otbMacro.h"
31 
32 namespace otb
33 {
34 
35 /* *******************************************************************
36  * CumulantsForEdgeworth
37  *********************************************************************
38  */
39 template <class TInput>
41 {
42  MakeSumAndMoments(input);
43  MakeCumulants();
44 }
45 
46 template <class TInput>
47 CumulantsForEdgeworth<TInput>::CumulantsForEdgeworth(const itk::Image<typename TInput::ImageType::PixelType, 1>* input)
48 {
49  MakeSumAndMoments(input);
50  MakeCumulants();
51 }
52 
53 /* ========================== Divergence de KL ======================= */
54 
55 template <class TInput>
56 template <class TInput2>
58 {
59  double cum1 = GetMean();
60  double cum2 = GetVariance();
61  double cum3 = GetSkewness();
62 
63  double sqrt_cum2 = sqrt(cum2);
64  double cum2_3 = cum2 * cum2 * cum2;
65  double cum3_2 = cum3 * cum3;
66 
67  double tilde_cum1 = cumulants.GetMean();
68  double tilde_cum2 = cumulants.GetVariance();
69  double tilde_cum3 = cumulants.GetSkewness();
70  double tilde_cum4 = cumulants.GetKurtosis();
71 
72  double tilde_cum2_2 = cum2 * cum2;
73  double tilde_cum2_3 = cum2 * tilde_cum2_2;
74  double tilde_cum2_6 = tilde_cum2_3 * tilde_cum2_3;
75  double tilde_cum3_2 = tilde_cum3 * tilde_cum3;
76 
77  double beta = sqrt_cum2 / tilde_cum2;
78  double alpha = (cum1 - tilde_cum1) / tilde_cum2;
79 
80  double alpha_2 = alpha * alpha;
81  double alpha_4 = alpha_2 * alpha_2;
82  double alpha_6 = alpha_2 * alpha_4;
83 
84  double beta_2 = beta * beta;
85  double beta_4 = beta_2 * beta_2;
86  double beta_6 = beta_2 * beta_4;
87 
88  double c2 = alpha_2 + beta_2;
89  double c3 = alpha * (alpha_2 + 3.0 * beta_2);
90  double c4 = alpha_4 + 6.0 * alpha_2 * beta_2 + 3.0 * beta_4;
91  double c6 = alpha_6 + 15.0 * alpha_4 * beta_2 + 45.0 * alpha_2 * beta_4 + 15.0 * beta_6;
92 
93  double a1 = c3 - 3.0 * alpha / tilde_cum2;
94  double a2 = c4 - 6.0 * c2 / tilde_cum2 + 3.0 / tilde_cum2_2; // Watch for tilde_cum2_2 mistake in the article!
95  double a3 = c6 - 15.0 * c4 / tilde_cum2 + 45.0 * c2 / tilde_cum2_2 - 15.0 / tilde_cum2_3;
96 
97  double tmp = cum1 - tilde_cum1 + sqrt_cum2;
98  double resu = cum3_2 / (12.0 * cum2_3) + (log(tilde_cum2 / cum2) - 1.0 + tmp * tmp / tilde_cum2) / 2.0 -
99  (tilde_cum3 * a1 / 6.0 + tilde_cum4 * a2 / 24.0 + tilde_cum3_2 * a3 / 72.0) -
100  tilde_cum3_2 * (c6 - 6.0 * c4 / cum2 + 9.0 * c2 / tilde_cum2_2) / 72.0 -
101  10.0 * cum3 * tilde_cum3 * (cum1 - tilde_cum1) * (cum2 - tilde_cum2) / tilde_cum2_6;
102 
103  return resu < 0.0 ? 0.0 : resu;
104 }
105 
106 /* ========== Moment estimation from initial neighborhood ============ */
107 
108 template <class TInput>
110 {
111 
112  fSum0 = fSum1 = fSum2 = fSum3 = fSum4 = 0.0;
113  double pixel, pixel_2;
114 
115  for (unsigned long i = 0; i < input.Size(); ++i)
116  {
117  pixel = static_cast<double>(input.GetPixel(i));
118  pixel_2 = pixel * pixel;
119 
120  fSum0 += 1.0;
121  fSum1 += pixel;
122  fSum2 += pixel_2;
123  fSum3 += pixel_2 * pixel;
124  fSum4 += pixel_2 * pixel_2;
125  }
126 
127  fMu1 = fSum1 / fSum0;
128  fMu2 = fSum2 / fSum0 - fMu1 * fMu1;
129 
130  if (fMu2 <= 0.0)
131  {
132  // otbGenericMsgDebugMacro( << "Potential NAN detected in function MakeSumAndMoments.");
133  fMu3 = 0.0;
134  fMu4 = 4.0;
135  fDataAvailable = false;
136  return;
137  }
138 
139  double sigma = sqrt(fMu2);
140 
141  itk::VariableLengthVector<double> tab(input.Size());
142  double* x = const_cast<double*>(tab.GetDataPointer());
143  for (unsigned long i = 0; i < input.Size(); ++i)
144  *x++ = (static_cast<double>(input.GetPixel(i)) - fMu1) / sigma;
145 
146  fMu3 = fMu4 = 0.0;
147  x = const_cast<double*>(tab.GetDataPointer());
148  for (unsigned long i = 0; i < input.Size(); ++i)
149  {
150  pixel = *x++;
151  pixel_2 = pixel * pixel;
152 
153  fMu3 += pixel * pixel_2;
154  fMu4 += pixel_2 * pixel_2;
155  }
156 
157  fMu3 /= fSum0;
158  fMu4 /= fSum0;
159 
160  fDataAvailable = true;
161 }
162 
163 /* ================= Moment estimation from raw data ================= */
164 
165 template <class TInput>
166 void CumulantsForEdgeworth<TInput>::MakeSumAndMoments(const itk::Image<typename TInput::ImageType::PixelType, 1>* input)
167 {
168 
169  fSum0 = fSum1 = fSum2 = fSum3 = fSum4 = 0.0;
170  double pixel, pixel_2;
171 
172  typedef itk::Image<typename TInput::ImageType::PixelType, 1> LocalImageType;
173  typedef itk::ImageRegionConstIterator<LocalImageType> ImageRegionConstIteratorType;
174 
175  ImageRegionConstIteratorType inputIter(input, input->GetRequestedRegion());
176  inputIter.GoToBegin();
177  unsigned int inputSize = 0;
178 
179  while (!inputIter.IsAtEnd())
180  {
181  pixel = static_cast<double>(inputIter.Get());
182  pixel_2 = pixel * pixel;
183 
184  fSum0 += 1.0;
185  fSum1 += pixel;
186  fSum2 += pixel_2;
187  fSum3 += pixel_2 * pixel;
188  fSum4 += pixel_2 * pixel_2;
189 
190  ++inputIter;
191  ++inputSize;
192  }
193 
194  fMu1 = fSum1 / fSum0;
195  fMu2 = fSum2 / fSum0 - fMu1 * fMu1;
196 
197  if (fMu2 <= 0.0)
198  {
199  // otbGenericMsgDebugMacro( << "Potential NAN detected in function MakeSumAndMoments.");
200  fMu3 = 0.0;
201  fMu4 = 4.0;
202 
203  fDataAvailable = false;
204 
205  return;
206  }
207 
208  double sigma = sqrt(fMu2);
209 
210  std::vector<double> tab(inputSize);
211  std::vector<double>::iterator iterTab = tab.begin();
212 
213  inputIter.GoToBegin();
214 
215  while (!inputIter.IsAtEnd())
216  {
217  *iterTab = (static_cast<double>(inputIter.Get()) - fMu1) / sigma;
218 
219  ++inputIter;
220  ++iterTab;
221  }
222 
223  fMu3 = fMu4 = 0.0;
224  for (unsigned int i = 0; i < inputSize; ++i)
225  {
226  pixel = tab[i];
227  pixel_2 = pixel * pixel;
228 
229  fMu3 += pixel * pixel_2;
230  fMu4 += pixel_2 * pixel_2;
231  }
232 
233  fMu3 /= fSum0;
234  fMu4 /= fSum0;
235 
236  otbGenericMsgDebugMacro(<< "Moments: " << fMu1 << ",\t" << fMu2 << ",\t" << fMu3 << ",\t" << fMu4);
237 
238  fDataAvailable = true;
239  // return 0;
240 }
241 
242 /* ================= moments -> cumulants transformation ============= */
243 
244 template <class TInput>
246 {
247  if (fDataAvailable)
248  {
249  fMean = fMu1;
250  fVariance = fMu2;
251  fSkewness = fMu3;
252  fKurtosis = fMu4 - 3.0;
253  }
254  // return 0;
255 }
256 
257 } // end of namespace otb
258 
259 #endif
otb::CumulantsForEdgeworth::MakeCumulants
void MakeCumulants()
Definition: otbKullbackLeiblerDistanceImageFilter.hxx:245
otb::CumulantsForEdgeworth::GetVariance
double GetVariance() const
Definition: otbKullbackLeiblerDistanceImageFilter.h:55
otb::CumulantsForEdgeworth::CumulantsForEdgeworth
CumulantsForEdgeworth(const TInput &input)
Definition: otbKullbackLeiblerDistanceImageFilter.hxx:40
otb::CumulantsForEdgeworth::GetMean
double GetMean() const
Definition: otbKullbackLeiblerDistanceImageFilter.h:51
otb::CumulantsForEdgeworth::GetKurtosis
double GetKurtosis() const
Definition: otbKullbackLeiblerDistanceImageFilter.h:63
otb::CumulantsForEdgeworth::GetSkewness
double GetSkewness() const
Definition: otbKullbackLeiblerDistanceImageFilter.h:59
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otbKullbackLeiblerDistanceImageFilter.h
otb::CumulantsForEdgeworth
Helper class for KullbackLeiblerDistanceImageFilter. Please refer to KullbackLeiblerDistanceImageFilt...
Definition: otbKullbackLeiblerDistanceImageFilter.h:38
otbMacro.h
otbGenericMsgDebugMacro
#define otbGenericMsgDebugMacro(x)
Definition: otbMacro.h:63
otb::CumulantsForEdgeworth::MakeSumAndMoments
void MakeSumAndMoments(const TInput &input)
Definition: otbKullbackLeiblerDistanceImageFilter.hxx:109
otb::CumulantsForEdgeworth::Divergence
double Divergence(const CumulantsForEdgeworth< TInput2 > &cumulants)
Definition: otbKullbackLeiblerDistanceImageFilter.hxx:57