OTB  10.0.0
Orfeo Toolbox
otbStreamingStatisticsImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2024 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 otbStreamingStatisticsImageFilter_hxx
23 #define otbStreamingStatisticsImageFilter_hxx
25 
26 #include "itkImageRegionIterator.h"
27 #include "itkProgressReporter.h"
28 #include "otbMacro.h"
29 #include "vcl_legacy_aliases.h"
30 
31 namespace otb
32 {
33 
34 template<class TInputImage>
37  : m_ThreadSum(1),
38  m_SumOfSquares(1),
39  m_Count(1),
40  m_ThreadMin(1),
41  m_ThreadMax(1),
42  m_IgnoreInfiniteValues(true),
43  m_IgnoreUserDefinedValue(false)
44 {
45  this->DynamicMultiThreadingOff();
46  // first output is a copy of the image, DataObject created by
47  // superclass
48  //
49  // allocate the data objects for the outputs which are
50  // just decorators around pixel types
51  for (int i = 1; i < 3; ++i)
52  {
53  typename PixelObjectType::Pointer output = static_cast<PixelObjectType*>(this->MakeOutput(i).GetPointer());
54  this->itk::ProcessObject::SetNthOutput(i, output.GetPointer());
55  }
56  // allocate the data objects for the outputs which are
57  // just decorators around real types
58  for (int i = 3; i < 7; ++i)
59  {
60  typename RealObjectType::Pointer output = static_cast<RealObjectType*>(this->MakeOutput(i).GetPointer());
61  this->itk::ProcessObject::SetNthOutput(i, output.GetPointer());
62  }
63 
64  this->GetMinimumOutput()->Set(itk::NumericTraits<PixelType>::max());
65  this->GetMaximumOutput()->Set(itk::NumericTraits<PixelType>::NonpositiveMin());
66  this->GetMeanOutput()->Set(itk::NumericTraits<RealType>::max());
67  this->GetSigmaOutput()->Set(itk::NumericTraits<RealType>::max());
68  this->GetVarianceOutput()->Set(itk::NumericTraits<RealType>::max());
69  this->GetSumOutput()->Set(itk::NumericTraits<RealType>::Zero);
70 
71  // Initiate the infinite ignored pixel counters
72  m_IgnoredInfinitePixelCount = std::vector<unsigned int>(this->GetNumberOfWorkUnits(), 0);
73  m_IgnoredUserPixelCount = std::vector<unsigned int>(this->GetNumberOfWorkUnits(), 0);
74 
75  this->Reset();
76 }
77 
78 template <class TInputImage>
80 {
81  switch (output)
82  {
83  case 0:
84  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
85  break;
86  case 1:
87  return static_cast<itk::DataObject*>(PixelObjectType::New().GetPointer());
88  break;
89  case 2:
90  return static_cast<itk::DataObject*>(PixelObjectType::New().GetPointer());
91  break;
92  case 3:
93  case 4:
94  case 5:
95  case 6:
96  return static_cast<itk::DataObject*>(RealObjectType::New().GetPointer());
97  break;
98  default:
99  // might as well make an image
100  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
101  break;
102  }
103 }
104 
105 template <class TInputImage>
107 {
108  return static_cast<PixelObjectType*>(this->itk::ProcessObject::GetOutput(1));
109 }
110 
111 template <class TInputImage>
113 {
114  return static_cast<const PixelObjectType*>(this->itk::ProcessObject::GetOutput(1));
115 }
116 
117 template <class TInputImage>
119 {
120  return static_cast<PixelObjectType*>(this->itk::ProcessObject::GetOutput(2));
121 }
122 
123 template <class TInputImage>
125 {
126  return static_cast<const PixelObjectType*>(this->itk::ProcessObject::GetOutput(2));
127 }
128 
129 template <class TInputImage>
131 {
132  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(3));
133 }
134 
135 template <class TInputImage>
137 {
138  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(3));
139 }
140 
141 template <class TInputImage>
143 {
144  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(4));
145 }
146 
147 template <class TInputImage>
149 {
150  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(4));
151 }
152 
153 template <class TInputImage>
155 {
156  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(5));
157 }
158 
159 template <class TInputImage>
161 {
162  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(5));
163 }
164 
165 template <class TInputImage>
167 {
168  return static_cast<RealObjectType*>(this->itk::ProcessObject::GetOutput(6));
169 }
170 
171 template <class TInputImage>
173 {
174  return static_cast<const RealObjectType*>(this->itk::ProcessObject::GetOutput(6));
175 }
176 template <class TInputImage>
178 {
179  Superclass::GenerateOutputInformation();
180  if (this->GetInput())
181  {
182  this->GetOutput()->CopyInformation(this->GetInput());
183  this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
184 
185  if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0)
186  {
187  this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion());
188  }
189  }
190 }
191 template <class TInputImage>
193 {
194  // This is commented to prevent the streaming of the whole image for the first stream strip
195  // It shall not cause any problem because the output image of this filter is not intended to be used.
196  // InputImagePointer image = const_cast< TInputImage * >( this->GetInput() );
197  // this->GraftOutput( image );
198  // Nothing that needs to be allocated for the remaining outputs
199 }
200 
201 template <class TInputImage>
203 {
204  int i;
205  long count;
206  RealType sumOfSquares;
207 
208  int numberOfThreads = this->GetNumberOfWorkUnits();
209 
210  PixelType minimum;
211  PixelType maximum;
212  RealType mean = itk::NumericTraits<RealType>::Zero;
213  RealType sigma = itk::NumericTraits<RealType>::Zero;
214  RealType variance = itk::NumericTraits<RealType>::Zero;
215  RealType sum;
216 
217  sum = sumOfSquares = itk::NumericTraits<RealType>::Zero;
218  count = 0;
219 
220  // Find the min/max over all threads and accumulate count, sum and
221  // sum of squares
222  minimum = itk::NumericTraits<PixelType>::max();
223  maximum = itk::NumericTraits<PixelType>::NonpositiveMin();
224  for (i = 0; i < numberOfThreads; ++i)
225  {
226  count += m_Count[i];
227  sum += m_ThreadSum[i];
228  sumOfSquares += m_SumOfSquares[i];
229 
230  if (m_ThreadMin[i] < minimum)
231  {
232  minimum = m_ThreadMin[i];
233  }
234  if (m_ThreadMax[i] > maximum)
235  {
236  maximum = m_ThreadMax[i];
237  }
238  }
239  if (count > 0)
240  {
241  // compute statistics
242  mean = sum / static_cast<RealType>(count);
243 
244  if (count > 1)
245  {
246  // unbiased estimate
247  variance = (sumOfSquares - (sum * sum / static_cast<RealType>(count))) / static_cast<RealType>(count - 1);
248  sigma = std::sqrt(variance);
249  }
250  }
251  else
252  {
253  itkWarningMacro(<< "No pixel found to compute statistics!");
254  }
255 
256  // Set the outputs
257  this->GetMinimumOutput()->Set(minimum);
258  this->GetMaximumOutput()->Set(maximum);
259  this->GetMeanOutput()->Set(mean);
260  this->GetSigmaOutput()->Set(sigma);
261  this->GetVarianceOutput()->Set(variance);
262  this->GetSumOutput()->Set(sum);
263 }
264 
265 template <class TInputImage>
267 {
268  int numberOfThreads = this->GetNumberOfWorkUnits();
269 
270  // Resize the thread temporaries
271  m_Count.SetSize(numberOfThreads);
272  m_SumOfSquares.SetSize(numberOfThreads);
273  m_ThreadSum.SetSize(numberOfThreads);
274  m_ThreadMin.SetSize(numberOfThreads);
275  m_ThreadMax.SetSize(numberOfThreads);
276  // Initialize the temporaries
277  m_Count.Fill(itk::NumericTraits<long>::Zero);
278  m_ThreadSum.Fill(itk::NumericTraits<RealType>::Zero);
279  m_SumOfSquares.Fill(itk::NumericTraits<RealType>::Zero);
280  m_ThreadMin.Fill(itk::NumericTraits<PixelType>::max());
281  m_ThreadMax.Fill(itk::NumericTraits<PixelType>::NonpositiveMin());
282  if (m_IgnoreInfiniteValues)
283  {
284  m_IgnoredInfinitePixelCount = std::vector<unsigned int>(numberOfThreads, 0);
285  }
286 
287  if (m_IgnoreUserDefinedValue)
288  {
289  m_IgnoredUserPixelCount = std::vector<unsigned int>(this->GetNumberOfWorkUnits(), 0);
290  }
291 }
292 
293 template <class TInputImage>
294 void PersistentStatisticsImageFilter<TInputImage>::ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId)
295 {
299  InputImagePointer inputPtr = const_cast<TInputImage*>(this->GetInput(0));
300  // support progress methods/callbacks
301  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
303 
304  RealType realValue;
305  PixelType value;
306 
307  itk::ImageRegionConstIterator<TInputImage> it(inputPtr, outputRegionForThread);
308 
309  it.GoToBegin();
310  // do the work
311  while (!it.IsAtEnd())
312  {
313  value = it.Get();
314  realValue = static_cast<RealType>(value);
315  if (m_IgnoreInfiniteValues && !(vnl_math_isfinite(realValue)))
316  {
317  m_IgnoredInfinitePixelCount[threadId]++;
318  }
319  else
320  {
321  if (m_IgnoreUserDefinedValue && (value == m_UserIgnoredValue))
322  {
323  m_IgnoredUserPixelCount[threadId]++;
324  }
325  else
326  {
327  if (value < m_ThreadMin[threadId])
328  {
329  m_ThreadMin[threadId] = value;
330  }
331  if (value > m_ThreadMax[threadId])
332  {
333  m_ThreadMax[threadId] = value;
334  }
335 
336  m_ThreadSum[threadId] += realValue;
337  m_SumOfSquares[threadId] += (realValue * realValue);
338  m_Count[threadId]++;
339  }
340  }
341  ++it;
342  progress.CompletedPixel();
343  }
344 }
345 template <class TImage>
346 void PersistentStatisticsImageFilter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
347 {
348  Superclass::PrintSelf(os, indent);
349 
350  os << indent << "Minimum: " << static_cast<typename itk::NumericTraits<PixelType>::PrintType>(this->GetMinimum()) << std::endl;
351  os << indent << "Maximum: " << static_cast<typename itk::NumericTraits<PixelType>::PrintType>(this->GetMaximum()) << std::endl;
352  os << indent << "Sum: " << this->GetSum() << std::endl;
353  os << indent << "Mean: " << this->GetMean() << std::endl;
354  os << indent << "Sigma: " << this->GetSigma() << std::endl;
355  os << indent << "Variance: " << this->GetVariance() << std::endl;
356 }
357 } // end namespace otb
358 #endif
void PrintSelf(std::ostream &os, itk::Indent indent) const override
DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override
void ThreadedGenerateData(const RegionType &outputRegionForThread, itk::ThreadIdType threadId) override
itk::SimpleDataObjectDecorator< PixelType > PixelObjectType
itk::SimpleDataObjectDecorator< RealType > RealObjectType
itk::NumericTraits< PixelType >::RealType RealType
itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.