diff --git a/Documentation/Cookbook/rst/recipes/python.rst b/Documentation/Cookbook/rst/recipes/python.rst
index f0b2e95f251d5e642a6eb6a1e6ad4c82328e703d..41306ac1ead88fee83e005cc9000ba3c25498b4b 100644
--- a/Documentation/Cookbook/rst/recipes/python.rst
+++ b/Documentation/Cookbook/rst/recipes/python.rst
@@ -173,6 +173,142 @@ implementation does not break it, for instance by using an internal
 writer to write intermediate data. In this case, execution should
 still be correct, but some intermediate data will be read or written.
 
+Interactions with OTB pipeline
+------------------------------
+
+[Since OTB 6.6]
+
+The application framework has been extended in order to provide ways to
+interact with the pipelines inside each application. It applies only to
+applications that use input or output images. Let's check what are the 
+functions added to the ``Application`` class. There are a lot of getter 
+functions:
+
++---------------------------------+---------------------------------------+
+| Function name                   | return value                          |
++=================================+=======================================+
+| ``GetImageOrigin(...)``         | origin of the image (physical position|
+|                                 | of the first pixel center)            |
++---------------------------------+---------------------------------------+
+| ``GetImageSpacing(...)``        | signed spacing of the image           |
++---------------------------------+---------------------------------------+
+| ``GetImageSize(...)``           | size of the LargestPossibleRegion     |
++---------------------------------+---------------------------------------+
+| ``GetImageNbBands(...)``        | number of components per pixel        |
++---------------------------------+---------------------------------------+
+| ``GetImageProjection(...)``     | Projection WKT string                 |
++---------------------------------+---------------------------------------+
+| ``GetImageKeywordlist(...)``    | Ossim keywordlist (sensor model)      |
++---------------------------------+---------------------------------------+
+| ``GetImageMetaData(...)``       | the entire MetaDataDictionary         |
++---------------------------------+---------------------------------------+
+| ``GetImageRequestedRegion(...)``| requested region                      |
++---------------------------------+---------------------------------------+
+| ``GetImageBasePixelType(...)``  | pixel type of the underlying          |
+|                                 | Image/VectorImage.                    |
++---------------------------------+---------------------------------------+
+
+All these getters functions use the following arguments:
+
+* ``key``: a string containing the key of the image parameter
+* ``idx``: an optional index (default is 0) that can be used to access ImageList
+  parameters transparently
+
+There is also a function to send orders to the pipeline:
+
+  ``PropagateRequestedRegion(key, region, idx=0)``: sets a given RequestedRegion
+  on the image and propagate it, returns the memory print estimation. This function
+  can be used to measure the requested portion of input images necessary to produce
+  an extract of the full output.
+
+Note: a requested region (like other regions in the C++ API of otb::Image) is 
+just a pair of an image index and a size, that define a rectangular extract of
+the full image.
+
+This set of function has been used to enhance the bridge between OTB images
+and Numpy arrays. There are now import and export functions available in
+Python that preserve the metadata of the image during conversions to Numpy
+arrays:
+
+* ``ExportImage(self, key)``: exports an output image parameter into a Python
+  dictionary.
+* ``ImportImage(self, key, dict, index=0)``: imports the image from a Python
+  dictionary into an image parameter (as a monoband image).
+* ``ImportVectorImage(self, key, dict, index=0)``: imports the image from a
+  Python dictionary into an image parameter (as a multiband image).
+
+The Python dictionary used has the following entries:
+
+  * ``'array'``: the Numpy array containing the pixel buffer
+  * ``'origin'``: origin of the image
+  * ``'spacing'``: signed spacing of the image
+  * ``'size'``: full size of the image
+  * ``'region'``: region of the image present in the buffer
+  * ``'metadata'``: metadata dictionary (contains projection, sensor model,...)
+
+Now some basic Q&A about this interface:
+
+    Q: What portion of the image is exported to Numpy array?
+    A: By default, the whole image is exported. If you had a non-empty requested
+    region (the result of calling PropagateRequestedRegion()), then this region
+    is exported.
+    
+    Q: What is the difference between ImportImage and ImportVectorImage?
+    A: The first one is here for Applications that expect a monoband otb::Image.
+    In most cases, you will use the second one: ImportVectorImage.
+    
+    Q: What kind of object are there in this dictionary export?
+    A: The array is a numpy.ndarray. The other fields are wrapped
+    objects from the OTB library but you can interact with them in a
+    Python way: they support ``len()`` and ``str()`` operator, as well as 
+    bracket operator ``[]``. Some of them also have a ``keys()`` function just like
+    dictionaries.
+    
+This interface allows you to export OTB images (or extracts) to Numpy array,
+process them  by other means, and re-import them with preserved metadatas. Please
+note that this is different from an in-memory connection.
+
+Here is a small example of what can be done:
+
+.. code-block:: python
+
+  import otbApplication as otb
+  
+  # Create a smoothing application
+  app = otb.Registry.CreateApplication("Smoothing")
+  app.SetParameterString("in",argv[1])
+  
+  # only call Execute() to setup the pipeline, not ExecuteAndWriteOutput() which would
+  # run it and write the output image
+  app.Execute()
+
+  # Setup a special requested region
+  myRegion = otb.itkRegion()
+  myRegion['size'][0] = 20
+  myRegion['size'][1] = 25
+  myRegion['index'].Fill(10)
+  ram = app.PropagateRequestedRegion("out",myRegion)
+  
+  # Check the requested region on the input image
+  print(app.GetImageRequestedRegion("in"))
+  
+  # Create a ReadImageInfo application
+  app2 = otb.Registry.CreateApplication("ReadImageInfo")
+  
+  # export "out" from Smoothing and import it as "in" in ReadImageInfo
+  ex = app.ExportImage("out")
+  app2.ImportVectorImage("in", ex)
+  app2.Execute()
+  
+  # Check the result of ReadImageInfo
+  someKeys = ['sizex', 'sizey', 'spacingx', 'spacingy', 'sensor', 'projectionref']
+  for key in someKeys:
+    print(key + ' : ' + str(app2.GetParameterValue(key)) )
+  
+  # Only a portion of "out" was exported but ReadImageInfo is still able to detect the 
+  # correct full size of the image
+
+
 Corner cases
 ------------
 
diff --git a/Modules/Core/ImageBase/include/otbImage.h b/Modules/Core/ImageBase/include/otbImage.h
index 109a5571436888420cfa87cf9178d95637e0c482..73d3e271add0bb7acd772e6c8b4356cd04f97267 100644
--- a/Modules/Core/ImageBase/include/otbImage.h
+++ b/Modules/Core/ImageBase/include/otbImage.h
@@ -49,18 +49,18 @@ namespace internal
   }
 
   template < class InputImage , typename SpacingType >
-  void SetSignedSpacing( InputImage input , SpacingType spacing )
+  void SetSignedSpacing( InputImage *input , SpacingType spacing )
   {
     // TODO check for spacing size ==> error
     typename InputImage::DirectionType direction = input->GetDirection();
-    for ( unsigned int i = 0 ; i < InputImage::VImageDimension ; i++ )
+    for ( unsigned int i = 0 ; i < InputImage::ImageDimension ; i++ )
       {
       // TODO check if spacing[i] = 0 ==> error
       if ( spacing[ i ] < 0 )
         {
         if ( direction[i][i] > 0 )
           {
-          for ( unsigned int j = 0 ; j < InputImage::VImageDimension ; j++ )
+          for ( unsigned int j = 0 ; j < InputImage::ImageDimension ; j++ )
             {
             direction[j][i] = - direction[j][i];
             }
diff --git a/Modules/Core/Streaming/include/otbPipelineMemoryPrintCalculator.h b/Modules/Core/Streaming/include/otbPipelineMemoryPrintCalculator.h
index 19c65071424f832ee7e6e239c05adcd142c56a1f..bda15b231d1f51cb876a8539b78371eff9c79f02 100644
--- a/Modules/Core/Streaming/include/otbPipelineMemoryPrintCalculator.h
+++ b/Modules/Core/Streaming/include/otbPipelineMemoryPrintCalculator.h
@@ -114,7 +114,7 @@ public:
   itkSetObjectMacro(DataToWrite, DataObjectType);
 
   /** Compute pipeline memory print */
-  void Compute();
+  void Compute(bool propagate=true);
 
   /** Const conversion factor */
   static const double ByteToMegabyte;
diff --git a/Modules/Core/Streaming/src/otbPipelineMemoryPrintCalculator.cxx b/Modules/Core/Streaming/src/otbPipelineMemoryPrintCalculator.cxx
index 403c9d38674047805593342aa9cd3363c23d29a8..4d629c4c6932fbf9ac8e108f6d92c938b2a6b64f 100644
--- a/Modules/Core/Streaming/src/otbPipelineMemoryPrintCalculator.cxx
+++ b/Modules/Core/Streaming/src/otbPipelineMemoryPrintCalculator.cxx
@@ -71,15 +71,18 @@ PipelineMemoryPrintCalculator
 
 void
 PipelineMemoryPrintCalculator
-::Compute()
+::Compute(bool propagate)
 {
   // Clear the visited process objects set
   m_VisitedProcessObjects.clear();
 
   // Dry run of pipeline synchronisation
-  m_DataToWrite->UpdateOutputInformation();
-  m_DataToWrite->SetRequestedRegionToLargestPossibleRegion();
-  m_DataToWrite->PropagateRequestedRegion();
+  if (propagate)
+    {
+    m_DataToWrite->UpdateOutputInformation();
+    m_DataToWrite->SetRequestedRegionToLargestPossibleRegion();
+    m_DataToWrite->PropagateRequestedRegion();
+    }
 
   // Get the source process object
   ProcessObjectType * source = m_DataToWrite->GetSource();
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
index 2686bb0e77c37c4a2ef3a756dfe9cfb95db81c47..f840418c3cf41522683483cebe35446206104ddb 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
@@ -478,7 +478,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * InputImageParameter
    */
-  void SetParameterInputImage(std::string parameter, InputImageParameter::ImageBaseType * inputImage);
+  void SetParameterInputImage(std::string parameter, ImageBaseType * inputImage);
 
   /**
    * Get the output image parameter as an ImageBase * instead
@@ -489,7 +489,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * OutputImageParameter
    */
-  OutputImageParameter::ImageBaseType * GetParameterOutputImage(std::string parameter);
+  ImageBaseType * GetParameterOutputImage(std::string parameter);
 
   /**
    * Set the input complex image parameter as an ImageBase * instead
@@ -500,7 +500,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * ComplexInputImageParameter
    */
-  void SetParameterComplexInputImage(std::string parameter, ComplexInputImageParameter::ImageBaseType * inputImage);
+  void SetParameterComplexInputImage(std::string parameter, ImageBaseType * inputImage);
 
   /**
    * Get the complex output image parameter as an ImageBase * instead
@@ -511,7 +511,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * ComplexOutputImageParameter
    */
-  ComplexOutputImageParameter::ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
+  ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
 
   /**
    * Add an image to an InputImageList parameter as an ImageBase
@@ -522,7 +522,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * InputImageList parameter
    */
-  void AddImageToParameterInputImageList(std::string parameter, InputImageListParameter::ImageBaseType * img);
+  void AddImageToParameterInputImageList(std::string parameter, ImageBaseType * img);
 
   /**
    * Set the nth image of an InputImageList parameter as an ImageBase pointer
@@ -534,7 +534,7 @@ public:
    * \throw itk::Exception if parameter is not found or not an
    * InputImageList parameter or if id is out of bounds
    */
-  void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, InputImageListParameter::ImageBaseType * img);
+  void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, ImageBaseType * img);
 
 /**
    * Add a value to a parameter list as a string
@@ -847,6 +847,73 @@ public:
     this->SetDocLink(link);
   }
 
+  /** Get the origin of the image parameter 'key'. The optional 'idx' allows
+   * to select the image in an InputImageList. */
+  ImageBaseType::PointType GetImageOrigin(const std::string & key, unsigned int idx = 0);
+
+  /** Get the spacing of the image parameter 'key'. The optional 'idx' allows to
+   *  select the image in an InputImageList. We use the signed spacing convention. */
+  ImageBaseType::SpacingType GetImageSpacing(const std::string & key, unsigned int idx = 0);
+
+  /** Get the size of the image parameter 'key'. The optional 'idx' allows to
+   * select the image in an InputImageList. It corresponds to the size of LargestPossibleRegion*/
+  ImageBaseType::SizeType GetImageSize(const std::string & key, unsigned int idx = 0);
+
+  /** Get the number of bands in the image parameter 'key'. The optional 'idx'
+   * allows to select the image in an InputImageList.*/
+  unsigned int GetImageNbBands(const std::string & key, unsigned int idx = 0);
+
+  /** Get the projection of the image parameter 'key'. The optional 'idx' allows
+   *  to select the image in an InputImageList.*/
+  std::string GetImageProjection(const std::string & key, unsigned int idx = 0);
+
+  /** Get the keywordlist of the image parameter 'key'. The optional 'idx'
+   * allows to select the image in an InputImageList.*/
+  otb::ImageKeywordlist GetImageKeywordlist(const std::string & key, unsigned int idx = 0);
+
+  /** Set the requested region on the image parameter 'key' and propagate it.
+   *  The returned value is an estimate of the RAM usage (in Bytes) to process
+   *  this region. It should be assumed that the index of the largest possible
+   *  region starts at (0,0). The optional 'idx' allows to select the image in
+   *  an InputImageList*/
+  unsigned long PropagateRequestedRegion(const std::string & key, ImageBaseType::RegionType region, unsigned int idx = 0);
+
+  /** Get the requested region of the image parameter 'key'. The optional 'idx'
+   * allows to select the image in an InputImageList. It should be assumed that
+   * the index of the largest possible region starts at (0,0).*/
+  ImageBaseType::RegionType GetImageRequestedRegion(const std::string & key, unsigned int idx = 0);
+
+  /** Returns a copy of the metadata dictionary of the image */
+  itk::MetaDataDictionary GetImageMetaData(const std::string & key, unsigned int idx = 0);
+
+  /** Find out what is the pixel type from an image parameter
+   *  This function assumes that the underlying object is either an otb::Image
+   *  or an otb::VectorImage. The optional 'idx' allows to access InputImageList.
+   */
+  ImagePixelType GetImageBasePixelType(const std::string & key, unsigned int idx = 0);
+
+  /** Return the image from parameter 'key' as a base type. The optional 'idx'
+   *  allows to access InputImageList.
+   *
+   *  Works on parameters:
+   *  \li ParameterType_InputImage
+   *  \li ParameterType_InputImageList
+   *  \li ParameterType_OutputImage
+   *  \li ParameterType_ComplexInputImage
+   *  \li ParameterType_ComplexOutputImage
+   */
+  ImageBaseType* GetParameterImageBase(const std::string & key, unsigned int idx = 0);
+
+  /** Set the image in parameter 'key' as a base type. The optional 'idx'
+   *  allows to access InputImageList.
+   *
+   *  Works on parameters:
+   *  \li ParameterType_InputImage
+   *  \li ParameterType_InputImageList
+   *  \li ParameterType_ComplexInputImage
+   */
+  void SetParameterImageBase(const std::string & key, ImageBaseType* img, unsigned int idx = 0);
+
 protected:
   /** Constructor */
   Application();
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.h
index 0c9fdfe7e7fafb8a504ab04817ebea0e1948a508..6cf2b6c34cc055c04bf271f941b822b197495595 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.h
@@ -44,8 +44,6 @@ public:
   typedef itk::SmartPointer<Self>       Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
 
-  typedef itk::ImageBase<2> ImageBaseType;
-
   /** Defining ::New() static method */
   itkNewMacro(Self);
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.txx b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.txx
index 92e8dfd32e135ecc522a178f90a2be8fd3e1386a..86dd38fdc9993cf66f6c4a92b21b5dc9df541427 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.txx
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexInputImageParameter.txx
@@ -132,6 +132,10 @@ ComplexInputImageParameter::GetImage()
     }
 }
 
+/** declare a specialization for ImageBaseType */
+template <>
+ImageBaseType*
+ComplexInputImageParameter::GetImage();
 
 template <class TComplexInputImage, class TOutputImage>
 TOutputImage*
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexOutputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexOutputImageParameter.h
index c43b21cdefeef818490ac822bc271540304af341..2dcfa3ddd20fb68606b03af241f917cd85b064f9 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexOutputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperComplexOutputImageParameter.h
@@ -44,8 +44,6 @@ public:
   typedef itk::SmartPointer<Self>       Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
 
-  typedef itk::ImageBase<2> ImageBaseType;
-
   /** Defining ::New() static method */
   itkNewMacro(Self);
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageListParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageListParameter.h
index 889e6d8df2bd02d831a1c26a571475407e6b6f86..914ab7b249597bc8fbd035ae88a71c4b1903a8eb 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageListParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageListParameter.h
@@ -48,8 +48,6 @@ public:
   typedef itk::SmartPointer< Self > Pointer;
   typedef itk::SmartPointer< const Self > ConstPointer;
 
-  typedef itk::ImageBase< 2 > ImageBaseType;
-
   /** Defining ::New() static method */
   itkNewMacro( Self );
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
index a12dba6efe980c8ae35d31a66b02df2d13049d19..722dbeead7ab40c868ec1fc0732292a9f6ab6b55 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
@@ -44,8 +44,6 @@ public:
   typedef itk::SmartPointer<Self>       Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
 
-  typedef itk::ImageBase<2> ImageBaseType;
-
   /** Defining ::New() static method */
   itkNewMacro(Self);
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.txx b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.txx
index 814695045a90df698c862b0a361fe78683ebaa7d..72a3794cddc43ae99c4aef6d2f362b89b8074477 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.txx
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.txx
@@ -215,6 +215,10 @@ InputImageParameter::GetImage()
     }
 }
 
