File: otbMeanShiftSmoothingImageFilter.h

package info (click to toggle)
otb 6.6.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 47,068 kB
  • sloc: cpp: 316,755; ansic: 4,474; sh: 1,610; python: 497; perl: 92; makefile: 82; java: 72
file content (688 lines) | stat: -rw-r--r-- 25,088 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
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
/*
 * Copyright (C) 2005-2017 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 otbMeanShiftSmoothingImageFilter_h
#define otbMeanShiftSmoothingImageFilter_h

#include "otbImage.h"
#include "otbVectorImage.h"
#include "itkImageToImageFilter.h"
#include "itkImageRegionConstIterator.h"
#include "itkImageRegionConstIteratorWithIndex.h"
#include <vcl_algorithm.h>


namespace otb
{
namespace Meanshift
{

template<typename T> inline T simple_pow(T const& v, unsigned int p)
{
  T res = 1;
  for (unsigned int i = 0; i != p; ++i)
    {
    res *= v;
    }
  return res;
}

/** \class SpatialRangeJointDomainTransform
 *
 *
 * Functor returning the joint spatial-range representation of a pixel, i.e. the
 * concatenation of range components and coordinates as a vector. Components are
 * scaled by their respective spatial and range bandwidth.
 *
 * \ingroup OTBSmoothing
 */
template<class TInputImage, class TOutputJointImage>
class SpatialRangeJointDomainTransform
{
public:
  typedef double RealType;

  SpatialRangeJointDomainTransform()
  {
  }
  // ~SpatialRangeJointDomainTransform() {}

  typename TOutputJointImage::PixelType operator()(const typename TInputImage::PixelType & inputPixel,
                                                   const typename TInputImage::IndexType & index) const
  {
    typename TOutputJointImage::PixelType jointPixel(m_ImageDimension + m_NumberOfComponentsPerPixel);

    for (unsigned int comp = 0; comp < m_ImageDimension; comp++)
      {
      jointPixel[comp] = index[comp] + m_GlobalShift[comp];
      }
    for (unsigned int comp = 0; comp < m_NumberOfComponentsPerPixel; comp++)
      {
      jointPixel[m_ImageDimension + comp] = inputPixel[comp];
      }
    return jointPixel;
  }

  void Initialize(unsigned int _ImageDimension, unsigned int numberOfComponentsPerPixel_, typename TInputImage::IndexType globalShift_)
  {
    m_ImageDimension = _ImageDimension;
    m_NumberOfComponentsPerPixel = numberOfComponentsPerPixel_;
    m_OutputSize = m_ImageDimension + m_NumberOfComponentsPerPixel;
    m_GlobalShift = globalShift_;
  }

  unsigned int GetOutputSize() const
  {
    return m_OutputSize;
  }

private:
  unsigned int m_ImageDimension;
  unsigned int m_NumberOfComponentsPerPixel;
  unsigned int m_OutputSize;
  typename TInputImage::IndexType m_GlobalShift;
};

class KernelUniform
{
public:
  typedef double RealType;

  // KernelUniform() {}
  // ~KernelUniform() {}

  RealType operator()(RealType x) const
  {
    return (x <= 1) ? 1.0 : 0.0;
  }

  RealType GetRadius(RealType bandwidth) const
  {
    return bandwidth;
  }
};

class KernelGaussian
{
public:
  typedef double RealType;

  // KernelGaussian() {}
  // ~KernelGaussian() {}

  RealType operator()(RealType x) const
  {
    return vcl_exp(-0.5 * x);
  }

  RealType GetRadius(RealType bandwidth) const
  {
    return 3.0 * bandwidth;
  }
};

/** \class FastImageRegionConstIterator
 *
 * Iterator for reading pixels over an image region, specialized for faster
 * access to pixels in vector images through the method GetPixelPointer
 *
 * \ingroup OTBSmoothing
 */
template<typename TImage>
class FastImageRegionConstIterator: public itk::ImageRegionConstIterator<TImage>
{
public:
  /** Standard class typedef. */
  typedef FastImageRegionConstIterator<TImage> Self;
  typedef itk::ImageRegionConstIterator<TImage> Superclass;

  typedef typename Superclass::ImageType ImageType;
  typedef typename Superclass::RegionType RegionType;

  typedef typename TImage::PixelType PixelType;
  typedef typename TImage::InternalPixelType InternalPixelType;

