OTB  9.0.0
Orfeo Toolbox
otbGridResampleImageFilter.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 otbGridResampleImageFilter_hxx
22 #define otbGridResampleImageFilter_hxx
23 
25 
26 #include "otbStreamingTraits.h"
27 #include "otbImage.h"
28 
29 #include "itkNumericTraits.h"
30 #include "itkProgressReporter.h"
31 #include "itkImageScanlineIterator.h"
32 #include "itkContinuousIndex.h"
33 
34 namespace otb
35 {
36 
37 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
39  : m_OutputStartIndex(),
40  m_OutputSize(),
41  m_OutputOrigin(),
42  m_OutputSpacing(),
43  m_EdgePaddingValue(),
44  m_InterpolationMargin(0.0),
45  m_CheckOutputBounds(true),
46  m_Interpolator(),
47  m_ReachableOutputRegion()
48 {
49  // Set linear interpolator as default
50  m_Interpolator = dynamic_cast<InterpolatorType*>(DefaultInterpolatorType::New().GetPointer());
51 
52  // Initialize EdgePaddingValue
53  m_EdgePaddingValue = itk::NumericTraits<OutputPixelType>::ZeroValue(m_EdgePaddingValue);
54 
55  // Initialize origin and spacing
56  m_OutputOrigin.Fill(0.);
57  m_OutputSpacing.Fill(1.);
58  m_OutputStartIndex.Fill(0);
59  m_OutputSize.Fill(0);
60 }
61 
62 
64 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
66 {
67  this->SetOutputOrigin(image->GetOrigin());
68  this->SetOutputSpacing(internal::GetSignedSpacing(image));
69  this->SetOutputStartIndex(image->GetLargestPossibleRegion().GetIndex());
70  this->SetOutputSize(image->GetLargestPossibleRegion().GetSize());
71 }
73 
74 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
76 {
77  // call the superclass' implementation of this method
78  Superclass::GenerateOutputInformation();
79 
80  // get pointers to the input and output
81  OutputImageType* outputPtr = this->GetOutput();
82  if (!outputPtr)
83  {
84  return;
85  }
86 
87  // Fill output image data
88  typename TOutputImage::RegionType outputLargestPossibleRegion;
89  outputLargestPossibleRegion.SetSize(m_OutputSize);
90  outputLargestPossibleRegion.SetIndex(m_OutputStartIndex);
91 
92  outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion);
93  outputPtr->SetSignedSpacing(m_OutputSpacing);
94  outputPtr->SetOrigin(m_OutputOrigin);
95 
96  // TODO: Report no data value here
97 }
98 
99 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
101 {
102  // call the superclass's implementation of this method
103  Superclass::GenerateInputRequestedRegion();
104 
105  // Check for input
106  if (!this->GetInput())
107  {
108  return;
109  }
110 
111  // get pointers to the input and output
112  typename TInputImage::Pointer inputPtr = const_cast<TInputImage*>(this->GetInput());
113 
114  // check for output
115  OutputImageType* outputPtr = this->GetOutput();
116  if (!outputPtr)
117  {
118  return;
119  }
120 
121  typename TOutputImage::RegionType outputRequestedRegion = outputPtr->GetRequestedRegion();
122 
123  IndexType outULIndex, outLRIndex;
124 
125  typedef itk::ContinuousIndex<double, TInputImage::ImageDimension> ContinuousIndexType;
126 
127  ContinuousIndexType inULCIndex, inLRCIndex;
128 
129  // Get output image requested region corners as Index
130  outULIndex = outputRequestedRegion.GetIndex();
131  outLRIndex = outULIndex + outputRequestedRegion.GetSize();
132  outLRIndex[0] -= 1;
133  outLRIndex[1] -= 1;
134 
135  // Transform to physiscal points
136  PointType outULPoint, outLRPoint;
137  outputPtr->TransformIndexToPhysicalPoint(outULIndex, outULPoint);
138  outputPtr->TransformIndexToPhysicalPoint(outLRIndex, outLRPoint);
139 
140  // Transform to input image Index
141  inputPtr->TransformPhysicalPointToContinuousIndex(outULPoint, inULCIndex);
142  inputPtr->TransformPhysicalPointToContinuousIndex(outLRPoint, inLRCIndex);
143 
144  SizeType inSize;
145  IndexType inULIndex, inLRIndex;
146 
147  // Reorder index properly and compute size
148  for (unsigned int dim = 0; dim < ImageDimension; ++dim)
149  {
150  if (inULCIndex[dim] > inLRCIndex[dim])
151  {
152  // swap
153  typename ContinuousIndexType::ValueType tmp(inULCIndex[dim]);
154  inULCIndex[dim] = inLRCIndex[dim];
155  inLRCIndex[dim] = tmp;
156  }
157 
158  // Ensure correct rounding of coordinates
159 
160  inULIndex[dim] = std::floor(inULCIndex[dim]);
161  inLRIndex[dim] = std::ceil(inLRCIndex[dim]);
162 
163  inSize[dim] = static_cast<typename SizeType::SizeValueType>(inLRIndex[dim] - inULIndex[dim]) + 1;
164  }
165 
166  // Build the input requested region
167  typename TInputImage::RegionType inputRequestedRegion;
168  inputRequestedRegion.SetIndex(inULIndex);
169  inputRequestedRegion.SetSize(inSize);
170 
171  // Compute the padding due to the interpolator
172  unsigned int interpolatorRadius = StreamingTraits<typename Superclass::InputImageType>::CalculateNeededRadiusForInterpolator(this->GetInterpolator());
173  inputRequestedRegion.PadByRadius(interpolatorRadius);
174 
175  // crop the input requested region at the input's largest possible region
176  if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
177  {
178  inputPtr->SetRequestedRegion(inputRequestedRegion);
179  }
180  else
181  {
182 
183  // store what we tried to request (prior to trying to crop)
184  inputPtr->SetRequestedRegion(inputRequestedRegion);
185 
186  // build an exception
187  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
188  e.SetLocation(ITK_LOCATION);
189  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
190  e.SetDataObject(inputPtr);
191  throw e;
192  }
193 }
194 
195 
196 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
198 {
199  if (!m_Interpolator)
200  {
201  itkExceptionMacro(<< "Interpolator not set");
202  }
203 
204  // Connect input image to interpolator
205  m_Interpolator->SetInputImage(this->GetInput());
206 
207 
208  unsigned int nComponents = itk::DefaultConvertPixelTraits<OutputPixelType>::GetNumberOfComponents(m_EdgePaddingValue);
209 
210  if (nComponents == 0)
211  {
212 
213  // Build a default value of the correct number of components
214  OutputPixelComponentType zeroComponent = itk::NumericTraits<OutputPixelComponentType>::ZeroValue(zeroComponent);
215 
216  nComponents = this->GetInput()->GetNumberOfComponentsPerPixel();
217 
218  itk::NumericTraits<OutputPixelType>::SetLength(m_EdgePaddingValue, nComponents);
219  for (unsigned int n = 0; n < nComponents; n++)
220  {
221  OutputPixelConvertType::SetNthComponent(n, m_EdgePaddingValue, zeroComponent);
222  }
223  }
224 
225  // Compute ReachableOutputRegion
226  // InputImage buffered region corresponds to a region of the output
227  // image. Computing it beforehand allows saving IsInsideBuffer
228  // calls in the interpolation loop
229 
230  // Compute the padding due to the interpolator
231 
232  IndexType inUL = this->GetInput()->GetBufferedRegion().GetIndex();
233  IndexType inLR = this->GetInput()->GetBufferedRegion().GetIndex() + this->GetInput()->GetBufferedRegion().GetSize();
234  inLR[0] -= 1;
235  inLR[1] -= 1;
236 
237  // We should take interpolation radius into account here, but this
238  // does not match the IsInsideBuffer method
239  // unsigned int interpolatorRadius =
240  // StreamingTraits<typename Superclass::InputImageType>::CalculateNeededRadiusForInterpolator(this->GetInterpolator());
241  // inUL[0]+=interpolatorRadius;
242  // inUL[1]+=interpolatorRadius;
243  // inLR[0]-=interpolatorRadius;
244  // inLR[1]-=interpolatorRadius;
245 
246  PointType inULp, inLRp;
247  this->GetInput()->TransformIndexToPhysicalPoint(inUL, inULp);
248  this->GetInput()->TransformIndexToPhysicalPoint(inLR, inLRp);
249 
250  inULp -= (0.5 - m_InterpolationMargin) * this->GetInput()->GetSignedSpacing();
251  inLRp += (0.5 - m_InterpolationMargin) * this->GetInput()->GetSignedSpacing();
252 
255  this->GetOutput()->TransformPhysicalPointToContinuousIndex(inULp, outUL);
256  this->GetOutput()->TransformPhysicalPointToContinuousIndex(inLRp, outLR);
257 
258  IndexType outputIndex;
259  // This needs to take into account negative spacing
260  outputIndex[0] = std::ceil(std::min(outUL[0], outLR[0]));
261  outputIndex[1] = std::ceil(std::min(outUL[1], outLR[1]));
262 
263  SizeType outputSize;
264  outputSize[0] = std::floor(std::max(outUL[0], outLR[0])) - outputIndex[0] + 1;
265  outputSize[1] = std::floor(std::max(outUL[1], outLR[1])) - outputIndex[1] + 1;
266 
267  m_ReachableOutputRegion.SetIndex(outputIndex);
268  m_ReachableOutputRegion.SetSize(outputSize);
269 
270  otbMsgDevMacro(<< "ReachableOutputRegion: " << m_ReachableOutputRegion);
271 }
272 
273 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
275  itk::ThreadIdType threadId)
276 {
277  // Get the output pointers
278  OutputImageType* outputPtr = this->GetOutput();
279 
280  // Get this input pointers
281  const InputImageType* inputPtr = this->GetInput();
282 
283  // Min/max values of the output pixel type AND these values
284  // represented as the output type of the interpolator
285  const OutputPixelComponentType minValue = itk::NumericTraits<OutputPixelComponentType>::NonpositiveMin();
286  const OutputPixelComponentType maxValue = itk::NumericTraits<OutputPixelComponentType>::max();
287 
288  const InterpolatorComponentType minOutputValue = static_cast<InterpolatorComponentType>(minValue);
289  const InterpolatorComponentType maxOutputValue = static_cast<InterpolatorComponentType>(maxValue);
290 
291  // Iterator on the output region for current thread
292  OutputImageRegionType regionToCompute = outputRegionForThread;
293  bool cropSucceed = regionToCompute.Crop(m_ReachableOutputRegion);
294 
295  // Fill thread buffer
296  itk::ImageScanlineIterator<OutputImageType> outItFull(outputPtr, outputRegionForThread);
297  outItFull.GoToBegin();
298  while (!outItFull.IsAtEnd())
299  {
300  while (!outItFull.IsAtEndOfLine())
301  {
302  outItFull.Set(m_EdgePaddingValue);
303  ++outItFull;
304  }
305  outItFull.NextLine();
306  }
307 
308  if (!cropSucceed)
309  return;
310 
311  itk::ImageScanlineIterator<OutputImageType> outIt(outputPtr, regionToCompute);
312 
313  // Support for progress methods/callbacks
314  itk::ProgressReporter progress(this, threadId, regionToCompute.GetSize()[1]);
315 
316  // Temporary variables for loop
317  PointType outPoint;
318  ContinuousInputIndexType inCIndex;
319  InterpolatorOutputType interpolatorValue; //(this->GetOutput()->GetNumberOfComponentsPerPixel());
320  OutputPixelType outputValue; //(this->GetOutput()->GetNumberOfComponentsPerPixel());
321 
322  // TODO: assert outputPtr->GetSignedSpacing() != 0 here
323  assert(outputPtr->GetSignedSpacing()[0] != 0 && "Null spacing will cause division by zero.");
324  const double delta = outputPtr->GetSignedSpacing()[0] / inputPtr->GetSignedSpacing()[0];
325 
326  // Iterate through the output region
327  outIt.GoToBegin();
328 
329  while (!outIt.IsAtEnd())
330  {
331  // Map output index to input continuous index
332  outputPtr->TransformIndexToPhysicalPoint(outIt.GetIndex(), outPoint);
333  inputPtr->TransformPhysicalPointToContinuousIndex(outPoint, inCIndex);
334 
335  while (!outIt.IsAtEndOfLine())
336  {
337  // Interpolate
338  interpolatorValue = m_Interpolator->EvaluateAtContinuousIndex(inCIndex);
339 
340  // Cast and check bounds
341  this->CastPixelWithBoundsChecking(interpolatorValue, minOutputValue, maxOutputValue, outputValue);
342 
343  // Set output value
344  outIt.Set(outputValue);
345 
346  // move one pixel forward
347  ++outIt;
348 
349  // Update input position
350  inCIndex[0] += delta;
351  }
352 
353  // Report progress
354  progress.CompletedPixel();
355 
356  // Move to next line
357  outIt.NextLine();
358  }
359 }
360 
361 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
363 {
364  // Disconnect input image from the interpolator
365  m_Interpolator->SetInputImage(nullptr);
366 }
367 
368 
369 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
371 {
372  itk::ModifiedTimeType latestTime = itk::Object::GetMTime();
373 
374  if (m_Interpolator)
375  {
376  if (latestTime < m_Interpolator->GetMTime())
377  {
378  latestTime = m_Interpolator->GetMTime();
379  }
380  }
381 
382  return latestTime;
383 }
384 
385 
386 template <typename TInputImage, typename TOutputImage, typename TInterpolatorPrecision>
388 {
389  Superclass::PrintSelf(os, indent);
390 
391  os << indent << "EdgePaddingValue: " << static_cast<typename itk::NumericTraits<OutputPixelType>::PrintType>(m_EdgePaddingValue) << std::endl;
392  os << indent << "OutputStartIndex: " << m_OutputStartIndex << std::endl;
393  os << indent << "OutputSize: " << m_OutputSize << std::endl;
394  os << indent << "OutputOrigin: " << m_OutputOrigin << std::endl;
395  os << indent << "OutputSpacing: " << m_OutputSpacing << std::endl;
396  os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl;
397  os << indent << "CheckOutputBounds: " << (m_CheckOutputBounds ? "On" : "Off") << std::endl;
398 }
399 
400 
401 } // namespace otb
402 
403 
404 #endif
otb::GridResampleImageFilter::PointType
ImageBaseType::PointType PointType
Definition: otbGridResampleImageFilter.h:106
otb::GridResampleImageFilter::m_Interpolator
InterpolatorPointerType m_Interpolator
Definition: otbGridResampleImageFilter.h:203
otb::GridResampleImageFilter::GetMTime
itk::ModifiedTimeType GetMTime(void) const override
Definition: otbGridResampleImageFilter.hxx:370
otb::GridResampleImageFilter::OutputImageType
TOutputImage OutputImageType
Definition: otbGridResampleImageFilter.h:83
otbGridResampleImageFilter.h
otb::GridResampleImageFilter::InterpolatorType
itk::InterpolateImageFunction< InputImageType, TInterpolatorPrecision > InterpolatorType
Definition: otbGridResampleImageFilter.h:92
otb::GridResampleImageFilter::ThreadedGenerateData
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
Definition: otbGridResampleImageFilter.hxx:274
otbImage.h
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::GridResampleImageFilter::m_OutputOrigin
PointType m_OutputOrigin
Definition: otbGridResampleImageFilter.h:192
otb::GridResampleImageFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbGridResampleImageFilter.hxx:387
otb::GridResampleImageFilter::BeforeThreadedGenerateData
void BeforeThreadedGenerateData() override
Definition: otbGridResampleImageFilter.hxx:197
otb::GridResampleImageFilter::InterpolatorOutputType
InterpolatorType::OutputType InterpolatorOutputType
Definition: otbGridResampleImageFilter.h:95
otb::GridResampleImageFilter::GridResampleImageFilter
GridResampleImageFilter()
Definition: otbGridResampleImageFilter.hxx:38
otb::StreamingTraits::CalculateNeededRadiusForInterpolator
static unsigned int CalculateNeededRadiusForInterpolator(const InterpolationType *interpolator)
Definition: otbStreamingTraits.hxx:29
otb::mpl::GetNumberOfComponents
unsigned int GetNumberOfComponents(PixelType const &pix)
Definition: otbArrayTraits.h:215
otb::GridResampleImageFilter::SetOutputParametersFromImage
void SetOutputParametersFromImage(const ImageBaseType *image)
Definition: otbGridResampleImageFilter.hxx:65
otb::GridResampleImageFilter::AfterThreadedGenerateData
void AfterThreadedGenerateData() override
Definition: otbGridResampleImageFilter.hxx:362
otb::GridResampleImageFilter::IndexType
ImageBaseType::IndexType IndexType
Definition: otbGridResampleImageFilter.h:107
otb::GridResampleImageFilter::m_OutputSize
SizeType m_OutputSize
Definition: otbGridResampleImageFilter.h:191
otb::GridResampleImageFilter::m_OutputStartIndex
IndexType m_OutputStartIndex
Definition: otbGridResampleImageFilter.h:190
otbStreamingTraits.h
otb::GridResampleImageFilter::InputImageType
TInputImage InputImageType
Definition: otbGridResampleImageFilter.h:82
otb::GridResampleImageFilter::m_EdgePaddingValue
OutputPixelType m_EdgePaddingValue
Definition: otbGridResampleImageFilter.h:195
otb::GridResampleImageFilter::m_OutputSpacing
SpacingType m_OutputSpacing
Definition: otbGridResampleImageFilter.h:193
otbMsgDevMacro
#define otbMsgDevMacro(x)
Definition: otbMacro.h:64
otb::GridResampleImageFilter::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbGridResampleImageFilter.h:84
otb::internal::GetSignedSpacing
ImageType::SpacingType GetSignedSpacing(const ImageType *input)
Definition: otbImage.h:41
otb::GridResampleImageFilter::ContinuousInputIndexType
itk::ContinuousIndex< double, InputImageDimension > ContinuousInputIndexType
Definition: otbGridResampleImageFilter.h:100
otb::GridResampleImageFilter::GenerateInputRequestedRegion
void GenerateInputRequestedRegion() override
Definition: otbGridResampleImageFilter.hxx:100
otb::GridResampleImageFilter::InterpolatorComponentType
InterpolatorConvertType::ComponentType InterpolatorComponentType
Definition: otbGridResampleImageFilter.h:97
otb::GridResampleImageFilter::GenerateOutputInformation
void GenerateOutputInformation() override
Definition: otbGridResampleImageFilter.hxx:75
otb::GridResampleImageFilter::SizeType
ImageBaseType::SizeType SizeType
Definition: otbGridResampleImageFilter.h:105
otb::GridResampleImageFilter::OutputPixelType
TOutputImage::PixelType OutputPixelType
Definition: otbGridResampleImageFilter.h:85
otb::GridResampleImageFilter::ImageBaseType
itk::ImageBase< OutputImageType::ImageDimension > ImageBaseType
Definition: otbGridResampleImageFilter.h:103
otb::GridResampleImageFilter::OutputPixelComponentType
OutputPixelConvertType::ComponentType OutputPixelComponentType
Definition: otbGridResampleImageFilter.h:89