+/** declare a specialization for ImageBaseType */
+template <>
+ImageBaseType*
+InputImageParameter::GetImage();
 
 template <class TInputImage, class TOutputImage>
 TOutputImage*
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperMetaDataHelper.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperMetaDataHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..36274a5a08de34996f70ac9e6eb17121b81fa963
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperMetaDataHelper.h
@@ -0,0 +1,130 @@
+/*
+ * 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 otbWrapperMetaDataHelper_h
+#define otbWrapperMetaDataHelper_h
+
+#include "otbMetaDataKey.h"
+#include "otbImageKeywordlist.h"
+#include "otbVectorDataKeywordlist.h"
+#include "itkMetaDataDictionary.h"
+#include "OTBApplicationEngineExport.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+/**
+ * \namespace MetaDataHelper
+ *
+ * \brief Contains small helper functions to manipulate itk::MetaDataDictionary
+ *
+ * These functions are only here to instanciate the different template function that
+ * allow to get/set values in MetaDataDictionary.
+ *
+ */
+namespace MetaDataHelper
+{
+
+  enum class MDType
+  {
+    String,
+    Int,
+    Double,
+    GCP,
+    Vector,
+    ImageKWL,
+    VectorDataKWL,
+    BoolVector
+  };
+
+  OTBApplicationEngine_EXPORT MDType GetType(const std::string &val);
+
+  OTBApplicationEngine_EXPORT std::string GetString(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetString(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const std::string &val);
+
+  OTBApplicationEngine_EXPORT unsigned int GetInt(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetInt(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    unsigned int val);
+
+  OTBApplicationEngine_EXPORT double GetDouble(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetDouble(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    double val);
+
+  OTBApplicationEngine_EXPORT otb::OTB_GCP GetGCP(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetGCP(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::OTB_GCP &val);
+
+  OTBApplicationEngine_EXPORT otb::MetaDataKey::VectorType GetVector(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetVector(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::MetaDataKey::VectorType &val);
+
+  OTBApplicationEngine_EXPORT otb::ImageKeywordlist GetImageKWL(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetImageKWL(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::ImageKeywordlist &val);
+
+  OTBApplicationEngine_EXPORT otb::VectorDataKeywordlist GetVectorDataKWL(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetVectorDataKWL(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::VectorDataKeywordlist &val);
+
+  OTBApplicationEngine_EXPORT otb::MetaDataKey::BoolVectorType GetBoolVector(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key);
+  OTBApplicationEngine_EXPORT void SetBoolVector(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::MetaDataKey::BoolVectorType &val);
+
+} // end of namespace MetaDataHelper
+
+} // end of namespace Wrapper
+} // end of namespace otb
+
+#endif
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
index aab831aba8bc42d530fbcc114e810584803ef9e5..b9bc451c3b3b9a59437ac306cf48929e9459d734 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
@@ -45,8 +45,6 @@ public:
   typedef itk::SmartPointer<Self>       Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
 
-  typedef itk::ImageBase<2> ImageBaseType;
-
   /** Defining ::New() static method */
   itkNewMacro(Self);
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperTypes.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperTypes.h
index a27e22508403dc4fed5069571f16991ea9a07310..bf51898aa92afed9ebad8929ba74ae403655e929 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperTypes.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperTypes.h
@@ -154,6 +154,8 @@ typedef otb::ObjectList<VectorDataType> VectorDataListType;
 typedef otb::ObjectList<FloatVectorImageType> FloatVectorImageListType;
 typedef otb::ObjectList<FloatImageType>       FloatImageListType;
 
+typedef itk::ImageBase<2> ImageBaseType;
+
 
 } // end namespace Wrapper
 } // end namespace otb
diff --git a/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt b/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
index 115c5a772bc146af0c87c8123920e90a4f33f1bf..4b665b6f97843fecb8e4d192949ce1316626c42e 100644
--- a/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
+++ b/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
@@ -57,6 +57,7 @@ set( OTBApplicationEngine_SRC
   otbWrapperAbstractParameterList.cxx
   otbWrapperParameterList.cxx
   otbWrapperBoolParameter.cxx
+  otbWrapperMetaDataHelper.cxx
   )
 
 add_library(OTBApplicationEngine ${OTBApplicationEngine_SRC})
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
index 5c597e94d233d22461c20b69a7f81308c754472e..5f20a11ace33f79f904a2810a7c19f5571d4142f 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
@@ -1223,7 +1223,7 @@ Application
   return ret;
 }
 
-void Application::SetParameterInputImage(std::string parameter, InputImageParameter::ImageBaseType * inputImage)
+void Application::SetParameterInputImage(std::string parameter, ImageBaseType * inputImage)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1239,7 +1239,7 @@ void Application::SetParameterInputImage(std::string parameter, InputImageParame
     }
 }
 
-OutputImageParameter::ImageBaseType * Application::GetParameterOutputImage(std::string parameter)
+ImageBaseType * Application::GetParameterOutputImage(std::string parameter)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1256,7 +1256,7 @@ OutputImageParameter::ImageBaseType * Application::GetParameterOutputImage(std::
 }
 
 
-void Application::SetParameterComplexInputImage(std::string parameter, ComplexInputImageParameter::ImageBaseType * inputImage)
+void Application::SetParameterComplexInputImage(std::string parameter, ImageBaseType * inputImage)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1272,7 +1272,7 @@ void Application::SetParameterComplexInputImage(std::string parameter, ComplexIn
     }
 }
 
-ComplexOutputImageParameter::ImageBaseType * Application::GetParameterComplexOutputImage(std::string parameter)
+ImageBaseType * Application::GetParameterComplexOutputImage(std::string parameter)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1288,7 +1288,7 @@ ComplexOutputImageParameter::ImageBaseType * Application::GetParameterComplexOut
     }
 }
 
-void Application::AddImageToParameterInputImageList(std::string parameter, InputImageListParameter::ImageBaseType * img)
+void Application::AddImageToParameterInputImageList(std::string parameter, ImageBaseType * img)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1305,7 +1305,7 @@ void Application::AddImageToParameterInputImageList(std::string parameter, Input
 
 }
 
-void Application::SetNthParameterInputImageList(std::string parameter, const unsigned int &id, InputImageListParameter::ImageBaseType * img)
+void Application::SetNthParameterInputImageList(std::string parameter, const unsigned int &id, ImageBaseType * img)
 {
   Parameter* param = GetParameterByKey(parameter);
 
@@ -1747,5 +1747,217 @@ double Application::GetLastExecutionTiming() const
   return m_Chrono.GetElapsedMilliseconds() / 1000.0;
 }
 
