OTB  10.0.0
Orfeo Toolbox
otbDisparityTranslateFilter.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 otbDisparityTranslateFilter_hxx
22 #define otbDisparityTranslateFilter_hxx
23 
25 
26 #include "itkImageRegionIteratorWithIndex.h"
27 #include "itkImageRegionIterator.h"
28 #include "otbNoDataHelper.h"
29 
30 namespace otb
31 {
32 
33 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
35  : m_NoDataValue(-32768)
36 {
37  this->DynamicMultiThreadingOn();
38  // Set the number of inputs (1 moving image by default -> 3 inputs)
39  this->SetNumberOfRequiredInputs(6);
40  this->SetNumberOfRequiredInputs(1);
41 
42  // Set the outputs
43  this->SetNumberOfRequiredOutputs(2);
44  this->SetNthOutput(0, TDisparityImage::New());
45  this->SetNthOutput(1, TDisparityImage::New());
46 }
47 
48 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
50 {
51  // Process object is not const-correct so the const casting is required.
52  this->SetNthInput(0, const_cast<TDisparityImage*>(hmap));
53 }
54 
55 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
57 {
58  // Process object is not const-correct so the const casting is required.
59  this->SetNthInput(1, const_cast<TDisparityImage*>(vmap));
60 }
61 
62 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
64 {
65  // Process object is not const-correct so the const casting is required.
66  this->SetNthInput(2, const_cast<TGridImage*>(lgrid));
67 }
68 
69 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
71 {
72  // Process object is not const-correct so the const casting is required.
73  this->SetNthInput(3, const_cast<TGridImage*>(rgrid));
74 }
75 
76 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
78 {
79  // Process object is not const-correct so the const casting is required.
80  this->SetNthInput(4, const_cast<TMaskImage*>(mask));
81 }
82 
83 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
85 {
86  // Process object is not const-correct so the const casting is required.
87  this->SetNthInput(5, const_cast<TSensorImage*>(left));
88 }
89 
90 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
92 {
93  if (this->GetNumberOfInputs() < 1)
94  {
95  return nullptr;
96  }
97  return static_cast<const TDisparityImage*>(this->itk::ProcessObject::GetInput(0));
98 }
99 
100 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
102 {
103  if (this->GetNumberOfInputs() < 2)
104  {
105  return nullptr;
106  }
107  return static_cast<const TDisparityImage*>(this->itk::ProcessObject::GetInput(1));
108 }
109 
110 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
112 {
113  if (this->GetNumberOfInputs() < 3)
114  {
115  return nullptr;
116  }
117  return static_cast<const TGridImage*>(this->itk::ProcessObject::GetInput(2));
118 }
119 
120 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
122 {
123  if (this->GetNumberOfInputs() < 4)
124  {
125  return nullptr;
126  }
127  return static_cast<const TGridImage*>(this->itk::ProcessObject::GetInput(3));
128 }
129 
130 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
132 {
133  if (this->GetNumberOfInputs() < 5)
134  {
135  return nullptr;
136  }
137  return static_cast<const TMaskImage*>(this->itk::ProcessObject::GetInput(4));
138 }
139 
140 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
142 {
143  if (this->GetNumberOfInputs() < 6)
144  {
145  return nullptr;
146  }
147  return static_cast<const TSensorImage*>(this->itk::ProcessObject::GetInput(5));
148 }
149 
150 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
152 {
153  if (this->GetNumberOfOutputs() < 1)
154  {
155  return nullptr;
156  }
157  return static_cast<TDisparityImage*>(this->itk::ProcessObject::GetOutput(0));
158 }
159 
160 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
162 {
163  if (this->GetNumberOfOutputs() < 2)
164  {
165  return nullptr;
166  }
167  return static_cast<TDisparityImage*>(this->itk::ProcessObject::GetOutput(1));
168 }
169 
170 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
172 {
173  // this->Superclass::GenerateOutputInformation();
174 
175  TDisparityImage* horizOut = this->GetHorizontalDisparityMapOutput();
176  TDisparityImage* vertiOut = this->GetVerticalDisparityMapOutput();
177 
178  const TSensorImage* leftIn = this->GetLeftSensorImageInput();
179 
180  horizOut->CopyInformation(leftIn);
181  vertiOut->CopyInformation(leftIn);
182 
183  // Set the NoData value
184  std::vector<bool> noDataValueAvailable = {true};
185  std::vector<double> noDataValue = {m_NoDataValue};
186 
187  WriteNoDataFlags(noDataValueAvailable, noDataValue, horizOut->GetImageMetadata());
188  WriteNoDataFlags(noDataValueAvailable, noDataValue, vertiOut->GetImageMetadata());
189 }
190 
191 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
193 {
194  this->Superclass::GenerateInputRequestedRegion();
195 
196  TGridImage* leftGrid = const_cast<TGridImage*>(this->GetInverseEpipolarLeftGrid());
197  TGridImage* rightGrid = const_cast<TGridImage*>(this->GetDirectEpipolarRightGrid());
198 
199  leftGrid->SetRequestedRegionToLargestPossibleRegion();
200  rightGrid->SetRequestedRegionToLargestPossibleRegion();
201 
202  leftGrid->UpdateOutputData();
203  rightGrid->UpdateOutputData();
204 
205  TSensorImage* leftIn = const_cast<TSensorImage*>(this->GetLeftSensorImageInput());
206  RegionType emptyRegion = leftIn->GetLargestPossibleRegion();
207  emptyRegion.SetSize(0, 0);
208  emptyRegion.SetSize(1, 0);
209  leftIn->SetRequestedRegion(emptyRegion);
210 
211  TDisparityImage* horizOut = this->GetHorizontalDisparityMapOutput();
212 
213  TDisparityImage* horizIn = const_cast<TDisparityImage*>(this->GetHorizontalDisparityMapInput());
214  TDisparityImage* vertiIn = const_cast<TDisparityImage*>(this->GetVerticalDisparityMapInput());
215 
216  TMaskImage* maskIn = const_cast<TMaskImage*>(this->GetDisparityMaskInput());
217 
218  RegionType requested = this->GetHorizontalDisparityMapOutput()->GetRequestedRegion();
219  RegionType inputlargest = this->GetHorizontalDisparityMapInput()->GetLargestPossibleRegion();
220  RegionType inputRequested;
221  GridRegionType gridLargest = leftGrid->GetLargestPossibleRegion();
222 
223  IndexType minIndex, maxIndex;
224  // -Wmaybe-uninitialized
225  minIndex.Fill(itk::NumericTraits<IndexValueType>::Zero);
226  maxIndex.Fill(itk::NumericTraits<IndexValueType>::Zero);
227 
228  IndexType corners[4];
229  for (int i = 0; i < 4; i++)
230  corners[i].Fill(itk::NumericTraits<IndexValueType>::Zero);
231 
232  corners[0] = requested.GetIndex();
233  corners[1] = requested.GetIndex();
234  corners[1][0] += static_cast<IndexValueType>(requested.GetSize()[0]) - 1;
235  corners[2] = requested.GetIndex();
236  corners[2][1] += static_cast<IndexValueType>(requested.GetSize()[1]) - 1;
237  corners[3] = requested.GetIndex();
238  corners[3][0] += static_cast<IndexValueType>(requested.GetSize()[0]) - 1;
239  corners[3][1] += static_cast<IndexValueType>(requested.GetSize()[1]) - 1;
240  for (unsigned int k = 0; k < 4; ++k)
241  {
242  PointType pointSensor;
243  horizOut->TransformIndexToPhysicalPoint(corners[k], pointSensor);
244  itk::ContinuousIndex<double, 2> indexGrid;
245  leftGrid->TransformPhysicalPointToContinuousIndex(pointSensor, indexGrid);
246  IndexType ul;
247  ul[0] = static_cast<long>(std::floor(indexGrid[0]));
248  ul[1] = static_cast<long>(std::floor(indexGrid[1]));
249  if (ul[0] < gridLargest.GetIndex()[0])
250  ul[0] = gridLargest.GetIndex()[0];
251  if (ul[1] < gridLargest.GetIndex()[1])
252  ul[1] = gridLargest.GetIndex()[1];
253  if (ul[0] > static_cast<IndexValueType>(gridLargest.GetIndex()[0] + gridLargest.GetSize()[0] - 2))
254  ul[0] = (gridLargest.GetIndex()[0] + gridLargest.GetSize()[0] - 2);
255  if (ul[1] > static_cast<IndexValueType>(gridLargest.GetIndex()[1] + gridLargest.GetSize()[1] - 2))
256  ul[1] = (gridLargest.GetIndex()[1] + gridLargest.GetSize()[1] - 2);
257 
258  IndexType ur = ul;
259  ur[0] += 1;
260  IndexType ll = ul;
261  ll[1] += 1;
262  IndexType lr = ul;
263  lr[0] += 1;
264  lr[1] += 1;
265 
266  double rx = indexGrid[0] - static_cast<double>(ul[0]);
267  double ry = indexGrid[1] - static_cast<double>(ul[1]);
268  PointType pointEpi = pointSensor;
269 
270  pointEpi[0] += (1. - ry) * ((1. - rx) * leftGrid->GetPixel(ul)[0] + rx * leftGrid->GetPixel(ur)[0]) +
271  ry * ((1. - rx) * leftGrid->GetPixel(ll)[0] + rx * leftGrid->GetPixel(lr)[0]);
272  pointEpi[1] += (1. - ry) * ((1. - rx) * leftGrid->GetPixel(ul)[1] + rx * leftGrid->GetPixel(ur)[1]) +
273  ry * ((1. - rx) * leftGrid->GetPixel(ll)[1] + rx * leftGrid->GetPixel(lr)[1]);
274  itk::ContinuousIndex<double, 2> indexEpi;
275 
276  horizIn->TransformPhysicalPointToContinuousIndex(pointEpi, indexEpi);
277  if (k == 0)
278  {
279  minIndex[0] = static_cast<long>(std::floor(indexEpi[0]));
280  minIndex[1] = static_cast<long>(std::floor(indexEpi[1]));
281  maxIndex[0] = static_cast<long>(std::ceil(indexEpi[0]));
282  maxIndex[1] = static_cast<long>(std::ceil(indexEpi[1]));
283  }
284  else
285  {
286  if (minIndex[0] > static_cast<long>(std::floor(indexEpi[0])))
287  minIndex[0] = static_cast<long>(std::floor(indexEpi[0]));
288  if (minIndex[1] > static_cast<long>(std::floor(indexEpi[1])))
289  minIndex[1] = static_cast<long>(std::floor(indexEpi[1]));
290  if (maxIndex[0] < static_cast<long>(std::ceil(indexEpi[0])))
291  maxIndex[0] = static_cast<long>(std::ceil(indexEpi[0]));
292  if (maxIndex[1] < static_cast<long>(std::ceil(indexEpi[1])))
293  maxIndex[1] = static_cast<long>(std::ceil(indexEpi[1]));
294  }
295  }
296 
297  inputRequested.SetIndex(minIndex);
298  inputRequested.SetSize(0, static_cast<unsigned long>(maxIndex[0] - minIndex[0]));
299  inputRequested.SetSize(1, static_cast<unsigned long>(maxIndex[1] - minIndex[1]));
300 
301  if (!inputRequested.Crop(inputlargest))
302  {
303  inputRequested.SetSize(0, 0);
304  inputRequested.SetSize(1, 0);
305  inputRequested.SetIndex(inputlargest.GetIndex());
306  }
307 
308  horizIn->SetRequestedRegion(inputRequested);
309  if (vertiIn)
310  vertiIn->SetRequestedRegion(inputRequested);
311  if (maskIn)
312  maskIn->SetRequestedRegion(inputRequested);
313 }
314 
315 template <class TDisparityImage, class TGridImage, class TSensorImage, class TMaskImage>
317 {
318  const TGridImage* leftGrid = this->GetInverseEpipolarLeftGrid();
319  const TGridImage* rightGrid = this->GetDirectEpipolarRightGrid();
320 
321  TDisparityImage* horizOut = this->GetHorizontalDisparityMapOutput();
322  TDisparityImage* vertiOut = this->GetVerticalDisparityMapOutput();
323 
324  const TDisparityImage* horizIn = this->GetHorizontalDisparityMapInput();
325  const TDisparityImage* vertiIn = this->GetVerticalDisparityMapInput();
326 
327  const TMaskImage* maskIn = this->GetDisparityMaskInput();
328 
329  GridRegionType leftLargest = leftGrid->GetLargestPossibleRegion();
330  GridRegionType rightLargest = rightGrid->GetLargestPossibleRegion();
331  RegionType buffered = horizIn->GetBufferedRegion();
332 
333  const bool emptyInputRegion = buffered.GetNumberOfPixels() == 0;
334 
335  typedef itk::ImageRegionIteratorWithIndex<TDisparityImage> DispIterator;
336  DispIterator horizIter(horizOut, outputRegionForThread);
337  DispIterator vertiIter(vertiOut, outputRegionForThread);
338 
339  horizIter.GoToBegin();
340  vertiIter.GoToBegin();
341 
342  while (!horizIter.IsAtEnd() && !vertiIter.IsAtEnd())
343  {
344 
345  if (!emptyInputRegion)
346  {
347  PointType pointSensor;
348  horizOut->TransformIndexToPhysicalPoint(horizIter.GetIndex(), pointSensor);
349 
350  itk::ContinuousIndex<double, 2> indexGrid;
351  leftGrid->TransformPhysicalPointToContinuousIndex(pointSensor, indexGrid);
352 
353  // Interpolate in left grid
354  IndexType ul;
355  ul[0] = static_cast<long>(std::floor(indexGrid[0]));
356  ul[1] = static_cast<long>(std::floor(indexGrid[1]));
357  if (ul[0] < leftLargest.GetIndex()[0])
358  ul[0] = leftLargest.GetIndex()[0];
359  if (ul[1] < leftLargest.GetIndex()[1])
360  ul[1] = leftLargest.GetIndex()[1];
361  if (ul[0] > static_cast<IndexValueType>(leftLargest.GetIndex()[0] + leftLargest.GetSize()[0] - 2))
362  ul[0] = (leftLargest.GetIndex()[0] + leftLargest.GetSize()[0] - 2);
363  if (ul[1] > static_cast<IndexValueType>(leftLargest.GetIndex()[1] + leftLargest.GetSize()[1] - 2))
364  ul[1] = (leftLargest.GetIndex()[1] + leftLargest.GetSize()[1] - 2);
365 
366  IndexType ur = ul;
367  ur[0] += 1;
368  IndexType ll = ul;
369  ll[1] += 1;
370  IndexType lr = ul;
371  lr[0] += 1;
372  lr[1] += 1;
373 
374  double rx = indexGrid[0] - static_cast<double>(ul[0]);
375  double ry = indexGrid[1] - static_cast<double>(ul[1]);
376  PointType pointEpi = pointSensor;
377 
378  pointEpi[0] += (1. - ry) * ((1. - rx) * leftGrid->GetPixel(ul)[0] + rx * leftGrid->GetPixel(ur)[0]) +
379  ry * ((1. - rx) * leftGrid->GetPixel(ll)[0] + rx * leftGrid->GetPixel(lr)[0]);
380  pointEpi[1] += (1. - ry) * ((1. - rx) * leftGrid->GetPixel(ul)[1] + rx * leftGrid->GetPixel(ur)[1]) +
381  ry * ((1. - rx) * leftGrid->GetPixel(ll)[1] + rx * leftGrid->GetPixel(lr)[1]);
382 
383  itk::ContinuousIndex<double, 2> indexEpi;
384  horizIn->TransformPhysicalPointToContinuousIndex(pointEpi, indexEpi);
385 
386  // Interpolate in disparity map
387  ul[0] = static_cast<long>(std::floor(indexEpi[0]));
388  ul[1] = static_cast<long>(std::floor(indexEpi[1]));
389  if (ul[0] < buffered.GetIndex()[0])
390  ul[0] = buffered.GetIndex()[0];
391  if (ul[1] < buffered.GetIndex()[1])
392  ul[1] = buffered.GetIndex()[1];
393  if (ul[0] > static_cast<IndexValueType>(buffered.GetIndex()[0] + buffered.GetSize()[0] - 2))
394  ul[0] = (buffered.GetIndex()[0] + buffered.GetSize()[0] - 2);
395  if (ul[1] > static_cast<IndexValueType>(buffered.GetIndex()[1] + buffered.GetSize()[1] - 2))
396  ul[1] = (buffered.GetIndex()[1] + buffered.GetSize()[1] - 2);
397 
398  ur = ul;
399  ur[0] += 1;
400  ll = ul;
401  ll[1] += 1;
402  lr = ul;
403  lr[0] += 1;
404  lr[1] += 1;
405 
406  // check if all corners are valid
407  if (!maskIn || (maskIn && maskIn->GetPixel(ul) > 0 && maskIn->GetPixel(ur) > 0 && maskIn->GetPixel(ll) > 0 && maskIn->GetPixel(lr) > 0))
408  {
409  rx = indexEpi[0] - static_cast<double>(ul[0]);
410  ry = indexEpi[1] - static_cast<double>(ul[1]);
411 
412  itk::ContinuousIndex<double, 2> indexRight(indexEpi);
413 
414  indexRight[0] += (1. - ry) * ((1. - rx) * horizIn->GetPixel(ul) + rx * horizIn->GetPixel(ur)) +
415  ry * ((1. - rx) * horizIn->GetPixel(ll) + rx * horizIn->GetPixel(lr));
416  if (vertiIn)
417  {
418  indexRight[1] += (1. - ry) * ((1. - rx) * vertiIn->GetPixel(ul) + rx * vertiIn->GetPixel(ur)) +
419  ry * ((1. - rx) * vertiIn->GetPixel(ll) + rx * vertiIn->GetPixel(lr));
420  }
421 
422  PointType pointRight;
423  horizIn->TransformContinuousIndexToPhysicalPoint(indexRight, pointRight);
424 
425  itk::ContinuousIndex<double, 2> indexGridRight;
426  rightGrid->TransformPhysicalPointToContinuousIndex(pointRight, indexGridRight);
427 
428  // Interpolate in right grid
429  ul[0] = static_cast<long>(std::floor(indexGridRight[0]));
430  ul[1] = static_cast<long>(std::floor(indexGridRight[1]));
431  if (ul[0] < rightLargest.GetIndex()[0])
432  ul[0] = rightLargest.GetIndex()[0];
433  if (ul[1] < rightLargest.GetIndex()[1])
434  ul[1] = rightLargest.GetIndex()[1];
435  if (ul[0] > static_cast<IndexValueType>(rightLargest.GetIndex()[0] + rightLargest.GetSize()[0] - 2))
436  ul[0] = (rightLargest.GetIndex()[0] + rightLargest.GetSize()[0] - 2);
437  if (ul[1] > static_cast<IndexValueType>(rightLargest.GetIndex()[1] + rightLargest.GetSize()[1] - 2))
438  ul[1] = (rightLargest.GetIndex()[1] + rightLargest.GetSize()[1] - 2);
439 
440  ur = ul;
441  ur[0] += 1;
442  ll = ul;
443  ll[1] += 1;
444  lr = ul;
445  lr[0] += 1;
446  lr[1] += 1;
447 
448  rx = indexGridRight[0] - static_cast<double>(ul[0]);
449  ry = indexGridRight[1] - static_cast<double>(ul[1]);
450 
451  PointType pointSensorRight = pointRight;
452 
453  pointSensorRight[0] += (1. - ry) * ((1. - rx) * rightGrid->GetPixel(ul)[0] + rx * rightGrid->GetPixel(ur)[0]) +
454  ry * ((1. - rx) * rightGrid->GetPixel(ll)[0] + rx * rightGrid->GetPixel(lr)[0]);
455  pointSensorRight[1] += (1. - ry) * ((1. - rx) * rightGrid->GetPixel(ul)[1] + rx * rightGrid->GetPixel(ur)[1]) +
456  ry * ((1. - rx) * rightGrid->GetPixel(ll)[1] + rx * rightGrid->GetPixel(lr)[1]);
457 
458  horizIter.Set(pointSensorRight[0] - pointSensor[0]);
459  vertiIter.Set(pointSensorRight[1] - pointSensor[1]);
460  }
461  else
462  {
463  horizIter.Set(m_NoDataValue);
464  vertiIter.Set(m_NoDataValue);
465  }
466  }
467  else
468  {
469  horizIter.Set(m_NoDataValue);
470  vertiIter.Set(m_NoDataValue);
471  }
472  ++horizIter;
473  ++vertiIter;
474  }
475 }
476 }
477 
478 #endif
void SetVerticalDisparityMapInput(const TDisparityImage *vmap)
const TDisparityImage * GetVerticalDisparityMapInput() const
void DynamicThreadedGenerateData(const RegionType &outputRegionForThread) override
const TDisparityImage * GetHorizontalDisparityMapInput() const
void SetLeftSensorImageInput(const TSensorImage *left)
const TGridImage * GetInverseEpipolarLeftGrid() const
const TMaskImage * GetDisparityMaskInput() const
void SetInverseEpipolarLeftGrid(const TGridImage *lgrid)
void SetHorizontalDisparityMapInput(const TDisparityImage *hmap)
const TSensorImage * GetLeftSensorImageInput() const
void SetDirectEpipolarRightGrid(const TGridImage *rgrid)
void SetDisparityMaskInput(const TMaskImage *mask)
const TGridImage * GetDirectEpipolarRightGrid() const
DispMapType::IndexValueType IndexValueType
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
void OTBMetadata_EXPORT WriteNoDataFlags(const std::vector< bool > &flags, const std::vector< double > &values, ImageMetadata &imd)