diff --git a/Documentation/Cookbook/rst/AdvancedUse.rst b/Documentation/Cookbook/rst/AdvancedUse.rst
index 604380e57a96fd41d45411e905f6380256f6c21c..5ce7228d2f45f4db63d51ed917a8283c3a9e4d0e 100644
--- a/Documentation/Cookbook/rst/AdvancedUse.rst
+++ b/Documentation/Cookbook/rst/AdvancedUse.rst
@@ -315,6 +315,36 @@ The available syntax for boolean options are:
 -  OFF, Off, off, false, False, 0 are available for setting a ’false’
    boolean value
    
+OGR DataSource options
+^^^^^^^^^^^^^^^^^^^^^^^
+
+We extended this process to OGR DataSource. There are three different type of
+option : open, creation and layer creation. Those options come from the GDAL 
+API. In order to use them one just need to specify to which of this family 
+the option one want to use is from.
+
+For open option :
+
+::
+
+    &gdal:oo:<GDALKEY>=<VALUE>
+
+
+For creation option :
+
+::
+
+    &gdal:co:<GDALKEY>=<VALUE>
+
+
+For layer creation option :
+
+::
+
+    &gdal:lco:<GDALKEY>=<VALUE>
+
+
+
 Examples
 ^^^^^^^^^^^^^^
 
diff --git a/Documentation/Cookbook/rst/Installation.rst b/Documentation/Cookbook/rst/Installation.rst
index 6058b155e95676de923b69e2649dbd86d0a0ef90..4a18859fc78af28af4d2eedf2be2fc2cc93fc54f 100644
--- a/Documentation/Cookbook/rst/Installation.rst
+++ b/Documentation/Cookbook/rst/Installation.rst
@@ -3,9 +3,9 @@ Installation
 
 We provide different standalone binary packages for OTB-Applications:
 
--  for Windows platform (7 or higher)
+-  for Windows platform (Seven or higher)
 
--  for 64bit Linux distribution
+-  for 64 bits Linux distribution
 
 -  for MacOS X
 
@@ -21,17 +21,17 @@ You can get latest binary packages from our `Download page <https://www.orfeo-to
 Windows
 -------
 
-.. include:: Installation_Windows.txt
+.. include:: Installation_Windows.rst
 
-Linux x86_64
+Linux
 ------------
 
-.. include:: Installation_Linux.txt
+.. include:: Installation_Linux.rst
 
 MacOS X
 -------
 
-.. include:: Installation_Macx.txt
+.. include:: Installation_Macos.rst
 
 Other packages
 --------------
diff --git a/Documentation/Cookbook/rst/Installation_Linux.txt b/Documentation/Cookbook/rst/Installation_Linux.rst
similarity index 77%
rename from Documentation/Cookbook/rst/Installation_Linux.txt
rename to Documentation/Cookbook/rst/Installation_Linux.rst
index a236e906a5417653c12333a5967c9b6026d120f0..8f90e6cd8183744e0e6f6e98b81f5041b13a3493 100644
--- a/Documentation/Cookbook/rst/Installation_Linux.txt
+++ b/Documentation/Cookbook/rst/Installation_Linux.rst
@@ -91,9 +91,9 @@ OTB wrappings. If no compatible Python 2.x version is found a
 notification is generated during the installation process.  If the installation completes
 without issue, information relating to your Python bindings will be provided. 
 
-You must have Python numpy bindings installed in your system. They can be installed locally
+You must have Python NumPy bindings installed in your system. They can be installed locally
 without admin rights as follows: "pip install --user numpy". This is to give users the option 
-to select their own existing Python installation rather than the one dibstributed by the OTB package.
+to select their own existing Python installation rather than the one distributed by the OTB package.
 
 By default, bindings for Python 2.7 will be enabled with the ``otbenv`` script.
 If you want to use bindings for Python 3.5, you can copy this script and modify:
@@ -115,38 +115,21 @@ Notes:
 FAQ
 ~~~
 
-Q: I am getting an error message...
+Q: Unable to import otbApplication library with Python3
 +++++++++++++++++++++++++++++++++++
 
 ::
 
-   Cannot mix incompatible Qt library (version 0x40806) with this library (version 0x40807)
-   Aborted
+   ImportError: libpython3.5m.so.rh-python35-1.0: cannot open shared object file: No such file or directory
 
-A: This is due to a conflict with system Qt4 (usually seen on KDE) and Qt4 + gtk libs in OTB package. The fix you need is to remove those libs from package.
+A: You need to add a symlink to libpython3.5m.so.rh-python35-1.0 to make it works. 
 
-.. parsed-literal::
-
-   cd /path/to/OTB-|release|-Linux64
-   rm -f lib/libQt* && rm -fr lib/gtk
-
-Q: Monteverdi and Mapla applications look different from my other applications.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-A: In versions 6.0, Monteverdi, Mapla and otbapplication (otbgui\_\*)
-use the system gtk theme. If you can't install GTK on your system you can use the
-one distributed with the OTB package. Note that using system GTK is the preferred
-way with the OTB standalone package as the distributed version of GTK do not
-work on recent Linux distributions. 
-
-To use the distributed GTK libraries you need to set the OTB_USE_LOCAL_GTK:
-
-::
-
-   export OTB_USE_LOCAL_GTK=1
+Here is the solution:
 
-And now start ``monteverdi.sh`` or ``mapla.sh`` from OTB-6.0.0-Linux64
-To get back default behaviour, unset OTB_USE_LOCAL_GTK=1 or set OTB_USE_LOCAL_GTK=0
+- find the libpython3.5XX on your system : find /usr/lib -iname *libpython3.5*
+(on Ubuntu 14.04, it is /usr/lib/x86_64-linux-gnu/libpython3.5m.so)
+- create a symlink : ln -s path/to/lib/python3.5XX
+path/to/lib/libpython3.5m.so.rh-python35-1.0
+- Try to import otbApplication again
 
-In version 6.2 and older, the Linux binaries are built without GTK support to cut some
-dependencies.
+See this discussion on `OTB issue tracker <https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/issues/1540#note_67864>`_
diff --git a/Documentation/Cookbook/rst/Installation_Linux_xdk.txt b/Documentation/Cookbook/rst/Installation_Linux_xdk.rst
similarity index 100%
rename from Documentation/Cookbook/rst/Installation_Linux_xdk.txt
rename to Documentation/Cookbook/rst/Installation_Linux_xdk.rst
diff --git a/Documentation/Cookbook/rst/Installation_Macx.txt b/Documentation/Cookbook/rst/Installation_Macos.rst
similarity index 100%
rename from Documentation/Cookbook/rst/Installation_Macx.txt
rename to Documentation/Cookbook/rst/Installation_Macos.rst
diff --git a/Documentation/Cookbook/rst/Installation_Macx_xdk.txt b/Documentation/Cookbook/rst/Installation_Macos_xsk.rst
similarity index 100%
rename from Documentation/Cookbook/rst/Installation_Macx_xdk.txt
rename to Documentation/Cookbook/rst/Installation_Macos_xsk.rst
diff --git a/Documentation/Cookbook/rst/Installation_Windows.txt b/Documentation/Cookbook/rst/Installation_Windows.rst
similarity index 100%
rename from Documentation/Cookbook/rst/Installation_Windows.txt
rename to Documentation/Cookbook/rst/Installation_Windows.rst
diff --git a/Documentation/Cookbook/rst/Installation_Windows_xdk.txt b/Documentation/Cookbook/rst/Installation_Windows_xdk.rst
similarity index 100%
rename from Documentation/Cookbook/rst/Installation_Windows_xdk.txt
rename to Documentation/Cookbook/rst/Installation_Windows_xdk.rst
diff --git a/Modules/Adapters/GdalAdapters/include/otbOGRDataSourceWrapper.h b/Modules/Adapters/GdalAdapters/include/otbOGRDataSourceWrapper.h
index eb6daff5f0510f2a9908ac88f3c5566df747ebd2..b06a173fd978e0d7237157fed617e3c90d9ad6f8 100644
--- a/Modules/Adapters/GdalAdapters/include/otbOGRDataSourceWrapper.h
+++ b/Modules/Adapters/GdalAdapters/include/otbOGRDataSourceWrapper.h
@@ -46,6 +46,7 @@
 
 #include "otbOGRLayerWrapper.h"
 #include "otbOGRVersionProxy.h"
+#include "otbOGRExtendedFilenameToOptions.h"
 
 class OGRLayer;
 class OGRSpatialReference;
@@ -88,6 +89,7 @@ public:
   typedef itk::SmartPointer<const Self> ConstPointer;
   //@}
 
+  typedef OGRExtendedFilenameToOptions FileNameHelperType;
   /**\name Standard macros */
   //@{
   /** Default builder.
@@ -162,7 +164,7 @@ public:
    * \note No condition is assumed on the non-nullity of \c source.
    * \see \c DataSource(GDALDataset *)
    */
-  static Pointer New(ogr::version_proxy::GDALDatasetType * sourcemode, Modes::type mode = Modes::Read);
+  static Pointer New(ogr::version_proxy::GDALDatasetType * sourcemode, Modes::type mode = Modes::Read , const std::vector< std::string > & layerOptions = std::vector< std::string >() );
   //@}
 
   /**\name Projection Reference property */
@@ -368,7 +370,7 @@ public:
   Layer CopyLayer(
     Layer            & srcLayer,
     std::string const& newName,
-    char            ** papszOptions = ITK_NULLPTR);
+    std::vector<std::string> const& papszOptions = std::vector<std::string>() );
   //@}
 
   /**\name Layers access
@@ -497,6 +499,10 @@ public:
    */
     ogr::version_proxy::GDALDatasetType & ogr();
 
+    void SetLayerCreationOptions( const std::vector< std::string > & options );
+    void AddLayerCreationOptions( std::vector< std::string > options );
+    const std::vector< std::string > & GetLayerCreationOptions() const ;
+
 protected:
   /** Default constructor.
    * The actual \c GDALDataset is using the <em>in-memory</em> \c
@@ -511,7 +517,7 @@ protected:
   /** Init constructor.
    * \post The newly constructed object owns the \c source parameter.
    */
-  DataSource(ogr::version_proxy::GDALDatasetType * source, Modes::type mode);
+  DataSource(ogr::version_proxy::GDALDatasetType * source, Modes::type mode , const std::vector< std::string > & layerOption = std::vector< std::string >() );
   /** Destructor.
    * \post The \c GDALDataset owned is released (if not null).
    */
@@ -549,6 +555,7 @@ private:
 
 private:
   ogr::version_proxy::GDALDatasetType *m_DataSource;
+  std::vector< std::string > m_LayerOptions;
   Modes::type    m_OpenMode;
   int            m_FirstModifiableLayerID;
   }; // end class DataSource
diff --git a/Modules/Adapters/GdalAdapters/include/otbOGRExtendedFilenameToOptions.h b/Modules/Adapters/GdalAdapters/include/otbOGRExtendedFilenameToOptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ae631531fd5d2de3f6198851deace861b11b1ec
--- /dev/null
+++ b/Modules/Adapters/GdalAdapters/include/otbOGRExtendedFilenameToOptions.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbOGRExtendedFilenameToOptions_h
+#define otbOGRExtendedFilenameToOptions_h
+
+#include <unordered_map>
+#include "otbExtendedFilenameHelper.h"
+
+namespace otb
+{
+
+/** \class OGRExtendedFilenameToOptions
+ *  \brief This class aim at processing GDAL option that can be pass through
+ * extended filename.
+ * \ingroup OTBExtendedFilename
+ * \ingroup OTBGdalAdapters
+ *
+ */
+#include "OTBGdalAdaptersExport.h"
+
+class OTBGdalAdapters_EXPORT OGRExtendedFilenameToOptions : public ExtendedFilenameHelper
+{
+public:
+  /** Standard class typedefs. */
+  typedef OGRExtendedFilenameToOptions Self;
+  typedef itk::SmartPointer<Self> Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+  typedef ExtendedFilenameHelper Superclass;
+
+  typedef Superclass::OptionMapType OptionMapType;
+  typedef OptionMapType::const_iterator ConstMapIteratorType;
+  typedef std::vector<std::string> GDALOptionType;
+
+  itkTypeMacro(OGRExtendedFilenameToOptions, otb::ExtendedFilenameHelper);
+  itkNewMacro(Self);
+
+
+  /** The creation option structure. */
+  struct OpenOptionType
+  {
+    GDALOptionType gdalOptions;
+    // std::unordered_map< std::string , bool > availableOptions;
+  };
+
+  struct CreationOptionType
+  {
+    GDALOptionType gdalOptions;
+    // std::unordered_map< std::string , bool > availableOptions;
+  };
+
+  struct LayerOptionType
+  {
+    std::unordered_map< std::string , std::string > gdalOptions;
+  };
+
+  /** Set extended filename */
+  void SetExtendedFileName(const char * extFname) override;
+
+  /** Get the GDAL option for type operation */
+  GDALOptionType GetGDALOptions( const std::string & type ) const ;
+
+  /** Get the deffierent GDAL options*/
+  GDALOptionType GetGDALOpenOptions() const ;
+  GDALOptionType GetGDALCreationOptions() const ;
+  GDALOptionType GetGDALLayerOptions() const ;
+
+  bool SimpleFileNameIsSet() const;
+  bool HasGDALLayerOption() const;
+
+  /** Set GDAL layer option through a vector of string */
+  void SetGDALLayerOptions( const GDALOptionType & options );
+
+  /** Add GDAL layer option to existing one */
+  void AddGDALLayerOptions( const GDALOptionType & options );
+
+  /** Constructor that return a pointer to an OGRExtendedFilename with 
+   * GDAL layer option as options
+   */
+  static Pointer GetGDALLayerOptionsHelper( const GDALOptionType & options );
+
+protected:
+  OGRExtendedFilenameToOptions();
+  OGRExtendedFilenameToOptions( const GDALOptionType & options );
+  ~OGRExtendedFilenameToOptions() override {};
+
+private:
+  OGRExtendedFilenameToOptions(const Self &) = delete ;
+  void operator =(const Self&) = delete ;
+
+  OpenOptionType m_OpenOptions;
+  CreationOptionType m_CreationOptions;
+  LayerOptionType m_LayerOptions;
+  bool m_HasFileName;
+};
+
+} //end namespace otb
+
+#endif // otbOGRExtendedFilenameToOptions_h
diff --git a/Modules/Adapters/GdalAdapters/include/otbOGRVersionProxy.h b/Modules/Adapters/GdalAdapters/include/otbOGRVersionProxy.h
index 7fdc308413d2a912eba471b90fe74576e1ef5310..7cae3f6dba4cf94203bfcb7e3cd52f431a5309c9 100644
--- a/Modules/Adapters/GdalAdapters/include/otbOGRVersionProxy.h
+++ b/Modules/Adapters/GdalAdapters/include/otbOGRVersionProxy.h
@@ -97,7 +97,7 @@ OTBGdalAdapters_EXPORT bool IsOFTInteger64(OGRFieldType type);
    * \return NULL if file could not be open.
    */
   OTBGdalAdapters_EXPORT   
-  GDALDatasetType * Open(const char * filename, bool readOnly = true);
+  GDALDatasetType * Open(const char * filename, bool readOnly = true , std::vector< std::string > const & options = std::vector< std::string >() );
 
   /**
    * This function closes a dataset.
@@ -126,7 +126,7 @@ OTBGdalAdapters_EXPORT bool IsOFTInteger64(OGRFieldType type);
    * \return NULL if dataset could not be created.
    */
   OTBGdalAdapters_EXPORT
-  GDALDatasetType * Create(GDALDriverType * driver, const char * name);
+  GDALDatasetType * Create(GDALDriverType * driver, const char * name , std::vector< std::string > const & options = std::vector< std::string >() );
 
 
   /**
diff --git a/Modules/Adapters/GdalAdapters/otb-module.cmake b/Modules/Adapters/GdalAdapters/otb-module.cmake
index 637a63ed4226e96af21f3fb7b3a1136c6db100b0..c985c5fb0e477a9f35de9a629e506d865239ee5e 100644
--- a/Modules/Adapters/GdalAdapters/otb-module.cmake
+++ b/Modules/Adapters/GdalAdapters/otb-module.cmake
@@ -29,6 +29,9 @@ ENABLE_SHARED
     OTBGDAL
     OTBITK
 
+  TEST_DEPENDS
+    OTBTestKernel
+    
   DESCRIPTION
     "${DOCUMENTATION}"
 )
diff --git a/Modules/Adapters/GdalAdapters/src/CMakeLists.txt b/Modules/Adapters/GdalAdapters/src/CMakeLists.txt
index 4ba50ff1e286f05842703510931bffec1d5f0f21..0f73c07a03e044b6c89d6a19b5df6fc6b9ae4851 100644
--- a/Modules/Adapters/GdalAdapters/src/CMakeLists.txt
+++ b/Modules/Adapters/GdalAdapters/src/CMakeLists.txt
@@ -29,6 +29,7 @@ set(OTBGdalAdapters_SRC
   otbGeometriesToGeometriesFilter.cxx
   otbOGRDataSourceWrapper.cxx
   otbOGRVersionProxy.cxx
+  otbOGRExtendedFilenameToOptions.cxx
   )
 
 add_library(OTBGdalAdapters ${OTBGdalAdapters_SRC})
diff --git a/Modules/Adapters/GdalAdapters/src/otbOGRDataSourceWrapper.cxx b/Modules/Adapters/GdalAdapters/src/otbOGRDataSourceWrapper.cxx
index ac43afbb4d837ce66ed40327bb4b8d1664626cc4..b8b5d4e94096611d5c8d42378157eea8332fec3b 100644
--- a/Modules/Adapters/GdalAdapters/src/otbOGRDataSourceWrapper.cxx
+++ b/Modules/Adapters/GdalAdapters/src/otbOGRDataSourceWrapper.cxx
@@ -41,6 +41,7 @@
 /*===========================================================================*/
 /*=======================[ construction/destruction ]========================*/
 /*===========================================================================*/
+
 bool otb::ogr::DataSource::Clear()
 {
   Reset(ITK_NULLPTR);
@@ -85,6 +86,7 @@ const ExtensionDriverAssociation k_ExtensionDriverMap[] =
     {".GPX", "GPX"},
     {".SQLITE", "SQLite"},
     {".KML", "KML"},
+    {".CSV", "CSV"},
   };
 /**\ingroup GeometryInternals
  * \brief Returns the OGR driver name associated to a filename.
@@ -117,22 +119,29 @@ char const* DeduceDriverName(std::string filename)
 
 otb::ogr::DataSource::DataSource()
 : m_DataSource(ITK_NULLPTR),
+  m_LayerOptions() , 
   m_OpenMode(Modes::Update_LayerUpdate),
   m_FirstModifiableLayerID(0)
 {
   Drivers::Init();
 
-  ogr::version_proxy::GDALDriverType * d = ogr::version_proxy::GetDriverByName("Memory");
+  ogr::version_proxy::GDALDriverType * d = 
+    ogr::version_proxy::GetDriverByName("Memory");
   assert(d && "OGR Memory driver not found");
   m_DataSource = ogr::version_proxy::Create(d,"in-memory");
   if (!m_DataSource) {
-    itkExceptionMacro(<< "Failed to create OGRMemDataSource: " << CPLGetLastErrorMsg());
+    itkExceptionMacro(<< "Failed to create OGRMemDataSource: " 
+                      << CPLGetLastErrorMsg());
   }
 }
 
-otb::ogr::DataSource::DataSource(otb::ogr::version_proxy::GDALDatasetType * source, Modes::type mode)
-: m_DataSource(source),
-  m_OpenMode(mode),
+otb::ogr::DataSource::DataSource( 
+    otb::ogr::version_proxy::GDALDatasetType * source ,
+    Modes::type mode ,
+    const std::vector< std::string > & options /*NULL*/ )
+: m_DataSource(source) ,
+  m_LayerOptions(options) ,
+  m_OpenMode(mode) ,
   m_FirstModifiableLayerID(0)
 {
   m_FirstModifiableLayerID = GetLayersCount();
@@ -140,9 +149,15 @@ otb::ogr::DataSource::DataSource(otb::ogr::version_proxy::GDALDatasetType * sour
 
 otb::ogr::DataSource::Pointer otb::ogr::DataSource::OpenDataSource(std::string const& datasourceName, Modes::type mode)
 {
-  bool update = (mode != Modes::Read);
+  FileNameHelperType::Pointer fileNameHelper = FileNameHelperType::New();
+  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
+  std::string simpleFileName = fileNameHelper->GetSimpleFileName();
 
-  ogr::version_proxy::GDALDatasetType * source = ogr::version_proxy::Open(datasourceName.c_str(),!update);
+  bool update = (mode != Modes::Read);
+  ogr::version_proxy::GDALDatasetType * source = 
+    ogr::version_proxy::Open( simpleFileName.c_str() ,
+                              !update ,
+                              fileNameHelper->GetGDALOpenOptions() );
   if (!source)
     {
     // In read mode, this is a failure
@@ -150,39 +165,51 @@ otb::ogr::DataSource::Pointer otb::ogr::DataSource::OpenDataSource(std::string c
     if (mode == Modes::Read)
       {
       itkGenericExceptionMacro(<< "Failed to open GDALDataset file "
-        << datasourceName<<" : " << CPLGetLastErrorMsg());
+        << simpleFileName<<" : " << CPLGetLastErrorMsg());
       }
 
     // Hand made factory based on file extension.
-    char const* driverName = DeduceDriverName(datasourceName);
+    char const* driverName = DeduceDriverName(simpleFileName);
     if (!driverName)
       {
-      itkGenericExceptionMacro(<< "No OGR driver known to OTB to create and handle a DataSource named <"
-        <<datasourceName<<">.");
+      itkGenericExceptionMacro(<< "No OGR driver known to OTB to create and "
+        "handle a DataSource named <"
+        <<simpleFileName<<">.");
       }
 
-    ogr::version_proxy::GDALDriverType * d = ogr::version_proxy::GetDriverByName(driverName);
+    ogr::version_proxy::GDALDriverType * d = 
+      ogr::version_proxy::GetDriverByName(  driverName  );
 
     if(!d)
       {
-      itkGenericExceptionMacro(<<"Could not create OGR driver "<<driverName<<", check your OGR configuration for available drivers.");
+      itkGenericExceptionMacro(<< "Could not create OGR driver " << driverName 
+        << ", check your OGR configuration for available drivers." );
       }
 
-    source = ogr::version_proxy::Create(d,datasourceName.c_str());
+    source = ogr::version_proxy::Create( 
+                  d ,
+                  simpleFileName.c_str() ,
+                  fileNameHelper->GetGDALCreationOptions() );
     if (!source) {
-      itkGenericExceptionMacro(<< "Failed to create GDALDataset <"<<datasourceName
-        <<"> (driver name: <" << driverName<<">: " << CPLGetLastErrorMsg());
+      itkGenericExceptionMacro(<< "Failed to create GDALDataset <"
+        << simpleFileName << "> (driver name: <" << driverName 
+        <<">: " << CPLGetLastErrorMsg());
     }
     }
-  return otb::ogr::DataSource::New(source, mode);
+  return otb::ogr::DataSource::New( source , mode , fileNameHelper->GetGDALLayerOptions() );
 }
 
 void DeleteDataSource(std::string const& datasourceName)
 {
-  bool ret = otb::ogr::version_proxy::Delete(datasourceName.c_str());
+  otb::OGRExtendedFilenameToOptions::Pointer fileNameHelper = 
+    otb::OGRExtendedFilenameToOptions::New();
+  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
+  std::string simpleFileName = fileNameHelper->GetSimpleFileName();
+
+  bool ret = otb::ogr::version_proxy::Delete(simpleFileName.c_str());
   if (!ret)
     {
-    itkGenericExceptionMacro(<< "Deletion of data source " << datasourceName
+    itkGenericExceptionMacro(<< "Deletion of data source " << simpleFileName
                              << " failed: " << CPLGetLastErrorMsg());
     }
 }
@@ -190,14 +217,18 @@ void DeleteDataSource(std::string const& datasourceName)
 otb::ogr::DataSource::Pointer
 otb::ogr::DataSource::New(std::string const& datasourceName, Modes::type mode)
 {
+  FileNameHelperType::Pointer fileNameHelper = FileNameHelperType::New();
+  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
+  std::string simpleFileName = fileNameHelper->GetSimpleFileName();
+
   if (mode < Modes::Read || mode >= Modes::MAX__)
     {
-    itkGenericExceptionMacro(<< "Wrong mode when opening " << datasourceName);
+    itkGenericExceptionMacro(<< "Wrong mode when opening " << simpleFileName );
     }
 
   Drivers::Init();
-
-  ogr::version_proxy::GDALDatasetType * ds = ogr::version_proxy::Open(datasourceName.c_str(),true);
+  ogr::version_proxy::GDALDatasetType * ds = 
+    ogr::version_proxy::Open( simpleFileName.c_str() , true );
 
   bool ds_exists = (ds!=ITK_NULLPTR);
 
@@ -214,9 +245,9 @@ otb::ogr::DataSource::New(std::string const& datasourceName, Modes::type mode)
 
 /*static*/
 otb::ogr::DataSource::Pointer
-otb::ogr::DataSource::New(otb::ogr::version_proxy::GDALDatasetType * source, Modes::type mode)
+otb::ogr::DataSource::New(otb::ogr::version_proxy::GDALDatasetType * source , Modes::type mode , const std::vector< std::string > & layerOptions )
 {
-  Pointer res = new DataSource(source, mode);
+  Pointer res = new DataSource( source , mode , layerOptions );
   res->UnRegister();
   return res;
 }
@@ -262,13 +293,20 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
   if (m_OpenMode == Modes::Read)
     {
     otb::ogr::Layer l = GetLayerChecked(name); // will throw if not existing
-    itkGenericOutputMacro(<< "Requesting layer creation in read-only GDALDataset. Returning the existing layer");
+    itkGenericOutputMacro(<< "Requesting layer creation in read-only "
+                             "GDALDataset. Returning the existing layer");
     return l;
     }
 
   // Other mode : Check if the layer already exists.
   otb::ogr::Layer layer = GetLayer(name); // won't throw on failure
 
+  FileNameHelperType::Pointer layerOptionHelper = 
+    FileNameHelperType::GetGDALLayerOptionsHelper( m_LayerOptions );
+  layerOptionHelper->AddGDALLayerOptions( papszOptions );
+  std::vector<std::string> layerOptions = 
+    layerOptionHelper->GetGDALLayerOptions();
+
   switch (m_OpenMode)
   {
   case Modes::Update_LayerOverwrite:
@@ -281,11 +319,15 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
 
     // Then create it
     OGRLayer * ol = m_DataSource->CreateLayer(
-      name.c_str(), poSpatialRef, eGType, otb::ogr::StringListConverter(papszOptions).to_ogr());
+      name.c_str() ,
+      poSpatialRef ,
+      eGType ,
+      otb::ogr::StringListConverter( layerOptions ).to_ogr() );
+
     if (!ol)
       {
       itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
-                               << "> in the GDALDataset file <" << GetDatasetDescription()
+        << "> in the GDALDataset file <" << GetDatasetDescription()
         <<">: " << CPLGetLastErrorMsg());
       }
 
@@ -304,11 +346,15 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
       {
       // Then create it
       OGRLayer * ol = m_DataSource->CreateLayer(
-        name.c_str(), poSpatialRef, eGType, otb::ogr::StringListConverter(papszOptions).to_ogr());
+        name.c_str() ,
+        poSpatialRef ,
+        eGType ,
+        otb::ogr::StringListConverter( layerOptions ).to_ogr() );
+
       if (!ol)
         {
         itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
-                                 << "> in the GDALDataset file <" <<  GetDatasetDescription()
+          << "> in the GDALDataset file <" <<  GetDatasetDescription()
           <<">: " << CPLGetLastErrorMsg());
         }
 
@@ -328,11 +374,15 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
 
     // Case where the layer does not exists
     OGRLayer * ol = m_DataSource->CreateLayer(
-      name.c_str(), poSpatialRef, eGType, otb::ogr::StringListConverter(papszOptions).to_ogr());
+          name.c_str() ,
+          poSpatialRef ,
+          eGType ,
+          otb::ogr::StringListConverter( layerOptions ).to_ogr() );
+
     if (!ol)
       {
       itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
-                               << "> in the GDALDataset file <" <<  GetDatasetDescription()
+        << "> in the GDALDataset file <" <<  GetDatasetDescription()
         <<">: " << CPLGetLastErrorMsg());
       }
 
@@ -353,7 +403,7 @@ otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
 otb::ogr::Layer otb::ogr::DataSource::CopyLayer(
   Layer & srcLayer,
   std::string const& newName,
-  char ** papszOptions/* = NULL */)
+  std::vector<std::string> const& papszOptions/* = NULL */)
 {
   assert(m_DataSource && "Datasource not initialized");
 
@@ -364,23 +414,33 @@ otb::ogr::Layer otb::ogr::DataSource::CopyLayer(
       itkGenericExceptionMacro(<< "Invalid GDALDataset opening mode");
       break;
     case Modes::Read:
-      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : cannot create a layer");
+      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : "
+                                  "cannot create a layer");
       break;
     default:
       break;
   }
+  
+  FileNameHelperType::Pointer layerOptionHelper = 
+    FileNameHelperType::GetGDALLayerOptionsHelper( m_LayerOptions );
+  layerOptionHelper->AddGDALLayerOptions( papszOptions );
+  std::vector<std::string> layerOptions = 
+    layerOptionHelper->GetGDALLayerOptions();
 
   OGRLayer * l0 = &srcLayer.ogr();
-  OGRLayer * ol = m_DataSource->CopyLayer(l0, newName.c_str(), papszOptions);
+  OGRLayer * ol = m_DataSource->CopyLayer( 
+                  l0 ,
+                  newName.c_str() ,
+                  otb::ogr::StringListConverter( layerOptions ).to_ogr() );
   if (!ol)
     {
     itkGenericExceptionMacro(<< "Failed to copy the layer <"
-      << srcLayer.GetName() << "> into the new layer <" <<newName
-                             << "> in the GDALDataset file <" <<  GetDatasetDescription()
+      << srcLayer.GetName() << "> into the new layer <" << newName
+      << "> in the GDALDataset file <" <<  GetDatasetDescription()
       <<">: " << CPLGetLastErrorMsg());
     }
   const bool modifiable = true;
-  Layer l(ol, modifiable);
+  Layer l( ol , modifiable );
   return l;
 }
 
@@ -395,10 +455,12 @@ void otb::ogr::DataSource::DeleteLayer(size_t i)
       itkGenericExceptionMacro(<< "Invalid GDALDataset opening mode");
       break;
     case Modes::Read:
-      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : cannot delete a layer");
+      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : "
+        "cannot delete a layer");
       break;
     case Modes::Update_LayerCreateOnly:
-      itkGenericExceptionMacro(<< "GDALDataset is opened in Update_LayerCreateOnly mode : cannot delete a layer");
+      itkGenericExceptionMacro(<< "GDALDataset is opened in "
+        "Update_LayerCreateOnly mode : cannot delete a layer");
       break;
     default:
       break;
@@ -407,14 +469,16 @@ void otb::ogr::DataSource::DeleteLayer(size_t i)
   const int nb_layers = GetLayersCount();
   if (int(i) >= nb_layers)
     {
-    itkExceptionMacro(<< "Cannot delete " << i << "th layer in the GDALDataset <"
-                      <<  GetDatasetDescription() << "> as it contains only " << nb_layers << "layers.");
+    itkExceptionMacro(<< "Cannot delete " << i 
+      << "th layer in the GDALDataset <" <<  GetDatasetDescription() 
+      << "> as it contains only " << nb_layers << "layers.");
     }
   const OGRErr err = m_DataSource->DeleteLayer(int(i));
   if (err != OGRERR_NONE)
     {
-    itkExceptionMacro(<< "Cannot delete " << i << "th layer in the GDALDataset <"
-                      <<  GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
+    itkExceptionMacro(<< "Cannot delete " << i 
+      << "th layer in the GDALDataset <" <<  GetDatasetDescription() 
+      << ">: " << CPLGetLastErrorMsg());
     }
 }
 
@@ -471,7 +535,7 @@ size_t otb::ogr::DataSource::GetLayerID(std::string const& name) const
   if (id < 0)
     {
     itkExceptionMacro( << "Cannot fetch any layer named <" << name
-                       << "> in the GDALDataset <" <<  GetDatasetDescription() << ">: "
+      << "> in the GDALDataset <" <<  GetDatasetDescription() << ">: "
       << CPLGetLastErrorMsg());
     }
   return 0; // keep compiler happy
@@ -484,13 +548,15 @@ otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(size_t i)
   if (int(i) >= nb_layers)
     {
     itkExceptionMacro(<< "Cannot fetch " << i << "th layer in the GDALDataset <"
-                      << GetDatasetDescription() << "> as it contains only " << nb_layers << "layers.");
+      << GetDatasetDescription() << "> as it contains only " << nb_layers 
+      << "layers.");
     }
   OGRLayer * layer_ptr = m_DataSource->GetLayer(int(i));
   if (!layer_ptr)
     {
-    itkExceptionMacro( << "Unexpected error: cannot fetch " << i << "th layer in the GDALDataset <"
-                       << GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
+    itkExceptionMacro( << "Unexpected error: cannot fetch " << i 
+      << "th layer in the GDALDataset <" << GetDatasetDescription() 
+      << ">: " << CPLGetLastErrorMsg());
     }
   return otb::ogr::Layer(layer_ptr, IsLayerModifiable(i));
 }
