File: otbPixelWiseBlockMatchingImageFilter.h

package info (click to toggle)
otb 7.2.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,005,476 kB
  • sloc: cpp: 270,143; xml: 128,722; ansic: 4,367; sh: 1,768; python: 1,084; perl: 92; makefile: 72
file content (510 lines) | stat: -rw-r--r-- 17,326 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef otbPixelWiseBlockMatchingImageFilter_h
#define otbPixelWiseBlockMatchingImageFilter_h


#include "itkImageToImageFilter.h"
#include "itkConstNeighborhoodIterator.h"
#include "itkImageRegionIterator.h"
#include "otbImage.h"

namespace otb
{

namespace Functor
{
/** \class SSDBlockMatching
 *  \brief Functor to perform simple SSD block-matching
 *
 *  This functor is designed to work with the
 *  PixelWiseBlockMatchingImageFilter. It performs a simple
 *  SSD (Sum of Square Distances) block-matching. The functor is
 *  templated by the type of inputs images and output metric image,
 *  and is using two neighborhood iterators as inputs.
 *
 * \ingroup OTBDisparityMap
 */
template <class TInputImage, class TOutputMetricImage>
ITK_EXPORT class SSDBlockMatching
{
public:
  typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType;
  typedef typename TOutputMetricImage::ValueType      MetricValueType;

  // Implement the SSD operator
  inline MetricValueType operator()(ConstNeighborhoodIteratorType& a, ConstNeighborhoodIteratorType& b) const
  {
    MetricValueType ssd = 0;

    // For some reason, iterators do not work on neighborhoods
    for (unsigned int i = 0; i < a.Size(); ++i)
    {
      ssd += (a.GetPixel(i) - b.GetPixel(i)) * (a.GetPixel(i) - b.GetPixel(i));
    }

    return ssd;
  }
};


/** \class SSDDivMeanBlockMatching
 *  \brief Functor to perform derived SSD block-matching (SSD divided by mean)
 *
 *  This functor is designed to work with the
 *  PixelWiseBlockMatchingImageFilter. It performs derived
 *  SSD (Sum of Square Distances) block-matching. The functor is
 *  templated by the type of inputs images and output metric image,
 *  and is using two neighborhood iterators as inputs.
 *
 * \ingroup OTBDisparityMap
 */
template <class TInputImage, class TOutputMetricImage>
ITK_EXPORT class SSDDivMeanBlockMatching
{
public:
  typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType;
  typedef typename TOutputMetricImage::ValueType      MetricValueType;

  // Implement the SSD DivMean operator
  inline MetricValueType operator()(ConstNeighborhoodIteratorType& a, ConstNeighborhoodIteratorType& b) const
  {
    MetricValueType ssd   = 0;
    MetricValueType meana = 0;
    MetricValueType meanb = 0;

    for (unsigned int i = 0; i < a.Size(); ++i)
    {
      meana += a.GetPixel(i);
      meanb += b.GetPixel(i);
    }
    meana /= a.Size();
    meanb /= b.Size();

    // For some reason, iterators do not work on neighborhoods
    for (unsigned int i = 0; i < a.Size(); ++i)
    {
      ssd += (a.GetPixel(i) / meana - b.GetPixel(i) / meanb) * (a.GetPixel(i) / meana - b.GetPixel(i) / meanb);
    }

    return ssd;
  }
};


/** \class NCCBlockMatching
 *  \brief Functor to perform simple NCC block-matching
 *
 *  This functor is designed to work with the
 *  PixelWiseBlockMatchingImageFilter. It performs a simple
 *  NCC (Normalized Cross-Correlation) block-matching. The functor is
 *  templated by the type of inputs images and output metric image,
 *  and is using two neighborhood iterators as inputs.
 *
 * \ingroup OTBDisparityMap
 */
template <class TInputImage, class TOutputMetricImage>
ITK_EXPORT class NCCBlockMatching
{
public:
  typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType;
  typedef typename TOutputMetricImage::ValueType      MetricValueType;

  // Implement the NCC operator
  inline MetricValueType operator()(ConstNeighborhoodIteratorType& a, ConstNeighborhoodIteratorType& b) const
  {
    // MetricValueType meanA(0),meanB(0), sigmaA(0), sigmaB(0), cov(0), ncc(0);
    double meanA  = 0.0;
    double meanB  = 0.0;
    double sigmaA = 0.0;
    double sigmaB = 0.0;
    double cov    = 0.0;
    double ncc    = 0.0;
    double valueA;
    double valueB;
    double size = a.Size();
    // For some reason, iterators do not work on neighborhoods
    for (unsigned int i = 0; i < size; ++i)
    {
      meanA += static_cast<double>(a.GetPixel(i));
      meanB += static_cast<double>(b.GetPixel(i));
    }

    // Compute mean
    meanA /= size;
    meanB /= size;

    for (unsigned int i = 0; i < size; ++i)
    {
      valueA = static_cast<double>(a.GetPixel(i));
      valueB = static_cast<double>(b.GetPixel(i));
      cov += (valueA - meanA) * (valueB - meanB);
      sigmaA += (valueA - meanA) * (valueA - meanA);
      sigmaB += (valueB - meanB) * (valueB - meanB);
    }

    cov /= size - 1;
    sigmaA /= size - 1;
    sigmaB /= size - 1;
    sigmaA = std::sqrt(sigmaA);
    sigmaB = std::sqrt(sigmaB);

    if (sigmaA > 1e-20 && sigmaB > 1e-20)
    {
      ncc = std::abs(cov) / (sigmaA * sigmaB);
    }
    else
    {
      ncc = 0;
    }

    return static_cast<MetricValueType>(ncc);
  }
};

/** \class LPBlockMatching
 *  \brief Functor to perform block-matching based on the L^p pseudo-norm
 *
 *  This functor is designed to work with the
 *  PixelWiseBlockMatchingImageFilter. It performs a distance computation between
 *  two windows based on the L^p pseudo norm (p greater than 0). The functor is
 *  templated by the type of inputs images and output metric image,
 *  and is using two neighborhood iterators as inputs.
 *
 * \ingroup OTBDisparityMap
 */
template <class TInputImage, class TOutputMetricImage>
ITK_EXPORT class LPBlockMatching
{
public:
  typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType;
  typedef typename TOutputMetricImage::ValueType      MetricValueType;

  LPBlockMatching() : m_P(1)
  {
  }

  void SetP(double p)
  {
    if (p > 0.0)
    {
      m_P = p;
    }
    else
    {
      m_P = 1.0;
    }
  }

  // Implement the Lp metric
  inline MetricValueType operator()(ConstNeighborhoodIteratorType& a, ConstNeighborhoodIteratorType& b) const
  {
    MetricValueType score(0);

    // For some reason, iterators do not work on neighborhoods
    for (unsigned int i = 0; i < a.Size(); ++i)
    {
      score += std::pow(std::abs(static_cast<double>(a.GetPixel(i) - b.GetPixel(i))), m_P);
    }

    return score;
  }

private:
  double m_P;
};

} // End Namespace Functor

/** \class PixelWiseBlockMatchingImageFilter
 *  \brief Perform 2D block matching between two images
 *
 *  This filter performs pixel-wise 2D block-matching
 *  between a pair of image. This is especially useful in the case of
 *  stereo pairs in epipolar geometry, where displacements
 *  corresponding to differences of elevation occur in the horizontal
 *  direction only (in that case, the exploration along the vertical
 *  direction can be disabled). Please note that only integer pixel
 *  displacement are explored. For finer results, consider up-sampling
 *  the input images or use the SubPixelDisparityImageFilter.
 *
 *  The block-matching metric itself is defined by a template functor
 *  on neighborhood iterators. A wide range of block-matching
 *  criterions can be implemented this way, but the default functor
 *  performs a simple SSD (Sum of Square Distances). The radius of the
 *  blocks can be set using the SetRadius() method. The filter will
 *  try to minimize the metric value by default. Setting the minimize
 *  flag to off using the MinimizeOff() method will make the filter
 *  try to maximize the metric.
 *
 *  Only a user defined area of disparities between the two images is
 *  explored, which can be set by using the SetMinimumHorizontalDisparity()
 *  , SetMinimumVerticalDisparity(), SetMaximumHorizontalDisparity()
 *  and SetMaximumVerticalDisparity() methods.
 *
 *  This filter has three outputs: the first is the metric image,
 *  which contains the metric optimum value corresponding to the
 *  estimated displacement. The second and last outputs are the
 *  horizontal and vertical disparity maps, which can be retrieved
 *  using the GetHorizontalDisparityOutput() and GetVerticalDisparityOutput()
 *  methods. They contain the horizontal and vertical local displacement
 *  between the two input images (displacement is given in pixels, from left
 *  image to right image).
 *
 *  Masks are not mandatory. A mask allows indicating pixels validity in
 *  either left or right image. Left and right masks can be used independently.
 *  If masks are used, only pixels whose mask values are strictly positive
 *  will be considered for disparity matching. The other will exhibit a null
 *  metric value and a disparity corresponding to the minimum allowed
 *  disparity.
 *
 *  The disparity exploration can also be reduced thanks to initial disparity
 *  maps. The user can provide initial disparity estimate (using the same image
 *  type and size as the output disparities), or global disparity values. Then
 *  an exploration radius indicates the disparity range to be explored around
 *  the initial estimate (global minimum and maximum values are still in use).
 *
 *  \sa FineRegistrationImageFilter
 *  \sa StereorectificationDisplacementFieldSource
 *  \sa SubPixelDisparityImageFilter
 *
 *  \ingroup Streamed
 *  \ingroup Threaded
 *
 *
 * \ingroup OTBDisparityMap
 */

template <class TInputImage, class TOutputMetricImage, class TOutputDisparityImage = TOutputMetricImage, class TMaskImage = otb::Image<unsigned char>,
          class TBlockMatchingFunctor = Functor::SSDBlockMatching<TInputImage, TOutputMetricImage>>
class ITK_EXPORT PixelWiseBlockMatchingImageFilter : public itk::ImageToImageFilter<TInputImage, TOutputDisparityImage>
{
public:
  /** Standard class typedef */
  typedef PixelWiseBlockMatchingImageFilter Self;
  typedef itk::ImageToImageFilter<TInputImage, TOutputDisparityImage> Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods). */
  itkTypeMacro(PixelWiseBlockMatchingImageFilter, ImageToImageFilter);