+ImageBaseType::PointType
+Application::GetImageOrigin(const std::string & key, unsigned int idx)
+{
+  return this->GetParameterImageBase(key, idx)->GetOrigin();
+}
+
+ImageBaseType::SpacingType
+Application::GetImageSpacing(const std::string & key, unsigned int idx)
+{
+  return otb::internal::GetSignedSpacing(this->GetParameterImageBase(key, idx));
+}
+
+ImageBaseType::SizeType
+Application::GetImageSize(const std::string & key, unsigned int idx)
+{
+  return this->GetParameterImageBase(key, idx)->GetLargestPossibleRegion().GetSize();
+}
+
+unsigned int
+Application::GetImageNbBands(const std::string & key, unsigned int idx)
+{
+  return this->GetParameterImageBase(key, idx)->GetNumberOfComponentsPerPixel();
+}
+
+std::string
+Application::GetImageProjection(const std::string & key, unsigned int idx)
+{
+  std::string proj;
+  const itk::MetaDataDictionary& dict =
+    this->GetParameterImageBase(key, idx)->GetMetaDataDictionary();
+
+  if (!dict.HasKey(MetaDataKey::ProjectionRefKey))
+    return std::string("");
+
+  itk::ExposeMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, proj);
+  return proj;
+}
+
+otb::ImageKeywordlist
+Application::GetImageKeywordlist(const std::string & key, unsigned int idx)
+{
+  ImageKeywordlist kwl;
+  const itk::MetaDataDictionary& dict =
+    this->GetParameterImageBase(key, idx)->GetMetaDataDictionary();
+
+  if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
+    itk::ExposeMetaData<ImageKeywordlist>(dict, MetaDataKey::OSSIMKeywordlistKey, kwl);
+
+  return kwl;
+}
+
+unsigned long
+Application::PropagateRequestedRegion(const std::string & key, ImageBaseType::RegionType region, unsigned int idx)
+{
+  ImageBaseType* image = this->GetParameterImageBase(key, idx);
+  ImageBaseType::RegionType largest = image->GetLargestPossibleRegion();
+  ImageBaseType::RegionType requested = region;
+  requested.SetIndex(0, requested.GetIndex(0) + largest.GetIndex(0));
+  requested.SetIndex(1, requested.GetIndex(1) + largest.GetIndex(1));
+  image->SetRequestedRegion(requested);
+  image->PropagateRequestedRegion();
+  // estimate RAM usage
+  otb::PipelineMemoryPrintCalculator::Pointer memoryPrintCalculator =
+    otb::PipelineMemoryPrintCalculator::New();
+  memoryPrintCalculator->SetDataToWrite(image);
+  memoryPrintCalculator->SetBiasCorrectionFactor(1);
+  memoryPrintCalculator->Compute(false);
+  return memoryPrintCalculator->GetMemoryPrint();
+}
+
+ImageBaseType::RegionType
+Application::GetImageRequestedRegion(const std::string & key, unsigned int idx)
+{
+  ImageBaseType* image = this->GetParameterImageBase(key, idx);
+  ImageBaseType::RegionType largest = image->GetLargestPossibleRegion();
+  ImageBaseType::RegionType requested = image->GetRequestedRegion();
+  requested.SetIndex(0, requested.GetIndex(0) - largest.GetIndex(0));
+  requested.SetIndex(1, requested.GetIndex(1) - largest.GetIndex(1));
+  return requested;
+}
+
+itk::MetaDataDictionary
+Application::GetImageMetaData(const std::string & key, unsigned int idx)
+{
+  ImageBaseType* image = this->GetParameterImageBase(key, idx);
+  return image->GetMetaDataDictionary();
+}
+
+ImageBaseType*
+Application::GetParameterImageBase(const std::string & key, unsigned int idx)
+{
+  Parameter* param = GetParameterByKey(key);
+  if (dynamic_cast<InputImageParameter*>(param))
+    {
+    InputImageParameter* paramDown = dynamic_cast<InputImageParameter*>(param);
+    return paramDown->GetImage<ImageBaseType>();
+    }
+  else if (dynamic_cast<InputImageListParameter*>(param))
+    {
+    InputImageListParameter* paramDown = dynamic_cast<InputImageListParameter*>(param);
+    return paramDown->GetNthImage(idx);
+    }
+  else if (dynamic_cast<ComplexInputImageParameter*>(param))
+    {
+    ComplexInputImageParameter* paramDown = dynamic_cast<ComplexInputImageParameter*>(param);
+    return paramDown->GetImage<ImageBaseType>();
+    }
+  else if (dynamic_cast<OutputImageParameter*>(param))
+    {
+    OutputImageParameter* paramDown = dynamic_cast<OutputImageParameter*>(param);
+    return paramDown->GetValue();
+    }
+  else if (dynamic_cast<ComplexOutputImageParameter*>(param))
+    {
+    ComplexOutputImageParameter* paramDown = dynamic_cast<ComplexOutputImageParameter*>(param);
+    return paramDown->GetValue();
+    }
+  else
+    {
+    itkExceptionMacro("Wrong parameter type, expect InputImageParameter, "
+      "InputImageListParameter, ComplexInputImageParameter, "
+      "OutputImageParameter, ComplexOutputImageParameter");
+    }
+  return nullptr;
+}
+
+void
+Application::SetParameterImageBase(const std::string & key, ImageBaseType* img, unsigned int idx)
+{
+  Parameter* param = GetParameterByKey(key);
+  if (dynamic_cast<InputImageParameter*>(param))
+    {
+    InputImageParameter* paramDown = dynamic_cast<InputImageParameter*>(param);
+    paramDown->SetImage<ImageBaseType>(img);
+    }
+  else if (dynamic_cast<InputImageListParameter*>(param))
+    {
+    InputImageListParameter* paramDown = dynamic_cast<InputImageListParameter*>(param);
+    if (idx >= paramDown->Size())
+      {
+      paramDown->AddImage(img);
+      }
+    else
+      {
+      paramDown->SetNthImage(idx, img);
+      }
+    }
+  else if (dynamic_cast<ComplexInputImageParameter*>(param))
+    {
+    ComplexInputImageParameter* paramDown = dynamic_cast<ComplexInputImageParameter*>(param);
+    paramDown->SetImage<ImageBaseType>(img);
+    }
+  else
+    {
+    itkExceptionMacro("Wrong parameter type, expect InputImageParameter, InputImageListParameter or ComplexInputImageParameter");
+    }
+}
+
+ImagePixelType
+Application::GetImageBasePixelType(const std::string & key, unsigned int idx)
+{
+  ImageBaseType* img = this->GetParameterImageBase(key, idx);
+  if (! img)
+    {
+    itkExceptionMacro("No input image");
+    }
+  std::string className(img->GetNameOfClass());
+  if (className == "VectorImage")
+    {
+#define FindVectorImagePixelTypeMacro(TImage, TPixel) \
+    TImage##VectorImageType* img##TImage = dynamic_cast< TImage##VectorImageType* >(img); \
+    if ( img##TImage ) return ImagePixelType_##TPixel ;
+
+    FindVectorImagePixelTypeMacro(UInt8,  uint8)
+    FindVectorImagePixelTypeMacro(Int16,  int16)
+    FindVectorImagePixelTypeMacro(UInt16, uint16)
+    FindVectorImagePixelTypeMacro(Int32,  int32)
+    FindVectorImagePixelTypeMacro(UInt32, uint32)
+    FindVectorImagePixelTypeMacro(Float,  float)
+    FindVectorImagePixelTypeMacro(Double, double)
+    FindVectorImagePixelTypeMacro(ComplexInt16,  cint16)
+    FindVectorImagePixelTypeMacro(ComplexInt32,  cint32)
+    FindVectorImagePixelTypeMacro(ComplexFloat,  cfloat)
+    FindVectorImagePixelTypeMacro(ComplexDouble, cdouble)
+#undef FindVectorImagePixelTypeMacro
+    }
+  else
+    {
+#define FindImagePixelTypeMacro(TImage, TPixel) \
+    TImage##ImageType* img##TImage = dynamic_cast< TImage##ImageType* >(img); \
+    if ( img##TImage ) return ImagePixelType_##TPixel ;
+
+    FindImagePixelTypeMacro(UInt8,  uint8)
+    FindImagePixelTypeMacro(Int16,  int16)
+    FindImagePixelTypeMacro(UInt16, uint16)
+    FindImagePixelTypeMacro(Int32,  int32)
+    FindImagePixelTypeMacro(UInt32, uint32)
+    FindImagePixelTypeMacro(Float,  float)
+    FindImagePixelTypeMacro(Double, double)
+    FindImagePixelTypeMacro(ComplexInt16,  cint16)
+    FindImagePixelTypeMacro(ComplexInt32,  cint32)
+    FindImagePixelTypeMacro(ComplexFloat,  cfloat)
+    FindImagePixelTypeMacro(ComplexDouble, cdouble)
+    FindImagePixelTypeMacro(UInt8RGB,  uint8)
+    FindImagePixelTypeMacro(UInt8RGBA, uint8)
+#undef FindImagePixelTypeMacro
+    }
+  itkWarningMacro("Unknown pixel type");
+  // by default uint8
+  return ImagePixelType_uint8;
+}
+
 }
 }
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexInputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexInputImageParameter.cxx
index 22629f407458a925afa397824fa678456a9878d6..1b3883e36c085758beb606f470fae231ad89b291 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexInputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexInputImageParameter.cxx
@@ -65,6 +65,15 @@ ComplexInputImageParameter::GetImage()
   return this->GetImage<ComplexFloatVectorImageType>();
 }
 
+template <>
+ImageBaseType*
+ComplexInputImageParameter::GetImage()
+{
+  if (m_Image.IsNull())
+    return this->GetImage<ComplexFloatVectorImageType>();
+
+  return m_Image;
+}
 
 #define otbGetImageMacro(image)                       \
   image##Type *                                       \
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
index 6d86118c4591da5f17e8a932356fbede5d2cdc3d..b97171cb71d9b270f07437cf22fa5116bc0b0d7c 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperComplexOutputImageParameter.cxx
@@ -278,7 +278,7 @@ ComplexOutputImageParameter::GetWriter()
   return writer;
 }
 
-ComplexOutputImageParameter::ImageBaseType*
+ImageBaseType*
 ComplexOutputImageParameter::GetValue( )
 {
   return m_Image;
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
index 96b315b050c76e22a9dd89060777e1d4dede5363..2b806426a16818f07293d9e05844541c45f472f7 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
@@ -68,6 +68,16 @@ InputImageParameter::GetImage()
   return this->GetImage<FloatVectorImageType>();
 }
 
