From 38a0b18ccaa76670da9c4ff754d9df0118097ca3 Mon Sep 17 00:00:00 2001
From: Aurelien Bricier <aurelien.bricier@c-s.fr>
Date: Mon, 11 Oct 2010 16:32:19 +0200
Subject: [PATCH] ENH: one-pass computation of the 11 flusser moments

---
 .../otbFlusserImageFunction.h                 | 280 ++++++-------
 .../otbFlusserImageFunction.txx               | 381 +++++++-----------
 .../FlusserMomentImageExample.cxx             |  19 +-
 .../FeatureExtraction/otbFlusserImage.cxx     |  37 +-
 4 files changed, 312 insertions(+), 405 deletions(-)

diff --git a/Code/FeatureExtraction/otbFlusserImageFunction.h b/Code/FeatureExtraction/otbFlusserImageFunction.h
index d5eac225cd..9bacb02c61 100644
--- a/Code/FeatureExtraction/otbFlusserImageFunction.h
+++ b/Code/FeatureExtraction/otbFlusserImageFunction.h
@@ -1,138 +1,142 @@
-/*=========================================================================
-
-  Program:   ORFEO Toolbox
-  Language:  C++
-  Date:      $Date$
-  Version:   $Revision$
-
-
-  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
-  See OTBCopyright.txt for details.
-
-
-     This software is distributed WITHOUT ANY WARRANTY; without even
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-     PURPOSE.  See the above copyright notices for more information.
-
-=========================================================================*/
-#ifndef __otbFlusserImageFunction_h
-#define __otbFlusserImageFunction_h
-
-#include "otbRealMomentImageFunction.h"
-
-#include <complex>
-
-namespace otb
-{
-
-/**
- * \class FlusserImageFunction
- * \brief Calculate the Flusser's invariant parameters.
- *
- * Calculate the Flusser's invariant over an image defined as:
- *
- * - \f$ \psi_{1} = c_{11} \f$
- * - \f$ \psi_{2} = c_{21} c_{12} \f$
- * - \f$ \psi_{3} = Re (c_{20} c_{12}^{2} )\f$
- * - \f$ \psi_{4} = Im (c_{20} c_{12}^{2} )\f$
- * - \f$ \psi_{5} = Re (c_{30} c_{12}^{3} )\f$
- * - \f$ \psi_{6} = Im (c_{30} c_{12}^{3} )\f$
- * - \f$ \psi_{7} = c_{22} \f$
- * - \f$ \psi_{8} = Re (c_{31} c_{12}^{2} )\f$
- * - \f$ \psi_{9} = Im (c_{31} c_{12}^{2} )\f$
- * - \f$ \psi_{10} = Re (c_{40} c_{12}^{4} )\f$
- * - \f$ \psi_{11} = Im (c_{40} c_{12}^{4} )\f$
- *
- * With :
- *
- *  \f[  c_{p,q}=\int_{-\infty}^{\infty} \int_{-\infty}^{\infty} (x+iy)^{p} \cdot (x-iy)^{q} \cdot f(x,y) \cdot
- dx \cdot dy \f]
- *
- * And:
- *  - \f$(x,y)\f$ pixel localization;
- *  - \f$ f(x,y)\f$ the pixel value over the \f$(x,y)\f$ coordinate.
- *
- * This class is templated over the input image type and the
- * coordinate representation type (e.g. float or double).
- *
- * \ingroup ImageFunctions
- */
-
-template <class TInput,
-    class TOutput    = double,
-    class TPrecision = double,
-    class TCoordRep  = float>
-class ITK_EXPORT FlusserImageFunction :
-  public RealMomentImageFunction<TInput, TOutput, TPrecision, TCoordRep>
-{
-public:
-  /** Standard class typedefs. */
-  typedef FlusserImageFunction                                            Self;
-  typedef RealMomentImageFunction<TInput, TOutput, TPrecision, TCoordRep> Superclass;
-  typedef itk::SmartPointer<Self>                                         Pointer;
-  typedef itk::SmartPointer<const Self>                                   ConstPointer;
-
-  /** Run-time type information (and related methods). */
-  itkTypeMacro(FlusserImageFunction, RealMomentImageFunction);
-
-  /** Method for creation through the object factory. */
-  itkNewMacro(Self);
-
-  /** InputImageType typedef support. */
-  typedef TInput                                   InputType;
-  typedef typename Superclass::IndexType           IndexType;
-  typedef typename Superclass::ContinuousIndexType ContinuousIndexType;
-  typedef typename Superclass::PointType           PointType;
-
-  typedef typename Superclass::RealType   RealType;
-  typedef typename std::complex<RealType> ComplexType;
-
-  /** Type for calculation precision */
-  typedef typename Superclass::PrecisionType PrecisionType;
-
-  /** Dimension of the underlying image. */
-  itkStaticConstMacro(ImageDimension, unsigned int,
-                      InputType::ImageDimension);
-
-  /** Evalulate the function at specified index */
-  virtual RealType EvaluateAtIndex(const IndexType& index) const;
-
-  /** Evaluate the function at non-integer positions */
-  virtual RealType Evaluate(const PointType& point) const
-  {
-    IndexType index;
-    this->ConvertPointToNearestIndex(point, index);
-    return this->EvaluateAtIndex(index);
-  }
-  virtual RealType EvaluateAtContinuousIndex(
-    const ContinuousIndexType& cindex) const
-  {
-    IndexType index;
-    this->ConvertContinuousIndexToNearestIndex(cindex, index);
-    return this->EvaluateAtIndex(index);
-  }
-
-  /** Get/Set the radius of the neighborhood over which the
-      statistics are evaluated */
-  itkSetClampMacro(MomentNumber, short, 1, 11);
-  itkGetConstReferenceMacro(MomentNumber, short);
-
-protected:
-  FlusserImageFunction();
-  virtual ~FlusserImageFunction() {}
-  void PrintSelf(std::ostream& os, itk::Indent indent) const;
-
-private:
-  FlusserImageFunction(const Self &);  //purposely not implemented
-  void operator =(const Self&);  //purposely not implemented
-
-  short m_MomentNumber;
-};
-
-} // namespace otb
-
-#ifndef OTB_MANUAL_INSTANTIATION
-#include "otbFlusserImageFunction.txx"
-#endif
-
-#endif
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __otbFlusserImageFunction_h
+#define __otbFlusserImageFunction_h
+
+#include "itkImageFunction.h"
+#include "itkFixedArray.h"
+
+namespace otb
+{
+
+/**
+ * \class FlusserImageFunction
+ * \brief Calculate the Flusser's invariant parameters.
+ *
+ * Calculate the Flusser's invariant over an image defined as:
+ *
+ * - \f$ \psi_{1} = c_{11} \f$
+ * - \f$ \psi_{2} = c_{21} c_{12} \f$
+ * - \f$ \psi_{3} = Re (c_{20} c_{12}^{2} )\f$
+ * - \f$ \psi_{4} = Im (c_{20} c_{12}^{2} )\f$
+ * - \f$ \psi_{5} = Re (c_{30} c_{12}^{3} )\f$
+ * - \f$ \psi_{6} = Im (c_{30} c_{12}^{3} )\f$
+ * - \f$ \psi_{7} = c_{22} \f$
+ * - \f$ \psi_{8} = Re (c_{31} c_{12}^{2} )\f$
+ * - \f$ \psi_{9} = Im (c_{31} c_{12}^{2} )\f$
+ * - \f$ \psi_{10} = Re (c_{40} c_{12}^{4} )\f$
+ * - \f$ \psi_{11} = Im (c_{40} c_{12}^{4} )\f$
+ *
+ * With :
+ *
+ *  \f[  c_{p,q}=\int_{-\infty}^{\infty} \int_{-\infty}^{\infty} (x+iy)^{p} \cdot (x-iy)^{q} \cdot f(x,y) \cdot
+ dx \cdot dy \f]
+ *
+ * And:
+ *  - \f$(x,y)\f$ pixel localization;
+ *  - \f$ f(x,y)\f$ the pixel value over the \f$(x,y)\f$ coordinate.
+ *
+ * This class is templated over the input image type and the
+ * coordinate representation type (e.g. float or double).
+ *
+ * \ingroup ImageFunctions
+ */
+
+template <class TInputImage, class TCoordRep = float >
+class ITK_EXPORT FlusserImageFunction :
+  public itk::ImageFunction< TInputImage,
+    itk::FixedArray<
+    ITK_TYPENAME itk::NumericTraits<typename TInputImage::PixelType>::RealType,
+    11 >,
+    TCoordRep >
+{
+public:
+  /** Standard class typedefs. */
+  typedef FlusserImageFunction                                            Self;
+  typedef itk::ImageFunction< TInputImage,
+		   itk::FixedArray<
+		   ITK_TYPENAME itk::NumericTraits<
+		   typename TInputImage::PixelType>::RealType,
+		   11 >,
+		    TCoordRep >                                           Superclass;
+  typedef itk::SmartPointer<Self>                                         Pointer;
+  typedef itk::SmartPointer<const Self>                                   ConstPointer;
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(FlusserImageFunction, ImageFunction);
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** InputImageType typedef support. */
+  typedef TInputImage                              InputImageType;
+  typedef typename Superclass::IndexType           IndexType;
+  typedef typename Superclass::ContinuousIndexType ContinuousIndexType;
+  typedef typename Superclass::PointType           PointType;
+
+  typedef typename Superclass::OutputType          RealType;
+  typedef typename RealType::ValueType             ScalarRealType;
+
+  /** Dimension of the underlying image. */
+  itkStaticConstMacro(ImageDimension, unsigned int,
+                      InputImageType::ImageDimension);
+
+  /** Evalulate the function at specified index */
+  virtual RealType EvaluateAtIndex(const IndexType& index) const;
+
+  /** Evaluate the function at non-integer positions */
+  virtual RealType Evaluate(const PointType& point) const
+  {
+    IndexType index;
+    this->ConvertPointToNearestIndex(point, index);
+    return this->EvaluateAtIndex(index);
+  }
+  virtual RealType EvaluateAtContinuousIndex(
+    const ContinuousIndexType& cindex) const
+  {
+    IndexType index;
+    this->ConvertContinuousIndexToNearestIndex(cindex, index);
+    return this->EvaluateAtIndex(index);
+  }
+
+  /** Get/Set the radius of the neighborhood over which the
+   *  statistics are evaluated 
+   */
+  itkSetMacro( NeighborhoodRadius, unsigned int );
+  itkGetConstReferenceMacro( NeighborhoodRadius, unsigned int );
+
+protected:
+  FlusserImageFunction();
+  virtual ~FlusserImageFunction() {}
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+  FlusserImageFunction(const Self &);  //purposely not implemented
+  void operator =(const Self&);  //purposely not implemented
+
+  unsigned int m_NeighborhoodRadius;
+};
+
+} // namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbFlusserImageFunction.txx"
+#endif
+
+#endif
+
diff --git a/Code/FeatureExtraction/otbFlusserImageFunction.txx b/Code/FeatureExtraction/otbFlusserImageFunction.txx
index e8274de0b8..a0f5bf8d2e 100644
--- a/Code/FeatureExtraction/otbFlusserImageFunction.txx
+++ b/Code/FeatureExtraction/otbFlusserImageFunction.txx
@@ -1,230 +1,151 @@
-/*=========================================================================
-
-  Program:   ORFEO Toolbox
-  Language:  C++
-  Date:      $Date$
-  Version:   $Revision$
-
-
-  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
-  See OTBCopyright.txt for details.
-
-
-     This software is distributed WITHOUT ANY WARRANTY; without even
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-     PURPOSE.  See the above copyright notices for more information.
-
-=========================================================================*/
-#ifndef __otbFlusserImageFunction_txx
-#define __otbFlusserImageFunction_txx
-
-#include "otbFlusserImageFunction.h"
-#include "otbComplexMomentImageFunction.h"
-#include "itkNumericTraits.h"
-#include "itkMacro.h"
-#include <complex>
-
-namespace otb
-{
-
-/**
-   * Constructor
-   */
-template <class TInput, class TOutput, class TPrecision, class TCoordRep>
-FlusserImageFunction<TInput, TOutput, TPrecision, TCoordRep>
-::FlusserImageFunction()
-{
-  m_MomentNumber = -1;
-}
-
-/**
-   *
-   */
-template <class TInput, class TOutput, class TPrecision, class TCoordRep>
-void
-FlusserImageFunction<TInput, TOutput, TPrecision, TCoordRep>
-::PrintSelf(std::ostream& os, itk::Indent indent) const
-{
-  this->Superclass::PrintSelf(os, indent);
-  os << indent << " m_MomentNumber           : "  << m_MomentNumber << std::endl;
-}
-
-template <class TInput, class TOutput, class TPrecision, class TCoordRep>
-typename FlusserImageFunction<TInput, TOutput, TPrecision, TCoordRep>::RealType
-FlusserImageFunction<TInput, TOutput, TPrecision, TCoordRep>
-::EvaluateAtIndex(const IndexType& index) const
-{
-
-  RealType                            FlusserValue(itk::NumericTraits<RealType>::Zero);
-  ComplexType                         FlusserValueComplex(itk::NumericTraits<ComplexType>::Zero);
-
-  typedef otb::ComplexMomentImageFunction<InputType, ComplexType> CMType;
-  typename CMType::Pointer function = CMType::New();
-
-  if (!this->GetInputImage())
-    {
-    return (itk::NumericTraits<RealType>::max());
-    }
-
-  if (!this->IsInsideBuffer(index))
-    {
-    return (itk::NumericTraits<RealType>::max());
-    }
-
-  assert(m_MomentNumber > 0);
-  assert(m_MomentNumber < 12);
-
-  function->SetInputImage(this->GetInputImage());
-  function->SetNeighborhoodRadius(this->GetNeighborhoodRadius());
-
-  switch (m_MomentNumber)
-    {
-    case 1:
-      {
-      ComplexType C11;
-      function->SetP(1);
-      function->SetQ(1);
-      C11 = function->EvaluateAtIndex(index);
-      FlusserValue = C11.real();
-      }
-      break;
-    case 2:
-      {
-      ComplexType C21, C12;
-      function->SetP(2);
-      function->SetQ(1);
-      C21 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-
-      FlusserValue = vcl_abs(C21 * C12);
-      }
-      break;
-    case 3:
-      {
-      ComplexType C20, C12;
-      function->SetP(2);
-      function->SetQ(0);
-      C20 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C20 * vcl_pow(C12, 2);
-      FlusserValue = FlusserValueComplex.real();
-      }
-      break;
-    case 4:
-      {
-      ComplexType C20, C12;
-      function->SetP(2);
-      function->SetQ(0);
-      C20 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C20 * vcl_pow(C12, 2);
-      FlusserValue = FlusserValueComplex.imag();
-      }
-      break;
-    case 5:
-      {
-      ComplexType C30, C12;
-      function->SetP(3);
-      function->SetQ(0);
-      C30 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-
-      FlusserValueComplex = C30 * vcl_pow(C12, 3);
-      FlusserValue = FlusserValueComplex.real();
-      }
-      break;
-    case 6:
-      {
-      ComplexType C30, C12;
-      function->SetP(3);
-      function->SetQ(0);
-      C30 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-
-      FlusserValueComplex = C30 * vcl_pow(C12, 3);
-      FlusserValue = FlusserValueComplex.imag();
-      }
-      break;
-    case 7:
-      {
-      ComplexType C22;
-      function->SetP(2);
-      function->SetQ(2);
-      C22 = function->EvaluateAtIndex(index);
-      FlusserValue = C22.real();
-      }
-      break;
-    case 8:
-      {
-      ComplexType C31, C12;
-      function->SetP(3);
-      function->SetQ(1);
-      C31 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C31 * vcl_pow(C12, 2);
-      FlusserValue = FlusserValueComplex.real();
-      }
-      break;
-    case 9:
-      {
-      ComplexType C31, C12;
-      function->SetP(3);
-      function->SetQ(1);
-      C31 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C31 * vcl_pow(C12, 2);
-      FlusserValue = FlusserValueComplex.imag();
-      }
-      break;
-    case 10:
-      {
-      ComplexType C40, C12;
-      function->SetP(4);
-      function->SetQ(0);
-      C40 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C40 * vcl_pow(C12, 4);
-      FlusserValue = FlusserValueComplex.real();
-      }
-      break;
-    case 11:
-      {
-      ComplexType C40, C12;
-      function->SetP(4);
-      function->SetQ(0);
-      C40 = function->EvaluateAtIndex(index);
-      function->SetP(1);
-      function->SetQ(2);
-      C12 = function->EvaluateAtIndex(index);
-      FlusserValueComplex = C40 * vcl_pow(C12, 4);
-      FlusserValue = FlusserValueComplex.imag();
-      }
-      break;
-
-    default:
-      itkWarningMacro("Hu's invariant parameters are between 1 and 7");
-    }
-
-  return (static_cast<RealType>(FlusserValue));
-
-}
-
-} // namespace otb
-
-#endif
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __otbFlusserImageFunction_txx
+#define __otbFlusserImageFunction_txx
+
+#include "otbFlusserImageFunction.h"
+#include "itkConstNeighborhoodIterator.h"
+#include "itkNumericTraits.h"
+#include "itkMacro.h"
+#include <complex>
+
+namespace otb
+{
+
+/**
+ * Constructor
+ */
+template <class TInputImage, class TCoordRep>
+FlusserImageFunction<TInputImage, TCoordRep>
+::FlusserImageFunction()
+{
+  m_NeighborhoodRadius = 1;
+}
+
+template <class TInputImage, class TCoordRep>
+void
+FlusserImageFunction<TInputImage, TCoordRep>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  this->Superclass::PrintSelf(os, indent);
+}
+
+template <class TInputImage, class TCoordRep>
+typename FlusserImageFunction<TInputImage,TCoordRep>::RealType
+FlusserImageFunction<TInputImage,TCoordRep>
+::EvaluateAtIndex(const IndexType& index) const
+{
+  // Build moments vector
+  RealType moments;
+  
+  // Initialize moments
+  moments.Fill( itk::NumericTraits< ScalarRealType >::Zero );
+  
+  // Check for input image
+  if( !this->GetInputImage() )
+    {
+    return moments;
+    }
+  
+  // Check for out of buffer
+  if ( !this->IsInsideBuffer( index ) )
+    {
+    return moments;
+    }
+  
+  // Define complex type
+  typedef std::complex<ScalarRealType> ComplexType;
+  
+  // Define and intialize cumulants for complex moments
+  ComplexType c11, c12, c21,c20, c30, c22, c31, c40;
+  c11 = itk::NumericTraits<ComplexType>::Zero;
+  c12 = itk::NumericTraits<ComplexType>::Zero;
+  c21 = itk::NumericTraits<ComplexType>::Zero;
+  c20 = itk::NumericTraits<ComplexType>::Zero;
+  c30 = itk::NumericTraits<ComplexType>::Zero;
+  c22 = itk::NumericTraits<ComplexType>::Zero;
+  c31 = itk::NumericTraits<ComplexType>::Zero;
+  c40 = itk::NumericTraits<ComplexType>::Zero;
+  
+  ScalarRealType c00 = itk::NumericTraits<ScalarRealType>::Zero;
+    
+  // Create an N-d neighborhood kernel, using a zeroflux boundary condition
+  typename InputImageType::SizeType kernelSize;
+  kernelSize.Fill( m_NeighborhoodRadius );
+  
+  itk::ConstNeighborhoodIterator<InputImageType>
+    it(kernelSize, this->GetInputImage(), this->GetInputImage()->GetBufferedRegion());
+  
+  // Set the iterator at the desired location
+  it.SetLocation(index);
+  
+  // Walk the neighborhood
+  const unsigned int size = it.Size();
+  for (unsigned int i = 0; i < size; ++i)
+    {
+    // Retrieve value, and centered-reduced position
+    ScalarRealType value = static_cast<ScalarRealType>(it.GetPixel(i));
+    ScalarRealType x = static_cast<ScalarRealType>(it.GetOffset(i)[0]);
+    ScalarRealType y = static_cast<ScalarRealType>(it.GetOffset(i)[1]);
+    
+    // Build complex value
+    ComplexType xpy(x,y),xmy(x,-y);
+    
+    // Update cumulants
+    c00+=value;
+    c11+=xpy*xmy*value;
+    c12+=xpy*xmy*xmy*value;
+    c21+=xpy*xpy*xmy*value;
+    c20+=xpy*xpy*value;
+    c30+=xpy*xpy*xpy*value;
+    c22+=xpy*xpy*xmy*xmy*value;
+    c31+=xpy*xpy*xpy*xmy*value;
+    c40+=xpy*xpy*xpy*xpy*value;
+    }
+  
+  // Nomalisation
+  c11/=vcl_pow(c00, (1+1)/2);
+  c12/=vcl_pow(c00, (1+2)/2);
+  c21/=vcl_pow(c00, (2+1)/2);
+  c20/=vcl_pow(c00, (2+0)/2);
+  c30/=vcl_pow(c00, (3+0)/2);
+  c22/=vcl_pow(c00, (2+2)/2);
+  c31/=vcl_pow(c00, (3+1)/2);
+  c40/=vcl_pow(c00, (4+0)/2);
+  
+  // Compute moments combinations
+  moments[0]  = static_cast<ScalarRealType>(c11.real());
+  moments[1]  = static_cast<ScalarRealType>((c21*c12).real());
+  moments[2]  = static_cast<ScalarRealType>((c20*c12*c12).real());
+  moments[3]  = static_cast<ScalarRealType>((c20*c12*c12).imag());
+  moments[4]  = static_cast<ScalarRealType>((c30*c12*c12*c12).real());
+  moments[5]  = static_cast<ScalarRealType>((c30*c12*c12*c12).imag());
+  moments[6]  = static_cast<ScalarRealType>(c22.real());
+  moments[7]  = static_cast<ScalarRealType>((c31*c12*c12).real());
+  moments[8]  = static_cast<ScalarRealType>((c31*c12*c12).imag());
+  moments[9]  = static_cast<ScalarRealType>((c40*c12*c12*c12*c12).real());
+  moments[10] = static_cast<ScalarRealType>((c40*c12*c12*c12*c12).imag());
+  
+  // Return result
+  return moments;
+}
+
+} // namespace otb
+
+#endif
+
diff --git a/Examples/FeatureExtraction/FlusserMomentImageExample.cxx b/Examples/FeatureExtraction/FlusserMomentImageExample.cxx
index 0dd0f47b45..97a9b9be0f 100644
--- a/Examples/FeatureExtraction/FlusserMomentImageExample.cxx
+++ b/Examples/FeatureExtraction/FlusserMomentImageExample.cxx
@@ -47,13 +47,12 @@ int main(int argc, char * argv[])
   if (argc != 3)
     {
     std::cerr << "Usage: " << argv[0] << " inputImageFile ";
-    std::cerr << " moment_number" << std::endl;
+    std::cerr << " neighborhood_radius" << std::endl;
     return EXIT_FAILURE;
     }
 
   const char * inputFilename  = argv[1];
