OTB  10.0.0
Orfeo Toolbox
otbPixelWiseBlockMatchingImageFilter.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 otbPixelWiseBlockMatchingImageFilter_hxx
22 #define otbPixelWiseBlockMatchingImageFilter_hxx
23 
25 #include "itkProgressReporter.h"
26 #include "itkConstantBoundaryCondition.h"
27 
28 namespace otb
29 {
30 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
31 PixelWiseBlockMatchingImageFilter<TInputImage, TOutputMetricImage, TOutputDisparityImage, TMaskImage,
32  TBlockMatchingFunctor>::PixelWiseBlockMatchingImageFilter()
33 {
34  this->DynamicMultiThreadingOff();
35  // Set the number of inputs
36  this->SetNumberOfRequiredInputs(6);
37  this->SetNumberOfRequiredInputs(2);
38 
39  // Set the outputs
40  this->SetNumberOfRequiredOutputs(3);
41  this->SetNthOutput(0, TOutputMetricImage::New());
42  this->SetNthOutput(1, TOutputDisparityImage::New());
43  this->SetNthOutput(2, TOutputDisparityImage::New());
44 
45  // Default parameters
46  m_Radius.Fill(2);
47 
48  // Minimize by default
49  m_Minimize = true;
50 
51  // Default disparity range
52  m_MinimumHorizontalDisparity = -10;
53  m_MaximumHorizontalDisparity = 10;
54  m_MinimumVerticalDisparity = 0;
55  m_MaximumVerticalDisparity = 0;
56 
57  // Default initial disparity
58  m_InitHorizontalDisparity = 0;
59  m_InitVerticalDisparity = 0;
60 
61  // Default exploration radius : 0 (not used)
62  m_ExplorationRadius.Fill(0);
63 
64  // Default step
65  m_Step = 1;
66 
67  // Default grid index
68  m_GridIndex[0] = 0;
69  m_GridIndex[1] = 0;
70 }
71 
72 
73 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
74 PixelWiseBlockMatchingImageFilter<TInputImage, TOutputMetricImage, TOutputDisparityImage, TMaskImage,
75  TBlockMatchingFunctor>::~PixelWiseBlockMatchingImageFilter()
76 {
77 }
78 
79 
80 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
82  const TInputImage* image)
83 {
84  // Process object is not const-correct so the const casting is required.
85  this->SetNthInput(0, const_cast<TInputImage*>(image));
86 }
87 
88 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
90  const TInputImage* image)
91 {
92  // Process object is not const-correct so the const casting is required.
93  this->SetNthInput(1, const_cast<TInputImage*>(image));
94 }
95 
96 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
98  const TMaskImage* image)
99 {
100  // Process object is not const-correct so the const casting is required.
101  this->SetNthInput(2, const_cast<TMaskImage*>(image));
102 }
103 
104 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
106  const TMaskImage* image)
107 {
108  // Process object is not const-correct so the const casting is required.
109  this->SetNthInput(3, const_cast<TMaskImage*>(image));
110 }
111 
112 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
113 const TInputImage*
115 {
116  if (this->GetNumberOfInputs() < 1)
117  {
118  return nullptr;
119  }
120  return static_cast<const TInputImage*>(this->itk::ProcessObject::GetInput(0));
121 }
122 
123 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
124 const TInputImage*
126 {
127  if (this->GetNumberOfInputs() < 2)
128  {
129  return nullptr;
130  }
131  return static_cast<const TInputImage*>(this->itk::ProcessObject::GetInput(1));
132 }
133 
134 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
135 const TMaskImage*
137 {
138  if (this->GetNumberOfInputs() < 3)
139  {
140  return nullptr;
141  }
142  return static_cast<const TMaskImage*>(this->itk::ProcessObject::GetInput(2));
143 }
144 
145 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
146 const TMaskImage*
148 {
149  if (this->GetNumberOfInputs() < 4)
150  {
151  return nullptr;
152  }
153  return static_cast<const TMaskImage*>(this->itk::ProcessObject::GetInput(3));
154 }
155 
156 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
157 const TOutputMetricImage*
159 {
160  if (this->GetNumberOfOutputs() < 1)
161  {
162  return nullptr;
163  }
164  return static_cast<const TOutputMetricImage*>(this->itk::ProcessObject::GetOutput(0));
165 }
166 
167 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
168 TOutputMetricImage*
170 {
171  if (this->GetNumberOfOutputs() < 1)
172  {
173  return nullptr;
174  }
175  return static_cast<TOutputMetricImage*>(this->itk::ProcessObject::GetOutput(0));
176 }
177 
178 
179 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
180 const TOutputDisparityImage* PixelWiseBlockMatchingImageFilter<TInputImage, TOutputMetricImage, TOutputDisparityImage, TMaskImage,
181  TBlockMatchingFunctor>::GetHorizontalDisparityOutput() const
182 {
183  if (this->GetNumberOfOutputs() < 2)
184  {
185  return nullptr;
186  }
187  return static_cast<const TOutputDisparityImage*>(this->itk::ProcessObject::GetOutput(1));
188 }
189 
190 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
191 TOutputDisparityImage*
193 {
194  if (this->GetNumberOfOutputs() < 2)
195  {
196  return nullptr;
197  }
198  return static_cast<TOutputDisparityImage*>(this->itk::ProcessObject::GetOutput(1));
199 }
200 
201 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
202 const TOutputDisparityImage*
204 {
205  if (this->GetNumberOfOutputs() < 3)
206  {
207  return nullptr;
208  }
209  return static_cast<const TOutputDisparityImage*>(this->itk::ProcessObject::GetOutput(2));
210 }
211 
212 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
213 TOutputDisparityImage*
215 {
216  if (this->GetNumberOfOutputs() < 3)
217  {
218  return nullptr;
219  }
220  return static_cast<TOutputDisparityImage*>(this->itk::ProcessObject::GetOutput(2));
221 }
222 
223 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
225  const TOutputDisparityImage* hfield)
226 {
227  // Process object is not const-correct so the const casting is required.
228  this->SetNthInput(4, const_cast<TOutputDisparityImage*>(hfield));
229 }
230 
231 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
233  const TOutputDisparityImage* vfield)
234 {
235  // Process object is not const-correct so the const casting is required.
236  this->SetNthInput(5, const_cast<TOutputDisparityImage*>(vfield));
237 }
238 
239 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
240 const TOutputDisparityImage* PixelWiseBlockMatchingImageFilter<TInputImage, TOutputMetricImage, TOutputDisparityImage, TMaskImage,
241  TBlockMatchingFunctor>::GetHorizontalDisparityInput() const
242 {
243  if (this->GetNumberOfInputs() < 5)
244  {
245  return nullptr;
246  }
247  return static_cast<const TOutputDisparityImage*>(this->itk::ProcessObject::GetInput(4));
248 }
249 
250 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
251 const TOutputDisparityImage*
253 {
254  if (this->GetNumberOfInputs() < 6)
255  {
256  return nullptr;
257  }
258  return static_cast<const TOutputDisparityImage*>(this->itk::ProcessObject::GetInput(5));
259 }
260 
261 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
263 {
264  // Call superclass implementation
265  Superclass::GenerateOutputInformation();
266 
267  // Sanity check
268  if (this->m_Step == 0)
269  this->m_Step = 1;
270  this->m_GridIndex[0] = this->m_GridIndex[0] % this->m_Step;
271  this->m_GridIndex[1] = this->m_GridIndex[1] % this->m_Step;
272 
273  // Modify output size and index depending on the step
274  const TInputImage* inLeftPtr = this->GetLeftInput();
275 
276  RegionType outputLargest = this->ConvertFullToSubsampledRegion(inLeftPtr->GetLargestPossibleRegion(), this->m_Step, this->m_GridIndex);
277 
278  TOutputMetricImage* outMetricPtr = const_cast<TOutputMetricImage*>(this->GetMetricOutput());
279  TOutputDisparityImage* outHDispPtr = const_cast<TOutputDisparityImage*>(this->GetHorizontalDisparityOutput());
280  TOutputDisparityImage* outVDispPtr = const_cast<TOutputDisparityImage*>(this->GetVerticalDisparityOutput());
281 
282  outMetricPtr->SetLargestPossibleRegion(outputLargest);
283  outHDispPtr->SetLargestPossibleRegion(outputLargest);
284  outVDispPtr->SetLargestPossibleRegion(outputLargest);
285 
286  // Adapt spacing
287  SpacingType outSpacing = inLeftPtr->GetSignedSpacing();
288  outSpacing[0] *= static_cast<double>(this->m_Step);
289  outSpacing[1] *= static_cast<double>(this->m_Step);
290 
291  outMetricPtr->SetSignedSpacing(outSpacing);
292  outHDispPtr->SetSignedSpacing(outSpacing);
293  outVDispPtr->SetSignedSpacing(outSpacing);
294 
295  // Adapt origin
296  PointType outOrigin = inLeftPtr->GetOrigin();
297  SpacingType inSpacing = inLeftPtr->GetSignedSpacing();
298  outOrigin[0] += inSpacing[0] * static_cast<double>(this->m_GridIndex[0]);
299  outOrigin[1] += inSpacing[1] * static_cast<double>(this->m_GridIndex[1]);
300 
301  outMetricPtr->SetOrigin(outOrigin);
302  outHDispPtr->SetOrigin(outOrigin);
303  outVDispPtr->SetOrigin(outOrigin);
304 }
305 
306 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
307 void PixelWiseBlockMatchingImageFilter<TInputImage, TOutputMetricImage, TOutputDisparityImage, TMaskImage,
308  TBlockMatchingFunctor>::GenerateInputRequestedRegion()
309 {
310  // Call superclass implementation
311  Superclass::GenerateInputRequestedRegion();
312 
313  // Retrieve input pointers
314  TInputImage* inLeftPtr = const_cast<TInputImage*>(this->GetLeftInput());
315  TInputImage* inRightPtr = const_cast<TInputImage*>(this->GetRightInput());
316  TMaskImage* inLeftMaskPtr = const_cast<TMaskImage*>(this->GetLeftMaskInput());
317  TMaskImage* inRightMaskPtr = const_cast<TMaskImage*>(this->GetRightMaskInput());
318  TOutputDisparityImage* inHDispPtr = const_cast<TOutputDisparityImage*>(this->GetHorizontalDisparityInput());
319  TOutputDisparityImage* inVDispPtr = const_cast<TOutputDisparityImage*>(this->GetVerticalDisparityInput());
320 
321  TOutputMetricImage* outMetricPtr = this->GetMetricOutput();
322  TOutputDisparityImage* outHDispPtr = this->GetHorizontalDisparityOutput();
323  TOutputDisparityImage* outVDispPtr = this->GetVerticalDisparityOutput();
324 
325  // Check pointers before using them
326  if (!inLeftPtr || !inRightPtr || !outMetricPtr || !outHDispPtr || !outVDispPtr)
327  {
328  return;
329  }
330 
331  // Now, we impose that both inputs have the same size
332  if (inLeftPtr->GetLargestPossibleRegion() != inRightPtr->GetLargestPossibleRegion())
333  {
334  itkExceptionMacro(<< "Left and right images do not have the same size ! Left largest region: " << inLeftPtr->GetLargestPossibleRegion()
335  << ", right largest region: " << inRightPtr->GetLargestPossibleRegion());
336  }
337 
338  // We also check that left mask image has same size if present
339  if (inLeftMaskPtr && inLeftPtr->GetLargestPossibleRegion() != inLeftMaskPtr->GetLargestPossibleRegion())
340  {
341  itkExceptionMacro(<< "Left and mask images do not have the same size ! Left largest region: " << inLeftPtr->GetLargestPossibleRegion()
342  << ", mask largest region: " << inLeftMaskPtr->GetLargestPossibleRegion());
343  }
344 
345  // We also check that right mask image has same size if present
346  if (inRightMaskPtr && inRightPtr->GetLargestPossibleRegion() != inRightMaskPtr->GetLargestPossibleRegion())
347  {
348  itkExceptionMacro(<< "Right and mask images do not have the same size ! Right largest region: " << inRightPtr->GetLargestPossibleRegion()
349  << ", mask largest region: " << inRightMaskPtr->GetLargestPossibleRegion());
350  }
351 
352  // We check that the input initial disparity maps have the same size if present
353  if (inHDispPtr && inLeftPtr->GetLargestPossibleRegion() != inHDispPtr->GetLargestPossibleRegion())
354  {
355  itkExceptionMacro(<< "Left image and initial horizontal disparity map do not have the same size ! Left largest region: "
356  << inLeftPtr->GetLargestPossibleRegion() << ", horizontal disparity largest region: " << inHDispPtr->GetLargestPossibleRegion());
357  }
358  if (inVDispPtr && inLeftPtr->GetLargestPossibleRegion() != inVDispPtr->GetLargestPossibleRegion())
359  {
360  itkExceptionMacro(<< "Left image and initial vertical disparity map do not have the same size ! Left largest region: "
361  << inLeftPtr->GetLargestPossibleRegion() << ", vertical disparity largest region: " << inVDispPtr->GetLargestPossibleRegion());
362  }
363 
364  // Sanity check
365  if (this->m_Step == 0)
366  this->m_Step = 1;
367  this->m_GridIndex[0] = this->m_GridIndex[0] % this->m_Step;
368  this->m_GridIndex[1] = this->m_GridIndex[1] % this->m_Step;
369 
370  // Retrieve requested region (TODO: check if we need to handle
371  // region for outHDispPtr)
372  RegionType inputLeftRegion = this->ConvertSubsampledToFullRegion(outMetricPtr->GetRequestedRegion(), this->m_Step, this->m_GridIndex);
373 
374  // Pad by the appropriate radius
375  inputLeftRegion.PadByRadius(m_Radius);
376 
377  // Now, we must find the corresponding region in moving image
378  IndexType rightRequestedRegionIndex = inputLeftRegion.GetIndex();
379  rightRequestedRegionIndex[0] += m_MinimumHorizontalDisparity;
380  rightRequestedRegionIndex[1] += m_MinimumVerticalDisparity;
381 
382  SizeType rightRequestedRegionSize = inputLeftRegion.GetSize();
383  rightRequestedRegionSize[0] += m_MaximumHorizontalDisparity - m_MinimumHorizontalDisparity;
384  rightRequestedRegionSize[1] += m_MaximumVerticalDisparity - m_MinimumVerticalDisparity;
385 
386  RegionType inputRightRegion;
387  inputRightRegion.SetIndex(rightRequestedRegionIndex);
388  inputRightRegion.SetSize(rightRequestedRegionSize);
389 
390  // crop the left region at the left's largest possible region
391  if (inputLeftRegion.Crop(inLeftPtr->GetLargestPossibleRegion()))
392  {
393  inLeftPtr->SetRequestedRegion(inputLeftRegion);
394  }
395  else
396  {
397  // Couldn't crop the region (requested region is outside the largest
398  // possible region). Throw an exception.
399  // store what we tried to request (prior to trying to crop)
400  inLeftPtr->SetRequestedRegion(inputLeftRegion);
401 
402  // build an exception
403  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
404  std::ostringstream msg;
405  msg << this->GetNameOfClass() << "::GenerateInputRequestedRegion()";
406  e.SetLocation(msg.str());
407  e.SetDescription("Requested region is (at least partially) outside the largest possible region of left image.");
408  e.SetDataObject(inLeftPtr);
409  throw e;
410  }
411 
412 
413  // crop the right region at the right's largest possible region
414  if (inputRightRegion.Crop(inRightPtr->GetLargestPossibleRegion()))
415  {
416  inRightPtr->SetRequestedRegion(inputRightRegion);
417  }
418  else
419  {
420  // Couldn't crop the region (requested region is outside the largest
421  // possible region). Throw an exception.
422  // store what we tried to request (prior to trying to crop)
423  inRightPtr->SetRequestedRegion(inputRightRegion);
424 
425  // build an exception
426  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
427  std::ostringstream msg;
428  msg << this->GetNameOfClass() << "::GenerateInputRequestedRegion()";
429  e.SetLocation(msg.str());
430  e.SetDescription("Requested region is (at least partially) outside the largest possible region of right image.");
431  e.SetDataObject(inRightPtr);
432  throw e;
433  }
434 
435  if (inLeftMaskPtr)
436  {
437  // no need to crop the mask region : left mask and left image have same largest possible region
438  inLeftMaskPtr->SetRequestedRegion(inputLeftRegion);
439  }
440 
441  if (inRightMaskPtr)
442  {
443  // no need to crop the mask region : right mask and right image have same largest possible region
444  inRightMaskPtr->SetRequestedRegion(inputRightRegion);
445  }
446 
447  if (inHDispPtr && inVDispPtr)
448  {
449  inHDispPtr->SetRequestedRegion(inputLeftRegion);
450  inVDispPtr->SetRequestedRegion(inputLeftRegion);
451  }
452 }
453 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
455 {
456  TOutputMetricImage* outMetricPtr = this->GetMetricOutput();
457  TOutputDisparityImage* outHDispPtr = this->GetHorizontalDisparityOutput();
458  TOutputDisparityImage* outVDispPtr = this->GetVerticalDisparityOutput();
459 
460  // Sanity check
461  if (this->m_Step == 0)
462  this->m_Step = 1;
463  this->m_GridIndex[0] = this->m_GridIndex[0] % this->m_Step;
464  this->m_GridIndex[1] = this->m_GridIndex[1] % this->m_Step;
465 
466  // Fill buffers with default values
467  outMetricPtr->FillBuffer(0.);
468  outHDispPtr->FillBuffer(static_cast<DisparityPixelType>(m_MaximumHorizontalDisparity) / static_cast<DisparityPixelType>(m_Step));
469  outVDispPtr->FillBuffer(static_cast<DisparityPixelType>(m_MinimumVerticalDisparity) / static_cast<DisparityPixelType>(m_Step));
470 }
471 
472 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
474  const RegionType& outputRegionForThread, itk::ThreadIdType threadId)
475 {
476  // Retrieve pointers
477  const TInputImage* inLeftPtr = this->GetLeftInput();
478  const TInputImage* inRightPtr = this->GetRightInput();
479  const TMaskImage* inLeftMaskPtr = this->GetLeftMaskInput();
480  const TMaskImage* inRightMaskPtr = this->GetRightMaskInput();
481  const TOutputDisparityImage* inHDispPtr = this->GetHorizontalDisparityInput();
482  const TOutputDisparityImage* inVDispPtr = this->GetVerticalDisparityInput();
483  TOutputMetricImage* outMetricPtr = this->GetMetricOutput();
484  TOutputDisparityImage* outHDispPtr = this->GetHorizontalDisparityOutput();
485  TOutputDisparityImage* outVDispPtr = this->GetVerticalDisparityOutput();
486 
487  // Set-up progress reporting (this is not exact, since we do not
488  // account for pixels that are out of range for a given disparity
489  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels() * (m_MaximumHorizontalDisparity - m_MinimumHorizontalDisparity + 1) *
490  (m_MaximumVerticalDisparity - m_MinimumVerticalDisparity + 1),
491  100);
492 
493 
494  // Handle initialization properly
495  typename InputMaskImageType::Pointer initMaskPtr = InputMaskImageType::New();
496  initMaskPtr->SetRegions(outputRegionForThread);
497  initMaskPtr->Allocate();
498  initMaskPtr->FillBuffer(0);
499 
500  // Compute region for thread at full resolution
501  RegionType fullRegionForThread = this->ConvertSubsampledToFullRegion(outputRegionForThread, this->m_Step, this->m_GridIndex);
502 
503  // Check if we use initial disparities and exploration radius
504  bool useExplorationRadius = false;
505  bool useInitDispMaps = false;
506  if (m_ExplorationRadius[0] >= 1 || m_ExplorationRadius[1] >= 1)
507  {
508  useExplorationRadius = true;
509  if (inHDispPtr && inVDispPtr)
510  {
511  useInitDispMaps = true;
512  }
513  }
514 
515  // step value as disparityType
516  DisparityPixelType stepDisparityInv = 1. / static_cast<DisparityPixelType>(this->m_Step);
517 
518  // We loop on disparities
519  for (int vdisparity = m_MinimumVerticalDisparity; vdisparity <= m_MaximumVerticalDisparity; ++vdisparity)
520  {
521  for (int hdisparity = m_MinimumHorizontalDisparity; hdisparity <= m_MaximumHorizontalDisparity; ++hdisparity)
522  {
523  // First, we cast output region to the right image
524  IndexType rightRequestedRegionIndex = fullRegionForThread.GetIndex();
525  rightRequestedRegionIndex[0] += hdisparity;
526  rightRequestedRegionIndex[1] += vdisparity;
527 
528  // We crop
529  RegionType inputRightRegion;
530  inputRightRegion.SetIndex(rightRequestedRegionIndex);
531  inputRightRegion.SetSize(fullRegionForThread.GetSize());
532  inputRightRegion.Crop(inRightPtr->GetLargestPossibleRegion());
533 
534  // And then cast back
535  IndexType leftRequestedRegionIndex = inputRightRegion.GetIndex();
536  leftRequestedRegionIndex[0] -= hdisparity;
537  leftRequestedRegionIndex[1] -= vdisparity;
538 
539  RegionType inputLeftRegion;
540  inputLeftRegion.SetIndex(leftRequestedRegionIndex);
541  inputLeftRegion.SetSize(inputRightRegion.GetSize());
542 
543  // Compute the equivalent region in subsampled grid
544  RegionType outputRegion = this->ConvertFullToSubsampledRegion(inputLeftRegion, this->m_Step, this->m_GridIndex);
545 
546  // Define iterators
547  itk::ConstNeighborhoodIterator<TInputImage> leftIt(m_Radius, inLeftPtr, inputLeftRegion);
548  itk::ConstNeighborhoodIterator<TInputImage> rightIt(m_Radius, inRightPtr, inputRightRegion);
549  itk::ImageRegionIterator<TOutputMetricImage> outMetricIt(outMetricPtr, outputRegion);
550  itk::ImageRegionIterator<TOutputDisparityImage> outHDispIt(outHDispPtr, outputRegion);
551  itk::ImageRegionIterator<TOutputDisparityImage> outVDispIt(outVDispPtr, outputRegion);
552  itk::ImageRegionConstIterator<TMaskImage> inLeftMaskIt;
553  itk::ImageRegionConstIterator<TMaskImage> inRightMaskIt;
554  itk::ImageRegionConstIterator<TOutputDisparityImage> inHDispIt;
555  itk::ImageRegionConstIterator<TOutputDisparityImage> inVDispIt;
556  itk::ImageRegionIterator<TMaskImage> initIt(initMaskPtr, outputRegion);
557 
558  itk::ConstantBoundaryCondition<TInputImage> nbc1;
559  itk::ConstantBoundaryCondition<TInputImage> nbc2;
560 
561  leftIt.OverrideBoundaryCondition(&nbc1);
562  rightIt.OverrideBoundaryCondition(&nbc2);
563 
564  // If we have a mask, define the iterator
565  if (inLeftMaskPtr)
566  {
567  inLeftMaskIt = itk::ImageRegionConstIterator<TMaskImage>(inLeftMaskPtr, inputLeftRegion);
568  inLeftMaskIt.GoToBegin();
569  }
570  if (inRightMaskPtr)
571  {
572  inRightMaskIt = itk::ImageRegionConstIterator<TMaskImage>(inRightMaskPtr, inputRightRegion);
573  inRightMaskIt.GoToBegin();
574  }
575 
576  // If we use initial disparity maps, define the iterators
577  if (useInitDispMaps)
578  {
579  inHDispIt = itk::ImageRegionConstIterator<TOutputDisparityImage>(inHDispPtr, inputLeftRegion);
580  inVDispIt = itk::ImageRegionConstIterator<TOutputDisparityImage>(inVDispPtr, inputLeftRegion);
581  inHDispIt.GoToBegin();
582  inVDispIt.GoToBegin();
583  }
584 
585  // Initialize iterators
586  leftIt.GoToBegin();
587  rightIt.GoToBegin();
588  outMetricIt.GoToBegin();
589  outHDispIt.GoToBegin();
590  outVDispIt.GoToBegin();
591  initIt.GoToBegin();
592 
593  // Loop on pixels
594  while (!leftIt.IsAtEnd() || !rightIt.IsAtEnd() || !outMetricIt.IsAtEnd() || !outHDispIt.IsAtEnd() || !outVDispIt.IsAtEnd() || !initIt.IsAtEnd())
595  {
596  // If the pixel location is on the subsampled grid
597  IndexType tmpIndex = leftIt.GetIndex(leftIt.GetCenterNeighborhoodIndex());
598  if (((tmpIndex[0] - this->m_GridIndex[0] + this->m_Step) % this->m_Step == 0) &&
599  ((tmpIndex[1] - this->m_GridIndex[1] + this->m_Step) % this->m_Step == 0))
600  {
601  // If the mask is present and valid
602  if (!inLeftMaskPtr || (inLeftMaskIt.Get() > 0))
603  {
604  if (!inRightMaskPtr || (inRightMaskIt.Get() > 0))
605  {
606  int estimatedMinHDisp = m_MinimumHorizontalDisparity;
607  int estimatedMinVDisp = m_MinimumVerticalDisparity;
608  int estimatedMaxHDisp = m_MaximumHorizontalDisparity;
609  int estimatedMaxVDisp = m_MaximumVerticalDisparity;
610  if (useExplorationRadius)
611  {
612  // compute disparity bounds from initial position and exploration radius
613  if (useInitDispMaps)
614  {
615  estimatedMinHDisp = inHDispIt.Get() - m_ExplorationRadius[0];
616  estimatedMinVDisp = inVDispIt.Get() - m_ExplorationRadius[1];
617  estimatedMaxHDisp = inHDispIt.Get() + m_ExplorationRadius[0];
618  estimatedMaxVDisp = inVDispIt.Get() + m_ExplorationRadius[1];
619  }
620  else
621  {
622  estimatedMinHDisp = m_InitHorizontalDisparity - m_ExplorationRadius[0];
623  estimatedMinVDisp = m_InitVerticalDisparity - m_ExplorationRadius[1];
624  estimatedMaxHDisp = m_InitHorizontalDisparity + m_ExplorationRadius[0];
625  estimatedMaxVDisp = m_InitVerticalDisparity + m_ExplorationRadius[1];
626  }
627  // clamp to the minimum disparities
628  if (estimatedMinHDisp < m_MinimumHorizontalDisparity)
629  {
630  estimatedMinHDisp = m_MinimumHorizontalDisparity;
631  }
632  if (estimatedMinVDisp < m_MinimumVerticalDisparity)
633  {
634  estimatedMinVDisp = m_MinimumVerticalDisparity;
635  }
636  }
637 
638  if (vdisparity >= estimatedMinVDisp && vdisparity <= estimatedMaxVDisp && hdisparity >= estimatedMinHDisp && hdisparity <= estimatedMaxHDisp)
639  {
640  // Compute the block matching value
641  double metric = m_Functor(leftIt, rightIt);
642 
643  // If we are at first loop, fill both outputs
644  // We adapt the disparity value to keep consistent with disparity map index space
645  if (initIt.Get() == 0)
646  {
647  outHDispIt.Set(static_cast<DisparityPixelType>(hdisparity) * stepDisparityInv);
648  outVDispIt.Set(static_cast<DisparityPixelType>(vdisparity) * stepDisparityInv);
649  outMetricIt.Set(metric);
650  initIt.Set(1);
651  }
652  else if (m_Minimize && metric < outMetricIt.Get())
653  {
654  outHDispIt.Set(static_cast<DisparityPixelType>(hdisparity) * stepDisparityInv);
655  outVDispIt.Set(static_cast<DisparityPixelType>(vdisparity) * stepDisparityInv);
656  outMetricIt.Set(metric);
657  }
658  else if (!m_Minimize && metric > outMetricIt.Get())
659  {
660  outHDispIt.Set(static_cast<DisparityPixelType>(hdisparity) * stepDisparityInv);
661  outVDispIt.Set(static_cast<DisparityPixelType>(vdisparity) * stepDisparityInv);
662  outMetricIt.Set(metric);
663  }
664  }
665  }
666  }
667  ++outMetricIt;
668  ++outHDispIt;
669  ++outVDispIt;
670  ++initIt;
671  progress.CompletedPixel();
672  }
673  ++leftIt;
674  ++rightIt;
675 
676  if (inLeftMaskPtr)
677  {
678  ++inLeftMaskIt;
679  }
680 
681  if (inRightMaskPtr)
682  {
683  ++inRightMaskIt;
684  }
685 
686  if (useInitDispMaps)
687  {
688  ++inHDispIt;
689  ++inVDispIt;
690  }
691  }
692  }
693  }
694 }
695 
696 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
699  RegionType full, unsigned int step, IndexType index)
700 {
701  IndexType shiftedFull = full.GetIndex();
702  shiftedFull[0] -= index[0];
703  shiftedFull[1] -= index[1];
704 
705  IndexType subIndex;
706  subIndex[0] = (shiftedFull[0]) / step;
707  subIndex[1] = (shiftedFull[1]) / step;
708  if (shiftedFull[0] % step)
709  ++subIndex[0];
710  if (shiftedFull[1] % step)
711  ++subIndex[1];
712 
713  if (shiftedFull[0] < 0)
714  subIndex[0] = 0;
715  if (shiftedFull[1] < 0)
716  subIndex[1] = 0;
717 
718  SizeType subSize;
719  subSize[0] = (full.GetSize(0) - (subIndex[0] * step) + shiftedFull[0]) / step;
720  subSize[1] = (full.GetSize(1) - (subIndex[1] * step) + shiftedFull[1]) / step;
721 
722  if ((full.GetSize(0) - (subIndex[0] * step) + shiftedFull[0]) % step)
723  ++subSize[0];
724  if ((full.GetSize(1) - (subIndex[1] * step) + shiftedFull[1]) % step)
725  ++subSize[1];
726 
727  RegionType subRegion;
728  subRegion.SetIndex(subIndex);
729  subRegion.SetSize(subSize);
730  return subRegion;
731 }
732 
733 template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor>
736  RegionType sub, unsigned int step, IndexType index)
737 {
738  IndexType fullIndex;
739  fullIndex[0] = sub.GetIndex(0) * step + index[0];
740  fullIndex[1] = sub.GetIndex(1) * step + index[1];
741 
742  SizeType fullSize;
743  fullSize[0] = sub.GetSize(0) * step;
744  fullSize[1] = sub.GetSize(1) * step;
745  if (fullSize[0] > 0)
746  fullSize[0] -= (step - 1);
747  if (fullSize[1] > 0)
748  fullSize[1] -= (step - 1);
749 
750  RegionType fullRegion;
751  fullRegion.SetIndex(fullIndex);
752  fullRegion.SetSize(fullSize);
753  return fullRegion;
754 }
755 
756 } // End namespace otb
757 
758 #endif
Perform 2D block matching between two images.
static RegionType ConvertSubsampledToFullRegion(RegionType sub, unsigned int step, IndexType index)
const TOutputDisparityImage * GetVerticalDisparityInput() const
static RegionType ConvertFullToSubsampledRegion(RegionType full, unsigned int step, IndexType index)
void SetHorizontalDisparityInput(const TOutputDisparityImage *hfield)
const TOutputDisparityImage * GetHorizontalDisparityOutput() const
const TOutputDisparityImage * GetVerticalDisparityOutput() const
void ThreadedGenerateData(const RegionType &outputRegionForThread, itk::ThreadIdType threadId) override
void SetVerticalDisparityInput(const TOutputDisparityImage *vfield)
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.