+template <>
+ImageBaseType*
+InputImageParameter::GetImage()
+{
+  if (m_Image.IsNull())
+    return this->GetImage<FloatVectorImageType>();
+
+  return m_Image;
+}
+
 otbGetImageMacro(UInt8RGBImage);
 otbGetImageMacro(UInt8RGBAImage);
 
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4cf7c602e1f247a6c9836a50cea9587218b9e989
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperMetaDataHelper.cxx
@@ -0,0 +1,221 @@
+/*
+ * 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 "otbWrapperMetaDataHelper.h"
+#include "itkMetaDataObject.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+namespace MetaDataHelper
+{
+
+MDType GetType(const std::string &val)
+{
+  MDType ret;
+  otb::MetaDataKey::KeyType kt = otb::MetaDataKey::GetKeyType(val);
+  switch (kt)
+    {
+    case otb::MetaDataKey::TSTRING:
+      ret = MDType::String;
+      break;
+    case otb::MetaDataKey::TENTIER:
+      ret = MDType::Int;
+      break;
+    case otb::MetaDataKey::TDOUBLE:
+      ret = MDType::Double;
+      break;
+    case otb::MetaDataKey::TOTB_GCP:
+      ret = MDType::GCP;
+      break;
+    case otb::MetaDataKey::TVECTOR:
+      ret = MDType::Vector;
+      break;
+    case otb::MetaDataKey::TOSSIMKEYWORDLIST:
+      ret = MDType::ImageKWL;
+      break;
+    case otb::MetaDataKey::TVECTORDATAKEYWORDLIST:
+      ret = MDType::VectorDataKWL;
+      break;
+    case otb::MetaDataKey::TBOOLVECTOR:
+      ret = MDType::BoolVector;
+      break;
+    default:
+      break;
+    }
+  return ret;
+}
+
+std::string
+GetString(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  std::string ret;
+  itk::ExposeMetaData<std::string>(dict, key, ret);
+  return ret;
+}
+
+void
+SetString(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const std::string &val)
+{
+  itk::EncapsulateMetaData<std::string>(dict, key, val);
+}
+
+unsigned int
+GetInt(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  unsigned int ret;
+  itk::ExposeMetaData<unsigned int>(dict, key, ret);
+  return ret;
+}
+
+void
+SetInt(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    unsigned int val)
+{
+  itk::EncapsulateMetaData<unsigned int>(dict, key, val);
+}
+
+double
+GetDouble(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  double ret;
+  itk::ExposeMetaData<double>(dict, key, ret);
+  return ret;
+}
+
+void
+SetDouble(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    double val)
+{
+  itk::EncapsulateMetaData<double>(dict, key, val);
+}
+
+otb::OTB_GCP
+GetGCP(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  otb::OTB_GCP ret;
+  itk::ExposeMetaData<otb::OTB_GCP>(dict, key, ret);
+  return ret;
+}
+
+void
+SetGCP(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::OTB_GCP &val)
+{
+  itk::EncapsulateMetaData<otb::OTB_GCP>(dict, key, val);
+}
+
+otb::MetaDataKey::VectorType
+GetVector(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  otb::MetaDataKey::VectorType ret;
+  itk::ExposeMetaData<otb::MetaDataKey::VectorType>(dict, key, ret);
+  return ret;
+}
+
+void
+SetVector(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::MetaDataKey::VectorType &val)
+{
+  itk::EncapsulateMetaData<otb::MetaDataKey::VectorType>(dict, key, val);
+}
+
+otb::ImageKeywordlist
+GetImageKWL(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  otb::ImageKeywordlist ret;
+  itk::ExposeMetaData<otb::ImageKeywordlist>(dict, key, ret);
+  return ret;
+}
+
+void
+SetImageKWL(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::ImageKeywordlist &val)
+{
+  itk::EncapsulateMetaData<otb::ImageKeywordlist>(dict, key, val);
+}
+
+otb::VectorDataKeywordlist
+GetVectorDataKWL(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  otb::VectorDataKeywordlist ret;
+  itk::ExposeMetaData<otb::VectorDataKeywordlist>(dict, key, ret);
+  return ret;
+}
+
+void
+SetVectorDataKWL(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::VectorDataKeywordlist &val)
+{
+  itk::EncapsulateMetaData<otb::VectorDataKeywordlist>(dict, key, val);
+}
+
+otb::MetaDataKey::BoolVectorType
+GetBoolVector(
+    const itk::MetaDataDictionary &dict,
+    const std::string &key)
+{
+  otb::MetaDataKey::BoolVectorType ret;
+  itk::ExposeMetaData<otb::MetaDataKey::BoolVectorType>(dict, key, ret);
+  return ret;
+}
+
+void
+SetBoolVector(
+    itk::MetaDataDictionary &dict,
+    const std::string &key,
+    const otb::MetaDataKey::BoolVectorType &val)
+{
+  itk::EncapsulateMetaData<otb::MetaDataKey::BoolVectorType>(dict, key, val);
+}
+
+} // end of namespace MetaDataHelper
+} // end of namespace Wrapper
+} // end of namespace otb
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
index d0dd6678797767b6f50d61ba0a9667173d1a77e1..32b0cfaa497bed989fedf6d01a20b1763dc0bf28 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
@@ -590,7 +590,7 @@ OutputImageParameter::GetWriter()
   return writer;
 }
 
-OutputImageParameter::ImageBaseType*
+ImageBaseType*
 OutputImageParameter::GetValue( )
 {
   return m_Image;
diff --git a/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt b/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
index 319466cb4c49d21b321d55aa57ff0df847f56a53..856191df14551aabfe7ea8982d7a70a59aa6ea56 100644
--- a/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
+++ b/Modules/Wrappers/ApplicationEngine/test/CMakeLists.txt
@@ -41,6 +41,7 @@ otbWrapperApplicationHtmlDocGeneratorTest.cxx
 otbWrapperInputVectorDataParameterTest.cxx
 otbWrapperOutputImageParameterTest.cxx
 otbApplicationMemoryConnectTest.cxx
+otbWrapperImageInterface.cxx
 )
 
 add_executable(otbApplicationEngineTestDriver ${OTBApplicationEngineTests})
@@ -197,3 +198,13 @@ otb_add_test(NAME owTvApplicationMemoryConnectTest COMMAND otbApplicationEngineT
 otb_add_test(NAME owTvParameterGroup COMMAND otbApplicationEngineTestDriver
   otbWrapperParameterList
   )
+
+otb_add_test(NAME owTvImageInterface COMMAND otbApplicationEngineTestDriver
+  --compare-ascii ${NOTOL}
+  ${BASELINE_FILES}/owTvImageInterfaceOut.txt
+  ${TEMP}/owTvImageInterfaceOut.txt
+  otbWrapperImageInterface
+  $<TARGET_FILE_DIR:otbapp_Smoothing>
+  ${INPUTDATA}/Capitole_Rasterization.tif
+  ${TEMP}/owTvImageInterfaceOut.txt
+  )
diff --git a/Modules/Wrappers/ApplicationEngine/test/otbApplicationEngineTestDriver.cxx b/Modules/Wrappers/ApplicationEngine/test/otbApplicationEngineTestDriver.cxx
index 5ccef4965304591a54437f5f75e1d4070bff360a..7413baadc59f2332227a41603d3018f474a85f0f 100644
--- a/Modules/Wrappers/ApplicationEngine/test/otbApplicationEngineTestDriver.cxx
+++ b/Modules/Wrappers/ApplicationEngine/test/otbApplicationEngineTestDriver.cxx
@@ -53,4 +53,5 @@ void RegisterTests()
   REGISTER_TEST(otbWrapperOutputImageParameterTest1);
   //~ REGISTER_TEST(otbWrapperOutputImageParameterConversionTest);
   REGISTER_TEST(otbApplicationMemoryConnectTest);
+  REGISTER_TEST(otbWrapperImageInterface);
 }
diff --git a/Modules/Wrappers/ApplicationEngine/test/otbWrapperImageInterface.cxx b/Modules/Wrappers/ApplicationEngine/test/otbWrapperImageInterface.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cc1963ecd181d8a75d280ed209bd53dca990913d
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/test/otbWrapperImageInterface.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.
+ */
+
+#if defined(_MSC_VER)
+#pragma warning ( disable : 4786 )
+#endif
+
+#include "otbWrapperApplicationRegistry.h"
+
+
+int otbWrapperImageInterface(int argc, char * argv[])
+{
+  if(argc<4)
+    {
+    std::cerr<<"Usage: "<<argv[0]<<" application_path  input_image  output_txt"<<std::endl;
+    return EXIT_FAILURE;
+    }
+
+  std::string path = argv[1];
+  std::string input = argv[2];
+  std::string output = argv[3];
+
+  otb::Wrapper::ApplicationRegistry::SetApplicationPath(path);
+  
+  otb::Wrapper::Application::Pointer app1 = otb::Wrapper::ApplicationRegistry::CreateApplication("Smoothing");
+  
+  if(app1.IsNull())
+    {
+    std::cerr<<"Failed to create application"<<std::endl;
+    return EXIT_FAILURE;
+    }
+
+  std::ofstream ofs( output );
+  if (!ofs.is_open())
+    {
+    fprintf(stderr, "Error, can't open file");
+    return EXIT_FAILURE;
+    }
+
+  app1->SetParameterString("in",input);
+  app1->Execute();
+
+  ofs << "Size: "<< app1->GetImageSize("out") << std::endl;
+  ofs << "Origin: "<< app1->GetImageOrigin("out") << std::endl;
+  ofs << "Spacing: "<< app1->GetImageSpacing("out") << std::endl;
+  ofs << "Keywordlist: "<< std::endl;
+  otb::ImageKeywordlist kwl = app1->GetImageKeywordlist("out");
+  kwl.Print(ofs);
+  ofs << "ProjectionRef:"<< std::endl;
+  ofs << app1->GetImageProjection("out") << std::endl;
+
+  itk::MetaDataDictionary dict = app1->GetImageMetaData("out");
+  ofs << "Dictionary keys:"<< std::endl;
+  for (auto & key : dict.GetKeys())
+    {
+    ofs << "  - "<< key << std::endl;
+    }
+
+  otb::Wrapper::ImageBaseType::RegionType region;
+  region.SetIndex(0,10);
+  region.SetIndex(1,10);
+  region.SetSize(0,7);
+  region.SetSize(1,7);
+
+  ofs << "RAM usage (in Bytes): "<< app1->PropagateRequestedRegion("out",region) << std::endl;
+  ofs << "Input requested: "<< app1->GetImageRequestedRegion("in") << std::endl;
+
+  otb::Wrapper::Application::Pointer app2 =
+    otb::Wrapper::ApplicationRegistry::CreateApplication("ConcatenateImages");
+  app2->AddParameterStringList("il",input);
+  app2->AddParameterStringList("il",input);
+  app2->Execute();
+
+  ofs << "Number of bands [il]: "<< app2->GetImageNbBands("il",0) << "+"
+    << app2->GetImageNbBands("il",1) << std::endl;
+  ofs << "Number of bands [out]: "<< app2->GetImageNbBands("out")<< std::endl;
+  ofs.close();
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/Wrappers/SWIG/src/itkBase.i b/Modules/Wrappers/SWIG/src/itkBase.i
index 2a15719f26f03106b4bb599ac0161931bb0636a7..f2ae37cc3d9dbf5268026f9e22508921a2946332 100644
--- a/Modules/Wrappers/SWIG/src/itkBase.i
+++ b/Modules/Wrappers/SWIG/src/itkBase.i
@@ -44,13 +44,194 @@
   }
 }
 
+// BASIC ITK TYPES WRAPPING
+%include "itkFloatTypes.h"
+%include "itkIntTypes.h"
+
 // Some code from STL
 // Do not wrap if not necessary as it really slows down compilation
 
 %include <std_string.i>
 %include <std_vector.i>
