diff --git a/Modules/Applications/AppSegmentation/app/CMakeLists.txt b/Modules/Applications/AppSegmentation/app/CMakeLists.txt
index 097d9971f16a23b266e64e28469fca2444e15f0f..f55ae3d7f91d607359b5024a17f89136428edf76 100644
--- a/Modules/Applications/AppSegmentation/app/CMakeLists.txt
+++ b/Modules/Applications/AppSegmentation/app/CMakeLists.txt
@@ -75,3 +75,8 @@ otb_create_application(
   NAME           MeanShiftSmoothing
   SOURCES        otbMeanShiftSmoothing.cxx
   LINK_LIBRARIES ${${otb-module}_LIBRARIES})
+
+otb_create_application(
+  NAME           LargeScaleMeanShift
+  SOURCES        otbLargeScaleMeanShift.cxx
+  LINK_LIBRARIES ${${otb-module}_LIBRARIES})
diff --git a/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx b/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d0dfadb1a535ce0c3acafecb650258c3c4d855e1
--- /dev/null
+++ b/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+#include "otbWrapperCompositeApplication.h"
+#include "otbWrapperApplicationFactory.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+/**
+ * \class LargeScaleMeanShift
+ *
+ * \brief All-in-one application for the LSMS framework
+ *
+ * This application gathers the 4 steps of the large-scale MeanShift
+ * segmentation framework.
+ * 
+ */
+class LargeScaleMeanShift : public CompositeApplication
+{
+public:
+  /** Standard class typedefs. */
+  typedef LargeScaleMeanShift           Self;
+  typedef CompositeApplication          Superclass;
+  typedef itk::SmartPointer<Self>       Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+
+/** Standard macro */
+  itkNewMacro(Self);
+
+  itkTypeMacro(LargeScaleMeanShift, otb::CompositeApplication);
+
+private:
+  void DoInit() ITK_OVERRIDE
+    {
+    SetName("LargeScaleMeanShift");
+    SetDescription("Large-scale segmentation using MeanShift");
+
+    // Documentation
+    SetDocName("Large-Scale MeanShift");
+    SetDocLongDescription("This application chains together the 4 steps of the "
+      "MeanShit framework, that is the MeanShiftSmoothing [1], the "
+      "LSMSSegmentation [2], the LSMSSmallRegionsMerging [3] and the "
+      "LSMSVectorization [4].\n\n"
+      "This application can be a preliminary step for an object-based analysis.\n\n"
+      "It generates a vector data file containing the regions extracted with "
+      "the MeanShift algorithm. The spatial and range radius parameters allow "
+      "to adapt the sensitivity of the algorithm depending on the image dynamic "
+      "and resolution. There is a step to remove small regions whose size "
+      "(in pixels) is less than the given 'minsize' parameter. These regions "
+      "are merged to a similar neighbor region. In the output vectors, there "
+      "are additional fields to describe each region. In particular the mean "
+      "and standard deviation (for each band) is computed for each region "
+      "using the input image as support. If an optional 'imfield' image is "
+      "given, it will be used as support image instead."
+      );
+    SetDocLimitations("None");
+    SetDocAuthors("OTB-Team");
+    SetDocSeeAlso("[1] MeanShiftSmoothing\n"
+      "[2] LSMSSegmentation\n"
+      "[3] LSMSSmallRegionsMerging\n"
+      "[4] LSMSVectorization");
+
+    AddDocTag(Tags::Segmentation);
+    AddDocTag("LSMS");
+
+    ClearApplications();
+    AddApplication("MeanShiftSmoothing", "smoothing", "Smoothing step");
+    AddApplication("LSMSSegmentation", "segmentation", "Segmentation step");
+    AddApplication("LSMSSmallRegionsMerging", "merging", "Small region merging step");
+    AddApplication("LSMSVectorization", "vectorization", "Vectorization step");
+
+    ShareParameter("in","smoothing.in");
+    ShareParameter("spatialr","smoothing.spatialr");
+    ShareParameter("ranger","smoothing.ranger");
+    ShareParameter("minsize","merging.minsize");
+
+    ShareParameter("tilesizex","segmentation.tilesizex");
+    ShareParameter("tilesizey","segmentation.tilesizey");
+
+    AddParameter(ParameterType_Choice, "mode","Output mode");
+    SetParameterDescription("mode", "Type of segmented output");
+
+    AddChoice("mode.vector", "Segmentation as vector output");
+    SetParameterDescription("mode.vector","In this mode, the application will "
+      "produce a vector file or database and compute field values for each "
+      "region");
+
+    AddParameter(ParameterType_InputImage, "mode.vector.imfield", "Support image for field computation");
+    SetParameterDescription( "mode.vector.imfield", "This is an optional support image "
+      "that can be used to compute field values in each region. Otherwise, the "
+      "input image is used as support." );
+    MandatoryOff("mode.vector.imfield");
+
+    ShareParameter("mode.vector.out","vectorization.out");
+
+    AddChoice("mode.raster", "Standard segmentation with labeled raster output");
+    SetParameterDescription("mode.raster","In this mode, the application will produce a standard labeled raster.");
+
+    ShareParameter("mode.raster.out","merging.out",
+      "The output raster image",
+      "It corresponds to the output of the small region merging step.");
+
+    AddParameter( ParameterType_Empty, "cleanup", "Temporary files cleaning" );
+    EnableParameter( "cleanup" );
+    SetParameterDescription( "cleanup",
+      "If activated, the application will try to clean all temporary files it created" );
+    MandatoryOff( "cleanup" );
+
+    // Setup RAM
+    ShareParameter("ram","smoothing.ram");
+    Connect("merging.ram","smoothing.ram");
+    Connect("vectorization.ram","smoothing.ram");
+
+    Connect("merging.tilesizex","segmentation.tilesizex");
+    Connect("merging.tilesizey","segmentation.tilesizey");
+    Connect("vectorization.tilesizex","segmentation.tilesizex");
+    Connect("vectorization.tilesizey","segmentation.tilesizey");
+
+    // TODO : this is not exactly true, we used to choose the smoothed image instead
+    Connect("merging.in","smoothing.in");
+
+    // Setup constant parameters
+    GetInternalApplication("smoothing")->SetParameterString("foutpos","foo");
+    GetInternalApplication("smoothing")->EnableParameter("foutpos");
+
+    // Doc example parameter settings
+    SetDocExampleParameterValue("in", "QB_1_ortho.tif");
+    SetDocExampleParameterValue("spatialr", "4");
+    SetDocExampleParameterValue("ranger", "80");
+    SetDocExampleParameterValue("minsize", "16");
+    SetDocExampleParameterValue("mode.vector.out", "regions.shp");
+
+    SetOfficialDocLink();
+    }
+
+  void DoUpdateParameters() ITK_OVERRIDE
+  {}
+
+  void DoExecute() ITK_OVERRIDE
+    {
+    bool isVector(GetParameterString("mode") == "vector");
+    std::string outPath(isVector ?
+      GetParameterString("mode.vector.out"):
+      GetParameterString("mode.raster.out"));
+    std::vector<std::string> tmpFilenames;
+    tmpFilenames.push_back(outPath+std::string("_labelmap.tif"));
+    tmpFilenames.push_back(outPath+std::string("_labelmap.geom"));
+    ExecuteInternal("smoothing");
+    // in-memory connexion here (saves 1 additional update for foutpos)
+    GetInternalApplication("segmentation")->SetParameterInputImage("in",
+      GetInternalApplication("smoothing")->GetParameterOutputImage("fout"));
+    GetInternalApplication("segmentation")->SetParameterInputImage("inpos",
+      GetInternalApplication("smoothing")->GetParameterOutputImage("foutpos"));
+    // temporary file output here
+    GetInternalApplication("segmentation")->SetParameterString("out",
+      tmpFilenames[0]);
+    // take half of previous radii
+    GetInternalApplication("segmentation")->SetParameterFloat("spatialr",
+      0.5 * (double)GetInternalApplication("smoothing")->GetParameterInt("spatialr"));
+    GetInternalApplication("segmentation")->SetParameterFloat("ranger",
+      0.5 * GetInternalApplication("smoothing")->GetParameterFloat("ranger"));
+    GetInternalApplication("segmentation")->ExecuteAndWriteOutput();
+
+    GetInternalApplication("merging")->SetParameterString("inseg",
+      tmpFilenames[0]);
+    EnableParameter("mode.raster.out");
+    if (isVector)
+      {
+      tmpFilenames.push_back(outPath+std::string("_labelmap_merged.tif"));
+      tmpFilenames.push_back(outPath+std::string("_labelmap_merged.geom"));
+      GetInternalApplication("merging")->SetParameterString("out",
+        tmpFilenames[2]);
+      GetInternalApplication("merging")->ExecuteAndWriteOutput();
+      if (IsParameterEnabled("mode.vector.imfield") &&
+          HasValue("mode.vector.imfield"))
+        {
+        GetInternalApplication("vectorization")->SetParameterString("in",
+          GetParameterString("mode.vector.imfield"));
+        }
+      else
+        {
+        GetInternalApplication("vectorization")->SetParameterString("in",
+          GetParameterString("in"));
+        }
+      GetInternalApplication("vectorization")->SetParameterString("inseg",
+        tmpFilenames[2]);
+      ExecuteInternal("vectorization");
+      }
+    else
+      {
+      GetInternalApplication("merging")->ExecuteAndWriteOutput();
+      }
+    DisableParameter("mode.raster.out");
+
+    if( IsParameterEnabled( "cleanup" ) )
+      {
+      otbAppLogINFO( <<"Final clean-up ..." );
+      for (unsigned int i=0 ; i<tmpFilenames.size() ; ++i)
+        {
+        if(itksys::SystemTools::FileExists(tmpFilenames[i].c_str()))
+          {
+          itksys::SystemTools::RemoveFile(tmpFilenames[i].c_str());
+          }
+        }
+      }
+    }
+
+};
+
+} // end of namespace Wrapper
+} // end of namespace otb
+
+OTB_APPLICATION_EXPORT(otb::Wrapper::LargeScaleMeanShift)
diff --git a/Modules/Applications/AppSegmentation/test/CMakeLists.txt b/Modules/Applications/AppSegmentation/test/CMakeLists.txt
index 090a2562ef000e91787672ced1a327d2cf4cd9bb..e04c3bbc1e328924e605ab1fd77fce88dcf800dc 100644
--- a/Modules/Applications/AppSegmentation/test/CMakeLists.txt
+++ b/Modules/Applications/AppSegmentation/test/CMakeLists.txt
@@ -293,3 +293,18 @@ otb_test_application(NAME     apTvSeHooverCompareSegmentationTest
                               --ignore-lines-with 2 outgt: outms:
                      )
 