-
-  unsigned int mMomentNumber((unsigned char) ::atoi(argv[2]));
+  const unsigned int radius   = atoi(argv[2]);
 
   typedef unsigned char InputPixelType;
   const unsigned int Dimension = 2;
@@ -75,9 +74,8 @@ int main(int argc, char * argv[])
   //  Software Guide : EndLatex
 
   // Software Guide : BeginCodeSnippet
-  typedef float MomentType;
-  typedef otb::FlusserImageFunction<InputImageType,
-      MomentType>   FlusserType;
+  typedef otb::FlusserImageFunction<InputImageType>   FlusserType;
+  typedef FlusserType::RealType                       MomentType;
 
   FlusserType::Pointer fmFunction = FlusserType::New();
   // Software Guide : EndCodeSnippet
@@ -122,7 +120,7 @@ int main(int argc, char * argv[])
 
   // Software Guide : BeginCodeSnippet
   fmFunction->SetInputImage(image);
-  fmFunction->SetMomentNumber(mMomentNumber);
+  fmFunction->SetNeighborhoodRadius(radius);
   // Software Guide : EndCodeSnippet
 
   //  Software Guide : BeginLatex
@@ -134,8 +132,11 @@ int main(int argc, char * argv[])
   // Software Guide : BeginCodeSnippet
   MomentType Result = fmFunction->EvaluateAtIndex(center);
 