  /** Useful typedefs */
  typedef TInputImage           InputImageType;
  typedef TOutputMetricImage    OutputMetricImageType;
  typedef TOutputDisparityImage OutputDisparityImageType;
  typedef TMaskImage            InputMaskImageType;
  typedef TBlockMatchingFunctor BlockMatchingFunctorType;

  typedef typename InputImageType::SizeType    SizeType;
  typedef typename InputImageType::IndexType   IndexType;
  typedef typename InputImageType::RegionType  RegionType;
  typedef typename InputImageType::SpacingType SpacingType;
  typedef typename InputImageType::PointType   PointType;

  typedef typename TOutputMetricImage::ValueType MetricValueType;

  typedef typename OutputDisparityImageType::PixelType DisparityPixelType;

  typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType;

  /** Set left input */
  void SetLeftInput(const TInputImage* image);

  /** Set right input */
  void SetRightInput(const TInputImage* image);

  /** Set mask input (optional) */
  void SetLeftMaskInput(const TMaskImage* image);

  /** Set right mask input (optional) */
  void SetRightMaskInput(const TMaskImage* image);

  /** Get the inputs */
  const TInputImage* GetLeftInput() const;
  const TInputImage* GetRightInput() const;
  const TMaskImage*  GetLeftMaskInput() const;
  const TMaskImage*  GetRightMaskInput() const;