+#----------- LargeScaleMeanShift TESTS ----------------
+otb_test_application(NAME     apTvSeLargeScaleMeanShiftTest
+                     APP      LargeScaleMeanShift
+                     OPTIONS  -in ${EXAMPLEDATA}/QB_1_ortho.tif
+                              -spatialr 3
+                              -ranger 80
+                              -minsize 16
+                              -tilesizex 100
+                              -tilesizey 100
+                              -mode vector
+                              -mode.vector.out ${TEMP}/apTvSeLargeScaleMeanShiftTestOut.shp
+                     VALID    --compare-ogr ${NOTOL}
+                              ${BASELINE_FILES}/apTvSeLargeScaleMeanShiftTestOut.shp
+                              ${TEMP}/apTvSeLargeScaleMeanShiftTestOut.shp
+                     )
diff --git a/Modules/Core/Common/include/otbUnaryFunctorImageFilter.h b/Modules/Core/Common/include/otbUnaryFunctorImageFilter.h
index 798d8fe6c5aaa75994a24a3718ca84e529be51a4..2217de58baf54d756792382afc2c6080ccda5ddd 100644
--- a/Modules/Core/Common/include/otbUnaryFunctorImageFilter.h
+++ b/Modules/Core/Common/include/otbUnaryFunctorImageFilter.h
@@ -32,7 +32,7 @@ namespace otb
  * Add the capability to change the number of channel when operation on
  * VectorImage compared to the itk::UnaryFunctorImageFilter
  *