+%include <std_map.i>
+#if SWIGPYTHON
+%include <std_complex.i>
+#endif
+
+%template(vectorstring)     std::vector< std::string >;
+%template(mapstringstring)  std::map< std::string, std::string >;
+%template(vectorbool)       std::vector<bool>;
+%template(vectordouble)     std::vector<double>;
+
+#if SWIGPYTHON
+%extend std::map< std::string, std::string >
+{
+  %pythoncode
+  {
+    def __str__(self):
+      ret = "{"
+      for key in self:
+        ret += str(key)+":"+str(self[key])+", "
+      if len(ret) == 1:
+        ret += ", "
+      return ret[:-2]+"}"
+  }
+};
+#endif
+
+//---------------- ITK classes ------------------------------------
+
+namespace itk
+{
+
+template <unsigned int VDim = 2>
+class Size
+{
+public:
+  Size();
+  ~Size();
+  void Fill(unsigned long val);
+  SizeValueType GetElement(unsigned long element) const;
+  void SetElement(unsigned long element, SizeValueType val);
+  static unsigned int GetSizeDimension();
+};
+
+template <unsigned int VDim = 2>
+class Index
+{
+public:
+  Index();
+  ~Index();
+  void Fill(signed long val);
+  IndexValueType GetElement(unsigned long element) const;
+  void SetElement(unsigned long element, IndexValueType val);
+  static unsigned int GetIndexDimension();
+};
+
+template <unsigned int VDim>
+class ImageRegion
+{
+public:
+  ImageRegion();
+  ImageRegion(const Index<VDim> &index, const Size<VDim> &size);
+  ~ImageRegion();
+  void SetIndex(const Index<VDim> &index);
+  void SetSize(const Size<VDim> &size);
+  void SetUpperIndex(const Index<VDim> &idx);
+  Index<VDim> GetUpperIndex() const;
+  const Index<VDim> & GetIndex() const;
+  const Size<VDim> & GetSize() const;
+  bool IsInside(const Index<VDim> & index) const;
+  void SetSize(unsigned int i, SizeValueType val);
+  SizeValueType GetSize(unsigned int i) const;
+  void SetIndex(unsigned int i, IndexValueType val);
+  IndexValueType GetIndex(unsigned int i) const;
+};
+
+template <typename TValue, unsigned int VLength = 3>
+class FixedArray
+{
+public:
+  FixedArray();
+  ~FixedArray();
+  unsigned int Size();
+  void SetElement(unsigned short idx, const TValue &val);
+  const TValue & GetElement(unsigned short idx);
+};
+
+template <typename TValue, unsigned int NDim = 3>
+class Vector: public FixedArray<TValue,NDim>
+{
+public: 
+  Vector();
+  ~Vector();
+  typedef NumericTraits<TValue>::RealType RealValueType;
+  RealValueType GetNorm() const;
+  RealValueType GetSquaredNorm() const;
+  RealValueType Normalize();
+};
+
+template <typename TCoord, unsigned int NDim = 3>
+class Point: public FixedArray<TCoord,NDim>
+{
+public:
+  Point();
+  ~Point();
+};
+
+// Instanciate the needed templates
+%template(itkSize) Size<2>;
+%template(itkIndex) Index<2>;
+%template(itkRegion) ImageRegion<2>;
+%template(itkFixedArray) FixedArray<SpacePrecisionType,2>;
+%template(itkVector) Vector<SpacePrecisionType,2>;
+%template(itkPoint) Point<SpacePrecisionType,2>;
 
-%template(vectorstring)   std::vector< std::string >;
+} // end of namespace itk
+
+#if SWIGPYTHON
+
+%define WRAP_AS_LIST(N, T...)
+%extend T
+  {
+  %pythoncode
+    {
+    def __str__(self):
+      ret = "["
+      for index in range(N):
+        ret += str(self.GetElement(index))+","
+      ret = ret[:-1] + "]"
+      return ret
+    def __len__(self):
+      return N
+    def __getitem__(self,idx):
+      if idx >= N or idx < 0:
+        raise IndexError('Index outside [0,'+str(N-1)+']')
+      return self.GetElement(idx)
+    def __setitem__(self,idx,val):
+      if idx >= N or idx < 0:
+        raise IndexError('Index outside [0,'+str(N-1)+']')
+      return self.SetElement(idx,val)
+    }
+  };
+%enddef
+
+namespace itk
+{
+WRAP_AS_LIST(2, Size<2>)
+WRAP_AS_LIST(2, Index<2>)
+WRAP_AS_LIST(2, FixedArray<SpacePrecisionType,2>)
+WRAP_AS_LIST(2, Vector<SpacePrecisionType,2>)
+WRAP_AS_LIST(2, Point<SpacePrecisionType,2>)
+
+%extend ImageRegion<2>
+{
+  %pythoncode
+    {
+    def __str__(self):
+      return "{index:"+str(self.GetIndex())+", size:"+str(self.GetSize())+"}"
+    def __len__(self):
+      return 2
+    def keys(self):
+      return ['index', 'size']
+    def __getitem__(self,key):
+      if key == 'index':
+        return self.GetIndex()
+      elif key == 'size':
+        return self.GetSize()
+      else:
+        raise IndexError('Key not in ["index","size"]')
+    def __setitem__(self,key,val):
+      if key == 'index':
+        self.SetIndex(val)
+      elif key == 'size':
+        self.SetSize(val)
+      else:
+        raise IndexError('Key not in ["index","size"]')
+    }
+};
+} // end of namespace itk
+#endif
 
 class itkIndent {
    public:
@@ -155,6 +336,21 @@ class itkIndent {
  };
  DECLARE_REF_COUNT_CLASS( itkObjectFactoryBase )
 
+class itkMetaDataObjectBase : public itkLightObject
+{
+public:
+  virtual const std::type_info & GetMetaDataObjectTypeInfo() const;
+  virtual const char * GetMetaDataObjectTypeName() const;
+  virtual const char * GetNameOfClass() const;
+  virtual void Print(std::ostream &os) const;
+protected:
+  itkMetaDataObjectBase();
+#if SWIGJAVA
+  ~itkMetaDataObjectBase();
+#endif
+};
+DECLARE_REF_COUNT_CLASS(itkMetaDataObjectBase)
+
  class itkMetaDataDictionary {
    public:
      virtual void Print(std::ostream & os) const;
@@ -163,7 +359,20 @@ class itkIndent {
      ~itkMetaDataDictionary();
      std::vector< std::string > GetKeys() const;
      bool HasKey(std::string const & arg0) const;
+     const itkMetaDataObjectBase* Get(const std::string &) const;
+     void Set(const std::string &, itkMetaDataObjectBase *);
  };
+
+namespace itk
+{
+
+template <typename T>
+inline bool ExposeMetaData(const itkMetaDataDictionary & Dictionary, const std::string key, T & outval);
+
+template <typename T>
+inline void EncapsulateMetaData(itkMetaDataDictionary & Dictionary, const std::string & key, const T & invalue);
+
+}
  
  class itkCommand : public itkObject {
    public:
diff --git a/Modules/Wrappers/SWIG/src/itkBase.includes b/Modules/Wrappers/SWIG/src/itkBase.includes
index 8cf4ee05bcc49a0a3542a5dee614fcafcb8de29b..4f7902f3a4e44a4b5883602803aaa83d906dcde5 100644
--- a/Modules/Wrappers/SWIG/src/itkBase.includes
+++ b/Modules/Wrappers/SWIG/src/itkBase.includes
@@ -38,6 +38,8 @@ typedef itk::ProcessObject::Pointer     itkProcessObject_Pointer;
 typedef itk::ObjectFactoryBase          itkObjectFactoryBase;
 typedef itk::ObjectFactoryBase::Pointer itkObjectFactoryBase_Pointer;
 typedef itk::MetaDataDictionary         itkMetaDataDictionary;
+typedef itk::MetaDataObjectBase         itkMetaDataObjectBase;
+typedef itk::MetaDataObjectBase::Pointer itkMetaDataObjectBase_Pointer;
 typedef itk::Indent                     itkIndent;
 
 typedef itk::Command              itkCommand;
diff --git a/Modules/Wrappers/SWIG/src/otbApplication.i b/Modules/Wrappers/SWIG/src/otbApplication.i
index 88802af41a2805f1c0921814d7dd1a7f34bcc175..c8b97c12e217b970a514dea5c1a248d6a89bb863 100644
--- a/Modules/Wrappers/SWIG/src/otbApplication.i
+++ b/Modules/Wrappers/SWIG/src/otbApplication.i
@@ -21,7 +21,7 @@
 
 %module otbApplication
 
- %{
+%{
 #include "itkBase.includes"
 #include "otbWrapperSWIGIncludes.h"
 #include <string>         // std::string
@@ -67,6 +67,8 @@ import_array();
 %apply (unsigned int** ARGOUTVIEW_ARRAY3, int *DIM1, int *DIM2, int *DIM3) {(unsigned int** buffer, int *dim1, int *dim2, int *dim3)};
 %apply (unsigned long** ARGOUTVIEW_ARRAY3, int *DIM1, int *DIM2, int *DIM3) {(unsigned long** buffer, int *dim1, int *dim2, int *dim3)};
 %apply (double** ARGOUTVIEW_ARRAY3, int *DIM1, int *DIM2, int *DIM3) {(double** buffer, int *dim1, int *dim2, int *dim3)};
+%apply (std::complex<float>** ARGOUTVIEW_ARRAY3, int *DIM1, int *DIM2, int *DIM3) {(std::complex<float>** buffer, int *dim1, int *dim2, int *dim3)};
+%apply (std::complex<double>** ARGOUTVIEW_ARRAY3, int *DIM1, int *DIM2, int *DIM3) {(std::complex<double>** buffer, int *dim1, int *dim2, int *dim3)};
 
 #endif /* OTB_SWIGNUMPY */
 
@@ -119,6 +121,10 @@ namespace Wrapper
     ImagePixelType_uint32,
     ImagePixelType_float,
     ImagePixelType_double,
+    ImagePixelType_cint16,
+    ImagePixelType_cint32,
+    ImagePixelType_cfloat,
+    ImagePixelType_cdouble,
   } ImagePixelType;
 
   typedef enum
@@ -133,9 +139,70 @@ namespace Wrapper
     ComplexImagePixelType_double,
   } ComplexImagePixelType;
 
-}
+} // end of namespace Wrapper
 
-}
+class ImageKeywordlist
+{
+public:
+  typedef std::map<std::string, std::string> KeywordlistMap;
+  typedef KeywordlistMap::size_type KeywordlistMapSizeType;
+  ImageKeywordlist();
+  virtual ~ImageKeywordlist();
+  const KeywordlistMap& GetKeywordlist() const;
+  void Clear(void);
+  KeywordlistMapSizeType Empty() const;
+  KeywordlistMapSizeType GetSize(void) const;
+  const std::string& GetMetadataByKey(const std::string& key) const;
+  bool HasKey(const std::string& key) const;
+  virtual void ClearMetadataByKey(const std::string& key);
+  virtual void AddKey(const std::string& key, const std::string& value);
+  virtual void Print(std::ostream& os, itkIndent indent = 0) const;
+};
+
+class VectorDataKeywordlist
+{
+public:
+  VectorDataKeywordlist();
+  ~VectorDataKeywordlist();
+  // VectorDataKeywordlist(const Self& other);
+  // TODO : finish wrapping
+};
+
+class OTB_GCP
+{
+public:
+  std::string m_Id;
+  std::string m_Info;
+  double m_GCPCol;
+  double m_GCPRow;
+  double m_GCPX;
+  double m_GCPY;
+  double m_GCPZ;
+  OTB_GCP();
+  ~OTB_GCP();
+  void Print(std::ostream& os) const;
+};
+
+#if SWIGPYTHON
+%extend ImageKeywordlist
+  {
+  %pythoncode
+    {
+    def __str__(self):
+      return str(self.GetKeywordlist())
+    def __len__(self):
+      return self.GetSize()
+    def __getitem__(self,key):
+      return self.GetKeywordlist()[key]
+    def __setitem__(self,key,val):
+      self.GetKeywordlist()[key] = val
+    def keys(self):
+      return self.GetKeywordlist().keys()
+    }
+  }
+#endif
+
+} // end of namespace otb
 
 class Application: public itkObject
 {
@@ -194,18 +261,27 @@ public:
   std::vector<std::string> GetParameterStringList(std::string parameter);
   std::string GetParameterAsString(std::string paramKey);
 
-  InputImageParameter::ImageBaseType * GetParameterOutputImage(std::string parameter);
-  void SetParameterInputImage(std::string parameter, InputImageParameter::ImageBaseType * inputImage);
-  ComplexInputImageParameter::ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
-  void SetParameterComplexInputImage(std::string parameter, ComplexInputImageParameter::ImageBaseType * inputImage);
-  void AddImageToParameterInputImageList(std::string parameter,InputImageParameter::ImageBaseType * img);
+  ImageBaseType * GetParameterOutputImage(std::string parameter);
+  void SetParameterInputImage(std::string parameter, ImageBaseType * inputImage);
+  ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
+  void SetParameterComplexInputImage(std::string parameter, ImageBaseType * inputImage);
+  void AddImageToParameterInputImageList(std::string parameter,ImageBaseType * img);
   void AddParameterStringList(std::string parameter,const std::string & str);
-  void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, InputImageParameter::ImageBaseType * img);
+  void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, ImageBaseType * img);
   void SetNthParameterStringList(std::string parameter, const unsigned int &id, const std::string& str);
   void ClearParameterInputImageList(std::string parameter);
   unsigned int GetNumberOfElementsInParameterInputImageList(std::string parameter);
 
-
+  itk::Point<SpacePrecisionType,2> GetImageOrigin(const std::string & key, unsigned int idx = 0);
+  itk::Vector<SpacePrecisionType,2> GetImageSpacing(const std::string & key, unsigned int idx = 0);
+  itk::Size<2> GetImageSize(const std::string & key, unsigned int idx = 0);
+  unsigned int GetImageNbBands(const std::string & key, unsigned int idx = 0);
+  std::string GetImageProjection(const std::string & key, unsigned int idx = 0);
+  otb::ImageKeywordlist GetImageKeywordlist(const std::string & key, unsigned int idx = 0);
+  unsigned long PropagateRequestedRegion(const std::string & key, itk::ImageRegion<2> region, unsigned int idx = 0);
+  itk::ImageRegion<2> GetImageRequestedRegion(const std::string & key, unsigned int idx = 0);
+  itkMetaDataDictionary GetImageMetaData(const std::string & key, unsigned int idx = 0);
+  otb::Wrapper::ImagePixelType GetImageBasePixelType(const std::string & key, unsigned int idx = 0);
 
   itkProcessObject* GetProgressSource() const;
 