@@ -540,8 +606,9 @@ otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL(
   if (!layer_ptr)
     {
 #if defined(PREFER_EXCEPTION)
-    itkExceptionMacro( << "Unexpected error: cannot execute the SQL request <" << statement
-      << "> in the GDALDataset <" <<  GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
+    itkExceptionMacro( << "Unexpected error: cannot execute the SQL request <" 
+      << statement << "> in the GDALDataset <" <<  GetDatasetDescription() 
+      << ">: " << CPLGetLastErrorMsg());
 #else
     // Cannot use the deleter made for result sets obtained from
     // GDALDataset::ExecuteSQL because it checks for non-nullity....
@@ -552,7 +619,33 @@ otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL(
   return otb::ogr::Layer(layer_ptr, *m_DataSource, modifiable);
 }
 
+void
+otb::ogr::DataSource::
+SetLayerCreationOptions( const std::vector< std::string > & options )
+{
+  FileNameHelperType::Pointer helper = FileNameHelperType::New();
+  helper->SetGDALLayerOptions( options );
+  m_LayerOptions = helper->GetGDALLayerOptions();
+  // perf : do we move code from  helper->SetGDALLayerOptions in here?
+}
 
+void
+otb::ogr::DataSource::
+AddLayerCreationOptions( std::vector< std::string > options )
+{
+  FileNameHelperType::Pointer helper = FileNameHelperType::New();
+  helper->SetGDALLayerOptions( m_LayerOptions );
+  helper->AddGDALLayerOptions( options );
+  m_LayerOptions = helper->GetGDALLayerOptions();
+  // perf : do we move code from helper->AddGDALLayerOptions in here?
+}
+
+const std::vector< std::string > &
+otb::ogr::DataSource::
+GetLayerCreationOptions() const
+{
+  return m_LayerOptions;
+}
 /*===========================================================================*/
 /*===============================[ features ]================================*/
 /*===========================================================================*/
@@ -591,7 +684,8 @@ OGREnvelope otb::ogr::DataSource::GetGlobalExtent(bool force/* = false */, std::
 
   if(lit==this->end())
     {
-    itkGenericExceptionMacro(<< "Cannot compute global extent because there are no layers in the DataSource");
+    itkGenericExceptionMacro(<< "Cannot compute global extent because there "
+      "are no layers in the DataSource");
     }
 
   const OGRSpatialReference * ref_srs = lit->GetSpatialRef();
@@ -695,16 +789,18 @@ void otb::ogr::DataSource::SyncToDisk()
   if(!ret)
     {
     itkExceptionMacro( << "Cannot flush the pending of the OGRDataSource <"
-                       << GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
+      << GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
     }
 }
 
 
 std::string otb::ogr::DataSource::GetDatasetDescription() const
 {
-  std::vector<std::string> files = otb::ogr::version_proxy::GetFileListAsStringVector(m_DataSource);
+  std::vector<std::string> files = 
+    otb::ogr::version_proxy::GetFileListAsStringVector( m_DataSource );
   std::string description = "";
-  for(std::vector<std::string>::const_iterator it = files.begin();it!=files.end();++it)
+  for( std::vector<std::string>::const_iterator it = files.begin() ; 
+       it!=files.end() ; ++it )
     description+=(*it)+", ";
 
   return description;
diff --git a/Modules/Adapters/GdalAdapters/src/otbOGRExtendedFilenameToOptions.cxx b/Modules/Adapters/GdalAdapters/src/otbOGRExtendedFilenameToOptions.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a34e70947138645f0d660570c6abdefedb7aa141
--- /dev/null
+++ b/Modules/Adapters/GdalAdapters/src/otbOGRExtendedFilenameToOptions.cxx
@@ -0,0 +1,178 @@
+/*
+ * 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 "otbOGRExtendedFilenameToOptions.h"
+#include "otb_boost_string_header.h"
+#include "otb_boost_tokenizer_header.h"
+
+namespace otb
+{
+
+OGRExtendedFilenameToOptions::
+OGRExtendedFilenameToOptions():
+m_HasFileName(false)
+{
+}
+
+OGRExtendedFilenameToOptions::
+OGRExtendedFilenameToOptions( const GDALOptionType & options ):
+m_LayerOptions(),
+m_HasFileName(false)
+{
+  this->SetGDALLayerOptions( options );
+}
+
+OGRExtendedFilenameToOptions::Pointer
+OGRExtendedFilenameToOptions::
+GetGDALLayerOptionsHelper( const GDALOptionType & options )
+{
+  Pointer res = new OGRExtendedFilenameToOptions( options );
+  res->UnRegister();
+  return res;
+}
+
+
+void
+OGRExtendedFilenameToOptions::
+SetExtendedFileName(const char *extFname)
+{
+  Superclass::SetExtendedFileName(extFname);
+  m_HasFileName = true;
+
+  const OptionMapType & map = GetOptionMap();
+
+  ConstMapIteratorType it;
+  for ( it=map.begin(); it != map.end(); it++ )
+    {
+    std::vector<std::string> tmp;
+    boost::split(tmp, it->first, boost::is_any_of(":"), boost::token_compress_on);
+
+    if (tmp.size()>2 && (tmp[0]=="gdal") )
+      {
+      if ( tmp[1]=="oo" )
+        {
+        m_OpenOptions.gdalOptions.push_back(tmp[2] + "=" +it->second);
+        }
+      else if ( tmp[1]=="co" )
+        {
+        m_CreationOptions.gdalOptions.push_back(tmp[2] + "=" +it->second);
+        }
+      else if ( tmp[1]=="lco" )
+        {
+        m_LayerOptions.gdalOptions[tmp[2]] = it->second;
+        }
+      else
+        {
+        // log a warning
+        }
+      }
+
+    }
+}
+
+OGRExtendedFilenameToOptions::
+GDALOptionType
+OGRExtendedFilenameToOptions::
+GetGDALOptions( const std::string & type ) const
+{
+  if ( type == "layer" )
+    return GetGDALLayerOptions();
+  else if ( type == "creation" )
+    return m_CreationOptions.gdalOptions;
+  else if ( type == "open" )
+    return m_OpenOptions.gdalOptions;
+  else 
+    {
+    // warn user : wrong option
+    return GDALOptionType();
+    }
+}
+
+void
+OGRExtendedFilenameToOptions::
+SetGDALLayerOptions( const OGRExtendedFilenameToOptions::GDALOptionType & options )
+{
+  std::vector<std::string> tmp;
+  for ( const auto & option : options )
+    {
+    boost::split(tmp, option , boost::is_any_of(":"), boost::token_compress_on);
+    if ( tmp.size()<2 )
+      boost::split(tmp, option , boost::is_any_of("="), boost::token_compress_on);
+    m_LayerOptions.gdalOptions[ tmp[0] ] = tmp[1] ;
+    }
+}
+
+void
+OGRExtendedFilenameToOptions::
+AddGDALLayerOptions( const OGRExtendedFilenameToOptions::GDALOptionType & options )
+{
+  for ( const auto & option : options )
+    {
+  std::vector<std::string> tmp;
+    boost::split(tmp, option , boost::is_any_of(":"), boost::token_compress_on);
+    if ( tmp.size()<2 )
+      boost::split(tmp, option , boost::is_any_of("="), boost::token_compress_on);
+    m_LayerOptions.gdalOptions[ tmp[0] ] = tmp[1] ;
+    }
+}
+
+bool
+OGRExtendedFilenameToOptions::
+SimpleFileNameIsSet() const
+{
+  return m_HasFileName;
+}
+
+bool
+OGRExtendedFilenameToOptions::
+HasGDALLayerOption() const
+{
+  return ! m_LayerOptions.gdalOptions.empty() ;
+}
+
+OGRExtendedFilenameToOptions::
+GDALOptionType
+OGRExtendedFilenameToOptions::
+GetGDALLayerOptions() const
+{
+  GDALOptionType options;
+  for (const auto & option : m_LayerOptions.gdalOptions )
+    {
+    options.push_back( option.first + "=" + option.second );
+    }
+  return options;
+}
+
+#define GetGDALOptionMacro( Type )                 \
+OGRExtendedFilenameToOptions::                     \
+GDALOptionType                                     \
+OGRExtendedFilenameToOptions::                     \
+GetGDAL##Type##Options() const   \
+{                                                  \
+  return m_##Type##Options.gdalOptions;        \
+}                                                  \
+
+GetGDALOptionMacro( Open )
+GetGDALOptionMacro( Creation )
+// GetGDALOptionMacro( Layer )
+
+
+
+} //end namespace otb
diff --git a/Modules/Adapters/GdalAdapters/src/otbOGRVersionProxy.cxx b/Modules/Adapters/GdalAdapters/src/otbOGRVersionProxy.cxx
index 22b7a612ca3f7f557eeed7abe2da3c2e1d047fe9..b616fe752698e68c3731b5ef6bf822802468a33c 100644
--- a/Modules/Adapters/GdalAdapters/src/otbOGRVersionProxy.cxx
+++ b/Modules/Adapters/GdalAdapters/src/otbOGRVersionProxy.cxx
@@ -19,6 +19,7 @@
  */
 
 #include "otbOGRVersionProxy.h"
+#include "otbOGRHelpers.h"
 
 #include "itkMacro.h"
 
@@ -60,12 +61,18 @@ OTBGdalAdapters_EXPORT bool IsOFTInteger64(OGRFieldType type)
 }
 
 
-GDALDatasetType * Open(const char * filename, bool readOnly)
+GDALDatasetType * Open(const char * filename, bool readOnly , std::vector< std::string > const & options )
 {
 #if GDAL_VERSION_NUM<2000000
+  (void)options;
   return OGRSFDriverRegistrar::Open(filename,!readOnly);
 #else
-  return (GDALDatasetType *)GDALOpenEx(filename, (readOnly? GDAL_OF_READONLY : GDAL_OF_UPDATE) | GDAL_OF_VECTOR,NULL,NULL,NULL);
+  return (GDALDatasetType *)GDALOpenEx(
+      filename, 
+      (readOnly? GDAL_OF_READONLY : GDAL_OF_UPDATE) | GDAL_OF_VECTOR,
+      NULL,
+      otb::ogr::StringListConverter( options ).to_ogr(),
+      NULL);
 #endif
 }
 
@@ -78,9 +85,10 @@ void Close(GDALDatasetType * dataset)
 #endif
 }
 
-GDALDatasetType * Create(GDALDriverType * driver, const char * name)
+GDALDatasetType * Create(GDALDriverType * driver, const char * name ,  std::vector< std::string > const & options )
 {
 #if GDAL_VERSION_NUM<2000000
+  (void)options;
   GDALDatasetType * ds = driver->CreateDataSource(name);
 
   if(ds)
@@ -88,7 +96,12 @@ GDALDatasetType * Create(GDALDriverType * driver, const char * name)
 
   return ds;
 #else
-  return driver->Create(name,0,0,0,GDT_Unknown,NULL);
+  return driver->Create( name ,
+                         0 ,
+                         0 ,
+                         0 ,
+                         GDT_Unknown ,
+                         otb::ogr::StringListConverter( options ).to_ogr() );
 #endif
 }
 
diff --git a/Modules/Adapters/GdalAdapters/test/CMakeLists.txt b/Modules/Adapters/GdalAdapters/test/CMakeLists.txt
index 5a0de851487aa4484815aa06e6b244c57d23f480..bc03ae797ebe581884ef8b30c42e3f317c9db315 100644
--- a/Modules/Adapters/GdalAdapters/test/CMakeLists.txt
+++ b/Modules/Adapters/GdalAdapters/test/CMakeLists.txt
@@ -35,5 +35,49 @@ endif()
 add_executable(otbOGRTestsIO otbOGRDataSourceWrapperIO.cxx)
 target_link_libraries(otbOGRTestsIO ${OTBGdalAdapters-Test_LIBRARIES})
 
-add_test(NAME coTuOGRDataSourceWrapperIO
+otb_add_test(NAME coTuOGRDataSourceWrapperIO
          COMMAND otbOGRTestsIO ${INPUTDATA}/ToulousePoints-examples.shp )
+
+set(OTBOGRTests
+otbOGRTestDriver.cxx
+otbOGRExtendedFilenameToOptionsTest.cxx
+otbOGRExtendedFilenameToOptionsGDALTest.cxx
+)
+
+add_executable(otbOGRTestDriver ${OTBOGRTests})
+target_link_libraries(otbOGRTestDriver ${OTBGdalAdapters-Test_LIBRARIES})
+otb_module_target_label(otbOGRTestDriver)
+
+otb_add_test(NAME TvOGRExtendedFilename
+         COMMAND otbOGRTestDriver
+         --compare-ascii ${NOTOL}
+         ${BASELINE}/TvOGRExtendedFilename.txt
+         ${TEMP}/TvOGRExtendedFilenameTest.txt
+         otbOGRExtendedFileName
+         test.shp?&writegeom=ON&gdal:co:QUALITY=75&gdal:co:TILED=YES&gdal:co:BLOCKYSIZE=1024&gdal:lco:layeroption=OPTION&gdal:oo:openoption=OPTION
+         ${TEMP}/TvOGRExtendedFilenameTest.txt     )
+
+#Problem with error thrown by GDAL : unable to catch it with "CPLGetLastErrorMsg"
+# otb_add_test(NAME TvOGRExtendedFilenameGDALOpen
+#          COMMAND otbOGRTestDriver
+#          otbOGRExtendedFileNameGDALOpen
+#          ${INPUTDATA}/ToulousePoints-examples.shp?&gdal:oo:openOption=OPTION
+#           )
+
+otb_add_test(NAME TvOGRExtendedFilenameGDALCreate
+         COMMAND otbOGRTestDriver
+         otbOGRExtendedFileNameGDALCreate
+         test.shp?gdal:co:creationOption=OPTION
+          )
+
+otb_add_test(NAME TvOGRExtendedFilenameGDALLayer
+         COMMAND otbOGRTestDriver
+         otbOGRExtendedFileNameGDALLayer
+         test.shp?&gdal:lco:layeroption=OPTION
+          )
+
+otb_add_test(NAME TvOGRExtendedFilenameGDALLayerOption
+         COMMAND otbOGRTestDriver
+         otbOGRExtendedFileNameGDALLayerOption
+         test.shp
+          )
\ No newline at end of file
diff --git a/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsGDALTest.cxx b/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsGDALTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..37368ea11836c6de38f616d14f368e51a611f702
--- /dev/null
+++ b/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsGDALTest.cxx
@@ -0,0 +1,69 @@
+/*
+ * 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 "cpl_error.h"
+#include "otbOGRExtendedFilenameToOptions.h"
+#include "otbOGRDataSourceWrapper.h"
+#include <iostream>
+#include <fstream>
+
+
+int otbOGRExtendedFileNameGDALOpen(int , char* argv[])
+{
+  auto test = otb::ogr::DataSource::New( argv[1] );
+  std::string  error = CPLGetLastErrorMsg();
+  return 0;
+}
+
+int otbOGRExtendedFileNameGDALCreate(int , char* argv[])
+{
+  auto test = otb::ogr::DataSource::New( argv[1] , otb::ogr::DataSource::Modes::Overwrite);
+  std::string error = CPLGetLastErrorMsg();
+  if ( error.find( "does not support creation option creationOption" ) )
+    return EXIT_SUCCESS;
+  return EXIT_FAILURE;
+}
+
+int otbOGRExtendedFileNameGDALLayer(int , char* argv[])
+{
+  auto test = otb::ogr::DataSource::New( argv[1] , otb::ogr::DataSource::Modes::Update_LayerOverwrite);
+  test->CreateLayer( "2layertest" , 
+      ITK_NULLPTR , 
+      wkbUnknown );
+  std::string error = CPLGetLastErrorMsg();
+  if ( error.find( "does not support layer creation option layeroption" ) )
+    return EXIT_SUCCESS;
+  return EXIT_FAILURE;
+}
+
+int otbOGRExtendedFileNameGDALLayerOption(int , char* argv[])
+{
+  auto test = otb::ogr::DataSource::New( argv[1] , otb::ogr::DataSource::Modes::Update_LayerOverwrite);
+  std::vector<std::string> option { "vectorlayeroption=OPTION" }; 
+  test->CreateLayer( "2layertest" , 
+      ITK_NULLPTR , 
+      wkbUnknown ,
+      option );
+  std::string error = CPLGetLastErrorMsg();
+  if ( error.find( "does not support layer creation option vectorlayeroption" ) )
+    return EXIT_SUCCESS;
+  return EXIT_FAILURE;
+}
+
diff --git a/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsTest.cxx b/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..63df6eeed09ed3c5b63ff8369dd95467bdaadb3c
--- /dev/null
+++ b/Modules/Adapters/GdalAdapters/test/otbOGRExtendedFilenameToOptionsTest.cxx
@@ -0,0 +1,96 @@
+/*
+ * 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 "otbOGRExtendedFilenameToOptions.h"
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+
+
+using namespace otb;
+
+
+typedef OGRExtendedFilenameToOptions FilenameHelperType;
+
+int otbOGRExtendedFileName(int , char* argv[])
+{
+  // Verify the number of parameters in the command line
+  const char * inputExtendedFilename  = argv[1];
+  const char * outputFilename = argv[2];
+
+  std::cout<< argv[1] <<"  "<<argv[2]<<std::endl;
+  FilenameHelperType::Pointer helper = FilenameHelperType::New();
+
+  helper->SetExtendedFileName(inputExtendedFilename);
+
+  std::ofstream file;
+  file.open(outputFilename);
+
+  file << helper->SimpleFileNameIsSet() << std::endl;
+  file << helper->GetSimpleFileName() << std::endl;
+
+  file << "Open option :"<<std::endl;
+  FilenameHelperType::GDALOptionType open = helper->GetGDALOpenOptions();
+  for ( auto option : open )
+    {
+    file<< option << std::endl;
+    }
+
+  file << "Create option :"<<std::endl;
+  FilenameHelperType::GDALOptionType create = helper->GetGDALOptions("creation");
+  for ( auto option : create )
+    {
+    file<< option << std::endl;
+    }
+
+  file << "Layer option :"<<std::endl;
+  FilenameHelperType::GDALOptionType layer = helper->GetGDALOptions("layer");
+  for ( auto option : layer )
+    {
+    file<< option << std::endl;
+    }
+
+  file<< "End of classic helper."<<std::endl;
+
+  layer.push_back("TOTO=first");
+  FilenameHelperType::Pointer layerHelper = 
+    FilenameHelperType::GetGDALLayerOptionsHelper ( layer );
+  std::cout<< layerHelper->GetGDALLayerOptions()[0] <<std::endl;
+  FilenameHelperType::GDALOptionType newOptions;
+    // std::vector< std::string> newOptions;
+  newOptions.push_back("TOTO=second");
+  newOptions.push_back("TiTi=option");
+  layerHelper->AddGDALLayerOptions( newOptions );
+
+  file << layerHelper->SimpleFileNameIsSet() << std::endl;
+  file << layerHelper->HasGDALLayerOption() << std::endl;
+  file << "Layer option from layer helper:"<<std::endl;
+  FilenameHelperType::GDALOptionType latestOptions = layerHelper->GetGDALOptions("layer");
+  // need to sort for dummy windows
+  std::sort( latestOptions.begin() , latestOptions.end() );
+  for ( auto option : latestOptions ) 
+    {
+    file<< option << std::endl;
+    }
+
+  file.close();
+  return EXIT_SUCCESS;
+}
+
diff --git a/Modules/Adapters/GdalAdapters/test/otbOGRTestDriver.cxx b/Modules/Adapters/GdalAdapters/test/otbOGRTestDriver.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..dba04ea4d743cc89be61e25aa01978fd87882a5b
--- /dev/null
+++ b/Modules/Adapters/GdalAdapters/test/otbOGRTestDriver.cxx
@@ -0,0 +1,30 @@
+/*
+ * 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 "otbTestMain.h"
+
+void RegisterTests()
+{
+  REGISTER_TEST(otbOGRExtendedFileName);
+  REGISTER_TEST(otbOGRExtendedFileNameGDALOpen);
+  REGISTER_TEST(otbOGRExtendedFileNameGDALCreate);
+  REGISTER_TEST(otbOGRExtendedFileNameGDALLayer);
+  REGISTER_TEST(otbOGRExtendedFileNameGDALLayerOption);
+}
diff --git a/Modules/Applications/AppClassification/app/CMakeLists.txt b/Modules/Applications/AppClassification/app/CMakeLists.txt
index 3e1dbd85f5cd2ca409ddb9ef51389edf5e544976..d34c3842d0a6d9e39011b98df48af97bfb2ceb87 100644
--- a/Modules/Applications/AppClassification/app/CMakeLists.txt
+++ b/Modules/Applications/AppClassification/app/CMakeLists.txt
@@ -125,5 +125,10 @@ otb_create_application(
   SOURCES        otbVectorClassifier.cxx
   LINK_LIBRARIES ${${otb-module}_LIBRARIES})
 
+otb_create_application(
+  NAME           SampleAugmentation
+  SOURCES        otbSampleAugmentation.cxx
+  LINK_LIBRARIES ${${otb-module}_LIBRARIES})
+
 # Mantis-1427 : temporary fix
 add_dependencies(${otb-module}-all otbapp_ImageEnvelope)
diff --git a/Modules/Applications/AppClassification/app/otbSampleAugmentation.cxx b/Modules/Applications/AppClassification/app/otbSampleAugmentation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6bb7382856e619cce13f501acea90530cfd18f37
--- /dev/null
+++ b/Modules/Applications/AppClassification/app/otbSampleAugmentation.cxx
@@ -0,0 +1,270 @@
+/*
+ * 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 "otbWrapperApplication.h"
+#include "otbWrapperApplicationFactory.h"
+#include "otbOGRDataSourceWrapper.h"
+#include "otbSampleAugmentationFilter.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+
+class SampleAugmentation : public Application
+{
+public:
+  /** Standard class typedefs. */
+  typedef SampleAugmentation              Self;
+  typedef Application                   Superclass;
+  typedef itk::SmartPointer<Self>       Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+
+  /** Standard macro */
+  itkNewMacro(Self);
+
+  itkTypeMacro(SampleAugmentation, otb::Application);
+
+  /** Filters typedef */
+  using FilterType = otb::SampleAugmentationFilter;
+  using SampleType = FilterType::SampleType;
+  using SampleVectorType = FilterType::SampleVectorType;
+
+private:
+  SampleAugmentation() {}
+
+  void DoInit()
+  {
+    SetName("SampleAugmentation");
+    SetDescription("Generates synthetic samples from a sample data file.");
+
+    // Documentation
+    SetDocName("Sample Augmentation");
+    SetDocLongDescription("The application takes a sample data file as "
+                          "generated by the SampleExtraction application and "
+                          "generates synthetic samples to increase the number of "
+                          "available samples.");
+    SetDocLimitations("None");
+    SetDocAuthors("OTB-Team");
+    SetDocSeeAlso(" ");
+
+    AddDocTag(Tags::Learning);
+
+    AddParameter(ParameterType_InputFilename, "in", "Input samples");
+    SetParameterDescription("in","Vector data file containing samples (OGR format)");
+
+    AddParameter(ParameterType_OutputFilename, "out", "Output samples");
+    SetParameterDescription("out","Output vector data file storing new samples"
+                            "(OGR format).");
+
+    AddParameter(ParameterType_ListView, "field", "Field Name");
+    SetParameterDescription("field","Name of the field carrying the class name in the input vectors.");
+    SetListViewSingleSelectionMode("field",true);
+    
+    AddParameter(ParameterType_Int, "layer", "Layer Index");
+    SetParameterDescription("layer", "Layer index to read in the input vector file.");
+    MandatoryOff("layer");
+    SetDefaultParameterInt("layer",0);
+
+    AddParameter(ParameterType_Int, "label", "Label of the class to be augmented");
+    SetParameterDescription("label", "Label of the class of the input file for which "
+                            "new samples will be generated.");
+    SetDefaultParameterInt("label",1);
+
+    AddParameter(ParameterType_Int, "samples", "Number of generated samples");
+    SetParameterDescription("samples", "Number of synthetic samples that will "
+                            "be generated.");
+    SetDefaultParameterInt("samples",100);
+
+    AddParameter(ParameterType_ListView, "exclude", "Field names for excluded features.");
+    SetParameterDescription("exclude",
+                            "List of field names in the input vector data that will not be generated in the output file.");
+
+    AddParameter(ParameterType_Choice, "strategy", "Augmentation strategy");
+
+    AddChoice("strategy.replicate","Replicate input samples");
+    SetParameterDescription("strategy.replicate","The new samples are generated "
+                            "by replicating input samples which are randomly "
+                            "selected with replacement.");
+
+    AddChoice("strategy.jitter","Jitter input samples");
+    SetParameterDescription("strategy.jitter","The new samples are generated "
+                            "by adding gaussian noise to input samples which are "
+                            "randomly selected with replacement.");
+    AddParameter(ParameterType_Float, "strategy.jitter.stdfactor", 
+                 "Factor for dividing the standard deviation of each feature");
+    SetParameterDescription("strategy.jitter.stdfactor", 
+                            "The noise added to the input samples will have the "
+                            "standard deviation of the input features divided "
+                            "by the value of this parameter. ");
+    SetDefaultParameterFloat("strategy.jitter.stdfactor",10);
+
+    AddChoice("strategy.smote","Smote input samples");
+    SetParameterDescription("strategy.smote","The new samples are generated "
+                            "by using the SMOTE algorithm (http://dx.doi.org/10.1613/jair.953) "
+                            "on input samples which are "
+                            "randomly selected with replacement.");
+    AddParameter(ParameterType_Int, "strategy.smote.neighbors", 
+                 "Number of nearest neighbors.");
+    SetParameterDescription("strategy.smote.neighbors", 
+                            "Number of nearest neighbors to be used in the "
+                            "SMOTE algorithm");
+    SetDefaultParameterFloat("strategy.smote.neighbors", 5);
+
+    AddRANDParameter("seed");
+    MandatoryOff("seed");
+
+    // Doc example parameter settings
+    SetDocExampleParameterValue("in", "samples.sqlite");
+    SetDocExampleParameterValue("field", "class");
+    SetDocExampleParameterValue("label", "3");
+    SetDocExampleParameterValue("samples", "100");
+    SetDocExampleParameterValue("out","augmented_samples.sqlite");
+    SetDocExampleParameterValue( "exclude", "OGC_FID name class originfid" );
+    SetDocExampleParameterValue("strategy", "smote");
+    SetDocExampleParameterValue("strategy.smote.neighbors", "5");
+
+    SetOfficialDocLink();
+  }
+
+  void DoUpdateParameters()
+  {
+    if ( HasValue("in") )
+      {
+      std::string vectorFile = GetParameterString("in");
+      ogr::DataSource::Pointer ogrDS =
+        ogr::DataSource::New(vectorFile, ogr::DataSource::Modes::Read);
+      ogr::Layer layer = ogrDS->GetLayer(this->GetParameterInt("layer"));
+      ogr::Feature feature = layer.ogr().GetNextFeature();
+
+      ClearChoices("exclude");
+      ClearChoices("field");
+      
+      for(int iField=0; iField<feature.ogr().GetFieldCount(); iField++)
+        {
+        std::string key, item = feature.ogr().GetFieldDefnRef(iField)->GetNameRef();
+        key = item;
+        std::string::iterator end = std::remove_if(key.begin(),key.end(),
+                                                   [](auto c){return !std::isalnum(c);});
+        std::transform(key.begin(), end, key.begin(), tolower);
+        
+        OGRFieldType fieldType = feature.ogr().GetFieldDefnRef(iField)->GetType();
+        
+        if(fieldType == OFTString || fieldType == OFTInteger || ogr::version_proxy::IsOFTInteger64(fieldType))
+          {
+          std::string tmpKey="field."+key.substr(0, end - key.begin());
+          AddChoice(tmpKey,item);
+          }
+        if( fieldType == OFTInteger || ogr::version_proxy::IsOFTInteger64( fieldType ) || fieldType == OFTReal )
+          {
+          std::string tmpKey = "exclude." + key.substr( 0, static_cast<unsigned long>( end - key.begin() ) );
+          AddChoice( tmpKey, item );
+          }
+        }
+      }
+  }
+
+  void DoExecute()
+    {
+    ogr::DataSource::Pointer vectors;
+    ogr::DataSource::Pointer output;
+    vectors = ogr::DataSource::New(this->GetParameterString("in"));
+    output = ogr::DataSource::New(this->GetParameterString("out"),
+                                  ogr::DataSource::Modes::Overwrite);
+
+    // Retrieve the field name
+    std::vector<int> selectedCFieldIdx = GetSelectedItems("field");
+
+    if(selectedCFieldIdx.empty())
+      {
+      otbAppLogFATAL(<<"No field has been selected for data labelling!");
+      }
+
+  std::vector<std::string> cFieldNames = GetChoiceNames("field");  
+  std::string fieldName = cFieldNames[selectedCFieldIdx.front()];
+    
+  std::vector<std::string> excludedFields = 
+    GetExcludedFields( GetChoiceNames( "exclude" ), 
+                       GetSelectedItems( "exclude" ));
+  for(const auto& ef : excludedFields)
+    otbAppLogINFO("Excluding feature " << ef << '\n');
+
+  int seed = std::time(nullptr);
+  if(IsParameterEnabled("seed")) seed = this->GetParameterInt("seed");
+
+
+  FilterType::Pointer filter = FilterType::New();
+  filter->SetInput(vectors);
+  filter->SetLayer(this->GetParameterInt("layer"));
+  filter->SetNumberOfSamples(this->GetParameterInt("samples"));
+  filter->SetOutputSamples(output);
+  filter->SetClassFieldName(fieldName);
+  filter->SetLabel(this->GetParameterInt("label"));
+  filter->SetExcludedFields(excludedFields);
+  filter->SetSeed(seed);
+  switch (this->GetParameterInt("strategy"))
+    {
+    // replicate
+    case 0:
+    {
+    otbAppLogINFO("Augmentation strategy : replicate");
+    filter->SetStrategy(FilterType::Strategy::Replicate);
+    }
+      break;
+    // jitter
+    case 1:
+    {
+    otbAppLogINFO("Augmentation strategy : jitter");
+    filter->SetStrategy(FilterType::Strategy::Jitter);
+    filter->SetStdFactor(this->GetParameterFloat("strategy.jitter.stdfactor"));
+    }
+    break;
+    case 2:
+    {
+    otbAppLogINFO("Augmentation strategy : smote");
+    filter->SetStrategy(FilterType::Strategy::Smote);
+    filter->SetSmoteNeighbors(this->GetParameterInt("strategy.smote.neighbors"));
+    }
+    break;
+    }
+  filter->Update();
+  output->SyncToDisk();
+    }
+
+
+  std::vector<std::string> GetExcludedFields(const std::vector<std::string>& fieldNames,
+                                             const std::vector<int>& selectedIdx)
+  {
+    auto nbFeatures = static_cast<unsigned int>(selectedIdx.size());
+    std::vector<std::string> result( nbFeatures );
+    for( unsigned int i = 0; i < nbFeatures; ++i )
+      {
+      result[i] = fieldNames[selectedIdx[i]];
+      }
+    return result;
+  }
+
+};
+
+} // end of namespace Wrapper
+} // end of namespace otb
+
+OTB_APPLICATION_EXPORT(otb::Wrapper::SampleAugmentation)
diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt
index fae1474266db959a03a6accd01b14b43f00f4ec0..e848e08ed8fca6c2f1bd840c6adc16816b716bc6 100644
--- a/Modules/Applications/AppClassification/test/CMakeLists.txt
+++ b/Modules/Applications/AppClassification/test/CMakeLists.txt
@@ -972,3 +972,39 @@ otb_test_application(
   ${OTBAPP_BASELINE_FILES}/apTvClMultiImageSamplingRate_out_3.csv
   ${TEMP}/apTvClMultiImageSamplingRate_out_3.csv
 )
+
+#------------ SampleAgmentation TESTS ----------------
+otb_test_application(NAME apTvClSampleAugmentationReplicate
+  APP  SampleAugmentation
+  OPTIONS -in ${INPUTDATA}/Classification/apTvClSampleExtractionOut.sqlite
+  -field class
+  -label 3
+  -samples 100
+  -out ${TEMP}/apTvClSampleAugmentationReplicate.sqlite
+  -exclude originfid
+  -strategy replicate
+  )
+
+otb_test_application(NAME apTvClSampleAugmentationJitter
+  APP  SampleAugmentation
+  OPTIONS -in ${INPUTDATA}/Classification/apTvClSampleExtractionOut.sqlite
+  -field class
+  -label 3
+  -samples 100
+  -out ${TEMP}/apTvClSampleAugmentationJitter.sqlite
+  -exclude originfid
+  -strategy jitter
+  -strategy.jitter.stdfactor 10
+  )
+
+otb_test_application(NAME apTvClSampleAugmentationSmote
+  APP  SampleAugmentation
+  OPTIONS -in ${INPUTDATA}/Classification/apTvClSampleExtractionOut.sqlite
+  -field class
+  -label 3
+  -samples 100
+  -out ${TEMP}/apTvClSampleAugmentationSmote.sqlite
+  -exclude originfid
+  -strategy smote
+  -strategy.smote.neighbors 5
+  )
diff --git a/Modules/Applications/AppImageUtils/app/otbCompareImages.cxx b/Modules/Applications/AppImageUtils/app/otbCompareImages.cxx
index fab3a3d9096e3d71ad39c26c182dfe8e41424271..cbdcb90795e11c3400a1bbeb9ab02c4b612f98db 100644
--- a/Modules/Applications/AppImageUtils/app/otbCompareImages.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbCompareImages.cxx
@@ -172,9 +172,12 @@ private:
   void DoExecute() override
   {
     // Init filters
-    m_ExtractRefFilter = ExtractROIMonoFilterType::New();
-    m_ExtractMeasFilter = ExtractROIMonoFilterType::New();
-    m_CompareFilter = StreamingCompareImageFilterType::New();
+    ExtractROIMonoFilterType::Pointer extractRefFilter = 
+      ExtractROIMonoFilterType::New();
+    ExtractROIMonoFilterType::Pointer extractMeasFilter = 
+      ExtractROIMonoFilterType::New();
+    StreamingCompareImageFilterType::Pointer compareFilter = 
+      StreamingCompareImageFilterType::New(); 
 
     // Get input image pointers
     FloatVectorImageType::Pointer refIm = this->GetParameterImage("ref.in");
@@ -200,41 +203,37 @@ private:
       otbAppLogFATAL( << "ROI is not contained in the images regions");
       }
 
-    m_ExtractRefFilter->SetInput( refIm );
-    m_ExtractMeasFilter->SetInput( measIm );
+    extractRefFilter->SetInput( refIm );
+    extractMeasFilter->SetInput( measIm );
 
-    m_ExtractRefFilter->SetExtractionRegion(region);
-    m_ExtractMeasFilter->SetExtractionRegion(region);
+    extractRefFilter->SetExtractionRegion(region);
+    extractMeasFilter->SetExtractionRegion(region);
 
     // Set channels to extract
     otbAppLogINFO( << "reference image channel "<<this->GetParameterInt("ref.channel")<<" is compared with measured image channel "<<this->GetParameterInt("meas.channel"));
-    m_ExtractRefFilter->SetChannel( this->GetParameterInt("ref.channel") );
-    m_ExtractMeasFilter->SetChannel( this->GetParameterInt("meas.channel") );
+    extractRefFilter->SetChannel( this->GetParameterInt("ref.channel") );
+    extractMeasFilter->SetChannel( this->GetParameterInt("meas.channel") );
 
     // Compute comparison
-    m_CompareFilter->SetInput1(m_ExtractRefFilter->GetOutput());
-    m_CompareFilter->SetInput2(m_ExtractMeasFilter->GetOutput());
-    m_CompareFilter->SetPhysicalSpaceCheck(false);
-    m_CompareFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
-    AddProcess(m_CompareFilter->GetStreamer(), "Comparing...");
-    m_CompareFilter->Update();
+    compareFilter->SetInput1(extractRefFilter->GetOutput());
+    compareFilter->SetInput2(extractMeasFilter->GetOutput());
+    compareFilter->SetPhysicalSpaceCheck(false);
+    compareFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
+    AddProcess(compareFilter->GetStreamer(), "Comparing...");
+    compareFilter->Update();
 
     // Show result
-    otbAppLogINFO( << "MSE: " << m_CompareFilter->GetMSE() );
-    otbAppLogINFO( << "MAE: " << m_CompareFilter->GetMAE() );
-    otbAppLogINFO( << "PSNR: " << m_CompareFilter->GetPSNR() );
-    otbAppLogINFO( << "Number of Pixel different: " << m_CompareFilter->GetDiffCount() );
-
-    SetParameterFloat( "mse",m_CompareFilter->GetMSE());
-    SetParameterFloat( "mae",m_CompareFilter->GetMAE());
-    SetParameterFloat( "psnr",m_CompareFilter->GetPSNR());
-    SetParameterFloat( "count",m_CompareFilter->GetDiffCount());
+    otbAppLogINFO( << "MSE: " << compareFilter->GetMSE() );
+    otbAppLogINFO( << "MAE: " << compareFilter->GetMAE() );
+    otbAppLogINFO( << "PSNR: " << compareFilter->GetPSNR() );
+    otbAppLogINFO( << "Number of Pixel different: " << compareFilter->GetDiffCount() );
+
+    SetParameterFloat( "mse",compareFilter->GetMSE());
+    SetParameterFloat( "mae",compareFilter->GetMAE());
+    SetParameterFloat( "psnr",compareFilter->GetPSNR());
+    SetParameterFloat( "count",compareFilter->GetDiffCount());
+    RegisterPipeline();
   }
-
-
-  ExtractROIMonoFilterType::Pointer m_ExtractRefFilter;
-  ExtractROIMonoFilterType::Pointer m_ExtractMeasFilter;
-  StreamingCompareImageFilterType::Pointer m_CompareFilter;
 };
 
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbConcatenateImages.cxx b/Modules/Applications/AppImageUtils/app/otbConcatenateImages.cxx
index 7e3459d154b7e919115d129c5084259b51792130..0c9d52659cf8864c387b70388470f51b9114db59 100644
--- a/Modules/Applications/AppImageUtils/app/otbConcatenateImages.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbConcatenateImages.cxx
@@ -72,10 +72,6 @@ private:
     AddDocTag("Concatenation");
     AddDocTag("Multi-channel");
 
-    m_Concatener = ListConcatenerFilterType::New();
-    m_ExtractorList = ExtractROIFilterListType::New();
-    m_ImageList = ImageListType::New();
-
     AddParameter(ParameterType_InputImageList,  "il",   "Input images list");
     SetParameterDescription("il", "The list of images to concatenate, must have the same size.");
 
@@ -94,15 +90,16 @@ private:
   void DoUpdateParameters() override
   {
     // Nothing to do here for the parameters : all are independent
-
-    // Reinitialize the object
-    m_Concatener = ListConcatenerFilterType::New();
-    m_ImageList = ImageListType::New();
-    m_ExtractorList = ExtractROIFilterListType::New();
   }
 
   void DoExecute() override
   {
+    ListConcatenerFilterType::Pointer m_Concatener =
+      ListConcatenerFilterType::New();
+    ExtractROIFilterListType::Pointer m_ExtractorList = 
+      ExtractROIFilterListType::New();
+    ImageListType::Pointer m_ImageList =
+      ImageListType::New();
     // Get the input image list
     FloatVectorImageListType::Pointer inList = this->GetParameterImageList("il");
 
@@ -140,12 +137,8 @@ private:
     m_Concatener->SetInput( m_ImageList );
 
     SetParameterOutputImage("out", m_Concatener->GetOutput());
+    RegisterPipeline();
   }
-
-
-  ListConcatenerFilterType::Pointer  m_Concatener;
-  ExtractROIFilterListType::Pointer  m_ExtractorList;
-  ImageListType::Pointer        m_ImageList;
 };
 
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbExtractROI.cxx b/Modules/Applications/AppImageUtils/app/otbExtractROI.cxx
index fd773fe9cad85082d67e2ccd85480823e85c7e44..66f2886edc0c2b5d47acca8bef211319d023726e 100644
--- a/Modules/Applications/AppImageUtils/app/otbExtractROI.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbExtractROI.cxx
@@ -828,23 +828,21 @@ private:
 
     this->CropRegionOfInterest();
 
-    m_ExtractROIFilter = ExtractROIFilterType::New();
-    m_ExtractROIFilter->SetInput(inImage);
-    m_ExtractROIFilter->SetStartX(GetParameterInt("startx"));
-    m_ExtractROIFilter->SetStartY(GetParameterInt("starty"));
-    m_ExtractROIFilter->SetSizeX(GetParameterInt("sizex"));
-    m_ExtractROIFilter->SetSizeY(GetParameterInt("sizey"));
+    ExtractROIFilterType::Pointer extractROIFilter = ExtractROIFilterType::New();
+    extractROIFilter->SetInput(inImage);
+    extractROIFilter->SetStartX(GetParameterInt("startx"));
+    extractROIFilter->SetStartY(GetParameterInt("starty"));
+    extractROIFilter->SetSizeX(GetParameterInt("sizex"));
+    extractROIFilter->SetSizeY(GetParameterInt("sizey"));
 
     for (unsigned int idx = 0; idx < GetSelectedItems("cl").size(); ++idx)
       {
-      m_ExtractROIFilter->SetChannel(GetSelectedItems("cl")[idx] + 1 );
+      extractROIFilter->SetChannel(GetSelectedItems("cl")[idx] + 1 );
       }
 
-    SetParameterOutputImage("out", m_ExtractROIFilter->GetOutput());
+    SetParameterOutputImage("out", extractROIFilter->GetOutput());
+    RegisterPipeline();
   }