- * The number of channel is provided by the functor: TFunction::OutputSize. If
+ * The number of channel is provided by the functor: TFunction::GetOutputSize. If
  * this number is lower or equal to zero, the behavior of the itk::UnaryFunctorImageFilter
  * remains unchanged.
  *
diff --git a/Modules/Feature/Descriptors/test/otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii.cxx b/Modules/Feature/Descriptors/test/otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii.cxx
index 4a2a416e5f9903b969816ecc22b52a059c419d90..d5f0f32747e42ebc0a7eb6a119a1d12628b34f2b 100644
--- a/Modules/Feature/Descriptors/test/otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii.cxx
+++ b/Modules/Feature/Descriptors/test/otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii.cxx
@@ -36,9 +36,9 @@ bool CMP(std::vector<float>  a, std::vector<float>  b)
   return lexicographical_compare(a.begin(), a.begin() + 2, b.begin(), b.begin() + 2);
 }
 
-int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(argc), char * argv[])
+int
+otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii( int itkNotUsed( argc ), char * argv[] )
 {
-
   const char * infname = argv[1];
   const char * outfname = argv[2];
 
@@ -59,7 +59,7 @@ int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(a
   typedef PointSetType::PointDataContainer PointDataContainerType;
   typedef PointDataContainerType::Iterator PointDataIteratorType;
 
-  typedef std::vector<float>          siftDataVector;
+  typedef std::vector< RealType > siftDataVector;
   typedef std::vector<siftDataVector> ImageDataType;   //Kind of PointSet with vectors
 
   // Instantiating object
@@ -76,10 +76,29 @@ int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(a
   PointsIteratorType    pIt = filter->GetOutput()->GetPoints()->Begin();
   PointDataIteratorType pDataIt = filter->GetOutput()->GetPointData()->Begin();
 
+  assert(
+    filter->GetOutput()->GetPoints()->Size() ==
+    filter->GetOutput()->GetPointData()->Size() );
+
   std::ofstream outfile(outfname);
 
   outfile << "Number of scales: " << scales << std::endl;
-  outfile << "Number of SIFT key points: " << filter->GetOutput()->GetNumberOfPoints() << std::endl;
+
+  outfile << "Number of SIFT key points: "
+	  << filter->GetOutput()->GetNumberOfPoints()
+	  << std::endl;
+
+  outfile << "Number of points: "
+	  << filter->GetOutput()->GetPoints()->Size()
+	  << std::endl;
+
+  outfile << "Number of points data: "
+	  << filter->GetOutput()->GetPointData()->Size()
+	  << std::endl;
+
+  if( filter->GetOutput()->GetPoints()->Size() !=
+      filter->GetOutput()->GetPointData()->Size() )
+    return EXIT_FAILURE;
 
   // Copy the PointSet to std::vector< std::vector >
   while (pIt != filter->GetOutput()->GetPoints()->End())
diff --git a/Modules/Filtering/ImageManipulation/include/otbBinaryFunctorImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbBinaryFunctorImageFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0e246aee5f7e787c0d4b994874bd42f75c01d06
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbBinaryFunctorImageFilter.h
@@ -0,0 +1,84 @@
+/*=========================================================================
+
+  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 otbBinaryFunctorImageFilter_h
+#define otbBinaryFunctorImageFilter_h
+
+#include "itkBinaryFunctorImageFilter.h"
+
+namespace otb
+{
+/**
+ * \class BinaryFunctorImageFilter
+ * \brief Implements pixel-wise generic operation on two images.
+ *
+ * Add the capability to change the number of channel when operation on
+ * VectorImage compared to the itk::BinaryFunctorImageFilter
+ *
+ * The number of channel is provided by the functor: TFunction::GetOutputSize. If
+ * this number is lower or equal to zero, the behavior of the itk::BinaryFunctorImageFilter
+ * remains unchanged.
+ *
+ * \sa itk::BinaryFunctorImageFilter
+ *
+ * \ingroup OTBImageManipulation
+ */
+template <class TInputImage1, class TInputImage2, class TOutputImage, class TFunction>
+class ITK_EXPORT BinaryFunctorImageFilter : public itk::BinaryFunctorImageFilter<TInputImage1, TInputImage2, TOutputImage, TFunction>
+{
+public:
+  /** Standard class typedefs. */
+  typedef BinaryFunctorImageFilter                                            Self;
+  typedef itk::BinaryFunctorImageFilter<TInputImage1, TInputImage2, TOutputImage, TFunction> Superclass;
+  typedef itk::SmartPointer<Self>                                            Pointer;
+  typedef itk::SmartPointer<const Self>                                      ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(BinaryFunctorImageFilter, itk::BinaryFunctorImageFilter);
+
+protected:
+  BinaryFunctorImageFilter() {};
+  ~BinaryFunctorImageFilter() ITK_OVERRIDE {}
+
+  /** BinaryFunctorImageFilter can produce an image which has a different number of bands
+   * than its input image.  As such, BinaryFunctorImageFilter
+   * needs to provide an implementation for
+   * GenerateOutputInformation() in order to inform the pipeline
+   * execution model.  The original documentation of this method is
+   * below.
+   *
+   * \sa ProcessObject::GenerateOutputInformaton()  */
+  void GenerateOutputInformation() ITK_OVERRIDE
+  {
+    Superclass::GenerateOutputInformation();
+    typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
+    outputPtr->SetNumberOfComponentsPerPixel( // propagate vector length info
+      this->GetFunctor().GetOutputSize());
+  }
+
+private:
+  BinaryFunctorImageFilter(const Self &); //purposely not implemented
+  void operator =(const Self&); //purposely not implemented
+
+};
+
+} // end namespace otb
+
+#endif
diff --git a/Modules/Filtering/ImageManipulation/include/otbTernaryFunctorImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbTernaryFunctorImageFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e6d3f540505708893faa290c511633e55d4b462
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbTernaryFunctorImageFilter.h
@@ -0,0 +1,84 @@
+/*=========================================================================
+
+  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 otbTernaryFunctorImageFilter_h
+#define otbTernaryFunctorImageFilter_h
+
+#include "itkTernaryFunctorImageFilter.h"
+
+namespace otb
+{
+/**
+ * \class TernaryFunctorImageFilter
+ * \brief Implements pixel-wise generic operation on three images.
+ *
+ * Add the capability to change the number of channel when operation on
+ * VectorImage compared to the itk::TernaryFunctorImageFilter
+ *
+ * The number of channel is provided by the functor: TFunction::GetOutputSize. If
+ * this number is lower or equal to zero, the behavior of the itk::TernaryFunctorImageFilter
+ * remains unchanged.
+ *
+ * \sa itk::TernaryFunctorImageFilter
+ *
+ * \ingroup OTBImageManipulation
+ */
+template <class TInputImage1, class TInputImage2, class TInputImage3, class TOutputImage, class TFunction>
+class ITK_EXPORT TernaryFunctorImageFilter : public itk::TernaryFunctorImageFilter<TInputImage1, TInputImage2, TInputImage3, TOutputImage, TFunction>
+{
+public:
+  /** Standard class typedefs. */
+  typedef TernaryFunctorImageFilter                                            Self;
+  typedef itk::TernaryFunctorImageFilter<TInputImage1, TInputImage2, TInputImage3, TOutputImage, TFunction> Superclass;
+  typedef itk::SmartPointer<Self>                                            Pointer;
+  typedef itk::SmartPointer<const Self>                                      ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(TernaryFunctorImageFilter, itk::TernaryFunctorImageFilter);
+
+protected:
+  TernaryFunctorImageFilter() {};
+  ~TernaryFunctorImageFilter() ITK_OVERRIDE {}
+
+  /** TernaryFunctorImageFilter can produce an image which has a different number of bands
+   * than its input image.  As such, TernaryFunctorImageFilter
+   * needs to provide an implementation for
+   * GenerateOutputInformation() in order to inform the pipeline
+   * execution model.  The original documentation of this method is
+   * below.
+   *
+   * \sa ProcessObject::GenerateOutputInformaton()  */
+  void GenerateOutputInformation() ITK_OVERRIDE
+  {
+    Superclass::GenerateOutputInformation();
+    typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
+    outputPtr->SetNumberOfComponentsPerPixel( // propagate vector length info
+      this->GetFunctor().GetOutputSize());
+  }
+
+private:
+  TernaryFunctorImageFilter(const Self &); //purposely not implemented
+  void operator =(const Self&); //purposely not implemented
+
+};
+
+} // end namespace otb
+
+#endif
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
index 3d944f931ca7f268d8b0b07389f97bf5cf289af6..aa0cdd076ad93109e8acd054fc920c4a3892304e 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
@@ -167,7 +167,7 @@ public:
   /* Get the internal application parameter specified
    *
    * WARNING: this method may disappear from the API */
-  const Parameter* GetParameterByKey(std::string parameter) const;
+  const Parameter* GetParameterByKey(std::string parameter, bool follow=true) const;
 
   /* Returns the description of a parameter */
   std::string GetParameterName(std::string paramKey);
@@ -284,8 +284,21 @@ public:
 
   void SetParameterEmpty(std::string parameter, bool value, bool hasUserValueFlag = true);
 
+  /** Checks if the application is ready to be executed. It checks that there
+   *  is no parameter missing
+   */
   bool IsApplicationReady();
 
+  /** Checks if a parameter 'key' is missing.
+   *
+   * A parameter is missing when all the following conditions are true :
+   *   - the parameter is mandatory
+   *   - the parameter has Role_Input
+   *   - the parameter is not a group
+   *   - the parameter has no value
+   *   - the parameter ancestors are mandatory or enabled.
+   */
+  bool IsParameterMissing(const std::string &key) const;
 
   /* Set an default integer value, must used in the
    * DoInit when setting a value by default
@@ -695,7 +708,10 @@ public:
    */
   ComplexImagePixelType GetParameterComplexOutputImagePixelType(std::string parameter);
 
-  otb::Logger* GetLogger();
+  otb::Logger* GetLogger() const;
+
+  /** Sets the logger instance of the application (use with caution) */
+  void SetLogger(otb::Logger *logger);
 
   itk::ProcessObject* GetProgressSource() const;
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperCompositeApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperCompositeApplication.h
index 3dae3b16346ec255054ddf14c6d5cfc711fe7215..859e6a81e733f238b81e51a80bf8bf665d72d653 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperCompositeApplication.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperCompositeApplication.h
@@ -149,10 +149,6 @@ private:
 
   InternalAppContainer m_AppContainer;
 
-  itk::StdStreamLogOutput::Pointer  m_LogOutput;
-
-  std::ostringstream m_Oss;
-
   AddProcessCommandType::Pointer    m_AddProcessCommand;
 };
 
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
index 7a7b45bb34e6b7b329b8ce174bd916d9a2f24c4d..178a8d55608661aa4253607f272cd54b5bddb6ad 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
@@ -36,6 +36,7 @@
 #include "otbWrapperInputProcessXMLParameter.h"
 #include "otbWrapperRAMParameter.h"
 #include "otbWrapperProxyParameter.h"