@@ -245,154 +321,161 @@ public:
   %extend {
 
 #define SetFromNumpyArrayMacro(prefix, PixelDataType, ImageClass)       \
-      void Set##ImageClass##From##prefix##NumpyArray_(std::string pkey, ##PixelDataType##* buffer, int dim1, int dim2, int dim3) \
-      {                                                                 \
-        otb::Wrapper::Parameter *parameter = $self->GetParameterList()->GetParameterByKey(pkey); \
-        InputImageParameter* inputImageParam = dynamic_cast<InputImageParameter*>(parameter); \
-        typedef otb::##ImageClass##<##PixelDataType##>   ImageType;     \
-        ImageType::Pointer output = ImageType::New();          \
-        typedef ImageType::SizeType        SizeType;           \
-        typedef ImageType::IndexType       IndexType;          \
-        typedef ImageType::RegionType      RegionType;         \
-        typedef ImageType::PointType       PointType;          \
-        typedef ImageType::SpacingType     SpacingType;        \
-        typedef ImageType::DirectionType   DirectionType;      \
-        IndexType start;                                                \
-        DirectionType direction;                                        \
-        start.Fill( 0 );                                                \
-        SizeType size;                                                  \
-        size[0] = dim2; size[1] = dim1;                                 \
-        SetVectorLengthMacro                                            \
-        output->Allocate();                                             \
-        unsigned int numberOfPixels = dim1 * dim2 * dim3;               \
-        RegionType region;                                              \
-        region.SetIndex( start );                                       \
-        region.SetSize( size );                                         \
-        PointType origin;                                               \
-        origin.Fill( 0.0 );                                             \
-        SpacingType spacing;                                            \
-        spacing.Fill( 1.0 );                                            \
-        direction.SetIdentity();                                        \
-        output->SetOrigin( origin );                                    \
-        output->SetSignedSpacing( spacing );                                  \
-        output->SetDirection(direction);                                \
-        output->SetLargestPossibleRegion(region);                       \
-        output->SetRequestedRegion(output->GetLargestPossibleRegion()); \
-        output->SetBufferedRegion(output->GetLargestPossibleRegion());  \
-        output->GetPixelContainer()->SetImportPointer(buffer, numberOfPixels, false); \
-        inputImageParam->SetImage<ImageType>(output);                   \
+  ImageBaseType* Set##ImageClass##From##prefix##NumpyArray_(std::string pkey, int idx, ##PixelDataType##* buffer, int dim1, int dim2, int dim3) \
+  {                                                                 \
+    typedef otb::##ImageClass##<##PixelDataType##>   ImageType;     \
+    ImageType::Pointer output = ImageType::New();                   \
+    unsigned int numberOfPixels = dim1 * dim2 * dim3;               \
+    ImageType::RegionType region;                                   \
+    region.SetIndex(0, 0);                                          \
+    region.SetIndex(1, 0);                                          \
+    region.SetSize( 0, dim2);                                       \
+    region.SetSize( 1, dim1);                                       \
+    output->SetNumberOfComponentsPerPixel(dim3);                    \
+    output->SetRegions(region);                                     \
+    output->GetPixelContainer()->SetImportPointer(buffer, numberOfPixels, false); \
+    $self->SetParameterImageBase(pkey,output.GetPointer(),idx);     \
+    return output.GetPointer();                                     \
   }
 
-#define SetVectorLengthMacro output->SetVectorLength(dim3);
-       SetFromNumpyArrayMacro(Float, float, VectorImage)
-       SetFromNumpyArrayMacro(Int8, signed char, VectorImage)
-       SetFromNumpyArrayMacro(Int16, signed short, VectorImage)
-       SetFromNumpyArrayMacro(Int32, signed int, VectorImage)
-       SetFromNumpyArrayMacro(Int64, signed long, VectorImage)
-       SetFromNumpyArrayMacro(UInt8, unsigned char, VectorImage)
-       SetFromNumpyArrayMacro(UInt16, unsigned short, VectorImage)
-       SetFromNumpyArrayMacro(UInt32, unsigned int, VectorImage)
-       SetFromNumpyArrayMacro(UInt64, unsigned long, VectorImage)
-       SetFromNumpyArrayMacro(Double, double, VectorImage)
-#undef SetVectorLengthMacro
-
-#define SetVectorLengthMacro dim3=1;
-       SetFromNumpyArrayMacro(Float, float, Image)
-       SetFromNumpyArrayMacro(Int8, signed char, Image)
-       SetFromNumpyArrayMacro(Int16, signed short, Image)
-       SetFromNumpyArrayMacro(Int32, signed int, Image)
-       SetFromNumpyArrayMacro(Int64, signed long, Image)
-       SetFromNumpyArrayMacro(UInt8, unsigned char, Image)
-       SetFromNumpyArrayMacro(UInt16, unsigned short, Image)
-       SetFromNumpyArrayMacro(UInt32, unsigned int, Image)
-       SetFromNumpyArrayMacro(UInt64, unsigned long, Image)
-       SetFromNumpyArrayMacro(Double, double, Image)
-#undef SetVectorLengthMacro
+  SetFromNumpyArrayMacro(UInt8, unsigned char, VectorImage)
+  SetFromNumpyArrayMacro(Int16, signed short, VectorImage)
+  SetFromNumpyArrayMacro(UInt16, unsigned short, VectorImage)
+  SetFromNumpyArrayMacro(Int32, signed int, VectorImage)
+  SetFromNumpyArrayMacro(UInt32, unsigned int, VectorImage)
+  // SetFromNumpyArrayMacro(Int64, signed long, VectorImage)
+  // SetFromNumpyArrayMacro(UInt64, unsigned long, VectorImage)
+  SetFromNumpyArrayMacro(Float, float, VectorImage)
+  SetFromNumpyArrayMacro(Double, double, VectorImage)
+  SetFromNumpyArrayMacro(CFloat, std::complex<float>, VectorImage)
+  SetFromNumpyArrayMacro(CDouble, std::complex<double>, VectorImage)
+
+  SetFromNumpyArrayMacro(UInt8, unsigned char, Image)
+  SetFromNumpyArrayMacro(Int16, signed short, Image)
+  SetFromNumpyArrayMacro(UInt16, unsigned short, Image)
+  SetFromNumpyArrayMacro(Int32, signed int, Image)
+  SetFromNumpyArrayMacro(UInt32, unsigned int, Image)
+  // SetFromNumpyArrayMacro(Int64, signed long, Image)
+  // SetFromNumpyArrayMacro(UInt64, unsigned long, Image)
+  SetFromNumpyArrayMacro(Float, float, Image)
+  SetFromNumpyArrayMacro(Double, double, Image)
+  SetFromNumpyArrayMacro(CFloat, std::complex<float>, Image)
+  SetFromNumpyArrayMacro(CDouble, std::complex<double>, Image)
 #undef SetFromNumpyArrayMacro
 
-#define GetVectorImageAsNumpyArrayMacro(prefix, PixelType)                    \
-      void GetVectorImageAs##prefix##NumpyArray_(std::string pkey, ##PixelType##** buffer, int *dim1, int *dim2, int *dim3) \
-        {                                                               \
-        otb::Wrapper::Parameter *parameter = $self->GetParameterList()->GetParameterByKey(pkey); \
-        OutputImageParameter* outputImageParam = dynamic_cast<OutputImageParameter*>(parameter); \
-        typedef itk::ImageBase<2> ImageBaseType;                        \
-        typedef ImageBaseType::RegionType RegionType;          \
-        ImageBaseType::Pointer imageBase;                               \
-        imageBase = outputImageParam->GetValue();                       \
-        imageBase->Update();                                            \
-        typedef ImageBaseType::SizeType        SizeType;       \
-        typedef ImageBaseType::IndexType       IndexType;      \
-        typedef ImageBaseType::PointType       PointType;      \
-        typedef ImageBaseType::SpacingType     SpacingType;    \
-        RegionType region = imageBase->GetBufferedRegion();             \
-        SizeType size =  region.GetSize();                              \
-        *dim1 = size[1];                                                \
-        *dim2 = size[0];                                                \
-        typedef otb::VectorImage<signed char> Int8ImageType;            \
-        typedef otb::VectorImage<signed short> Int16ImageType;          \
-        typedef otb::VectorImage<signed int> Int32ImageType;            \
-        typedef otb::VectorImage<unsigned char> UInt8ImageType;         \
-        typedef otb::VectorImage<unsigned short> UInt16ImageType;       \
-        typedef otb::VectorImage<unsigned int> UInt32ImageType;         \
-        typedef otb::VectorImage<float> FloatImageType;                 \
-        typedef otb::VectorImage<double> DoubleImageType;               \
-        if (dynamic_cast<UInt8ImageType*>(imageBase.GetPointer()))      \
-          {                                                             \
-            UInt8ImageType* output = dynamic_cast<UInt8ImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<Int16ImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            Int16ImageType* output = dynamic_cast<Int16ImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<UInt16ImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            UInt16ImageType* output = dynamic_cast<UInt16ImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<Int32ImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            Int32ImageType* output = dynamic_cast<Int32ImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<UInt32ImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            UInt32ImageType* output = dynamic_cast<UInt32ImageType*>(imageBase.GetPointer()); \
-            *buffer = reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<FloatImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            FloatImageType* output = dynamic_cast<FloatImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else if (dynamic_cast<DoubleImageType*>(imageBase.GetPointer())) \
-          {                                                             \
-            DoubleImageType* output = dynamic_cast<DoubleImageType*>(imageBase.GetPointer()); \
-            *buffer  =  reinterpret_cast<##PixelType##*>(output->GetBufferPointer()); \
-              *dim3 = output->GetNumberOfComponentsPerPixel();          \
-          }                                                             \
-        else                                                            \
-          {                                                             \
-            std::cerr << "unknown image type. cannot make a numpy array" << std::endl; \
-          }                                                             \
-      }
+#define GetVectorImageAsNumpyArrayMacro(suffix, TPixel)                     \
+  void GetVectorImageAs##suffix##NumpyArray_                                  \
+    (std::string pkey, ##TPixel##** buffer, int *dim1, int *dim2, int *dim3)  \
+    {                                                                         \
+    ImageBaseType *img = $self->GetParameterOutputImage(pkey);                \
+    img->Update();                                                            \
+    unsigned int nbComp = img->GetNumberOfComponentsPerPixel();               \
+    ImageBaseType::RegionType region = img->GetBufferedRegion();              \
+    ImageBaseType::SizeType size = region.GetSize();                          \
+    *dim1 = region.GetSize(1);                                                \
+    *dim2 = region.GetSize(0);                                                \
+    *dim3 = nbComp;                                                           \
+    std::string className(img->GetNameOfClass());                             \
+    if (className == "VectorImage")                                           \
+      {                                                                       \
+      typedef otb::VectorImage<##TPixel##,2> LocalVectorImageType;            \
+      LocalVectorImageType* imgDown = dynamic_cast<LocalVectorImageType*>(img); \
+      if (imgDown)                                                            \
+        *buffer  =  reinterpret_cast<##TPixel##*>(imgDown->GetBufferPointer());  \
+      else                                                                    \
+        std::cerr << "VectorImage type doesn't match" << std::endl;           \
+      }                                                                       \
+    else                                                                      \
+      {                                                                       \
+      if (nbComp == 1)                                                        \
+        {                                                                     \
+        otb::Image<##TPixel##,2>* imgDown = dynamic_cast< otb::Image<##TPixel##,2>* >(img); \
+        if (imgDown)                                                          \
+          *buffer  =  reinterpret_cast<##TPixel##*>(imgDown->GetBufferPointer()); \
+        else                                                                  \
+          std::cerr << "Image type doesn't match" << std::endl;               \
+        }                                                                     \
+      else                                                                    \
+        {                                                                     \
+        std::cerr << "Unhandled number of components in otb::Image (RGB<T> "  \
+            "and RGBA<T> not supported yet)" << std::endl;                    \
+        }                                                                     \
+      }                                                                       \
+    }
 
-       GetVectorImageAsNumpyArrayMacro(Float, float)
-       GetVectorImageAsNumpyArrayMacro(Int16, signed short)
-       GetVectorImageAsNumpyArrayMacro(Int32, signed int)
-       GetVectorImageAsNumpyArrayMacro(UInt8, unsigned char)
-       GetVectorImageAsNumpyArrayMacro(UInt16, unsigned short)
-       GetVectorImageAsNumpyArrayMacro(UInt32, unsigned int)
-       GetVectorImageAsNumpyArrayMacro(Double, double)
+  GetVectorImageAsNumpyArrayMacro(UInt8, unsigned char)
+  GetVectorImageAsNumpyArrayMacro(Int16,signed short);
+  GetVectorImageAsNumpyArrayMacro(UInt16,unsigned short);
+  GetVectorImageAsNumpyArrayMacro(Int32,signed int);
+  GetVectorImageAsNumpyArrayMacro(UInt32,unsigned int);
+  GetVectorImageAsNumpyArrayMacro(Float,float);
+  GetVectorImageAsNumpyArrayMacro(Double,double);
+  GetVectorImageAsNumpyArrayMacro(CFloat,std::complex<float> );
+  GetVectorImageAsNumpyArrayMacro(CDouble,std::complex<double> );
+  // CInt16 and CInt32 are not supported in Numpy
 #undef GetVectorImageAsNumpyArrayMacro
 
+  std::string ConvertPixelTypeToNumpy(otb::Wrapper::ImagePixelType pixType)
+    {
+    std::ostringstream oss;
+    switch (pixType)
+      {
+      case otb::Wrapper::ImagePixelType_uint8 :
+        oss << "uint" << (sizeof(unsigned char) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_int16 :
+        oss << "int" << (sizeof(signed short) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_uint16 :
+        oss << "uint" << (sizeof(unsigned short) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_int32 :
+        oss << "int" << (sizeof(signed int) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_uint32 :
+        oss << "uint" << (sizeof(unsigned int) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_float :
+        oss << "float" << (sizeof(float) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_double :
+        oss << "float" << (sizeof(double) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_cfloat :
+        oss << "complex" << (sizeof(std::complex<float>) * 8);
+        break;
+      case otb::Wrapper::ImagePixelType_cdouble :
+        oss << "complex" << (sizeof(std::complex<double>) * 8);
+        break;
+      default:
+        std::cerr << "Pixel type not handled" << std::endl;
+        break;
+      }
+    return oss.str();
+    }
+
+  void SetupImageInformation(
+    ImageBaseType* img,
+    itk::Point<SpacePrecisionType,2> origin,
+    itk::Vector<SpacePrecisionType,2> spacing,
+    itk::Size<2> size,
+    itk::ImageRegion<2> bufferRegion,
+    itkMetaDataDictionary metadata)
+    {
+    img->SetOrigin(origin);
+    otb::internal::SetSignedSpacing(img, spacing);
+    itk::ImageRegion<2> largest;
+    largest.SetSize(size);
+    img->SetLargestPossibleRegion(largest);
+    if (bufferRegion.GetSize() != img->GetBufferedRegion().GetSize())
+      {
+      std::cerr << "Given buffered size doesn't match actual buffer size" << std::endl;
+      return;
+      }
+    img->SetRequestedRegion(bufferRegion);
+    img->SetBufferedRegion(bufferRegion);
+    img->SetMetaDataDictionary(metadata);
+    }
 } /* end of %extend */
 #endif /* OTB_SWIGNUMPY */
 
@@ -633,140 +716,159 @@ class ApplicationProxy(object):
 {
   %pythoncode
     {
-    def SetImageFromNumpyArray(self, paramKey, npArray):
+    NumpyExporterMap = {
+      ImagePixelType_uint8 : GetVectorImageAsUInt8NumpyArray_,
+      ImagePixelType_int16 : GetVectorImageAsInt16NumpyArray_,
+      ImagePixelType_uint16 : GetVectorImageAsUInt16NumpyArray_,
+      ImagePixelType_int32 : GetVectorImageAsInt32NumpyArray_,
+      ImagePixelType_uint32 : GetVectorImageAsUInt32NumpyArray_,
+      ImagePixelType_float : GetVectorImageAsFloatNumpyArray_,
+      ImagePixelType_double : GetVectorImageAsDoubleNumpyArray_,
+      ImagePixelType_cfloat : GetVectorImageAsCFloatNumpyArray_,
+      ImagePixelType_cdouble : GetVectorImageAsCDoubleNumpyArray_,
+      }
+    ImageImporterMap = {
+      ImagePixelType_uint8 : SetImageFromUInt8NumpyArray_,
+      ImagePixelType_int16 : SetImageFromInt16NumpyArray_,
+      ImagePixelType_uint16 : SetImageFromUInt16NumpyArray_,
+      ImagePixelType_int32 : SetImageFromInt32NumpyArray_,
+      ImagePixelType_uint32 : SetImageFromUInt32NumpyArray_,
+      ImagePixelType_float : SetImageFromFloatNumpyArray_,
+      ImagePixelType_double : SetImageFromDoubleNumpyArray_,
+      ImagePixelType_cfloat : SetImageFromCFloatNumpyArray_,
+      ImagePixelType_cdouble : SetImageFromCDoubleNumpyArray_,
+      }
+    VectorImageImporterMap = {
+      ImagePixelType_uint8 : SetVectorImageFromUInt8NumpyArray_,
+      ImagePixelType_int16 : SetVectorImageFromInt16NumpyArray_,
+      ImagePixelType_uint16 : SetVectorImageFromUInt16NumpyArray_,
+      ImagePixelType_int32 : SetVectorImageFromInt32NumpyArray_,
+      ImagePixelType_uint32 : SetVectorImageFromUInt32NumpyArray_,
+      ImagePixelType_float : SetVectorImageFromFloatNumpyArray_,
+      ImagePixelType_double : SetVectorImageFromDoubleNumpyArray_,
+      ImagePixelType_cfloat : SetVectorImageFromCFloatNumpyArray_,
+      ImagePixelType_cdouble : SetVectorImageFromCDoubleNumpyArray_,
+      }
+    
+    def SetImageFromNumpyArray(self, paramKey, npArray, index=0):
       """
       This method takes a numpy array and set ImageIOBase of
       InputImageParameter by creating an otbImage with
       same pixel type as numpyarray.dtype
       """
-      if len(npArray.shape) == 3:
-         raise ValueError( "(len(npArray.shape) == 3)\n"
-                           "Input array given is of 3 dimension.\n"
-                           "SetImageFromNumpyArray create ImageIO from otbImage and thus demands a 2d array.\n"
-                           "you can either provide an 2d numpy array or use SetVectorImageFromNumpyArray depending on your application.\n")
-
-      dt = npArray.dtype.name
-      if dt == 'int8':
-        self.SetImageFromInt8NumpyArray_(paramKey, npArray)
-      elif dt == 'int16':
-        self.SetImageFromInt16NumpyArray_(paramKey, npArray)
-      elif dt == 'int32':
-        self.SetImageFromInt32NumpyArray_(paramKey, npArray)
-      elif dt == 'uint8':
-        self.SetImageFromUInt8NumpyArray_(paramKey, npArray)
-      elif dt == 'uint16':
-        self.SetImageFromUInt16NumpyArray_(paramKey, npArray)
-      elif dt == 'uint32':
-        self.SetImageFromUInt32NumpyArray_(paramKey, npArray)
-      elif dt == 'float':
-        self.SetImageFromFloatNumpyArray_(paramKey, npArray)
-      elif dt == 'double':
-        self.SetImageFromDoubleNumpyArray_(paramKey, npArray)
+      shp = npArray.shape
+      if len(shp) == 2:
+        npArray = npArray.reshape((shp[0],shp[1],1))
+      elif len(shp) == 3:
+        if shp[2] > 1:
+          raise ValueError( "More than 1 band in numpy array\n"
+                           "Cannot convert to Image, use SetVectorImageFromNumpyArray instead\n")
       else:
-        self.SetImageFromFloatNumpyArray_(paramKey, npArray)
-      return
-
-    def SetVectorImageFromNumpyArray(self, paramKey, npArray):
+        raise ValueError( "Expected 2 or 3 dimensions for numpyarray\n")
+      dt = npArray.dtype.name
+      isFound = False
+      for pixT in self.ImageImporterMap:
+        if dt == self.ConvertPixelTypeToNumpy(pixT):
+          isFound = True
+          img = self.ImageImporterMap[pixT](self,paramKey, index, npArray)
+          break
+      if len(shp) == 2:
+        npArray = npArray.reshape(shp)
+      if not isFound:
+        raise ValueError("Can't convert Numpy array of dtype "+dt)
+      return img
+
+    def SetVectorImageFromNumpyArray(self, paramKey, npArray, index=0):
       """
-      This method takes a numpy array and set ImageIOBase of
+      This method takes a numpy array and set
       InputImageParameter by creating an otbVectorImage with
       same pixel type as numpyarray.dtype.
-      NOTE: Input (npArray) must be an ndarray with 3 dimension,
-      len(npArray.shape) must be > 2
+      NOTE: Input (npArray) must be an ndarray with 2 or 3 dimensions,
       """
-      if len(npArray.shape) < 3:
-        raise ValueError( "(len(npArray.shape) < 3)\n"
-                        "Input array given is not of 3 dimension.\n"
-                        "SetVectorImageFromNumpyArray create ImageIO from otbVectorImage and thus demands an array of shape 3.\n"
-                        "you can either provide an 3d numpy array or use SetImageFromNumpyArray depending on your application.\n")
-
+      shp = npArray.shape
+      if len(shp) == 2:
+        npArray = npArray.reshape((shp[0],shp[1],1))
+      elif len(npArray.shape) != 3:
+        raise ValueError( "Expected 2 or 3 dimensions for numpyarray")
       dt = npArray.dtype.name
-      if dt == 'int8':
-        self.SetVectorImageFromInt8NumpyArray_(paramKey, npArray)
-      elif dt == 'int16':
-        self.SetVectorImageFromInt16NumpyArray_(paramKey, npArray)
-      elif dt == 'int32':
-        self.SetVectorImageFromInt32NumpyArray_(paramKey, npArray)
-      elif dt == 'uint8':
-        self.SetVectorImageFromUInt8NumpyArray_(paramKey, npArray)
-      elif dt == 'uint16':
-        self.SetVectorImageFromUInt16NumpyArray_(paramKey, npArray)
-      elif dt == 'uint32':
-        self.SetVectorImageFromUInt32NumpyArray_(paramKey, npArray)
-      elif dt == 'float':
-        self.SetVectorImageFromFloatNumpyArray_(paramKey, npArray)
-      elif dt == 'double':
-        self.SetVectorImageFromDoubleNumpyArray_(paramKey, npArray)
-      else:
-        self.SetVectorImageFromFloatNumpyArray_(paramKey, npArray)
-      return
+      isFound = False
+      for pixT in self.VectorImageImporterMap:
+        if dt == self.ConvertPixelTypeToNumpy(pixT):
+          isFound = True
+          img = self.VectorImageImporterMap[pixT](self,paramKey, index, npArray)
+          break
+      if len(shp) == 2:
+        npArray = npArray.reshape(shp)
+      if not isFound:
+        raise ValueError("Can't convert Numpy array of dtype "+dt)
+      return img
 
     def GetVectorImageAsNumpyArray(self, paramKey, dt='float'):
       """
-      If datatype is unknown this method assumes to numpy.float32
-      Valid datatypes are:
-      int8, int16, int32, uint8, uint16, uint32, float, double.
-      NOTE: This method always return an numpy array with dimension 3
+      This function retrieves an output image parameter as a Numpy array.
+      The array datatype is guessed automatically from the underlying
+      otb::VectorImage<T,2> type (should also work with otb::Image<T,2>). The
+      optional parameter dt is deprecated and should not be used anymore. The
+      possible output datatypes are:
+      int8, int16, int32, uint8, uint16, uint32, float, double, cint16, cint32,
+      cfloat, cdouble.
+      NOTE: This method always return an numpy array with 3 dimensions
+      NOTE: cint16 and cint32 are not supported yet
       """
-      if dt == 'int8':
-        return self.GetVectorImageAsInt8NumpyArray_(paramKey)
-      elif dt == 'int16':
-        return self.GetVectorImageAsInt16NumpyArray_(paramKey)
-      elif dt == 'int32':
-        return self.GetVectorImageAsInt32NumpyArray_(paramKey)
-      elif dt == 'uint8':
-        return self.GetVectorImageAsUInt8NumpyArray_(paramKey)
-      elif dt == 'uint16':
-        return self.GetVectorImageAsUInt16NumpyArray_(paramKey)
-      elif dt == 'uint32':
-        return self.GetVectorImageAsUInt32NumpyArray_(paramKey)
-      elif dt == 'float':
-        return self.GetVectorImageAsFloatNumpyArray_(paramKey)
-      elif dt == 'double':
-        return self.GetVectorImageAsDoubleNumpyArray_(paramKey)
-      else:
-        print ("Unknown datatype '" + dt + "'. Using float instead. Available types are:")
-        print ("int8, int16, int32, uint8, uint16, uint32, float, double")
-        return self.GetVectorImageAsFloatNumpyArray_(paramKey)
+      pixT = self.GetImageBasePixelType(paramKey)
+      return self.NumpyExporterMap[pixT](self,paramKey)
 
     def GetImageAsNumpyArray(self, paramKey, dt='float'):
       """
-      If datatype is unknown this method assumes to numpy.float32
-      Valid datatypes are:
-      int8, int16, int32, uint8, uint16, uint32, float, double.
-      NOTE: This method always return an numpy array with dimension 3
+      This function retrieves an output image parameter as a Numpy array.
+      The array datatype is guessed automatically from the underlying
+      otb::VectorImage<T,2> type (should also work with otb::Image<T,2>). The
+      optional parameter dt is deprecated and should not be used anymore. The
+      possible output datatypes are:
+      int8, int16, int32, uint8, uint16, uint32, float, double, cint16, cint32,
+      cfloat, cdouble.
+      NOTE: This method always return an numpy array with 2 dimensions
+      NOTE: cint16 and cint32 are not supported yet
       """
-      if dt == 'int8':
-        numpy_vector_image = self.GetVectorImageAsInt8NumpyArray_(paramKey)
-      elif dt == 'int16':
-        numpy_vector_image = self.GetVectorImageAsInt16NumpyArray_(paramKey)
-      elif dt == 'int32':
-        numpy_vector_image = self.GetVectorImageAsInt32NumpyArray_(paramKey)
-      elif dt == 'uint8':
-        numpy_vector_image = self.GetVectorImageAsUInt8NumpyArray_(paramKey)
-      elif dt == 'uint16':
-        numpy_vector_image = self.GetVectorImageAsUInt16NumpyArray_(paramKey)
-      elif dt == 'uint32':
-        numpy_vector_image = self.GetVectorImageAsUInt32NumpyArray_(paramKey)
-      elif dt == 'float':
-        numpy_vector_image = self.GetVectorImageAsFloatNumpyArray_(paramKey)
-      elif dt == 'double':
-        numpy_vector_image = self.GetVectorImageAsDoubleNumpyArray_(paramKey)
-
-      else:
-        print ("Unknown datatype '" + dt + "'. Using float instead. Available types are:")
-        print ("int8, int16, int32, uint8, uint16, uint32, float, double")
-        numpy_vector_image = self.GetVectorImageAsFloatNumpyArray_(paramKey)
-
-      if numpy_vector_image.shape[2] > 1:
-        raise ValueError("numpy_vector_image.shape[2] > 1\n"
+      pixT = self.GetImageBasePixelType(paramKey)
+      array = self.NumpyExporterMap[pixT](self,paramKey)
+      if array.shape[2] > 1:
+        raise ValueError("array.shape[2] > 1\n"
                          "Output image from application has more than 1 band\n"
                          "GetImageFromNumpyArray only returns the first band, which will result in a loss of data.\n"
                          "In this case you must use GetVectorImageFromNumpyArray which is capable of return a 3 dimension image.\n")
+      array = array[:,:,0]
+      return array
+
+    def ImportImage(self, paramKey, pyImg, index = 0):
+      """
+      Import an image into a parameter, from a Python dict. with the following
+      keys: array, origin, spacing, size, region, metadata
+      """
+      img = self.SetImageFromNumpyArray(paramKey, pyImg["array"], index)
+      self.SetupImageInformation(img, pyImg["origin"], pyImg["spacing"], pyImg["size"], pyImg["region"], pyImg["metadata"])
 
-      numpy_vector_image = numpy_vector_image[:,:,0]
-      return numpy_vector_image
+    def ImportVectorImage(self, paramKey, pyImg, index = 0):
+      """
+      Import a vector image into a parameter, from a Python dict. with the following
+      keys: array, origin, spacing, size, region, metadata
+      """
+      img = self.SetVectorImageFromNumpyArray(paramKey, pyImg["array"], index)
+      self.SetupImageInformation(img, pyImg["origin"], pyImg["spacing"], pyImg["size"], pyImg["region"], pyImg["metadata"])
 
+    def ExportImage(self, paramKey):
+      """
+      Export an output image from an otbApplication into a python dictionary with the
+      following fields: array, origin, spacing, size, region, metadata
+      """
+      output = {}
+      output["array"] = self.GetVectorImageAsNumpyArray(paramKey)
+      output["origin"] = self.GetImageOrigin(paramKey)
+      output["spacing"] = self.GetImageSpacing(paramKey)
+      output["size"] = self.GetImageSize(paramKey)
+      output["region"] = self.GetImageRequestedRegion(paramKey)
+      output["metadata"] = self.GetImageMetaData(paramKey)
+      return output
 
     }
 }
@@ -781,6 +883,7 @@ public:
   static Application_Pointer CreateApplication(const std::string& name);
   static void AddApplicationPath(std::string newpath);
   static void SetApplicationPath(std::string newpath);
+  static void CleanRegistry();
 
 protected:
   Registry();
@@ -804,3 +907,133 @@ public:
 };
 
 %include "PyCommand.i"
+
+%extend itkMetaDataDictionary
+{
+  int GetType(const std::string &key)
+    {
+    return (int) otb::Wrapper::MetaDataHelper::GetType(key);
+    }
+
+  std::string GetString(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetString(* $self,key);
+    }
+  void SetString(const std::string &key, const std::string &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetString(* $self,key,val);
+    }
+
+  unsigned int GetInt(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetInt(* $self,key);
+    }
+  void SetInt(const std::string &key, unsigned int val)
+    {
+    otb::Wrapper::MetaDataHelper::SetInt(* $self,key,val);
+    }
+
+  double GetDouble(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetDouble(* $self,key);
+    }
+  void SetDouble(const std::string &key, double val)
+    {
+    otb::Wrapper::MetaDataHelper::SetDouble(* $self,key,val);
+    }
+
+  otb::OTB_GCP GetGCP(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetGCP(* $self,key);
+    }
+  void SetGCP(const std::string &key, const otb::OTB_GCP &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetGCP(* $self,key,val);
+    }
+
+  std::vector<double> GetVector(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetVector(* $self,key);
+    }
+  void SetVector(const std::string &key, const std::vector<double> &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetVector(* $self,key,val);
+    }
+
+  otb::ImageKeywordlist GetImageKWL(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetImageKWL(* $self,key);
+    }
+  void SetImageKWL(const std::string &key, const otb::ImageKeywordlist &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetImageKWL(* $self,key,val);
+    }
+
+  otb::VectorDataKeywordlist GetVectorDataKWL(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetVectorDataKWL(* $self,key);
+    }
+  void SetVectorDataKWL(const std::string &key, const otb::VectorDataKeywordlist &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetVectorDataKWL(* $self,key,val);
+    }
+
+  std::vector<bool> GetBoolVector(const std::string &key)
+    {
+    return otb::Wrapper::MetaDataHelper::GetBoolVector(* $self,key);
+    }
+  void SetBoolVector(const std::string &key, const std::vector<bool> &val)
+    {
+    otb::Wrapper::MetaDataHelper::SetBoolVector(* $self,key,val);
+    }
+
+#if SWIGPYTHON
+// enhance the MetaDataDictionary class for Python
+  %pythoncode
+  {
+    GetterMap = {
+      0 : GetString,
+      1 : GetInt,
+      2 : GetDouble,
+      3 : GetGCP,
+      4 : GetVector,
+      5 : GetImageKWL,
+      6 : GetVectorDataKWL,
+      7 : GetBoolVector,
+      }
+
+    SetterMap = {
+      0 : SetString,
+      1 : SetInt,
+      2 : SetDouble,
+      3 : SetGCP,
+      4 : SetVector,
+      5 : SetImageKWL,
+      6 : SetVectorDataKWL,
+      7 : SetBoolVector,
+      }
+
+    def __str__(self):
+      ret = ''
+      for k in self.GetKeys():
+        ret += k + ':<...>, '
+      if len(ret) == 0:
+        ret += ', '
+      return "{"+ret[:-2] +"}"
+    def __len__(self):
+      return len(self.GetKeys())
+    def keys(self):
+      return self.GetKeys()
+    def __getitem__(self,key):
+      if key in self.GetKeys():
+        return self.GetterMap[self.GetType(key)](self,key)
+      else:
+        raise IndexError('Key not recognized')
+    def __setitem__(self,key,val):
+      if key in self.GetKeys():
+        self.SetterMap[self.GetType(key)](self,key,val)
+      else:
+        raise IndexError('Key not recognized')
+  }
+#endif
+};
diff --git a/Modules/Wrappers/SWIG/src/otbWrapperSWIGIncludes.h b/Modules/Wrappers/SWIG/src/otbWrapperSWIGIncludes.h
index 9bd940ef789a342131b1656906c14c1566949e40..8ded93c90a6869320b45d597d51d43d4ca565a43 100644
--- a/Modules/Wrappers/SWIG/src/otbWrapperSWIGIncludes.h
+++ b/Modules/Wrappers/SWIG/src/otbWrapperSWIGIncludes.h
@@ -24,6 +24,7 @@
 #include "otbWrapperApplicationRegistry.h"
 #include "otbWrapperAddProcessToWatchEvent.h"
 #include "otbWrapperDocExampleStructure.h"
+#include "otbWrapperMetaDataHelper.h"
 
 typedef otb::Wrapper::Application                        Application;
 typedef otb::Wrapper::Application::Pointer               Application_Pointer;
@@ -36,4 +37,6 @@ typedef otb::Wrapper::InputImageParameter                InputImageParameter;
 typedef otb::Wrapper::ComplexOutputImageParameter        ComplexOutputImageParameter;
 typedef otb::Wrapper::ComplexInputImageParameter         ComplexInputImageParameter;
 
+typedef otb::Wrapper::ImageBaseType                      ImageBaseType;
+
 #endif
diff --git a/Modules/Wrappers/SWIG/test/python/CMakeLists.txt b/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
index bd5865b5706658c76aa13d81c90f4ee5926c5b6d..edbef92fe8ac7a2267ec0c395a84809b3151c16f 100644
--- a/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
+++ b/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
@@ -146,3 +146,10 @@ add_test( NAME pyTvParametersDict
   ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/PythonTestDriver.py
   PythonParametersDict
   ${OTB_DATA_ROOT}/Input/poupees.tif)
+
+add_test( NAME pyTvImageInterface
+  COMMAND ${TEST_DRIVER} Execute
+  ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/PythonTestDriver.py
+  PythonImageInterface
+  ${OTB_DATA_ROOT}/Examples/QB_Toulouse_Ortho_XS.tif
+  )
diff --git a/Modules/Wrappers/SWIG/test/python/PythonImageInterface.py b/Modules/Wrappers/SWIG/test/python/PythonImageInterface.py
new file mode 100644
index 0000000000000000000000000000000000000000..62aade511e61aeaf5689fdaa00f8bda03afe4b9a
--- /dev/null
+++ b/Modules/Wrappers/SWIG/test/python/PythonImageInterface.py
@@ -0,0 +1,23 @@
+
+def test(otb, argv):
+  # Create a smoothing application
+  app = otb.Registry.CreateApplication("Smoothing")
+  app.SetParameterString("in",argv[1])
+  app.Execute()
+
+  # Setup a special requested region
+  myRegion = otb.itkRegion()
+  myRegion.GetSize()[0] = 20
+  myRegion.GetSize()[1] = 25
+  myRegion.GetIndex().Fill(10)
+  app.PropagateRequestedRegion("out",myRegion)
+  print(app.GetImageRequestedRegion("in"))
+  
+  # Create a ReadImageInfo application and plug the output of app
+  app2 = otb.Registry.CreateApplication("ReadImageInfo")
+  ex = app.ExportImage("out")
+  app2.ImportVectorImage("in", ex)
+  app2.Execute()
+  someKeys = ['sizex', 'sizey', 'spacingx', 'spacingy', 'sensor', 'projectionref']
+  for key in someKeys:
+    print(key + ' : ' + str(app2.GetParameterValue(key)) )