21 #ifndef otbDifferenceImageFilter_hxx
22 #define otbDifferenceImageFilter_hxx
26 #include "itkConstNeighborhoodIterator.h"
27 #include "itkImageRegionIterator.h"
28 #include "itkNeighborhoodAlgorithm.h"
29 #include "itkProgressReporter.h"
30 #include "itkDefaultConvertPixelTraits.h"
36 template <
class TInputImage,
class TOutputImage>
40 this->SetNumberOfRequiredInputs(2);
43 m_DifferenceThreshold = itk::NumericTraits<ScalarRealType>::Zero;
46 m_ToleranceRadius = 0;
51 m_MeanDifference = itk::NumericTraits<RealType>::ZeroValue(m_MeanDifference);
52 m_TotalDifference = itk::NumericTraits<AccumulateType>::ZeroValue(m_TotalDifference);
53 m_NumberOfPixelsWithDifferences = 0;
58 template <
class TInputImage,
class TOutputImage>
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";
70 template <
class TInputImage,
class TOutputImage>
74 this->SetInput(0, validImage);
78 template <
class TInputImage,
class TOutputImage>
82 this->SetInput(1, testImage);
85 template <
class TInputImage,
class TOutputImage>
88 Superclass::GenerateOutputInformation();
89 if (this->GetInput(0)->GetNumberOfComponentsPerPixel() != this->GetInput(1)->GetNumberOfComponentsPerPixel())
91 itkExceptionMacro(<<
"Image 1 has " << this->GetInput(0)->GetNumberOfComponentsPerPixel() <<
" bands, whereas image 2 has "
92 << this->GetInput(1)->GetNumberOfComponentsPerPixel());
94 this->GetOutput()->SetNumberOfComponentsPerPixel(this->GetInput(0)->GetNumberOfComponentsPerPixel());
97 template <
class TInputImage,
class TOutputImage>
100 this->UpdateOutputInformation();
102 int numberOfThreads = this->GetNumberOfThreads();
104 itk::NumericTraits<RealType>::SetLength(m_MeanDifference, this->GetInput(0)->GetNumberOfComponentsPerPixel());
105 itk::NumericTraits<AccumulateType>::SetLength(m_TotalDifference, this->GetInput(0)->GetNumberOfComponentsPerPixel());
108 m_MeanDifference = itk::NumericTraits<RealType>::ZeroValue(m_MeanDifference);
109 m_TotalDifference = itk::NumericTraits<AccumulateType>::ZeroValue(m_TotalDifference);
110 m_NumberOfPixelsWithDifferences = 0;
113 m_ThreadDifferenceSum.reserve(numberOfThreads);
114 m_ThreadNumberOfPixels.SetSize(numberOfThreads);
117 for (
int i = 0; i < numberOfThreads; ++i)
119 m_ThreadDifferenceSum.push_back(m_TotalDifference);
121 m_ThreadNumberOfPixels.Fill(0);
125 template <
class TInputImage,
class TOutputImage>
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;
138 itk::ZeroFluxNeumannBoundaryCondition<InputImageType> nbc;
147 radius.Fill(std::max(0, m_ToleranceRadius));
150 FacesCalculator boundaryCalculator;
151 FaceListType faceList = boundaryCalculator(testImage, threadRegion, radius);
154 itk::ProgressReporter progress(
this, threadId, threadRegion.GetNumberOfPixels());
157 itk::NumericTraits<AccumulateType>::SetLength(threadDifferenceSum, this->GetInput(0)->GetNumberOfComponentsPerPixel());
158 unsigned long threadNumberOfPixels = 0;
161 for (FaceListIterator face = faceList.begin(); face != faceList.end(); ++face)
163 SmartIterator test(radius, testImage, *face);
164 InputIterator valid(validImage, *face);
165 OutputIterator out(outputPtr, *face);
166 test.OverrideBoundaryCondition(&nbc);
171 InputPixelType t = valid.Get();
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);
179 for (valid.GoToBegin(), test.GoToBegin(), out.GoToBegin(); !valid.IsAtEnd(); ++valid, ++test, ++out)
186 minimumDifference = out_max;
187 unsigned int neighborhoodSize = test.Size();
188 for (
unsigned int i = 0; i < neighborhoodSize; ++i)
191 for (
unsigned int j = 0; j < pixel_size; ++j)
198 itk::DefaultConvertPixelTraits<InputPixelType>::GetNthComponent(j, test.GetPixel(i)));
203 itk::DefaultConvertPixelTraits<OutputPixelType>::SetNthComponent(j, minimumDifference, d);
216 for (
unsigned int j = 0; j < pixel_size; ++j)
219 tMax = std::max(std::abs(tc), tMax);
224 bool isDifferent =
false;
226 for (
unsigned int j = 0; j < pixel_size; ++j)
229 if (m > m_DifferenceThreshold * tMax)
240 out.Set(minimumDifference);
243 threadDifferenceSum += minimumDifference;
244 threadNumberOfPixels++;
253 progress.CompletedPixel();
258 m_ThreadDifferenceSum[threadId] += threadDifferenceSum;
259 m_ThreadNumberOfPixels[threadId] += threadNumberOfPixels;
262 template <
class TInputImage,
class TOutputImage>
266 int numberOfThreads = this->GetNumberOfThreads();
267 for (
int i = 0; i < numberOfThreads; ++i)
269 m_TotalDifference += m_ThreadDifferenceSum[i];
270 m_NumberOfPixelsWithDifferences += m_ThreadNumberOfPixels[i];
278 unsigned int numberOfPixels = region.GetNumberOfPixels();
281 m_MeanDifference = m_TotalDifference / numberOfPixels;