  itkTypeMacro(FastImageRegionConstIterator, ImageRegionConstIterator)
;

  FastImageRegionConstIterator() :
    Superclass()
  {
  }
  FastImageRegionConstIterator(const ImageType *ptr, const RegionType &region) :
    Superclass(ptr, region)
  {
    m_NumberOfComponentsPerPixel = ptr->GetNumberOfComponentsPerPixel();
  }

  const InternalPixelType * GetPixelPointer() const
  {
    return this->m_Buffer + (this->m_Offset * m_NumberOfComponentsPerPixel);
  }

private:
  unsigned int m_NumberOfComponentsPerPixel;
};

#if 0 //disable bucket mode
/** \class BucketImage
 *
 * This class indexes pixels in a N-dimensional image into a N+1-dimensional
 * array of buckets. Each pixel is stored into one bucket depending on its
 * position on the lattice (the width of a bucket is given at construction) and
 * one spectral component (also given at construction by spectralCoordinate).
 *
 * The (spatially and spectrally) neighboring buckets of pixels can then be
 * obtained by using GetNeighborhoodBucketListIndices().
 *
 * \ingroup OTBSmoothing
 */
template<class TImage>
class BucketImage
{
public:
  typedef TImage ImageType;
  typedef typename ImageType::ConstPointer ImageConstPointerType;
  typedef typename ImageType::PixelType PixelType;
  typedef typename ImageType::InternalPixelType InternalPixelType;
  typedef typename ImageType::RegionType RegionType;
  typedef typename ImageType::IndexType IndexType;

  typedef double RealType;

  static const unsigned int ImageDimension = ImageType::ImageDimension;

  /** The bucket image has dimension N+1 (ie. usually 3D for most images) */
  typedef std::vector<typename ImageType::SizeType::SizeValueType> BucketImageSizeType;
  typedef std::vector<typename ImageType::IndexType::IndexValueType> BucketImageIndexType;
  //typedef std::vector<long> BucketImageIndexType;


  /** pixel buckets typedefs and declarations */
  typedef const typename ImageType::InternalPixelType * ImageDataPointerType;
  typedef std::vector<ImageDataPointerType> BucketType;
  typedef std::vector<BucketType> BucketListType;

  BucketImage()
  {
  }

