OTB  10.0.0
Orfeo Toolbox
otbStreamingCompareImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2024 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 otbStreamingCompareImageFilter_hxx
22 #define otbStreamingCompareImageFilter_hxx
24 
25 #include "itkImageRegionIterator.h"
26 #include "itkProgressReporter.h"
27 #include "itkMath.h"
28 #include "otbMacro.h"
29 
30 namespace otb
31 {
32 
33 template <class TInputImage>
35  : m_SquareOfDifferences(1), m_AbsoluteValueOfDifferences(1), m_ThreadMinRef(1), m_ThreadMaxRef(1), m_Count(1), m_DiffCount(1), m_PhysicalSpaceCheck(true)
36 {
37  this->DynamicMultiThreadingOff();
38  this->SetNumberOfRequiredInputs( 2 );
39  // first output is a copy of the image, DataObject created by
40  // superclass
41 
42  // allocate the data objects for the outputs which are
43  // just decorators around real types
44  for (int i = 1; i < 5; ++i)
45  {
46  typename RealObjectType::Pointer output = static_cast<RealObjectType*>(this->MakeOutput(i).GetPointer());
47  this->itk::ProcessObject::SetNthOutput(i, output.GetPointer());
48  }
49 
50  this->GetPSNROutput()->Set(itk::NumericTraits<RealType>::max());
51  this->GetMSEOutput()->Set(itk::NumericTraits<RealType>::max());
52  this->GetMAEOutput()->Set(itk::NumericTraits<RealType>::max());
53  this->GetDiffCountOutput()->Set(itk::NumericTraits<RealType>::Zero);
54 
55  this->Reset();
56 }
57 
61 template <class TInputImage>
63 {
64  // The ProcessObject is not const-correct so the const_cast is required here
65  this->SetNthInput(0, const_cast<TInputImage*>(image));
66 }
67 
71 template <class TInputImage>
73 {
74  // The ProcessObject is not const-correct so the const_cast is required here
75  this->SetNthInput(1, const_cast<TInputImage*>(image));
76 }
77 
78 template <class TInputImage>
80 {
81  if (this->GetNumberOfInputs() < 1)
82  {
83  return 0;
84  }
85  return static_cast<const TInputImage*>(this->itk::ProcessObject::GetInput(0));
86 }
87 
88 template <class TInputImage>
90 {
91  if (this->GetNumberOfInputs() < 2)
92  {
93  return 0;
94  }
95  return static_cast<const TInputImage*>(this->itk::ProcessObject::GetInput(1));
96 }
97 
98 template <class TInputImage>
100 {
101  switch (output)
102  {
103  case 0:
104  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
105  break;
106  case 1:
107  case 2:
108  case 3:
109  case 4:
110  return static_cast<itk::DataObject*>(RealObjectType::New().GetPointer());
111  break;
112  default:
113  // might as well make an image
114  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
115  break;
116  }
117 }
118 
119 template <class TInputImage>
121 {
122  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(1));
123 }
124 
125 template <class TInputImage>
127 {
128  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(1));
129 }
130 
131 template <class TInputImage>
133 {
134  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(2));
135 }
136 
137 template <class TInputImage>
139 {
140  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(2));
141 }
142 
143 template <class TInputImage>
145 {
146  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(3));
147 }
148 
149 template <class TInputImage>
151 {
152  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(3));
153 }
154 
155 template <class TInputImage>
157 {
158  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(4));
159 }
160 
161 template <class TInputImage>
163 {
164  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(4));
165 }
166 
167 template <class TInputImage>
169 {
170  Superclass::GenerateOutputInformation();
171  if (this->GetInput())
172  {
173  this->GetOutput()->CopyInformation(this->GetInput());
174  this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
175 
176  if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0)
177  {
178  this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion());
179  }
180  }
181 }
182 template <class TInputImage>
184 {
185  // This is commented to prevent the streaming of the whole image for the first stream strip
186  // It shall not cause any problem because the output image of this filter is not intended to be used.
187  // InputImagePointer image = const_cast< TInputImage * >( this->GetInput() );
188  // this->GraftOutput( image );
189  // Nothing that needs to be allocated for the remaining outputs
190 }
191 
192 template <class TInputImage>
194 {
195  int i;
196  unsigned long count;
197  unsigned long diffCount;
198  RealType squareOfDifferences, absoluteValueOfDifferences;
199 
200  int numberOfThreads = this->GetNumberOfWorkUnits();
201 
202  PixelType minimumRef, maximumRef;
203  RealType mse;
204  RealType mae;
205  RealType psnr;
206 
207  squareOfDifferences = absoluteValueOfDifferences = itk::NumericTraits<RealType>::Zero;
208  count = 0;
209  diffCount = 0;
210 
211  // Find min/max and the accumulate count and difference of squares over all threads
212  minimumRef = itk::NumericTraits<PixelType>::max();
213  maximumRef = itk::NumericTraits<PixelType>::NonpositiveMin();
214 
215  for (i = 0; i < numberOfThreads; ++i)
216  {
217  count += m_Count[i];
218  diffCount += m_DiffCount[i];
219  squareOfDifferences += m_SquareOfDifferences[i];
220  absoluteValueOfDifferences += m_AbsoluteValueOfDifferences[i];
221 
222  if (m_ThreadMinRef[i] < minimumRef)
223  {
224  minimumRef = m_ThreadMinRef[i];
225  }
226  if (m_ThreadMaxRef[i] > maximumRef)
227  {
228  maximumRef = m_ThreadMaxRef[i];
229  }
230  }
231 
232  // compute mse
233  mse = (count != 0) ? squareOfDifferences / static_cast<RealType>(count) : 0.;
234  // compute mse
235  mae = (count != 0) ? absoluteValueOfDifferences / static_cast<RealType>(count) : 0.;
236 
237  // compute psnr
238  psnr = (std::abs(mse) > 0.0000000001 && (maximumRef - minimumRef) > 0.0000000001)
239  ? 10. * std::log10(((maximumRef - minimumRef) * (maximumRef - minimumRef)) / mse)
240  : 0.;
241  // Set the output
242  this->GetMSEOutput()->Set(mse);
243  this->GetMAEOutput()->Set(mae);
244  this->GetPSNROutput()->Set(psnr);
245  this->GetDiffCountOutput()->Set(static_cast<RealType>(diffCount));
246 }
247 
248 template <class TInputImage>
250 {
251  int numberOfThreads = this->GetNumberOfWorkUnits();
252 
253  // Resize the thread temporaries
254  m_Count.SetSize(numberOfThreads);
255  m_DiffCount.SetSize(numberOfThreads);
256  m_SquareOfDifferences.SetSize(numberOfThreads);
257  m_AbsoluteValueOfDifferences.SetSize(numberOfThreads);
258 
259  m_ThreadMinRef.SetSize(numberOfThreads);
260  m_ThreadMaxRef.SetSize(numberOfThreads);
261 
262  // Initialize the temporaries
263  m_Count.Fill(itk::NumericTraits<long>::Zero);
264  m_DiffCount.Fill(itk::NumericTraits<long>::Zero);
265  m_SquareOfDifferences.Fill(itk::NumericTraits<RealType>::Zero);
266  m_AbsoluteValueOfDifferences.Fill(itk::NumericTraits<RealType>::Zero);
267  m_ThreadMinRef.Fill(itk::NumericTraits<PixelType>::max());
268  m_ThreadMaxRef.Fill(itk::NumericTraits<PixelType>::NonpositiveMin());
269 }
270 
271 template <class TInputImage>
273 {
274  if (m_PhysicalSpaceCheck)
275  Superclass::VerifyInputInformation();
276 }
277 
278 template <class TInputImage>
279 void PersistentCompareImageFilter<TInputImage>::ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId)
280 {
284  InputImagePointer inputPtr1 = const_cast<TInputImage*>(this->GetInput(0));
285  InputImagePointer inputPtr2 = const_cast<TInputImage*>(this->GetInput(1));
287 
288  // support progress methods/callbacks
289  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
290 
291  RealType realValue1, realValue2;
292  PixelType value1, value2;
293 
294  itk::ImageRegionConstIterator<TInputImage> it1(inputPtr1, outputRegionForThread);
295  itk::ImageRegionConstIterator<TInputImage> it2(inputPtr2, outputRegionForThread);
296 
297  it1.GoToBegin();
298  it2.GoToBegin();
299  // do the work
300  while (!it1.IsAtEnd() && !it2.IsAtEnd())
301  {
302  value1 = it1.Get();
303  realValue1 = static_cast<RealType>(value1);
304 
305  value2 = it2.Get();
306  realValue2 = static_cast<RealType>(value2);
307 
308  if (value1 < m_ThreadMinRef[threadId])
309  {
310  m_ThreadMinRef[threadId] = value1;
311  }
312  if (value1 > m_ThreadMaxRef[threadId])
313  {
314  m_ThreadMaxRef[threadId] = value1;
315  }
316 
317  RealType diffVal = realValue1 - realValue2;
318  m_SquareOfDifferences[threadId] += diffVal * diffVal;
319  m_AbsoluteValueOfDifferences[threadId] += std::abs(diffVal);
320  if (!itk::Math::FloatAlmostEqual(realValue1, realValue2))
321  {
322  m_DiffCount[threadId]++;
323  }
324  m_Count[threadId]++;
325  ++it1;
326  ++it2;
327  progress.CompletedPixel();
328  }
329 }
330 template <class TImage>
331 void PersistentCompareImageFilter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
332 {
333  Superclass::PrintSelf(os, indent);
334 
335  os << indent << "PSNR: " << this->GetPSNR() << std::endl;
336  os << indent << "MSE: " << this->GetMSE() << std::endl;
337  os << indent << "MAE: " << this->GetMAE() << std::endl;
338  os << indent << "Count: " << this->GetDiffCount() << std::endl;
339 }
340 } // end namespace otb
341 #endif
void ThreadedGenerateData(const RegionType &outputRegionForThread, itk::ThreadIdType threadId) override
DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override
itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType
itk::NumericTraits< PixelType >::RealType RealType
itk::SimpleDataObjectDecorator< RealType > RealObjectType
void PrintSelf(std::ostream &os, itk::Indent indent) const override
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.