OTB  10.0.0
Orfeo Toolbox
otbImageToPointSetFilter.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 otbImageToPointSetFilter_hxx
22 #define otbImageToPointSetFilter_hxx
23 
25 #include "itkMultiThreaderBase.h"
26 
27 namespace otb
28 {
29 
33 template <class TInputImage, class TOutputPointSet>
35 {
36  this->ProcessObjectType::SetNumberOfRequiredInputs(1);
37 
38  OutputPointSetPointer output = dynamic_cast<OutputPointSetType*>(this->MakeOutput(0).GetPointer());
39 
40  ProcessObjectType::SetNumberOfRequiredOutputs(1);
41  ProcessObjectType::SetNthOutput(0, output.GetPointer());
42 
43  m_PointsContainerPerThread.clear();
44  m_PointDataContainerPerThread.clear();
45 
46  // create default region splitter
47  m_StreamingManager = StreamingManagerType::New();
48 }
49 
53 template <class TInputImage, class TOutputPointSet>
55 {
56  // process object is not const-correct, the const_cast
57  // is required here.
58  this->ProcessObjectType::SetNthInput(idx, const_cast<InputImageType*>(input));
59 }
60 
64 template <class TInputImage, class TOutputPointSet>
66 {
67  // process object is not const-correct, the const_cast
68  // is required here.
69  this->ProcessObjectType::SetNthInput(0, const_cast<InputImageType*>(input));
70 }
71 
75 template <class TInputImage, class TOutputPointSet>
78 {
79 
80  return dynamic_cast<const InputImageType*>(this->ProcessObjectType::GetInput(idx));
81 }
82 
86 template <class TInputImage, class TOutputPointSet>
88 {
89  if (this->GetNumberOfInputs() < 1)
90  return nullptr;
91 
92  return dynamic_cast<const InputImageType*>(this->ProcessObjectType::GetInput(0));
93 }
94 
98 template <class TInputImage, class TOutputPointSet>
99 void ImageToPointSetFilter<TInputImage, TOutputPointSet>::PrintSelf(std::ostream& os, itk::Indent indent) const
100 {
101  Superclass::PrintSelf(os, indent);
102 }
103 
109 template <class TInputImage, class TOutputPointSet>
111 {
112 }
113 
117 template <class TInputImage, class TOutputPointSet>
119 {
120 
121  PointsContainerType* outputPointsContainer = this->GetOutput()->GetPoints();
122  outputPointsContainer->Initialize();
123 
124  PointDataContainerType* outputPointDataContainer = this->GetOutput()->GetPointData();
125  outputPointDataContainer->Initialize();
126 
127  typename TInputImage::RegionType inputRegion = this->GetInput()->GetLargestPossibleRegion();
128 
129  // Input is an image, cast away the constness so we can set
130  // the requested region.
131  InputImagePointer input = const_cast<TInputImage*>(this->GetInput());
132 
133  m_StreamingManager->PrepareStreaming(input, inputRegion);
134 
135  unsigned long numDivisions = m_StreamingManager->GetNumberOfSplits();
136 
141  unsigned int piece;
142  InputImageRegionType streamRegion;
143  for (piece = 0; piece < numDivisions && !this->GetAbortGenerateData(); piece++)
144  {
145  streamRegion = m_StreamingManager->GetSplit(piece);
146  typedef itk::ImageToImageFilterDetail::ImageRegionCopier<itkGetStaticConstMacro(InputImageDimension), itkGetStaticConstMacro(InputImageDimension)>
147  OutputToInputRegionCopierType;
148  OutputToInputRegionCopierType regionCopier;
149  InputImageRegionType inputRegion2;
150  regionCopier(inputRegion2, streamRegion);
151  input->SetRequestedRegion(inputRegion2);
153 
154  // Call a method that can be overridden by a subclass to perform
155  // some calculations prior to splitting the main computations into
156  // separate threads
157  this->BeforeThreadedGenerateData();
158 
159  // Set up the multithreaded processing
160  ThreadStruct str;
161  str.Filter = this;
162 
163  // Initializing object per thread
164  typename PointsContainerType::Pointer defaultPointsContainer = PointsContainerType::New();
165  this->m_PointsContainerPerThread = OutputPointsContainerForThreadType(this->GetNumberOfWorkUnits(), defaultPointsContainer);
166 
167  typename PointDataContainerType::Pointer defaultPointDataContainer = PointDataContainerType::New();
168  this->m_PointDataContainerPerThread = OutputPointDataContainerForThreadType(this->GetNumberOfWorkUnits(), defaultPointDataContainer);
169 
170  // Setting up multithreader
171  this->GetMultiThreader()->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits());
172  this->GetMultiThreader()->SetSingleMethod(this->ThreaderCallback, &str);
173 
174  // multithread the execution
175  this->GetMultiThreader()->SingleMethodExecute();
176 
177  // Call a method that can be overridden by a subclass to perform
178  // some calculations after all the threads have completed
179  this->AfterThreadedGenerateData();
180  }
181 }
182 
183 template <class TInputImage, class TOutputPointSet>
185 {
186 }
187 
188 template <class TInputImage, class TOutputPointSet>
190 {
191  // copy the lists to the output
192  PointsContainerType* outputPointsContainer = this->GetOutput()->GetPoints();
193  unsigned long currentIndex = outputPointsContainer->Size();
194 
195  typedef typename PointsContainerType::ConstIterator OutputPointsContainerIterator;
196  for (unsigned int i = 0; i < this->m_PointsContainerPerThread.size(); ++i)
197  {
198  if (this->m_PointsContainerPerThread[i].IsNotNull())
199  {
200  for (OutputPointsContainerIterator it = this->m_PointsContainerPerThread[i]->Begin(); it != this->m_PointsContainerPerThread[i]->End(); ++it)
201  {
202  outputPointsContainer->InsertElement(currentIndex, it.Value());
203  ++currentIndex;
204  }
205  }
206  }
207 
208  PointDataContainerType* outputPointDataContainer = this->GetOutput()->GetPointData();
209  currentIndex = outputPointDataContainer->Size();
210 
211  typedef typename PointDataContainerType::ConstIterator OutputPointDataContainerIterator;
212  for (unsigned int i = 0; i < this->m_PointDataContainerPerThread.size(); ++i)
213  {
214  if (this->m_PointDataContainerPerThread[i].IsNotNull())
215  {
216  for (OutputPointDataContainerIterator it = this->m_PointDataContainerPerThread[i]->Begin(); it != this->m_PointDataContainerPerThread[i]->End(); ++it)
217  {
218  outputPointDataContainer->InsertElement(currentIndex, it.Value());
219  ++currentIndex;
220  }
221  }
222  }
223 }
224 
225 template <class TInputImage, class TOutputPointSet>
227 {
228  // The following code is equivalent to:
229  // itkExceptionMacro("subclass should override this method!!!");
230  // The ExceptionMacro is not used because gcc warns that a
231  // 'noreturn' function does return
232  std::ostringstream message;
233  message << "itk::ERROR: " << this->GetNameOfClass() << "(" << this << "): "
234  << "Subclass should override this method!!!";
235  itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION);
236  throw e_;
237 }
238 
239 template <class TInputImage, class TOutputPointSet>
240 itk::ITK_THREAD_RETURN_TYPE
243 {
244  ThreadStruct* str;
245  unsigned int total, threadCount;
246  itk::ThreadIdType threadId;
247 
248  threadId = ((itk::MultiThreaderBase::WorkUnitInfo *) (arg))->WorkUnitID;
249  threadCount = ((itk::MultiThreaderBase::WorkUnitInfo *) (arg))->NumberOfWorkUnits;
250  str = (ThreadStruct *) (((itk::MultiThreaderBase::WorkUnitInfo *) (arg))->UserData);
251 
252  // execute the actual method with appropriate output region
253  // first find out how many pieces extent can be split into.
254  typename TInputImage::RegionType splitRegion;
255  total = str->Filter->SplitRequestedRegion(threadId, threadCount, splitRegion);
256 
257  if (threadId < total)
258  {
259  str->Filter->ThreadedGenerateData(splitRegion, threadId);
260  }
261  // else
262  // {
263  // otherwise don't use this thread. Sometimes the threads don't
264  // break up very well and it is just as efficient to leave a
265  // few threads idle.
266  // }
267 
268  return itk::ITK_THREAD_RETURN_DEFAULT_VALUE;
269 }
270 
271 template <class TInputImage, class TOutputPointSet>
273 {
274  // Get the output pointer
275  typename InputImageType::ConstPointer inputPtr = this->GetInput();
276  const typename TInputImage::SizeType& requestedRegionSize = inputPtr->GetRequestedRegion().GetSize();
277 
278  int splitAxis;
279  typename TInputImage::IndexType splitIndex;
280  typename TInputImage::SizeType splitSize;
281 
282  // Initialize the splitRegion to the output requested region
283  splitRegion = inputPtr->GetRequestedRegion();
284  splitIndex = splitRegion.GetIndex();
285  splitSize = splitRegion.GetSize();
286 
287  // split on the outermost dimension available
288  splitAxis = inputPtr->GetImageDimension() - 1;
289  while (requestedRegionSize[splitAxis] == 1)
290  {
291  --splitAxis;
292  if (splitAxis < 0)
293  { // cannot split
294  itkDebugMacro(" Cannot Split");
295  return 1;
296  }
297  }
298 
299  // determine the actual number of pieces that will be generated
300  typename TInputImage::SizeType::SizeValueType range = requestedRegionSize[splitAxis];
301  int valuesPerThread = (int)::std::ceil(range / (double)num);
302  int maxThreadIdUsed = (int)::std::ceil(range / (double)valuesPerThread) - 1;
303 
304  // Split the region
305  if (i < maxThreadIdUsed)
306  {
307  splitIndex[splitAxis] += i * valuesPerThread;
308  splitSize[splitAxis] = valuesPerThread;
309  }
310  if (i == maxThreadIdUsed)
311  {
312  splitIndex[splitAxis] += i * valuesPerThread;
313  // last thread needs to process the "rest" dimension being split
314  splitSize[splitAxis] = splitSize[splitAxis] - i * valuesPerThread;
315  }
316 
317  // set the split region ivars
318  splitRegion.SetIndex(splitIndex);
319  splitRegion.SetSize(splitSize);
320 
321  itkDebugMacro(" Split Piece: " << splitRegion);
322 
323  return maxThreadIdUsed + 1;
324 }
325 
326 } // end namespace otb
327 
328 #endif
virtual int SplitRequestedRegion(int i, int num, InputImageRegionType &splitRegion)
virtual void ThreadedGenerateData(const InputImageRegionType &inputRegionForThread, itk::ThreadIdType threadId)
Superclass::PointsContainerType PointsContainerType
InputImageType::Pointer InputImagePointer
std::vector< typename OutputPointSetType::PointDataContainer::Pointer > OutputPointDataContainerForThreadType
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Superclass::OutputPointSetType OutputPointSetType
Superclass::PointDataContainerType PointDataContainerType
Superclass::OutputPointSetPointer OutputPointSetPointer
std::vector< typename OutputPointSetType::PointsContainer::Pointer > OutputPointsContainerForThreadType
static itk::ITK_THREAD_RETURN_TYPE ThreaderCallback(void *arg)
InputImageType::RegionType InputImageRegionType
void GenerateOutputInformation(void) override
const InputImageType * GetInput()
void SetInput(unsigned int idx, const InputImageType *input)
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.