-
-  ExtractROIFilterType::Pointer   m_ExtractROIFilter;
-
 };
 
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbQuicklook.cxx b/Modules/Applications/AppImageUtils/app/otbQuicklook.cxx
index 978740d95ecd1eba022252b3be4bb6818359d026..f31b64075bec5a3d90dcb6e8c04d2685a555ecde 100644
--- a/Modules/Applications/AppImageUtils/app/otbQuicklook.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbQuicklook.cxx
@@ -207,27 +207,29 @@ bool CropRegionOfInterest()
   {
     InputImageType::Pointer inImage = GetParameterImage("in");
 
-    m_ExtractROIFilter = ExtractROIFilterType::New();
-    m_ResamplingFilter = ShrinkImageFilterType::New();
+    ExtractROIFilterType::Pointer extractROIFilter =
+      ExtractROIFilterType::New();
+    ShrinkImageFilterType::Pointer resamplingFilter =
+      ShrinkImageFilterType::New();
 
     // The image on which the quicklook will be generated
-    // Will eventually be the m_ExtractROIFilter output
+    // Will eventually be the extractROIFilter output
 
     if (HasUserValue("rox") || HasUserValue("roy")
         || HasUserValue("rsx") || HasUserValue("rsy")
         || (GetSelectedItems("cl").size() > 0))
       {
-      m_ExtractROIFilter->SetInput(inImage);
-      m_ExtractROIFilter->SetStartX(GetParameterInt("rox"));
-      m_ExtractROIFilter->SetStartY(GetParameterInt("roy"));
-      m_ExtractROIFilter->SetSizeX(GetParameterInt("rsx"));
-      m_ExtractROIFilter->SetSizeY(GetParameterInt("rsy"));
+      extractROIFilter->SetInput(inImage);
+      extractROIFilter->SetStartX(GetParameterInt("rox"));
+      extractROIFilter->SetStartY(GetParameterInt("roy"));
+      extractROIFilter->SetSizeX(GetParameterInt("rsx"));
+      extractROIFilter->SetSizeY(GetParameterInt("rsy"));
 
       if ((GetSelectedItems("cl").size() > 0))
         {
         for (unsigned int idx = 0; idx < GetSelectedItems("cl").size(); ++idx)
           {
-          m_ExtractROIFilter->SetChannel(GetSelectedItems("cl")[idx] + 1 );
+          extractROIFilter->SetChannel(GetSelectedItems("cl")[idx] + 1 );
           }
         }
       else
@@ -235,14 +237,14 @@ bool CropRegionOfInterest()
         unsigned int nbComponents = inImage->GetNumberOfComponentsPerPixel();
         for (unsigned int idx = 0; idx < nbComponents; ++idx)
           {
-          m_ExtractROIFilter->SetChannel(idx + 1);
+          extractROIFilter->SetChannel(idx + 1);
           }
         }
-      m_ResamplingFilter->SetInput( m_ExtractROIFilter->GetOutput() );
+      resamplingFilter->SetInput( extractROIFilter->GetOutput() );
       }
     else
       {
-      m_ResamplingFilter->SetInput(inImage);
+      resamplingFilter->SetInput(inImage);
       }
 
     unsigned int Ratio = static_cast<unsigned int>(GetParameterInt("sr"));
@@ -278,15 +280,13 @@ bool CropRegionOfInterest()
       }
     otbAppLogINFO( << "Ratio used: "<<Ratio << ".");
 
-    m_ResamplingFilter->SetShrinkFactor( Ratio );
-    m_ResamplingFilter->Update();
+    resamplingFilter->SetShrinkFactor( Ratio );
+    resamplingFilter->Update();
 
-    SetParameterOutputImage("out", m_ResamplingFilter->GetOutput());
+    SetParameterOutputImage("out", resamplingFilter->GetOutput());
+    RegisterPipeline();
   }
 
-  ExtractROIFilterType::Pointer m_ExtractROIFilter;
-  ShrinkImageFilterType::Pointer m_ResamplingFilter;
-
 };
 
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbRescale.cxx b/Modules/Applications/AppImageUtils/app/otbRescale.cxx
index a94e8440ac341c8a4964734145096686c3b89dcd..ad0992f5048a89db4af581e732dc1e44859e806c 100644
--- a/Modules/Applications/AppImageUtils/app/otbRescale.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbRescale.cxx
@@ -100,24 +100,25 @@ private:
     FloatVectorImageType::Pointer inImage = GetParameterImage("in");
 
     otbAppLogDEBUG( << "Starting Min/Max computation" )
+  
+    MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New();
+    minMaxFilter->SetInput( inImage );
+    minMaxFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
 
-    m_MinMaxFilter = MinMaxFilterType::New();
-    m_MinMaxFilter->SetInput( inImage );
-    m_MinMaxFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
+    AddProcess(minMaxFilter->GetStreamer(), "Min/Max computing");
+    minMaxFilter->Update();
 
-    AddProcess(m_MinMaxFilter->GetStreamer(), "Min/Max computing");
-    m_MinMaxFilter->Update();
-
-    otbAppLogDEBUG( << "Min/Max computation done : min=" << m_MinMaxFilter->GetMinimum()
-                    << " max=" << m_MinMaxFilter->GetMaximum() )
+    otbAppLogDEBUG( << "Min/Max computation done : min=" << minMaxFilter->GetMinimum()
+                    << " max=" << minMaxFilter->GetMaximum() )
 
     FloatVectorImageType::PixelType inMin, inMax;
 
-    m_RescaleFilter = RescaleImageFilterType::New();
-    m_RescaleFilter->SetInput( inImage );
-    m_RescaleFilter->SetAutomaticInputMinMaxComputation(false);
-    m_RescaleFilter->SetInputMinimum( m_MinMaxFilter->GetMinimum() );
-    m_RescaleFilter->SetInputMaximum( m_MinMaxFilter->GetMaximum() );
+    RescaleImageFilterType::Pointer rescaleFilter = 
+      RescaleImageFilterType::New();
+    rescaleFilter->SetInput( inImage );
+    rescaleFilter->SetAutomaticInputMinMaxComputation(false);
+    rescaleFilter->SetInputMinimum( minMaxFilter->GetMinimum() );
+    rescaleFilter->SetInputMaximum( minMaxFilter->GetMaximum() );
 
     FloatVectorImageType::PixelType outMin, outMax;
     outMin.SetSize( inImage->GetNumberOfComponentsPerPixel() );
@@ -125,15 +126,13 @@ private:
     outMin.Fill( GetParameterFloat("outmin") );
     outMax.Fill( GetParameterFloat("outmax") );
 
-    m_RescaleFilter->SetOutputMinimum( outMin );
-    m_RescaleFilter->SetOutputMaximum( outMax );
-    m_RescaleFilter->UpdateOutputInformation();
+    rescaleFilter->SetOutputMinimum( outMin );
+    rescaleFilter->SetOutputMaximum( outMax );
+    rescaleFilter->UpdateOutputInformation();
 
-    SetParameterOutputImage("out", m_RescaleFilter->GetOutput());
+    SetParameterOutputImage("out", rescaleFilter->GetOutput());
+    RegisterPipeline();
   }
-
-  RescaleImageFilterType::Pointer m_RescaleFilter;
-  MinMaxFilterType::Pointer       m_MinMaxFilter;
 };
 
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbSplitImage.cxx b/Modules/Applications/AppImageUtils/app/otbSplitImage.cxx
index fba6fb7580027a544875ca533104d631593e0a05..3f73fba77a07e69fd3bd4a58f502dc4c285d90ea 100644
--- a/Modules/Applications/AppImageUtils/app/otbSplitImage.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbSplitImage.cxx
@@ -103,13 +103,13 @@ private:
     ext   = itksys::SystemTools::GetFilenameExtension(ofname);
 
     // Set the extract filter input image
-    m_Filter = FilterType::New();
-    m_Filter->SetInput(inImage);
+    FilterType::Pointer filter = FilterType::New();
+    filter->SetInput(inImage);
 
     for (unsigned int i = 0; i < inImage->GetNumberOfComponentsPerPixel(); ++i)
       {
       // Set the channel to extract
-      m_Filter->SetChannel(i+1);
+      filter->SetChannel(i+1);
 
       // build the current output filename
       std::ostringstream oss;
@@ -129,7 +129,7 @@ private:
       // Set the filename of the current output image
       paramOut->SetFileName(oss.str());
       otbAppLogINFO(<< "File: "<<paramOut->GetFileName() << " will be written.");
-      paramOut->SetValue(m_Filter->GetOutput());
+      paramOut->SetValue(filter->GetOutput());
       paramOut->SetPixelType(this->GetParameterOutputImagePixelType("out"));
       // Add the current level to be written
       paramOut->InitializeWriters();
@@ -140,9 +140,8 @@ private:
     // Disable the output Image parameter to avoid writing
     // the last image (Application::ExecuteAndWriteOutput method)
     DisableParameter("out");
+    RegisterPipeline();
   }
-
-  FilterType::Pointer        m_Filter;
 };
 }
 }
diff --git a/Modules/Applications/AppImageUtils/app/otbTileFusion.cxx b/Modules/Applications/AppImageUtils/app/otbTileFusion.cxx
index fd53f599b9ab23dd9f12548e539c84e14cc9cdf8..7ba75ba1a3007513cc3d864b0287a2aa340ea451 100644
--- a/Modules/Applications/AppImageUtils/app/otbTileFusion.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbTileFusion.cxx
@@ -95,23 +95,22 @@ private:
       itkExceptionMacro("No input Image set...");
       }
 
-    m_FusionFilter = TileFilterType::New();
+    TileFilterType::Pointer fusionFilter = TileFilterType::New();
 
     TileFilterType::SizeType layout;
     layout[0] = this->GetParameterInt("cols");
     layout[1] = this->GetParameterInt("rows");
-    m_FusionFilter->SetLayout(layout);
+    fusionFilter->SetLayout(layout);
 
     for (unsigned int i=0; i<(layout[0]*layout[1]); i++)
       {
-      m_FusionFilter->SetInput(i,tileList->GetNthElement(i));
+      fusionFilter->SetInput(i,tileList->GetNthElement(i));
       }
 
-    SetParameterOutputImage("out", m_FusionFilter->GetOutput());
+    SetParameterOutputImage("out", fusionFilter->GetOutput());
+    RegisterPipeline();
   }
 
-  TileFilterType::Pointer m_FusionFilter;
-
 };
 
 }
diff --git a/Modules/Applications/AppSegmentation/app/otbLSMSSegmentation.cxx b/Modules/Applications/AppSegmentation/app/otbLSMSSegmentation.cxx
index 1d1fe5e17c187f1a1f92a72ccea9287990fd576e..290b393e841bbfef53018353985f4912a29f14e9 100644
--- a/Modules/Applications/AppSegmentation/app/otbLSMSSegmentation.cxx
+++ b/Modules/Applications/AppSegmentation/app/otbLSMSSegmentation.cxx
@@ -88,13 +88,14 @@ public:
     LabelImageType,
     AffineFunctorType>                        LabelShiftFilterType;
 
-  LSMSSegmentation(): m_FinalReader(),m_ImportGeoInformationFilter(),m_FilesToRemoveAfterExecute(),m_TmpDirCleanup(false){}
+  LSMSSegmentation(): //m_FinalReader(),m_ImportGeoInformationFilter(),
+    m_FilesToRemoveAfterExecute(),m_TmpDirCleanup(false){}
 
   ~LSMSSegmentation() override{}
 
 private:
-  LabelImageReaderType::Pointer m_FinalReader;
-  ImportGeoInformationImageFilterType::Pointer m_ImportGeoInformationFilter;
+  // LabelImageReaderType::Pointer m_FinalReader;
+  // ImportGeoInformationImageFilterType::Pointer m_ImportGeoInformationFilter;
   std::vector<std::string> m_FilesToRemoveAfterExecute;
   bool m_TmpDirCleanup;
 
@@ -708,20 +709,23 @@ private:
       otbAppLogINFO(<<"Elapsed time: "<<(double)(toc - tic) / CLOCKS_PER_SEC<<" seconds");
 
       // Final writing
-      m_FinalReader = LabelImageReaderType::New();
-      m_FinalReader->SetFileName(vrtfile);
+      LabelImageReaderType::Pointer finalReader = LabelImageReaderType::New();
+      finalReader->SetFileName(vrtfile);
 
-      m_ImportGeoInformationFilter = ImportGeoInformationImageFilterType::New();
-      m_ImportGeoInformationFilter->SetInput(m_FinalReader->GetOutput());
-      m_ImportGeoInformationFilter->SetSource(imageIn);
+      ImportGeoInformationImageFilterType::Pointer 
+        importGeoInformationFilter = 
+        ImportGeoInformationImageFilterType::New();
+      importGeoInformationFilter->SetInput(finalReader->GetOutput());
+      importGeoInformationFilter->SetSource(imageIn);
 
-      SetParameterOutputImage("out",m_ImportGeoInformationFilter->GetOutput());
+      SetParameterOutputImage("out",importGeoInformationFilter->GetOutput());
+      RegisterPipeline();
   }
 
   void AfterExecuteAndWriteOutputs() override
   {
     // Release input files
-    m_FinalReader = ITK_NULLPTR;
+    // finalReader = ITK_NULLPTR;
 
     if(GetParameterInt("cleanup"))
       {
diff --git a/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx b/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx
index 3b8dca5976ca3ca7c8ee1fba11e4efa1b42e8563..1d30963c546efd88ebc84ec613144f2463a6ade8 100644
--- a/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx
+++ b/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx
@@ -181,21 +181,21 @@ private:
   {
     FloatVectorImageType* input = GetParameterImage("in");
 
-    m_Filter = MSFilterType::New();
+    MSFilterType::Pointer filter = MSFilterType::New();
 
-    m_Filter->SetInput(input);
+    filter->SetInput(input);
 
-    m_Filter->SetSpatialBandwidth(GetParameterInt("spatialr"));
-    m_Filter->SetRangeBandwidth(GetParameterFloat("ranger"));
-    m_Filter->SetThreshold(GetParameterFloat("thres"));
-    m_Filter->SetMaxIterationNumber(GetParameterInt("maxiter"));
-    m_Filter->SetRangeBandwidthRamp(GetParameterFloat("rangeramp"));
-    m_Filter->SetModeSearch(GetParameterInt("modesearch"));
+    filter->SetSpatialBandwidth(GetParameterInt("spatialr"));
+    filter->SetRangeBandwidth(GetParameterFloat("ranger"));
+    filter->SetThreshold(GetParameterFloat("thres"));
+    filter->SetMaxIterationNumber(GetParameterInt("maxiter"));
+    filter->SetRangeBandwidthRamp(GetParameterFloat("rangeramp"));
+    filter->SetModeSearch(GetParameterInt("modesearch"));
 
     //Compute the margin used to ensure exact results (tile wise smoothing)
     //This margin is valid for the default uniform kernel used by the
     //MeanShiftSmoothing filter (bandwidth equal to radius in this case)
-    const unsigned int margin = (m_Filter->GetMaxIterationNumber() * m_Filter->GetSpatialBandwidth()) + 1;
+    const unsigned int margin = (filter->GetMaxIterationNumber() * filter->GetSpatialBandwidth()) + 1;
     
     otbAppLogINFO(<<"Margin of " << margin << " pixels applied to each tile to stabilized mean shift filtering." << std::endl);
 
@@ -204,19 +204,18 @@ private:
       otbAppLogWARNING(<<"Margin value exceed the input image size." << std::endl);
       }
 
-    SetParameterOutputImage("fout", m_Filter->GetOutput());
+    SetParameterOutputImage("fout", filter->GetOutput());
     if (IsParameterEnabled("foutpos") && HasValue("foutpos"))
       {
-      SetParameterOutputImage("foutpos", m_Filter->GetSpatialOutput());
+      SetParameterOutputImage("foutpos", filter->GetSpatialOutput());
       }
     if(!GetParameterInt("modesearch"))
       {
       otbAppLogINFO(<<"Mode Search is disabled." << std::endl);
       }
+    RegisterPipeline();
    }
 
-  MSFilterType::Pointer m_Filter;
-
 };
 
 
diff --git a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h b/Modules/Core/Common/include/otbExtendedFilenameHelper.h
similarity index 94%
rename from Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h
rename to Modules/Core/Common/include/otbExtendedFilenameHelper.h
index 72123839c76f922c32d63296abd6c3559f92f705..549ad2451d85745f196db750ceea2ba3a9156c12 100644
--- a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h
+++ b/Modules/Core/Common/include/otbExtendedFilenameHelper.h
@@ -23,6 +23,7 @@
 
 #include "itkObject.h"
 #include "itkObjectFactory.h"
+#include "OTBCommonExport.h"
 
 namespace otb
 {
@@ -33,9 +34,10 @@ namespace otb
  *  \sa ImageFileReader
  *
  * \ingroup OTBExtendedFilename
+ * \ingroup OTBCommon
  */
 
-class ITK_EXPORT ExtendedFilenameHelper : public itk::Object
+class OTBCommon_EXPORT ExtendedFilenameHelper : public itk::Object
 {
 public:
 /** Standard class typedefs. */
@@ -55,7 +57,7 @@ public:
   itkGetStringMacro(ExtendedFileName);
   itkGetStringMacro(SimpleFileName);
 
-  struct GenericBandRange : std::pair<int,int>
+  struct OTBCommon_EXPORT GenericBandRange : std::pair<int,int>
   {
     GenericBandRange() {}
 
diff --git a/Modules/Core/Common/include/otbUtils.h b/Modules/Core/Common/include/otbUtils.h
index da2ecc286ed4abf8e175a700b69f9e14a8483fb4..ec8ed5475928066f74af913491931433b1a4d6da 100644
--- a/Modules/Core/Common/include/otbUtils.h
+++ b/Modules/Core/Common/include/otbUtils.h
@@ -51,6 +51,9 @@ namespace Utils
   /** Function that prints nothing (useful to disable libsvm logs)*/
   void OTBCommon_EXPORT PrintNothing(const char *s);
 
+  extern OTBCommon_EXPORT bool const TrueConstant;
+
+  extern OTBCommon_EXPORT bool const FalseConstant;
 }
 
 } // namespace otb
diff --git a/Modules/Core/Common/otb-module.cmake b/Modules/Core/Common/otb-module.cmake
index 97ba992dd7ca4a88b6ce1ac6475678f27eb1368b..b3276d69422b566872290eba6a5d817cb2b45be1 100644
--- a/Modules/Core/Common/otb-module.cmake
+++ b/Modules/Core/Common/otb-module.cmake
@@ -27,6 +27,8 @@ ENABLE_SHARED
     OTBITK
     #Add dependency to OTBGDAL as GDAL module need to set OTB_USE_GDAL_20 before configuring otbConfigure.h
     OTBGDAL
+    #Add dependency for extended filename helper class
+    OTBBoostAdapters
 
   TEST_DEPENDS
     OTBImageBase
diff --git a/Modules/Core/Common/src/CMakeLists.txt b/Modules/Core/Common/src/CMakeLists.txt
index ce5d20761e59a5e57cf7f3b909317dc1c072f7aa..1aee98f792eca87f73212b1892b60e4571698bf2 100644
--- a/Modules/Core/Common/src/CMakeLists.txt
+++ b/Modules/Core/Common/src/CMakeLists.txt
@@ -29,6 +29,7 @@ set(OTBCommon_SRC
   otbWriterWatcherBase.cxx
   otbStopwatch.cxx
   otbStringToHTML.cxx
+  otbExtendedFilenameHelper.cxx
   otbLogger.cxx
   )
 
diff --git a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx b/Modules/Core/Common/src/otbExtendedFilenameHelper.cxx
similarity index 100%
rename from Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx
rename to Modules/Core/Common/src/otbExtendedFilenameHelper.cxx
diff --git a/Modules/Core/Common/src/otbUtils.cxx b/Modules/Core/Common/src/otbUtils.cxx
index f837789ba6ee406bb6739f527dc2ef103f780f9a..7bdf9edb7121801353360e316d8c15ac4836fe6b 100644
--- a/Modules/Core/Common/src/otbUtils.cxx
+++ b/Modules/Core/Common/src/otbUtils.cxx
@@ -41,6 +41,10 @@ void PrintNothing(const char * /* s */)
 {
 }
 
+bool const TrueConstant = true;
+
+bool const FalseConstant = false;
+
 }
 
 }
diff --git a/Modules/Core/ObjectList/include/otbDataObjectListInterface.h b/Modules/Core/ObjectList/include/otbDataObjectListInterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1a1ac722fd9398613bac3953252dcc1b8c2af0b
--- /dev/null
+++ b/Modules/Core/ObjectList/include/otbDataObjectListInterface.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbDataObjectListInterface_h
+#define otbDataObjectListInterface_h
+
+#include "itkDataObject.h"
+#include <boost/noncopyable.hpp>
+
+namespace otb
+{
+
+class DataObjectListInterface : private boost::noncopyable
+{
+/** \class DataObjectListInterface
+ *  \brief This non template class is an interface that wrapp ObjectList
+ *  
+ *  New method that do not need the template parameter of ObjectList 
+ *  should be declare here.
+ *
+ * \ingroup OTBObjectList
+ */
+public:
+  /**
+  Get the nth element of the list as a DataObject *.
+  */
+  virtual itk::DataObject * GetNthDataObject(unsigned int index) const = 0;
+
+  virtual std::size_t Size(void) const = 0;
+
+protected:
+  DataObjectListInterface() = default ;
+  virtual ~DataObjectListInterface() = default ;
+};
+
+} // end of otb namespace
+
+#endif
diff --git a/Modules/Core/ObjectList/include/otbObjectList.h b/Modules/Core/ObjectList/include/otbObjectList.h
index 6df4f167c879a5ffd349ef2ec587e0e6ad26fb3a..80464782d4af1ccf21c9f93b13f406d4017831e6 100644
--- a/Modules/Core/ObjectList/include/otbObjectList.h
+++ b/Modules/Core/ObjectList/include/otbObjectList.h
@@ -23,6 +23,7 @@
 
 #include <vector>
 #include "itkDataObject.h"
+#include "otbDataObjectListInterface.h"
 #include "itkObjectFactory.h"
 
 namespace otb
@@ -36,7 +37,7 @@ namespace otb
  * \ingroup OTBObjectList
  */
 template <class TObject>
-class ITK_EXPORT ObjectList : public itk::DataObject
+class ITK_EXPORT ObjectList : public itk::DataObject , public DataObjectListInterface
 {
 public:
   /** Standard typedefs */
@@ -71,7 +72,7 @@ public:
    * Get the number of elements in the vector.
    * \return The number of elements in the vector.
    */
-  InternalContainerSizeType Size(void) const;
+  InternalContainerSizeType Size(void) const override;
   /**
    * Resize the maximal list capacity.
    * \param size The new maximal size of the list.
@@ -99,6 +100,11 @@ public:
    * \return The pointer to the nth element of the list.
    */
   ObjectPointerType GetNthElement(unsigned int index) const;
+  /**
+   * Get the nth element of the list as a DataObject *.
+   * \param index The index of the object to get.
+   */
+  Superclass *  GetNthDataObject(unsigned int index) const override;
   /**
    * Return the first element of the list.
    * \return The first element of the list.
@@ -462,7 +468,7 @@ public:
     friend class ConstIterator;
     friend class ReverseIterator;
     /** typedef of the internal iterator */
-    typedef typename InternalContainerType::reverse_iterator InternalReverseConstIteratorType;
+    typedef typename InternalContainerType::const_reverse_iterator InternalReverseConstIteratorType;
     /** Constructor */
     ReverseConstIterator() {};
     /** Constructor with iternal iterator parameter */
diff --git a/Modules/Core/ObjectList/include/otbObjectList.txx b/Modules/Core/ObjectList/include/otbObjectList.txx
index 26044b1432f2023d2c34ecbdb57afa8374bab3e3..84f600c6fd2480db7c8dfedca12e923fa602f7da 100644
--- a/Modules/Core/ObjectList/include/otbObjectList.txx
+++ b/Modules/Core/ObjectList/include/otbObjectList.txx
@@ -162,6 +162,16 @@ ObjectList<TObject>
     }
   return m_InternalContainer[index];
 }
+
+template <class TObject>
+typename ObjectList<TObject>::Superclass *
+ObjectList<TObject>
+::GetNthDataObject(unsigned int index) const
+{
+  
+  return dynamic_cast<itk::DataObject *> ( GetNthElement(index).GetPointer() );
+}
+
 /**
    * Return the first element of the list.
    * \return The first element of the list.
@@ -236,7 +246,11 @@ typename ObjectList<TObject>::ReverseIterator
 ObjectList<TObject>
 ::Insert(ReverseIterator position, ObjectPointerType element)
 {
-  ReverseIterator iter(m_InternalContainer.insert(position.GetIter(), element));
+  ReverseIterator iter(
+    InternalContainerType::reverse_iterator(
+      m_InternalContainer.insert(position.GetIter().base(), element)
+      )
+    );
   this->Modified();
   return iter;
 }
diff --git a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.h b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.h
index 998ba4c287f98991973e8c15d96448124ad21058..29fafc6bf528190377325ff63be8fb2e5b67664b 100644
--- a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.h
+++ b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.h
@@ -24,6 +24,7 @@
 #include "itkMacro.h"
 #include "itkImageToImageFilter.h"
 #include "otbStreamingManager.h"
+#include "itkFastMutexLock.h"
 
 namespace otb
 {
@@ -142,6 +143,11 @@ public:
    *  This filter does not produce an output */
   void Update() override;
 
+  /** This override doesn't return a const ref on the actual boolean */
+  const bool & GetAbortGenerateData() const override;
+
+  void SetAbortGenerateData(const bool val) override;
+
 protected:
   StreamingImageVirtualWriter();
 
@@ -186,6 +192,9 @@ private:
 
   bool          m_IsObserving;
   unsigned long m_ObserverID;
+
+  /** Lock to ensure thread-safety (added for the AbortGenerateData flag) */
+  itk::SimpleFastMutexLock m_Lock;
 };
 
 } // end namespace otb
diff --git a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
index 008b6c0eaafe7d39dfc3febf6889be7471d1cf0c..ec0ae5ae6d760b11ca6238deb582174752bb7f21 100644
--- a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
+++ b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
@@ -32,6 +32,7 @@
 #include "otbTileDimensionTiledStreamingManager.h"
 #include "otbRAMDrivenTiledStreamingManager.h"
 #include "otbRAMDrivenAdaptativeStreamingManager.h"
+#include "otbUtils.h"
 
 namespace otb
 {
@@ -258,6 +259,13 @@ StreamingImageVirtualWriter<TInputImage>
     {
     this->UpdateProgress(1.0);
     }
+  else
+    {
+    itk::ProcessAborted e(__FILE__, __LINE__);
+    e.SetLocation(ITK_LOCATION);
+    e.SetDescription("Image streaming has been aborted");
+    throw e;
+    }
 
   // Notify end event observers
   this->InvokeEvent(itk::EndEvent());
@@ -285,6 +293,27 @@ StreamingImageVirtualWriter<TInputImage>
   this->ReleaseInputs();
 }
 
+template <class TInputImage>
+const bool &
+StreamingImageVirtualWriter<TInputImage>
+::GetAbortGenerateData() const
+{
+  m_Lock.Lock();
+  bool ret = Superclass::GetAbortGenerateData();
+  m_Lock.Unlock();
+  if (ret) return otb::Utils::TrueConstant;
+  return otb::Utils::FalseConstant;
+}
+
+template <class TInputImage>
+void
+StreamingImageVirtualWriter<TInputImage>
+::SetAbortGenerateData(bool val)
+{
+  m_Lock.Lock();
+  Superclass::SetAbortGenerateData(val);
+  m_Lock.Unlock();
+}
 
 } // end namespace otb
 
diff --git a/Modules/Core/Streaming/include/otbStreamingManager.h b/Modules/Core/Streaming/include/otbStreamingManager.h
index cd57e83f9e7ddeda81282d35af4d048a4d837faa..0bffd7e95779c755c41e2a94a276a72360845e1d 100644
--- a/Modules/Core/Streaming/include/otbStreamingManager.h
+++ b/Modules/Core/Streaming/include/otbStreamingManager.h
@@ -67,6 +67,7 @@ public:
   typedef typename ImageType::InternalPixelType PixelType;
 
   typedef otb::PipelineMemoryPrintCalculator::MemoryPrintType MemoryPrintType;
+  typedef itk::ImageRegionSplitterBase          AbstractSplitterType;
 
   /** Type macro */
   itkTypeMacro(StreamingManager, itk::LightObject);
@@ -74,6 +75,8 @@ public:
   /** Dimension of input image. */
   itkStaticConstMacro(ImageDimension, unsigned int, ImageType::ImageDimension);
 
+  const AbstractSplitterType * GetSplitter() const;
+
   /** Actually computes the stream divisions, according to the specified streaming mode,
    * eventually using the input parameter to estimate memory consumption */
   virtual void PrepareStreaming(itk::DataObject * input, const RegionType &region) = 0;
@@ -106,7 +109,6 @@ protected:
   RegionType m_Region;
 
   /** The splitter used to compute the different strips */
-  typedef itk::ImageRegionSplitterBase           AbstractSplitterType;
   typedef typename AbstractSplitterType::Pointer AbstractSplitterPointerType;
   AbstractSplitterPointerType m_Splitter;
 
diff --git a/Modules/Core/Streaming/include/otbStreamingManager.txx b/Modules/Core/Streaming/include/otbStreamingManager.txx
index 1d76ff1fe498007c5b9bb60fcc7fa80e040733b2..24e487a4e55998ee7d28b1be1a58cbda21ee8768 100644
--- a/Modules/Core/Streaming/include/otbStreamingManager.txx
+++ b/Modules/Core/Streaming/include/otbStreamingManager.txx
@@ -40,6 +40,13 @@ StreamingManager<TImage>::~StreamingManager()
 {
 }
 
+template <class TImage>
+const typename StreamingManager<TImage>::AbstractSplitterType *
+StreamingManager<TImage>::GetSplitter() const
+{
+  return m_Splitter;
+}
+
 template <class TImage>
 typename StreamingManager<TImage>::MemoryPrintType
 StreamingManager<TImage>::GetActualAvailableRAMInBytes(MemoryPrintType availableRAMInMB)
diff --git a/Modules/Feature/Edge/include/otbLineSegmentDetector.txx b/Modules/Feature/Edge/include/otbLineSegmentDetector.txx
index c06344e1831c17e0f9c07448a40f7ceb1b154155..8ff969c22c23d5558295af53589c62a5d8168e38 100644
--- a/Modules/Feature/Edge/include/otbLineSegmentDetector.txx
+++ b/Modules/Feature/Edge/include/otbLineSegmentDetector.txx
@@ -792,8 +792,14 @@ LineSegmentDetector<TInputImage, TPrecision>
     l =  (static_cast<double>((*it)[0]) - x) * dx + (static_cast<double>((*it)[1]) - y) * dy;
     w = -(static_cast<double>((*it)[0]) - x) * dy + (static_cast<double>((*it)[1]) - y) * dx;
 
-    if (l < l_min) l_min = l; if (l > l_max) l_max = l;
-    if (w < w_min) w_min = w; if (w > w_max) w_max = w;
+    if (l < l_min)
+      l_min = l;
+    if (l > l_max)
+      l_max = l;
+    if (w < w_min)
+      w_min = w;
+    if (w > w_max)
+      w_max = w;
 
     sum_l[static_cast < int > (vcl_floor(l) + 0.5) + Diagonal] +=  static_cast<MagnitudePixelType>(weight);
     sum_w[static_cast < int > (vcl_floor(w) + 0.5) + Diagonal] +=  static_cast<MagnitudePixelType>(weight);
diff --git a/Modules/Feature/Edge/include/otbLocalHoughFilter.txx b/Modules/Feature/Edge/include/otbLocalHoughFilter.txx
index a3b0d6e6be609527145600c5024aa0f8ffec19a3..b6a21b20f2e078f308d1af840690944d5096bc1c 100644
--- a/Modules/Feature/Edge/include/otbLocalHoughFilter.txx
+++ b/Modules/Feature/Edge/include/otbLocalHoughFilter.txx
@@ -229,7 +229,11 @@ LocalHoughFilter<TInputImage>
       // Get the list of LineSpatialObject lines
       // ---------------------------------------
 
+      #if !defined(ITK_LEGACY_REMOVE)
       lines = houghFilter->GetLines(m_NumberOfLines);
+      #else
+      lines = houghFilter->GetLines();
+      #endif
 
       LineIterator itLines = lines.begin();
 
diff --git a/Modules/Filtering/Path/include/otbClosePathFunctor.h b/Modules/Filtering/Path/include/otbClosePathFunctor.h
index 90924a2b427f09eedc3289678f17115078c5cd1f..d880196c9f4b9d4992fd538fc8c988f74369fcdc 100644
--- a/Modules/Filtering/Path/include/otbClosePathFunctor.h
+++ b/Modules/Filtering/Path/include/otbClosePathFunctor.h
@@ -59,6 +59,9 @@ public:
 
     if(input->GetVertexList()->Size()>0)
       {
+      //Initialization of lastVertex to GetVertexList
+      lastVertex = input->GetVertexList()->Begin().Value();
+      
       for (VertexListConstIteratorType vertexIt = input->GetVertexList()->Begin();
           vertexIt != input->GetVertexList()->End();
           ++vertexIt)
diff --git a/Modules/IO/ExtendedFilename/otb-module.cmake b/Modules/IO/ExtendedFilename/otb-module.cmake
index cf194a8edde1a755df8dd5343ffaeefbb56b65c9..1e46b70a5bfefcc72cda05d38d35e428fba5d6f5 100644
--- a/Modules/IO/ExtendedFilename/otb-module.cmake
+++ b/Modules/IO/ExtendedFilename/otb-module.cmake
@@ -26,8 +26,8 @@ product by skipping either geographic or sensor-model information.")
 
 otb_module(OTBExtendedFilename
   DEPENDS
+    OTBCommon
     OTBIOGDAL
-    OTBBoostAdapters
     OTBITK
 
   TEST_DEPENDS
diff --git a/Modules/IO/ExtendedFilename/src/CMakeLists.txt b/Modules/IO/ExtendedFilename/src/CMakeLists.txt
index 033f0db2d93dfe762ed49684cdbf8cba0eed68b8..35ec302ad43392100078862ecc954abce105eeaa 100644
--- a/Modules/IO/ExtendedFilename/src/CMakeLists.txt
+++ b/Modules/IO/ExtendedFilename/src/CMakeLists.txt
@@ -20,15 +20,13 @@
 
 set(OTBExtendedFilename_SRC
   otbExtendedFilenameToReaderOptions.cxx
-  otbExtendedFilenameHelper.cxx
   otbExtendedFilenameToWriterOptions.cxx
   )
 
 add_library(OTBExtendedFilename ${OTBExtendedFilename_SRC})
 target_link_libraries(OTBExtendedFilename 
+  ${OTBCommon_LIBRARIES}
   ${OTBIOGDAL_LIBRARIES}
-  ${OTBBoost_LIBRARIES}
-
   )
 
 otb_module_target(OTBExtendedFilename)
diff --git a/Modules/IO/ImageIO/include/otbImageFileWriter.h b/Modules/IO/ImageIO/include/otbImageFileWriter.h
index 2851c8b03d3372f6353bba967aeaf0f99a1c9ba5..169e946c7579a241c7bed42424c561101d608912 100644
--- a/Modules/IO/ImageIO/include/otbImageFileWriter.h
+++ b/Modules/IO/ImageIO/include/otbImageFileWriter.h
@@ -25,6 +25,7 @@
 #include "itkProcessObject.h"
 #include "otbStreamingManager.h"
 #include "otbExtendedFilenameToWriterOptions.h"
+#include "itkFastMutexLock.h"
 
 namespace otb
 {
@@ -199,6 +200,11 @@ public:
   itkGetObjectMacro(ImageIO, otb::ImageIOBase);
   itkGetConstObjectMacro(ImageIO, otb::ImageIOBase);
 
+  /** This override doesn't return a const ref on the actual boolean */
+  const bool & GetAbortGenerateData() const override;
+
+  void SetAbortGenerateData(const bool val) override;
+
 protected:
   ImageFileWriter();
   ~ImageFileWriter() override;
@@ -207,6 +213,9 @@ protected:
   /** Does the real work. */
   void GenerateData(void) override;
 
+  /** Prepare the streaming and write the output information on disk */
+  void GenerateOutputInformation(void) override;
+
 private:
   ImageFileWriter(const ImageFileWriter &); //purposely not implemented
   void operator =(const ImageFileWriter&); //purposely not implemented
@@ -270,6 +279,9 @@ private:
    *  This variable can be the number of components in m_ImageIO or the
    *  number of components in the m_BandList (if used) */
   unsigned int m_IOComponents;
+
+  /** Lock to ensure thread-safety (added for the AbortGenerateData flag) */
+  itk::SimpleFastMutexLock m_Lock;
 };
 
 } // end namespace otb
diff --git a/Modules/IO/ImageIO/include/otbImageFileWriter.txx b/Modules/IO/ImageIO/include/otbImageFileWriter.txx
index 677ea22b4bab59d04121735bd58990ca0b516ec4..6cfff64f8ae1df38f26344110537bb1c47d0336c 100644
--- a/Modules/IO/ImageIO/include/otbImageFileWriter.txx
+++ b/Modules/IO/ImageIO/include/otbImageFileWriter.txx
@@ -48,6 +48,7 @@
 #include "otb_boost_tokenizer_header.h"
 
 #include "otbStringUtils.h"
+#include "otbUtils.h"
 
 namespace otb
 {
@@ -262,13 +263,11 @@ ImageFileWriter<TInputImage>
   return static_cast<const InputImageType*>(this->ProcessObject::GetInput(0));
 }
 
-/**
- * Update method : update output information of input and write to file
- */
+/** Prepare everything and call m_ImageIO.WriteInformation() */
 template<class TInputImage>
 void
 ImageFileWriter<TInputImage>
-::Update()
+::GenerateOutputInformation(void)
 {
   // Update output information on input image
   InputImagePointer inputPtr =
@@ -397,14 +396,6 @@ ImageFileWriter<TInputImage>
       }
     }
 