  /** Constructor for the bucket image. It operates on the specified
   * region.
   * spatialRadius specifies the width of a bucket in pixels.
   * rangeRadius is the spectral width for the specified spectral coordinate in
   * one bucket.
   * spectralCoordinate is the index of the pixel used for classification in buckets.
   */
  BucketImage(ImageConstPointerType image, const RegionType & region, RealType spatialRadius, RealType rangeRadius,
              unsigned int spectralCoordinate) :
    m_Image(image), m_Region(region), m_SpatialRadius(spatialRadius), m_RangeRadius(rangeRadius),
        m_SpectralCoordinate(spectralCoordinate)
  {

    // Find max and min of the used spectral band
    itk::ImageRegionConstIterator<ImageType> inputIt(m_Image, m_Region);
    inputIt.GoToBegin();
    InternalPixelType minValue = inputIt.Get()[spectralCoordinate];
    InternalPixelType maxValue = minValue;
    ++inputIt;
    while (!inputIt.IsAtEnd())
      {
      const PixelType &p = inputIt.Get();
      minValue = vcl_min(minValue, p[m_SpectralCoordinate]);
      maxValue = vcl_max(maxValue, p[m_SpectralCoordinate]);
      ++inputIt;
      }

    m_MinValue = minValue;
    m_MaxValue = maxValue;

    // Compute bucket image dimensions. Note: empty buckets are at each border
    // to simplify image border issues
    m_DimensionVector.resize(ImageDimension + 1); // NB: pays for a 0-innit
    for (unsigned int dim = 0; dim < ImageDimension; ++dim)
      {
      m_DimensionVector[dim] = m_Region.GetSize()[dim] / m_SpatialRadius + 3;
      }
    m_DimensionVector[ImageDimension] = (unsigned int) ((maxValue - minValue) / m_RangeRadius) + 3;

    unsigned int numBuckets = m_DimensionVector[0];
    for (unsigned int dim = 1; dim <= ImageDimension; ++dim)
      numBuckets *= m_DimensionVector[dim];

    m_BucketList.resize(numBuckets);
    // Build buckets
    itk::ImageRegionConstIteratorWithIndex<ImageType> it(m_Image, m_Region);
    it.GoToBegin();
    // this iterator is only used to get the pixel data pointer
    FastImageRegionConstIterator<ImageType> fastIt(m_Image, m_Region);
    fastIt.GoToBegin();

    while (!it.IsAtEnd())
      {
      const IndexType & index = it.GetIndex();
      const PixelType & pixel = it.Get();

      // Find which bucket this pixel belongs to
      const BucketImageIndexType bucketIndex = GetBucketIndex(pixel, index);

      unsigned int bucketListIndex = BucketIndexToBucketListIndex(bucketIndex);
      assert(bucketListIndex < numBuckets);
      m_BucketList[bucketListIndex].push_back(fastIt.GetPixelPointer());
      ++it;
      ++fastIt;
      }

    // Prepare neighborhood offset vector
    // BucketImageIndexType zeroOffsetIndex(ImageDimension+1);
    std::vector<BucketImageIndexType> neighborsIndexList;
    neighborsIndexList.reserve(simple_pow(3, ImageDimension + 1));
    neighborsIndexList.resize(1, BucketImageIndexType(ImageDimension + 1)); // zeroOffsetIndex
    // neighborsIndexList.push_back(zeroOffsetIndex);
    for (unsigned dim = 0; dim <= ImageDimension; ++dim)
      {
      // take all neighbors already in the list and add their direct neighbor
      // along the current dim
      const unsigned int curSize = neighborsIndexList.size();
      for (unsigned int i = 0; i < curSize; ++i)
        {
        BucketImageIndexType index = neighborsIndexList[i];
        index[dim]--;
        neighborsIndexList.push_back(index);
        index[dim] += 2;
        neighborsIndexList.push_back(index);
        }
      }
    // Convert all neighbors n-dimensional indices to bucket list 1D indices
    const unsigned int neighborhoodOffsetVectorSize = neighborsIndexList.size();
    m_NeighborhoodOffsetVector.reserve(neighborhoodOffsetVectorSize);
    for (unsigned int i = 0; i < neighborhoodOffsetVectorSize; ++i)
      {
      const int listIndex = BucketIndexToBucketListIndex(neighborsIndexList[i]);
      m_NeighborhoodOffsetVector.push_back(listIndex);
      }
  }

  ~BucketImage()
  {
  }

  /** Returns the N+1-dimensional bucket index for a given pixel value at the given index */
  BucketImageIndexType GetBucketIndex(const PixelType & pixel, const IndexType & index)
  {
    BucketImageIndexType bucketIndex(ImageDimension + 1);
    for (unsigned int dim = 0; dim < ImageDimension; ++dim)
      {
      bucketIndex[dim] = (index[dim] - m_Region.GetIndex()[dim]) / m_SpatialRadius + 1;
      }
    bucketIndex[ImageDimension] = (pixel[m_SpectralCoordinate] - m_MinValue) / m_RangeRadius + 1;
    return bucketIndex;
  }

  /** Converts a N+1-dimensional bucket index into the 1D list index usable by
   GetBucket() */
  int BucketIndexToBucketListIndex(const BucketImageIndexType & bucketIndex) const
  {
    int bucketListIndex = bucketIndex[0];
    for (unsigned int dim = 1; dim <= ImageDimension; ++dim)
      {
      bucketListIndex = bucketListIndex * m_DimensionVector[dim] + bucketIndex[dim];
      }
    return bucketListIndex;
  }

  /** Retrieves the list of all buckets in the neighborhood of the given bucket */
  std::vector<unsigned int> GetNeighborhoodBucketListIndices(int bucketIndex) const
  {
    const unsigned int neighborhoodOffsetVectorSize = m_NeighborhoodOffsetVector.size();
    std::vector<unsigned int> indices(neighborhoodOffsetVectorSize);

    for (unsigned int i = 0; i < neighborhoodOffsetVectorSize; ++i)
      {
      indices[i] = bucketIndex + m_NeighborhoodOffsetVector[i];
      }
    return indices;
  }

  /* Returns the list of pixels (actually pointer to pixel data) contained in a bucket */
  const BucketType & GetBucket(unsigned int index) const
  {
    return m_BucketList[index];
  }