+#include "otbWrapperParameterKey.h"
 
 
 #include "otbWrapperAddProcessToWatchEvent.h"
@@ -74,11 +75,19 @@ Application::~Application()
 {
 }
 
-otb::Logger* Application::GetLogger()
+otb::Logger* Application::GetLogger() const
 {
   return m_Logger;
 }
 
+void Application::SetLogger(otb::Logger *logger)
+{
+  if (m_Logger != logger)
+    {
+    m_Logger = logger;
+    }
+}
+
 std::vector<std::string>
 Application::GetParametersKeys(bool recursive)
 {
@@ -297,11 +306,11 @@ void Application::SetParameterUserValue(std::string paramKey, bool value)
   GetParameterByKey(paramKey)->SetUserValue(value);
 }
 
-const Parameter* Application::GetParameterByKey(std::string name) const
+const Parameter* Application::GetParameterByKey(std::string name, bool follow) const
 {
   // GetParameterList is non const...
   Application* _this = const_cast<Application*>(this);
-  return _this->GetParameterByKey(name);
+  return _this->GetParameterByKey(name,follow);
 }
 
 void Application::Init()
@@ -1599,57 +1608,50 @@ Application::IsApplicationReady()
        it != paramList.end();
        ++it)
     {
-    // Check all Input Parameters with Input Role
-    if (GetParameterByKey(*it)->GetRole() == Role_Input)
+    // Check all parameters
+    if (IsParameterMissing(*it))
       {
-      // When a parameter is mandatory :
-      // return false when does not have value and:
-      //  - The param is root
-      //  - The param is not root and belonging to a Mandatory Group
-      //    which is activated
-      if ( !this->HasValue(*it)  && IsMandatory(*it) )
-        {
-        if( GetParameterByKey(*it)->IsRoot() )
-          {
-          otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Root)");
-          return false;
-          }
-        else
-          {
-          // check if the parameter is linked to a root parameter with a chain of active parameters
-          Parameter* currentParam = GetParameterByKey(*it)->GetRoot();
-          if (currentParam->IsRoot())
-            {
-            otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Level 1)");
-            return false;
-            }
-
-          int level = 1;
-
-          while (!currentParam->IsRoot())
-            {
-            if (!currentParam->GetActive())
-              {
-              // the missing parameter is not on an active branch : we can ignore it
-              break;
-              }
-            currentParam = currentParam->GetRoot();
-
-            level++;
+      ready = false;
+      break;
+      }
+    }
+  return ready;
+}
 
