OTB  9.0.0
Orfeo Toolbox
otbStreamingMosaicFilterBase.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
4  * Copyright (C) 2016-2019 IRSTEA
5  *
6  * This file is part of Orfeo Toolbox
7  *
8  * https://www.orfeo-toolbox.org/
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22 #ifndef __StreamingMosaicFilterBase_hxx
23 #define __StreamingMosaicFilterBase_hxx
24 
26 
27 namespace otb
28 {
29 
30 template <class TInputImage, class TOutputImage, class TInternalValueType>
32 {
33 
34  m_OutputSpacing.Fill(0);
35  m_OutputOrigin.Fill(0);
36  m_OutputSize.Fill(0);
37  m_ShiftScaleInputImages = false;
38  m_AutomaticOutputParametersComputation = true;
39  Superclass::SetCoordinateTolerance(itk::NumericTraits<double>::max());
40  Superclass::SetDirectionTolerance(itk::NumericTraits<double>::max());
41  interpolatorRadius = 0;
42  nbOfBands = 0;
43 }
44 
48 template <class TInputImage, class TOutputImage, class TInternalValueType>
50  InputImagePointType& extentSup)
51 {
52 
53  // Get index of the last pixel
54  InputImageIndexType imageLastIndex;
55 
56  for (unsigned int dim = 0; dim < OutputImageType::ImageDimension; ++dim)
57  {
58  imageLastIndex[dim] = image->GetLargestPossibleRegion().GetSize()[dim];
59  }
60 
61  // Compute extent
62  InputImagePointType imageOrigin = image->GetOrigin();
63  OutputImagePointType imageEnd;
64  image->TransformIndexToPhysicalPoint(imageLastIndex, imageEnd);
65  for (unsigned int dim = 0; dim < OutputImageType::ImageDimension; ++dim)
66  {
67  extentInf[dim] = vnl_math_min(imageOrigin[dim], imageEnd[dim]);
68  extentSup[dim] = vnl_math_max(imageOrigin[dim], imageEnd[dim]);
69  }
70 }
71 
79 template <class TInputImage, class TOutputImage, class TInternalValueType>
81  InputImageRegionType& inputRegion,
82  InputImageType*& inputImage)
83 {
84 
85  // Mosaic Region Start & End (mosaic image index)
86  OutputImageIndexType outIndexStart = outputRegion.GetIndex();
87  OutputImageIndexType outIndexEnd = outputRegion.GetUpperIndex();
88 
89  // Mosaic Region Start & End (geo)
90  OutputImagePointType outPointStart, outPointEnd;
91  this->GetOutput()->TransformIndexToPhysicalPoint(outIndexStart, outPointStart);
92  this->GetOutput()->TransformIndexToPhysicalPoint(outIndexEnd, outPointEnd);
93 
94  // Mosaic Region Start & End (input image index)
95  InputImageIndexType defIndexStart, defIndexEnd;
96  inputImage->TransformPhysicalPointToIndex(outPointStart, defIndexStart);
97  inputImage->TransformPhysicalPointToIndex(outPointEnd, defIndexEnd);
98 
99  // Compute input image region
100  InputImageSizeType defRequestedSize;
101  InputImageIndexType defRequestedIndex;
102  for (unsigned int dim = 0; dim < OutputImageType::ImageDimension; ++dim)
103  {
104  defRequestedIndex[dim] = vnl_math_min(defIndexStart[dim], defIndexEnd[dim]);
105  defRequestedSize[dim] = vnl_math_max(defIndexStart[dim], defIndexEnd[dim]) - defRequestedIndex[dim] + 1;
106  }
107  InputImageRegionType computedInputRegion(defRequestedIndex, defRequestedSize);
108 
109  // avoid extrapolation
110  computedInputRegion.PadByRadius(1);
111 
112  // padding for interpolator
113  computedInputRegion.PadByRadius(interpolatorRadius);
114 
115  inputRegion = computedInputRegion;
116 
117  // crop the input requested region at the input's largest possible region
118  return inputRegion.Crop(inputImage->GetLargestPossibleRegion());
119 }
120 
121 template <class TInputImage, class TOutputImage, class TInternalValueType>
123 {
124 
125  // Output requested region
126  const OutputImageRegionType outRegion = this->GetOutput()->GetRequestedRegion();
127 
128  // Get the input image pointer
129  InputImageType* inputTile = static_cast<InputImageType*>(Superclass::ProcessObject::GetInput(inputImageIndex));
130  InputImageRegionType inRegion;
131 
132  // Compute the requested region
133  if (OutputRegionToInputRegion(outRegion, inRegion, inputTile))
134  {
135  // Image does overlap requested region: add the image to the used input
136  // images list
137  itkDebugMacro(<< "Image #" << inputImageIndex << "\n" << inRegion << " is inside the requested region");
138  AddUsedInputImageIndex(inputImageIndex);
139  }
140  else
141  {
142  // Image does not overlap requested region: set requested region to null
143  itkDebugMacro(<< "Image #" << inputImageIndex << "\n" << inRegion << " is outside the requested region");
144  inRegion.GetModifiableSize().Fill(0);
145  inRegion.GetModifiableIndex().Fill(0);
146  }
147  inputTile->SetRequestedRegion(inRegion);
148 }
149 
153 template <class TInputImage, class TOutputImage, class TInternalValueType>
155 {
156  usedInputIndices.clear();
157 
158  // For each image, get the requested region
159  for (unsigned int i = 0; i < this->GetNumberOfInputs(); ++i)
160  {
161  ComputeRequestedRegionOfInputImage(i);
162  }
163 }
164 
166 template <class TInputImage, class TOutputImage, class TInternalValueType>
168 {
169 
170  const unsigned int numberOfInputImages = this->GetNumberOfInputImages();
171 
172  // Check shift-scale matrix dimensions
173  if (m_ShiftScaleInputImages)
174  {
175  if (m_ShiftMatrix.rows() == 0)
176  {
177  m_ShiftMatrix.set_size(numberOfInputImages, nbOfBands);
178  m_ShiftMatrix.fill(itk::NumericTraits<InternalValueType>::Zero);
179  }
180  if (m_ScaleMatrix.rows() == 0)
181  {
182  m_ScaleMatrix.set_size(numberOfInputImages, nbOfBands);
183  m_ScaleMatrix.fill(itk::NumericTraits<InternalValueType>::One);
184  }
185  if (m_ShiftMatrix.cols() != nbOfBands || m_ScaleMatrix.cols() != nbOfBands)
186  {
187  itkWarningMacro(<< "Shift-Scale matrices should have " << nbOfBands << " cols (1 col/band)"
188  << " instead of " << m_ShiftMatrix.cols());
189  }
190  if (m_ShiftMatrix.rows() != numberOfInputImages || m_ScaleMatrix.rows() != numberOfInputImages)
191  {
192  itkWarningMacro(<< "Shift-Scale matrices must have " << numberOfInputImages << " rows (1 row/input image)"
193  << " instead of " << m_ShiftMatrix.rows());
194  }
195  }
196 }
197 
198 /*
199  * Compute output parameters:
200  * -number of component per pixel
201  * -spacing
202  * -size
203  * -origin
204  */
205 template <class TInputImage, class TOutputImage, class TInternalValueType>
207 {
208  itkDebugMacro(<< "Computing output parameters of the mosaic image");
209 
210  // Initialize extent and spacing
211  OutputImagePointType extentInf, extentSup;
212  m_OutputSpacing.Fill(itk::NumericTraits<double>::max());
213  extentInf.Fill(itk::NumericTraits<double>::max());
214  extentSup.Fill(itk::NumericTraits<double>::NonpositiveMin());
215 
216  // Compute output spacing, size, and origin
217  for (unsigned int imageIndex = 0; imageIndex < this->GetNumberOfInputs(); imageIndex++)
218  {
219  // Read image (cast is required since filter can have multiple input images
220  // types)
221  InputImageType* currentImage = static_cast<InputImageType*>(Superclass::ProcessObject::GetInput(imageIndex));
222 
223  // Update mosaic spacing (keep the nearest of 0)
224  for (unsigned int dim = 0; dim < OutputImageType::ImageDimension; ++dim)
225  {
226  if (vcl_abs(currentImage->GetSignedSpacing()[dim]) < vcl_abs(m_OutputSpacing[dim]))
227  {
228  m_OutputSpacing[dim] = currentImage->GetSignedSpacing()[dim];
229  }
230  }
231 
232  // Update mosaic image extent
233  InputImagePointType currentInputImageExtentInf, currentInputImageExtentSup;
234  ImageToExtent(currentImage, currentInputImageExtentInf, currentInputImageExtentSup);
235  for (unsigned int dim = 0; dim < OutputImageType::ImageDimension; ++dim)
236  {
237  extentInf[dim] = vnl_math_min(currentInputImageExtentInf[dim], extentInf[dim]);
238  extentSup[dim] = vnl_math_max(currentInputImageExtentSup[dim], extentSup[dim]);
239  }
240  }
241 
242  // Set final size
243  m_OutputSize[0] = std::round((extentSup[0] - extentInf[0]) / vcl_abs(m_OutputSpacing[0]));
244  m_OutputSize[1] = std::round((extentSup[1] - extentInf[1]) / vcl_abs(m_OutputSpacing[1]));
245 
246  // Set final origin (Coordinate of the upper left pixel center)
247  m_OutputOrigin[0] = extentInf[0];
248  m_OutputOrigin[1] = extentSup[1];
249 }
250 
256 template <class TInputImage, class TOutputImage, class TInternalValueType>
258 {
259  itkDebugMacro(<< "Generate output information");
260  Superclass::GenerateOutputInformation();
262 
263  // check interpolator and put a default interpolator if empty
264  if (!m_Interpolator)
265  {
266  itkDebugMacro(<< "No interpolator specified. Using default");
267  typename DefaultInterpolatorType::Pointer interp = DefaultInterpolatorType::New();
268  m_Interpolator = static_cast<InterpolatorType*>(interp.GetPointer());
269  }
270 
271  // buffer padding radius
272  interpolatorRadius = StreamingTraitsType::CalculateNeededRadiusForInterpolator(m_Interpolator);
273 
274  // If AutomaticOutputParametersComputation mode is TRUE
275  if (m_AutomaticOutputParametersComputation)
276  {
277  ComputeOutputParameters(); // compute output size, spacing, origin
278  }
279 
280  // Update/Check following things:
281  // -number of component per pixel
282  // -projection
283  nbOfBands = 0;
284  std::string projectionRef = "";
285  for (unsigned int imageIndex = 0; imageIndex < this->GetNumberOfInputs(); imageIndex++)
286  {
287  itkDebugMacro(<< "Input image #" << imageIndex);
288 
289  // Read image (cast is required since filter can have multiple input images
290  // types)
291  InputImageType* currentImage = static_cast<InputImageType*>(Superclass::ProcessObject::GetInput(imageIndex));
292 
293  itkDebugMacro(<< "\tSize : " << currentImage->GetLargestPossibleRegion().GetSize());
294  itkDebugMacro(<< "\tSpacing: " << currentImage->GetSignedSpacing());
295  itkDebugMacro(<< "\tOrigin : " << currentImage->GetOrigin());
296 
297  // Update number of bands (keep the max)
298  nbOfBands = vnl_math_max(nbOfBands, currentImage->GetNumberOfComponentsPerPixel());
299 
300  // Check projection
301  itk::MetaDataDictionary metaData = currentImage->GetMetaDataDictionary();
302  std::string currentProjectionRef;
303  if (metaData.HasKey(otb::MetaDataKey::ProjectionRefKey))
304  {
305  itk::ExposeMetaData<std::string>(metaData, static_cast<std::string>(otb::MetaDataKey::ProjectionRefKey), currentProjectionRef);
306  }
307 
308  if (projectionRef.size() != 0)
309  {
310  if (currentProjectionRef.size() != 0)
311  {
312  if (currentProjectionRef.compare(projectionRef) != 0)
313  {
314  itkWarningMacro(<< "Input images may have not the same projection");
315  }
316  }
317  }
318  else
319  projectionRef = currentProjectionRef;
320  }
321  itk::MetaDataDictionary mosaicMetaData;
322  itk::EncapsulateMetaData<std::string>(mosaicMetaData, static_cast<std::string>(otb::MetaDataKey::ProjectionRefKey), projectionRef);
323 
324  // check no data pixels
325  if (m_NoDataInputPixel.GetSize() != nbOfBands)
326  {
327  if (m_NoDataInputPixel.GetSize() != 0)
328  itkWarningMacro(<< "Specified NoDataInputPixel has not " << nbOfBands << " components. Using default (zeros)");
329 
330  m_NoDataInputPixel.SetSize(nbOfBands);
331  m_NoDataInputPixel.Fill(itk::NumericTraits<InputImageInternalPixelType>::Zero);
332  }
333  if (m_NoDataOutputPixel.GetSize() == 0)
334  {
335  itkDebugMacro(<< "NoDataOutputPixel not set. Using zeros");
336  m_NoDataOutputPixel.SetSize(nbOfBands);
337  m_NoDataOutputPixel.Fill(itk::NumericTraits<InputImageInternalPixelType>::Zero);
338  }
339 
340 
341  // Write no data flags
342  std::vector<bool> noDataValueAvailable;
343  std::vector<double> noDataValues1;
344  for (unsigned int band = 0; band < nbOfBands; band++)
345  {
346  noDataValueAvailable.push_back(true);
347  noDataValues1.push_back(static_cast<double>(m_NoDataOutputPixel[band]));
348  }
349  otb::WriteNoDataFlags(noDataValueAvailable, noDataValues1, this->GetOutput()->GetImageMetadata());
350 
351  // Get min & max values from output pixel type
352  minOutputPixelValue = static_cast<InternalValueType>(itk::NumericTraits<OutputImageInternalPixelType>::NonpositiveMin());
353  maxOutputPixelValue = static_cast<InternalValueType>(itk::NumericTraits<OutputImageInternalPixelType>::max());
354 
355  // Output parameters
356  OutputImageIndexType outputRegionStart;
357  outputRegionStart.Fill(0);
358  OutputImageRegionType outputRegion(outputRegionStart, m_OutputSize);
359  OutputImageType* outputPtr = this->GetOutput();
360  outputPtr->SetOrigin(m_OutputOrigin);
361  outputPtr->SetSignedSpacing(m_OutputSpacing);
362  outputPtr->SetNumberOfComponentsPerPixel(nbOfBands);
363  outputPtr->SetLargestPossibleRegion(outputRegion);
364 
365  itkDebugMacro(<< "Output mosaic parameters:"
366  << "\n\tBands : " << nbOfBands << "\n\tOrigin : " << m_OutputOrigin << "\n\tSize : " << m_OutputSize << "\n\tSpacing: " << m_OutputSpacing);
367 
368  // Check shift-scale matrices
369  if (m_ShiftScaleInputImages)
370  {
371  CheckShiftScaleMatrices();
372  }
373 }
374 
375 /*
376  * Check if the pixel is empty
377  */
378 template <class TInputImage, class TOutputImage, class TInternalValueType>
380 {
381  bool isDataInCurrentInputPixel = false;
382 
383  for (unsigned int band = 0; band < nbOfBands; band++)
384  {
385  isDataInCurrentInputPixel = isDataInCurrentInputPixel || (pixelValue[band] != m_NoDataInputPixel[band]);
386  }
387  return isDataInCurrentInputPixel;
388 }
389 
390 /*
391  * Clipping
392  */
393 template <class TInputImage, class TOutputImage, class TInternalValueType>
395 {
396  if (pixelValue < minOutputPixelValue)
397  pixelValue = minOutputPixelValue;
398  if (pixelValue > maxOutputPixelValue)
399  pixelValue = maxOutputPixelValue;
400 }
401 
407 template <class TInputImage, class TOutputImage, class TInternalValueType>
409 {
410  if (!m_Interpolator)
411  {
412  itkExceptionMacro(<< "Interpolator not set");
413  }
414 }
416 
420 template <class TInputImage, class TOutputImage, class TInternalValueType>
422 {
423  // Disconnect input image from interpolator
424  m_Interpolator->SetInputImage(NULL);
425 }
426 
427 template <class TInputImage, class TOutputImage, class TInternalValueType>
429  typename std::vector<InputImageType*>& image, typename std::vector<InterpolatorPointerType>& interpolator)
430 {
431 
432  // Get number of used input images
433  const unsigned int n = GetNumberOfUsedInputImages();
434 
435  interpolator.reserve(n);
436  image.reserve(n);
437 
438  // Loop on input images
439  for (unsigned int i = 0; i < n; i++)
440  {
441  // Input image i
442  image.push_back(const_cast<InputImageType*>(this->GetInput(usedInputIndices.at(i))));
443 
444  // Interpolator i
445  interpolator.push_back(static_cast<InterpolatorType*>((m_Interpolator->CreateAnother()).GetPointer()));
446  interpolator[i]->SetInputImage(image[i]);
447  }
448 }
449 
450 } // end namespace otb
451 
452 #endif
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImageRegionType
InputImageType::RegionType InputImageRegionType
Definition: otbStreamingMosaicFilterBase.h:69
otb::StreamingMosaicFilterBase::IsPixelNotEmpty
virtual bool IsPixelNotEmpty(InputImagePixelType &inputPixel)
Definition: otbStreamingMosaicFilterBase.hxx:379
otb::WriteNoDataFlags
void OTBMetadata_EXPORT WriteNoDataFlags(const std::vector< bool > &flags, const std::vector< double > &values, ImageMetadata &imd)
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImagePixelType
InputImageType::PixelType InputImagePixelType
Definition: otbStreamingMosaicFilterBase.h:70
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::OutputImagePointType
OutputImageType::PointType OutputImagePointType
Definition: otbStreamingMosaicFilterBase.h:82
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImagePointType
InputImageType::PointType InputImagePointType
Definition: otbStreamingMosaicFilterBase.h:71
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImageSizeType
InputImageType::SizeType InputImageSizeType
Definition: otbStreamingMosaicFilterBase.h:73
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImageIndexType
InputImageType::IndexType InputImageIndexType
Definition: otbStreamingMosaicFilterBase.h:72
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InputImageType
TInputImage InputImageType
Definition: otbStreamingMosaicFilterBase.h:64
otbStreamingMosaicFilterBase.h
otb::StreamingMosaicFilterBase::GenerateOutputInformation
void GenerateOutputInformation(void) override
Definition: otbStreamingMosaicFilterBase.hxx:257
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::OutputImageType
TInputImage OutputImageType
Definition: otbStreamingMosaicFilterBase.h:78
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::OutputImageIndexType
OutputImageType::IndexType OutputImageIndexType
Definition: otbStreamingMosaicFilterBase.h:81
otb::StreamingMosaicFilterBase::NormalizePixelValue
virtual void NormalizePixelValue(InternalValueType &pixelValue)
Definition: otbStreamingMosaicFilterBase.hxx:394
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbStreamingMosaicFilterBase.h:80
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InterpolatorType
itk::InterpolateImageFunction< InputImageType, InternalValueType > InterpolatorType
Definition: otbStreamingMosaicFilterBase.h:91
otb::StreamingMosaicFilterBase::PrepareImageAccessors
virtual void PrepareImageAccessors(typename std::vector< InputImageType * > &image, typename std::vector< InterpolatorPointerType > &interpolator)
Definition: otbStreamingMosaicFilterBase.hxx:428
otb::StreamingMosaicFilterBase::ComputeRequestedRegionOfInputImage
virtual void ComputeRequestedRegionOfInputImage(unsigned int inputImageIndex)
Definition: otbStreamingMosaicFilterBase.hxx:122
otb::StreamingMosaicFilterBase::AfterThreadedGenerateData
void AfterThreadedGenerateData() override
Definition: otbStreamingMosaicFilterBase.hxx:421
otb::StreamingMosaicFilterBase::GenerateInputRequestedRegion
void GenerateInputRequestedRegion(void) override
Definition: otbStreamingMosaicFilterBase.hxx:154
otb::StreamingMosaicFilterBase::ComputeOutputParameters
virtual void ComputeOutputParameters()
Definition: otbStreamingMosaicFilterBase.hxx:206
otb::StreamingMosaicFilterBase::CheckShiftScaleMatrices
virtual void CheckShiftScaleMatrices()
Definition: otbStreamingMosaicFilterBase.hxx:167
otb::StreamingMosaicFilterBase< TInputImage, TInputImage, double >::InternalValueType
double InternalValueType
Definition: otbStreamingMosaicFilterBase.h:89
otb::MetaDataKey::ProjectionRefKey
OTBMetadata_EXPORT char const * ProjectionRefKey
otb::StreamingMosaicFilterBase::BeforeThreadedGenerateData
void BeforeThreadedGenerateData() override
Definition: otbStreamingMosaicFilterBase.hxx:408
otb::StreamingMosaicFilterBase::OutputRegionToInputRegion
virtual bool OutputRegionToInputRegion(const OutputImageRegionType &mosaicRegion, InputImageRegionType &inputRegion, InputImageType *&inputImage)
Definition: otbStreamingMosaicFilterBase.hxx:80
otb::StreamingMosaicFilterBase::ImageToExtent
virtual void ImageToExtent(InputImageType *image, InputImagePointType &extentInf, InputImagePointType &extentSup)
Definition: otbStreamingMosaicFilterBase.hxx:49
otb::StreamingMosaicFilterBase::StreamingMosaicFilterBase
StreamingMosaicFilterBase()
Definition: otbStreamingMosaicFilterBase.hxx:31