  unsigned int GetNumberOfNeighborBuckets() const
  {
    return m_NeighborhoodOffsetVector.size();
  }

private:
  /** Input image */
  ImageConstPointerType m_Image;
  /** Processed region */
  RegionType m_Region;

  /** Spatial radius of one bucket of pixels */
  RealType m_SpatialRadius;
  /** Range radius (at a single dimension) of one bucket of pixels */
  RealType m_RangeRadius;
  /** pixels are separated in buckets depending on their spatial position and
   also their value at one coordinate */
  unsigned int m_SpectralCoordinate;
  /** Min and Max of selected spectral coordinate */
  InternalPixelType m_MinValue;
  InternalPixelType m_MaxValue;

  /** the buckets are stored in this list */
  BucketListType m_BucketList;
  /** This vector holds the dimensions of the 3D (ND?) bucket image */
  BucketImageSizeType m_DimensionVector;
  /** Vector of offsets in the buckets list to get all buckets in the
   * neighborhood
   */
  std::vector<int> m_NeighborhoodOffsetVector;
};
#endif

} // end namespace Meanshift

/** \class MeanShiftSmoothingImageFilter
 *
 *
 * Mean shift is an edge-preserving smoothing algorithm often used in image
 * processing and segmentation. It will iteratively smooth a given pixel with
 * its neighbors that are within a spatial distance (set using
 * SetSpatialBandwidth()) and within a spectral range (set using
 * SetRangeBandwidth()). The resulting filtered image can be retrieved by
 * GetOutput() or GetRangeOutput(). Parameter SetRangeBandwidthRamp()
 * allows linearly adapting the range bandwidth to the intensity of
 * each channel if set greater than 0 (default value is 0).
 *
 * There are additional output images, as explained below.
 * Internally, the algorithm will iteratively update a pixel both in position
 * and spectral value, with respect to its neighbors, until convergence to a
 * local mode. The map of the distance traveled by pixels is obtained by
 * GetSpatialOutput(). A map of detected local modes is also available in
 * GetLabelOutput() if mode search is set to true (default set to false)
 * and can be seen as a first segmentation of the input image,
 * although usually highly oversegmented.
 * Finally, GetIterationOutput() will return the number of algorithm iterations
 * for each pixel.
 *
 * The class template parameter TKernel allows one to choose how pixels in the
 * spatial and spectral neighborhood of a given pixel participate in the
 * smoothed result. By default, a uniform kernel is used (KernelUniform), giving
 * an equal weight to all neighbor pixels. KernelGaussian can also be used,
 * although the computation time is significantly higher. The TKernel class
 * should define operator(), taking a squared norm as parameter and returning a
 * real value between 0 and 1. It should also define GetRadius(), converting the
 * spatial bandwidth parameter to the spatial radius defining how many pixels
 * are in the processing window local to a pixel.
 *
 * MeanShifVector squared norm is compared with Threshold (set using Get/Set accessor) to define pixel convergence (1e-3 by default).
 * MaxIterationNumber defines maximum iteration number for each pixel convergence (set using Get/Set accessor). Set to 4 by default.
 * ModeSearch is a boolean value, to choose between optimized and non optimized algorithm. If set to true (by default), assign mode value to each pixel on a path covered in convergence steps.
 *
 * For more information on mean shift techniques, one might consider reading the following article:
 *
 * D. Comaniciu, P. Meer, "Mean Shift: A Robust Approach Toward Feature Space Analysis," IEEE Transactions on
 * Pattern Analysis and Machine Intelligence, vol. 24, no. 5, pp. 603-619, May, 2002
 * D. Comaniciu, P. Meer, "Robust analysis of feature spaces: color image segmentation," cvpr, p. 750, 1997
 * IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR'97), 1997
 * D. Comaniciu, P. Meer, "Mean Shift Analysis and Applications," iccv, p. 1197, Seventh International Conference
 * on Computer Vision (ICCV'99) - Volume 2, 1999
 *
 * \sa MeanShiftSegmentationFilter
 *
 * \ingroup ImageSegmentation
 * \ingroup ImageEnhancement
 *
 * \ingroup OTBSmoothing
 */
template<class TInputImage, class TOutputImage, class TKernel = Meanshift::KernelUniform,
    class TOutputIterationImage = otb::Image<unsigned int, TInputImage::ImageDimension> >