-            if (currentParam->IsRoot())
-              {
-              // the missing parameter is on an active branch : we need it
-              otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Level "<< level<<")");
-              return false;
-              }
-            }
-          }
+bool
+Application::IsParameterMissing(const std::string &key) const
+{
+  bool ret(false);
+  const Parameter* param = GetParameterByKey(key);
+  if (param->GetRole() == Role_Input &&
+      GetParameterType(key) != ParameterType_Group &&
+      param->GetMandatory() &&
+      !param->HasValue())
+    {
+    ret = true;
+    ParameterKey paramKey(key);
+    std::vector<std::string> split = paramKey.Split();
+    std::string currentRoot(key);
+    unsigned int level = 1;
+    while (level < split.size())
+      {
+      currentRoot.resize(currentRoot.find_last_of("."));
+      param = GetParameterByKey(currentRoot);
+      if (!param->GetActive() && !param->GetMandatory())
+        {
+        // the missing parameter is not on an active branch : we can ignore it
+        ret = false;
+        break;
         }
+      level++;
+      }
+    if (ret)
+      {
+      // the missing parameter is on an active branch : we need it
+      otbDebugMacro("MISSING : "<< key << " (Level "<< split.size()<<")");
       }
     }
-
-  return ready;
+  return ret;
 }
 
 void
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperChoiceParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperChoiceParameter.cxx
index 1ebb88d529cb5648416a466f98dc4a1dec8ec527..2f64625f58a08987b4db3c4940c8d1b978d2e3f6 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperChoiceParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperChoiceParameter.cxx
@@ -44,7 +44,7 @@ ChoiceParameter::AddChoice( std::string choicekey, std::string choiceName )
   choice.m_AssociatedParameter->SetName(choiceName);
   choice.m_AssociatedParameter->SetRoot(this);
   choice.m_AssociatedParameter->SetKey(choicekey);
