OTB  9.0.0
Orfeo Toolbox
otbOverlapSaveConvolutionImageFilter.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 otbOverlapSaveConvolutionImageFilter_hxx
22 #define otbOverlapSaveConvolutionImageFilter_hxx
23 
24 #include "itkConfigure.h"
25 
27 
28 #include "itkConstNeighborhoodIterator.h"
29 #include "itkImageRegionIteratorWithIndex.h"
30 #include "itkNeighborhoodAlgorithm.h"
31 #include "itkOffset.h"
32 #include "itkProgressReporter.h"
33 
34 // debug
35 #include "itkImageRegionIterator.h"
36 #include "otbMath.h"
37 
38 #ifdef ITK_USE_FFTWD
39 #include "itkFFTWCommon.h"
40 #endif
41 
42 namespace otb
43 {
44 
45 template <class TInputImage, class TOutputImage, class TBoundaryCondition>
47 {
48  m_Radius.Fill(1);
49  m_Filter.SetSize(3 * 3);
50  m_Filter.Fill(1);
51  m_NormalizeFilter = false;
52 }
53 
54 template <class TInputImage, class TOutputImage, class TBoundaryCondition>
56 {
57 #if defined ITK_USE_FFTWD
58  // call the superclass' implementation of this method
59  Superclass::GenerateInputRequestedRegion();
60 
61  // get pointers to the input and output
62  typename Superclass::InputImagePointer inputPtr = const_cast<TInputImage*>(this->GetInput());
63  typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
64 
65  if (!inputPtr || !outputPtr)
66  {
67  return;
68  }
69 
70  // get a copy of the input requested region (should equal the output
71  // requested region)
72  typename TInputImage::RegionType inputRequestedRegion;
73  inputRequestedRegion = inputPtr->GetRequestedRegion();
74 
75  // Pad by filter radius
76  inputRequestedRegion.PadByRadius(m_Radius);
77 
78  // crop the input requested region at the input's largest possible region
79  if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
80  {
81  inputPtr->SetRequestedRegion(inputRequestedRegion);
82  return;
83  }
84  else
85  {
86  // Couldn't crop the region (requested region is outside the largest
87  // possible region). Throw an exception.
88 
89  // store what we tried to request (prior to trying to crop)
90  inputPtr->SetRequestedRegion(inputRequestedRegion);
91 
92  // build an exception
93  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
94  e.SetLocation(ITK_LOCATION);
95  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
96  e.SetDataObject(inputPtr);
97  throw e;
98  }
99 #else
100  itkGenericExceptionMacro(<< "The OverlapSaveConvolutionImageFilter can not operate without the FFTW library (double implementation). Please build ITK with "
101  "USE_FFTD set to ON, and rebuild OTB.");
102 #endif
103 }
104 
105 template <class TInputImage, class TOutputImage, class TBoundaryCondition>
107  /* TODO commented out since multi-threading is not supported for the moment
108  * ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) */
109  ::GenerateData()
110 {
111 #if defined ITK_USE_FFTWD
112  // Input/Output pointers
113  typename OutputImageType::Pointer output = this->GetOutput();
114  typename InputImageType::ConstPointer input = this->GetInput();
115 
116  /* TODO: This is a patch to switch from GenerateData() to ThreadedGenerateData(). Remove these two lines
117  once multi-threading problem is solved */
118  this->AllocateOutputs();
119  OutputImageRegionType outputRegionForThread = output->GetRequestedRegion();
120 
121  // Size of the filter
122  typename InputImageType::SizeType sizeOfFilter;
123  sizeOfFilter[0] = 2 * m_Radius[0] + 1;
124  sizeOfFilter[1] = 2 * m_Radius[1] + 1;
125 
126  // Filter normalization
127  InputRealType norm;
128 
129  // Compute the input region for the given thread
130  OutputImageRegionType inputRegionForThread = outputRegionForThread;
131  inputRegionForThread.PadByRadius(m_Radius);
132 
133  // Compute the piece region for the input thread. Piece region is different
134  // from input region on boundaries
135  typename InputImageType::RegionType pieceRegion = inputRegionForThread;
136  typename InputImageType::SizeType pieceSize = pieceRegion.GetSize();
137  typename InputImageType::IndexType pieceIndex = pieceRegion.GetIndex();
138 
139  // Compute the size of the FFT and the size of the piece
140  unsigned int pieceNbOfPixel = pieceRegion.GetNumberOfPixels();
141  unsigned int sizeFFT = (pieceSize[0] / 2 + 1) * pieceSize[1];
142 
143  // Achieve the computation of the inputRegionForThread
144  inputRegionForThread.Crop(input->GetLargestPossibleRegion());
145  typename InputImageType::IndexType inputIndex = inputRegionForThread.GetIndex();
146  typename InputImageType::SizeType inputSize = inputRegionForThread.GetSize();
147 
148  // Iterator of input image
149  itk::ConstNeighborhoodIterator<InputImageType, BoundaryConditionType> inputIt(m_Radius, input, inputRegionForThread);
150  inputIt.GoToBegin();
151 
152  // Iterator of output image
153  itk::ImageRegionIteratorWithIndex<OutputImageType> outputIt;
154  outputIt = itk::ImageRegionIteratorWithIndex<OutputImageType>(output, outputRegionForThread);
155 
156  // variables for loops
157  unsigned int i, j, k, l;
158 
159  // ITK proxy to the fftw library
160  typedef typename itk::fftw::Proxy<double> FFTWProxyType;
161 
162  // memory allocation
163  InputPixelType* resampledFilterPiece;
164  resampledFilterPiece = static_cast<FFTWProxyType::PixelType*>(fftw_malloc(pieceNbOfPixel * sizeof(InputPixelType)));
165 
166  FFTWProxyType::ComplexType* filterPieceFFT;
167  filterPieceFFT = static_cast<FFTWProxyType::ComplexType*>(fftw_malloc(sizeFFT * sizeof(FFTWProxyType::ComplexType)));
168 
169  InputPixelType* inputPiece;
170  inputPiece = static_cast<FFTWProxyType::PixelType*>(fftw_malloc(pieceNbOfPixel * sizeof(InputPixelType)));
171 
172  FFTWProxyType::ComplexType* inputPieceFFT;
173  inputPieceFFT = static_cast<FFTWProxyType::ComplexType*>(fftw_malloc(sizeFFT * sizeof(FFTWProxyType::ComplexType)));
174 
175  // Image piece FFT
176  FFTWProxyType::PlanType inputPlan = FFTWProxyType::Plan_dft_r2c_2d(pieceSize[1], pieceSize[0], inputPiece, inputPieceFFT, FFTW_MEASURE);
177 
178  // left zero padding
179  unsigned int leftskip = static_cast<unsigned int>(std::max((typename InputImageType::IndexValueType)0, inputIndex[0] - pieceIndex[0]));
180  unsigned int topskip = pieceSize[0] * static_cast<unsigned int>(std::max((typename InputImageType::IndexValueType)0, inputIndex[1] - pieceIndex[1]));
181 
182  // zero filling
183  memset(inputPiece, 0, pieceNbOfPixel * sizeof(InputPixelType));
184 
185  // Filling the buffer with image values
186  for (l = 0; l < inputSize[1]; ++l)
187  {
188  for (k = 0; k < inputSize[0]; ++k)
189  {
190  inputPiece[topskip + pieceSize[0] * l + k + leftskip] = inputIt.GetCenterPixel();
191  ++inputIt;
192  }
193  }
194 
195  FFTWProxyType::Execute(inputPlan);
196 
197  // Resampled filter FFT
198  FFTWProxyType::PlanType filterPlan = FFTWProxyType::Plan_dft_r2c_2d(pieceSize[1], pieceSize[0], resampledFilterPiece, filterPieceFFT, FFTW_MEASURE);
199 
200  // zero filling
201  memset(resampledFilterPiece, 0, pieceNbOfPixel * sizeof(InputPixelType));
202 
203  k = 0;
204  // Filling the buffer with filter values
205  for (j = 0; j < sizeOfFilter[1]; ++j)
206  {
207  for (i = 0; i < sizeOfFilter[0]; ++i)
208  {
209  resampledFilterPiece[i + j * pieceSize[0]] = m_Filter.GetElement(k); // Copy values
210  ++k;
211  }
212  }
213 
214  FFTWProxyType::Execute(filterPlan);
215 
216  // memory allocation for inverse FFT
217  FFTWProxyType::ComplexType* multipliedFFTarray;
218  multipliedFFTarray = static_cast<FFTWProxyType::ComplexType*>(fftw_malloc(sizeFFT * sizeof(FFTWProxyType::ComplexType)));
219 
220  FFTWProxyType::PixelType* inverseFFTpiece;
221  inverseFFTpiece = static_cast<FFTWProxyType::PixelType*>(fftw_malloc(pieceNbOfPixel * sizeof(FFTWProxyType::PixelType)));
222 
223  // Inverse FFT of the product of FFT (actually do filtering here)
224  FFTWProxyType::PlanType outputPlan = FFTWProxyType::Plan_dft_c2r_2d(pieceSize[1], pieceSize[0], multipliedFFTarray, inverseFFTpiece, FFTW_MEASURE);
225 
226  // Filling the buffer with complex product values
227  for (k = 0; k < sizeFFT; ++k)
228  {
229  // complex mutiplication
230  multipliedFFTarray[k][0] = inputPieceFFT[k][0] * filterPieceFFT[k][0] - inputPieceFFT[k][1] * filterPieceFFT[k][1];
231  multipliedFFTarray[k][1] = inputPieceFFT[k][0] * filterPieceFFT[k][1] + inputPieceFFT[k][1] * filterPieceFFT[k][0];
232  }
233 
234  FFTWProxyType::Execute(outputPlan);
235 
236  // Computing the filter normalization
237 
238  if (m_NormalizeFilter)
239  {
240  norm = itk::NumericTraits<InputRealType>::Zero;
241  for (i = 0; i < sizeOfFilter[0] * sizeOfFilter[1]; ++i)
242  {
243  norm += static_cast<InputRealType>(m_Filter(i));
244  }
245  if (norm == 0.0)
246  {
247  norm = 1.0;
248  }
249  else
250  {
251  norm = 1 / norm;
252  }
253  }
254  else
255  {
256  norm = 1.0;
257  }
258 
259  // Fill the output image
260  outputIt.GoToBegin();
261  while (!outputIt.IsAtEnd())
262  {
263  typename InputImageType::IndexType index = outputIt.GetIndex();
264  unsigned int linearIndex = (index[1] + sizeOfFilter[1] - 1 - outputRegionForThread.GetIndex()[1]) * pieceSize[0] - 1 + index[0] + sizeOfFilter[0] -
265  outputRegionForThread.GetIndex()[0];
266  outputIt.Set(static_cast<OutputPixelType>((inverseFFTpiece[linearIndex] / pieceNbOfPixel) * static_cast<double>(norm)));
267  ++outputIt;
268  }
269 
270  // destroy the FFT plans
271  FFTWProxyType::DestroyPlan(inputPlan);
272  FFTWProxyType::DestroyPlan(filterPlan);
273  FFTWProxyType::DestroyPlan(outputPlan);
274 
275  // frees memory
276  fftw_free(resampledFilterPiece);
277  fftw_free(inputPiece);
278  fftw_free(filterPieceFFT);
279  fftw_free(inputPieceFFT);
280  fftw_free(multipliedFFTarray);
281  fftw_free(inverseFFTpiece);
282 #else
283  itkGenericExceptionMacro(<< "The OverlapSaveConvolutionImageFilter can not operate without the FFTW library (double implementation). Please build ITK with "
284  "USE_FFTD set to ON, and rebuild OTB.");
285 #endif
286 }
287 
289 template <class TInputImage, class TOutput, class TBoundaryCondition>
291 {
292  Superclass::PrintSelf(os, indent);
293  os << indent << "Radius: " << m_Radius << std::endl;
294  os << indent << "Normalize filter: " << m_NormalizeFilter << std::endl;
295 }
296 } // end namespace otb
298 
299 #endif
otb::OverlapSaveConvolutionImageFilter::OverlapSaveConvolutionImageFilter
OverlapSaveConvolutionImageFilter()
Definition: otbOverlapSaveConvolutionImageFilter.hxx:46
otb::OverlapSaveConvolutionImageFilter
Definition: otbOverlapSaveConvolutionImageFilter.h:62
otbMath.h
otb::OverlapSaveConvolutionImageFilter::InputPixelType
InputImageType::PixelType InputPixelType
Definition: otbOverlapSaveConvolutionImageFilter.h:84
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::OverlapSaveConvolutionImageFilter::GenerateInputRequestedRegion
void GenerateInputRequestedRegion() override
Definition: otbOverlapSaveConvolutionImageFilter.hxx:55
otb::OverlapSaveConvolutionImageFilter::InputRealType
itk::NumericTraits< InputPixelType >::RealType InputRealType
Definition: otbOverlapSaveConvolutionImageFilter.h:89
otb::OverlapSaveConvolutionImageFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbOverlapSaveConvolutionImageFilter.hxx:290
otb::OverlapSaveConvolutionImageFilter::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbOverlapSaveConvolutionImageFilter.h:91
otb::OverlapSaveConvolutionImageFilter::OutputPixelType
OutputImageType::PixelType OutputPixelType
Definition: otbOverlapSaveConvolutionImageFilter.h:88
otbOverlapSaveConvolutionImageFilter.h