From 28bcb759d9252a25370c3c539e231540cde0ea3d Mon Sep 17 00:00:00 2001
From: Julien Michel <julien.michel@c-s.fr>
Date: Thu, 23 Nov 2006 14:18:28 +0000
Subject: [PATCH] Correction ObjectList, correction comparaison multiple, ajout
 de la classe MorphologicalPyramidAnalyseFilter.

---
 .../otbOpeningClosingMorphologicalFilter.h    |   1 -
 Code/Common/otbObjectList.txx                 |  16 +-
 Code/Common/otbTestMain.h                     |   4 +-
 .../otbMorphologicalPyramidAnalyseFilter.h    | 143 ++++++++
 .../otbMorphologicalPyramidAnalyseFilter.txx  | 318 ++++++++++++++++++
 Testing/Code/BasicFilters/CMakeLists.txt      |   8 +-
 Testing/Code/Common/CMakeLists.txt            |   4 +-
 Testing/Code/Common/otbObjectList.cxx         |  32 +-
 Testing/Code/MultiScale/CMakeLists.txt        |  25 +-
 .../otbMorphologicalPyramidAnalyseFilter.cxx  | 134 ++++++++
 ...tbMorphologicalPyramidAnalyseFilterNew.cxx |  56 +++
 .../Code/MultiScale/otbMultiScaleTests.cxx    |   2 +-
 otbIncludeDirectories.cmake                   |   2 +
 13 files changed, 717 insertions(+), 28 deletions(-)
 create mode 100644 Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.h
 create mode 100644 Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.txx
 create mode 100644 Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.cxx
 create mode 100644 Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilterNew.cxx