-  
+  choice.m_AssociatedParameter->SetMandatory(false);
   m_ChoiceList.push_back(choice);
 
   // check if the new choice matches the m_CurrentChoice : if so the group should be active.
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperCompositeApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperCompositeApplication.cxx
index 741bcb03974feef556c01fd1be194be907d3bf40..db216594f54992949895a4158aadc5e3137f15eb 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperCompositeApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperCompositeApplication.cxx
@@ -32,8 +32,6 @@ namespace Wrapper
 
 CompositeApplication::CompositeApplication()
 {
-  m_LogOutput = itk::StdStreamLogOutput::New();
-  m_LogOutput->SetStream(m_Oss);
   m_AddProcessCommand = AddProcessCommandType::New();
   m_AddProcessCommand->SetCallbackFunction(this, &CompositeApplication::LinkWatchers);
 }
@@ -65,8 +63,7 @@ CompositeApplication
   container.App = ApplicationRegistry::CreateApplication(appType);
   container.Desc = desc;
   // Setup logger
-  container.App->GetLogger()->AddLogOutput(m_LogOutput);
-  container.App->GetLogger()->SetTimeStampFormat(itk::LoggerBase::HUMANREADABLE);
+  container.App->SetLogger(this->GetLogger());
   container.App->AddObserver(AddProcessToWatchEvent(), m_AddProcessCommand.GetPointer());
   m_AppContainer[key] = container;
   return true;
