OTB  9.0.0
Orfeo Toolbox
otbDifferenceImageFilter.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 otbDifferenceImageFilter_hxx
22 #define otbDifferenceImageFilter_hxx
23 
25 
26 #include "itkConstNeighborhoodIterator.h"
27 #include "itkImageRegionIterator.h"
28 #include "itkNeighborhoodAlgorithm.h"
29 #include "itkProgressReporter.h"
30 #include "itkDefaultConvertPixelTraits.h"
31 
32 namespace otb
33 {
34 
35 //----------------------------------------------------------------------------
36 template <class TInputImage, class TOutputImage>
38 {
39  // We require two inputs to execute.
40  this->SetNumberOfRequiredInputs(2);
41 
42  // Set the default DifferenceThreshold.
43  m_DifferenceThreshold = itk::NumericTraits<ScalarRealType>::Zero;
44 
45  // Set the default ToleranceRadius.
46  m_ToleranceRadius = 0;
47 
48  // Initialize statistics about difference image.
49  itk::NumericTraits<RealType>::SetLength(m_MeanDifference, itk::DefaultConvertPixelTraits<RealType>::GetNumberOfComponents());
50  itk::NumericTraits<AccumulateType>::SetLength(m_TotalDifference, itk::DefaultConvertPixelTraits<RealType>::GetNumberOfComponents());
51  m_MeanDifference = itk::NumericTraits<RealType>::ZeroValue(m_MeanDifference);
52  m_TotalDifference = itk::NumericTraits<AccumulateType>::ZeroValue(m_TotalDifference);
53  m_NumberOfPixelsWithDifferences = 0;
54 
55 }
56 
57 //----------------------------------------------------------------------------
58 template <class TInputImage, class TOutputImage>
59 void DifferenceImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
60 {
61  this->Superclass::PrintSelf(os, indent);
62  os << indent << "ToleranceRadius: " << m_ToleranceRadius << "\n";
63  os << indent << "DifferenceThreshold: " << m_DifferenceThreshold << "\n";
64  os << indent << "MeanDifference: " << m_MeanDifference << "\n";
65  os << indent << "TotalDifference: " << m_TotalDifference << "\n";
66  os << indent << "NumberOfPixelsWithDifferences: " << m_NumberOfPixelsWithDifferences << "\n";
67 }
68 
69 //----------------------------------------------------------------------------
70 template <class TInputImage, class TOutputImage>
72 {
73  // The valid image should be input 0.
74  this->SetInput(0, validImage);
75 }
76 
77 //----------------------------------------------------------------------------
78 template <class TInputImage, class TOutputImage>
80 {
81  // The test image should be input 1.
82  this->SetInput(1, testImage);
83 }
84 
85 template <class TInputImage, class TOutputImage>
87 {
88  Superclass::GenerateOutputInformation();
89  if (this->GetInput(0)->GetNumberOfComponentsPerPixel() != this->GetInput(1)->GetNumberOfComponentsPerPixel())
90  {
91  itkExceptionMacro(<< "Image 1 has " << this->GetInput(0)->GetNumberOfComponentsPerPixel() << " bands, whereas image 2 has "
92  << this->GetInput(1)->GetNumberOfComponentsPerPixel());
93  }
94  this->GetOutput()->SetNumberOfComponentsPerPixel(this->GetInput(0)->GetNumberOfComponentsPerPixel());
95 }
96 
97 template <class TInputImage, class TOutputImage>
99 {
100  this->UpdateOutputInformation();
101 
102  int numberOfThreads = this->GetNumberOfThreads();
103 
104  itk::NumericTraits<RealType>::SetLength(m_MeanDifference, this->GetInput(0)->GetNumberOfComponentsPerPixel());
105  itk::NumericTraits<AccumulateType>::SetLength(m_TotalDifference, this->GetInput(0)->GetNumberOfComponentsPerPixel());
106 
107  // Initialize statistics about difference image.
108  m_MeanDifference = itk::NumericTraits<RealType>::ZeroValue(m_MeanDifference);
109  m_TotalDifference = itk::NumericTraits<AccumulateType>::ZeroValue(m_TotalDifference);
110  m_NumberOfPixelsWithDifferences = 0;
111 
112  // Resize the thread temporaries
113  m_ThreadDifferenceSum.reserve(numberOfThreads);
114  m_ThreadNumberOfPixels.SetSize(numberOfThreads);
115 
116  // Initialize the temporaries
117  for (int i = 0; i < numberOfThreads; ++i)
118  {
119  m_ThreadDifferenceSum.push_back(m_TotalDifference);
120  }
121  m_ThreadNumberOfPixels.Fill(0);
122 }
123 
124 //----------------------------------------------------------------------------
125 template <class TInputImage, class TOutputImage>
127 {
128  typedef itk::ConstNeighborhoodIterator<InputImageType> SmartIterator;
129  typedef itk::ImageRegionConstIterator<InputImageType> InputIterator;
130  typedef itk::ImageRegionIterator<OutputImageType> OutputIterator;
131  typedef itk::NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<InputImageType> FacesCalculator;
132  typedef typename FacesCalculator::RadiusType RadiusType;
133  typedef typename FacesCalculator::FaceListType FaceListType;
134  typedef typename FaceListType::iterator FaceListIterator;
135  typedef typename InputImageType::PixelType InputPixelType;
136 
137  // Prepare standard boundary condition.
138  itk::ZeroFluxNeumannBoundaryCondition<InputImageType> nbc;
139 
140  // Get a pointer to each image.
141  const InputImageType* validImage = this->GetInput(0);
142  const InputImageType* testImage = this->GetInput(1);
143  OutputImageType* outputPtr = this->GetOutput();
144 
145  // Create a radius of pixels.
146  RadiusType radius;
147  radius.Fill(std::max(0, m_ToleranceRadius));
148 
149  // Find the data-set boundary faces.
150  FacesCalculator boundaryCalculator;
151  FaceListType faceList = boundaryCalculator(testImage, threadRegion, radius);
152 
153  // Support progress methods/callbacks.
154  itk::ProgressReporter progress(this, threadId, threadRegion.GetNumberOfPixels());
155 
156  AccumulateType threadDifferenceSum;
157  itk::NumericTraits<AccumulateType>::SetLength(threadDifferenceSum, this->GetInput(0)->GetNumberOfComponentsPerPixel()); // @post: threadDifferenceSum=={0...}
158  unsigned long threadNumberOfPixels = 0;
159 
160  // Process the internal face and each of the boundary faces.
161  for (FaceListIterator face = faceList.begin(); face != faceList.end(); ++face)
162  {
163  SmartIterator test(radius, testImage, *face); // Iterate over test image.
164  InputIterator valid(validImage, *face); // Iterate over valid image.
165  OutputIterator out(outputPtr, *face); // Iterate over output image.
166  test.OverrideBoundaryCondition(&nbc);
167 
168  // Extract a typical pixel in order to know the exact size of the
169  // pixel, the typical 0, and the typical max
170  valid.GoToBegin();
171  InputPixelType t = valid.Get();
172 
173  const auto pixel_size = itk::NumericTraits<InputPixelType>::GetLength(t);
174  const auto out_max = itk::NumericTraits<OutputPixelType>::max(t);
175  const auto zero = itk::NumericTraits<OutputPixelType>::ZeroValue(t);
176 
177  OutputPixelType minimumDifference = out_max;
178 
179  for (valid.GoToBegin(), test.GoToBegin(), out.GoToBegin(); !valid.IsAtEnd(); ++valid, ++test, ++out)
180  {
181  // Get the current valid pixel.
182  t = valid.Get();
183 
184  // Find the closest-valued pixel in the neighborhood of the test
185  // image.
186  minimumDifference = out_max; // reset by assignment, avoid allocation in VLV case
187  unsigned int neighborhoodSize = test.Size();
188  for (unsigned int i = 0; i < neighborhoodSize; ++i)
189  {
190 
191  for (unsigned int j = 0; j < pixel_size; ++j)
192  {
193  // Use the RealType for the difference to make sure we get
194  // the sign.
195  // Work on component independently in order to avoid
196  // allocation of VLV pixels
197  ScalarRealType d = static_cast<ScalarRealType>(itk::DefaultConvertPixelTraits<InputPixelType>::GetNthComponent(j, t) -
198  itk::DefaultConvertPixelTraits<InputPixelType>::GetNthComponent(j, test.GetPixel(i)));
199  d = std::abs(d);
200  ScalarRealType m = static_cast<ScalarRealType>(itk::DefaultConvertPixelTraits<OutputPixelType>::GetNthComponent(j, minimumDifference));
201  if (d < m)
202  {
203  itk::DefaultConvertPixelTraits<OutputPixelType>::SetNthComponent(j, minimumDifference, d);
204  // std::cout << std::setprecision(16) << minimumDifference[j] << std::endl;
205  // std::cout << std::setprecision(16) << t << std::endl;
206  // std::cout << std::setprecision(16) << test.GetPixel(i) << std::endl;
207  // std::cout << "----------------------" << std::endl;
208  }
209  }
210  }
211 
212  // for complex and vector type. FIXME: module might be better
213  // ScalarRealType tMax=std::abs(t[0]);
214  ScalarRealType tMax = 0.01; // Avoiding the 0 case for neighborhood computing
215  // NB: still more restrictive than before for small values.
216  for (unsigned int j = 0; j < pixel_size; ++j)
217  {
218  ScalarRealType tc = static_cast<ScalarRealType>(itk::DefaultConvertPixelTraits<InputPixelType>::GetNthComponent(j, t));
219  tMax = std::max(std::abs(tc), tMax);
220  }
221 
222  // Check if difference is above threshold
223  // the threshold is interpreted as relative to the value
224  bool isDifferent = false;
225 
226  for (unsigned int j = 0; j < pixel_size; ++j)
227  {
228  ScalarRealType m = static_cast<ScalarRealType>(itk::DefaultConvertPixelTraits<OutputPixelType>::GetNthComponent(j, minimumDifference));
229  if (m > m_DifferenceThreshold * tMax)
230  {
231  // std::cout << std::setprecision(16) << minimumDifference[j] << std::endl;
232  isDifferent = true;
233  break;
234  }
235  }
236 
237  if (isDifferent)
238  {
239  // Store the minimum difference value in the output image.
240  out.Set(minimumDifference);
241 
242  // Update local difference image statistics.
243  threadDifferenceSum += minimumDifference;
244  threadNumberOfPixels++;
245  }
246  else
247  {
248  // Difference is below threshold.
249  out.Set(zero);
250  }
251 
252  // Update progress.
253  progress.CompletedPixel();
254  }
255  }
256 
257  // Update global difference image statistics.
258  m_ThreadDifferenceSum[threadId] += threadDifferenceSum;
259  m_ThreadNumberOfPixels[threadId] += threadNumberOfPixels;
260 }
261 
262 template <class TInputImage, class TOutputImage>
264 {
265  // Set statistics about difference image.
266  int numberOfThreads = this->GetNumberOfThreads();
267  for (int i = 0; i < numberOfThreads; ++i)
268  {
269  m_TotalDifference += m_ThreadDifferenceSum[i];
270  m_NumberOfPixelsWithDifferences += m_ThreadNumberOfPixels[i];
271  }
272 
273  // Get the total number of pixels processed in the region.
274  // This is different from the m_TotalNumberOfPixels which
275  // is the number of pixels that actually have differences
276  // above the intensity threshold.
277  OutputImageRegionType region = this->GetOutput()->GetRequestedRegion();
278  unsigned int numberOfPixels = region.GetNumberOfPixels();
279 
280  // Calculate the mean difference.
281  m_MeanDifference = m_TotalDifference / numberOfPixels;
282 }
283 
284 
285 
286 } // end namespace otb
287 
288 #endif
otb::DifferenceImageFilter::GenerateOutputInformation
void GenerateOutputInformation() override
Definition: otbDifferenceImageFilter.hxx:86
otb::DifferenceImageFilter::ScalarRealType
itk::NumericTraits< OutputPixelType >::ScalarRealType ScalarRealType
Definition: otbDifferenceImageFilter.h:67
otb::DifferenceImageFilter::Synthetize
void Synthetize(void) override
Definition: otbDifferenceImageFilter.hxx:263
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::DifferenceImageFilter::OutputPixelType
OutputImageType::PixelType OutputPixelType
Definition: otbDifferenceImageFilter.h:63
otb::mpl::GetNumberOfComponents
unsigned int GetNumberOfComponents(PixelType const &pix)
Definition: otbArrayTraits.h:215
otb::DifferenceImageFilter::DifferenceImageFilter
DifferenceImageFilter()
Definition: otbDifferenceImageFilter.hxx:37
otb::DifferenceImageFilter::SetTestInput
virtual void SetTestInput(const InputImageType *testImage)
Definition: otbDifferenceImageFilter.hxx:79
otbDifferenceImageFilter.h
otb::PersistentImageFilter::OutputImageType
TOutputImage OutputImageType
Definition: otbPersistentImageFilter.h:61
otb::PersistentImageFilter::InputImageType
TInputImage InputImageType
Definition: otbPersistentImageFilter.h:57
otb::DifferenceImageFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbDifferenceImageFilter.hxx:59
otb::DifferenceImageFilter::SetValidInput
virtual void SetValidInput(const InputImageType *validImage)
Definition: otbDifferenceImageFilter.hxx:71
otb::DifferenceImageFilter::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbDifferenceImageFilter.h:64
otb::DifferenceImageFilter::Reset
void Reset(void) override
Definition: otbDifferenceImageFilter.hxx:98
otb::DifferenceImageFilter::ThreadedGenerateData
void ThreadedGenerateData(const OutputImageRegionType &threadRegion, itk::ThreadIdType threadId) override
Definition: otbDifferenceImageFilter.hxx:126
otb::DifferenceImageFilter::AccumulateType
itk::NumericTraits< RealType >::AccumulateType AccumulateType
Definition: otbDifferenceImageFilter.h:66