From 7f1b3e66fe3aba841bd86c340c38261f3d32a032 Mon Sep 17 00:00:00 2001
From: Julien Malik <julien.malik@c-s.fr>
Date: Fri, 10 Sep 2010 10:03:21 +0200
Subject: [PATCH] ENH: add NormalizeAttributesLabelMapFilter & update
 MinMaxAttributesLabelMapFilter

---
 Code/OBIA/otbMinMaxAttributesLabelMapFilter.h |  19 +--
 .../otbMinMaxAttributesLabelMapFilter.txx     |  55 ++++---
 .../otbNormalizeAttributesLabelMapFilter.h    | 154 ++++++++++++++++++
 .../otbNormalizeAttributesLabelMapFilter.txx  |  89 ++++++++++
 Testing/Code/OBIA/CMakeLists.txt              |  15 +-
 .../otbMinMaxAttributesLabelMapFilter.cxx     |  24 +--
 .../otbNormalizeAttributesLabelMapFilter.cxx  | 133 +++++++++++++++
 Testing/Code/OBIA/otbOBIATests1.cxx           |   2 +
 8 files changed, 443 insertions(+), 48 deletions(-)
 create mode 100644 Code/OBIA/otbNormalizeAttributesLabelMapFilter.h
 create mode 100644 Code/OBIA/otbNormalizeAttributesLabelMapFilter.txx
 create mode 100644 Testing/Code/OBIA/otbNormalizeAttributesLabelMapFilter.cxx

diff --git a/Code/OBIA/otbMinMaxAttributesLabelMapFilter.h b/Code/OBIA/otbMinMaxAttributesLabelMapFilter.h
index d08f5212d8..5c80093cc6 100644
--- a/Code/OBIA/otbMinMaxAttributesLabelMapFilter.h
+++ b/Code/OBIA/otbMinMaxAttributesLabelMapFilter.h
@@ -18,7 +18,6 @@ PURPOSE.  See the above copyright notices for more information.
 #ifndef __otbMinMaxAttributesLabelMapFilter_h
 #define __otbMinMaxAttributesLabelMapFilter_h
 
-#include <vector>
 #include "itkLabelMapFilter.h"
 #include "itkSimpleDataObjectDecorator.h"
 
@@ -54,9 +53,9 @@ public:
   typedef typename OutputImageType::PixelType      OutputImagePixelType;
   typedef typename OutputImageType::IndexType      IndexType;
   