  /** Get the metric output */
  const TOutputMetricImage* GetMetricOutput() const;
  TOutputMetricImage*       GetMetricOutput();

  /** Get the disparity output */
  const TOutputDisparityImage* GetHorizontalDisparityOutput() const;
  TOutputDisparityImage*       GetHorizontalDisparityOutput();

  /** Get the disparity output */
  const TOutputDisparityImage* GetVerticalDisparityOutput() const;
  TOutputDisparityImage*       GetVerticalDisparityOutput();


  /** Set unsigned int radius */
  void SetRadius(unsigned int radius)
  {
    m_Radius.Fill(radius);
  }

  /** Set/Get the radius of the area on which metric is evaluated */
  itkSetMacro(Radius, SizeType);
  itkGetConstReferenceMacro(Radius, SizeType);

  /*** Set/Get the minimum disparity to explore */
  itkSetMacro(MinimumHorizontalDisparity, int);
  itkGetConstReferenceMacro(MinimumHorizontalDisparity, int);

  /*** Set/Get the maximum disparity to explore */
  itkSetMacro(MaximumHorizontalDisparity, int);
  itkGetConstReferenceMacro(MaximumHorizontalDisparity, int);

  /*** Set/Get the minimum disparity to explore */
  itkSetMacro(MinimumVerticalDisparity, int);
  itkGetConstReferenceMacro(MinimumVerticalDisparity, int);

