OTB  10.0.0
Orfeo Toolbox
otbSFSTexturesImageFilter.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 otbSFSTexturesImageFilter_hxx
22 #define otbSFSTexturesImageFilter_hxx
23 
25 
26 #include "itkProgressReporter.h"
27 #include "itkImageRegionIterator.h"
28 #include "itkNeighborhoodAlgorithm.h"
29 #include "otbMath.h"
30 #include "otbMacro.h" //for
31 namespace otb
32 {
33 
34 template <class TInputImage, class TOutputImage>
36 {
37  this->DynamicMultiThreadingOff();
38  this->SetNumberOfRequiredInputs(1);
39  this->SetNumberOfRequiredInputs(1);
40  this->SetNumberOfRequiredOutputs(6);
41  this->SetNumberOfRequiredOutputs(1);
42 
43  this->SetNthOutput(0, OutputImageType::New());
44  this->SetNthOutput(1, OutputImageType::New());
45  this->SetNthOutput(2, OutputImageType::New());
46  this->SetNthOutput(3, OutputImageType::New());
47  this->SetNthOutput(4, OutputImageType::New());
48  this->SetNthOutput(5, OutputImageType::New());
49 
50  m_Radius = this->GetSpatialThreshold();
51  m_FunctorList.clear();
52 }
58 // Return output length image
59 template <class TInputImage, class TOutputImage>
61 {
62  if (this->GetNumberOfOutputs() < 1)
63  {
64  return 0;
65  }
66  if (this->GetTexturesStatus()[0] == false)
67  {
68  itkExceptionMacro(<< "Impossible to create length image : texture not selected");
69  }
70  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(0));
71 }
72 template <class TInputImage, class TOutputImage>
74 {
75  if (this->GetNumberOfOutputs() < 1)
76  {
77  return nullptr;
78  }
79  if (this->GetTexturesStatus()[0] == false)
80  {
81  itkExceptionMacro(<< "Impossible to create length image : texture not selected");
82  }
83  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(0));
84 }
86 
87 // Return output width image
88 template <class TInputImage, class TOutputImage>
90 {
91  if (this->GetNumberOfOutputs() < 2)
92  {
93  return 0;
94  }
95  if (this->GetTexturesStatus()[1] == false)
96  {
97  itkExceptionMacro(<< "Impossible to create width image : texture not selected");
98  }
99  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(1));
100 }
101 template <class TInputImage, class TOutputImage>
103 {
104  if (this->GetNumberOfOutputs() < 2)
105  {
106  return nullptr;
107  }
108  if (this->GetTexturesStatus()[1] == false)
109  {
110  itkExceptionMacro(<< "Impossible to create width image : texture not selected");
111  }
112  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(1));
113 }
114 
115 // Return output PSI image
116 template <class TInputImage, class TOutputImage>
118 {
119  if (this->GetNumberOfOutputs() < 3)
120  {
121  return 0;
122  }
123  if (this->GetTexturesStatus()[2] == false)
124  {
125  itkExceptionMacro(<< "Impossible to create PSI image : texture not selected");
126  }
127  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(2));
128 }
129 template <class TInputImage, class TOutputImage>
131 {
132  if (this->GetNumberOfOutputs() < 3)
133  {
134  return nullptr;
135  }
136  if (this->GetTexturesStatus()[2] == false)
137  {
138  itkExceptionMacro(<< "Impossible to create PSI image : texture not selected");
139  }
140 
141  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(2));
142 }
143 
144 // Return output WMean image
145 template <class TInputImage, class TOutputImage>
147 {
148  if (this->GetNumberOfOutputs() < 4)
149  {
150  return 0;
151  }
152  if (this->GetTexturesStatus()[3] == false)
153  {
154  itkExceptionMacro(<< "Impossible to create W-Mean image : texture not selected");
155  }
156  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(3));
157 }
158 template <class TInputImage, class TOutputImage>
160 {
161  if (this->GetNumberOfOutputs() < 4)
162  {
163  return nullptr;
164  }
165  if (this->GetTexturesStatus()[3] == false)
166  {
167  itkExceptionMacro(<< "Impossible to create W-Mean image : texture not selected");
168  }
169  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(3));
170 }
171 
172 // Return output ratio image
173 template <class TInputImage, class TOutputImage>
175 {
176  if (this->GetNumberOfOutputs() < 5)
177  {
178  return 0;
179  }
180  if (this->GetTexturesStatus()[4] == false)
181  {
182  itkExceptionMacro(<< "Impossible to create Ratio image : texture not selected");
183  }
184  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(4));
185 }
186 template <class TInputImage, class TOutputImage>
188 {
189  if (this->GetNumberOfOutputs() < 5)
190  {
191  return nullptr;
192  }
193  if (this->GetTexturesStatus()[4] == false)
194  {
195  itkExceptionMacro(<< "Impossible to create Ratio image : texture not selected");
196  }
197  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(4));
198 }
199 
200 // Return output SD image
201 template <class TInputImage, class TOutputImage>
203 {
204  if (this->GetNumberOfOutputs() < 6)
205  {
206  return 0;
207  }
208  if (this->GetTexturesStatus()[5] == false)
209  {
210  itkExceptionMacro(<< "Impossible to create SD image : texture not selected");
211  }
212  return static_cast<const OutputImageType*>(this->itk::ProcessObject::GetOutput(5));
213 }
214 template <class TInputImage, class TOutputImage>
216 {
217  if (this->GetNumberOfOutputs() < 6)
218  {
219  return nullptr;
220  }
221  if (this->GetTexturesStatus()[5] == false)
222  {
223  itkExceptionMacro(<< "Impossible to create SD image : texture not selected");
224  }
225 
226  return static_cast<OutputImageType*>(this->itk::ProcessObject::GetOutput(5));
227 }
228 
229 template <class TInputImage, class TOutputImage>
231 {
232  Superclass::BeforeThreadedGenerateData();
233  if (this->GetSpatialThreshold() < this->GetRatioMaxConsiderationNumber())
234  {
235  itkExceptionMacro(<< "Spatial Threshold (" << this->GetSpatialThreshold() << ") is lower than Ration Max Consideration Number ("
236  << this->GetRatioMaxConsiderationNumber() << ") what is not allowed.");
237  }
238  for (unsigned int i = 0; i < this->GetNumberOfWorkUnits(); ++i)
239  {
240  m_FunctorList.push_back(m_Functor);
241  }
242  this->InitFeatureStatus(true);
243 }
244 
245 template <class TInputImage, class TOutputImage>
247 {
248  // call the superclass' implementation of this method
249  Superclass::GenerateInputRequestedRegion();
250 
251  // get pointers to the input and output
252  typename Superclass::InputImagePointer inputPtr = const_cast<TInputImage*>(this->GetInput());
253  typename Superclass::OutputImagePointer outputPtr1 = this->GetOutput(0); // this->GetLengthOutput();
254  typename Superclass::OutputImagePointer outputPtr2 = this->GetOutput(1); // this->GetWidthOutput();
255  typename Superclass::OutputImagePointer outputPtr3 = this->GetOutput(2); // this->GetPSIOutput();
256  typename Superclass::OutputImagePointer outputPtr4 = this->GetOutput(3); // this->GetWMeanOutput();
257  typename Superclass::OutputImagePointer outputPtr5 = this->GetOutput(4); // this->GetRatioOutput();
258  typename Superclass::OutputImagePointer outputPtr6 = this->GetOutput(5); // this->GetSDOutput();
259 
260  if (!inputPtr || !outputPtr1 || !outputPtr2 || !outputPtr3 || !outputPtr4 || !outputPtr5 || !outputPtr6)
261  {
262  return;
263  }
264  // get a copy of the input requested region (should equal the output
265  // requested region)
266  typename TInputImage::RegionType inputRequestedRegion;
267  inputRequestedRegion = inputPtr->GetRequestedRegion();
268 
269  // pad the input requested region by the operator radius
270  InputImageSizeType rad;
271  rad[0] = m_Radius;
272  rad[1] = m_Radius;
273  inputRequestedRegion.PadByRadius(rad);
274 
275  // crop the input requested region at the input's largest possible region
276  if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
277  {
278  inputPtr->SetRequestedRegion(inputRequestedRegion);
279  return;
280  }
281  else
282  {
283  // Couldn't crop the region (requested region is outside the largest
284  // possible region). Throw an exception.
285 
286  // store what we tried to request (prior to trying to crop)
287  inputPtr->SetRequestedRegion(inputRequestedRegion);
288 
289  // build an exception
290  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
291  std::ostringstream msg;
292  msg << this->GetNameOfClass() << "::GenerateInputRequestedRegion()";
293  e.SetLocation(msg.str());
294  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
295  e.SetDataObject(inputPtr);
296  throw e;
297  }
298 }
299 
300 template <class TInputImage, class TOutputImage>
302 {
303  Superclass::GenerateOutputInformation();
304  // this->GetOutput()->SetNumberOfComponentsPerPixel(6);
305 }
306 
307 template <class TInputImage, class TOutputImage>
308 void SFSTexturesImageFilter<TInputImage, TOutputImage>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
309 {
310  itk::ZeroFluxNeumannBoundaryCondition<TInputImage> nbc;
311 
312  // We use dynamic_cast since inputs are stored as DataObjects. The
313  // ImageToImageFilter::GetInput(int) always returns a pointer to a
314  // TInputImage so it cannot be used for the second input.
315  InputImagePointerType inputPtr = dynamic_cast<const TInputImage*>(ProcessObjectType::GetInput(0));
316  OutputImagePointerType outputPtr1 = this->GetOutput(0);
317  OutputImagePointerType outputPtr2 = this->GetOutput(1);
318  OutputImagePointerType outputPtr3 = this->GetOutput(2);
319  OutputImagePointerType outputPtr4 = this->GetOutput(3);
320  OutputImagePointerType outputPtr5 = this->GetOutput(4);
321  OutputImagePointerType outputPtr6 = this->GetOutput(5);
322 
323  RadiusType r;
324  r.Fill(this->GetRadius());
325  NeighborhoodIteratorType neighInputIt;
326 
327  itk::ImageRegionIterator<TOutputImage> outputIt1, outputIt2, outputIt3, outputIt4, outputIt5, outputIt6;
328  FunctorOutputType outputFunctor;
329 
330  // Find the data-set boundary "faces"
331  typename itk::NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<TInputImage>::FaceListType faceList;
332  typename itk::NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<TInputImage> bC;
333  faceList = bC(inputPtr, outputRegionForThread, r);
334 
335  typename itk::NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<TInputImage>::FaceListType::iterator fit;
336 
337  // support progress methods/callbacks
338  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
339 
340  // Process each of the boundary faces. These are N-d regions which border
341  // the edge of the buffer.
342 
343  std::vector<bool> textStatus = this->GetTexturesStatus();
344  for (fit = faceList.begin(); fit != faceList.end(); ++fit)
345  {
346  neighInputIt = itk::ConstNeighborhoodIterator<TInputImage>(r, inputPtr, *fit);
347 
348  outputIt1 = itk::ImageRegionIterator<TOutputImage>(outputPtr1, *fit);
349  outputIt2 = itk::ImageRegionIterator<TOutputImage>(outputPtr2, *fit);
350  outputIt3 = itk::ImageRegionIterator<TOutputImage>(outputPtr3, *fit);
351  outputIt4 = itk::ImageRegionIterator<TOutputImage>(outputPtr4, *fit);
352  outputIt5 = itk::ImageRegionIterator<TOutputImage>(outputPtr5, *fit);
353  outputIt6 = itk::ImageRegionIterator<TOutputImage>(outputPtr6, *fit);
354 
355  std::vector<itk::ImageRegionIterator<TOutputImage>*> outItList;
356  outItList.push_back(&outputIt1);
357  outItList.push_back(&outputIt2);
358  outItList.push_back(&outputIt3);
359  outItList.push_back(&outputIt4);
360  outItList.push_back(&outputIt5);
361  outItList.push_back(&outputIt6);
362 
363  neighInputIt.OverrideBoundaryCondition(&nbc);
364  neighInputIt.GoToBegin();
365 
366  for (unsigned int i = 0; i < outItList.size(); ++i)
367  {
368  (*outItList[i]).GoToBegin();
369  }
370 
371  while (!outputIt1.IsAtEnd())
372  {
373 
374  outputFunctor = m_FunctorList[threadId](neighInputIt);
375  for (unsigned int i = 0; i < outItList.size(); ++i)
376  {
377  if (textStatus[i] == true)
378  (*outItList[i]).Set(outputFunctor[i]);
379  }
380 
381  ++neighInputIt;
382  for (unsigned int i = 0; i < outItList.size(); ++i)
383  {
384  ++(*outItList[i]);
385  }
386 
387  progress.CompletedPixel();
388  }
389  }
390 }
391 
392 template <class TInputImage, class TOutputImage>
394 {
395  for (FeatureType id = LENGTH; id <= SD; id = static_cast<FeatureType>(id + 1))
396  {
397  this->SetFeatureStatus(static_cast<FeatureType>(id), status);
398  }
399 }
400 
404 template <class TInputImage, class TOutputImage>
405 void SFSTexturesImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
406 {
407  Superclass::PrintSelf(os, indent);
408 
409  // os << indent << "Spatial Threshold : " << this->GetSpatialThreshold() << std::endl;
410  // os << indent << "Spectral Threshold : " << this->GetSpectralThreshold() << std::endl;
411  // os << indent << "Ratio Max Consideration Number: " << this->GetRatioMaxConsiderationNumber() << std::endl;
412  // os << indent << "Alpha : " << this->GetAlpha() << std::endl;
413  // os << indent << "Number Of Directions : " << this->GetNumberOfDirections() << std::endl;
414 }
415 
416 } // end namespace otb
417 
418 #endif
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
const OutputImageType * GetLengthOutput() const
FunctorType::OutputType FunctorOutputType
const OutputImageType * GetWMeanOutput() const
InputImageType::SizeType InputImageSizeType
const OutputImageType * GetWidthOutput() const
NeighborhoodIteratorType::RadiusType RadiusType
OutputImageType::RegionType OutputImageRegionType
itk::ConstNeighborhoodIterator< TInputImage > NeighborhoodIteratorType
InputImageType::ConstPointer InputImagePointerType
OutputImageType::Pointer OutputImagePointerType
const OutputImageType * GetSDOutput() const
void GenerateInputRequestedRegion(void) override
void PrintSelf(std::ostream &os, itk::Indent indent) const override
const OutputImageType * GetRatioOutput() const
const OutputImageType * GetPSIOutput() const
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.