class ITK_EXPORT MeanShiftSmoothingImageFilter: public itk::ImageToImageFilter<TInputImage, TOutputImage>
{
public:
  /** Standard class typedef */
  typedef MeanShiftSmoothingImageFilter Self;
  typedef itk::ImageToImageFilter<TInputImage, TOutputImage> Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
  typedef double RealType;

  /** Type macro */
  itkTypeMacro(MeanShiftSmoothingImageFilter, ImageToImageFilter)
; itkNewMacro(Self)
;

  /** Template parameters typedefs */

  typedef TInputImage InputImageType;
  typedef typename InputImageType::Pointer InputImagePointerType;
  typedef typename InputImageType::PixelType InputPixelType;
  typedef typename InputImageType::IndexType InputIndexType;
  typedef typename InputImageType::SizeType InputSizeType;
  typedef typename InputImageType::IndexValueType InputIndexValueType;
  typedef typename InputImageType::PointType PointType;
  typedef typename InputImageType::RegionType RegionType;
  typedef typename InputImageType::SizeType SizeType;

  typedef TOutputImage OutputImageType;
  typedef typename OutputImageType::Pointer OutputImagePointerType;
  typedef typename OutputImageType::PixelType OutputPixelType;
  typedef typename OutputImageType::RegionType OutputRegionType;

  typedef TOutputIterationImage OutputIterationImageType;

  typedef unsigned long LabelType;
  typedef otb::Image<LabelType, InputImageType::ImageDimension> OutputLabelImageType;

  typedef otb::VectorImage<RealType, InputImageType::ImageDimension> OutputSpatialImageType;
  typedef typename OutputSpatialImageType::Pointer OutputSpatialImagePointerType;
  typedef typename OutputSpatialImageType::PixelType OutputSpatialPixelType;

  typedef TKernel KernelType;

  itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension);

  typedef itk::VariableLengthVector<RealType> RealVector;
  typedef otb::VectorImage<RealType, InputImageType::ImageDimension> RealVectorImageType;
  typedef otb::Image<unsigned short, InputImageType::ImageDimension> ModeTableImageType;

  /** Sets the spatial bandwidth (or radius in the case of a uniform kernel)
   * of the neighborhood for each pixel
   */
  itkSetMacro(SpatialBandwidth, RealType);
  itkGetConstReferenceMacro(SpatialBandwidth, RealType);

  /** Sets the spectral bandwidth (or radius for a uniform kernel) for pixels
   * to be included in the same mode
   */
  itkSetMacro(RangeBandwidth, RealType);
  itkGetConstReferenceMacro(RangeBandwidth, RealType);

   /** Sets the range bandwidth ramp. If > 0, the range bandwidth
    * will be y = RangeBandwidthRamp * x + RangeBandwidth, where x is
    * the band value. */
  itkSetMacro(RangeBandwidthRamp, RealType);
  itkGetConstReferenceMacro(RangeBandwidthRamp,RealType);

  /** Sets the maximum number of algorithm iterations */
  itkGetConstReferenceMacro(MaxIterationNumber, unsigned int);
  itkSetMacro(MaxIterationNumber, unsigned int);

  /** Sets the threshold value for the mean shift vector's squared norm,
   * under which convergence is assumed
   */
  itkGetConstReferenceMacro(Threshold, double);
  itkSetMacro(Threshold, double);

  /** Toggle mode search, which is enabled by default.
   * When off, the output label image is not available
   * Be careful, with this option, the result will slightly depend on thread number.
   */
  itkSetMacro(ModeSearch, bool);
  itkGetConstReferenceMacro(ModeSearch, bool);

#if 0
  /** Toggle bucket optimization, which is disabled by default.
   */
  itkSetMacro(BucketOptimization, bool);
  itkGetConstReferenceMacro(BucketOptimization, bool);