  /*** Set/Get the maximum disparity to explore */
  itkSetMacro(MaximumVerticalDisparity, int);
  itkGetConstReferenceMacro(MaximumVerticalDisparity, int);

  itkSetMacro(Minimize, bool);
  itkGetConstReferenceMacro(Minimize, bool);
  itkBooleanMacro(Minimize);

  /** Set/Get the exploration radius in the disparity space */
  itkSetMacro(ExplorationRadius, SizeType);
  itkGetConstReferenceMacro(ExplorationRadius, SizeType);

  /** Set/Get the initial horizontal disparity */
  itkSetMacro(InitHorizontalDisparity, int);
  itkGetConstReferenceMacro(InitHorizontalDisparity, int);

  /** Set/Get the initial vertical disparity */
  itkSetMacro(InitVerticalDisparity, int);
  itkGetConstReferenceMacro(InitVerticalDisparity, int);

  /** Get the functor for parameters setting */
  BlockMatchingFunctorType& GetFunctor()
  {
    return m_Functor;
  }

  /** Get the functor (const version) */
  const BlockMatchingFunctorType& GetFunctor() const
  {
    return m_Functor;
  }

  /** Set initial horizontal disparity field (optional, override m_InitHorizontalDisparity) */
  void SetHorizontalDisparityInput(const TOutputDisparityImage* hfield);

  /** Set initial vertical disparity field (optional, override m_InitVerticalDisparity) */
  void SetVerticalDisparityInput(const TOutputDisparityImage* vfield);

  /** Get the initial disparity fields */
  const TOutputDisparityImage* GetHorizontalDisparityInput() const;
  const TOutputDisparityImage* GetVerticalDisparityInput() const;

  /** Set/Get macro for the subsampling step */
  itkSetMacro(Step, unsigned int);
  itkGetMacro(Step, unsigned int);

  /** Set/Get macro for the grid start index */
  itkSetMacro(GridIndex, IndexType);
  itkGetConstReferenceMacro(GridIndex, IndexType);

  /** Conversion function between full and subsampled grid region */
  static RegionType ConvertFullToSubsampledRegion(RegionType full, unsigned int step, IndexType index);

  /** Conversion function between subsampled and full grid region */
  static RegionType ConvertSubsampledToFullRegion(RegionType sub, unsigned int step, IndexType index);

protected:
  /** Constructor */
  PixelWiseBlockMatchingImageFilter();

  /** Destructor */
  ~PixelWiseBlockMatchingImageFilter() override;

  /** Generate output information */
  void GenerateOutputInformation() override;

  /** Generate input requested region */
  void GenerateInputRequestedRegion() override;

  /** Before threaded generate data */
  void BeforeThreadedGenerateData() override;

  /** Threaded generate data */
  void ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId) override;

private:
  PixelWiseBlockMatchingImageFilter(const Self&) = delete;
  void operator                                  =(const Self&); // purposely not implemeFnted

  /** The radius of the blocks */
  SizeType m_Radius;

  /** The min disparity to explore */
  int m_MinimumHorizontalDisparity;

  /** The max disparity to explore */
  int m_MaximumHorizontalDisparity;

  /** The min disparity to explore */
  int m_MinimumVerticalDisparity;

  /** The max disparity to explore */
  int m_MaximumVerticalDisparity;

  /** Should we minimize or maximize ? */
  bool m_Minimize;

  /** The exploration radius for disparities (used if non null) */
  SizeType m_ExplorationRadius;

  /** Block-matching functor */
  BlockMatchingFunctorType m_Functor;

  /** Initial horizontal disparity (0 by default, used if an exploration radius is set and if no input horizontal
    disparity map is given) */
  int m_InitHorizontalDisparity;

  /** Initial vertical disparity (0 by default, used if an exploration radius is set and if no input vertical
    disparity map is given) */
  int m_InitVerticalDisparity;

  /** Computation step : disparities are computed on locations of a subsampled grid */
  unsigned int m_Step;

  /** Starting index for the subsampled grid. The index is measured with respect to the input image grid
   *  Each coordinate shall lie in [0, m_Step-1]
   */
  IndexType m_GridIndex;
};
} // end namespace otb

#ifndef OTB_MANUAL_INSTANTIATION
#include "otbPixelWiseBlockMatchingImageFilter.hxx"
#endif

#endif