diff --git a/Code/BasicFilters/otbOpeningClosingMorphologicalFilter.h b/Code/BasicFilters/otbOpeningClosingMorphologicalFilter.h
index d145f9c971..dfdc2fec3b 100644
--- a/Code/BasicFilters/otbOpeningClosingMorphologicalFilter.h
+++ b/Code/BasicFilters/otbOpeningClosingMorphologicalFilter.h
@@ -1,4 +1,3 @@
-
 /*=========================================================================
 
   Program:   ORFEO Toolbox
diff --git a/Code/Common/otbObjectList.txx b/Code/Common/otbObjectList.txx
index ab95f08d74..ee5460ac97 100644
--- a/Code/Common/otbObjectList.txx
+++ b/Code/Common/otbObjectList.txx
@@ -162,7 +162,9 @@ namespace otb
   template <class TObject>
   ObjectList<TObject>::Iterator
   ::Iterator(InternalIteratorType iter)
-  {}
+  {
+    m_Iter=iter;
+  }
   /**
    * Get the current object.
    * \return The current object pointed by the iterator.
@@ -245,7 +247,9 @@ namespace otb
   template <class TObject>
   ObjectList<TObject>::ConstIterator
   ::ConstIterator(InternalConstIteratorType iter)
-  {}
+  {
+    m_Iter=iter;
+  }
   /**
    * Get the current object.
    * \return The current object pointed by the iterator.
@@ -348,7 +352,9 @@ namespace otb
   template <class TObject>
   ObjectList<TObject>::ReverseIterator
   ::ReverseIterator(InternalReverseIteratorType iter)
-  {}
+  {
+    m_Iter=iter;
+  }
   /**
    * Get the current object.
    * \return The current object pointed by the iterator.
@@ -431,7 +437,9 @@ namespace otb
   template <class TObject>
   ObjectList<TObject>::ReverseConstIterator
   ::ReverseConstIterator(InternalReverseConstIteratorType iter)
-  {}
+  {
+    m_Iter=iter;
+  }
   /**
    * Get the current object.
    * \return The current object pointed by the iterator.
diff --git a/Code/Common/otbTestMain.h b/Code/Common/otbTestMain.h
index 5869999d6c..bdfd4aa0d6 100644
--- a/Code/Common/otbTestMain.h
+++ b/Code/Common/otbTestMain.h
@@ -145,8 +145,8 @@ int main(int ac, char* av[] )
 	    baseLineFilenamesImage.push_back(av[4+2*i]);
 	    testFilenamesImage.push_back(av[5+2*i]);
 	  }
-	av+=2+2*nbComparisons;
-	ac-=2+2*nbComparisons;
+	av+=3+2*nbComparisons;
+	ac-=3+2*nbComparisons;
       }
     else if (strcmp(av[1], "--compare-binary") == 0)
       {
diff --git a/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.h b/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.h
new file mode 100644
index 0000000000..4dba1c28d3
--- /dev/null
+++ b/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.h
@@ -0,0 +1,143 @@
+/*=========================================================================
+
+  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 _otbMorphologicalPyramidAnalyseFilter_h
+#define _otbMorphologicalPyramidAnalyseFilter_h
+
+#include "otbImageToImageListFilter.h"
+
+namespace otb
+{
+/** \class MorphologicalPyramidAnalyseFilter
+ * \brief Multiscale analysis filter using the morphological pyramid algorithm.
+ *
+ * Pyramidal decomposition is based on the following statement : once an
+ * image has been smoothed with a linear filter, it does not contain
+ * any more high-frequency details. Therefore, it can be down-sampled
+ * without any loss of information, according to Shannon Theorem. By
+ * iterating the same smoothing on the down-sampled image, a
+ * multi-resolution decomposition of the scene is
+ * computed. If the smoothing filter is a morphological filter, this
+ * is no longer true, as the filter is not linear. However, by keeping
+ * the details possibly lost in the down-sampling operation, such a
+ * decomposition can be used. 
+ *
+ * The MorphologicalPyramidAnalyseFilter provide such a
+ * decomposition. It's computation process is an iterative analyse
+ * involving smoothing by the morphological filter, computing the
+ * details lost in the smoothing, down-sampling the current image, and
+ * computing the details lost in the down-sampling.
+ *
+ * \ingroup MultiScale
+ * \sa MorphologicalPyramidSynthesisFilter,OpeningClosingMorphologicalFilter,
+ * ClosingOpeningMorphologicalFilter
+ */
+template <class TInputImage, class TOutputImage, class TMorphoFilter>
+class MorphologicalPyramidAnalyseFilter
+  : public ImageToImageListFilter<TInputImage,TOutputImage>
+{
+public:
+  /** Standard typedefs */
+  typedef MorphologicalPyramidAnalyseFilter                    Self;
+  typedef ImageToImageListFilter<TInputImage,TOutputImage>     Superclass;
+  typedef itk::SmartPointer<Self>                              Pointer;
+  typedef itk::SmartPointer<const Self>                        ConstPointer;
+  /** Creation through object factory macro */
+  itkNewMacro(Self);
+  /** Type macro */
+  itkTypeMacro(MorphologicalPyramidAnalyseFilter,MorphologicalPyramidAnalyseFilter);
+  /** Input image dimension constant macro */
+  itkStaticConstMacro(InputImageDimension, unsigned int,TInputImage::ImageDimension);
+  /** Template parameters typedefs */
+  typedef TMorphoFilter MorphoFilterType;
+  typedef typename MorphoFilterType::KernelType KernelType;
+  /** Output related typedefs */
+  typedef typename Superclass::OutputImageType         OutputImageType;
+  typedef typename Superclass::OutputImageListType     OutputImageListType;
+  typedef typename OutputImageListType::Pointer        OutputImageListPointerType;
+  typedef typename Superclass::OutputImagePointerType  OutputImagePointerType;
+  /** Input related typedefs */
+  typedef typename Superclass::InputImageType          InputImageType;          
+  typedef typename Superclass::InputImageRegionType    InputImageRegionType;
+  typedef typename InputImageType::Pointer             InputImagePointerType;
+  typedef typename InputImageType::ConstPointer        InputImageConstPointerType;
+  typedef typename InputImageType::SizeType            SizeType;                 
+  typedef typename InputImageType::ValueType           ValueType;  
+  typedef typename InputImageType::PixelType           PixelType;
+  typedef typename InputImageType::SpacingType         SpacingType;
+  /** Size and spacing vector typedefs */
+  typedef std::vector<SpacingType>                     SpacingVectorType;
+  typedef std::vector<SizeType>                        SizeVectorType;
+  /** Accessors */
+  itkSetMacro(NumberOfIterations, int);
+  itkSetMacro(SubSampleScale, float);
+  itkGetConstReferenceMacro(NumberOfIterations, int);
+  itkGetConstReferenceMacro(SubSampleScale, float);
+  /** Details images lists getters */
+  itkGetConstReferenceMacro(SupFiltre,OutputImageListPointerType);
+  itkGetConstReferenceMacro(InfFiltre,OutputImageListPointerType);
+  itkGetConstReferenceMacro(SupDeci,OutputImageListPointerType);
+  itkGetConstReferenceMacro(InfDeci,OutputImageListPointerType);
+  /* /\** Spacings list getters *\/ */
+/*   virtual  std::vector<typename TOutputImage::SpacingType> GetSpacing(); */
+/*   /\** Size list getters *\/ */
+/*   virtual  std::vector<typename TOutputImage::SizeType> GetSize(); */
+
+protected:  
+  /** Constructor */
+  MorphologicalPyramidAnalyseFilter();
+  /** Destructor */
+  ~MorphologicalPyramidAnalyseFilter();
+  virtual void GenerateOutputInformation(){}; // does nothing
+  /** Main computation method */
+  virtual void GenerateData();
+  /** Printself method */
+  virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;  
+  /**
+   * Resample an image according to specific size and spacing.
+   * \param image The image to down sample.
+   * \param size The new size of the image.
+   * \param spacing The new spacing of the image.
+   * \return The resampled image.
+   */
+  InputImagePointerType ResampleImage(InputImagePointerType image, SizeType size, SpacingType spacing);
+
+ private:
+  /** Number of iterations of the algorithm */
+  int m_NumberOfIterations;
+  /** Subsampling scale used */
+  float m_SubSampleScale;
+  /** Sup details from filtering operations */
+  OutputImageListPointerType m_SupFiltre;
+  /** Inf details from filtering operations */
+  OutputImageListPointerType m_InfFiltre;
+  /** Sup details from subsampling operations */
+  OutputImageListPointerType m_SupDeci;
+  /** Inf details from subsampling operations */
+  OutputImageListPointerType m_InfDeci;
+  /** Spacings vector */
+  SpacingVectorType m_Spacing;
+  /** Sizes vector */
+  SizeVectorType m_Size;
+};
+}// End namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbMorphologicalPyramidAnalyseFilter.txx"
+#endif
+
+#endif
diff --git a/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.txx b/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.txx
new file mode 100644
index 0000000000..855817e913
--- /dev/null
+++ b/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.txx
@@ -0,0 +1,318 @@
+/*=========================================================================
+
+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 _otbMorphologicalPyramidAnalyseFilter_txx
+#define _otbMorphologicalPyramidAnalyseFilter_txx
+
+#include "otbMorphologicalPyramidAnalyseFilter.h"
+#include "itkSubtractImageFilter.h"
+#include "itkMaximumImageFilter.h"
+#include  "itkImageDuplicator.h"
+#include "itkResampleImageFilter.h"
+#include "itkIdentityTransform.h"
+#include "itkLinearInterpolateImageFunction.h"
+#include "itkProgressAccumulator.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "otbMacro.h"
+
+namespace otb
+{
+  /**
+   * Constructor
+   */
+  template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage, TMorphoFilter>
+  ::MorphologicalPyramidAnalyseFilter()
+  {
+    m_SubSampleScale = 2.0;
+    m_NumberOfIterations = 4;
+    m_SupFiltre = OutputImageListType::New();
+    m_InfFiltre = OutputImageListType::New();
+    m_SupDeci =   OutputImageListType::New();
+    m_InfDeci =   OutputImageListType::New();
+  }
+  /**
+   * Destructor
+   */
+  template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  ::~MorphologicalPyramidAnalyseFilter(){}
+
+  // template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  // std::vector<typename TOutputImage::SpacingType>
+  // MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  // ::GetSpacing(void)
+  // {
+  //   return m_Spacing;
+  // }
+  // template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  // std::vector<typename TOutputImage::SizeType>
+  // MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  // ::GetSize(void)
+  // {
+  //   return m_Size;
+  // }
+
+  /**
+   * Resample an image according to specific size and spacing.
+   * \param image The image to down sample.
+   * \param size The new size of the image.
+   * \param spacing The new spacing of the image.
+   * \return The resampled image.
+   */
+  template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  typename MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  ::InputImagePointerType
+  MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  ::ResampleImage(InputImagePointerType image, SizeType size, SpacingType spacing)
+  {
+    otbMsgDebugMacro(<<"Call to the ResampleImage method");
+    // local variables
+    unsigned int i;
+    InputImagePointerType result;
+  
+    // Filters definition
+    typedef itk::ResampleImageFilter<InputImageType,InputImageType> ResampleFilterType;
+    typedef itk::IdentityTransform<double,InputImageType::ImageDimension> TransformType;
+    typedef itk::LinearInterpolateImageFunction<InputImageType,double> InterpolatorType;
+    typedef itk::ImageRegionConstIterator<InputImageType> ConstIteratorType;
+    typedef itk::ImageRegionIterator<InputImageType> IteratorType;
+  
+    // Resampling Filter instantiation
+    typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
+    typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
+    typename TransformType::Pointer transform = TransformType::New();
+    resampler->SetTransform(transform);
+    resampler->SetInterpolator(interpolator);
+
+    // Resampling filter set up
+    resampler->SetOutputSpacing(spacing);
+    resampler->SetOutputOrigin(image->GetOrigin());
+    resampler->SetSize(size);
+    //resampler->ReleaseDataFlagOn();
+
+    // Compute the resampled image
+    resampler->SetInput(image);
+    resampler->Update();
+    result = resampler->GetOutput();
+    otbMsgDebugMacro(<<"Resampling done.");
+
+    // // Spacing, scale and size variables declarations 
+//     // For special cases management
+//     typename InputImageType::RegionType::IndexType inputStart;
+//     typename InputImageType::RegionType::IndexType outputStart;
+//     typename InputImageType::RegionType::SizeType  inputSize;
+//     typename InputImageType::RegionType inputRegion;
+//     typename InputImageType::RegionType outputRegion;
+
+//     // Spmetimes the last line is black
+//     // In this case, we simply duplicate it
+//     if(spacing[0]*static_cast<float>(size[0]-1)>=(this->GetInput()->GetSpacing()[0]
+// 						      *static_cast<float>(image->GetLargestPossibleRegion().GetSize()[0]-1)))
+//       {
+// 	inputStart[0]=size[0]-2;
+// 	inputStart[1]=0;
+// 	outputStart[0]=size[0]-1;
+// 	outputStart[1]=0;
+// 	inputSize[0]=1;
+// 	inputSize[1]=size[1];
+// 	inputRegion.SetSize(inputSize);
+// 	outputRegion.SetSize(inputSize);
+// 	inputRegion.SetIndex(inputStart);
+// 	outputRegion.SetIndex(outputStart);
+// 	ConstIteratorType inputIt(result, inputRegion);
+// 	IteratorType outputIt(result,outputRegion);
+// 	// Last line duplication
+// 	for(inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd();++inputIt,++outputIt)
+// 	  {
+// 	    outputIt.Set(inputIt.Get());
+// 	  }
+//       }
+//     // Spmetimes the last column is black
+//     // In this case, we simply duplicate it
+//     if(spacing[1]*static_cast<float>(size[1]-1)>=(this->GetInput()->GetSpacing()[1]
+// 						      *static_cast<float>(image->GetLargestPossibleRegion().GetSize()[1]-1)))
+//       {
+// 	inputStart[1]=size[1]-2;
+// 	inputStart[0]=0;
+// 	outputStart[1]=size[1]-1;
+// 	outputStart[0]=0;
+// 	inputSize[1]=1;
+// 	inputSize[0]=size[0];
+// 	inputRegion.SetSize(inputSize);
+// 	outputRegion.SetSize(inputSize);
+// 	inputRegion.SetIndex(inputStart);
+// 	outputRegion.SetIndex(outputStart);
+// 	ConstIteratorType inputIt(result, inputRegion);
+// 	IteratorType outputIt(result,outputRegion);
+// 	// Last column duplication
+// 	for(inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd();++inputIt,++outputIt)
+// 	  {
+// 	    outputIt.Set(inputIt.Get());
+// 	  }
+//       }
+    return result;
+  }
+  /**
+   * Main computation method
+   */
+  template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  void
+  MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  ::GenerateData(void)
+  { 
+    // Input image pointer
+    OutputImageListType *   OutputImageList   = this->GetOutput();
+    // typedefs of the filters
+    typedef itk::SubtractImageFilter<InputImageType,InputImageType,OutputImageType> SubtractFilterType;
+    typedef itk::MaximumImageFilter<InputImageType,InputImageType,InputImageType> MaxFilterType;
+    typedef itk::ImageDuplicator<InputImageType> DuplicatorType;
+  
+    // Input Image duplication to the currentImage Pointer 
+    typename DuplicatorType::Pointer duplicator = DuplicatorType::New();
+    duplicator->SetInputImage(this->GetInput());
+    duplicator->Update();
+    typename InputImageType::Pointer currentImage =duplicator->GetOutput();
+    typename InputImageType::Pointer upsampled;
+
+    // Structuring element size computation
+    const int structElementDimension=static_cast<int>(ceilf(this->GetSubSampleScale()/2.));
+  
+    // Structuring element creation
+    KernelType structuringElement;
+    structuringElement.SetRadius(structElementDimension);
+    structuringElement.CreateStructuringElement();
+  
+    // Filters declarations
+    typename MorphoFilterType::Pointer morphoFilter;
+    typename MaxFilterType::Pointer max;
+    typename SubtractFilterType::Pointer subtract1,subtract2,subtract3,subtract4;
+  
+    // Spacing and size vectors declarations
+    typename InputImageType::SpacingType spacing;
+    typename InputImageType::SizeType size;
+
+    // local variables declarations and initialisations
+    int i = 0;
+    int j;
+    int sizeTmp;
+    //--------------------------------------------------------//
+    //                      Main loop                         //
+    //--------------------------------------------------------//
+    // While the number of iterations is not reached
+    otbMsgDebugMacro(<<"Entering main loop");
+    while(i<this->GetNumberOfIterations())
+      {
+
+	// morphological filtering
+	morphoFilter = MorphoFilterType::New();
+	morphoFilter->SetKernel(structuringElement);
+	morphoFilter->SetInput(currentImage);
+	morphoFilter->Update();
+
+	// Maximum between current and filtered image
+	max=MaxFilterType::New();
+	max->SetInput1(morphoFilter->GetOutput());
+	max->SetInput2(currentImage);
+	max->Update();
+
+	// SupFiltre detail image computation
+	subtract1 = SubtractFilterType::New();
+	subtract1->SetInput1(max->GetOutput());
+	subtract1->SetInput2(morphoFilter->GetOutput());
+	subtract1->Update();
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: subtract1 OK "<<subtract1->GetOutput()->GetLargestPossibleRegion().GetSize());
+	m_SupFiltre->PushBack(subtract1->GetOutput());
+	otbMsgDebugMacro("MorphologicalPyramidAnalyseFilter: step "<<i<<" - Image appended to m_SupFiltre");
+
+	// InfFiltre detail image computation
+	subtract2 = SubtractFilterType::New();
+	subtract2->SetInput1(max->GetOutput());
+	subtract2->SetInput2(currentImage);
+	subtract2->Update();
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: subtract2 OK "<<subtract2->GetOutput()->GetLargestPossibleRegion().GetSize());
+	m_InfFiltre->PushBack(subtract2->GetOutput());
+	otbMsgDebugMacro("MorphologicalPyramidAnalyseFilter: step "<<i<<" - Image appended to m_InfFiltre");
+	// New  Size/Spacing computation
+	spacing = morphoFilter->GetOutput()->GetSpacing();
+	size = morphoFilter->GetOutput()->GetLargestPossibleRegion().GetSize();
+	m_Spacing.push_back(spacing);
+	m_Size.push_back(size);
+	otbMsgDebugMacro(<<"New size and spacing :");
+	for (int j =0; j<InputImageType::ImageDimension;j++)
+	  {
+	    sizeTmp=size[j];
+	    size[j]=static_cast<int>(round(static_cast<double>(sizeTmp)/this->GetSubSampleScale()));
+	    spacing[j]=spacing[j]*((static_cast<double>(sizeTmp))/(static_cast<double>(size[j])));
+	    otbMsgDebugMacro(<<" "<<size[j]<<", "<<spacing[j]);
+	  }
+    
+	// Image subsampling 
+	// Current image becomes the newly subsampled image
+	currentImage = ResampleImage(morphoFilter->GetOutput(),size,spacing);
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: DownSampling OK "<<currentImage->GetLargestPossibleRegion().GetSize());
+	// New current image is appeneded to the output list
+	OutputImageList->PushBack(currentImage);
+
+	// Image upsampling
+	upsampled = ResampleImage(currentImage,m_Size.back(),m_Spacing.back());
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: UpSampling OK "<<upsampled->GetLargestPossibleRegion().GetSize());
+	// Computation of the details lost in the subsampling operation
+	max=MaxFilterType::New();
+	max->SetInput1(morphoFilter->GetOutput());
+	max->SetInput2(upsampled);
+	max->Update();
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: Max OK "<<max->GetOutput()->GetLargestPossibleRegion().GetSize());
+
+	// InfDeci detail image computation
+	subtract4 = SubtractFilterType::New();
+	subtract4->SetInput1(max->GetOutput());
+	subtract4->SetInput2(morphoFilter->GetOutput());
+	subtract4->Update();
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: subtract4 OK "<<subtract4->GetOutput()->GetLargestPossibleRegion().GetSize());
+	m_InfDeci->PushBack(subtract4->GetOutput());
+	otbMsgDebugMacro("MorphologicalPyramidAnalyseFilter: step "<<i<<" - Image appended to m_InfDeci");
+
+	// SupDeci detail image computation
+	subtract3 = SubtractFilterType::New();
+	subtract3->SetInput1(max->GetOutput());
+	subtract3->SetInput2(upsampled);
+	subtract3->Update();
+	otbMsgDebugMacro(<<"MorphologicalPyramidAnalyseFilter: subtract3 OK "<<subtract3->GetOutput()->GetLargestPossibleRegion().GetSize());
+	m_SupDeci->PushBack(subtract3->GetOutput());
+	otbMsgDebugMacro("MorphologicalPyramidAnalyseFilter: step "<<i<<" - Image appended to m_SupDeci");
+
+	// Iteration ounter incrementation
+	i++;
+      }
+    otbMsgDebugMacro(<<"Exiting main loop");
+  }
+  /**
+   * PrintSelf method
+   */
+  template <class TInputImage, class TOutputImage, class TMorphoFilter>
+  void
+  MorphologicalPyramidAnalyseFilter<TInputImage,TOutputImage,TMorphoFilter>
+  ::PrintSelf(std::ostream& os, itk::Indent indent) const
+  {
+    Superclass::PrintSelf(os, indent);
+    os << indent << "SubSampleScale: " << m_SubSampleScale << std::endl;
+    os << indent << "NumberOfIterations: " << m_NumberOfIterations << std::endl;
+  }
+} // End namespace otb
+#endif
diff --git a/Testing/Code/BasicFilters/CMakeLists.txt b/Testing/Code/BasicFilters/CMakeLists.txt
index b2bd0a9cdb..e6ac43de2c 100755
--- a/Testing/Code/BasicFilters/CMakeLists.txt
+++ b/Testing/Code/BasicFilters/CMakeLists.txt
@@ -67,10 +67,10 @@ ADD_TEST(bfTuOpeningClosingFilterNew ${BASICFILTERS_TESTS}
 
 ADD_TEST(bfTvOpeningClosingFilter ${BASICFILTERS_TESTS}
    --compare-image ${TOL}  ${BASELINE}/bfFiltreOpeningClosing_1.tif
-                           ${TEMP}/ROI_IKO_PAN_LesHalles_OC_MorphoFilter_1.tif
+                           ${TEMP}/bfFiltreOpeningClosing_1.tif
         otbOpeningClosingMorphologicalFilter
         ${INPUTDATA}/ROI_IKO_PAN_LesHalles.tif
-	${TEMP}/ROI_IKO_PAN_LesHalles_OC_MorphoFilter_1.tif
+	${TEMP}/bfFiltreOpeningClosing_1.tif
 	1)
 
 # -------            otb::ClosingOpeningMorphologicalFilter   ------------------------------
@@ -80,10 +80,10 @@ ADD_TEST(bfTuClosingOpeningFilterNew ${BASICFILTERS_TESTS}
 
 ADD_TEST(bfTvClosingOpeningFilter ${BASICFILTERS_TESTS}
    --compare-image ${TOL}  ${BASELINE}/bfFiltreClosingOpening_1.tif
-                           ${TEMP}/ROI_IKO_PAN_LesHalles_CO_MorphoFilter_1.tif
+                           ${TEMP}/bfFiltreClosingOpening_1.tif
         otbClosingOpeningMorphologicalFilter
         ${INPUTDATA}/ROI_IKO_PAN_LesHalles.tif
-	${TEMP}/ROI_IKO_PAN_LesHalles_CO_MorphoFilter_1.tif
+	${TEMP}/bfFiltreClosingOpening_1.tif
 	1)
 
 # A enrichir
diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt
index 41c0b2ac4e..3e7368592c 100644
--- a/Testing/Code/Common/CMakeLists.txt
+++ b/Testing/Code/Common/CMakeLists.txt
@@ -245,10 +245,10 @@ ADD_TEST(coTuImageListNew ${COMMON_TESTS}
 
 ADD_TEST(coTvImageList ${COMMON_TESTS}  
 	--compare-image ${TOL}   ${INPUTDATA}/amst.png
-				 ${TEMP}/coImageList_amst.png
+				 ${TEMP}/amst.png
          otbImageList 
 	 ${INPUTDATA}/amst.png
-         ${TEMP}/coImageList_amst.png
+         ${TEMP}/amst.png
 )
 
 # -------            otb::ImageListSource   -------------------------------------------
diff --git a/Testing/Code/Common/otbObjectList.cxx b/Testing/Code/Common/otbObjectList.cxx
index e8bff9c630..8eaefa5728 100644
--- a/Testing/Code/Common/otbObjectList.cxx
+++ b/Testing/Code/Common/otbObjectList.cxx
@@ -24,7 +24,7 @@
 
 void fail(char * failString)
 {
-  std::cout<<"Test failed in "<<failString<<std::endl;
+  std::cerr<<"Test failed in "<<failString<<std::endl;
   exit(-1);
 }
 
@@ -123,6 +123,11 @@ int otbObjectList(int argc, char * argv[])
 
       // Testing iterator
       ImageListType::Iterator iter = imageList->Begin();
+
+      if(!(iter!=imageList->End()))
+      {
+	fail("Iterator/Begin()!=Iterator/End()");
+      }
       unsigned int index = 0;
       while(iter!=imageList->End())
 	{
@@ -130,11 +135,11 @@ int otbObjectList(int argc, char * argv[])
 	    {
 	      fail("Iterator/1/iter.Get()");
 	    }
-	  else if(index==1&&(reader2->GetOutput()!=iter.Get()))
+	  if((index==1)&&(reader2->GetOutput()!=iter.Get()))
 	    {
 	      fail("Iterator/2/iter.Get()");
 	    }
-	  else
+	  if(index>1)
 	    {
 	      fail("Iterator/OutOfBound/iter.Get()");
 	    }
@@ -151,11 +156,11 @@ int otbObjectList(int argc, char * argv[])
 	    {
 	      fail("ConstIterator/1/iter.Get()");
 	    }
-	  else if(index==1&&(reader2->GetOutput()!=constIter.Get()))
+	  if((index==1)&&(reader2->GetOutput()!=constIter.Get()))
 	    {
 	      fail("ConstIterator/2/iter.Get()");
 	    }
-	  else
+	  if(index>1)
 	    {
 	      fail("ConstIterator/OutOfBound/iter.Get()");
 	    }
@@ -165,18 +170,23 @@ int otbObjectList(int argc, char * argv[])
 
       //Testing reverse iterator
       ImageListType::ReverseIterator revIter = imageList->ReverseBegin();
+      if(!(revIter!=imageList->ReverseEnd()))
+      {
+	fail("ReverseIterator/ReverseBegin()!=ReverseIterator/ReverseEnd()");
+      }
+
       index = 0;
       while(revIter!=imageList->ReverseEnd())
 	{
-	  if((index==0)&&(reader1->GetOutput()!=revIter.Get()))
+	  if((index==0)&&(reader2->GetOutput()!=revIter.Get()))
 	    {
 	      fail("ReverseIterator/1/iter.Get()");
 	    }
-	  else if(index==1&&(reader2->GetOutput()!=revIter.Get()))
+	  if((index==1)&&(reader1->GetOutput()!=revIter.Get()))
 	    {
 	      fail("ReverseIterator/2/iter.Get()");
 	    }
-	  else
+	  if(index>1)
 	    {
 	      fail("ReverseIterator/OutOfBound/iter.Get()");
 	    }
@@ -189,15 +199,15 @@ int otbObjectList(int argc, char * argv[])
       index = 0;
       while(revConstIter!=imageList->ReverseEnd())
 	{
-	  if((index==0)&&(reader1->GetOutput()!=revConstIter.Get()))
+	  if((index==0)&&(reader2->GetOutput()!=revConstIter.Get()))
 	    {
 	      fail("ReverseConstIterator/1/iter.Get()");
 	    }
-	  else if(index==1&&(reader2->GetOutput()!=revConstIter.Get()))
+	  if((index==1)&&(reader1->GetOutput()!=revConstIter.Get()))
 	    {
 	      fail("ReverseConstIterator/2/iter.Get()");
 	    }
-	  else
+	  if(index>1)
 	    {
 	      fail("ReverseConstIterator/OutOfBound/iter.Get()");
 	    }
diff --git a/Testing/Code/MultiScale/CMakeLists.txt b/Testing/Code/MultiScale/CMakeLists.txt
index 10aaef6e51..537918e5a4 100644
--- a/Testing/Code/MultiScale/CMakeLists.txt
+++ b/Testing/Code/MultiScale/CMakeLists.txt
@@ -16,13 +16,32 @@ SET(MULTISCALE_TESTS ${CXX_TEST_PATH}/otbMultiScaleTests)
 
 # -------            otb::MorphologicalPyramidAnalyseFilter   ----------
 
-ADD_TEST(msTuMorphologicalPyramidAnalyseFilterNew ${MULTISCALE_TESTS} 
-         otbMorphologicalPyramidAnalyseFilterNew) 
+ADD_TEST(msTuMorphoPyrAnalyseFilterNew ${MULTISCALE_TESTS} 
+         otbMorphologicalPyramidAnalyseFilterNew)
+
+ADD_TEST(msTvMorphoPyrAnalyseFilter ${MULTISCALE_TESTS} 
+  --compare-n-images ${TOL} 5
+		   ${BASELINE}/msPyrAn_mire_log_an_2.png
+		   ${TEMP}/msPyrAn_mire_log_an_2.png
+		   ${BASELINE}/msPyrAn_mire_log_sf_2.png
+		   ${TEMP}/msPyrAn_mire_log_sf_2.png
+		   ${BASELINE}/msPyrAn_mire_log_if_2.png
+		   ${TEMP}/msPyrAn_mire_log_if_2.png
+		   ${BASELINE}/msPyrAn_mire_log_sd_2.png
+		   ${TEMP}/msPyrAn_mire_log_sd_2.png
+		   ${BASELINE}/msPyrAn_mire_log_id_2.png
+		   ${TEMP}/msPyrAn_mire_log_id_2.png
+         otbMorphologicalPyramidAnalyseFilter
+	 ${INPUTDATA}/mire_log.png
+	 ${TEMP}/msPyrAn_mire_log
+	 png
+	 2
+	 2.0)
 
 # -------       Fichiers sources CXX -----------------------------------
 SET(BasicMultiScale_SRCS
 otbMorphologicalPyramidAnalyseFilterNew.cxx
-#otbMorphologicalPyramidAnalyseFilter.cxx
+otbMorphologicalPyramidAnalyseFilter.cxx
 )
 
 
diff --git a/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.cxx b/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.cxx
new file mode 100644
index 0000000000..52443d8dcc
--- /dev/null
+++ b/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilter.cxx
@@ -0,0 +1,134 @@
+/*=========================================================================
+
+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 "itkExceptionObject.h"
+
+#include "otbMorphologicalPyramidAnalyseFilter.h"
+#include "otbOpeningClosingMorphologicalFilter.h"
+#include "itkBinaryBallStructuringElement.h"
+#include "otbImageFileReader.h"
+#include "otbImageFileWriter.h"
+#include "otbImage.h"
+
+int otbMorphologicalPyramidAnalyseFilter(int argc, char * argv[])
+{
+  try
+    {
+      const char * inputFilename = argv[1];
+      const char * outputFilenamePrefix = argv[2];
+      const char * outputFilenameSuffix = argv[3];
+      const unsigned int numberOfIterations = atoi(argv[4]);
+      const float subSampleScale = atof(argv[5]);
+
+      const unsigned int Dimension = 2;
+      typedef unsigned char InputPixelType;
+      typedef unsigned char OutputPixelType;
+
+      typedef otb::Image<InputPixelType,Dimension> InputImageType;
+      typedef otb::Image<OutputPixelType,Dimension> OutputImageType;
+
+      typedef otb::ImageFileReader<InputImageType> ReaderType;
+      typedef otb::ImageFileWriter<OutputImageType> WriterType;
+
+      typedef itk::BinaryBallStructuringElement<InputPixelType,Dimension> StructuringElementType;
+      typedef otb::OpeningClosingMorphologicalFilter<InputImageType,InputImageType,StructuringElementType>
+	OpeningClosingFilterType;
+      typedef otb::MorphologicalPyramidAnalyseFilter<InputImageType,OutputImageType,OpeningClosingFilterType>
+	PyramidFilterType;
+      typedef PyramidFilterType::OutputImageListType::Iterator ImageListIterator;
+      
+      // Reading input image
+      ReaderType::Pointer reader = ReaderType::New();
+      reader->SetFileName(inputFilename);
+
+      // Instantiation
+      PyramidFilterType::Pointer pyramid = PyramidFilterType::New();
+      pyramid->SetNumberOfIterations(numberOfIterations);
+      pyramid->SetSubSampleScale(subSampleScale);
+      pyramid->SetInput(reader->GetOutput());
+      pyramid->Update();
+
+
+      // Retrieving iterators on the results images
+      ImageListIterator itAnalyse = pyramid->GetOutput()->Begin();
+      ImageListIterator itSupFiltre = pyramid->GetSupFiltre()->Begin();
+      ImageListIterator itInfFiltre = pyramid->GetInfFiltre()->Begin();
+      ImageListIterator itInfDeci = pyramid->GetSupDeci()->Begin();
+      ImageListIterator itSupDeci =  pyramid->GetInfDeci()->Begin();
+
+      WriterType::Pointer writer =  WriterType::New();
+
+      int i=1;
+      // Writing the results images
+      std::cout<<(itAnalyse!=(pyramid->GetOutput()->End()))<<std::endl;
+      while((itAnalyse!=pyramid->GetOutput()->End())
+	    &&(itSupFiltre!=pyramid->GetSupFiltre()->End())
+	    &&(itInfFiltre!=pyramid->GetInfFiltre()->End())
+	    &&(itInfDeci!=pyramid->GetInfDeci()->End())
+	    &&(itSupDeci!=pyramid->GetSupDeci()->End())
+	    )
+	{
+	  std::stringstream oss;
+	  oss<<outputFilenamePrefix<<"_an_"<<i<<"."<<outputFilenameSuffix;
+	  writer->SetInput(itAnalyse.Get());
+	  writer->SetFileName(oss.str().c_str());	  
+	  writer->Update();
+	  oss.str("");
+	  oss<<outputFilenamePrefix<<"_sf_"<<i<<"."<<outputFilenameSuffix;
+	  writer->SetInput(itSupFiltre.Get());
+	  writer->SetFileName(oss.str().c_str());
+	  writer->Update();
+	  oss.str("");
+	  oss<<outputFilenamePrefix<<"_if_"<<i<<"."<<outputFilenameSuffix;
+	  writer->SetInput(itInfFiltre.Get());
+	  writer->SetFileName(oss.str().c_str());
+	  writer->Update();
+	  oss.str("");
+	  oss<<outputFilenamePrefix<<"_id_"<<i<<"."<<outputFilenameSuffix;
+	  writer->SetInput(itInfDeci.Get());
+	  writer->SetFileName(oss.str().c_str());
+	  writer->Update();
+	  std::cout<<"File "<<oss<<" written"<<std::endl;
+	  oss.str("");
+	  oss<<outputFilenamePrefix<<"_sd_"<<i<<"."<<outputFilenameSuffix;
+	  writer->SetInput(itSupDeci.Get());
+	  writer->SetFileName(oss.str().c_str());
+	  writer->Update();
+	  oss.str("");
+	  ++itAnalyse;
+	  ++itSupFiltre;
+	  ++itInfFiltre;
+	  ++itInfDeci;
+	  ++itSupDeci;
+	  ++i;
+	}
+    }
+      catch( itk::ExceptionObject & err ) 
+	{ 
+	  std::cout << "Exception itk::ExceptionObject thrown !" << std::endl; 
+	  std::cout << err << std::endl; 
+	  return EXIT_FAILURE;
+	} 
+
+      catch( ... ) 
+	{ 
+	  std::cout << "Unknown exception thrown !" << std::endl; 
+	  return EXIT_FAILURE;
+	} 
+
+      return EXIT_SUCCESS;
+    }
diff --git a/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilterNew.cxx b/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilterNew.cxx
new file mode 100644
index 0000000000..d3970d5022
--- /dev/null
+++ b/Testing/Code/MultiScale/otbMorphologicalPyramidAnalyseFilterNew.cxx
@@ -0,0 +1,56 @@
+/*=========================================================================
+
+  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 "itkExceptionObject.h"
+#include "otbMorphologicalPyramidAnalyseFilter.h"
+#include "otbOpeningClosingMorphologicalFilter.h"
+#include "itkBinaryBallStructuringElement.h"
+#include "otbImage.h"
+
+int otbMorphologicalPyramidAnalyseFilterNew(int argc, char * argv[])
+{
+  try
+    {
+      const unsigned int Dimension = 2;
+      typedef unsigned char InputPixelType;
+      typedef unsigned char OutputPixelType;
+      typedef otb::Image<InputPixelType,Dimension> InputImageType;
+      typedef otb::Image<OutputPixelType,Dimension> OutputImageType;
+      typedef itk::BinaryBallStructuringElement<InputPixelType,Dimension> StructuringElementType;
+      typedef otb::OpeningClosingMorphologicalFilter<InputImageType,InputImageType,StructuringElementType>
+	OpeningClosingFilterType;
+      typedef otb::MorphologicalPyramidAnalyseFilter<InputImageType,OutputImageType,OpeningClosingFilterType>
+	PyramidFilterType;
+      // Instantiation
+      PyramidFilterType::Pointer pyramid = PyramidFilterType::New();
+    }
+
+  catch( itk::ExceptionObject & err ) 
+    { 
+    std::cout << "Exception itk::ExceptionObject thrown !" << std::endl; 
+    std::cout << err << std::endl; 
+    return EXIT_FAILURE;
+    } 
+
+  catch( ... ) 
+    { 
+    std::cout << "Unknown exception thrown !" << std::endl; 
+    return EXIT_FAILURE;
+    } 
+
+  return EXIT_SUCCESS;
+}
diff --git a/Testing/Code/MultiScale/otbMultiScaleTests.cxx b/Testing/Code/MultiScale/otbMultiScaleTests.cxx
index ea6d1b34fe..5433d46e80 100644
--- a/Testing/Code/MultiScale/otbMultiScaleTests.cxx
+++ b/Testing/Code/MultiScale/otbMultiScaleTests.cxx
@@ -27,5 +27,5 @@
 void RegisterTests()
 {
 REGISTER_TEST(otbMorphologicalPyramidAnalyseFilterNew);
-
+REGISTER_TEST(otbMorphologicalPyramidAnalyseFilter);
 }
diff --git a/otbIncludeDirectories.cmake b/otbIncludeDirectories.cmake
index c7129447b5..c7690b553b 100644
--- a/otbIncludeDirectories.cmake
+++ b/otbIncludeDirectories.cmake
@@ -15,6 +15,7 @@ SET(OTB_INCLUDE_DIRS_BUILD_TREE ${OTB_INCLUDE_DIRS_BUILD_TREE}
   ${OTB_SOURCE_DIR}/Code/ChangeDetection
   ${OTB_SOURCE_DIR}/Code/FeatureExtraction
   ${OTB_SOURCE_DIR}/Code/Learning
+  ${OTB_SOURCE_DIR}/Code/MultiScale
   ${OTB_SOURCE_DIR}/Code/Visu
   ${OTB_BINARY_DIR}/Code/Visu
 )
@@ -65,6 +66,7 @@ SET(OTB_INCLUDE_DIRS_INSTALL_TREE ${OTB_INCLUDE_DIRS_INSTALL_TREE}
   ${OTB_INSTALL_INCLUDE_DIR}/ChangeDetection
   ${OTB_INSTALL_INCLUDE_DIR}/FeatureExtraction
   ${OTB_INSTALL_INCLUDE_DIR}/Learning
+  ${OTB_INSTALL_INCLUDE_DIR}/MultiScale
   ${OTB_INSTALL_INCLUDE_DIR}/Visu
   ${OTB_INSTALL_INCLUDE_DIR}/Utilities
   ${OTB_INSTALL_INCLUDE_DIR}/Utilities/ITK
-- 
GitLab