#endif

  /** Global shift allows tackling down numerical instabilities by
  aligning pixel indices when performing tile processing */
  itkSetMacro(GlobalShift,InputIndexType);

  /** Returns the const spatial image output,spatial image output is a displacement map (pixel position after convergence minus pixel index)  */
  const OutputSpatialImageType * GetSpatialOutput() const;
  /** Returns the const spectral image output */
  const OutputImageType * GetRangeOutput() const;
  /** Returns the const number of iterations map. */
  const OutputIterationImageType * GetIterationOutput() const;
  /** Returns the const image of region labels. This output does not have sense without mode search optimization (each label codes for one mode)*/
  const OutputLabelImageType * GetLabelOutput() const;

  /** Returns the spatial image output,spatial image output is a displacement map (pixel position after convergence minus pixel index)  */
  OutputSpatialImageType * GetSpatialOutput();
  /** Returns the spectral image output */
  OutputImageType * GetRangeOutput();
  /** Returns the number of iterations done at each pixel */
  OutputIterationImageType * GetIterationOutput();
  /** Returns the image of region labels. This output does not have sense without mode search optimization (each label codes for one mode) */
  OutputLabelImageType * GetLabelOutput();

protected:

  /** GenerateOutputInformation
   *  Define output pixel size
   *
   **/
  void GenerateOutputInformation(void) override;

  void GenerateInputRequestedRegion() override;

  void BeforeThreadedGenerateData() override;

  /** MeanShiftFilter can be implemented as a multithreaded filter.
   * Therefore, this implementation provides a ThreadedGenerateData()
   * routine which is called for each processing thread. The output
   * image data is allocated automatically by the superclass prior to
   * calling ThreadedGenerateData().  ThreadedGenerateData can only
   * write to the portion of the output image specified by the
   * parameter "outputRegionForThread"
   *
   * \sa ImageToImageFilter::ThreadedGenerateData(),
   *     ImageToImageFilter::GenerateData() */
  void ThreadedGenerateData(const OutputRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;

  void AfterThreadedGenerateData() override;

  /** Allocates the outputs (need to be reimplemented since outputs have different type) */
  void AllocateOutputs() override;

  /** Constructor */
  MeanShiftSmoothingImageFilter();

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

  /** PrintSelf method */
  void PrintSelf(std::ostream& os, itk::Indent indent) const override;

  virtual void CalculateMeanShiftVector(const typename RealVectorImageType::Pointer inputImagePtr,
                                        const RealVector& jointPixel, const OutputRegionType& outputRegion,
                                        const RealVector& bandwidth,
                                        RealVector& meanShiftVector);
#if 0
  virtual void CalculateMeanShiftVectorBucket(const RealVector& jointPixel, RealVector& meanShiftVector);
#endif

private:
  MeanShiftSmoothingImageFilter(const Self &); //purposely not implemented
  void operator =(const Self&); //purposely not implemented

  /** Range bandwidth */
  RealType m_RangeBandwidth;

  /** Coefficient */
  RealType m_RangeBandwidthRamp;

  /** Spatial bandwidth */
  RealType m_SpatialBandwidth;

  /** Radius of pixel neighborhood, determined by the kernel from the spatial bandwidth  */
  InputSizeType m_SpatialRadius;

  /** Threshold on the squared norm of the mean shift vector to decide when to stop iterating **/
  double m_Threshold;

  /** Maximum number of iterations **/
  unsigned int m_MaxIterationNumber;

  /** Kernel object, implementing operator() which returns a weight between 0 and 1
   * depending on the squared norm given in parameter **/
  KernelType m_Kernel;

  /** Number of components per pixel in the input image */
  unsigned int m_NumberOfComponentsPerPixel;

  /** Input data in the joint spatial-range domain, scaled by the bandwidths */
  typename RealVectorImageType::Pointer m_JointImage;

  /** Image to store the status at each pixel:
   * 0 : no mode has been found yet
   * 1 : a mode has been assigned to this pixel
   * 2 : pixel is in the path of the currently processed pixel and a mode will
   *     be assigned to it
   */
  typename ModeTableImageType::Pointer m_ModeTable;

  /** Boolean to enable mode search  */
  bool m_ModeSearch;

#if 0
  /** Boolean to enable bucket optimization */
  bool m_BucketOptimization;
#endif

  /** Mode counters (local to each thread) */
  itk::VariableLengthVector<LabelType> m_NumLabels;
  /** Number of bits used to represent the threadId in the most significant bits
   of labels */
  unsigned int m_ThreadIdNumberOfBits;

#if 0
  typedef Meanshift::BucketImage<RealVectorImageType> BucketImageType;
  BucketImageType m_BucketImage;
#endif

  InputIndexType m_GlobalShift;

};

} // end namespace otb

#ifndef OTB_MANUAL_INSTANTIATION
#include "otbMeanShiftSmoothingImageFilter.txx"
#endif

#endif