-  this->SetAbortGenerateData(0);
-  this->SetProgress(0.0);
-
-  /**
-   * Tell all Observers that the filter is starting
-   */
-  this->InvokeEvent(itk::StartEvent());
-
   /** Prepare ImageIO  : create ImageFactory */
 
   if (m_FileName == "")
@@ -476,7 +467,6 @@ ImageFileWriter<TInputImage>
   /**
    * Grab the input
    */
-  inputPtr->UpdateOutputInformation();
   InputImageRegionType inputRegion = inputPtr->GetLargestPossibleRegion();
 
   /** Parse region size modes */
@@ -540,12 +530,6 @@ ImageFileWriter<TInputImage>
   const auto firstSplitSize = m_StreamingManager->GetSplit(0).GetSize();
   otbLogMacro(Info,<<"File "<<m_FileName<<" will be written in "<<m_NumberOfDivisions<<" blocks of "<<firstSplitSize[0]<<"x"<<firstSplitSize[1]<<" pixels");
 
-  /**
-   * Loop over the number of pieces, execute the upstream pipeline on each
-   * piece, and copy the results into the output image.
-   */
-  InputImageRegionType streamRegion;
-
   //
   // Setup the ImageIO with information from inputPtr
   //
@@ -585,12 +569,33 @@ ImageFileWriter<TInputImage>
   m_ImageIO->SetFileName(m_FileName.c_str());
 
   m_ImageIO->WriteImageInformation();
+}
 
+/**
+ * Update method : update output information of input and write to file
+ */
+template<class TInputImage>
+void
+ImageFileWriter<TInputImage>
+::Update()
+{
+  this->UpdateOutputInformation();
+
+  this->SetAbortGenerateData(0);
+  this->SetProgress(0.0);
+
+  /**
+   * Tell all Observers that the filter is starting
+   */
+  this->InvokeEvent(itk::StartEvent());
+  
   this->UpdateProgress(0);
   m_CurrentDivision = 0;
   m_DivisionProgress = 0;
 
   // Get the source process object
+  InputImagePointer inputPtr =
+    const_cast<InputImageType *>(this->GetInput());
   itk::ProcessObject* source = inputPtr->GetSource();
   m_IsObserving = false;
   m_ObserverID = 0;
@@ -612,6 +617,12 @@ ImageFileWriter<TInputImage>
     otbLogMacro(Warning,<< "Could not get the source process object. Progress report might be buggy");
     }
 
+  /**
+   * Loop over the number of pieces, execute the upstream pipeline on each
+   * piece, and copy the results into the output image.
+   */
+  InputImageRegionType streamRegion;
+
   for (m_CurrentDivision = 0;
        m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
        m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
@@ -645,6 +656,13 @@ ImageFileWriter<TInputImage>
     {
     this->UpdateProgress(1.0);
     }
+  else
+    {
+    itk::ProcessAborted e(__FILE__, __LINE__);
+    e.SetLocation(ITK_LOCATION);
+    e.SetDescription("Image writing has been aborted");
+    throw e;
+    }
 
   // Notify end event observers
   this->InvokeEvent(itk::EndEvent());
@@ -833,6 +851,29 @@ ImageFileWriter<TInputImage>
 return this->m_FilenameHelper->GetSimpleFileName();
 }
 
+template <class TInputImage>
+const bool &
+ImageFileWriter<TInputImage>
+::GetAbortGenerateData() const
+{
+  m_Lock.Lock();
+  // protected read here
+  bool ret = Superclass::GetAbortGenerateData();
+  m_Lock.Unlock();
+  if (ret) return otb::Utils::TrueConstant;
+  return otb::Utils::FalseConstant;
+}
+
+template <class TInputImage>
+void
+ImageFileWriter<TInputImage>
+::SetAbortGenerateData(bool val)
+{
+  m_Lock.Lock();
+  Superclass::SetAbortGenerateData(val);
+  m_Lock.Unlock();
+}
+
 } // end namespace otb
 
 #endif
diff --git a/Modules/IO/ImageIO/include/otbImageIOFactory.h b/Modules/IO/ImageIO/include/otbImageIOFactory.h
index 287c149792eada50c4605aaa1213d6e621c4807a..591999ac6ef4aa91d5017f171fad14df516bb1d7 100644
--- a/Modules/IO/ImageIO/include/otbImageIOFactory.h
+++ b/Modules/IO/ImageIO/include/otbImageIOFactory.h
@@ -23,6 +23,7 @@
 
 #include "itkObject.h"
 #include "otbImageIOBase.h"