-  std::cout << "The moment of order " << mMomentNumber <<
-  " is equal to " << Result << std::endl;
+  for (unsigned int j=0; j<11; j++)
+    {
+    std::cout << "The moment of order " << j+1 <<
+      " is equal to " << Result[j] << std::endl;
+    }
   // Software Guide : EndCodeSnippet
 
   //  Software Guide : BeginLatex
diff --git a/Testing/Code/FeatureExtraction/otbFlusserImage.cxx b/Testing/Code/FeatureExtraction/otbFlusserImage.cxx
index 5a49e32aa6..7ba36af02f 100644
--- a/Testing/Code/FeatureExtraction/otbFlusserImage.cxx
+++ b/Testing/Code/FeatureExtraction/otbFlusserImage.cxx
@@ -33,7 +33,6 @@ int otbFlusserImage(int argc, char * argv[])
 {
   const char * inputFilename  = argv[1];
   const char * outputFilename  = argv[2];
-  unsigned int Number = 1;
 
   typedef unsigned char InputPixelType;
   const unsigned int Dimension = 2;
@@ -41,48 +40,30 @@ int otbFlusserImage(int argc, char * argv[])
   typedef itk::Image<InputPixelType,  Dimension>                  InputImageType;
   typedef otb::ImageFileReader<InputImageType>                    ReaderType;
   typedef std::complex<float>                                     ComplexType;
-  typedef float                                                   RealType;
-  typedef otb::FlusserImageFunction<InputImageType, float, float> FunctionType;
-
-  InputImageType::RegionType region;
-  InputImageType::SizeType   size;
-  InputImageType::IndexType  start;
-
-  start.Fill(0);
-  size[0] = 50;
-  size[1] = 50;
+  typedef otb::FlusserImageFunction<InputImageType>               FunctionType;
+  typedef FunctionType::RealType                                  RealType;
 
   ReaderType::Pointer   reader         = ReaderType::New();
-  FunctionType::Pointer function = FunctionType::New();
+  FunctionType::Pointer function       = FunctionType::New();
 
   reader->SetFileName(inputFilename);
-
-  InputImageType::Pointer image = reader->GetOutput();
-
-  region.SetIndex(start);
-  region.SetSize(size);
-
-  image->SetRegions(region);
-  image->Update();
-  function->SetInputImage(image);
+  reader->Update();
+  function->SetInputImage(reader->GetOutput());
 
   InputImageType::IndexType index;
   index[0] = 10;
   index[1] = 10;
 
+  function->SetNeighborhoodRadius(3);  
   RealType Result;
+  Result = function->EvaluateAtIndex(index);
 
   std::ofstream outputStream(outputFilename);
   outputStream << std::setprecision(10) << "Flusser Image moments: [12]" << std::endl;
 
-  for (Number = 1; Number < 12; Number++)
+  for (unsigned int j = 1; j < 12; j++)
     {
-    //OTB-FA-00024-CS
-    function->SetMomentNumber(Number);
-    //OTB-FA-00025-CS
-    function->SetNeighborhoodRadius(3);
-    Result = function->EvaluateAtIndex(index);
-    outputStream << "Flusser(" << Number << ") = " << Result << std::endl;
+    outputStream << "Flusser(" << j << ") = " << Result[j-1] << std::endl;
     }
 
   outputStream.close();
-- 
GitLab