OTB  9.0.0
Orfeo Toolbox
otbComputeHistoFilter.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 otbComputeHistoFilter_hxx
22 #define otbComputeHistoFilter_hxx
23 
24 #include "otbComputeHistoFilter.h"
25 
26 #include <limits>
27 
28 namespace otb
29 {
30 
31 template <class TInputImage, class TOutputImage>
33 {
34  this->SetNumberOfRequiredOutputs(2);
35  this->SetNthOutput(0, this->MakeOutput(0));
36  this->SetNthOutput(1, this->MakeOutput(1));
37  m_Min = std::numeric_limits<InputPixelType>::quiet_NaN();
38  m_Max = std::numeric_limits<InputPixelType>::quiet_NaN();
39  m_NoDataFlag = false;
40  m_NoData = std::numeric_limits<InputPixelType>::quiet_NaN();
41  m_NbBin = 256;
42  m_Threshold = -1;
43  m_ThumbSize.Fill(0);
44  m_ValidThreads = 1;
45  m_Step = -1;
46 }
47 
48 template <class TInputImage, class TOutputImage>
49 itk::ProcessObject::DataObjectPointer ComputeHistoFilter<TInputImage, TOutputImage>::MakeOutput(itk::ProcessObject::DataObjectPointerArraySizeType idx)
50 {
51  itk::DataObject::Pointer output;
52 
53  switch (idx)
54  {
55  case 0:
56  output = (OutputImageType::New()).GetPointer();
57  break;
58  case 1:
59  output = (OutputImageType::New()).GetPointer();
60  break;
61  default:
62  std::cerr << "No output " << idx << std::endl;
63  output = NULL;
64  break;
65  }
66  return output;
67 }
68 
69 template <class TInputImage, class TOutputImage>
70 itk::ProcessObject::DataObjectPointer ComputeHistoFilter<TInputImage, TOutputImage>::MakeOutput(const itk::ProcessObject::DataObjectIdentifierType& name)
71 {
72  return Superclass::MakeOutput(name);
73 }
74 
75 template <class TInputImage, class TOutputImage>
77 {
78  typename Superclass::InputImagePointer inputPtr(const_cast<InputImageType*>(this->GetInput()));
79  inputPtr->SetRequestedRegion(this->GetOutput()->GetRequestedRegion());
80  if (inputPtr->GetRequestedRegion().GetNumberOfPixels() == 0)
81  {
82  inputPtr->SetRequestedRegionToLargestPossibleRegion();
83  }
84 }
85 
86 template <class TInputImage, class TOutputImage>
88 {
89  Superclass::GenerateOutputInformation();
90  typename InputImageType::ConstPointer input(this->GetInput());
91  typename OutputImageType::Pointer output(this->GetHistoOutput());
92  typename OutputImageType::Pointer outImage(this->GetOutput());
93 
94  typename InputImageType::RegionType inputLargestRegion(input->GetLargestPossibleRegion());
95  outImage->SetLargestPossibleRegion(inputLargestRegion);
96 
97  typename OutputImageType::IndexType start;
98  typename OutputImageType::SizeType size;
99 
100  start.Fill(0);
101 
102  assert(m_ThumbSize[0] != 0);
103  assert(m_ThumbSize[1] != 0);
104 
105  // TODO throw error if 0
106 
107  size[0] = std::ceil(inputLargestRegion.GetSize()[0] / static_cast<double>(m_ThumbSize[0]));
108  size[1] = std::ceil(inputLargestRegion.GetSize()[1] / static_cast<double>(m_ThumbSize[1]));
109 
110  typename OutputImageType::RegionType region;
111  region.SetSize(size);
112  region.SetIndex(start);
113  output->SetNumberOfComponentsPerPixel(m_NbBin);
114  output->SetLargestPossibleRegion(region);
115  typename InputImageType::SpacingType inputSpacing(input->GetSignedSpacing());
116  typename InputImageType::PointType inputOrigin(input->GetOrigin());
117 
118  typename OutputImageType::SpacingType histoSpacing;
119  histoSpacing[0] = inputSpacing[0] * m_ThumbSize[0];
120  histoSpacing[1] = inputSpacing[1] * m_ThumbSize[1];
121  output->SetSignedSpacing(histoSpacing);
122 
123  typename OutputImageType::PointType histoOrigin;
124  histoOrigin[0] = histoSpacing[0] / 2 + inputOrigin[0] - inputSpacing[0] / 2;
125  histoOrigin[1] = histoSpacing[1] / 2 + inputOrigin[1] - inputSpacing[1] / 2;
126  output->SetOrigin(histoOrigin);
127 }
128 
129 template <class TInputImage, class TOutputImage>
131 {
132  if (GetHistoOutput()->GetRequestedRegion().GetNumberOfPixels() == 0)
133  {
134  GetHistoOutput()->SetRequestedRegionToLargestPossibleRegion();
135  }
136  typename OutputImageType::Pointer outImage(this->GetOutput());
137  SetRequestedRegion(outImage);
138 }
139 
140 template <class TInputImage, class TOutputImage>
142 {
143  this->AllocateOutputs();
144 
145  // Set up the multithreaded processing
146  typename itk::ImageSource<OutputImageType>::ThreadStruct str;
147  str.Filter = this;
148 
149  // Get the output pointer
150  const OutputImageType* outputPtr(this->GetOutput());
151  const itk::ImageRegionSplitterBase* splitter(this->GetImageRegionSplitter());
152  m_ValidThreads = splitter->GetNumberOfSplits(outputPtr->GetRequestedRegion(), this->GetNumberOfThreads());
153 
154  this->BeforeThreadedGenerateData();
155 
156  this->GetMultiThreader()->SetNumberOfThreads(m_ValidThreads);
157  this->GetMultiThreader()->SetSingleMethod(this->ThreaderCallback, &str);
158  // multithread the execution
159  this->GetMultiThreader()->SingleMethodExecute();
160 
161  this->AfterThreadedGenerateData();
162 }
163 
164 template <class TInputImage, class TOutputImage>
166 {
167  // Initializing output
168  typename OutputImageType::Pointer output(this->GetHistoOutput());
169  typename OutputImageType::PixelType zeroPixel(m_NbBin);
170  zeroPixel.Fill(0);
171  output->FillBuffer(zeroPixel);
172 
173  // Initializing shared variable with thread number parameter
174  SizeType outSize(output->GetRequestedRegion().GetSize());
175  m_HistoThread.resize(m_ValidThreads * outSize[0] * outSize[1]);
176  m_HistoThread.shrink_to_fit();
177  std::fill(m_HistoThread.begin(), m_HistoThread.end(), zeroPixel);
178 
179  m_Step = static_cast<double>(m_Max - m_Min) / static_cast<double>(m_NbBin - 1);
180 }
181 
182 template <class TInputImage, class TOutputImage>
183 void ComputeHistoFilter<TInputImage, TOutputImage>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
184 {
185  assert(m_Step > 0);
186  // TODO throw error
187 
188  // itk::ProgressReporter progress(this , threadId ,
189  // outputRegionForThread.GetNumberOfPixels() );
190  typename InputImageType::ConstPointer input(this->GetInput());
191  typename OutputImageType::Pointer output(this->GetHistoOutput());
192 
193  OutputImageRegionType histoRegion(GetHistoOutput()->GetRequestedRegion());
194  SizeType outSize(histoRegion.GetSize());
195  IndexType outIndex(histoRegion.GetIndex());
196 
197  typename InputImageType::RegionType region;
198 
199  unsigned int threadIndex(threadId * outSize[0] * outSize[1]), pixel(0);
200 
201  for (unsigned int nthHisto = 0; nthHisto < outSize[0] * outSize[1]; nthHisto++)
202  {
203  IndexType start;
204  start[0] = (outIndex[0] + nthHisto % outSize[0]) * m_ThumbSize[0];
205  start[1] = (outIndex[1] + nthHisto / outSize[0]) * m_ThumbSize[1];
206  region.SetSize(m_ThumbSize);
207  region.SetIndex(start);
208 
209  if (!region.Crop(outputRegionForThread))
210  continue;
211 
212  typename itk::ImageRegionConstIterator<InputImageType> it(input, region);
213  InputPixelType currentPixel(0);
214  for (it.GoToBegin(); !it.IsAtEnd(); ++it)
215  {
216  currentPixel = it.Get();
217  if ((currentPixel == m_NoData && m_NoDataFlag) || currentPixel > m_Max || currentPixel < m_Min)
218  continue;
219 
220  pixel = static_cast<unsigned int>(std::round((currentPixel - m_Min) / m_Step));
221  ++m_HistoThread[threadIndex + nthHisto][pixel];
222  }
223  }
224 }
225 
226 template <class TInputImage, class TOutputImage>
228 {
229  typename OutputImageType::Pointer output(this->GetHistoOutput());
230  typename itk::ImageRegionIterator<OutputImageType> oit(output, output->GetRequestedRegion());
231  OutputImageRegionType histoRegion(GetHistoOutput()->GetRequestedRegion());
232  SizeType outSize(histoRegion.GetSize());
233  IndexType outIndex(histoRegion.GetIndex());
234 
235  unsigned int agreg(0), total(0);
236 
237  for (oit.GoToBegin(); !oit.IsAtEnd(); ++oit)
238  {
239  total = 0;
240 
241  for (unsigned int i = 0; i < m_NbBin; i++)
242  {
243  agreg = 0;
244 
245  for (unsigned int threadId = 0; threadId < m_ValidThreads; threadId++)
246  {
247  agreg += m_HistoThread[threadId * outSize[0] * outSize[1] + (oit.GetIndex()[1] - outIndex[1]) * outSize[0] + ((oit.GetIndex()[0] - outIndex[0]))][i];
248  }
249  oit.Get()[i] = agreg;
250  total += agreg;
251  }
252  if (m_Threshold > 0)
253  ApplyThreshold(oit, total);
254  }
255 }
256 
257 template <class TInputImage, class TOutputImage>
258 void ComputeHistoFilter<TInputImage, TOutputImage>::ApplyThreshold(typename itk::ImageRegionIterator<OutputImageType> oit, unsigned int total)
259 {
260  unsigned int rest(0);
261  unsigned int height(static_cast<unsigned int>(m_Threshold * (total / m_NbBin)));
262  // Do i need to static_cast in a an assignation?
263  // Warning!!!! Need to handle out of bound int!!!
264 
265  for (unsigned int i = 0; i < m_NbBin; i++)
266  {
267  if (static_cast<unsigned int>(oit.Get()[i]) > height)
268  {
269  rest += oit.Get()[i] - height;
270  oit.Get()[i] = height;
271  }
272  }
273  height = rest / m_NbBin;
274  rest = rest % m_NbBin;
275  for (unsigned int i = 0; i < m_NbBin; i++)
276  {
277  oit.Get()[i] += height;
278  if (i > (m_NbBin - rest) / 2 && i <= (m_NbBin - rest) / 2 + rest)
279  {
280  ++oit.Get()[i];
281  }
282  }
283 }
284 
285 template <class TInputImage, class TOutputImage>
287 {
288  assert(this->itk::ProcessObject::GetOutput(1));
289 
290  return dynamic_cast<TOutputImage*>(this->itk::ProcessObject::GetOutput(1));
291 }
292 
293 template <class TInputImage, class TOutputImage>
295 {
296  OutputImageRegionType histoRegion(GetHistoOutput()->GetRequestedRegion());
297 
298  IndexType start;
299  start[0] = histoRegion.GetIndex()[0] * m_ThumbSize[0];
300  start[1] = histoRegion.GetIndex()[1] * m_ThumbSize[1];
301 
302  SizeType size;
303  size[0] = histoRegion.GetSize()[0] * m_ThumbSize[0];
304  size[1] = histoRegion.GetSize()[1] * m_ThumbSize[1];
305 
306  typename OutputImageType::RegionType outputRequestedRegion;
307  outputRequestedRegion.SetIndex(start);
308  outputRequestedRegion.SetSize(size);
309 
310  outputRequestedRegion.Crop(image->GetLargestPossibleRegion());
311  image->SetRequestedRegion(outputRequestedRegion);
312 }
313 
314 template <class TInputImage, class TOutputImage>
315 void ComputeHistoFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
316 {
317  Superclass::PrintSelf(os, indent);
318  os << indent << "Is no data activated: " << m_NoDataFlag << std::endl;
319  os << indent << "No Data: " << m_NoData << std::endl;
320  os << indent << "Minimum: " << m_Min << std::endl;
321  os << indent << "Maximum: " << m_Max << std::endl;
322  os << indent << "Step: " << m_Step << std::endl;
323  os << indent << "Number of bin: " << m_NbBin << std::endl;
324  os << indent << "Thumbnail size: " << m_ThumbSize << std::endl;
325  os << indent << "Threshold value: " << m_Threshold << std::endl;
326 }
327 
328 } // End namespace otb
329 
330 #endif
otb::ComputeHistoFilter::GenerateData
void GenerateData() override
Definition: otbComputeHistoFilter.hxx:141
otb::ComputeHistoFilter::SetRequestedRegion
void SetRequestedRegion(itk::ImageBase< 2 > *image)
Definition: otbComputeHistoFilter.hxx:294
otb::ComputeHistoFilter::InputPixelType
InputImageType::InternalPixelType InputPixelType
Definition: otbComputeHistoFilter.h:56
otb::ComputeHistoFilter::GenerateInputRequestedRegion
void GenerateInputRequestedRegion() override
Definition: otbComputeHistoFilter.hxx:76
otb::ComputeHistoFilter::GetHistoOutput
OutputImageType::Pointer GetHistoOutput()
Definition: otbComputeHistoFilter.hxx:286
otb::ComputeHistoFilter::MakeOutput
virtual itk::ProcessObject::DataObjectPointer MakeOutput(itk::ProcessObject::DataObjectPointerArraySizeType idx) override
Definition: otbComputeHistoFilter.hxx:49
otb::ComputeHistoFilter::InputImageType
TInputImage InputImageType
Definition: otbComputeHistoFilter.h:48
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::ComputeHistoFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbComputeHistoFilter.hxx:315
otb::ComputeHistoFilter::ApplyThreshold
void ApplyThreshold(typename itk::ImageRegionIterator< OutputImageType > oit, unsigned int total)
Definition: otbComputeHistoFilter.hxx:258
otb::ComputeHistoFilter::ThreadedGenerateData
virtual void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
Definition: otbComputeHistoFilter.hxx:183
otbComputeHistoFilter.h
otb::ComputeHistoFilter::BeforeThreadedGenerateData
void BeforeThreadedGenerateData() override
Definition: otbComputeHistoFilter.hxx:165
otb::ComputeHistoFilter::SizeType
InputImageType::SizeType SizeType
Definition: otbComputeHistoFilter.h:58
otb::ComputeHistoFilter::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbComputeHistoFilter.h:59
otb::ComputeHistoFilter::ComputeHistoFilter
ComputeHistoFilter()
Definition: otbComputeHistoFilter.hxx:32
otb::ComputeHistoFilter::AfterThreadedGenerateData
void AfterThreadedGenerateData() override
Definition: otbComputeHistoFilter.hxx:227
otb::ComputeHistoFilter::GenerateOutputRequestedRegion
void GenerateOutputRequestedRegion(itk::DataObject *output) override
Definition: otbComputeHistoFilter.hxx:130
otb::ComputeHistoFilter::OutputImageType
TOutputImage OutputImageType
Definition: otbComputeHistoFilter.h:49
otb::ComputeHistoFilter::IndexType
InputImageType::IndexType IndexType
Definition: otbComputeHistoFilter.h:57
otb::ComputeHistoFilter::GenerateOutputInformation
void GenerateOutputInformation() override
Definition: otbComputeHistoFilter.hxx:87