+#include "OTBImageIOExport.h"
 
 namespace otb
 {
@@ -31,7 +32,7 @@ namespace otb
  *
  * \ingroup OTBImageIO
  */
-class ITK_EXPORT ImageIOFactory : public itk::Object
+class OTBImageIO_EXPORT ImageIOFactory : public itk::Object
 {
 public:
   /** Standard class typedefs. */
diff --git a/Modules/IO/ImageIO/include/otbMultiImageFileWriter.h b/Modules/IO/ImageIO/include/otbMultiImageFileWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d2cf24f80ddbcf858d00becb3fbbd3489e5e9f9
--- /dev/null
+++ b/Modules/IO/ImageIO/include/otbMultiImageFileWriter.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) CS SI
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbMultiImageFileWriter_h
+#define otbMultiImageFileWriter_h
+
+#include "otbImageFileWriter.h"
+#include "otbImage.h"
+#include "itkImageBase.h"
+#include "itkProcessObject.h"
+#include "itkImageIOBase.h"
+#include "OTBImageIOExport.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace otb
+{
+
+/** \class MultiImageFileWriter
+ *  \brief Streams a pipeline with multiple outputs.
+ *  It writes each output to a file. Inputs
+ *  are connected to the writer using the AddInputImage method.
+ *  The type of streaming can be chosen. Each output may have a different size.
+ *  When the user gives a number of lines per strip or a tile size, the value
+ *  is interpreted on the first input to deduce the number of streams. This
+ *  number of streams is then used to split the other inputs.
+ */
+class OTBImageIO_EXPORT MultiImageFileWriter: public itk::ProcessObject
+{
+public:
+  /** Standard class typedefs. */
+  typedef MultiImageFileWriter Self;
+  typedef itk::ProcessObject Superclass;
+  typedef itk::SmartPointer<Self> Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+
+  itkNewMacro(Self);
+
+  itkTypeMacro(MultiImageFileWriter, itk::ProcessObject);
+
+  /** Public typedefs */
+  typedef itk::ImageBase<2> ImageBaseType;
+  typedef ImageBaseType::RegionType RegionType;
+  typedef ImageBaseType::IndexType  IndexType;
+  typedef ImageBaseType::IndexValueType  IndexValueType;
+  typedef ImageBaseType::SizeType   SizeType;
+  typedef ImageBaseType::SizeValueType   SizeValueType;
+
+  /**  Set the streaming mode to 'stripped' and configure the number of strips
+   *   which will be used to stream the image */
+  void SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions);
+
+  /**  Set the streaming mode to 'tiled' and configure the number of tiles
+   *   which will be used to stream the image */
+  void SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions);
+
+  /**  Set the streaming mode to 'stripped' and configure the number of strips
+   *   which will be used to stream the image with respect to a number of line
+   *   per strip */
+  void SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip);
+
+  /**  Set the streaming mode to 'stripped' and configure the number of MB
+   *   available. The actual number of divisions is computed automatically
+   *   by estimating the memory consumption of the pipeline.
+   *   Setting the availableRAM parameter to 0 means that the available RAM
+   *   is set from the CMake configuration option.
+   *   The bias parameter is a multiplier applied on the estimated memory size
+   *   of the pipeline and can be used to fine tune the potential gap between
+   *   estimated memory and actual memory used, which can happen because of
+   *   composite filters for example */
+  void SetAutomaticStrippedStreaming(unsigned int availableRAM = 0, double bias = 1.0);
+
+  /**  Set the streaming mode to 'tiled' and configure the dimension of the tiles
+   *   in pixels for each dimension (square tiles will be generated) */
+  void SetTileDimensionTiledStreaming(unsigned int tileDimension);
+
+  /**  Set the streaming mode to 'tiled' and configure the number of MB
+   *   available. The actual number of divisions is computed automatically
+   *   by estimating the memory consumption of the pipeline.
+   *   Tiles will be square.
+   *   Setting the availableRAM parameter to 0 means that the available RAM
+   *   is set from the CMake configuration option
+   *   The bias parameter is a multiplier applied on the estimated memory size
+   *   of the pipeline and can be used to fine tune the potential gap between
+   *   estimated memory and actual memory used, which can happen because of
+   *   composite filters for example */
+  void SetAutomaticTiledStreaming(unsigned int availableRAM = 0, double bias = 1.0);
+
+  /**  Set the streaming mode to 'adaptative' and configure the number of MB
+   *   available. The actual number of divisions is computed automatically
+   *   by estimating the memory consumption of the pipeline.
+   *   Tiles will try to match the input file tile scheme.
+   *   Setting the availableRAM parameter to 0 means that the available RAM
+   *   is set from the CMake configuration option */
+  void SetAutomaticAdaptativeStreaming(unsigned int availableRAM = 0, double bias = 1.0);
+
+  virtual void UpdateOutputData(itk::DataObject * itkNotUsed(output));
+
+  /** Connect a new input to the multi-writer. Only the input pointer is
+   *  required. If the filename list is empty,
+   *  streaming will occur without writing. It the filename list contains more
+   *  than one element, then the output will be divided into this number of
+   *  granule files. The resolution factor specifies the ratio between the height of this image and the
+   *  height of a reference image. The number of lines per strip class parameter will be modified according to this factor, so
+   *  that images with different resolutions can be streamed together. For example, use 1.0 for a 10m pixels image, 0.5 for a 20m
+   *  pixels image, and specify the number of lines per strip according to the 10m pixels image.
+   *  You may specify top and bottom margins that will be removed from the input image, according to its largest possible region.
+   */
+  template <class TImage>
+  void AddInputImage(const TImage* inputPtr, const std::string & fileName)
+  {
+    Sink<TImage> * sink = new Sink<TImage>(inputPtr, fileName);
+    m_SinkList.push_back(SinkBase::Pointer(sink));
+    unsigned int size = m_SinkList.size();
+    this->SetNthInput(size - 1, const_cast<itk::DataObject*>(dynamic_cast<const itk::DataObject*>(inputPtr)));
+  }
+
+  /** Add a new ImageFileWriter to the multi-writer. This is an alternative method
+   *  when you already have an instanciated writer.
+   */
+  template <class TWriter>
+  void AddInputWriter(const TWriter* writer)
+  {
+    Sink<typename TWriter::InputImageType > * sink =
+      new Sink<typename TWriter::InputImageType >(writer);
+    m_SinkList.push_back(SinkBase::Pointer(sink));
+    unsigned int size = m_SinkList.size();
+    this->SetNthInput(size - 1, const_cast<itk::DataObject*>(dynamic_cast<const itk::DataObject*>(writer->GetInput())));
+  }
+
+  virtual void UpdateOutputInformation();
+
+  virtual void Update()
+  {
+    this->UpdateOutputInformation();
+    this->UpdateOutputData(NULL);
+  }
+
+protected:
+  /** SetInput is changed to protected. Use AddInputImage to connect the
+   *  pipeline to the writer
+   */
+  virtual void SetInput(const itk::ProcessObject::DataObjectIdentifierType & key, itk::DataObject* image)
+    { this->Superclass::SetInput(key, image); }
+
+  /** SetNthInput is changed to protected. Use AddInputImage to connect the
+   *  pipeline to the writer
+   */
+  virtual void SetNthInput(itk::ProcessObject::DataObjectPointerArraySizeType i, itk::DataObject* image)
+    { this->Superclass::SetNthInput(i, image); }
+
+  MultiImageFileWriter();
+  virtual ~MultiImageFileWriter() {}
+
+  /** GenerateData calls the Write method for each connected input */
+  virtual void GenerateData(void);
+
+  /** GenerateInputRequestedRegion can predict approximate input regions
+   *  based on the requested region of the fake output. Only usefull for
+   *  pipeline memory print estimation
+   */
+  virtual void GenerateInputRequestedRegion();
+
+  /** Computes the number of divisions */
+  virtual void InitializeStreaming();
+
+  /** Goes up the pipeline starting at imagePtr, resetting all requested regions
+   *  to a null region. This may be usefull when mixing inputs of different
+   *  resolutions. */
+  void ResetAllRequestedRegions(ImageBaseType* imagePtr);
+
+  /** Returns the current stream region of the given input */
+  virtual RegionType GetStreamRegion(int inputIndex);
+
+  void operator =(const MultiImageFileWriter&); //purposely not implemented
+
+  void ObserveSourceFilterProgress(itk::Object* object, const itk::EventObject & event)
+  {
+    if (typeid(event) != typeid(itk::ProgressEvent))
+      {
+      return;
+      }
+
+    itk::ProcessObject* processObject = dynamic_cast<itk::ProcessObject*>(object);
+    if (processObject)
+      {
+      m_DivisionProgress = processObject->GetProgress();
+      }
+
+    this->UpdateFilterProgress();
+  }
+
+  void UpdateFilterProgress()
+  {
+    this->UpdateProgress((m_DivisionProgress + m_CurrentDivision) / m_NumberOfDivisions);
+  }
+
+private:
+  typedef otb::Image<unsigned char, 2> FakeOutputType;
+  typedef StreamingManager<FakeOutputType>        StreamingManagerType;
+  /** Streaming manager used for the N inputs */
+  StreamingManagerType::Pointer m_StreamingManager;
+
+  //Division parameters
+  unsigned int m_NumberOfDivisions;
+  unsigned int m_CurrentDivision;
+  float m_DivisionProgress;
+
+  bool m_IsObserving;
+  unsigned long m_ObserverID;
+
+  /** Internal base wrapper class to handle each ImageFileWriter */
+  class SinkBase
+  {
+  public:
+    SinkBase() {}
+    SinkBase(ImageBaseType::ConstPointer inputImage) :
+      m_InputImage(inputImage)
+    {}
+    virtual ~SinkBase() {}
+    virtual ImageBaseType::ConstPointer GetInput() const { return m_InputImage; }
+    virtual ImageBaseType::Pointer GetInput() { return const_cast<ImageBaseType*>(m_InputImage.GetPointer()); }
+    virtual void WriteImageInformation() = 0;
+    virtual void Write(const RegionType & streamRegion) = 0;
+    virtual bool CanStreamWrite() = 0;
+    typedef boost::shared_ptr<SinkBase> Pointer;
+  protected:
+    /** The image on which streaming is performed */
+    ImageBaseType::ConstPointer m_InputImage;
+  };
+
+  /** \class Sink
+   *  Wrapper class for each ImageFileWriter
+   */
+  template <class TImage>
+  class Sink : public SinkBase
+  {
+  public:
+    Sink() {}
+    Sink(typename TImage::ConstPointer inputImage,
+         const std::string & filename);
+    Sink(typename otb::ImageFileWriter<TImage>::ConstPointer writer);
+
+    virtual ~Sink() {}
+
+    virtual void WriteImageInformation();
+    virtual void Write(const RegionType & streamRegion);
+    virtual bool CanStreamWrite();
+    typedef boost::shared_ptr<Sink> Pointer;
+  private:
+    /** Actual writer for this image */
+    typename otb::ImageFileWriter<TImage>::Pointer m_Writer;
+
+    /** An ImageIO used to actually write data to a file */
+    otb::ImageIOBase::Pointer m_ImageIO;
+  };
+
+  /** The list of inputs and their associated parameters, built using AddInput */
+  typedef std::vector<boost::shared_ptr<SinkBase> > SinkListType;
+  SinkListType m_SinkList;
+
+  std::vector<RegionType> m_StreamRegionList;
+};
+
+} // end of namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbMultiImageFileWriter.txx"
+#endif
+
+#endif // otbMultiImageFileWriter_h
diff --git a/Modules/IO/ImageIO/include/otbMultiImageFileWriter.txx b/Modules/IO/ImageIO/include/otbMultiImageFileWriter.txx
new file mode 100644
index 0000000000000000000000000000000000000000..5e6d6304dc52aa3dc95a497b45264ff2cc15d277
--- /dev/null
+++ b/Modules/IO/ImageIO/include/otbMultiImageFileWriter.txx
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) CS SI
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbMultiImageFileWriter_txx
+#define otbMultiImageFileWriter_txx
+
+#include "otbMultiImageFileWriter.h"
+#include "otbImageIOFactory.h"
+#include "otbMacro.h"
+
+namespace otb
+{
+
+template <class TImage>
+MultiImageFileWriter::Sink<TImage>
+::Sink(typename TImage::ConstPointer inputImage,
+       const std::string & fileName):
+  SinkBase(dynamic_cast<const ImageBaseType*>(inputImage.GetPointer())),
+  m_Writer(otb::ImageFileWriter<TImage>::New()),
+  m_ImageIO(NULL)
+{
+  m_Writer->SetFileName(fileName);
+  m_Writer->SetInput(inputImage);
+}
+
+template <class TImage>
+MultiImageFileWriter::Sink<TImage>
+::Sink(typename otb::ImageFileWriter<TImage>::ConstPointer writer):
+  SinkBase(dynamic_cast<const ImageBaseType*>(writer->GetInput()->GetPointer())),
+  m_Writer(writer),
+  m_ImageIO(NULL)
+{
+}
+
+template <class TImage>
+bool
+MultiImageFileWriter::Sink<TImage>
+::CanStreamWrite()
+{
+  if (m_ImageIO.IsNull())
+    return false;
+  return m_ImageIO->CanStreamWrite();
+}
+
+template <class TImage>
+void
+MultiImageFileWriter::Sink<TImage>
+::WriteImageInformation()
+{
+  m_Writer->UpdateOutputInformation();
+  m_ImageIO = m_Writer->GetImageIO();
+}
+
+template <class TImage>
+void
+MultiImageFileWriter::Sink<TImage>
+::Write(const RegionType & streamRegion)
+{
+  // Write the image stream
+  itk::ImageIORegion ioRegion(TImage::ImageDimension);
+  for (unsigned int i = 0; i < TImage::ImageDimension; ++i)
+    {
+    ioRegion.SetSize(i, streamRegion.GetSize(i));
+    ioRegion.SetIndex(i, streamRegion.GetIndex(i));
+    }
+  m_ImageIO->SetIORegion(ioRegion);
+  m_Writer->UpdateOutputData(nullptr);
+}
+
+} // end of namespace otb
+
+#endif // otbMultiImageFileWriter_txx
diff --git a/Modules/IO/ImageIO/otb-module.cmake b/Modules/IO/ImageIO/otb-module.cmake
index 552d431d5a41aba8c23ba62004eac3e60a905c80..d592ba8b086549b5a132f64f0867282e9b7a4de8 100644
--- a/Modules/IO/ImageIO/otb-module.cmake
+++ b/Modules/IO/ImageIO/otb-module.cmake
@@ -22,6 +22,7 @@ set(DOCUMENTATION "This module contains classes related to the reading and the
 writing of remote sensing images.")
 
 otb_module(OTBImageIO
+  ENABLE_SHARED
   DEPENDS
     OTBBoostAdapters
     OTBCommon
diff --git a/Modules/IO/ImageIO/src/CMakeLists.txt b/Modules/IO/ImageIO/src/CMakeLists.txt
index 2d580c6541b14e92fb19e500276f5146103257e0..e604942a7cd4b8473e595bd457dfbdac05523938 100644
--- a/Modules/IO/ImageIO/src/CMakeLists.txt
+++ b/Modules/IO/ImageIO/src/CMakeLists.txt
@@ -20,6 +20,7 @@
 
 set(OTBImageIO_SRC
   otbImageIOFactory.cxx
+  otbMultiImageFileWriter.cxx
   )
 
 add_library(OTBImageIO ${OTBImageIO_SRC})
diff --git a/Modules/IO/ImageIO/src/otbMultiImageFileWriter.cxx b/Modules/IO/ImageIO/src/otbMultiImageFileWriter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a3f32a8d36bd404a271c2fd58d61b94488faf981
--- /dev/null
+++ b/Modules/IO/ImageIO/src/otbMultiImageFileWriter.cxx
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) CS SI
+ *
+ * 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 "otbMultiImageFileWriter.h"
+#include "otbImageIOFactory.h"
+
+namespace otb
+{
+
+MultiImageFileWriter
+::MultiImageFileWriter() :
+ m_NumberOfDivisions(0),
+ m_CurrentDivision(0),
+ m_DivisionProgress(0.0),
+ m_IsObserving(true),
+ m_ObserverID(0)
+{
+  // By default, we use tiled streaming, with automatic tile size
+  // We don't set any parameter, so the memory size is retrieved from the OTB configuration options
+  this->SetAutomaticAdaptativeStreaming();
+  // add a fake output to drive memory estimation
+  this->SetNthOutput(0, FakeOutputType::New());
+}
+
+void
+MultiImageFileWriter
+::SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
+{
+  typedef NumberOfDivisionsStrippedStreamingManager<FakeOutputType> NumberOfDivisionsStrippedStreamingManagerType;
+  NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager =
+    NumberOfDivisionsStrippedStreamingManagerType::New();
+  streamingManager->SetNumberOfDivisions(nbDivisions);
+
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
+{
+  typedef NumberOfDivisionsTiledStreamingManager<FakeOutputType> NumberOfDivisionsTiledStreamingManagerType;
+  NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager =
+    NumberOfDivisionsTiledStreamingManagerType::New();
+  streamingManager->SetNumberOfDivisions(nbDivisions);
+
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
+{
+  typedef NumberOfLinesStrippedStreamingManager<FakeOutputType> NumberOfLinesStrippedStreamingManagerType;
+  NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager =
+    NumberOfLinesStrippedStreamingManagerType::New();
+  streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
+
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
+{
+  typedef RAMDrivenStrippedStreamingManager<FakeOutputType> RAMDrivenStrippedStreamingManagerType;
+  RAMDrivenStrippedStreamingManagerType::Pointer streamingManager =
+    RAMDrivenStrippedStreamingManagerType::New();
+  streamingManager->SetAvailableRAMInMB(availableRAM);
+  streamingManager->SetBias(bias);
+
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetTileDimensionTiledStreaming(unsigned int tileDimension)
+{
+  typedef TileDimensionTiledStreamingManager<FakeOutputType> TileDimensionTiledStreamingManagerType;
+  TileDimensionTiledStreamingManagerType::Pointer streamingManager =
+    TileDimensionTiledStreamingManagerType::New();
+  streamingManager->SetTileDimension(tileDimension);
+
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
+{
+  typedef RAMDrivenTiledStreamingManager<FakeOutputType> RAMDrivenTiledStreamingManagerType;
+  RAMDrivenTiledStreamingManagerType::Pointer streamingManager =
+    RAMDrivenTiledStreamingManagerType::New();
+  streamingManager->SetAvailableRAMInMB(availableRAM);
+  streamingManager->SetBias(bias);
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
+{
+  typedef RAMDrivenAdaptativeStreamingManager<FakeOutputType> RAMDrivenAdaptativeStreamingManagerType;
+  RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager =
+    RAMDrivenAdaptativeStreamingManagerType::New();
+  streamingManager->SetAvailableRAMInMB(availableRAM);
+  streamingManager->SetBias(bias);
+  m_StreamingManager = streamingManager;
+}
+
+void
+MultiImageFileWriter
+::InitializeStreaming()
+{
+//  const ImageBaseType* inputPtr = this->GetInput(0);
+  if(m_SinkList.size() == 0)
+    itkExceptionMacro("At least one input must be connected to the writer\n");
+  const ImageBaseType* inputPtr = m_SinkList[0]->GetInput();
+  if(!inputPtr)
+    itkExceptionMacro("At least one input must be connected to the writer\n");
+
+  /** Control if the ImageIO is CanStreamWrite */
+  m_NumberOfDivisions = 1;
+  bool canStream = true;
+  bool isBuffered = true;
+  for (unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
+    {
+    if (!m_SinkList[inputIndex]->CanStreamWrite())
+      {
+      canStream = false;
+      }
+    if (m_SinkList[inputIndex]->GetInput()->GetBufferedRegion() !=
+        m_SinkList[inputIndex]->GetInput()->GetLargestPossibleRegion())
+      {
+      isBuffered = false;
+      }
+    }
+  if (canStream == false)
+    {
+    otbWarningMacro(
+      << "One of the selected ImageIO does not support streaming.");
+    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
+    }
+
+  /** Compare the buffered region  with the inputRegion which is the largest
+  * possible region or a user defined region through extended filename
+  * Not sure that if this modification is needed  */
+  else if (isBuffered)
+    {
+    otbMsgDevMacro(<< "Buffered region is the largest possible region, there is"
+      " no need for streaming.");
+    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
+    }
+  else
+    {
+    /**
+     * Determine of number of pieces to divide the input.  This will be the
+     * first estimated on the fake output, which has the same size as the
+     * first input. Then there is a check that each input can be split into
+     * this number of pieces.
+     */
+    FakeOutputType * fakeOut = static_cast<FakeOutputType *>(
+      this->itk::ProcessObject::GetOutput(0));
+    RegionType region = fakeOut->GetLargestPossibleRegion();
+    m_StreamingManager->PrepareStreaming(fakeOut, region);
+    m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
+    // Check this number of division is compatible with all inputs
+    bool nbDivValid = false;
+    while ( (!nbDivValid) && 1 < m_NumberOfDivisions)
+      {
+      unsigned int smallestNbDiv = m_NumberOfDivisions;
+      for (unsigned int i = 0; i < m_SinkList.size(); ++i)
+        {
+        unsigned int div = m_StreamingManager->GetSplitter()->GetNumberOfSplits(
+          m_SinkList[i]->GetInput()->GetLargestPossibleRegion(),
+          m_NumberOfDivisions);
+        smallestNbDiv = std::min(div, smallestNbDiv);
+        }
+      if (smallestNbDiv == m_NumberOfDivisions)
+        {
+        nbDivValid = true;
+        }
+      else
+        {
+        m_NumberOfDivisions = smallestNbDiv;
+        }
+      }
+    if (m_NumberOfDivisions == 1)
+      {
+      otbWarningMacro("Can't find a common split scheme between all inputs, streaming disabled\n");
+      }
+    otbMsgDebugMacro(<< "Number Of Stream Divisions : " << m_NumberOfDivisions);
+    }
+}
+
+void
+MultiImageFileWriter
+::ResetAllRequestedRegions(ImageBaseType* imagePtr)
+{
+  RegionType nullRegion = imagePtr->GetLargestPossibleRegion();
+  nullRegion.SetSize(0, 0);
+  nullRegion.SetSize(1, 0);
+
+  imagePtr->SetRequestedRegion(nullRegion);
+  if(imagePtr->GetSource())
+    {
+    itk::ProcessObject::DataObjectPointerArray inputs = imagePtr->GetSource()->GetInputs();
+    for( itk::ProcessObject::DataObjectPointerArray::iterator
+        it = inputs.begin();
+        it != inputs.end();
+        ++it )
+      {
+      ImageBaseType * inputImagePtr = dynamic_cast<ImageBaseType*>(it->GetPointer());
+      if(inputImagePtr != NULL)
+        {
+        ResetAllRequestedRegions(inputImagePtr);
+        }
+      }
+    }
+}
+
+void
+MultiImageFileWriter
+::UpdateOutputInformation()
+{
+  for(unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
+    {
+    m_SinkList[inputIndex]->WriteImageInformation();
+    }
+  this->GenerateOutputInformation();
+}
+
+void
+MultiImageFileWriter
+::UpdateOutputData(itk::DataObject * itkNotUsed(output))
+{
+  /**
+   * prevent chasing our tail
+   */
+  if (this->m_Updating)
+    {
+    return;
+    }
+
+  // Initialize streaming
+  this->InitializeStreaming();
+
+  this->SetAbortGenerateData(0);
+  this->SetProgress(0.0);
+  this->m_Updating = true;
+
+  /**
+   * Tell all Observers that the filter is starting
+   */
+  this->InvokeEvent(itk::StartEvent());
+
+  this->UpdateProgress(0);
+  m_CurrentDivision = 0;
+  m_DivisionProgress = 0;
+
+  /** Loop over the number of pieces, set and propagate requested regions then
+   * update pipeline upstream
+   */
+  int numInputs = m_SinkList.size(); //this->GetNumberOfInputs();
+  m_StreamRegionList.resize(numInputs);
+  itkDebugMacro( "Number of streaming divisions: " << m_NumberOfDivisions);
+
+  // Add observer only to first input
+  if(numInputs > 0)
+    {
+    m_IsObserving = false;
+    m_ObserverID = 0;
+
+    typedef itk::MemberCommand<Self> CommandType;
+    typedef CommandType::Pointer CommandPointerType;
+
+    CommandPointerType command = CommandType::New();
+    command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);
+
+    itk::ProcessObject* src = this->GetInput(0)->GetSource();
+    m_ObserverID = src->AddObserver(itk::ProgressEvent(), command);
+    m_IsObserving = true;
+    }
+
+  for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
+      m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
+    {
+    // Update all stream regions
+    for(int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
+      {
+      m_StreamRegionList[inputIndex] = GetStreamRegion(inputIndex);
+      }
+
+    // NOTE : this reset was probably designed to work with the next section
+    // Where the final requested region is the "union" between the computed
+    // requested region and the current requested region.
+    
+    // Reset requested regions for all images
+    for(int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
+      {
+      ResetAllRequestedRegions(m_SinkList[inputIndex]->GetInput());
+      }
+
+    for(int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
+      {
+      ImageBaseType::Pointer inputPtr = m_SinkList[inputIndex]->GetInput();
+      RegionType inputRequestedRegion = m_StreamRegionList[inputIndex];
+      const RegionType & currentInputRequestedRegion = inputPtr->GetRequestedRegion();
+      if( currentInputRequestedRegion != inputPtr->GetLargestPossibleRegion()
+        && currentInputRequestedRegion.GetNumberOfPixels() != 0)
+        {
+        IndexType startIndex = currentInputRequestedRegion.GetIndex();
+        IndexType lastIndex = currentInputRequestedRegion.GetUpperIndex();
+        startIndex[0] = std::min(startIndex[0], inputRequestedRegion.GetIndex(0));
+        startIndex[1] = std::min(startIndex[1], inputRequestedRegion.GetIndex(1));
+        lastIndex[0] = std::max(lastIndex[0], inputRequestedRegion.GetUpperIndex()[0]);
+        lastIndex[1] = std::max(lastIndex[1], inputRequestedRegion.GetUpperIndex()[1]);
+        inputRequestedRegion.SetIndex(startIndex);
+        inputRequestedRegion.SetUpperIndex(lastIndex);
+        }
+
+      inputPtr->SetRequestedRegion(inputRequestedRegion);
+      inputPtr->PropagateRequestedRegion();
+      }
+
+    /** Call GenerateData to write streams to files if needed */
+    this->GenerateData();
+    }
+
+  /**
+   * If we ended due to aborting, push the progress up to 1.0 (since
+   * it probably didn't end there)
+   */
+  if (!this->GetAbortGenerateData())
+    {
+    this->UpdateProgress(1.0);
+    }
+
+  // Notify end event observers
+  this->InvokeEvent(itk::EndEvent());
+
+  if (m_IsObserving)
+    {
+    ImageBaseType::Pointer inputPtr = m_SinkList[0]->GetInput(); // const_cast<ImageBaseType *>(this->GetInput(0));
+    itk::ProcessObject* source = inputPtr->GetSource();
+    m_IsObserving = false;
+    source->RemoveObserver(m_ObserverID);
+    }
+
+  /**
+   * Release any inputs if marked for release
+   */
+  this->ReleaseInputs();
+
+  // Mark that we are no longer updating the data in this filter
+  this->m_Updating = false;
+}
+
+
+void
+MultiImageFileWriter
+::GenerateInputRequestedRegion()
+{
+  Superclass::GenerateInputRequestedRegion();
+
+  // Approximate conversion of output requested region into each input,
+  // but this is only to have a consistent pipeline memory estimation.
+  int numInputs = m_SinkList.size(); //this->GetNumberOfInputs();
+
+  FakeOutputType* fakeOut = static_cast<FakeOutputType *>(
+    this->itk::ProcessObject::GetOutput(0));
+
+  if (numInputs)
+    {
+    RegionType refLargest = fakeOut->GetLargestPossibleRegion();
+    RegionType refRequest = fakeOut->GetRequestedRegion();
+    IndexType idxLargest = refLargest.GetIndex();
+    SizeType sizeLargest = refLargest.GetSize();
+    IndexType idxRequest = refRequest.GetIndex();
+    SizeType sizeRequest = refRequest.GetSize();
+    for (int i = 0; i < numInputs; ++i)
+      {
+      ImageBaseType* inputPtr = m_SinkList[i]->GetInput();
+      if(!inputPtr)
+        {
+        return;
+        }
+      RegionType region = inputPtr->GetLargestPossibleRegion();
+      IndexType idx = region.GetIndex();
+      SizeType size = region.GetSize();
+      idx[0] += size[0] * (idxRequest[0] - idxLargest[0]) / sizeLargest[0];
+      idx[1] += size[1] * (idxRequest[1] - idxLargest[1]) / sizeLargest[1];
+      size[0] *= sizeRequest[0] / sizeLargest[0];
+      size[1] *= sizeRequest[1] / sizeLargest[1];
+      region.SetIndex(idx);
+      region.SetSize(size);
+      inputPtr->SetRequestedRegion(region);
+      }
+    }
+}
+
+void
+MultiImageFileWriter
+::GenerateData()
+{
+  int numInputs = m_SinkList.size();
+  for(int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
+    {
+    m_SinkList[inputIndex]->Write(m_StreamRegionList[inputIndex]);
+    }
+}
+
+MultiImageFileWriter::RegionType
+MultiImageFileWriter
+::GetStreamRegion(int inputIndex)
+{
+  const SinkBase::Pointer sink = m_SinkList[inputIndex];
+  RegionType region = sink->GetInput()->GetLargestPossibleRegion();
+
+  m_StreamingManager->GetSplitter()->GetSplit(
+    m_CurrentDivision,
+    m_NumberOfDivisions,
+    region);
+  return region;
+}
+
+} // end of namespace otb
diff --git a/Modules/IO/ImageIO/test/CMakeLists.txt b/Modules/IO/ImageIO/test/CMakeLists.txt
index aac49fcdeab48d245227689b5aeb6461f6d6dd07..110b25410e8bfd8f663a505fa202b4399d213609 100644
--- a/Modules/IO/ImageIO/test/CMakeLists.txt
+++ b/Modules/IO/ImageIO/test/CMakeLists.txt
@@ -76,6 +76,7 @@ otbImageIOFactoryNew.cxx
 otbCompareWritingComplexImage.cxx
 otbImageFileReaderOptBandTest.cxx
 otbImageFileWriterOptBandTest.cxx
+otbMultiImageFileWriterTest.cxx
 )
 
 add_executable(otbImageIOTestDriver ${OTBImageIOTests})
@@ -1339,3 +1340,31 @@ otb_add_test(NAME ioTvImageIOToWriterOptions_OptBandReorgTest COMMAND otbImageIO
   ${TEMP}/QB_Toulouse_Ortho_XS_WriterOptBandReorg.tif?bands=2,:,-3,2:-1
   4
   )
+
+otb_add_test(NAME ioTvMultiImageFileWriter_SameSize
+  COMMAND otbImageIOTestDriver
+  --compare-n-images ${EPSILON_9} 2
+  ${INPUTDATA}/GomaAvant.png
+  ${TEMP}/ioTvMultiImageFileWriter_SameSize1.tif
+  ${INPUTDATA}/GomaApres.png
+  ${TEMP}/ioTvMultiImageFileWriter_SameSize2.tif
+  otbMultiImageFileWriterTest
+  ${INPUTDATA}/GomaAvant.png
+  ${INPUTDATA}/GomaApres.png
+  ${TEMP}/ioTvMultiImageFileWriter_SameSize1.tif
+  ${TEMP}/ioTvMultiImageFileWriter_SameSize2.tif
+  50)
+
+otb_add_test(NAME ioTvMultiImageFileWriter_DiffSize
+  COMMAND otbImageIOTestDriver
+  --compare-n-images ${EPSILON_9} 2
+  ${INPUTDATA}/GomaAvant.png
+  ${TEMP}/ioTvMultiImageFileWriter_DiffSize1.tif
+  ${INPUTDATA}/QB_Toulouse_Ortho_PAN.tif
+  ${TEMP}/ioTvMultiImageFileWriter_DiffSize2.tif
+  otbMultiImageFileWriterTest
+  ${INPUTDATA}/GomaAvant.png
+  ${INPUTDATA}/QB_Toulouse_Ortho_PAN.tif
+  ${TEMP}/ioTvMultiImageFileWriter_DiffSize1.tif
+  ${TEMP}/ioTvMultiImageFileWriter_DiffSize2.tif
+  25)
diff --git a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx
index fb2aa583aa73653ece1ffb9f523ae6caaec71d84..4a7ff9409a53d34ec7d404c6f6d56cc57c8917bf 100644
--- a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx
+++ b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx
@@ -154,4 +154,5 @@ void RegisterTests()
   REGISTER_TEST(otbCompareWritingComplexImageTest);
   REGISTER_TEST(otbImageFileReaderOptBandTest);
   REGISTER_TEST(otbImageFileWriterOptBandTest);
+  REGISTER_TEST(otbMultiImageFileWriterTest);
 }
diff --git a/Modules/IO/ImageIO/test/otbMultiImageFileWriterTest.cxx b/Modules/IO/ImageIO/test/otbMultiImageFileWriterTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..77d6ede243b19c34694ff18a74959457c060a0d0
--- /dev/null
+++ b/Modules/IO/ImageIO/test/otbMultiImageFileWriterTest.cxx
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) CS SI
+ *
+ * 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 "otbMultiImageFileWriter.h"
+#include "otbImage.h"
+#include "otbImageFileReader.h"
+
+int otbMultiImageFileWriterTest(int argc, char* argv[])
+{
+  typedef unsigned short PixelType1;
+  typedef otb::Image<PixelType1, 2> ImageType1;
+  typedef otb::ImageFileReader<ImageType1> ReaderType1;
+
+  typedef double PixelType2;
+  typedef otb::Image<PixelType2, 2> ImageType2;
+  typedef otb::ImageFileReader<ImageType2> ReaderType2;
+
+  typedef otb::MultiImageFileWriter WriterType;
+
+  if (argc < 6)
+    {
+    std::cout << "Usage: " << argv[0] << " inputImageFileName1 inputImageFileName2 outputImageFileName1 outputImageFileName2 numberOfLinesPerStrip\n";
+    return EXIT_FAILURE;
+    }
+
+  const char * inputImageFileName1 = argv[1];
+  const char * inputImageFileName2 = argv[2];
+  const std::string outputImageFileName1 = argv[3];
+  const std::string outputImageFileName2 = argv[4];
+  const int numberOfLinesPerStrip = atoi(argv[5]);
+
+  ReaderType1::Pointer reader1 = ReaderType1::New();
+  reader1->SetFileName( inputImageFileName1 );
+
+  ReaderType2::Pointer reader2 = ReaderType2::New();
+  reader2->SetFileName( inputImageFileName2 );
+
+  WriterType::Pointer writer = WriterType::New();
+  writer->AddInputImage( reader1->GetOutput(), outputImageFileName1);
+  writer->AddInputImage( reader2->GetOutput(), outputImageFileName2);
+  writer->SetNumberOfLinesStrippedStreaming( numberOfLinesPerStrip );
+
+  writer->Update();
+
+  std::cout << writer << std::endl;
+
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/Learning/Sampling/include/otbSampleAugmentation.h b/Modules/Learning/Sampling/include/otbSampleAugmentation.h
new file mode 100644
index 0000000000000000000000000000000000000000..8196b3e9da759e330f6a652a13377b9f609e0d57
--- /dev/null
+++ b/Modules/Learning/Sampling/include/otbSampleAugmentation.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbSampleAugmentation_h
+#define otbSampleAugmentation_h
+
+#ifdef _OPENMP
+ # include <omp.h>
+#endif
+
+#include <vector>
+#include <algorithm>
+#include <random>
+#include <ctime>
+#include <cassert>
+#include <iostream>
+
+namespace otb
+{
+
+namespace sampleAugmentation
+{
+using SampleType = std::vector<double>;
+using SampleVectorType = std::vector<SampleType>;
+
+/**
+Estimate standard deviations of the components in one pass using
+Welford's algorithm
+*/
+SampleType EstimateStds(const SampleVectorType& samples)
+{
+  const auto nbSamples = samples.size();
+  const auto nbComponents = samples[0].size();
+  SampleType stds(nbComponents, 0.0);
+  SampleType means(nbComponents, 0.0);
+  for(size_t i=0; i<nbSamples; ++i)
+    {
+    auto norm_factor = 1.0/(i+1);
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif 
+    for(size_t j=0; j<nbComponents; ++j)
+      {
+      const auto mu = means[j];
+      const auto x = samples[i][j];
+      auto muNew = mu+(x-mu)*norm_factor;
+      stds[j] += (x-mu)*(x-muNew);
+      means[j] = muNew;
+      }
+    }
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+  for(size_t j=0; j<nbComponents; ++j)
+    {
+    stds[j] = std::sqrt(stds[j]/nbSamples);
+    }
+  return stds;
+}
+
+/** Create new samples by replicating input samples. We loop through
+* the input samples and add them to the new data set until nbSamples
+* are added. The elements of newSamples are removed before proceeding.
+*/
+void ReplicateSamples(const SampleVectorType& inSamples, 
+                      const size_t nbSamples,
+                    SampleVectorType& newSamples)
+{
+  newSamples.resize(nbSamples);
+  size_t imod{0};
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+  for(size_t i=0; i<nbSamples; ++i)
+    {
+    if (imod == inSamples.size()) imod = 0;
+    newSamples[i] = inSamples[imod++];
+    }
+
+}
+
+/** Create new samples by adding noise to existing samples. Gaussian
+* noise is added to randomly selected samples. The standard deviation
+* of the noise added to each component is the same as the one of the
+* input variables divided by stdFactor (defaults to 10). The
+* elements of newSamples are removed before proceeding.
+*/
+void JitterSamples(const SampleVectorType& inSamples, 
+                   const size_t nbSamples,
+                      SampleVectorType& newSamples,
+                   float stdFactor=10,
+                   const int seed = std::time(nullptr))
+{
+  newSamples.resize(nbSamples);
+  const auto nbComponents = inSamples[0].size();
+  std::random_device rd;
+  std::mt19937 gen(rd());
+  // The input samples are selected randomly with replacement
+  std::srand(seed);
+  // We use one gaussian distribution per component since they may
+  // have different stds
+  auto stds = EstimateStds(inSamples);
+  std::vector<std::normal_distribution<double>> gaussDis(nbComponents);
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+  for(size_t i=0; i<nbComponents; ++i)
+    gaussDis[i] = std::normal_distribution<double>{0.0, stds[i]/stdFactor};
+
+  for(size_t i=0; i<nbSamples; ++i)
+    {
+    newSamples[i] = inSamples[std::rand()%inSamples.size()];
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+    for(size_t j=0; j<nbComponents; ++j)
+      newSamples[i][j] += gaussDis[j](gen);
+    }
+}
+
+
+struct NeighborType
+{
+  size_t index;
+  double distance;
+};
+
+struct NeighborSorter
+{
+  constexpr bool operator ()(const NeighborType& a, const NeighborType& b) const
+  {
+    return b.distance > a.distance;
+  }
+};
+
+double ComputeSquareDistance(const SampleType& x, const SampleType& y)
+{
+  assert(x.size()==y.size());
+  double dist{0};
+  for(size_t i=0; i<x.size(); ++i)
+    {
+    dist += (x[i]-y[i])*(x[i]-y[i]);
+    }
+  return dist/(x.size()*x.size());
+}
+
+using NNIndicesType = std::vector<NeighborType>;
+using NNVectorType = std::vector<NNIndicesType>;
+/** Returns the indices of the nearest neighbors for each input sample
+*/
+void FindKNNIndices(const SampleVectorType& inSamples, 
+                    const size_t nbNeighbors,
+                    NNVectorType& nnVector)
+{
+  const auto nbSamples = inSamples.size();
+  nnVector.resize(nbSamples);
+  #ifdef _OPENMP
+  #pragma omp parallel for
+  #endif
+  for(size_t sampleIdx=0; sampleIdx<nbSamples; ++sampleIdx)
+    {
+    NNIndicesType nns;
+    for(size_t neighborIdx=0; neighborIdx<nbSamples; ++neighborIdx) 
+      {
+      if(sampleIdx!=neighborIdx)
+        nns.push_back({neighborIdx, ComputeSquareDistance(inSamples[sampleIdx],
+                                                          inSamples[neighborIdx])});
+      }  
+    std::partial_sort(nns.begin(), nns.begin()+nbNeighbors, nns.end(), NeighborSorter{});
+    nns.resize(nbNeighbors);
+    nnVector[sampleIdx] = std::move(nns);
+    }
+}
+
+/** Generate the new sample in the line linking s1 and s2
+*/
+SampleType SmoteCombine(const SampleType& s1, const SampleType& s2, double position)
+{
+  auto result = s1;
+  for(size_t i=0; i<s1.size(); ++i)
+    result[i] = s1[i]+(s2[i]-s1[i])*position;
+  return result;
+}
+
+/** Create new samples using the SMOTE algorithm
+Chawla, N. V., Bowyer, K. W., Hall, L. O., & Kegelmeyer, W. P., Smote:
+synthetic minority over-sampling technique, Journal of artificial
+intelligence research, 16(), 321–357 (2002).
+http://dx.doi.org/10.1613/jair.953
+*/
+void Smote(const SampleVectorType& inSamples, 
+           const size_t nbSamples,
+           SampleVectorType& newSamples,
+           const int nbNeighbors,
+           const int seed = std::time(nullptr))
+{
+  newSamples.resize(nbSamples);
+  NNVectorType nnVector;
+  FindKNNIndices(inSamples, nbNeighbors, nnVector);
+  // The input samples are selected randomly with replacement
+  std::srand(seed);
+  #ifdef _OPENMP
+  #pragma omp parallel for
+  #endif
+  for(size_t i=0; i<nbSamples; ++i)
+    {
+    const auto sampleIdx = std::rand()%(inSamples.size());
+    const auto sample = inSamples[sampleIdx];
+    const auto neighborIdx = nnVector[sampleIdx][std::rand()%nbNeighbors].index;
+    const auto neighbor = inSamples[neighborIdx];
+    newSamples[i] = SmoteCombine(sample, neighbor, std::rand()/double{RAND_MAX}); 
+    }
+}
+
+}//end namespaces sampleAugmentation
+}//end namespace otb
+
+#endif
diff --git a/Modules/Learning/Sampling/include/otbSampleAugmentationFilter.h b/Modules/Learning/Sampling/include/otbSampleAugmentationFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..63b8af0a7a95dabb33795817a4a4b302d495b832
--- /dev/null
+++ b/Modules/Learning/Sampling/include/otbSampleAugmentationFilter.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbSampleAugmentationFilter_h
+#define otbSampleAugmentationFilter_h
+
+#include "itkProcessObject.h"
+#include "otbOGRDataSourceWrapper.h"
+#include "otbSampleAugmentation.h"
+#include "OTBSamplingExport.h"
+
+namespace otb
+{
+
+
+/** 
+ * \class SampleAugmentationFilter
+ *
+ * \brief Filter to generate synthetic samples from existing ones 
+ *
+ * This class generates synthetic samples from existing ones either by
+ * replication, jitter (adding gaussian noise to the features of
+ * existing samples) or SMOTE (linear combination of pairs
+ * neighbouring samples of the same class.
+ *
+ * \ingroup OTBSampling
+ */
+
+class OTBSampling_EXPORT SampleAugmentationFilter :
+    public itk::ProcessObject
+{
+public:
+
+  /** typedef for the classes standards. */
+  typedef SampleAugmentationFilter                 Self;
+  typedef itk::ProcessObject                              Superclass;
+  typedef itk::SmartPointer<Self>                         Pointer;
+  typedef itk::SmartPointer<const Self>                   ConstPointer;
+
+  /** Method for management of the object factory. */
+  itkNewMacro(Self);
+
+  /** Return the name of the class. */
+  itkTypeMacro(SampleAugmentationFilter, ProcessObject);
+
+  typedef ogr::DataSource                            OGRDataSourceType;
+  typedef typename OGRDataSourceType::Pointer        OGRDataSourcePointerType;
+  typedef ogr::Layer                                 OGRLayerType;
+
+  typedef itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType;
+
+  using SampleType = sampleAugmentation::SampleType;
+  using SampleVectorType = sampleAugmentation::SampleVectorType;
+
+  enum class Strategy { Replicate, Jitter, Smote };
+
+  /** Set/Get the input OGRDataSource of this process object.  */
+  using Superclass::SetInput;
+  virtual void SetInput(const OGRDataSourceType* ds);
+  const OGRDataSourceType*  GetInput(unsigned int idx);
+
+  virtual void SetOutputSamples(ogr::DataSource* data);
+
+  /** Set the Field Name in which labels will be written. (default is "class")
+   * A field "ClassFieldName" of type integer is created in the output memory layer.
+   */
+  itkSetMacro(ClassFieldName, std::string);
+  /**
+   * Return the Field name in which labels have been written.
+   */
+  itkGetMacro(ClassFieldName, std::string);
+
+
+  itkSetMacro(Layer, size_t);
+  itkGetMacro(Layer, size_t);
+  itkSetMacro(Label, int);
+  itkGetMacro(Label, int);
+  void SetStrategy(Strategy s)
+  {
+    m_Strategy = s;
+  }
+  Strategy GetStrategy() const
+  {
+    return m_Strategy;
+  }
+  itkSetMacro(NumberOfSamples, int);
+  itkGetMacro(NumberOfSamples, int);
+  void SetExcludedFields(const std::vector<std::string>& ef)
+  {
+    m_ExcludedFields = ef;
+  }
+  std::vector<std::string> GetExcludedFields() const
+  {
+    return m_ExcludedFields;
+  }
+  itkSetMacro(StdFactor, double);
+  itkGetMacro(StdFactor, double);
+  itkSetMacro(SmoteNeighbors, size_t);
+  itkGetMacro(SmoteNeighbors, size_t);
+  itkSetMacro(Seed, int);
+  itkGetMacro(Seed, int);
+/**
+   * Get the output \c ogr::DataSource which is a "memory" datasource.
+   */
+  const OGRDataSourceType * GetOutput();
+
+protected:
+  SampleAugmentationFilter();
+  ~SampleAugmentationFilter() ITK_OVERRIDE {}
+
+  /** Generate Data method*/
+  void GenerateData() ITK_OVERRIDE;
+
+  /** DataObject pointer */
+  typedef itk::DataObject::Pointer DataObjectPointer;
+
+  DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) ITK_OVERRIDE;
+  using Superclass::MakeOutput;
+
+
+  SampleVectorType ExtractSamples(const ogr::DataSource::Pointer vectors, 
+                                  size_t layerName,
+                                  const std::string& classField, const int label,
+                                  const std::vector<std::string>& excludedFields = {});
+
+  void SampleToOGRFeatures(const ogr::DataSource::Pointer& vectors,
+                           ogr::DataSource* output, 
+                           const SampleVectorType& samples,
+                           const size_t layerName,
+                           const std::string& classField, int label,
+                           const std::vector<std::string>& excludedFields = {});
+
+  std::set<size_t> GetExcludedFieldsIds(const std::vector<std::string>& excludedFields,
+                                        const ogr::Layer& inputLayer);
+  bool IsNumericField(const ogr::Feature& feature, const int idx);
+
+  ogr::Feature SelectTemplateFeature(const ogr::Layer& inputLayer, 
+                                     const std::string& classField, int label);
+private:
+  SampleAugmentationFilter(const Self &);  //purposely not implemented
+  void operator =(const Self&);      //purposely not implemented
+
+  std::string m_ClassFieldName;
+  size_t m_Layer;
+  int m_Label;
+  std::vector<std::string> m_ExcludedFields;
+  Strategy m_Strategy;
+  int m_NumberOfSamples;
+  double m_StdFactor;
+  size_t m_SmoteNeighbors;
+  int m_Seed;
+
+};
+
+
+} // end namespace otb
+
+#endif
diff --git a/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h b/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
index e16e8a9a48447e453cf2c70e69b4c881eb1c19fb..c16a758a5d82b51578de112e59963470f3625f41 100644
--- a/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
+++ b/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
@@ -24,6 +24,7 @@
 #include "itkImageRegion.h"
 #include "itkVectorContainer.h"
 #include <set>
+#include "OTBSamplingExport.h"
 
 namespace otb
 {
@@ -36,7 +37,7 @@ namespace otb
  * \ingroup OTBSampling
  */
 
-class ITK_EXPORT SamplingRateCalculator
+class OTBSampling_EXPORT SamplingRateCalculator
   : public itk::Object
 {
 public:
@@ -49,7 +50,7 @@ public:
   /** typdefs **/
   typedef std::map<std::string, unsigned long>  ClassCountMapType;
   typedef ClassCountMapType::const_iterator constItMapType;
-  typedef struct Triplet
+  typedef struct OTBSampling_EXPORT Triplet
    {
      unsigned long Required;
      unsigned long Tot;
diff --git a/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h b/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h
index 7bc78c188d8e0be07a8da44b22547bb4a8138f15..ad9d86a54edded0d444b6a9b8463f775be5107f7 100644
--- a/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h
+++ b/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h
@@ -23,6 +23,7 @@
 
 #include "otbSamplingRateCalculator.h"
 #include "otbObjectList.h"
+#include "OTBSamplingExport.h"
 
 namespace otb
 {
@@ -37,7 +38,7 @@ namespace otb
  *
  * \ingroup OTBSampling
  */
-class ITK_EXPORT SamplingRateCalculatorList
+class OTBSampling_EXPORT SamplingRateCalculatorList
   : public ObjectList<SamplingRateCalculator>
 {
 public:
diff --git a/Modules/Learning/Sampling/otb-module.cmake b/Modules/Learning/Sampling/otb-module.cmake
index 4eb65c39829be9317c80589eac55b93f934db40e..2b8ca50f8a4579e401b3d83fb04212f1a63b3cc0 100644
--- a/Modules/Learning/Sampling/otb-module.cmake
+++ b/Modules/Learning/Sampling/otb-module.cmake
@@ -21,6 +21,7 @@
 set(DOCUMENTATION "This module contains OTB sampling framework.")
 
 otb_module(OTBSampling
+  ENABLE_SHARED
   DEPENDS
     OTBCommon
     OTBConversion
diff --git a/Modules/Learning/Sampling/src/CMakeLists.txt b/Modules/Learning/Sampling/src/CMakeLists.txt
index 8504c688f4827bd93006e71961bb5255b4cfb809..bef592365baf129ebdfd02742ca5d76830d11b06 100644
--- a/Modules/Learning/Sampling/src/CMakeLists.txt
+++ b/Modules/Learning/Sampling/src/CMakeLists.txt
@@ -21,7 +21,8 @@
 set(OTBSampling_SRC
   otbSamplingRateCalculator.cxx
   otbSamplingRateCalculatorList.cxx
-)
+  otbSampleAugmentationFilter.cxx
+  )
 
 add_library(OTBSampling ${OTBSampling_SRC})
 target_link_libraries(OTBSampling
diff --git a/Modules/Learning/Sampling/src/otbSampleAugmentationFilter.cxx b/Modules/Learning/Sampling/src/otbSampleAugmentationFilter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5778de0d9324b7a022cab8569c3b25a48260cfc8
--- /dev/null
+++ b/Modules/Learning/Sampling/src/otbSampleAugmentationFilter.cxx
@@ -0,0 +1,269 @@
+/*
+ * 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 "otbSampleAugmentationFilter.h"
+#include "stdint.h" //needed for uintptr_t
+
+namespace otb
+{
+
+SampleAugmentationFilter
+::SampleAugmentationFilter() : m_ClassFieldName{"class"}, m_Layer{0}, m_Label{1},
+                               m_Strategy{SampleAugmentationFilter::Strategy::Replicate},
+                               m_NumberOfSamples{100}, m_StdFactor{10.0}, 
+                               m_SmoteNeighbors{5}, m_Seed{0}
+{
+  this->SetNumberOfRequiredInputs(1);
+  this->SetNumberOfRequiredOutputs(1);
+  this->ProcessObject::SetNthOutput(0, this->MakeOutput(0) );
+}
+
+
+typename SampleAugmentationFilter::DataObjectPointer
+SampleAugmentationFilter
+::MakeOutput(DataObjectPointerArraySizeType itkNotUsed(idx))
+{
+  return static_cast< DataObjectPointer >(OGRDataSourceType::New().GetPointer());
+}
+
+const typename SampleAugmentationFilter::OGRDataSourceType *
+SampleAugmentationFilter
+::GetOutput()
+{
+  return static_cast< const OGRDataSourceType *>(
+    this->ProcessObject::GetOutput(0));
+}
+
+void
+SampleAugmentationFilter
+::SetInput(const otb::ogr::DataSource* ds)
+{
+  this->Superclass::SetNthInput(0, const_cast<otb::ogr::DataSource *>(ds));
+}
+
+const typename SampleAugmentationFilter::OGRDataSourceType *
+SampleAugmentationFilter
+::GetInput(unsigned int idx)
+{
+  return static_cast<const OGRDataSourceType *>
+    (this->itk::ProcessObject::GetInput(idx));
+}
+
+void
+SampleAugmentationFilter
+::SetOutputSamples(ogr::DataSource* data)
+{
+  this->SetNthOutput(0,data);
+}
+
+
+void
+SampleAugmentationFilter
+::GenerateData(void)
+{
+
+  OGRDataSourcePointerType inputDS = dynamic_cast<OGRDataSourceType*>(this->itk::ProcessObject::GetInput(0));
+  auto outputDS = static_cast<ogr::DataSource *>(this->itk::ProcessObject::GetOutput(0));
+  auto inSamples = this->ExtractSamples(inputDS, m_Layer,
+                                        m_ClassFieldName,
+                                        m_Label,
+                                        m_ExcludedFields);
+  SampleVectorType newSamples;
+  switch (m_Strategy)
+    {
+    case Strategy::Replicate:
+    {
+    sampleAugmentation::ReplicateSamples(inSamples, m_NumberOfSamples,
+                                         newSamples);
+    }
+    break;
+    case Strategy::Jitter:
+    {
+    sampleAugmentation::JitterSamples(inSamples, m_NumberOfSamples,
+                                      newSamples,
+                                      m_StdFactor,
+                                      m_Seed);
+    }
+    break;
+    case Strategy::Smote:
+    {
+    sampleAugmentation::Smote(inSamples, m_NumberOfSamples,
+                              newSamples,
+                              m_SmoteNeighbors,
+                              m_Seed);
+    }
+    break;
+    }
+  this->SampleToOGRFeatures(inputDS, outputDS, newSamples, m_Layer,
+                            m_ClassFieldName,
+                            m_Label,
+                            m_ExcludedFields);
+
+
+  //  this->SetNthOutput(0,outputDS);
+}
+
+/** Extracts the samples of a single class from the vector data to a
+* vector and excludes some unwanted features.
+*/
+SampleAugmentationFilter::SampleVectorType 
+SampleAugmentationFilter
+::ExtractSamples(const ogr::DataSource::Pointer vectors, 
+                 size_t layerName,
+                 const std::string& classField, const int label,
+                 const std::vector<std::string>& excludedFields)
+{
+  ogr::Layer layer = vectors->GetLayer(layerName);
+  auto featureIt = layer.begin();
+  if(featureIt==layer.end())
+    {
+    itkExceptionMacro("Layer " << layerName << " of input sample file is empty.\n");
+    }
+  int cFieldIndex = (*featureIt).ogr().GetFieldIndex( classField.c_str() );
+  if( cFieldIndex < 0 )
+    {
+    itkExceptionMacro( "The field name for class label (" << classField
+                       << ") has not been found in the vector file " );
+    }
+
+  auto numberOfFields = (*featureIt).ogr().GetFieldCount();
+  auto excludedIds = this->GetExcludedFieldsIds(excludedFields, layer);
+  SampleVectorType samples;
+  int sampleCount{0};
+  while( featureIt!=layer.end() )
+    {
+    // Retrieve all the features for each field in the ogr layer.
+    if((*featureIt).ogr().GetFieldAsInteger(classField.c_str()) == label)
+      {
+
+      SampleType mv;
+      for(auto idx=0; idx<numberOfFields; ++idx)
+        {
+        if(excludedIds.find(idx) == excludedIds.cend() &&
+           this->IsNumericField((*featureIt), idx))
+          mv.push_back((*featureIt).ogr().GetFieldAsDouble(idx));
+        }
+      samples.push_back(mv); 
+      ++sampleCount;
+      }
+    ++featureIt;
+    }
+  if(sampleCount==0)
+    {
+    itkExceptionMacro("Could not find any samples in layer " << layerName <<
+                      " with label " << label << '\n');
+    }
+  return samples;
+}
+
+void 
+SampleAugmentationFilter
+::SampleToOGRFeatures(const ogr::DataSource::Pointer& vectors,
+                      ogr::DataSource* output, 
+                      const SampleAugmentationFilter::SampleVectorType& samples,
+                      const size_t layerName,
+                      const std::string& classField, int label,
+                      const std::vector<std::string>& excludedFields)
+{
+
+  auto inputLayer = vectors->GetLayer(layerName);
+  auto excludedIds = this->GetExcludedFieldsIds(excludedFields, inputLayer);
+
+  OGRSpatialReference * oSRS = nullptr;
+  if (inputLayer.GetSpatialRef())
+    {
+    oSRS = inputLayer.GetSpatialRef()->Clone();
+    }
+  OGRFeatureDefn &layerDefn = inputLayer.GetLayerDefn();
+
+  auto outputLayer = output->CreateLayer(inputLayer.GetName(), oSRS, 
+                                         inputLayer.GetGeomType());
+  for (int k=0 ; k < layerDefn.GetFieldCount() ; k++)
+    {
+    OGRFieldDefn originDefn(layerDefn.GetFieldDefn(k));
+    ogr::FieldDefn fieldDefn(originDefn);
+    outputLayer.CreateField(fieldDefn);
+    }
+
+  auto featureCount = outputLayer.GetFeatureCount(false);
+  auto templateFeature = this->SelectTemplateFeature(inputLayer, classField, label);
+  for(const auto& sample : samples)
+    {
+    ogr::Feature dstFeature(outputLayer.GetLayerDefn());
+    dstFeature.SetFrom( templateFeature, TRUE );
+    dstFeature.SetFID(++featureCount);
+    auto sampleFieldCounter = 0;
+    for (int k=0 ; k < layerDefn.GetFieldCount() ; k++)
+      {
+      if(excludedIds.find(k) == excludedIds.cend() &&
+         this->IsNumericField(dstFeature, k))
+        {
+        dstFeature.ogr().SetField(k, sample[sampleFieldCounter++]);
+        }
+      }
+    outputLayer.CreateFeature( dstFeature );
+    }
+}
+
+std::set<size_t> 
+SampleAugmentationFilter
+::GetExcludedFieldsIds(const std::vector<std::string>& excludedFields,
+                       const ogr::Layer& inputLayer)
+{
+  auto feature = *(inputLayer).begin();
+  std::set<size_t> excludedIds;
+  if( excludedFields.size() != 0)
+    {
+    for(const auto& fieldName : excludedFields)
+      {
+      auto idx = feature.ogr().GetFieldIndex( fieldName.c_str() );
+      excludedIds.insert(idx);
+      }
+    }
+  return excludedIds;
+}
+
+bool 
+SampleAugmentationFilter
+::IsNumericField(const ogr::Feature& feature,
+                 const int idx)
+{
+  OGRFieldType fieldType = feature.ogr().GetFieldDefnRef(idx)->GetType();
+  return (fieldType == OFTInteger 
+          || ogr::version_proxy::IsOFTInteger64( fieldType ) 
+          || fieldType == OFTReal);
+}
+
+ogr::Feature
+SampleAugmentationFilter
+::SelectTemplateFeature(const ogr::Layer& inputLayer, 
+                        const std::string& classField, int label)
+{
+  auto wh = std::find_if(inputLayer.begin(), inputLayer.end(),
+                         [&](auto& featureIt) 
+                         { 
+                           return featureIt.ogr().GetFieldAsInteger(classField.c_str()) == 
+                           label; 
+                         });
+  return (wh == inputLayer.end()) ? *(inputLayer.begin()) : *wh;
+
+}
+} // end namespace otb
+
diff --git a/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.h b/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.h
index f008e22bbb46c34eb77b2c8fafb464a68f5bb4dd..a7c413064a46a9afdd5f07ae2ca614ebc37b09d2 100644
--- a/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.h
+++ b/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.h
@@ -31,6 +31,7 @@
 #include "itkImageFileWriter.h"
 
 #include "itkObjectFactoryBase.h"
+#include "itkFastMutexLock.h"
 
 #include "itkImageRegionMultidimensionalSplitter.h"
 #include "otbImageIOFactory.h"
@@ -252,6 +253,11 @@ public:
   itkSetMacro(TiffTiledMode, bool);
   itkGetMacro(TiffTiledMode, bool);
 
+  /** This override doesn't return a const ref on the actual boolean */
+  const bool & GetAbortGenerateData() const override;
+
+  void SetAbortGenerateData(bool val) override;
+
 protected:
   SimpleParallelTiffWriter();
   virtual ~SimpleParallelTiffWriter();
@@ -325,6 +331,9 @@ private:
   bool m_Verbose;
   bool m_VirtualMode;
   bool m_TiffTiledMode;
+
+  /** Lock to ensure thread-safety (added for the AbortGenerateData flag) */
+  itk::SimpleFastMutexLock m_Lock;
 };
 
 
diff --git a/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.txx b/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.txx
index 9a3790c872e8f11dc6f0dc65ef0c565e26794cde..4292ad0f8460c3811e541e25a793711f59caec43 100644
--- a/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.txx
+++ b/Modules/MPI/MPITiffWriter/include/otbSimpleParallelTiffWriter.txx
@@ -23,6 +23,7 @@
 
 #include "otbSimpleParallelTiffWriter.h"
 #include "otbStopwatch.h"
+#include "otbUtils.h"
 
 using std::vector;
 
@@ -729,6 +730,16 @@ SimpleParallelTiffWriter<TInputImage>
       }
     }
 
+  // abort case
+  if (this->GetAbortGenerateData())
+    {
+    itk::ProcessAborted e(__FILE__, __LINE__);
+    e.SetLocation(ITK_LOCATION);
+    e.SetDescription("Image writing has been aborted");
+    throw e;
+    otb::MPIConfig::Instance()->abort(EXIT_FAILURE);
+    }
+
   // Clean up
   close_raster(output_raster);
   output_raster = NULL;
@@ -837,5 +848,27 @@ SimpleParallelTiffWriter<TInputImage>
   return this->m_FilenameHelper->GetSimpleFileName();
  }
 
+template <class TInputImage>
+const bool &
+SimpleParallelTiffWriter<TInputImage>
+::GetAbortGenerateData() const
+{
+  m_Lock.Lock();
+  bool ret = Superclass::GetAbortGenerateData();
+  m_Lock.Unlock();
+  if (ret) return otb::Utils::TrueConstant;
+  return otb::Utils::FalseConstant;
+}
+
+template <class TInputImage>
+void
+SimpleParallelTiffWriter<TInputImage>
+::SetAbortGenerateData(bool val)
+{
+  m_Lock.Lock();
+  Superclass::SetAbortGenerateData(val);
+  m_Lock.Unlock();
+}
+
 }
 #endif
diff --git a/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.h b/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.h
index ecec379e6d0cdaab2a6b39817b61ccd1a533c524..1800dc62ae4a170c70f0039906c79f2b2093e40d 100644
--- a/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.h
+++ b/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.h
@@ -47,232 +47,102 @@
 namespace otb {
 
 /**
- *\brief Write image data to multiple files with MPI processus and add a VRT file.
+ * \class MPIVrtWriter
  *
- * The image is divided into several pieces.
- * Each pieces is distributed to a MPI processus.
- * Each MPI processus write their pieces into a separate
- * file.
- * The master processus writes a VRT file (optional).
+ * \brief Write each tile of an image into a separate Tiff file and join them in a VRT
  *
- *\param img Image
- *\param output Output Filename
- *\param availableRAM Available memory for streaming
- *\param writeVRTFile Activate the VRT file writing
+ * \ingroup OTBMPIVrtWriter
  */
-template <typename TImage> void WriteMPI(TImage *img, const std::string &output, unsigned int availableRAM = 0, bool writeVRTFile=true)
+template <typename TImage>
+class MPIVrtWriter: public itk::ProcessObject
 {
-  typename otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();
-
-  unsigned int myRank = mpiConfig->GetMyRank();
-  unsigned int nbProcs = mpiConfig->GetNbProcs();
-
-  typedef otb::ImageFileWriter<TImage>                                           WriterType;
-  typedef otb::NumberOfDivisionsTiledStreamingManager<TImage>                    StreamingManagerType;
-  typedef itk::RegionOfInterestImageFilter<TImage, TImage>                       ExtractFilterType;
-
-  // First, update infomration from image to write
-  img->UpdateOutputInformation();
-
-  // Configure streaming manager
-  typename StreamingManagerType::Pointer streamingManager = StreamingManagerType::New();
-  streamingManager->SetNumberOfDivisions(nbProcs);
-  streamingManager->PrepareStreaming(img,img->GetLargestPossibleRegion());
-  unsigned int numberOfSplits = streamingManager->GetNumberOfSplits();
-
-  // This vector will hold all regions to write for current rank
-  std::vector<typename TImage::RegionType> regionsToWrite;
-
-  // Handle both cases when there are much more (resp. less) region to
-  // write than NbProcs
-  if(myRank < numberOfSplits)
-  {
-    unsigned int splitIdx = myRank;
-    while(splitIdx < numberOfSplits)
-    {
-      typename TImage::RegionType currentRegion = streamingManager->GetSplit(splitIdx);
-      regionsToWrite.push_back(currentRegion);
-      splitIdx+=nbProcs;
-    }
-  }
-
-  // Output prefix
-  std::string extension = itksys::SystemTools::GetFilenameExtension(output);
-  if (extension != ".vrt")
-  {
-
-  // TODO: Maybe remove this
-    if (extension == "")
-	{
-	  // Missing extension
-	  mpiConfig->logInfo("Filename has no extension. Adding <.vrt> extension.");
-	}
-	else
-	{
-	  // Bad extension
-	  mpiConfig->logError("Filename must have .vrt extension!");
-	  mpiConfig->abort(EXIT_FAILURE);
-	}
-  }
-  std::vector<std::string> joins;
-  joins.push_back(itksys::SystemTools::GetFilenamePath(output).append("/"));
-  joins.push_back(itksys::SystemTools::GetFilenameWithoutExtension(output));
-  std::string prefix = itksys::SystemTools::JoinPath(joins);
-
+public:
+  /** Standard class typedefs. */
+  typedef MPIVrtWriter                                      Self;
+  typedef itk::ProcessObject                                Superclass;
+  typedef itk::SmartPointer<Self>                           Pointer;
+  typedef itk::SmartPointer<const Self>                     ConstPointer;
 
-  // Data type
-  std::string dataTypeStr = "Float32";
-  GDALImageIO::Pointer gdalImageIO;
+  typedef TImage InputImageType;
 
-  // Now write all the regions
-  for(typename std::vector<typename TImage::RegionType>::const_iterator it = regionsToWrite.begin();
-      it!=regionsToWrite.end();++it)
-  {
-    typename ExtractFilterType::Pointer extractFilter = ExtractFilterType::New();
-    extractFilter->SetInput(img);
-    extractFilter->SetRegionOfInterest(*it);
-    // Writer
-	  // Output Filename
-    std::stringstream ss;
-    ss<<prefix<<"_"<<it->GetIndex()[0]<<"_"<<it->GetIndex()[1]<<"_"<<it->GetSize()[0]<<"_"<<it->GetSize()[1]<<".tif";
-    typename WriterType::Pointer writer = WriterType::New();
-    writer->SetFileName(ss.str());
-    writer->SetInput(extractFilter->GetOutput());
-    // Datatype
-    gdalImageIO = dynamic_cast<GDALImageIO *>(writer->GetImageIO());
-    if(gdalImageIO.IsNotNull())
-    {
-      dataTypeStr = gdalImageIO->GetGdalPixelTypeAsString();
-    }
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
 
-    if (!availableRAM)
-      {
-      writer->SetNumberOfDivisionsTiledStreaming(0);
-      }
-    else
-      {
-      writer->SetAutomaticAdaptativeStreaming(availableRAM);
-      }
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MPIVrtWriter, itk::ProcessObject);
 
-    // Pipeline execution
-    try
-    {
-      writer->Update();
-    }
-    catch (itk::ExceptionObject& err)
-    {
-      std::stringstream message;
-      message << "ExceptionObject caught: " << err << std::endl;
-      mpiConfig->logError(message.str());
-      mpiConfig->abort(EXIT_FAILURE);
-    }
-  }
+  using Superclass::SetInput;
+  virtual void SetInput(const InputImageType *input);
 
-  // MPI process synchronization
-  mpiConfig->barrier();
+  /** Get writer only input */
+  const InputImageType* GetInput();
 
-  // Write VRT file
-  try
-  {
-    if (writeVRTFile && (myRank == 0))
-    {
-      // VRT Filename
-      std::stringstream vrtfOut;
-      vrtfOut<< prefix << ".vrt";
+  /** Does the real work. */
+  virtual void Update() override;
 
-      // Data type
-      GDALDataType dataType;
-      dataType = GDALGetDataTypeByName(dataTypeStr.c_str());
+  /** SimpleParallelTiffWriter Methods */
+  virtual void SetFileName(const char* extendedFileName);
+  virtual void SetFileName(std::string extendedFileName);
+  virtual const char* GetFileName () const;
 
-      int imageSizeY = img->GetLargestPossibleRegion().GetSize()[1];
-      int imageSizeX = img->GetLargestPossibleRegion().GetSize()[0];
-      const unsigned int nbBands = img->GetNumberOfComponentsPerPixel();
+  /** Specify the region to write. If left NULL, then the whole image
+   * is written. */
+  void SetIORegion(const itk::ImageIORegion& region);
+  itkGetConstReferenceMacro(IORegion, itk::ImageIORegion);
 
-      // Get VRT driver
-      GDALAllRegister();
-      GDALDriver *driver = GetGDALDriverManager()->GetDriverByName("VRT");
-      if (driver == NULL) {
-         mpiConfig->logError("Error opening VRT driver.");
-         mpiConfig->abort(EXIT_FAILURE);
-      }
+  itkSetMacro(WriteVRT, bool);
+  itkGetMacro(WriteVRT, bool);
 
-      // Create output raster
-      GDALDataset *VRTOutput = driver->Create(vrtfOut.str().c_str(),
-            imageSizeX,
-            imageSizeY,
-            0,
-            dataType,
-            NULL); // No options
-      if (VRTOutput == NULL) {
-        mpiConfig->logError("driver->Create call failed.\n");
-        mpiConfig->abort(EXIT_FAILURE);
-      }
+  itkSetMacro(AvailableRAM, unsigned int);
+  itkGetMacro(AvailableRAM, unsigned int);
 
-      // Set GeoTransform
-      double gt[6];
-      gt[0] = img->GetOrigin()[0] - 0.5*img->GetSignedSpacing()[0];
-      gt[1] = img->GetSignedSpacing()[0];
-      gt[2] = 0.0;
-      gt[3] = img->GetOrigin()[1] - 0.5*img->GetSignedSpacing()[1];
-      gt[4] = 0.0;
-      gt[5] = img->GetSignedSpacing()[1];
-      VRTOutput->SetGeoTransform(gt);
+protected:
+  MPIVrtWriter();
+  virtual ~MPIVrtWriter();
+  void PrintSelf(std::ostream& os, itk::Indent indent) const override;
 
-      // Set projection
-      OGRSpatialReference out_sr;
-      char *wkt = NULL;
-      out_sr.SetFromUserInput(img->GetProjectionRef().c_str());
-      out_sr.exportToWkt(&wkt);
-      VRTOutput->SetProjection(wkt);
+private:
+  MPIVrtWriter(const MPIVrtWriter &) = delete;
+  void operator =(const MPIVrtWriter&) = delete;
 
-      for(unsigned int band = 1; band<=nbBands;++band)
-      {
-        VRTOutput->AddBand(dataType, NULL);
+  unsigned int m_AvailableRAM;
 
-        typename TImage::RegionType currentRegion;
-        for(unsigned int id=0; id < numberOfSplits; ++id)
-        {
-          currentRegion = streamingManager->GetSplit(id);
-          int tileSizeX = currentRegion.GetSize()[0];
-          int tileSizeY = currentRegion.GetSize()[1];
-          int tileIndexX = currentRegion.GetIndex()[0];
-          int tileIndexY = currentRegion.GetIndex()[1];
-          std::stringstream tileFileName;
-          tileFileName <<prefix<<"_"<<tileIndexX<<"_"<<tileIndexY<<"_"<<tileSizeX<<"_"<<tileSizeY<<".tif";
-          std::cout<<tileFileName.str()<<std::endl;
+  itk::ImageIORegion m_IORegion;
 
-          GDALDataset *dataset = (GDALDataset*) GDALOpen(tileFileName.str().c_str(), GA_ReadOnly);
+  std::string m_Filename;
 
-          VRTSourcedRasterBand *VRTBand = dynamic_cast<VRTSourcedRasterBand*> (VRTOutput->GetRasterBand(band));
-          VRTBand->AddSimpleSource(dataset->GetRasterBand(band),
-                                      0, //xOffSrc
-                                      0, //yOffSrc
-                                      tileSizeX, //xSizeSrc
-                                      tileSizeY, //ySizeSrc
-                                      tileIndexX, //xOffDest
-                                      tileIndexY, //yOffDest
-                                      tileSizeX, //xSizeDest
-                                      tileSizeY, //ySizeDest
-                                      "near",
-                                      VRT_NODATA_UNSET);
-        }
+  bool m_WriteVRT;
 
-      }
-
-      // Close
-      CPLFree(wkt);
-      GDALClose(VRTOutput);
-    }
-  }
-  catch (itk::ExceptionObject& err)
-  {
-    std::stringstream message;
-    message << "ExceptionObject caught: " << err << std::endl;
-    mpiConfig->logError(message.str());
-    mpiConfig->abort(EXIT_FAILURE);
-  }
+};
 
+/**
+ *\brief Write image data to multiple files with MPI processus and add a VRT file.
+ *
+ * The image is divided into several pieces.
+ * Each pieces is distributed to a MPI processus.
+ * Each MPI processus write their pieces into a separate
+ * file.
+ * The master processus writes a VRT file (optional).
+ *
+ *\param img Image
+ *\param output Output Filename
+ *\param availableRAM Available memory for streaming
+ *\param writeVRTFile Activate the VRT file writing
+ */
+template <typename TImage> void WriteMPI(TImage *img, const std::string &output, unsigned int availableRAM = 0, bool writeVRTFile=true)
+{
+  typename MPIVrtWriter<TImage>::Pointer writer = MPIVrtWriter<TImage>::New();
+  writer->SetInput(img);
+  writer->SetFileName(output);
+  writer->SetAvailableRAM(availableRAM);
+  writer->SetWriteVRT(writeVRTFile);
+  writer->Update();
 }
 
 } // End namespace otb
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbMPIVrtWriter.txx"
+#endif
+
 #endif //__otbMPIVrtWriter_h
diff --git a/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.txx b/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.txx
new file mode 100644
index 0000000000000000000000000000000000000000..b57518ed73d613b37e33b86c59ba732ed0e44cc2
--- /dev/null
+++ b/Modules/MPI/MPIVrtWriter/include/otbMPIVrtWriter.txx
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef otbMPIVrtWriter_txx
+#define otbMPIVrtWriter_txx
+
+#include "otbMPIVrtWriter.h"
+#include "otbMacro.h"
+
+namespace otb
+{
+
+template <typename TImage>
+MPIVrtWriter<TImage>::MPIVrtWriter()
+  : m_AvailableRAM(0)
+  , m_IORegion()
+  , m_Filename("")
+  , m_WriteVRT(true)
+{
+}
+
+template <typename TImage>
+MPIVrtWriter<TImage>::~MPIVrtWriter()
+{
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::SetInput(const InputImageType *input)
+{
+  this->ProcessObject::SetNthInput(0,const_cast<InputImageType*>(input));
+}
+
+template <typename TImage>
+const TImage*
+MPIVrtWriter<TImage>::GetInput()
+{
+  if (this->GetNumberOfInputs() < 1)
+    {
+    return 0;
+    }
+  return static_cast<const InputImageType*>(this->ProcessObject::GetInput(0));
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::SetFileName(const char* extendedFileName)
+{
+  if (m_Filename.compare(extendedFileName) != 0 )
+    {
+    m_Filename = std::string(extendedFileName);
+    this->Modified();
+    }
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::SetFileName(std::string extendedFileName)
+{
+  this->SetFileName(extendedFileName.c_str());
+}
+
+template <typename TImage>
+const char*
+MPIVrtWriter<TImage>::GetFileName () const
+{
+  return m_Filename.c_str();
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::SetIORegion(const itk::ImageIORegion& region)
+{
+  if (m_IORegion != region)
+    {
+    m_IORegion = region;
+    this->Modified();
+    }
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+  os << indent << "File Name: "<< m_Filename << std::endl;
+  os << indent << "Available RAM: "<< m_AvailableRAM << std::endl;
+  os << indent << "Write VRT: "<< m_WriteVRT << std::endl;
+}
+
+template <typename TImage>
+void
+MPIVrtWriter<TImage>::Update()
+{
+  typename otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();
+
+  unsigned int myRank = mpiConfig->GetMyRank();
+  unsigned int nbProcs = mpiConfig->GetNbProcs();
+
+  typedef otb::ImageFileWriter<TImage>                                           WriterType;
+  typedef otb::NumberOfDivisionsTiledStreamingManager<TImage>                    StreamingManagerType;
+  typedef itk::RegionOfInterestImageFilter<TImage, TImage>                       ExtractFilterType;
+
+  // First, update infomration from image to write
+  UpdateOutputInformation();
+  InputImageType* img = const_cast<InputImageType*>(GetInput());
+  std::string output = GetFileName();
+
+  // Configure streaming manager
+  typename StreamingManagerType::Pointer streamingManager = StreamingManagerType::New();
+  streamingManager->SetNumberOfDivisions(nbProcs);
+  streamingManager->PrepareStreaming(img,img->GetLargestPossibleRegion());
+  unsigned int numberOfSplits = streamingManager->GetNumberOfSplits();
+
+  // This vector will hold all regions to write for current rank
+  std::vector<typename TImage::RegionType> regionsToWrite;
+
+  // Handle both cases when there are much more (resp. less) region to
+  // write than NbProcs
+  if(myRank < numberOfSplits)
+  {
+    unsigned int splitIdx = myRank;
+    while(splitIdx < numberOfSplits)
+    {
+      typename TImage::RegionType currentRegion = streamingManager->GetSplit(splitIdx);
+      regionsToWrite.push_back(currentRegion);
+      splitIdx+=nbProcs;
+    }
+  }
+
+  // Output prefix
+  std::string extension = itksys::SystemTools::GetFilenameExtension(output);
+  if (extension != ".vrt")
+  {
+
+  // TODO: Maybe remove this
+    if (extension == "")
+	{
+	  // Missing extension
+	  mpiConfig->logInfo("Filename has no extension. Adding <.vrt> extension.");
+	}
+	else
+	{
+	  // Bad extension
+	  mpiConfig->logError("Filename must have .vrt extension!");
+	  mpiConfig->abort(EXIT_FAILURE);
+	}
+  }
+  std::vector<std::string> joins;
+  itksys::SystemTools::SplitPath(output, joins);
+  joins.back() = itksys::SystemTools::GetFilenameWithoutExtension(output);
+  std::string prefix = itksys::SystemTools::JoinPath(joins);
+
+  // Data type
+  std::string dataTypeStr = "Float32";
+  GDALImageIO::Pointer gdalImageIO;
+
+  // Now write all the regions
+  for(typename std::vector<typename TImage::RegionType>::const_iterator it = regionsToWrite.begin();
+      it!=regionsToWrite.end();++it)
+  {
+    typename ExtractFilterType::Pointer extractFilter = ExtractFilterType::New();
+    extractFilter->SetInput(img);
+    extractFilter->SetRegionOfInterest(*it);
+    // Writer
+	  // Output Filename
+    std::stringstream ss;
+    ss<<prefix<<"_"<<it->GetIndex()[0]<<"_"<<it->GetIndex()[1]<<"_"<<it->GetSize()[0]<<"_"<<it->GetSize()[1]<<".tif";
+    typename WriterType::Pointer writer = WriterType::New();
+    writer->SetFileName(ss.str());
+    writer->SetInput(extractFilter->GetOutput());
+    // Datatype
+    gdalImageIO = dynamic_cast<GDALImageIO *>(writer->GetImageIO());
+    if(gdalImageIO.IsNotNull())
+    {
+      dataTypeStr = gdalImageIO->GetGdalPixelTypeAsString();
+    }
+
+    if (!m_AvailableRAM)
+      {
+      writer->SetNumberOfDivisionsTiledStreaming(0);
+      }
+    else
+      {
+      writer->SetAutomaticAdaptativeStreaming(m_AvailableRAM);
+      }
+
+    // Pipeline execution
+    try
+    {
+      writer->Update();
+    }
+    catch (itk::ExceptionObject& err)
+    {
+      std::stringstream message;
+      message << "ExceptionObject caught: " << err << std::endl;
+      mpiConfig->logError(message.str());
+      mpiConfig->abort(EXIT_FAILURE);
+    }
+  }
+
+  // MPI process synchronization
+  mpiConfig->barrier();
+
+  // Write VRT file
+  try
+  {
+    if (m_WriteVRT && (myRank == 0))
+    {
+      // VRT Filename
+      std::stringstream vrtfOut;
+      vrtfOut<< prefix << ".vrt";
+
+      // Data type
+      GDALDataType dataType;
+      dataType = GDALGetDataTypeByName(dataTypeStr.c_str());
+
+      int imageSizeY = img->GetLargestPossibleRegion().GetSize()[1];
+      int imageSizeX = img->GetLargestPossibleRegion().GetSize()[0];
+      const unsigned int nbBands = img->GetNumberOfComponentsPerPixel();
+
+      // Get VRT driver
+      GDALAllRegister();
+      GDALDriver *driver = GetGDALDriverManager()->GetDriverByName("VRT");
+      if (driver == NULL) {
+         mpiConfig->logError("Error opening VRT driver.");
+         mpiConfig->abort(EXIT_FAILURE);
+      }
+
+      // Create output raster
+      GDALDataset *VRTOutput = driver->Create(vrtfOut.str().c_str(),
+            imageSizeX,
+            imageSizeY,
+            0,
+            dataType,
+            NULL); // No options
+      if (VRTOutput == NULL) {
+        mpiConfig->logError("driver->Create call failed.\n");
+        mpiConfig->abort(EXIT_FAILURE);
+      }
+
+      // Set GeoTransform
+      double gt[6];
+      gt[0] = img->GetOrigin()[0] - 0.5*img->GetSignedSpacing()[0];
+      gt[1] = img->GetSignedSpacing()[0];
+      gt[2] = 0.0;
+      gt[3] = img->GetOrigin()[1] - 0.5*img->GetSignedSpacing()[1];
+      gt[4] = 0.0;
+      gt[5] = img->GetSignedSpacing()[1];
+      VRTOutput->SetGeoTransform(gt);
+
+      // Set projection
+      OGRSpatialReference out_sr;
+      char *wkt = NULL;
+      out_sr.SetFromUserInput(img->GetProjectionRef().c_str());
+      out_sr.exportToWkt(&wkt);
+      VRTOutput->SetProjection(wkt);
+
+      for(unsigned int band = 1; band<=nbBands;++band)
+      {
+        VRTOutput->AddBand(dataType, NULL);
+
+        typename TImage::RegionType currentRegion;
+        for(unsigned int id=0; id < numberOfSplits; ++id)
+        {
+          currentRegion = streamingManager->GetSplit(id);
+          int tileSizeX = currentRegion.GetSize()[0];
+          int tileSizeY = currentRegion.GetSize()[1];
+          int tileIndexX = currentRegion.GetIndex()[0];
+          int tileIndexY = currentRegion.GetIndex()[1];
+          std::stringstream tileFileName;
+          tileFileName <<prefix<<"_"<<tileIndexX<<"_"<<tileIndexY<<"_"<<tileSizeX<<"_"<<tileSizeY<<".tif";
+          otbDebugMacro(<<tileFileName.str());
+
+          GDALDataset *dataset = (GDALDataset*) GDALOpen(tileFileName.str().c_str(), GA_ReadOnly);
+
+          VRTSourcedRasterBand *VRTBand = dynamic_cast<VRTSourcedRasterBand*> (VRTOutput->GetRasterBand(band));
+          VRTBand->AddSimpleSource(dataset->GetRasterBand(band),
+                                      0, //xOffSrc
+                                      0, //yOffSrc
+                                      tileSizeX, //xSizeSrc
+                                      tileSizeY, //ySizeSrc
+                                      tileIndexX, //xOffDest
+                                      tileIndexY, //yOffDest
+                                      tileSizeX, //xSizeDest
+                                      tileSizeY, //ySizeDest
+                                      "near",
+                                      VRT_NODATA_UNSET);
+        }
+
+      }
+
+      // Close
+      CPLFree(wkt);
+      GDALClose(VRTOutput);
+    }
+  }
+  catch (itk::ExceptionObject& err)
+  {
+    std::stringstream message;
+    message << "ExceptionObject caught: " << err << std::endl;
+    mpiConfig->logError(message.str());
+    mpiConfig->abort(EXIT_FAILURE);
+  }
+}
+
+
+} // end of namespace otb
+
+#endif
diff --git a/Modules/MPI/MPIVrtWriter/otb-module.cmake b/Modules/MPI/MPIVrtWriter/otb-module.cmake
index 0e95d97f7cbe02b27ba37be548a0106b3d70ea9e..f98ab957d207a9bf02f6f13c27002ad054582897 100644
--- a/Modules/MPI/MPIVrtWriter/otb-module.cmake
+++ b/Modules/MPI/MPIVrtWriter/otb-module.cmake
@@ -22,8 +22,9 @@ set(DOCUMENTATION "Provides a template function for MPI writing to a VRT file")
 
 otb_module(OTBMPIVrtWriter
   DEPENDS
-  OTBMPIConfig
-    OTBPanSharpening
+    OTBCommon
+    OTBMPIConfig
+#    OTBPanSharpening
     OTBProjection
     OTBInterpolation
     OTBTestKernel
diff --git a/Modules/Visualization/Monteverdi/src/mvdMainWindow.cxx b/Modules/Visualization/Monteverdi/src/mvdMainWindow.cxx
index 6b1d92cf582d251cb2a3c6a7936f8842d73ee0a4..9420452e321f19bb13b9ba6521c5b79ae9415280 100644
--- a/Modules/Visualization/Monteverdi/src/mvdMainWindow.cxx
+++ b/Modules/Visualization/Monteverdi/src/mvdMainWindow.cxx
@@ -1431,11 +1431,11 @@ MainWindow
 
       if( !( *it )->IsClosable() )
 	{
-	assert( !( *it )->GetApplication().IsNull() );
+	assert( ( *it )->GetModel()->GetApplication() );
 
 	// qDebug() << "OTB-application:" << ( *it )->GetApplication()->GetDocName();
 
-	names.push_back( ( *it )->GetApplication()->GetDocName() );
+	names.push_back( ( *it )->GetModel()->GetApplication()->GetDocName() );
 	}
       }
 
diff --git a/Modules/Visualization/MonteverdiGui/include/mvdQtWidgetView.h b/Modules/Visualization/MonteverdiGui/include/mvdQtWidgetView.h
index c55664e2dcbf8871e6510a930f564b1372afd8e9..08ead75886afef2b4b57f26e5359f1df37895dda 100644
--- a/Modules/Visualization/MonteverdiGui/include/mvdQtWidgetView.h
+++ b/Modules/Visualization/MonteverdiGui/include/mvdQtWidgetView.h
@@ -37,16 +37,10 @@
 #include <QtGui>
 #include <QShortcut>
 
-//
-// System includes (sorted by alphabetic order)
-
-//
-// ITK includes (sorted by alphabetic order)
-
 //
 // OTB includes (sorted by alphabetic order)
 #ifndef Q_MOC_RUN  // See: https://bugreports.qt-project.org/browse/QTBUG-22829  //tag=QT4-boost-compatibility
-#include "otbWrapperApplication.h"
+#include "otbWrapperQtWidgetView.h"
 #include "otbWrapperQtWidgetModel.h"
 #endif //tag=QT4-boost-compatibility
 #include "OTBMonteverdiGUIExport.h"
@@ -57,18 +51,8 @@
 #include "mvdTypes.h"
 #endif //tag=QT4-boost-compatibility
 
-/*****************************************************************************/
-/* PRE-DECLARATION SECTION                                                   */
-
-//
-// External classes pre-declaration.
-namespace
-{
-}
-
 namespace mvd
 {
-
 namespace Wrapper
 {
 
@@ -84,16 +68,12 @@ namespace Wrapper
  */
 
 class OTBMonteverdiGUI_EXPORT QtWidgetView :
-    public QWidget
+    public otb::Wrapper::QtWidgetView
 {
   /*-[ QOBJECT SECTION ]-----------------------------------------------------*/
 
   Q_OBJECT
 
-  Q_PROPERTY( bool isClosable
-	      READ IsClosable
-	      WRITE SetClosable );
-
   /*-[ PUBLIC SECTION ]------------------------------------------------------*/
 
 //
@@ -112,29 +92,6 @@ public:
   /** \brief Destructor. */
   ~QtWidgetView() override;
 
-  /** \brief Gui Creation. */
-  void CreateGui();
-
-  /** \brief Model Accessor */
-  inline otb::Wrapper::QtWidgetModel* GetModel()
-  {
-    return m_Model;
-  }
-
-  /**
-   * \return The OTB-application pointer of this view.
-   */
-  otb::Wrapper::Application::ConstPointer GetApplication() const
-  {
-    return otb::ConstCast< otb::Wrapper::Application >(
-      m_Application
-    );
-  }
-
-  /**
-   */
-  inline bool IsClosable() const;
-
   /*-[ PUBLIC SLOTS SECTION ]------------------------------------------------*/
 
 //
@@ -146,12 +103,9 @@ public slots:
 //
 // Signals.
 signals:
-  void QuitSignal();
 
   void OTBApplicationOutputImageChanged( const QString &, const QString &);
 
-  void ExecuteAndWriteOutput();
-
   void ExecutionDone( int nbOutputs );
 
   /*-[ PROTECTED SECTION ]---------------------------------------------------*/
@@ -160,14 +114,16 @@ signals:
 // Protected methods.
 protected:
 
-  //
-  // QWidget overloads.
+  QWidget* CreateInputWidgets() override;
 
-  void closeEvent( QCloseEvent * event ) override;
+protected slots:
 
-//
-// Protected attributes.
-protected:
+  /** extend the behaviour of base class OnExecButtonClicked */
+  void OnExecButtonClicked();
+
+  /** modify the behaviour of base class OnExceptionRaised
+   */
+  void OnExceptionRaised( QString what );
 
   /*-[ PRIVATE SECTION ]-----------------------------------------------------*/
 
@@ -178,12 +134,6 @@ private:
   QtWidgetView(const QtWidgetView&); //purposely not implemented
   void operator=(const QtWidgetView&); //purposely not implemented
 
-  QWidget* CreateFooter();
-
-  QWidget* CreateInputWidgets();
-
-  QWidget* CreateDoc();
-
   /**
    */
   void SetupParameterWidgets( QWidget* widget );
@@ -192,21 +142,6 @@ private:
    */
   void SetupFileSelectionWidget( QWidget * );
 
-//
-// Private attributes.
-
-private:
-
-  otb::Wrapper::Application::Pointer m_Application;
-  otb::Wrapper::QtWidgetModel* m_Model;
-
-  QPushButton* m_ExecButton;
-  QPushButton* m_QuitButton;
-  QShortcut* m_QuitShortcut;
-  QLabel* m_Message;
-
-  bool m_IsClosable : 1;
-
   /*-[ PRIVATE SLOTS SECTION ]-----------------------------------------------*/
 
 //
@@ -218,30 +153,6 @@ private slots:
   // image filename{s} set by the user in this OTB application (if any).
   void OnApplicationExecutionDone( int );
 
-  void UpdateMessageAfterApplicationReady(bool val);
-
-  void UpdateMessageAfterExecution(int status);
-
-  /**
-   */
-  void OnExecButtonClicked();
-
-  /**
-   */
-  inline void OnProgressReportBegin();
-
-  /**
-   */
-  inline void OnProgressReportEnd( int status );
-
-  /**
-   */
-  void OnExceptionRaised( QString what );
-
-  /**
-   */
-  inline void SetClosable( bool );
-
   /**
    */
   inline void OnFileSelectionWidgetAdded0( QWidget * );
@@ -264,47 +175,6 @@ namespace mvd
 namespace Wrapper
 {
 
-/*****************************************************************************/
-inline
-bool
-QtWidgetView
-::IsClosable() const
-{
-  return m_IsClosable;
-}
-
-/*****************************************************************************/
-inline
-void
-QtWidgetView
-::SetClosable( bool enabled )
-{
-  m_IsClosable = enabled;
-
-  setEnabled( true );
-
-  if( m_QuitButton!=NULL )
-    m_QuitButton->setEnabled( m_IsClosable );
-}
-
-/*******************************************************************************/
-inline
-void
-QtWidgetView
-::OnProgressReportBegin()
-{
-  SetClosable( false );
-}
-
-/*******************************************************************************/
-inline
-void
-QtWidgetView
-::OnProgressReportEnd( int )
-{
-  SetClosable( true );
-}
-
 /*******************************************************************************/
 inline
 void
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdApplicationLauncher.cxx b/Modules/Visualization/MonteverdiGui/src/mvdApplicationLauncher.cxx
index 7d571ff73bccdfba11819ccd01eafeb6e258439d..b3a28a432f839bb8e67921f440449a9ff9bee71e 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdApplicationLauncher.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdApplicationLauncher.cxx
@@ -217,13 +217,13 @@ ApplicationLauncher
     ApplicationLauncher::NewOtbApplicationWidget( appName, isStandalone );
 
   assert( appWidget!=NULL );
-  assert( appWidget->GetApplication() );
+  assert( appWidget->GetModel()->GetApplication() );
 
   QMainWindow * mainWindow = new QMainWindow( p, flags );
 
   mainWindow->setWindowTitle(
     QString( "%1 (OTB-" OTB_VERSION_STRING ")" )
-    .arg( appWidget->GetApplication()->GetDocName() )
+    .arg( appWidget->GetModel()->GetApplication()->GetDocName() )
   );
 
   mainWindow->setWindowIcon( QIcon( ":/otb_small.png" ) );
@@ -251,11 +251,11 @@ ApplicationLauncher
     );
 
   assert( appWidget!=NULL );
-  assert( appWidget->GetApplication() );
+  assert( appWidget->GetModel()->GetApplication() );
 
   appWidget->setWindowTitle(
     QString( "%1 (OTB-" OTB_VERSION_STRING ")" )
-    .arg( appWidget->GetApplication()->GetDocName() )
+    .arg( appWidget->GetModel()->GetApplication()->GetDocName() )
   );
 
   appWidget->setWindowIcon( QIcon( ":/icons/process" ) );
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdQtWidgetView.cxx b/Modules/Visualization/MonteverdiGui/src/mvdQtWidgetView.cxx
index 3c33015a5bde59b586340e7fc5155ed3166c4c84..252c6043797f53d43bfa40cbf5c8dde1abc3421c 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdQtWidgetView.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdQtWidgetView.cxx
@@ -23,28 +23,16 @@
 /*****************************************************************************/
 /* INCLUDE SECTION                                                           */
 
-//
-// Qt includes (sorted by alphabetic order)
-//// Must be included before system/custom includes.
-
 //
 // System includes (sorted by alphabetic order)
 #include <functional>
 
-//
-// ITK includes (sorted by alphabetic order)
-
 //
 // OTB includes (sorted by alphabetic order)
 #include "otbWrapperApplicationHtmlDocGenerator.h"
-// #include "otbWrapperComplexOutputImageParameter.h"
 #include "otbWrapperOutputFilenameParameter.h"
-// #include "otbWrapperOutputImageParameter.h"
 #include "otbWrapperOutputVectorDataParameter.h"
-// #include "otbWrapperQtWidgetOutputImageParameter.h"
-// #include "otbWrapperQtWidgetProgressReport.h"
 #include "otbWrapperQtWidgetSimpleProgressReport.h"
-// #include "otbWrapperTypes.h"
 
 //
 // Monteverdi includes (sorted by alphabetic order)
@@ -140,208 +128,43 @@ QtWidgetView
 ::QtWidgetView( const otb::Wrapper::Application::Pointer & otbApp,
 		QWidget* p,
 		Qt::WindowFlags flags ) :
-  QWidget( p, flags ),
-  m_Application( otbApp ),
-  m_Model( NULL ),
-  m_ExecButton( NULL ),
-  m_QuitButton( NULL ),
-  m_Message( NULL ),
-  m_IsClosable( true )
+  otb::Wrapper::QtWidgetView( otbApp, p, flags )
 {
   setObjectName( QtWidgetView::OBJECT_NAME );
 
-  m_Model = new otb::Wrapper::QtWidgetModel( otbApp );
-  m_QuitShortcut = new QShortcut(QKeySequence("Ctrl+Q"), this);
-
-  QObject::connect(
-    m_Model, SIGNAL( SetProgressReportBegin() ),
-    this, SLOT( OnProgressReportBegin() )
-  );
-
-  QObject::connect(
-    m_Model, SIGNAL( SetProgressReportDone( int ) ),
-    this, SLOT( OnProgressReportEnd( int ) )
-  );
-
-  QObject::connect(
-    m_Model, SIGNAL( ExceptionRaised( QString ) ),
-    this, SLOT( OnExceptionRaised( QString ) )
-  );
-}
-
-/*******************************************************************************/
-QtWidgetView
-::~QtWidgetView()
-{
-  // m_Application is smart-pointed and will be automatically deleted.
-
-  delete m_Model;
-  m_Model = NULL;
-}
-
-/*******************************************************************************/
-void
-QtWidgetView
-::CreateGui()
-{
-  // Create a VBoxLayout with the header, the input widgets, and the footer
-  QVBoxLayout *mainLayout = new QVBoxLayout();
-  QTabWidget *tab = new QTabWidget();
-  tab->addTab(CreateInputWidgets(), tr("Parameters"));
-
-  //otb::Wrapper::QtWidgetProgressReport* prog =  new otb::Wrapper::QtWidgetProgressReport(m_Model);
-  //prog->SetApplication(m_Application);
-  //tab->addTab(prog, "Progress");
-  tab->addTab(CreateDoc(), tr("Documentation"));
-  mainLayout->addWidget(tab);
-
-  QTextEdit *log = new QTextEdit();
-  connect( m_Model->GetLogOutput(), SIGNAL(NewContentLog(QString)), log, SLOT(append(QString) ) );
-  tab->addTab(log, tr("Logs"));
-
-  m_Message = new QLabel("<center><font color=\"#FF0000\">"+tr("Select parameters")+"</font></center>");
-  connect(
-    m_Model,
-    SIGNAL( SetApplicationReady( bool ) ),
-    this, SLOT( UpdateMessageAfterApplicationReady( bool ) )
-  );
-  connect(
-    m_Model,
-    SIGNAL(SetProgressReportDone(int)),
-    this, SLOT(UpdateMessageAfterExecution(int)) );
-  mainLayout->addWidget(m_Message);
-
-  otb::Wrapper::QtWidgetSimpleProgressReport* progressReport =
-    new otb::Wrapper::QtWidgetSimpleProgressReport(m_Model);
-  progressReport->SetApplication(m_Application);
-
-  QWidget* footer = CreateFooter();
-   
-  QHBoxLayout *footLayout = new QHBoxLayout;
-  footLayout->addWidget(progressReport);
-  footLayout->addWidget(footer);
-  mainLayout->addLayout(footLayout);
-
-  footLayout->setAlignment(footer, Qt::AlignBottom);
-
-  QGroupBox *mainGroup = new QGroupBox();
-  mainGroup->setLayout(mainLayout);
-
-  QVBoxLayout  *finalLayout = new QVBoxLayout();
-  finalLayout->addWidget(mainGroup);
-
-  // Make the final layout to the widget
-  this->setLayout(finalLayout);
-}
-
-/*******************************************************************************/
-QWidget*
-QtWidgetView
-::CreateInputWidgets()
-{
-  QScrollArea *scrollArea = new QScrollArea;
-
-  QWidget * widget = 
-    otb::Wrapper::QtWidgetParameterFactory::CreateQtWidget(
-      m_Model->GetApplication()->GetParameterList(),
-      m_Model
-    );
-
-  scrollArea->setWidget( widget );
-  scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
-  scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
-  scrollArea->setWidgetResizable(true);
+  m_IconPathDone = std::string("<img src=\":/icons/done\" width=\"16\" height=\"16\" />");
+  m_IconPathFailed = std::string("<img src=\":/icons/failed\" width=\"16\" height=\"16\" />");
 
   //
   // need to be connected to the end of a process
   QObject::connect(
-    m_Model,
+    GetModel(),
     SIGNAL( SetProgressReportDone( int ) ),
     // to:
     this,
     SLOT ( OnApplicationExecutionDone( int ) )
     );
-
-  SetupParameterWidgets( widget );
-
-  return scrollArea;
 }
 
 /*******************************************************************************/
-QWidget*
 QtWidgetView
-::CreateFooter()
+::~QtWidgetView()
 {
-  // an HLayout with two buttons : Execute and Quit
-  QGroupBox *footerGroup = new QGroupBox;
-  QHBoxLayout *footerLayout = new QHBoxLayout;
- 
-  footerGroup->setFixedHeight(40);
-  footerGroup->setContentsMargins(0, 0, 0, 0);
-  footerLayout->setContentsMargins(5, 5, 5, 5);
-
-  m_ExecButton = new QPushButton(footerGroup);
-  m_ExecButton->setDefault(true);
-  m_ExecButton->setEnabled(false);
-  m_ExecButton->setText(QObject::tr("Execute"));
-  connect(
-    m_Model, SIGNAL( SetApplicationReady( bool ) ),
-    m_ExecButton, SLOT( setEnabled( bool ) )
-  );
-
-  QObject::connect(
-    m_ExecButton, SIGNAL( clicked() ),
-    // to:
-    this, SLOT( OnExecButtonClicked() )
-  );
-  QObject::connect(
-    this, SIGNAL( ExecuteAndWriteOutput() ),
-    // to:
-    m_Model, SLOT( ExecuteAndWriteOutputSlot() )
-  );
-
-  m_QuitButton = new QPushButton(footerGroup);
-  m_QuitButton->setText(QObject::tr("Quit"));
-  connect(
-    m_QuitButton,
-    SIGNAL( clicked() ),
-    // to:
-    this,
-    SLOT( close() )
-  );
-
-  // Add Ctrl-Q shortcut to quit
-  connect( m_QuitShortcut, SIGNAL(activated()), this, SLOT(close()) );
-
-
-  // Put the buttons on the right
-  footerLayout->addStretch();
-  footerLayout->addWidget(m_ExecButton);
-  footerLayout->addWidget(m_QuitButton);
-
-  footerGroup->setLayout(footerLayout);
-
-  return footerGroup;
 }
 
 /*******************************************************************************/
 QWidget*
 QtWidgetView
-::CreateDoc()
+::CreateInputWidgets()
 {
-  QTextEdit *text = new QTextEdit;
-  text->setReadOnly(true);
-
-  QTextDocument * doc = new QTextDocument();
+  QWidget * widget = otb::Wrapper::QtWidgetView::CreateInputWidgets();
 
-  std::string docContain;
-  otb::Wrapper::ApplicationHtmlDocGenerator::GenerateDoc( m_Application, docContain);
+  otb::Wrapper::QtWidgetParameterBase *paramWidget =
+    widget->findChild<otb::Wrapper::QtWidgetParameterBase*>();
 
-  doc->setHtml(docContain.c_str());
+  SetupParameterWidgets(paramWidget);
 
-  text->setDocument(doc);
-
-  return text;
+  return widget;
 }
 
 /*******************************************************************************/
@@ -369,11 +192,11 @@ QtWidgetView
 
   SetupWidget(
     widget,
-    OutputImageInitializer( m_Application->GetName() )
+    OutputImageInitializer( GetModel()->GetApplication()->GetName() )
   );
   SetupWidget(
     widget,
-    ComplexOutputImageInitializer( m_Application->GetName() )
+    ComplexOutputImageInitializer( GetModel()->GetApplication()->GetName() )
   );
 
   SetupWidget( widget, OutputVectorDataInitializer() );
@@ -394,36 +217,6 @@ QtWidgetView
   initialize( qobject_cast< FileSelectionInitializer::argument_type >( widget ) );
 }
 
-/*******************************************************************************/
-void
-QtWidgetView
-::closeEvent( QCloseEvent * e )
-{
-  assert( e!=NULL );
-
-  if( !IsClosable() )
-    {
-    assert( !m_Application.IsNull() );
-
-    QMessageBox::warning(
-      this,
-      tr( "Warning!" ),
-      tr( "OTB-Application '%1' cannot be closed while running!")
-      .arg( m_Application->GetDocName() )
-    );
-
-    e->ignore();
-
-    return;
-    }
-
-  QWidget::closeEvent( e );
-
-  emit QuitSignal();
-
-  deleteLater();
-}
-
 /*******************************************************************************/
 /* SLOTS                                                                       */
 /*******************************************************************************/
@@ -431,226 +224,180 @@ void
 QtWidgetView
 ::OnExecButtonClicked()
 {
-  assert( m_Model!=NULL );
-  assert( m_Model->GetApplication()!=NULL );
-
-
-  assert( I18nCoreApplication::Instance()!=NULL );
-
-  //
-  // Get layer-stack, if any.
-  StackedLayerModel * layerStack =
-    I18nCoreApplication::Instance()->GetModel< StackedLayerModel >();
-
-  otb::Wrapper::Application::Pointer otbApp( m_Model->GetApplication() );
-
-  //
-  // Check output parameters of OTB-application.
-  StringVector paramKeys( otbApp->GetParametersKeys() );
-  QStringList filenames1;
-
-  KeyLayerAccumulator::KeyLayerPairList layers;
-  QStringList filenames2;
-
-  for( StringVector::const_iterator it( paramKeys.begin() );
-       it!=paramKeys.end();
-       ++it )
+  if ( !IsRunning() )
     {
-    if( otbApp->IsParameterEnabled( *it, true ) &&
-        otbApp->HasValue( *it ) )
+    assert( GetModel()!=NULL );
+    assert( GetModel()->GetApplication()!=NULL );
+  
+  
+    assert( I18nCoreApplication::Instance()!=NULL );
+  
+    //
+    // Get layer-stack, if any.
+    StackedLayerModel * layerStack =
+      I18nCoreApplication::Instance()->GetModel< StackedLayerModel >();
+  
+    otb::Wrapper::Application::Pointer otbApp( GetModel()->GetApplication() );
+  
+    //
+    // Check output parameters of OTB-application.
+    StringVector paramKeys( otbApp->GetParametersKeys() );
+    QStringList filenames1;
+  
+    KeyLayerAccumulator::KeyLayerPairList layers;
+    QStringList filenames2;
+  
+    for( StringVector::const_iterator it( paramKeys.begin() );
+         it!=paramKeys.end();
+         ++it )
       {
-      otb::Wrapper::Parameter::Pointer param( otbApp->GetParameterByKey( *it ) );
-      assert( !param.IsNull() );
-
-      // qDebug()
-      // 	<< it->c_str() << ": type" << otbApp->GetParameterType( *it );
-
-      // const char* filename = NULL;
-      std::string filename;
-
-      switch( otbApp->GetParameterType( *it ) )
-	{
-	case otb::Wrapper::ParameterType_OutputFilename:
-	  filename =
-	    otb::DynamicCast< otb::Wrapper::OutputFilenameParameter >( param )
-	    ->GetValue();
-	  break;
-	//
-	// FILENAME.
-	//
-	// IMAGE.
-	case otb::Wrapper::ParameterType_OutputImage:
-	  filename =
-	    otb::DynamicCast< otb::Wrapper::OutputImageParameter >( param )
-	    ->GetFileName();
-	  break;
-	//
-	// VECTOR-DATA.
-	case otb::Wrapper::ParameterType_OutputVectorData:
-	  filename =
-	    otb::DynamicCast< otb::Wrapper::OutputVectorDataParameter >( param )
-	    ->GetFileName();
-	  break;
-	//
-	// COMPLEX IMAGE.
-	case otb::Wrapper::ParameterType_ComplexOutputImage:
-	  filename =
-	    otb::DynamicCast< otb::Wrapper::ComplexOutputImageParameter >( param )
-	    ->GetFileName();
-	  break;
-	//
-	// NONE.
-	default:
-	  break;
-	}
-
-      if( QFileInfo( filename.c_str() ).exists() )
-	filenames1.push_back( filename.c_str() );
-
-      if( layerStack!=NULL )
-	{
-	KeyLayerAccumulator accumulator(
-	  std::for_each(
-	    layerStack->Begin(),
-	    layerStack->End(), KeyLayerAccumulator( filename, layers )
-	  )
-	);
-
-	if( accumulator.GetCount()>0 )
-	  filenames2.push_back( filename.c_str() );
-	}
-      }
-    }
-
-  {
-  QString message;
-
-  if( filenames1.size()==1 )
-    {
-    // qDebug()
-    //   << it->c_str() << ":" << QString( filename.c_str() );
-
-    message =
-      tr( "Are you sure you want to overwrite file '%1'?" )
-      .arg( filenames1.front() );
-    }
-  else if( filenames1.size()>1 )
-    {
-    message =
-      tr( "Following files will be overwritten. Are you sure you want to continue?\n- %1" )
-      .arg( filenames1.join( "\n- " ) );
-    }
-
-  if( !message.isEmpty() )
+      if( otbApp->IsParameterEnabled( *it, true ) &&
+          otbApp->HasValue( *it ) )
+        {
+        otb::Wrapper::Parameter::Pointer param( otbApp->GetParameterByKey( *it ) );
+        assert( !param.IsNull() );
+  
+        // qDebug()
+        // 	<< it->c_str() << ": type" << otbApp->GetParameterType( *it );
+  
+        // const char* filename = NULL;
+        std::string filename;
+  
+        switch( otbApp->GetParameterType( *it ) )
     {
-    QMessageBox::StandardButton button =
-      QMessageBox::question(
-	this,
-	PROJECT_NAME,
-	message,
-	QMessageBox::Yes | QMessageBox::No,
-	QMessageBox::No
-      );
-
-    if( button==QMessageBox::No )
-      return;
+    case otb::Wrapper::ParameterType_OutputFilename:
+      filename =
+        otb::DynamicCast< otb::Wrapper::OutputFilenameParameter >( param )
+        ->GetValue();
+      break;
+    //
+    // FILENAME.
+    //
+    // IMAGE.
+    case otb::Wrapper::ParameterType_OutputImage:
+      filename =
+        otb::DynamicCast< otb::Wrapper::OutputImageParameter >( param )
+        ->GetFileName();
+      break;
+    //
+    // VECTOR-DATA.
+    case otb::Wrapper::ParameterType_OutputVectorData:
+      filename =
+        otb::DynamicCast< otb::Wrapper::OutputVectorDataParameter >( param )
+        ->GetFileName();
+      break;
+    //
+    // COMPLEX IMAGE.
+    case otb::Wrapper::ParameterType_ComplexOutputImage:
+      filename =
+        otb::DynamicCast< otb::Wrapper::ComplexOutputImageParameter >( param )
+        ->GetFileName();
+      break;
+    //
+    // NONE.
+    default:
+      break;
     }
-  }
-
-  {
-  QString message;
-
-  if( filenames2.size()==1 )
+  
+        if( QFileInfo( filename.c_str() ).exists() )
+    filenames1.push_back( filename.c_str() );
+  
+        if( layerStack!=NULL )
     {
-    // qDebug()
-    //   << it->c_str() << ":" << QString( filename.c_str() );
-
-    message =
-      tr( "File '%1' is being viewed in " PROJECT_NAME " and will be concurrently overwritten by running this %2. File will be removed from layer-stack before running %2 and reloaded after.\n\nDo you want to continue?" )
-      .arg( filenames2.front() )
-      .arg( otbApp->GetDocName() );
+    KeyLayerAccumulator accumulator(
+      std::for_each(
+        layerStack->Begin(),
+        layerStack->End(), KeyLayerAccumulator( filename, layers )
+      )
+    );
+  
+    if( accumulator.GetCount()>0 )
+      filenames2.push_back( filename.c_str() );
     }
-  else if( filenames2.size()>1 )
+        }
+      }
+  
     {
-    message =
-      tr( "Following files are being viewed in " PROJECT_NAME " and will be concurrently overwritter by running %2. Files will be removed from layer-stack before running %2. Do you want to continue?\n- %1" )
-      .arg( filenames2.join( "\n- " ) )
-      .arg( otbApp->GetDocName() );
+    QString message;
+  
+    if( filenames1.size()==1 )
+      {
+      // qDebug()
+      //   << it->c_str() << ":" << QString( filename.c_str() );
+  
+      message =
+        tr( "Are you sure you want to overwrite file '%1'?" )
+        .arg( filenames1.front() );
+      }
+    else if( filenames1.size()>1 )
+      {
+      message =
+        tr( "Following files will be overwritten. Are you sure you want to continue?\n- %1" )
+        .arg( filenames1.join( "\n- " ) );
+      }
+  
+    if( !message.isEmpty() )
+      {
+      QMessageBox::StandardButton button =
+        QMessageBox::question(
+    this,
+    PROJECT_NAME,
+    message,
+    QMessageBox::Yes | QMessageBox::No,
+    QMessageBox::No
+        );
+  
+      if( button==QMessageBox::No )
+        return;
+      }
     }
-
-  if( !message.isEmpty() )
+  
     {
-    QMessageBox::StandardButton button =
-      QMessageBox::question(
-	this,
-	PROJECT_NAME,
-	message,
-	QMessageBox::Yes | QMessageBox::No,
-	QMessageBox::No
-      );
-
-    if( button==QMessageBox::No )
-      return;
-
-    while( !layers.empty() )
+    QString message;
+  
+    if( filenames2.size()==1 )
       {
-      layerStack->Delete( layers.front().first );
-
-      layers.pop_front();
+      // qDebug()
+      //   << it->c_str() << ":" << QString( filename.c_str() );
+  
+      message =
+        tr( "File '%1' is being viewed in " PROJECT_NAME " and will be concurrently overwritten by running this %2. File will be removed from layer-stack before running %2 and reloaded after.\n\nDo you want to continue?" )
+        .arg( filenames2.front() )
+        .arg( otbApp->GetDocName() );
+      }
+    else if( filenames2.size()>1 )
+      {
+      message =
+        tr( "Following files are being viewed in " PROJECT_NAME " and will be concurrently overwritter by running %2. Files will be removed from layer-stack before running %2. Do you want to continue?\n- %1" )
+        .arg( filenames2.join( "\n- " ) )
+        .arg( otbApp->GetDocName() );
+      }
+  
+    if( !message.isEmpty() )
+      {
+      QMessageBox::StandardButton button =
+        QMessageBox::question(
+    this,
+    PROJECT_NAME,
+    message,
+    QMessageBox::Yes | QMessageBox::No,
+    QMessageBox::No
+        );
+  
+      if( button==QMessageBox::No )
+        return;
+  
+      while( !layers.empty() )
+        {
+        layerStack->Delete( layers.front().first );
+  
+        layers.pop_front();
+        }
       }
     }
   }
 
-
-  /* U N S A F E
-  // BUGFIX: Mantis-750
-  //
-  // Remove files which will be overwritten in order to use
-  // file-existence to check whether to emit the OutputImageChanged
-  // signal (see ::OnApplicationExecutionDone()).
-  for( FileInfoVector::const_iterator it( fileInfos.begin() );
-       it!=fileInfos.end();
-       ++it )
-    {
-    qDebug() << "Removing:" << it->filePath();
-
-    it->dir().remove( it->fileName() );
-    }
-  */
-
-  emit ExecuteAndWriteOutput();
-
-  m_Message->setText("<center><font color=\"#FF0000\">"+tr("Running")+"</font></center>");
-}
-
-/******************************************************************************/
-void
-QtWidgetView
-::UpdateMessageAfterExecution(int status)
-{
-  if (status >= 0)
-    {
-    m_Message->setText("<center>"
-      "<img src=\":/icons/done\" width=\"16\" height=\"16\" />"
-      "<font color=\"#00A000\">"+tr("Done")+"</font></center>");
-    }
-  else
-    {
-    m_Message->setText("<center>"
-      "<img src=\":/icons/failed\" width=\"16\" height=\"16\" />"
-      "<font color=\"#FF0000\">"+tr("Failed")+"</font></center>");
-    }
-}
-
-/*******************************************************************************/
-void
-QtWidgetView
-::UpdateMessageAfterApplicationReady( bool val )
-{
-  if(val == true)
-    m_Message->setText("<center><font color=\"#00A000\">"+tr("Ready to run")+"</font></center>");
-  else
-    m_Message->setText("<center><font color=\"#FF0000\">"+tr("Select parameters")+"</font></center>");
+  otb::Wrapper::QtWidgetView::OnExecButtonClicked();
 }
 
 /*******************************************************************************/
@@ -675,7 +422,7 @@ void
 QtWidgetView
 ::OnApplicationExecutionDone( int status )
 {
-  otb::Wrapper::Application::Pointer otbApp( m_Model->GetApplication() );
+  otb::Wrapper::Application::Pointer otbApp( GetModel()->GetApplication() );
 
   if( status!=0 )
     {
@@ -765,6 +512,5 @@ QtWidgetView
   emit ExecutionDone( status );
 }
 
-}
-
-}
+} // end of namespace Wrapper
+} // end of namespace mvd
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
index f840418c3cf41522683483cebe35446206104ddb..4748ab0c5ddc71a9a1ffff72b8ba89585d86bc8d 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
@@ -22,6 +22,7 @@
 #define otbWrapperApplication_h
 
 #include <string>
+#include <set>
 #include "otbWrapperTypes.h"
 #include "otbWrapperTags.h"
 #include "otbWrapperParameterGroup.h"
@@ -154,6 +155,9 @@ public:
    */
   int ExecuteAndWriteOutput();
 
+  /** Request the application to stop its processing */
+  void Stop();
+
   /* Get the internal application parameters
    *
    * WARNING: this method may disappear from the API */
@@ -914,6 +918,27 @@ public:
    */
   void SetParameterImageBase(const std::string & key, ImageBaseType* img, unsigned int idx = 0);
 
+  /**
+  Register all ProcessObject that are linked to parameters : 
+    \li ParameterType_OutputImage
+    \li ParameterType_OutputVectorData
+
+    Those ProcessObjects are stored in the m_Filters set and are deleted at the 
+  end of ExecuteAndWriteOutput (if there are only held by the set)
+  This method can be called just before the end of a DoExecute in a derived 
+  class of Application.
+  */
+  void RegisterPipeline();
+
+  /**
+  Register all DataObject that are reachable from :
+    \li ParameterType_OutputImage
+    \li ParameterType_OutputVectorData
+
+  Once registered, the methode ReleaseData is called on each one of them.
+  */
+  void FreeRessources();
+
 protected:
   /** Constructor */
   Application();
@@ -1048,6 +1073,8 @@ private:
    * implementation does nothing */
   virtual void AfterExecuteAndWriteOutputs();
 
+  virtual void DoFreeRessources(){};
+
   Application(const Application &); //purposely not implemented
   void operator =(const Application&); //purposely not implemented
 
@@ -1059,6 +1086,8 @@ private:
   itk::ProcessObject::Pointer       m_ProgressSource;
   std::string                       m_ProgressSourceDescription;
 
+  std::set<itk::ProcessObject::Pointer> m_Filters;
+
   /** Long name of the application (that can be displayed...) */
   std::string m_DocName;
   /** Long and precise application description . */
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
index 722dbeead7ab40c868ec1fc0732292a9f6ab6b55..29b9ac2866266b6439baf95154f147ea44241e67 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
@@ -109,7 +109,6 @@ public:
 
   void ClearValue() override;
 
-
 protected:
   /** Constructor */
   InputImageParameter();
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
index b9bc451c3b3b9a59437ac306cf48929e9459d734..eac7df4cadad4e1c8376918f53401439748a6094 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
@@ -117,14 +117,8 @@ protected:
   /** Destructor */
   ~OutputImageParameter() override;
 
-  template <class TInputVectorImageType>
-    void SwitchVectorImageWrite();
-
-  template <class TInputVectorImageType>
-    void SwitchRGBImageWrite();
-
-  template <class TInputVectorImageType>
-    void SwitchRGBAImageWrite();
+  template <class TInput>
+    int SwitchInput(TInput *img);
 
   //FloatVectorImageType::Pointer m_Image;
   ImageBaseType::Pointer m_Image;
@@ -132,46 +126,28 @@ protected:
   ImagePixelType         m_PixelType;
   ImagePixelType         m_DefaultPixelType;
 
-  typedef otb::ImageFileWriter<UInt8VectorImageType>  VectorUInt8WriterType;
-  typedef otb::ImageFileWriter<Int16VectorImageType>  VectorInt16WriterType;
-  typedef otb::ImageFileWriter<UInt16VectorImageType> VectorUInt16WriterType;
-  typedef otb::ImageFileWriter<Int32VectorImageType>  VectorInt32WriterType;
-  typedef otb::ImageFileWriter<UInt32VectorImageType> VectorUInt32WriterType;
-  typedef otb::ImageFileWriter<FloatVectorImageType>  VectorFloatWriterType;
-  typedef otb::ImageFileWriter<DoubleVectorImageType> VectorDoubleWriterType;
-
-  typedef otb::ImageFileWriter<UInt8RGBAImageType>  RGBAUInt8WriterType;
-  typedef otb::ImageFileWriter<UInt8RGBImageType>   RGBUInt8WriterType;
-
-  typedef otb::ImageFileWriter<ComplexInt16VectorImageType>  ComplexVectorInt16WriterType;
-  typedef otb::ImageFileWriter<ComplexInt32VectorImageType>  ComplexVectorInt32WriterType;
-  typedef otb::ImageFileWriter<ComplexFloatVectorImageType>  ComplexVectorFloatWriterType;
-  typedef otb::ImageFileWriter<ComplexDoubleVectorImageType> ComplexVectorDoubleWriterType;
-
-  VectorUInt8WriterType::Pointer  m_VectorUInt8Writer;
-  VectorInt16WriterType::Pointer  m_VectorInt16Writer;
-  VectorUInt16WriterType::Pointer m_VectorUInt16Writer;
-  VectorInt32WriterType::Pointer  m_VectorInt32Writer;
-  VectorUInt32WriterType::Pointer m_VectorUInt32Writer;
-  VectorFloatWriterType::Pointer  m_VectorFloatWriter;
-  VectorDoubleWriterType::Pointer m_VectorDoubleWriter;
-
-  RGBUInt8WriterType::Pointer   m_RGBUInt8Writer;
-  RGBAUInt8WriterType::Pointer  m_RGBAUInt8Writer;
-
-  ComplexVectorInt16WriterType::Pointer  m_ComplexVectorInt16Writer;
-  ComplexVectorInt32WriterType::Pointer  m_ComplexVectorInt32Writer;
-  ComplexVectorFloatWriterType::Pointer  m_ComplexVectorFloatWriter;
-  ComplexVectorDoubleWriterType::Pointer m_ComplexVectorDoubleWriter;
-
 private:
   OutputImageParameter(const Parameter &); //purposely not implemented
   void operator =(const Parameter&); //purposely not implemented
 
   unsigned int                  m_RAMValue;
 
+  itk::ProcessObject::Pointer m_Caster;
+
+  itk::ProcessObject::Pointer m_Writer;
+
 }; // End class OutputImage Parameter
 
+// Declare specialisation for UInt8RGBAImageType
+template <>
+int
+OutputImageParameter::SwitchInput(UInt8RGBAImageType *img);
+
+// Declare specialisation for UInt8RGBImageType
+template <>
+int
+OutputImageParameter::SwitchInput(UInt8RGBImageType *img);
+
 } // End namespace Wrapper
 } // End namespace otb
 
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
index 5f20a11ace33f79f904a2810a7c19f5571d4142f..31f46f3a019e6fe335ebcae5535b4b6284bc2f4a 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
@@ -45,6 +45,8 @@
 #include "otbWrapperTypes.h"
 #include <exception>
 #include "itkMacro.h"
+#include <stack>
+#include <set>
 
 namespace otb
 {
@@ -380,6 +382,213 @@ void Application::UpdateParameters()
 void Application::AfterExecuteAndWriteOutputs()
 {}
 
+void
+Application::RegisterPipeline()
+{
+  std::stack< itk::DataObject * > dataStack;
+  std::set< itk::DataObject * > inputData;
+  std::vector<std::string> paramList = GetParametersKeys(true);
+  // Get both end of the pipeline
+  for ( auto const & key : paramList )
+    {
+    if ( GetParameterType(key) == ParameterType_OutputImage )
+      {
+      Parameter* param = GetParameterByKey(key);
+      OutputImageParameter * outP = 
+        dynamic_cast< OutputImageParameter * >( param );
+      itk::ImageBase< 2 > * outData = outP->GetValue();
+      if ( outData )
+        dataStack.push(outData);
+      }
+    else if ( GetParameterType(key) == ParameterType_OutputVectorData )
+      {
+      Parameter* param = GetParameterByKey(key);
+      OutputVectorDataParameter * outP = 
+        dynamic_cast< OutputVectorDataParameter * >( param );
+      VectorDataType * outData = outP->GetValue();
+      if ( outData )
+        dataStack.push(outData);
+      }
+    else if ( GetParameterType(key) == ParameterType_InputImage )
+      {
+      Parameter* param = GetParameterByKey(key);
+      InputImageParameter * inP = 
+        dynamic_cast< InputImageParameter * >( param );
+      if ( !inP->HasValue() )
+        continue;
+      ImageBaseType * inData = inP->GetImage< ImageBaseType >();
+      if ( inData && !inputData.count(inData) )
+        inputData.insert(inData);
+      }
+    else if ( GetParameterType(key) == ParameterType_InputImageList )
+      {
+      Parameter * param = GetParameterByKey(key);
+      InputImageListParameter * inP = 
+        dynamic_cast< InputImageListParameter * > ( param );
+      if ( !inP->HasValue() )
+        continue;
+      const FloatVectorImageListType * list = inP->GetImageList();
+      for ( auto it = list->Begin() ; it != list->End() ; ++it ) 
+        {
+        FloatVectorImageType * inData = it.Get().GetPointer();
+        if ( inData && !inputData.count(inData) )
+          inputData.insert(inData);
+        }
+      }
+    else if ( GetParameterType(key) == ParameterType_InputVectorData )
+      {
+      Parameter * param = GetParameterByKey(key);
+      InputVectorDataParameter * inP =
+        dynamic_cast< InputVectorDataParameter * > ( param );
+      if ( !inP->HasValue() )
+        continue;
+      VectorDataType * inData = inP->GetVectorData();
+      if ( inData && !inputData.count(inData) )
+        inputData.insert(inData);
+      }
+    else if ( GetParameterType(key) == ParameterType_InputVectorDataList )
+      {
+      Parameter * param = GetParameterByKey(key);
+      InputVectorDataListParameter * inP =
+        dynamic_cast< InputVectorDataListParameter * > ( param );
+      if ( !inP->HasValue() )
+        continue;
+      VectorDataListType * list = inP->GetVectorDataList();
+      for ( auto it = list->Begin() ; it != list->End() ; ++it )
+        {
+        VectorDataType * inData = it.Get().GetPointer();
+        if ( inData && !inputData.count(inData) )
+          inputData.insert(inData);
+        }
+      }
+    }
+
+  // DFS
+  while ( !dataStack.empty() )
+    {
+    itk::DataObject * current = dataStack.top();
+    dataStack.pop();
+    // whether current = null or is an input data it has no source
+    if ( !current || inputData.count( current ) )
+      continue;
+    // if current is a list push every of its members in datastack
+    if ( dynamic_cast< DataObjectListInterface *> (current) )
+      {
+      DataObjectListInterface * list = 
+        dynamic_cast< DataObjectListInterface *> (current);
+      int length = list->Size();
+      for ( int i = 0 ; i < length ; i++ )
+        {
+        itk::DataObject * newData = list->GetNthDataObject(i);
+        if ( !current || inputData.count( current ) )
+          continue;
+        dataStack.push( newData );
+      continue;
+        }
+      }
+    // Finally get the current's process object source
+    itk::ProcessObject * process = (current->GetSource()).GetPointer();
+    if ( !process || m_Filters.find( process ) != m_Filters.end() )
+      continue;
+    m_Filters.insert( process );
+    std::vector< itk::DataObject::Pointer > inputs = process->GetInputs();
+    // Push back all source's inputs in datastack
+    for ( auto const & it : inputs )
+      {
+      if ( inputData.count( it.GetPointer() ) )
+        continue;
+      dataStack.push( it.GetPointer() );
+      }
+    }
+}
+
+void Application::FreeRessources()
+{
+  std::set< itk::DataObject * > dataSetToRelease; // do not release output
+  std::set< itk::DataObject * > dataSet;
+  std::vector<std::string> paramList = GetParametersKeys(true);
+  // Get the end of the pipeline
+  for ( const auto & key : paramList )
+    {
+    if ( GetParameterType(key) == ParameterType_OutputImage )
+      {
+      Parameter* param = GetParameterByKey(key);
+      OutputImageParameter * outP = dynamic_cast<OutputImageParameter*>(param);
+      itk::ImageBase<2> * outData = outP->GetValue();
+      if ( outData )
+        dataSet.insert(outData);
+      }
+    else if ( GetParameterType(key) == ParameterType_OutputVectorData )
+      {
+      Parameter* param = GetParameterByKey(key);
+      OutputVectorDataParameter * outP = dynamic_cast<OutputVectorDataParameter*>(param);
+      Wrapper::VectorDataType * outData = outP->GetValue();
+      if ( outData )
+        dataSet.insert(outData);
+      }
+    else
+      continue;
+    }
+  // initialize DFS
+  std::stack< itk::ProcessObject * > processStack;
+  for ( auto data : dataSet )
+    {
+    auto process = (data->GetSource()).GetPointer();
+    if ( process )
+      processStack.push( process );
+    }
+  // DFS
+  while ( !processStack.empty() )
+    {
+    itk::ProcessObject * current = processStack.top();
+    processStack.pop();
+    // if null continue
+    if ( !current )
+      continue;
+    // Get all inputs
+    auto inputVector = current->GetInputs();
+    for ( auto data : inputVector )
+      {
+      // If input is null or already in the set continue
+      if ( !data.GetPointer() || dataSet.count( data.GetPointer() ) )
+        continue;
+      // If input is a list
+      if ( dynamic_cast< DataObjectListInterface *> (data.GetPointer()) )
+        {
+        DataObjectListInterface * list = 
+          dynamic_cast< DataObjectListInterface *> (data.GetPointer());
+        int length = list->Size();
+        for ( int i = 0 ; i < length ; i++ )
+          {
+          itk::DataObject * newData = list->GetNthDataObject(i);
+          if ( !newData || dataSet.count( newData ) )
+            continue;
+          dataSet.insert( newData );
+          dataSetToRelease.insert( newData );
+          itk::ProcessObject * process = newData->GetSource().GetPointer();
+          if ( process )
+            processStack.push( process );
+          }
+        }
+      else
+        {
+        dataSet.insert( data.GetPointer() );
+        dataSetToRelease.insert( data.GetPointer() );
+        itk::ProcessObject * process = data->GetSource().GetPointer();
+        if ( process )
+          processStack.push( process );
+        }
+      }
+    }
+  // Release data
+  for ( auto data : dataSetToRelease )
+  {
+    data->ReleaseData();
+  }
+  // Call override method
+  DoFreeRessources();
+}
+
 int Application::Execute()
 {
 
@@ -477,7 +686,6 @@ int Application::ExecuteAndWriteOutput()
 
           if(outputParam!=ITK_NULLPTR)
             {
-            outputParam->InitializeWriters();
             std::string checkReturn = outputParam->CheckFileName(true);
             if (!checkReturn.empty())
               {
@@ -487,6 +695,7 @@ int Application::ExecuteAndWriteOutput()
               {
               outputParam->SetRAMValue(ram);
               }
+            outputParam->InitializeWriters();
             std::ostringstream progressId;
             progressId << "Writing " << outputParam->GetFileName() << "...";
             AddProcess(outputParam->GetWriter(), progressId.str());
@@ -526,7 +735,6 @@ int Application::ExecuteAndWriteOutput()
             outputParam->Write();
             }
           }
-
         //xml writer parameter
         else if (m_HaveOutXML && GetParameterType(key) == ParameterType_OutputProcessXML
                  && IsParameterEnabled(key) && HasValue(key) )
@@ -542,11 +750,19 @@ int Application::ExecuteAndWriteOutput()
     }
 
   this->AfterExecuteAndWriteOutputs();
-
   m_Chrono.Stop();
+  
+  FreeRessources();
+  m_Filters.clear();
   return status;
 }
 
+void
+Application::Stop()
+{
+  m_ProgressSource->SetAbortGenerateData(true);
+}
+
 /* Enable the use of an optional parameter. Returns the previous state */
 void Application::EnableParameter(std::string paramKey)
 {
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
index b97171cb71d9b270f07437cf22fa5116bc0b0d7c..4218836ed7eb3091f1cf1a451c165d9bb77a040a 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
@@ -259,20 +259,22 @@ ComplexOutputImageParameter::GetWriter()
     case ComplexImagePixelType_int16:
     {
       writer = m_ComplexVectorInt16Writer;
+      break;
     }
     case ComplexImagePixelType_int32:
     {
       writer = m_ComplexVectorInt32Writer;
+      break;
     }
     case ComplexImagePixelType_float:
     {
       writer = m_ComplexVectorFloatWriter;
-    break;
+      break;
     }
     case ComplexImagePixelType_double:
     {
       writer = m_ComplexVectorDoubleWriter;
-    break;
+      break;
     }
     }
   return writer;
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx
index 4cf7c602e1f247a6c9836a50cea9587218b9e989..02ddfea8985acb5b67f29cbbf344139b5bcacc3f 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx
@@ -30,7 +30,7 @@ namespace MetaDataHelper
 
 MDType GetType(const std::string &val)
 {
-  MDType ret;
+  MDType ret(MDType::String);
   otb::MetaDataKey::KeyType kt = otb::MetaDataKey::GetKeyType(val);
   switch (kt)
     {
@@ -88,7 +88,7 @@ GetInt(
     const itk::MetaDataDictionary &dict,
     const std::string &key)
 {
-  unsigned int ret;
+  unsigned int ret=0;
   itk::ExposeMetaData<unsigned int>(dict, key, ret);
   return ret;
 }
@@ -107,7 +107,7 @@ GetDouble(
     const itk::MetaDataDictionary &dict,
     const std::string &key)
 {
-  double ret;
+  double ret = 0.0;
   itk::ExposeMetaData<double>(dict, key, ret);
   return ret;
 }
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
index 09396447765610f1b1f2dd903943b9a2cc116922..9e6e33efdac2c1223830dad9db754e7110777817 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
@@ -42,7 +42,9 @@ namespace Wrapper
 OutputImageParameter::OutputImageParameter()
   : m_PixelType(ImagePixelType_float),
     m_DefaultPixelType(ImagePixelType_float),
-    m_RAMValue(0)
+    m_RAMValue(0),
+    m_Caster(nullptr),
+    m_Writer(nullptr)
 {
   this->SetName("Output Image");
   this->SetKey("out");
@@ -149,35 +151,102 @@ OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePi
 
 void OutputImageParameter::InitializeWriters()
 {
-  m_VectorUInt8Writer = VectorUInt8WriterType::New();
-  m_VectorInt16Writer = VectorInt16WriterType::New();
-  m_VectorUInt16Writer = VectorUInt16WriterType::New();
-  m_VectorInt32Writer = VectorInt32WriterType::New();
-  m_VectorUInt32Writer = VectorUInt32WriterType::New();
-  m_VectorFloatWriter = VectorFloatWriterType::New();
-  m_VectorDoubleWriter = VectorDoubleWriterType::New();
-
-  m_RGBUInt8Writer = RGBUInt8WriterType::New();
-  m_RGBAUInt8Writer = RGBAUInt8WriterType::New();
-
-  m_ComplexVectorInt16Writer = ComplexVectorInt16WriterType::New();
-  m_ComplexVectorInt32Writer = ComplexVectorInt32WriterType::New();
-  m_ComplexVectorFloatWriter = ComplexVectorFloatWriterType::New();
-  m_ComplexVectorDoubleWriter = ComplexVectorDoubleWriterType::New();
+  ImageBaseType* imgBase = m_Image.GetPointer();
+  // Guess the image type
+  std::string className(m_Image->GetNameOfClass());
+  if (className == "VectorImage")
+    {
+    UInt8VectorImageType* imgUInt8 = dynamic_cast<UInt8VectorImageType*>(imgBase);
+    if (imgUInt8 && SwitchInput(imgUInt8)) return;
+
+    Int16VectorImageType* imgInt16 = dynamic_cast<Int16VectorImageType*>(imgBase);
+    if (imgInt16 && SwitchInput(imgInt16)) return;
+
+    UInt16VectorImageType* imgUInt16 = dynamic_cast<UInt16VectorImageType*>(imgBase);
+    if (imgUInt16 && SwitchInput(imgUInt16)) return;
+
+    Int32VectorImageType* imgInt32 = dynamic_cast<Int32VectorImageType*>(imgBase);
+    if (imgInt32 && SwitchInput(imgInt32)) return;
+
+    UInt32VectorImageType* imgUInt32 = dynamic_cast<UInt32VectorImageType*>(imgBase);
+    if (imgUInt32 && SwitchInput(imgUInt32)) return;
+
+    FloatVectorImageType* imgFloat = dynamic_cast<FloatVectorImageType*>(imgBase);
+    if (imgFloat && SwitchInput(imgFloat)) return;
+
+    DoubleVectorImageType* imgDouble = dynamic_cast<DoubleVectorImageType*>(imgBase);
+    if (imgDouble && SwitchInput(imgDouble)) return;
+
+    ComplexInt16VectorImageType* imgCInt16 = dynamic_cast<ComplexInt16VectorImageType*>(imgBase);
+    if (imgCInt16 && SwitchInput(imgCInt16)) return;
+
+    ComplexInt32VectorImageType* imgCInt32 = dynamic_cast<ComplexInt32VectorImageType*>(imgBase);
+    if (imgCInt32 && SwitchInput(imgCInt32)) return;
+
+    ComplexFloatVectorImageType* imgCFloat = dynamic_cast<ComplexFloatVectorImageType*>(imgBase);
+    if (imgCFloat && SwitchInput(imgCFloat)) return;
+
+    ComplexDoubleVectorImageType* imgCDouble = dynamic_cast<ComplexDoubleVectorImageType*>(imgBase);
+    if (imgCDouble && SwitchInput(imgCDouble)) return;
+    }
+  else
+    {
+    UInt8ImageType* imgUInt8 = dynamic_cast<UInt8ImageType*>(imgBase);
+    if (imgUInt8 && SwitchInput(imgUInt8)) return;
+
+    Int16ImageType* imgInt16 = dynamic_cast<Int16ImageType*>(imgBase);
+    if (imgInt16 && SwitchInput(imgInt16)) return;
+
+    UInt16ImageType* imgUInt16 = dynamic_cast<UInt16ImageType*>(imgBase);
+    if (imgUInt16 && SwitchInput(imgUInt16)) return;
+
+    Int32ImageType* imgInt32 = dynamic_cast<Int32ImageType*>(imgBase);
+    if (imgInt32 && SwitchInput(imgInt32)) return;
+
+    UInt32ImageType* imgUInt32 = dynamic_cast<UInt32ImageType*>(imgBase);
+    if (imgUInt32 && SwitchInput(imgUInt32)) return;
+
+    FloatImageType* imgFloat = dynamic_cast<FloatImageType*>(imgBase);
+    if (imgFloat && SwitchInput(imgFloat)) return;
+
+    DoubleImageType* imgDouble = dynamic_cast<DoubleImageType*>(imgBase);
+    if (imgDouble && SwitchInput(imgDouble)) return;
+
+    ComplexInt16ImageType* imgCInt16 = dynamic_cast<ComplexInt16ImageType*>(imgBase);
+    if (imgCInt16 && SwitchInput(imgCInt16)) return;
+
+    ComplexInt32ImageType* imgCInt32 = dynamic_cast<ComplexInt32ImageType*>(imgBase);
+    if (imgCInt32 && SwitchInput(imgCInt32)) return;
+
+    ComplexFloatImageType* imgCFloat = dynamic_cast<ComplexFloatImageType*>(imgBase);
+    if (imgCFloat && SwitchInput(imgCFloat)) return;
+
+    ComplexDoubleImageType* imgCDouble = dynamic_cast<ComplexDoubleImageType*>(imgBase);
+    if (imgCDouble && SwitchInput(imgCDouble)) return;
+
+    UInt8RGBImageType* imgRGB = dynamic_cast<UInt8RGBImageType*>(imgBase);
+    if (imgRGB && SwitchInput(imgRGB)) return;
+
+    UInt8RGBAImageType* imgRGBA = dynamic_cast<UInt8RGBAImageType*>(imgBase);
+    if (imgRGBA && SwitchInput(imgRGBA)) return;
+    }
+
+  itkExceptionMacro("Unknown image type");
 }
 
 
 template <typename TInput, typename TOutput> 
-void 
-ClampAndWriteVectorImage( itk::ImageBase<2> * in ,
-                    otb::ImageFileWriter<TOutput> * writer , 
+std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> 
+ClampAndWriteVectorImage( TInput * in ,
                     const std::string & filename , 
                     const unsigned int & ramValue )
 {
+  std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> ret;
   typedef ClampImageFilter < TInput , TOutput > ClampFilterType;
   typename ClampFilterType::Pointer clampFilter ( ClampFilterType::New() );
 
-  clampFilter->SetInput( dynamic_cast<TInput*>(in));
+  clampFilter->SetInput( in);
+  ret.first = clampFilter.GetPointer();
   
   bool useStandardWriter = true;
 
@@ -194,8 +263,14 @@ ClampAndWriteVectorImage( itk::ImageBase<2> * in ,
 
     if(extension == ".vrt")
       {
-      // Use the WriteMPI function
-      WriteMPI(clampFilter->GetOutput(),filename,ramValue);      
+      // Use the MPIVrtWriter
+      typedef otb::MPIVrtWriter<TOutput> VRTWriterType;
+
+      typename VRTWriterType::Pointer vrtWriter = VRTWriterType::New();
+      vrtWriter->SetInput(clampFilter->GetOutput());
+      vrtWriter->SetFileName(filename);
+      vrtWriter->SetAvailableRAM(ramValue);
+      ret.second = vrtWriter.GetPointer();
       }
     #ifdef OTB_USE_SPTW
     else if (extension == ".tif")
@@ -206,9 +281,8 @@ ClampAndWriteVectorImage( itk::ImageBase<2> * in ,
       typename SPTWriterType::Pointer sptWriter = SPTWriterType::New();
       sptWriter->SetFileName(filename);
       sptWriter->SetInput(clampFilter->GetOutput());
-      sptWriter->SetAutomaticAdaptativeStreaming(ramValue);
       sptWriter->GetStreamingManager()->SetDefaultRAM(ramValue);
-      sptWriter->Update();
+      ret.second = sptWriter.GetPointer();
       }
     
     #endif
@@ -223,114 +297,110 @@ ClampAndWriteVectorImage( itk::ImageBase<2> * in ,
   
   if(useStandardWriter)
     {
+    typename otb::ImageFileWriter<TOutput>::Pointer writer =
+      otb::ImageFileWriter<TOutput>::New();
     writer->SetFileName( filename );
     writer->SetInput(clampFilter->GetOutput());
     writer->GetStreamingManager()->SetDefaultRAM(ramValue);
-    writer->Update();
+    ret.second = writer.GetPointer();
     }
+
+  return ret;
 }
 
 template <class TInput>
-void
-OutputImageParameter::SwitchVectorImageWrite()
-  {
+int
+OutputImageParameter::SwitchInput(TInput *img)
+{
+  if (! img) return 0;
+
+  std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> ret;
   switch(m_PixelType )
     {
     case ImagePixelType_uint8:
     {
-    ClampAndWriteVectorImage< TInput , UInt8VectorImageType > (
-      m_Image ,
-      m_VectorUInt8Writer ,
+    ret = ClampAndWriteVectorImage< TInput , UInt8VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_int16:
     {
-    ClampAndWriteVectorImage< TInput , Int16VectorImageType > (
-      m_Image ,
-      m_VectorInt16Writer ,
+    ret = ClampAndWriteVectorImage< TInput , Int16VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_uint16:
     {
-    ClampAndWriteVectorImage< TInput , UInt16VectorImageType > (
-      m_Image ,
-      m_VectorUInt16Writer ,
+    ret = ClampAndWriteVectorImage< TInput , UInt16VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_int32:
     {
-    ClampAndWriteVectorImage< TInput , Int32VectorImageType > (
-      m_Image ,
-      m_VectorInt32Writer ,
+    ret = ClampAndWriteVectorImage< TInput , Int32VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_uint32:
     {
-    ClampAndWriteVectorImage< TInput , UInt32VectorImageType > (
-      m_Image ,
-      m_VectorUInt32Writer ,
+    ret = ClampAndWriteVectorImage< TInput , UInt32VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_float:
     {
-    ClampAndWriteVectorImage< TInput , FloatVectorImageType > (
-      m_Image ,
-      m_VectorFloatWriter ,
+    ret = ClampAndWriteVectorImage< TInput , FloatVectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_double:
     {
-    ClampAndWriteVectorImage< TInput , DoubleVectorImageType > (
-      m_Image ,
-      m_VectorDoubleWriter ,
+    ret = ClampAndWriteVectorImage< TInput , DoubleVectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
     }
     case ImagePixelType_cint16:
     {
-    ClampAndWriteVectorImage < TInput , ComplexInt16VectorImageType > (
-      m_Image ,
-      m_ComplexVectorInt16Writer ,
+    ret = ClampAndWriteVectorImage < TInput , ComplexInt16VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue ); 
     break;
     }
     case ImagePixelType_cint32:
     {
-    ClampAndWriteVectorImage < TInput , ComplexInt32VectorImageType > (
-      m_Image ,
-      m_ComplexVectorInt32Writer ,
+    ret = ClampAndWriteVectorImage < TInput , ComplexInt32VectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue ); 
     break;
     }
     case ImagePixelType_cfloat:
     {
-    ClampAndWriteVectorImage < TInput , ComplexFloatVectorImageType > (
-      m_Image ,
-      m_ComplexVectorFloatWriter ,
+    ret = ClampAndWriteVectorImage < TInput , ComplexFloatVectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue ); 
     break;
     }
     case ImagePixelType_cdouble:
     {
-    ClampAndWriteVectorImage < TInput , ComplexDoubleVectorImageType > (
-      m_Image ,
-      m_ComplexVectorDoubleWriter ,
+    ret = ClampAndWriteVectorImage < TInput , ComplexDoubleVectorImageType > (
+      img ,
       m_FileName ,
       m_RAMValue );
     break;
@@ -338,256 +408,27 @@ OutputImageParameter::SwitchVectorImageWrite()
     default:
       break;
     }
-  }
-
-template <class TInputRGBAImageType>
-void
-OutputImageParameter::SwitchRGBAImageWrite()
-  {
-  if( m_PixelType == ImagePixelType_uint8 )
-    {
-    m_RGBAUInt8Writer->SetFileName( this->GetFileName() );
-    m_RGBAUInt8Writer->SetInput(dynamic_cast<UInt8RGBAImageType*>(m_Image.GetPointer()) );
-    m_RGBAUInt8Writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
-    m_RGBAUInt8Writer->Update();
-    }
-   else
-     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");
-  }
-
-template <class TInputRGBImageType>
-void
-OutputImageParameter::SwitchRGBImageWrite()
-  {
-   if( m_PixelType == ImagePixelType_uint8 )
-    {
-    m_RGBUInt8Writer->SetFileName( this->GetFileName() );
-    m_RGBUInt8Writer->SetInput(dynamic_cast<UInt8RGBImageType*>(m_Image.GetPointer()) );
-    m_RGBUInt8Writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
-    m_RGBUInt8Writer->Update();
-    }
-   else
-     itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");
-  }
+  // Save the caster and writer
+  m_Caster = ret.first;
+  m_Writer = ret.second;
+  return 1;
+}
 
 void
 OutputImageParameter::Write()
 {
-  m_Image->UpdateOutputInformation();
+  m_Writer->Update();
 
-  if (dynamic_cast<UInt8ImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt8ImageType>();
-    }
-  else if (dynamic_cast<Int16ImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<Int16ImageType>();
-    }
-  else if (dynamic_cast<UInt16ImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt16ImageType>();
-    }
-  else if (dynamic_cast<Int32ImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<Int32ImageType>();
-    }
-  else if (dynamic_cast<UInt32ImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt32ImageType>();
-    }
-  else if (dynamic_cast<FloatImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<FloatImageType>();
-    }
-  else if (dynamic_cast<DoubleImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<DoubleImageType>();
-    }
-  else if (dynamic_cast<ComplexInt16ImageType*>(m_Image.GetPointer()) )
-    {
-    SwitchVectorImageWrite<ComplexInt16ImageType>();
-    }
-  else if (dynamic_cast<ComplexInt32ImageType*>(m_Image.GetPointer()) )
-    {
-    SwitchVectorImageWrite<ComplexInt32ImageType>();
-    }
-  else if (dynamic_cast<ComplexFloatImageType*>(m_Image.GetPointer()) )
-    {
-    SwitchVectorImageWrite<ComplexFloatImageType>();
-    }
-  else if (dynamic_cast<ComplexDoubleImageType*>(m_Image.GetPointer()) )
-    {
-    SwitchVectorImageWrite<ComplexDoubleImageType>();
-    }
-  else if (dynamic_cast<UInt8VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt8VectorImageType>();
-    }
-  else if (dynamic_cast<Int16VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<Int16VectorImageType>();
-    }
-  else if (dynamic_cast<UInt16VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt16VectorImageType>();
-    }
-  else if (dynamic_cast<Int32VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<Int32VectorImageType>();
-    }
-  else if (dynamic_cast<UInt32VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<UInt32VectorImageType>();
-    }
-  else if (dynamic_cast<FloatVectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<FloatVectorImageType>();
-    }
-  else if (dynamic_cast<DoubleVectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<DoubleVectorImageType>();
-    }
-  else if (dynamic_cast<ComplexInt16VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<ComplexInt16VectorImageType>();
-    }
-  else if (dynamic_cast<ComplexInt32VectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<ComplexInt32VectorImageType>();
-    }
-  else if (dynamic_cast<ComplexFloatVectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<ComplexFloatVectorImageType>();
-    }
-  else if (dynamic_cast<ComplexDoubleVectorImageType*>(m_Image.GetPointer()))
-    {
-    SwitchVectorImageWrite<ComplexDoubleVectorImageType>();
-    }
-  else if (dynamic_cast<UInt8RGBImageType*>(m_Image.GetPointer()))
-    {
-    SwitchRGBImageWrite<UInt8RGBImageType>();
-    }
-  else if (dynamic_cast<UInt8RGBAImageType*>(m_Image.GetPointer()))
-    {
-    SwitchRGBAImageWrite<UInt8RGBAImageType>();
-    }
-  else
-    {
-    itkExceptionMacro("Unknown image type");
-    }
-  }
+  // Clean internal filters
+  m_Caster = nullptr;
+  m_Writer = nullptr;
+}
 
 
 itk::ProcessObject*
 OutputImageParameter::GetWriter()
 {
-  int type = 1;
-  // 0 : image
-  // 1 : VectorImage
-  // 2 : RGBAImage
-  // 3 : RGBImage
-  itk::ProcessObject* writer = ITK_NULLPTR;
-
-  if (dynamic_cast<UInt8RGBAImageType*> (m_Image.GetPointer()))
-    {
-    type = 2;
-    writer = m_RGBAUInt8Writer;
-    itkWarningMacro("UInt8RGBAImageType will be saved in UInt8 format.");
-    return writer;
-    }
-  else if (dynamic_cast<UInt8RGBImageType*> (m_Image.GetPointer()))
-    {
-    type = 3;
-    writer = m_RGBUInt8Writer;
-    itkWarningMacro("UInt8RGBImageType will be saved in UInt8 format.");
-    return writer;
-    }
-  
-  switch (GetPixelType())
-    {
-    case ImagePixelType_uint8:
-      {
-      switch(type)
-        {
-        case 1:
-          writer = m_VectorUInt8Writer;
-          break;
-        case 2:
-          writer = m_RGBAUInt8Writer;
-          break;
-        default:
-          writer = m_RGBUInt8Writer;
-          break;
-        }
-      break;
-      }
-    case ImagePixelType_int16:
-      {
-      if (type == 1)
-        writer = m_VectorInt16Writer;
-      break;
-      }
-    case ImagePixelType_uint16:
-      {
-      if (type == 1)
-        writer = m_VectorUInt16Writer;
-      break;
-      }
-    case ImagePixelType_int32:
-      {
-      if (type == 1)
-        writer = m_VectorInt32Writer;
-      break;
-      }
-    case ImagePixelType_uint32:
-      {
-      if (type == 1)
-        writer = m_VectorUInt32Writer;
-      break;
-      }
-    case ImagePixelType_float:
-      {
-      if (type == 1)
-        writer = m_VectorFloatWriter;
-      break;
-      }
-    case ImagePixelType_double:
-      {
-      if (type == 1)
-        writer = m_VectorDoubleWriter;
-      break;
-      }
-    case ImagePixelType_cint16:
-      {
-      if( type == 1 )
-        writer = m_ComplexVectorInt16Writer;
-      break;
-      }
-    case ImagePixelType_cint32:
-      {
-      if( type == 1 )
-        writer = m_ComplexVectorInt32Writer;
-      break;
-      }
-    case ImagePixelType_cfloat:
-      {
-      if( type == 1 )
-        writer = m_ComplexVectorFloatWriter;
-      break;
-      }
-    case ImagePixelType_cdouble:
-      {
-      if( type == 1 )
-        writer = m_ComplexVectorDoubleWriter;
-      break;
-      }
-    }
-  if (ITK_NULLPTR == writer)
-    {
-    itkExceptionMacro("Unknown Writer type.");
-    }
-
-  return writer;
+  return m_Writer;
 }
 
 ImageBaseType*
@@ -651,5 +492,45 @@ OutputImageParameter::CheckFileName(bool fixMissingExtension)
   return ret;
 }
 
+// Specialization for UInt8RGBAImageType
+template <>
+int
+OutputImageParameter::SwitchInput(UInt8RGBAImageType *img)
+{
+  if (! img) return 0;
+  if( m_PixelType == ImagePixelType_uint8 )
+    {
+    typename otb::ImageFileWriter<UInt8RGBAImageType>::Pointer writer =
+      otb::ImageFileWriter<UInt8RGBAImageType>::New();
+    writer->SetFileName( this->GetFileName() );
+    writer->SetInput(img);
+    writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
+    m_Writer = writer.GetPointer();
+    }
+   else
+     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");
+  return 1;
+}
+
+// Specialization for UInt8RGBImageType
+template <>
+int
+OutputImageParameter::SwitchInput(UInt8RGBImageType *img)
+{
+  if (! img) return 0;
+  if( m_PixelType == ImagePixelType_uint8 )
+    {
+    typename otb::ImageFileWriter<UInt8RGBImageType>::Pointer writer =
+      otb::ImageFileWriter<UInt8RGBImageType>::New();
+    writer->SetFileName( this->GetFileName() );
+    writer->SetInput(img);
+    writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
+    m_Writer = writer.GetPointer();
+    }
+   else
+     itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");
+  return 1;
+}
+
 }
 }
diff --git a/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt b/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
index 856191df14551aabfe7ea8982d7a70a59aa6ea56..e92b69dc0324ee9debb1e80104b846a545fa3c4d 100644
--- a/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
+++ b/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
@@ -190,6 +190,7 @@ otb_add_test(NAME owTuDocExampleStructureNew COMMAND otbApplicationEngineTestDri
   otbWrapperDocExampleStructureNew
   )
 
+# Warning this test require otbapp_Smoothing and otbapp_ConcatenateImages to be built
 otb_add_test(NAME owTvApplicationMemoryConnectTest COMMAND otbApplicationEngineTestDriver otbApplicationMemoryConnectTest
   $<TARGET_FILE_DIR:otbapp_Smoothing>
   ${INPUTDATA}/poupees.tif
diff --git a/Modules/Wrappers/CommandLine/src/otbApplicationLauncherCommandLine.cxx b/Modules/Wrappers/CommandLine/src/otbApplicationLauncherCommandLine.cxx
index 4c5bd8a93f43780e7d4827b260ae92e73ca9fde3..72f8b84d95c656070dbe0748572a1e140e2d78b7 100644
--- a/Modules/Wrappers/CommandLine/src/otbApplicationLauncherCommandLine.cxx
+++ b/Modules/Wrappers/CommandLine/src/otbApplicationLauncherCommandLine.cxx
@@ -270,7 +270,7 @@ int main(int argc, char* argv[])
   if (argc < 2)
   {
       ShowUsage(argv);
-      return false;
+      return EXIT_FAILURE;
   }
 
   std::vector<std::string> vexp;
@@ -302,7 +302,7 @@ int main(int argc, char* argv[])
   if (vexp.empty())
   {
     ShowUsage(argv);
-    return false;
+    return EXIT_FAILURE;
   }
 
   bool success = launcher->Load(vexp) && launcher->ExecuteAndWriteOutput();
diff --git a/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetModel.h b/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetModel.h
index 2fefeda56e012736bd3f0d13ca782ddf39aa5b38..09d040a4dcd35f5ef17f1e820c30f8d8f55f3471 100644
--- a/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetModel.h
+++ b/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetModel.h
@@ -68,6 +68,13 @@ signals:
    */
   void ExceptionRaised( QString what );
 
+public slots:
+  /** Ask the running application to stop */
+  void Stop()
+    {
+    m_Application->Stop();
+    }
+
 protected:
   void run() override;
 
@@ -139,6 +146,8 @@ signals:
 
   void UpdateGui();
 
+  void Stop();
+
 protected slots:
   /**
    * \brief Slot called when execution is requested (e.g. by
diff --git a/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetView.h b/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetView.h
index 5a004af2dc56df5e5a94d8510df22b60d7e822a2..0f1ac8a3455cd5487c7af6b2dfd45b3c25069984 100644
--- a/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetView.h
+++ b/Modules/Wrappers/QtWidget/include/otbWrapperQtWidgetView.h
@@ -22,75 +22,244 @@
 #define otbWrapperQtWidgetView_h
 
 #include <QtGui>
-#include <QObject>
 #include <QShortcut>
+
+//
+// OTB includes (sorted by alphabetic order)
 #ifndef Q_MOC_RUN  // See: https://bugreports.qt-project.org/browse/QTBUG-22829  //tag=QT4-boost-compatibility
+#include "otbWrapperApplication.h"
 #include "otbWrapperQtWidgetModel.h"
 #endif //tag=QT4-boost-compatibility
+#include "OTBQtWidgetExport.h"
 
 namespace otb
 {
 namespace Wrapper
 {
 
-/** \class QtWidgetView
- * \brief
+/*****************************************************************************/
+/* CLASS DEFINITION SECTION                                                  */
+
+/**
+ * \class QtWidgetView
  *
  * \ingroup OTBQtWidget
+ *
+ * \brief WIP.
  */
-class OTBQtWidget_EXPORT QtWidgetView : public QWidget
+
+class OTBQtWidget_EXPORT QtWidgetView :
+    public QWidget
 {
+  /*-[ QOBJECT SECTION ]-----------------------------------------------------*/
+
   Q_OBJECT
+
+  Q_PROPERTY( bool isClosable
+	      READ IsClosable
+	      WRITE SetClosable );
+
+  /*-[ PUBLIC SECTION ]------------------------------------------------------*/
+
+//
+// Public methods.
 public:
-  QtWidgetView(Application* app);
+
+  /**
+   */
+  static char const * const OBJECT_NAME;
+
+  /** \brief Constructor. */
+  QtWidgetView( const otb::Wrapper::Application::Pointer & otbApp,
+		QWidget* p =0,
+		Qt::WindowFlags flags =0 );
+
+  /** \brief Destructor. */
   ~QtWidgetView() override;
 
+  /** \brief Gui Creation. */
   void CreateGui();
 
-  QtWidgetModel* GetModel()
+  /** \brief Model Accessor */
+  inline otb::Wrapper::QtWidgetModel* GetModel()
   {
     return m_Model;
   }
 
+  /**
+   * \return The OTB-application pointer of this view.
+   */
+  //~ otb::Wrapper::Application::ConstPointer GetApplication() const
+  //~ {
+    //~ return otb::ConstCast< otb::Wrapper::Application >(
+      //~ m_Application
+    //~ );
+  //~ }
+
+  /**
+   */
+  inline bool IsClosable() const;
+
+  /*-[ PUBLIC SLOTS SECTION ]------------------------------------------------*/
+
+//
+// Public SLOTS.
 public slots:
-  void CloseSlot();
-  void UnhandledException(QString message);
-  void OnExceptionRaised(QString message);
 
-private slots:
-  void UpdateMessageAfterExecuteClicked();
-  void UpdateMessageAfterExecution(int status);
-  void UpdateMessageAfterApplicationReady(bool val);
+  /*-[ SIGNALS SECTION ]-----------------------------------------------------*/
 
+//
+// Signals.
 signals:
   void QuitSignal();
+  void ExecuteAndWriteOutput();
+  void Stop();
 
 
+  /*-[ PROTECTED SECTION ]---------------------------------------------------*/
+
+//
+// Protected methods.
+protected:
+
+  bool IsRunning();
+
+  virtual QWidget* CreateInputWidgets();
+
+  //
+  // QWidget overloads.
+
+  void closeEvent( QCloseEvent * event ) override;
+
+//
+// Protected attributes.
+protected:
+
+  /** Html section for 'Done' icon */
+  std::string m_IconPathDone;
+
+  /** Html section for 'Failed' icon */
+  std::string m_IconPathFailed;
+
+protected slots:
+
+  /**
+   */
+  void OnExecButtonClicked();
+
+  void UnhandledException(QString message);
+  void OnExceptionRaised( QString what );
+  
+  /*-[ PRIVATE SECTION ]-----------------------------------------------------*/
+
+//
+// Private methods.
 private:
+
   QtWidgetView(const QtWidgetView&); //purposely not implemented
   void operator=(const QtWidgetView&); //purposely not implemented
 
   QWidget* CreateFooter();
 
-  QWidget* CreateInputWidgets();
-
   QWidget* CreateDoc();
 
-  Application::Pointer m_Application;
 
-  QtWidgetModel* m_Model;
+//
+// Private attributes.
 
-  QTextEdit *m_LogText;
-  QTabWidget *m_TabWidget;
+private:
+
+  otb::Wrapper::QtWidgetModel* m_Model;
 
   QPushButton* m_ExecButton;
   QPushButton* m_QuitButton;
   QShortcut* m_QuitShortcut;
   QLabel* m_Message;
+  QTextEdit *m_LogText;
+  QTabWidget *m_TabWidget;
+
+  bool m_IsClosable : 1;
+
+  bool m_IsRunning;
+
+  /*-[ PRIVATE SLOTS SECTION ]-----------------------------------------------*/
+
+//
+// Slots.
+private slots:
+  void UpdateMessageAfterExecution(int status);
+  void UpdateMessageAfterApplicationReady(bool val);
+
+  /**
+   */
+  inline void OnProgressReportBegin();
+
+  /**
+   */
+  inline void OnProgressReportEnd( int status );
+
+  /**
+   */
+  inline void SetClosable( bool );
+
 };
 
+} // end namespace 'Wrapper'
 
+} // end namespace 'otb'
+
+/*****************************************************************************/
+/* INLINE SECTION                                                            */
+
+namespace otb
+{
+
+namespace Wrapper
+{
+
+/*****************************************************************************/
+inline
+bool
+QtWidgetView
+::IsClosable() const
+{
+  return m_IsClosable;
 }
+
+/*****************************************************************************/
+inline
+void
+QtWidgetView
+::SetClosable( bool enabled )
+{
+  m_IsClosable = enabled;
+
+  setEnabled( true );
+
+  if( m_QuitButton!=NULL )
+    m_QuitButton->setEnabled( m_IsClosable );
 }
 
+/*******************************************************************************/
+inline
+void
+QtWidgetView
+::OnProgressReportBegin()
+{
+  SetClosable( false );
+}
+
+/*******************************************************************************/
+inline
+void
+QtWidgetView
+::OnProgressReportEnd( int )
+{
+  SetClosable( true );
+}
+
+} // end namespace 'Wrapper'
+
+} // end namespace 'otb'
+
 #endif
diff --git a/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetModel.cxx b/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetModel.cxx
index a0d61138d72e424fd282b89c1daeb9da67bb9fe6..d19102fa8fe5bd21479caf4724941c7da5fd130a 100644
--- a/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetModel.cxx
+++ b/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetModel.cxx
@@ -200,7 +200,7 @@ QtWidgetModel
     }
 
   // launch the output image writing
-  AppliThread * taskAppli = new AppliThread( m_Application );
+  AppliThread *taskAppli = new AppliThread( m_Application );
 
   QObject::connect(
     taskAppli,
@@ -225,10 +225,19 @@ QtWidgetModel
     SLOT( deleteLater() )
   );
 
+  QObject::connect(
+    this,
+    SIGNAL( Stop() ),
+    taskAppli,
+    SLOT( Stop() )
+  );
+
   // Tell the Progress Reporter to begin
   emit SetProgressReportBegin();
 
   taskAppli->Execute();
+
+  emit SetApplicationReady(true);
 }
 
 void
@@ -322,6 +331,10 @@ AppliThread
     m_Application->GetLogger()->Fatal(string("Cannot open image ") + err.m_Filename + string(". ") + err.GetDescription() + string("\n"));
     emit ExceptionRaised( err.what() );
   }
+  catch(itk::ProcessAborted& /*err*/)
+  {
+    m_Application->GetLogger()->Info("Processing aborted\n");
+  }
   catch(itk::ExceptionObject& err)
   {
     m_Application->GetLogger()->Debug("Caught itk::ExceptionObject during application execution:\n");
diff --git a/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetView.cxx b/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetView.cxx
index 39c9d80bd4f84283c9878a6c985404ad9e37dfaa..f689d59d81183f5c54173b29afdd2307403c1bbe 100644
--- a/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetView.cxx
+++ b/Modules/Wrappers/QtWidget/src/otbWrapperQtWidgetView.cxx
@@ -20,31 +20,77 @@
 
 #include "otbWrapperQtWidgetView.h"
 
+#include <functional>
+
 #include "otbWrapperQtWidgetParameterGroup.h"
 #include "otbWrapperQtWidgetParameterFactory.h"
-#include "otbWrapperQtWidgetProgressReport.h"
-#include "otbWrapperOutputImageParameter.h"
-#include "otbWrapperChoiceParameter.h"
-#include "otbWrapperQtWidgetSimpleProgressReport.h"
 #include "otbWrapperApplicationHtmlDocGenerator.h"
-
-#include "itksys/SystemTools.hxx"
-
+#include "otbWrapperOutputFilenameParameter.h"
+#include "otbWrapperOutputVectorDataParameter.h"
+#include "otbWrapperQtWidgetSimpleProgressReport.h"
 
 namespace otb
 {
 namespace Wrapper
 {
-
-QtWidgetView::QtWidgetView(Application* app)
+/*
+  TRANSLATOR mvd::Wrapper::QtWidgetView
+
+  Necessary for lupdate to be aware of C++ namespaces.
+
+  Context comment for translator.
+*/
+
+/*****************************************************************************/
+/* CONSTANTS                                                                 */
+
+char const * const
+QtWidgetView
+::OBJECT_NAME = "otb::Wrapper::QtWidgetView";
+
+/*****************************************************************************/
+/* CLASS IMPLEMENTATION SECTION                                              */
+/*****************************************************************************/
+QtWidgetView::QtWidgetView( const otb::Wrapper::Application::Pointer & otbApp,
+		QWidget* p,
+		Qt::WindowFlags flags ) :
+  QWidget( p, flags ),
+  m_IconPathDone(""),
+  m_IconPathFailed(""),
+  m_Model( NULL ),
+  m_ExecButton( NULL ),
+  m_QuitButton( NULL ),
+  m_Message( NULL ),
+  m_LogText( NULL ),
+  m_TabWidget( NULL ),
+  m_IsClosable( true ),
+  m_IsRunning(false)
 {
-  m_Model = new QtWidgetModel(app);
-  m_Application = app;
+  setObjectName( QtWidgetView::OBJECT_NAME );
+
+  m_Model = new otb::Wrapper::QtWidgetModel( otbApp );
+  m_QuitShortcut = new QShortcut(QKeySequence("Ctrl+Q"), this);
+
+  QObject::connect(
+    m_Model, SIGNAL( SetProgressReportBegin() ),
+    this, SLOT( OnProgressReportBegin() )
+  );
+
+  QObject::connect(
+    m_Model, SIGNAL( SetProgressReportDone( int ) ),
+    this, SLOT( OnProgressReportEnd( int ) )
+  );
+
+  QObject::connect(
+    m_Model, SIGNAL( ExceptionRaised( QString ) ),
+    this, SLOT( OnExceptionRaised( QString ) )
+  );
 }
 
 QtWidgetView::~QtWidgetView()
 {
   delete m_Model;
+  m_Model = NULL;
 }
 
 void QtWidgetView::CreateGui()
@@ -53,71 +99,74 @@ void QtWidgetView::CreateGui()
   QVBoxLayout *mainLayout = new QVBoxLayout();
   m_TabWidget = new QTabWidget();
 
-  m_TabWidget->addTab(CreateInputWidgets(), "Parameters");
+  m_TabWidget->addTab(CreateInputWidgets(), tr("Parameters"));
   m_LogText = new QTextEdit();
   connect( m_Model->GetLogOutput(), SIGNAL(NewContentLog(QString)), m_LogText, SLOT(append(QString) ) );
-  m_TabWidget->addTab(m_LogText, "Logs");
-  QtWidgetProgressReport* prog =  new QtWidgetProgressReport(m_Model);
-  prog->SetApplication(m_Application);
-  m_TabWidget->addTab(prog, "Progress");
-  m_TabWidget->addTab(CreateDoc(), "Documentation");
+  m_TabWidget->addTab(m_LogText, tr("Logs"));
+  m_TabWidget->addTab(CreateDoc(), tr("Documentation"));
   mainLayout->addWidget(m_TabWidget);
 
-  m_Message = new QLabel("<center><font color=\"#FF0000\">Select parameters</font></center>");
-  connect( m_Model, SIGNAL(SetApplicationReady(bool)), this, SLOT(UpdateMessageAfterApplicationReady(bool)) );
+  m_Message = new QLabel("<center><font color=\"#FF0000\">"+tr("Select parameters")+"</font></center>");
+  connect( m_Model, SIGNAL(SetApplicationReady(bool)), this, SLOT( UpdateMessageAfterApplicationReady(bool)) );
   connect( m_Model, SIGNAL(SetProgressReportDone(int)), this, SLOT(UpdateMessageAfterExecution(int)) );
   mainLayout->addWidget(m_Message);
 
-  QtWidgetSimpleProgressReport * progressReport =  new QtWidgetSimpleProgressReport(m_Model);
-  progressReport->SetApplication(m_Application);
+  otb::Wrapper::QtWidgetSimpleProgressReport * progressReport = new otb::Wrapper::QtWidgetSimpleProgressReport(m_Model);
+  progressReport->SetApplication(m_Model->GetApplication());
 
+  QWidget* footer = CreateFooter();
+   
   QHBoxLayout *footLayout = new QHBoxLayout;
   footLayout->addWidget(progressReport);
-  footLayout->addWidget(CreateFooter());
+  footLayout->addWidget(footer);
   mainLayout->addLayout(footLayout);
 
+  footLayout->setAlignment(footer, Qt::AlignBottom);
+
   QGroupBox *mainGroup = new QGroupBox();
   mainGroup->setLayout(mainLayout);
 
   QVBoxLayout  *finalLayout = new QVBoxLayout();
   finalLayout->addWidget(mainGroup);
 
-  connect( m_Model, SIGNAL(ExceptionRaised(QString)), this, SLOT(OnExceptionRaised(QString)) );
-
   // Make the final layout to the widget
   this->setLayout(finalLayout);
 }
 
-void QtWidgetView::UpdateMessageAfterExecuteClicked()
-{
-  m_Message->setText("<center><font color=\"#FF0000\">Running</font></center>");
-}
-
 void QtWidgetView::UpdateMessageAfterExecution(int status)
 {
   if (status >= 0)
     {
-    m_Message->setText("<center><font color=\"#00A000\">Done</font></center>");
+    m_Message->setText("<center>"+QString(m_IconPathDone.c_str())+
+      "<font color=\"#00A000\">"+tr("Done")+"</font></center>");
     }
   else
     {
-    m_Message->setText("<center><font color=\"#FF0000\">Failed</font></center>");
+    m_Message->setText("<center>"+QString(m_IconPathFailed.c_str())+
+      "<font color=\"#FF0000\">"+tr("Failed")+"</font></center>");
     }
+  m_ExecButton->setText(QObject::tr("Execute"));
+  m_IsRunning = false;
 }
 
 void QtWidgetView::UpdateMessageAfterApplicationReady( bool val )
 {
-  if(val == true)
-    m_Message->setText("<center><font color=\"#00A000\">Ready to run</font></center>");
-  else
-    m_Message->setText("<center><font color=\"#FF0000\">Select parameters</font></center>");
+  if(!m_IsRunning)
+    {
+    if(val == true)
+      m_Message->setText("<center><font color=\"#00A000\">"+tr("Ready to run")+"</font></center>");
+    else
+      m_Message->setText("<center><font color=\"#FF0000\">"+tr("Select parameters")+"</font></center>");
+    }
 }
 
 QWidget* QtWidgetView::CreateInputWidgets()
 {
   QScrollArea *scrollArea = new QScrollArea;
-  // Put the main group inside a scroll area
-  scrollArea->setWidget(QtWidgetParameterFactory::CreateQtWidget(m_Model->GetApplication()->GetParameterList(), m_Model));
+
+  scrollArea->setWidget( otb::Wrapper::QtWidgetParameterFactory::CreateQtWidget(
+      m_Model->GetApplication()->GetParameterList(),
+      m_Model));
   scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
   scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
   scrollArea->setWidgetResizable(true);
@@ -131,7 +180,7 @@ QWidget* QtWidgetView::CreateFooter()
   // an HLayout with two buttons : Execute and Quit
   QGroupBox *footerGroup = new QGroupBox;
   QHBoxLayout *footerLayout = new QHBoxLayout;
-
+ 
   footerGroup->setFixedHeight(40);
   footerGroup->setContentsMargins(0, 0, 0, 0);
   footerLayout->setContentsMargins(5, 5, 5, 5);
@@ -140,17 +189,17 @@ QWidget* QtWidgetView::CreateFooter()
   m_ExecButton->setDefault(true);
   m_ExecButton->setEnabled(false);
   m_ExecButton->setText(QObject::tr("Execute"));
-  connect( m_ExecButton, SIGNAL(clicked()), m_Model, SLOT(ExecuteAndWriteOutputSlot() ) );
-  connect( m_Model, SIGNAL(SetApplicationReady(bool)), m_ExecButton, SLOT(setEnabled(bool)) );
-  connect( m_ExecButton, SIGNAL(clicked()), this, SLOT(UpdateMessageAfterExecuteClicked() ) );
+  connect( m_Model, SIGNAL( SetApplicationReady( bool ) ), m_ExecButton, SLOT( setEnabled( bool ) ));
+  QObject::connect( m_ExecButton, SIGNAL( clicked() ), this, SLOT( OnExecButtonClicked() ));
+  QObject::connect( this, SIGNAL( ExecuteAndWriteOutput() ), m_Model, SLOT( ExecuteAndWriteOutputSlot() ));
+  QObject::connect( this, SIGNAL( Stop() ), m_Model, SIGNAL( Stop() ));
 
   m_QuitButton = new QPushButton(footerGroup);
   m_QuitButton->setText(QObject::tr("Quit"));
-  connect( m_QuitButton, SIGNAL(clicked()), this, SLOT(CloseSlot()) );
+  connect(m_QuitButton, SIGNAL( clicked() ), this, SLOT( close() ));
 
   // Add Ctrl-Q shortcut to quit
-  m_QuitShortcut = new QShortcut(QKeySequence("Ctrl+Q"), this);
-  connect( m_QuitShortcut, SIGNAL(activated()), this, SLOT(CloseSlot()) );
+  connect( m_QuitShortcut, SIGNAL(activated()), this, SLOT(close()) );
 
   // Put the buttons on the right
   footerLayout->addStretch();
@@ -170,7 +219,7 @@ QWidget* QtWidgetView::CreateDoc()
   QTextDocument * doc = new QTextDocument();
 
   std::string docContain;
-  ApplicationHtmlDocGenerator::GenerateDoc( m_Application, docContain, true);
+  otb::Wrapper::ApplicationHtmlDocGenerator::GenerateDoc( GetModel()->GetApplication(), docContain);
 
   doc->setHtml(docContain.c_str());
 
@@ -179,13 +228,49 @@ QWidget* QtWidgetView::CreateDoc()
   return text;
 }
 
-void QtWidgetView::CloseSlot()
+void QtWidgetView::closeEvent( QCloseEvent * e )
 {
-  // Close the widget
-  this->close();
+  assert( e!=NULL );
+
+  if( !IsClosable() )
+    {
+    assert( GetModel()->GetApplication() );
+
+    QMessageBox::warning(
+      this,
+      tr( "Warning!" ),
+      tr( "OTB-Application '%1' cannot be closed while running!")
+      .arg( GetModel()->GetApplication()->GetDocName() )
+    );
+
+    e->ignore();
+
+    return;
+    }
+
+  QWidget::closeEvent( e );
 
-  // Emit a signal to close any widget that this gui belonging to
   emit QuitSignal();
+
+  deleteLater();
+}
+
+void
+QtWidgetView
+::OnExecButtonClicked()
+{
+  if (m_IsRunning)
+    {
+    m_Message->setText("<center><font color=\"#FF0000\">"+tr("Cancelling")+"...</font></center>");
+    emit Stop();
+    }
+  else
+    {
+    m_IsRunning =  true;
+    m_Message->setText("<center><font color=\"#FF0000\">"+tr("Running")+"</font></center>");
+    m_ExecButton->setText(QObject::tr("Cancel"));
+    emit ExecuteAndWriteOutput();
+    }
 }
 
 void QtWidgetView::UnhandledException(QString message)
@@ -194,10 +279,16 @@ void QtWidgetView::UnhandledException(QString message)
   m_LogText->append(message);
 }
 
-void QtWidgetView::OnExceptionRaised(QString /*message*/)
+void QtWidgetView::OnExceptionRaised( QString /*message*/)
 {
   m_TabWidget->setCurrentIndex(1);
 }
 
+bool QtWidgetView::IsRunning()
+{
+  return m_IsRunning;
 }
-}
+
+} // end of namespace Wrapper
+} // end of namespace otb
+
diff --git a/Modules/Wrappers/SWIG/src/otbApplication.i b/Modules/Wrappers/SWIG/src/otbApplication.i
index c8b97c12e217b970a514dea5c1a248d6a89bb863..665b689fd17300b423490b77bace6c518edc5164 100644
--- a/Modules/Wrappers/SWIG/src/otbApplication.i
+++ b/Modules/Wrappers/SWIG/src/otbApplication.i
@@ -287,6 +287,8 @@ public:
 
   std::string GetProgressDescription() const;
 
+  void FreeRessources();
+
   itkSetStringMacro(DocName);
   itkGetStringMacro(DocName);
   itkSetStringMacro(DocLongDescription);
diff --git a/Packaging/README.md b/Packaging/README.md
index e845566c06f9bf557d35e8292c37cf05d97a9769..df83d58b21e469b8a3723b04c7efc6702ae7c32c 100644
--- a/Packaging/README.md
+++ b/Packaging/README.md
@@ -1 +1 @@
-README
+OTB recipes to build standalone binary packages for Windows/Linux/Mac OS X
diff --git a/Packaging/installer_files.cmake b/Packaging/installer_files.cmake
index 941f7f8cdfbf8caa17e8f52e3553a65bd25b6ab9..b864b74b7eacbfff0d65cb5ffbf94a26f1a7deff 100644
--- a/Packaging/installer_files.cmake
+++ b/Packaging/installer_files.cmake
@@ -22,11 +22,11 @@ macro(installer_files)
   #configure README from rst docs
   set(RSTDOC_DIR "${PACKAGE_OTB_SRC_DIR}/Documentation/Cookbook/rst")
   if(APPLE)
-    set(README_FILE ${RSTDOC_DIR}/Installation_Macx.txt)
+    set(README_FILE ${RSTDOC_DIR}/Installation_Macos.rst)
   elseif(LINUX) #not osx
-    set(README_FILE ${RSTDOC_DIR}/Installation_Linux.txt)
+    set(README_FILE ${RSTDOC_DIR}/Installation_Linux.rst)
   elseif(WIN32) #windows
-    set(README_FILE ${RSTDOC_DIR}/Installation_Windows.txt)
+    set(README_FILE ${RSTDOC_DIR}/Installation_Windows.rst)
   endif()
   configure_file("${README_FILE}" ${CMAKE_BINARY_DIR}/README )
   install(FILES ${CMAKE_BINARY_DIR}/README DESTINATION ${PKG_STAGE_DIR} )