-  typedef typename LabelObjectType::AttributesValueType             AttributesValueType;
-  typedef std::vector<AttributesValueType>                          AttributesValueVectorType;
-  typedef itk::SimpleDataObjectDecorator<AttributesValueVectorType> AttributesValueVectorObjectType;
+  typedef typename LabelObjectType::AttributesValueType     AttributesValueType;
+  typedef typename LabelObjectType::AttributesMapType       AttributesMapType;
+  typedef itk::SimpleDataObjectDecorator<AttributesMapType> AttributesMapObjectType;
 
   /** ImageDimension constants */
   itkStaticConstMacro(InputImageDimension, unsigned int,
@@ -73,20 +72,20 @@ public:
 
 
   /** Return the computed Minimum. */
-  AttributesValueVectorType GetMinimum() const
+  AttributesMapType GetMinimum() const
   {
     return this->GetMinimumOutput()->Get();
   }
-  AttributesValueVectorObjectType* GetMinimumOutput();
-  const AttributesValueVectorObjectType* GetMinimumOutput() const;
+  AttributesMapObjectType* GetMinimumOutput();
+  const AttributesMapObjectType* GetMinimumOutput() const;
 
   /** Return the computed Maximum. */
-  AttributesValueVectorType GetMaximum() const
+  AttributesMapType GetMaximum() const
   {
     return this->GetMaximumOutput()->Get();
   }
-  AttributesValueVectorObjectType* GetMaximumOutput();
-  const AttributesValueVectorObjectType* GetMaximumOutput() const;
+  AttributesMapObjectType* GetMaximumOutput();
+  const AttributesMapObjectType* GetMaximumOutput() const;
 
 
 protected:
diff --git a/Code/OBIA/otbMinMaxAttributesLabelMapFilter.txx b/Code/OBIA/otbMinMaxAttributesLabelMapFilter.txx
index f6ab1d0556..f992ebd520 100644
--- a/Code/OBIA/otbMinMaxAttributesLabelMapFilter.txx
+++ b/Code/OBIA/otbMinMaxAttributesLabelMapFilter.txx
@@ -20,8 +20,6 @@ PURPOSE.  See the above copyright notices for more information.
 
 #include "otbMinMaxAttributesLabelMapFilter.h"
 #include "itkNumericTraits.h"
-#include "itkProgressReporter.h"
-#include "itkImageRegionConstIteratorWithIndex.h"
 
 namespace otb {
 
@@ -29,43 +27,43 @@ template <class TInputImage, class TOutputImage>
 MinMaxAttributesLabelMapFilter<TInputImage, TOutputImage>
 ::MinMaxAttributesLabelMapFilter()
 {
-  typename AttributesValueVectorObjectType::Pointer min = AttributesValueVectorObjectType::New();
-  typename AttributesValueVectorObjectType::Pointer max = AttributesValueVectorObjectType::New();
+  typename AttributesMapObjectType::Pointer min = AttributesMapObjectType::New();
+  typename AttributesMapObjectType::Pointer max = AttributesMapObjectType::New();
 
   this->itk::ProcessObject::SetNthOutput(1, min.GetPointer());
   this->itk::ProcessObject::SetNthOutput(2, max.GetPointer());
 }
 
 template<class TInputImage, class TOutputImage>
-typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesValueVectorObjectType*
+typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesMapObjectType*
 MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>
 ::GetMinimumOutput()
 {
-  return static_cast<AttributesValueVectorObjectType*>(this->itk::ProcessObject::GetOutput(1));
+  return static_cast<AttributesMapObjectType*>(this->itk::ProcessObject::GetOutput(1));
 }
 
 template<class TInputImage, class TOutputImage>
-const typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesValueVectorObjectType*
+const typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesMapObjectType*
 MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>
 ::GetMinimumOutput() const
 {
-  return static_cast<const AttributesValueVectorObjectType*>(this->itk::ProcessObject::GetOutput(1));
+  return static_cast<const AttributesMapObjectType*>(this->itk::ProcessObject::GetOutput(1));
 }
 
 template<class TInputImage, class TOutputImage>
-typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesValueVectorObjectType*
+typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesMapObjectType*
 MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>
 ::GetMaximumOutput()
 {
-  return static_cast<AttributesValueVectorObjectType*>(this->itk::ProcessObject::GetOutput(2));
+  return static_cast<AttributesMapObjectType*>(this->itk::ProcessObject::GetOutput(2));
 }
 
 template<class TInputImage, class TOutputImage>
-const typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesValueVectorObjectType*
+const typename MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>::AttributesMapObjectType*
 MinMaxAttributesLabelMapFilter<TInputImage,TOutputImage>
 ::GetMaximumOutput() const
 {
-  return static_cast<const AttributesValueVectorObjectType*>(this->itk::ProcessObject::GetOutput(2));
+  return static_cast<const AttributesMapObjectType*>(this->itk::ProcessObject::GetOutput(2));
 }
 
 template<class TInputImage, class TOutputImage>
@@ -73,34 +71,37 @@ void
 MinMaxAttributesLabelMapFilter<TInputImage, TOutputImage>
 ::GenerateData()
 {
-  LabelObjectContainerConstIterator it  = this->GetLabelMap()->GetLabelObjectContainer().begin();
-  LabelObjectContainerConstIterator end = this->GetLabelMap()->GetLabelObjectContainer().end();
-
   unsigned int nbAttr = this->GetLabelMap()->GetLabelObject(0)->GetNumberOfAttributes();
   std::vector<std::string> attributes = this->GetLabelMap()->GetLabelObject(0)->GetAvailableAttributes();
 
-  AttributesValueVectorType& minAttr = this->GetMinimumOutput()->Get();
-  AttributesValueVectorType& maxAttr = this->GetMaximumOutput()->Get();
+  AttributesMapType& minAttr = this->GetMinimumOutput()->Get();
+  AttributesMapType& maxAttr = this->GetMaximumOutput()->Get();
 
-  minAttr.resize(nbAttr);
-  maxAttr.resize(nbAttr);
-  std::fill(minAttr.begin(), minAttr.end(), itk::NumericTraits<AttributesValueType>::max());
-  std::fill(maxAttr.begin(), maxAttr.end(), itk::NumericTraits<AttributesValueType>::NonpositiveMin());
+  // create an entry in the output maps for each attribute
+  std::vector<std::string>::const_iterator valueIt;
+  for (valueIt = attributes.begin(); valueIt != attributes.end(); ++valueIt)
+    {
+    minAttr[*valueIt] = itk::NumericTraits<AttributesValueType>::max();
+    maxAttr[*valueIt] = itk::NumericTraits<AttributesValueType>::NonpositiveMin();
+    }
 
+  LabelObjectContainerConstIterator it  = this->GetLabelMap()->GetLabelObjectContainer().begin();
+  LabelObjectContainerConstIterator end = this->GetLabelMap()->GetLabelObjectContainer().end();
   for (; it != end; ++it)
     {
     // get the label object
     LabelObjectType * labelObject = it->second;
 
-    for (unsigned int i = 0; i < attributes.size(); ++i)
+    std::vector<std::string>::const_iterator it;
+    for (it = attributes.begin(); it != attributes.end(); ++it)
       {
-      AttributesValueType val = labelObject->GetAttribute(attributes[i].c_str());
+      AttributesValueType val = labelObject->GetAttribute((*it).c_str());
       // Update min
-      if (val < minAttr[i])
-        minAttr[i] = val;
+      if (val < minAttr[*it])
+        minAttr[*it] = val;
       //Update max
-      if (val > maxAttr[i])
-        maxAttr[i] = val;
+      if (val > maxAttr[*it])
+        maxAttr[*it] = val;
       }
     }
 }
diff --git a/Code/OBIA/otbNormalizeAttributesLabelMapFilter.h b/Code/OBIA/otbNormalizeAttributesLabelMapFilter.h
new file mode 100644
index 0000000000..9d709d2e22
--- /dev/null
+++ b/Code/OBIA/otbNormalizeAttributesLabelMapFilter.h
@@ -0,0 +1,154 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+  Some parts of this code are derived from ITK. See ITKCopyright.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 __otbNormalizeAttributesLabelMapFilter_h
+#define __otbNormalizeAttributesLabelMapFilter_h
+
+#include "otbLabelMapFeaturesFunctorImageFilter.h"
+#include <vector>
+
+namespace otb
+{
+
+namespace Functor
+{
+/** \class NormalizeAttributesLabelObjectFunctor
+*   \brief Functor to normalize all attributes of a LabelMap
+*
+*   \sa MinMaxAttributesLabelMapFilter
+*/
+template <class TLabelObject>
+class NormalizeAttributesLabelObjectFunctor
+{
+public:
+  /** Self typedef */
+  typedef NormalizeAttributesLabelObjectFunctor Self;
+
+  /** LabelObject typedef */
+  typedef TLabelObject                                  LabelObjectType;
+  typedef typename LabelObjectType::AttributesMapType   AttributesMapType;
+  typedef typename LabelObjectType::AttributesValueType AttributesValueType;
+
+  /** Constructor */
+  NormalizeAttributesLabelObjectFunctor();
+
+  /** Destructor */
+  virtual ~NormalizeAttributesLabelObjectFunctor() {}
+
+  /** The comparators */
+  bool operator !=(const Self& self);
+  bool operator ==(const Self& self);
+
+  /** This is the functor implementation
+   *  Calling the functor on a label object
+   *  will update its shape attributes */
+  inline void operator ()(LabelObjectType * lo) const;
+
+  void SetMinAttributesValues(const AttributesMapType& minValues)
+  {
+    m_Min = minValues;
+  }
+
+  void SetMaxAttributesValues(const AttributesMapType& maxValues)
+  {
+    m_Max = maxValues;
+  }
+
+private:
+  AttributesMapType m_Min;
+  AttributesMapType m_Max;
+};
+
+}
+
+/** \class NormalizeAttributesLabelMapFilter
+ * \brief This class works with AttributesMapLabelObject, and normalizes all attributes
+ *        wrt a vector of minimal and maximal attribute value, such that the resulting
+ *        attributes are in [0,1]
+ *
+ * \sa MinMaxAttributesLabelMapFilter
+ */
+template<class TImage>
+class ITK_EXPORT NormalizeAttributesLabelMapFilter
+  : public otb::LabelMapFeaturesFunctorImageFilter
+  <TImage,
+      typename Functor::NormalizeAttributesLabelObjectFunctor
+      <typename TImage::LabelObjectType> >
+{
+public:
+  /** Template parameters typedefs */
+  typedef TImage                                        ImageType;
+  typedef typename ImageType::LabelObjectType           LabelObjectType;
+  typedef typename LabelObjectType::AttributesMapType   AttributesMapType;
+
+  typedef Functor::NormalizeAttributesLabelObjectFunctor
+  <LabelObjectType>                           FunctorType;
+
+  /** Standard class typedefs. */
+  typedef NormalizeAttributesLabelMapFilter Self;
+  typedef LabelMapFeaturesFunctorImageFilter
+  <ImageType, FunctorType>                  Superclass;
+  typedef itk::SmartPointer<Self>           Pointer;
+  typedef itk::SmartPointer<const Self>     ConstPointer;
+
+  /** ImageDimension constants */
+  itkStaticConstMacro(ImageDimension, unsigned int, TImage::ImageDimension);
+
+  /** Standard New method. */
+  itkNewMacro(Self);
+
+  /** Runtime information support. */
+  itkTypeMacro(NormalizeAttributesLabelMapFilter, LabelMapFeaturesFunctorImageFilter);
+
+  void SetMinAttributesValues(const AttributesMapType& minValues)
+  {
+    this->GetFunctor().SetMinAttributesValues(minValues);
+    this->Modified();
+  }
+
+  void SetMaxAttributesValues(const AttributesMapType& maxValues)
+  {
+    this->GetFunctor().SetMaxAttributesValues(maxValues);
+    this->Modified();
+  }
+
+protected:
+  /** Constructor */
+  NormalizeAttributesLabelMapFilter(){}
+
+  /** Destructor */
+  virtual ~NormalizeAttributesLabelMapFilter(){}
+
+  /** PrintSelf method */
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+  NormalizeAttributesLabelMapFilter(const Self &); //purposely not implemented
+  void operator =(const Self&); //purposely not implemented
+
+}; // end of class
+
+} // end namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbNormalizeAttributesLabelMapFilter.txx"
+#endif
+
+#endif
diff --git a/Code/OBIA/otbNormalizeAttributesLabelMapFilter.txx b/Code/OBIA/otbNormalizeAttributesLabelMapFilter.txx
new file mode 100644
index 0000000000..bbbe523971
--- /dev/null
+++ b/Code/OBIA/otbNormalizeAttributesLabelMapFilter.txx
@@ -0,0 +1,89 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+  Some parts of this code are derived from ITK. See ITKCopyright.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 __otbNormalizeAttributesLabelMapFilter_txx
+#define __otbNormalizeAttributesLabelMapFilter_txx
+
+#include "otbNormalizeAttributesLabelMapFilter.h"
+
+namespace otb {
+
+namespace Functor {
+
+template <class TLabelObject>
+NormalizeAttributesLabelObjectFunctor<TLabelObject>
+::NormalizeAttributesLabelObjectFunctor()
+{}
+
+/** The comparator (!=) */
+template <class TLabelObject>
+bool
+NormalizeAttributesLabelObjectFunctor<TLabelObject>
+::operator != (const Self &other)
+  {
+  bool resp = (m_Min != other.m_Min) || (m_Max != other.m_Max);
+  return resp;
+  }
+
+/** The comparator (==)*/
+template <class TLabelObject>
+bool
+NormalizeAttributesLabelObjectFunctor<TLabelObject>
+::operator == (const Self &self)
+  {
+  // Call the != implementation
+  return !(this != self);
+  }
+
+/** This is the functor implementation
+ *  Calling the functor on a label object
+ *  will update its shape attributes */
+template <class TLabelObject>
+void
+NormalizeAttributesLabelObjectFunctor<TLabelObject>
+::operator() (LabelObjectType * lo) const
+{
+  const std::vector<std::string>& attr = lo->GetAvailableAttributes();
+
+  std::vector<std::string>::const_iterator it;
+  for (it = attr.begin(); it != attr.end(); ++it)
+    {
+    const AttributesValueType& value = lo->GetAttribute( (*it).c_str() );
+    typename AttributesMapType::const_iterator minIt = m_Min.find(*it);
+    typename AttributesMapType::const_iterator maxIt = m_Max.find(*it);
+    if (minIt != m_Min.end() && maxIt != m_Max.end())
+      {
+      lo->SetAttribute( (*it).c_str(), (value - minIt->second)/(maxIt->second - minIt->second) );
+      }
+    }
+}
+
+} // end namespace Functor
+
+template<class TImage>
+void
+NormalizeAttributesLabelMapFilter<TImage>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+}
+
+} // end namespace otb
+#endif
diff --git a/Testing/Code/OBIA/CMakeLists.txt b/Testing/Code/OBIA/CMakeLists.txt
index 1b748bb90d..c4ecc21a0e 100644
--- a/Testing/Code/OBIA/CMakeLists.txt
+++ b/Testing/Code/OBIA/CMakeLists.txt
@@ -101,7 +101,19 @@ otbMinMaxAttributesLabelMapFilterNew
 ADD_TEST(obTvMinMaxAttributesLabelMapFilter ${OBIA_TESTS1}
          otbMinMaxAttributesLabelMapFilter
          ${INPUTDATA}/calanques.tif
-         ${INPUTDATA}/cala_labelled.tif)
+         ${INPUTDATA}/cala_labelled.tif
+         ${TEMP}/obTvMinMaxAttributesLabelMapFilter.txt)
+
+ADD_TEST(obTuNormalizeAttributesLabelMapFilterNew ${OBIA_TESTS1}
+         otbNormalizeAttributesLabelMapFilterNew
+)
+
+ADD_TEST(obTvNormalizeAttributesLabelMapFilter ${OBIA_TESTS1}
+         otbNormalizeAttributesLabelMapFilter
+         ${INPUTDATA}/calanques.tif
+         ${INPUTDATA}/cala_labelled.tif
+         ${TEMP}/obTvNormalizeAttributesLabelMapFilter.txt)
+
 
 ADD_TEST(obTuRadiometricAttributesLabelMapFilterNew ${OBIA_TESTS1}
 otbRadiometricAttributesLabelMapFilterNew
@@ -157,6 +169,7 @@ otbLabelMapWithClassLabelToLabeledSampleListFilterNew.cxx
 otbLabelObjectMapVectorizer.cxx
 otbLabelObjectToPolygonFunctorNew.cxx
 otbMinMaxAttributesLabelMapFilter.cxx
+otbNormalizeAttributesLabelMapFilter.cxx
 otbRadiometricAttributesLabelMapFilterNew.cxx
 otbShapeAttributesLabelMapFilterNew.cxx
 otbStatisticsAttributesLabelMapFilterNew.cxx
diff --git a/Testing/Code/OBIA/otbMinMaxAttributesLabelMapFilter.cxx b/Testing/Code/OBIA/otbMinMaxAttributesLabelMapFilter.cxx
index 6cac377276..e70fc13e0b 100644
--- a/Testing/Code/OBIA/otbMinMaxAttributesLabelMapFilter.cxx
+++ b/Testing/Code/OBIA/otbMinMaxAttributesLabelMapFilter.cxx
@@ -53,6 +53,7 @@ int otbMinMaxAttributesLabelMapFilter(int argc, char * argv[])
 {
   const char * infname = argv[1];
   const char * lfname  = argv[2];
+  const char * outfname = argv[3];
 
   // SmartPointer instanciation
   ReaderType::Pointer         reader = ReaderType::New();
@@ -76,21 +77,24 @@ int otbMinMaxAttributesLabelMapFilter(int argc, char * argv[])
   minmaxLabelMapFilter->SetInput(shapeFilter->GetOutput());
   minmaxLabelMapFilter->Update();
 
-  MinMaxAttributesLabelMapFilterType::AttributesValueVectorType minimum = minmaxLabelMapFilter->GetMinimum();
-  std::cout << "Minimum : " << std::endl;
-  for (unsigned int i = 0; i < minimum.size(); ++i)
+  std::ofstream outfile(outfname);
+
+  MinMaxAttributesLabelMapFilterType::AttributesMapType minimum = minmaxLabelMapFilter->GetMinimum();
+  MinMaxAttributesLabelMapFilterType::AttributesMapType::const_iterator it;
+  outfile << "Minimum : " << std::endl;
+  for (it = minimum.begin(); it != minimum.end(); ++it)
     {
-    std::cout << minimum[i] << " ; ";
+    outfile << "  " << (*it).first << " : " << (*it).second << std::endl;
     }
-  std::cout << std::endl;
+  outfile << std::endl;
 
-  MinMaxAttributesLabelMapFilterType::AttributesValueVectorType maximum = minmaxLabelMapFilter->GetMaximum();
-  std::cout << "Maximum : " << std::endl;
-  for (unsigned int i = 0; i < maximum.size(); ++i)
+  MinMaxAttributesLabelMapFilterType::AttributesMapType maximum = minmaxLabelMapFilter->GetMaximum();
+  outfile << "Maximum : " << std::endl;
+  for (it = maximum.begin(); it != maximum.end(); ++it)
     {
-    std::cout << maximum[i] << " ; ";
+    outfile << "  " << (*it).first << " : " << (*it).second << std::endl;
     }
-  std::cout << std::endl;
+  outfile << std::endl;
 
   return EXIT_SUCCESS;
 }
diff --git a/Testing/Code/OBIA/otbNormalizeAttributesLabelMapFilter.cxx b/Testing/Code/OBIA/otbNormalizeAttributesLabelMapFilter.cxx
new file mode 100644
index 0000000000..d15ef8f6cc
--- /dev/null
+++ b/Testing/Code/OBIA/otbNormalizeAttributesLabelMapFilter.cxx
@@ -0,0 +1,133 @@
+/*=========================================================================
+
+  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.
+
+=========================================================================*/
+
+#include "otbImageFileReader.h"
+
+#include <fstream>
+#include <iostream>
+
+#include "otbImage.h"
+#include "otbVectorImage.h"
+#include "otbAttributesMapLabelObject.h"
+#include "otbLabelImageToLabelMapWithAdjacencyFilter.h"
+#include "otbImageToLabelMapWithAttributesFilter.h"
+#include "otbMinMaxAttributesLabelMapFilter.h"
+#include "otbNormalizeAttributesLabelMapFilter.h"
+
+const unsigned int Dimension = 2;
+typedef unsigned short LabelType;
+typedef double         PixelType;
+
+typedef otb::AttributesMapLabelObject<LabelType, Dimension, double>             LabelObjectType;
+typedef otb::LabelMapWithAdjacency<LabelObjectType>                             LabelMapType;
+typedef otb::VectorImage<PixelType, Dimension>                                  VectorImageType;
+typedef otb::Image<unsigned int,2>                                              LabeledImageType;
+
+typedef otb::ImageFileReader<VectorImageType>                                   ReaderType;
+typedef otb::ImageFileReader<LabeledImageType>                                  LabeledReaderType;
+typedef otb::LabelImageToLabelMapWithAdjacencyFilter<LabeledImageType,LabelMapType> LabelMapFilterType;
+typedef otb::ShapeAttributesLabelMapFilter<LabelMapType>                        ShapeFilterType;
+typedef otb::MinMaxAttributesLabelMapFilter<LabelMapType, VectorImageType>      MinMaxAttributesLabelMapFilterType;
+typedef otb::NormalizeAttributesLabelMapFilter<LabelMapType>                    NormalizeAttributesLabelMapFilterType;
+
+int otbNormalizeAttributesLabelMapFilterNew(int argc, char * argv[])
+{
+  NormalizeAttributesLabelMapFilterType::Pointer normalizeLabelMapFilter = NormalizeAttributesLabelMapFilterType::New();
+  return EXIT_SUCCESS;
+}
+
+int otbNormalizeAttributesLabelMapFilter(int argc, char * argv[])
+{
+  const char * infname  = argv[1];
+  const char * lfname   = argv[2];
+  const char * outfname = argv[3];
+
+  // SmartPointer instanciation
+  ReaderType::Pointer         reader = ReaderType::New();
+  LabeledReaderType::Pointer  labeledReader = LabeledReaderType::New();
+  LabelMapFilterType::Pointer filter = LabelMapFilterType::New();
+  ShapeFilterType::Pointer    shapeFilter = ShapeFilterType::New();
+  MinMaxAttributesLabelMapFilterType::Pointer minmaxLabelMapFilter = MinMaxAttributesLabelMapFilterType::New();
+  NormalizeAttributesLabelMapFilterType::Pointer normalizeLabelMapFilter = NormalizeAttributesLabelMapFilterType::New();
+  MinMaxAttributesLabelMapFilterType::Pointer minmaxAfterLabelMapFilter = MinMaxAttributesLabelMapFilterType::New();
+
+  // Inputs
+  reader->SetFileName(infname);
+  reader->UpdateOutputInformation();
+  labeledReader->SetFileName(lfname);
+  labeledReader->UpdateOutputInformation();
+
+  // Filter
+  filter->SetInput(labeledReader->GetOutput());
+  filter->SetBackgroundValue(itk::NumericTraits<LabelType>::max());
+
+  shapeFilter->SetInput(filter->GetOutput());
+
+  minmaxLabelMapFilter->SetInput(shapeFilter->GetOutput());
+  minmaxLabelMapFilter->Update();
+
+  std::ofstream outfile(outfname);
+
+  {
+  MinMaxAttributesLabelMapFilterType::AttributesMapType minimum = minmaxLabelMapFilter->GetMinimum();
+  MinMaxAttributesLabelMapFilterType::AttributesMapType::const_iterator it;
+  outfile<< "Minimum before normalization : " << std::endl;
+  for (it = minimum.begin(); it != minimum.end(); ++it)
+    {
+    outfile << "  " << (*it).first << " : " << std::fixed << std::setprecision(6) << (*it).second << std::endl;
+    }
+  outfile << std::endl;
+
+  MinMaxAttributesLabelMapFilterType::AttributesMapType maximum = minmaxLabelMapFilter->GetMaximum();
+  outfile << "Maximum before normalization : " << std::endl;
+  for (it = maximum.begin(); it != maximum.end(); ++it)
+    {
+    outfile << "  " << (*it).first << " : " << std::fixed << std::setprecision(6) << (*it).second << std::endl;
+    }
+  outfile << std::endl;
+  }
+
+  normalizeLabelMapFilter->SetInput(shapeFilter->GetOutput());
+  normalizeLabelMapFilter->SetMinAttributesValues(minmaxLabelMapFilter->GetMinimum());
+  normalizeLabelMapFilter->SetMaxAttributesValues(minmaxLabelMapFilter->GetMaximum());
+  normalizeLabelMapFilter->Update();
+
+  minmaxAfterLabelMapFilter->SetInput(normalizeLabelMapFilter->GetOutput());
+  minmaxAfterLabelMapFilter->Update();
+
+  {
+  MinMaxAttributesLabelMapFilterType::AttributesMapType minimum = minmaxAfterLabelMapFilter->GetMinimum();
+  MinMaxAttributesLabelMapFilterType::AttributesMapType::const_iterator it;
+  outfile << "Minimum after normalization : " << std::endl;
+  for (it = minimum.begin(); it != minimum.end(); ++it)
+    {
+    outfile << "  " << (*it).first << " : " << std::fixed << std::setprecision(6) << (*it).second << std::endl;
+    }
+  outfile << std::endl;
+
+  MinMaxAttributesLabelMapFilterType::AttributesMapType maximum = minmaxAfterLabelMapFilter->GetMaximum();
+  outfile << "Maximum after normalization : " << std::endl;
+  for (it = maximum.begin(); it != maximum.end(); ++it)
+    {
+    outfile << "  " << (*it).first << " : " << std::fixed << std::setprecision(6) << (*it).second << std::endl;
+    }
+  outfile << std::endl;
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/Testing/Code/OBIA/otbOBIATests1.cxx b/Testing/Code/OBIA/otbOBIATests1.cxx
index b4b3e7cf1e..fdae20c10c 100644
--- a/Testing/Code/OBIA/otbOBIATests1.cxx
+++ b/Testing/Code/OBIA/otbOBIATests1.cxx
@@ -43,6 +43,8 @@ REGISTER_TEST(otbLabelObjectMapVectorizer);
 REGISTER_TEST(otbLabelObjectToPolygonFunctorNew);
 REGISTER_TEST(otbMinMaxAttributesLabelMapFilterNew);
 REGISTER_TEST(otbMinMaxAttributesLabelMapFilter);
+REGISTER_TEST(otbNormalizeAttributesLabelMapFilterNew);
+REGISTER_TEST(otbNormalizeAttributesLabelMapFilter);
 REGISTER_TEST(otbRadiometricAttributesLabelMapFilterNew);
 REGISTER_TEST(otbShapeAttributesLabelMapFilterNew);
 REGISTER_TEST(otbStatisticsAttributesLabelMapFilterNew);
-- 
GitLab