@@ -179,40 +176,14 @@ CompositeApplication
 ::ExecuteInternal(std::string key)
 {
   otbAppLogINFO(<< GetInternalAppDescription(key) <<"...");
-  try
-    {
-    GetInternalApplication(key)->Execute();
-    }
-  catch(...)
-    {
-    this->GetLogger()->Write( itk::LoggerBase::FATAL, std::string("\n") + m_Oss.str() );
-    throw;
-    }
-  if(!m_Oss.str().empty())
-    {
-    otbAppLogINFO(<< "\n" << m_Oss.str());
-    m_Oss.str(std::string(""));
-    }
+  GetInternalApplication(key)->Execute();
 }
 
 void
 CompositeApplication
 ::UpdateInternalParameters(std::string key)
 {
-  try
-    {
-    GetInternalApplication(key)->UpdateParameters();
-    }
-  catch(...)
-    {
-    this->GetLogger()->Write( itk::LoggerBase::FATAL, std::string("\n") + m_Oss.str() );
-    throw;
-    }
-  if(!m_Oss.str().empty())
-    {
-    otbAppLogINFO(<< "\n" << m_Oss.str());
-    m_Oss.str(std::string(""));
-    }
+  GetInternalApplication(key)->UpdateParameters();
 }
 
 } // end namespace Wrapper
diff --git a/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx b/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
index 686d4d58cf65f248024accc8ad306cda13d73e4a..736ad395b5255f46e4ff29d725bbeb64f38f5e36 100644
--- a/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
+++ b/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
@@ -582,99 +582,23 @@ CommandLineLauncher::ParamResultType CommandLineLauncher::LoadParameters()
   for (unsigned int i = 0; i < appKeyList.size(); i++)
     {
     const std::string paramKey(appKeyList[i]);
-    Parameter::Pointer param = m_Application->GetParameterByKey(paramKey);
     ParameterType type = m_Application->GetParameterType(paramKey);
-    const bool paramExists(m_Parser->IsAttributExists(std::string("-").append(paramKey), m_VExpression));
-    std::vector<std::string> values;
-
-    // When a parameter is mandatory :
-    // it must be set if :
-    //  - The param is root
-    //  - The param is not root and belonging to a Mandatory Group
-    //    which is activated
-    bool mustBeSet = false;
-    const bool hasValue = m_Application->HasValue(paramKey);
-
-    //skip if mandatory parameters are missing because we have it already in XML
-    if(!paramInXMLExists)
-      {
-      if( param->GetMandatory() == true && param->GetRole() != Role_Output && type != ParameterType_Group)
-        {
-        // check if the parameter is linked to a root parameter with a chain of active parameters
-        if( param->IsRoot() || param->GetRoot()->IsRoot())
-          {
-          // the parameter is a root or inside a group at root level
-          mustBeSet = true;
-          }
-        else
-          {
-          Parameter* currentParam = param->GetRoot();
-          while (!currentParam->IsRoot())
-            {
-            if (!currentParam->GetActive())
-              {
-              // the missing parameter is not on an active branch : we can ignore it
-              break;
-              }
-            currentParam = currentParam->GetRoot();
-
-            if (currentParam->IsRoot())
-              {
-              // the missing parameter is on an active branch : we need it
-              mustBeSet = true;
-              }
-            }
-          }
-        }
-      }
-
-    if( mustBeSet )
-    {
-      if (!paramExists)
-      {
-        // If key doesn't exist and parameter hasn't default value set...
-        if (!hasValue)
-        {
-          std::cerr << "ERROR: Missing mandatory parameter -" << paramKey << "." << std::endl;
-          return MISSINGMANDATORYPARAMETER;
-        }
-      }
-      else
-      {
-        values = m_Parser->GetAttribut(std::string("-").append(paramKey), m_VExpression);
-        if (values.size() == 0 && !m_Application->HasValue(paramKey))
-        {
-          std::cerr << "ERROR: Missing mandatory parameter -" << paramKey << "." << std::endl;
-          return MISSINGPARAMETERVALUE;
-        }
-      }
-    }
-    // Check if non mandatory parameter have values
-    else
+    if (m_Application->IsParameterMissing(paramKey))
       {
-      if( paramExists )
-        {
-        values = m_Parser->GetAttribut(std::string("-").append(paramKey), m_VExpression);
-        if (values.size() == 0)
-          {
-          std::cerr << "ERROR: Missing non-mandatory parameter -" << paramKey << "." << std::endl;
-          return MISSINGPARAMETERVALUE;
-          }
-        }
+      std::cerr << "ERROR: Missing mandatory parameter -" << paramKey << "." << std::endl;
+      return MISSINGMANDATORYPARAMETER;
       }
 
     // Check output paths validity
-    if (hasValue)
+    if (m_Application->HasValue(paramKey) &&
+        type == ParameterType_OutputFilename)
       {
-      if (type == ParameterType_OutputFilename)
+      std::string filename = m_Application->GetParameterString(paramKey);
+      itksys::String path = itksys::SystemTools::GetFilenamePath(filename);
+      if (path!="" && !itksys::SystemTools::FileIsDirectory(path.c_str()))
         {
-        std::string filename = m_Application->GetParameterString(paramKey);
-        itksys::String path = itksys::SystemTools::GetFilenamePath(filename);
-        if (path!="" && !itksys::SystemTools::FileIsDirectory(path.c_str()))
-          {
-          std::cerr <<"ERROR: Directory doesn't exist : "<< path.c_str() << std::endl;
-          return WRONGPARAMETERVALUE;
-          }
+        std::cerr <<"ERROR: Directory doesn't exist : "<< path.c_str() << std::endl;
+        return WRONGPARAMETERVALUE;
         }
       }
     }
@@ -813,47 +737,7 @@ std::string CommandLineLauncher::DisplayParameterHelp(const Parameter::Pointer &
 
   std::ostringstream oss;
 
-  // When a parameter is mandatory :
-  // it must be set if :
-  //  - The param is root
-  //  - The param is not root and belonging to a Mandatory Group
-  //    which is activated
-  bool isMissing = false;
-  if (!m_Parser->IsAttributExists(std::string("-").append(paramKey), m_VExpression))
-    {
-    if (!m_Application->HasValue(paramKey))
-      {
-      if( param->GetMandatory() && param->GetRole() != Role_Output )
-        {
-        if( param->IsRoot() || param->GetRoot()->IsRoot())
-          {
-          // the parameter is a root or inside a group at root level
-          isMissing = true;
-          }
-        else
-          {
-          Parameter* currentParam = param->GetRoot();
-          while (!currentParam->IsRoot())
-            {
-            if (!currentParam->GetActive())
-              {
-              // the missing parameter is not on an active branch : we can ignore it
-              break;
-              }
-            currentParam = currentParam->GetRoot();
-
-            if (currentParam->IsRoot())
-              {
-              // the missing parameter is on an active branch : we need it
-              isMissing = true;
-              }
-            }
-          }
-        }
-      }
-    }
-
-  if( isMissing )
+  if( m_Application->IsParameterMissing(paramKey) )
     {
     oss << "MISSING ";
     }