diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f75933dfe9f27bf2218896049fcb8955b553b713..f59baac2626b15469be898b1003c153933de6885 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,7 +5,7 @@
 # But Git fails to manage efficiently numerous LFS data.
 # We have to use directly git-lfs wrapping commands to have an
 # efficient cloning step.
-# Furthermore, Git-LFS and Gitlab sufer a bug preventing usage of 
+# Furthermore, Git-LFS and Gitlab sufer a bug preventing usage of
 # GIT_STRATEGY=fetch (https://gitlab.com/gitlab-org/gitlab-runner/issues/3318)
 
 variables:
@@ -29,6 +29,8 @@ after_script:
   - python3 CI/cdash_handler.py $CI_COMMIT_SHA $CI_PROJECT_ID $CI_PROJECT_DIR $K8S_SECRET_CDASH
 
 stages:
+  - precheck
+  - prepare
   - build
 
 .general:
@@ -38,40 +40,91 @@ stages:
       - runner_system_failure
       - stuck_or_timeout_failure
 
-native-build:
+fast-build:
   extends: .general
-  only: [merge_requests]
-  stage: build
-  image: $BUILD_IMAGE_REGISTRY/otb-ubuntu-native:18.04
+  only: [merge_requests, branches]
+  stage: precheck
+  image: $CI_REGISTRY/gpasero/otb/otb-install-ubuntu-native
+  before_script:
+    - export GIT_LFS_SKIP_SMUDGE=1
+    - git checkout $CI_COMMIT_REF_NAME
+    - python3 CI/check_twin_pipelines.py
   script:
-    - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_ci.cmake -DIMAGE_NAME:string=ubuntu-18.04-gcc
+    - ctest -V -S CI/main_ci.cmake -DIMAGE_NAME:string=ubuntu-18.04-fast
+    - ccache -s
 
-debian-build:
+.common-build:
   extends: .general
   only: [merge_requests]
   stage: build
+
+debian-build:
+  extends: .common-build
   image: $BUILD_IMAGE_REGISTRY/otb-debian-native:unstable
   script:
     - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_ci.cmake -DIMAGE_NAME:string=debian-unstable-gcc
 
-.common-build:
-  extends: .general
-  stage: build
-  image: $BUILD_IMAGE_REGISTRY/otb-ubuntu-shark:18.04
+ubuntu-llvm:
+  extends: .common-build
+  image: $BUILD_IMAGE_REGISTRY/otb-ubuntu-native:18.04
   script:
-    - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_ci.cmake -DIMAGE_NAME:string=ubuntu-18.04-llvm-shark
+    - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_ci.cmake -DIMAGE_NAME:string=ubuntu-18.04-llvm
   artifacts:
     paths:
       - build/CookBook-*-html.tar.gz
       - build/Documentation/Cookbook/latex/CookBook-*.pdf
       - build/Documentation/Doxygen/OTB-Doxygen-*.tar.bz2
 
-# This is needed to have only one pipeline in a merge request context
-ubuntu-llvm:
+.common-prepare:
+  extends: .general
   only: [merge_requests]
-  extends: .common-build
+  stage: prepare
+  before_script:
+# This override the previous before_script
+    - git checkout $CI_COMMIT_REF_NAME
+# We are now doing the git-lfs install
+# This is done after the checkout so we avoid downloading Data
+# But we need it to upload the archive
+    - git-lfs install
+    - git config --global user.email "otbbot@orfeo-toolbox.org"
+    - git config --global user.name "otbbot"
+    - eval $(ssh-agent -s)
+    - ssh-add <(echo "$K8S_SECRET_SSH")
+# This is for debug, we are checking the owner of the ssh key
+    - ssh -o StrictHostKeyChecking=no -T git@gitlab.orfeo-toolbox.org
+  after_script:
+    - echo "Nothing to do for after_script"
+  artifacts:
+    expire_in: 24 hrs
+    paths:
+      # This recovers logs from superbuild build
+      - build/*/*/*/*.log
+      - sb_branch.txt
 
-ubuntu-llvm-wip:
-  except: [merge_requests]
+ubuntu-superbuild-prepare:
+  extends: .common-prepare
+  image: $BUILD_IMAGE_REGISTRY/otb-ubuntu-superbuild-base:18.04
+  script:
+    - ctest -V -S CI/prepare_superbuild.cmake -DIMAGE_NAME:string=otb-ubuntu-superbuild-base
+
+centos-superbuild-prepare:
+  extends: .common-prepare
+  image: $BUILD_IMAGE_REGISTRY/otb-centos-superbuild-base:6.6
+  script:
+    - ctest -V -S CI/prepare_superbuild.cmake -DIMAGE_NAME:string=otb-centos-superbuild-base
+
+ubuntu-superbuild-build:
   extends: .common-build
+  image: $BUILD_IMAGE_REGISTRY/otb-ubuntu-superbuild-base:18.04
+  script:
+    - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_superbuild.cmake -DIMAGE_NAME:string=otb-ubuntu-superbuild-base
+  dependencies:
+    - ubuntu-superbuild-prepare
 
+centos-superbuild-build:
+  extends: .common-build
+  image: $BUILD_IMAGE_REGISTRY/otb-centos-superbuild-base:6.6
+  script:
+    - xvfb-run -a -n 1 -s "-screen 0 1024x768x24 -dpi 96" ctest -V -S CI/main_superbuild.cmake -DIMAGE_NAME:string=otb-centos-superbuild-base
+  dependencies:
+    - centos-superbuild-prepare
diff --git a/CI/check_twin_pipelines.py b/CI/check_twin_pipelines.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2a6113924677266de8cf30f8d35debc8ee2c3ea
--- /dev/null
+++ b/CI/check_twin_pipelines.py
@@ -0,0 +1,88 @@
+#
+# Copyright (C) 2005-2019 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.
+#
+
+import os
+import urllib.request
+import urllib.parse
+import json
+import re
+import time
+
+"""
+Send a request to Gitlab and return the answer
+The request parameter is added after `project/:id/`
+WARNING: when data is given, the request will be a POST
+Otherwise, it is a GET
+"""
+def GitlabRequest(request, project=53, data=None, token=''):
+  gitlab_url = "https://gitlab.orfeo-toolbox.org/api/v4/projects/"
+  gitlab_url+= str(project) + '/' + request
+  params = None
+  myHeader = {}
+  if not data is None:
+    params = urllib.parse.urlencode(data).encode('ascii')
+  if token:
+    myHeader = {'PRIVATE-TOKEN':token}
+  gitlab_request = urllib.request.Request(gitlab_url, data=params, headers=myHeader)
+  res = urllib.request.urlopen(gitlab_request)
+  return json.loads(res.read().decode())
+
+"""
+Check needed environment parameters
+"""
+def CheckEnvParameters(params):
+  for p in params:
+    if not p in os.environ.keys():
+      print("Missing environment variable '"+p+"'")
+      return False
+  return True
+
+"""
+Check for any duplicated twin pipeline and cancel it
+"""
+if __name__ == "__main__":
+  if not CheckEnvParameters(['CI_COMMIT_SHA']):
+    sys.exit(1)
+  env = os.environ
+  sha1 = env['CI_COMMIT_SHA']
+  # are we in a merge_request pipeline ?
+  if 'CI_MERGE_REQUEST_IID' in env.keys():
+    if not CheckEnvParameters(['K8S_SECRET_TWIN_PIPELINE','CI_PROJECT_ID','CI_PIPELINE_ID']):
+      sys.exit(1)
+    mrInfo = GitlabRequest('merge_requests/'+env['CI_MERGE_REQUEST_IID'],token=env['K8S_SECRET_TWIN_PIPELINE'])
+    wip_regex = re.compile("^[Ww][Ii][Pp]:")
+    # is it a "WIP" merge request ?
+    if wip_regex.search(mrInfo["title"]):
+      # Yes: cancel the current pipeline
+      print("Cancel current pipeline "+env['CI_PIPELINE_ID'])
+      GitlabRequest('pipelines/'+env['CI_PIPELINE_ID']+'/cancel', data={}, \
+        project=env['CI_PROJECT_ID'], token=env['K8S_SECRET_TWIN_PIPELINE'])
+      time.sleep(180)
+      print("Error: this pipeline should have been canceled")
+      sys.exit(1)
+    else:
+      # No: cancel any previous "normal" pipeline on the same SHA1
+      jres = GitlabRequest('pipelines?sha='+sha1, project=env['CI_PROJECT_ID'], token=env['K8S_SECRET_TWIN_PIPELINE'])
+      for item in jres:
+        if item["id"] < int(env['CI_PIPELINE_ID']) and item["status"] == "running":
+          print("Cancel pipeline "+str(item["id"]))
+          jres2 = GitlabRequest('pipelines/'+str(item["id"])+'/cancel', data={}, \
+            project=env['CI_PROJECT_ID'], token=env['K8S_SECRET_TWIN_PIPELINE'])
+
diff --git a/CI/configure_option.cmake b/CI/configure_option.cmake
index 26502b11bfa758e483b8b60cafb62e1ad6ff9067..d0b41c6adc0fe7546fecfbb698a5710cf849755d 100644
--- a/CI/configure_option.cmake
+++ b/CI/configure_option.cmake
@@ -19,13 +19,13 @@
 #
 
 # This script is a prototype for the future CI, it may evolve rapidly in a near future
-#This file set the following variable : 
+#This file set the following variable :
 # * otb_build_project_option
 # * otb_use_option
 # * otb_wrap_option
 # * CONFIGURE_OPTIONS
 
-set (otb_build_project_option 
+set (otb_build_project_option
 "BUILD_COOKBOOK:BOOL=OFF
 BUILD_EXAMPLES:BOOL=ON
 BUILD_SHARED_LIBS:BOOL=ON
@@ -40,7 +40,7 @@ OTB_USE_GLUT:BOOL=ON
 OTB_USE_GSL:BOOL=ON
 OTB_USE_LIBKML:BOOL=ON
 OTB_USE_LIBSVM:BOOL=ON
-OTB_USE_MPI:BOOL=ON
+OTB_USE_MPI:BOOL=OFF
 OTB_USE_MUPARSER:BOOL=ON
 OTB_USE_MUPARSERX:BOOL=ON
 OTB_USE_OPENCV:BOOL=ON
diff --git a/CI/macros.cmake b/CI/macros.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..544daca845fd1b0d8fe36d746cd698fa09ce3a76
--- /dev/null
+++ b/CI/macros.cmake
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2005-2019 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.
+#
+# This script is for the superbuild build on the CI platform
+
+# Find the build name and CI profile
+macro( set_dash_build_name )
+  set(ci_profile wip)
+
+  set(ci_mr_source "$ENV{CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}")
+  set(ci_mr_target "$ENV{CI_MERGE_REQUEST_TARGET_BRANCH_NAME}")
+  set(ci_mr_iid "$ENV{CI_MERGE_REQUEST_IID}")
+
+  set(ci_pipeline_id "$ENV{CI_PIPELINE_ID}")
+  set(ci_job_id "$ENV{CI_JOB_ID}")
+
+  set(ci_ref_name "$ENV{CI_COMMIT_REF_NAME}")
+
+  set (CTEST_BUILD_NAME ${ci_short_sha})
+
+  if(ci_mr_source AND ci_mr_target AND ci_mr_iid)
+    set (CTEST_BUILD_NAME "${ci_mr_source} (MR ${ci_mr_iid}) P-${ci_pipeline_id}")
+    set(ci_profile mr)
+
+  elseif(ci_ref_name)
+    set (CTEST_BUILD_NAME "${ci_ref_name} P-${ci_pipeline_id}")
+
+    if("${ci_ref_name}" STREQUAL "develop")
+      set(ci_profile develop)
+
+    elseif("${ci_ref_name}" MATCHES "^release-[0-9]+\\.[0-9]+\$")
+      set(ci_profile release)
+    endif()
+
+  endif()
+
+endmacro()
diff --git a/CI/main_ci.cmake b/CI/main_ci.cmake
index 64c72fb95ce501ec653cb5040925913ffc11d4da..eba3829c5017383a253e86a2d197ec0f1b860f1a 100644
--- a/CI/main_ci.cmake
+++ b/CI/main_ci.cmake
@@ -18,6 +18,8 @@
 # limitations under the License.
 #
 
+include( "${CMAKE_CURRENT_LIST_DIR}/macros.cmake" )
+
 # This script is a prototype for the future CI, it may evolve rapidly in a near future
 get_filename_component(OTB_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
 set (ENV{LANG} "C") # Only ascii output
@@ -26,39 +28,49 @@ set (ENV{LANG} "C") # Only ascii output
 set (CTEST_BUILD_CONFIGURATION "Release")
 set (CTEST_CMAKE_GENERATOR "Ninja")
 
-# Find the build name and CI profile
-set(ci_profile wip)
-set(ci_mr_source "$ENV{CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}")
-set(ci_mr_target "$ENV{CI_MERGE_REQUEST_TARGET_BRANCH_NAME}")
-set(ci_mr_iid "$ENV{CI_MERGE_REQUEST_IID}")
-set(ci_ref_name "$ENV{CI_COMMIT_REF_NAME}")
-set (CTEST_BUILD_NAME "$ENV{CI_COMMIT_SHORT_SHA}")
-if(ci_mr_source AND ci_mr_target AND ci_mr_iid)
-  set (CTEST_BUILD_NAME "${ci_mr_source} (MR ${ci_mr_iid})")
-  set(ci_profile mr)
-elseif(ci_ref_name)
-  set (CTEST_BUILD_NAME "${ci_ref_name}")
-  if("${ci_ref_name}" STREQUAL "develop")
-    set(ci_profile develop)
-  elseif("${ci_ref_name}" MATCHES "^release-[0-9]+\\.[0-9]+\$")
-    set(ci_profile release)
-  endif()
+# detect short sha
+if(NOT DEFINED ENV{CI_COMMIT_SHORT_SHA})
+  execute_process(COMMAND git log -1 --pretty=format:%h
+                  WORKING_DIRECTORY ${OTB_SOURCE_DIR}
+                  OUTPUT_VARIABLE ci_short_sha)
+else()
+  set(ci_short_sha "$ENV{CI_COMMIT_SHORT_SHA}")
 endif()
 
+# Find the build name and CI profile
+set_dash_build_name()
+
 # set pipelines to enable documentation
 set(ci_cookbook_profiles mr develop release)
 set(ci_doxygen_profiles mr develop release)
 list(FIND ci_cookbook_profiles ${ci_profile} ci_do_cookbook)
 list(FIND ci_doxygen_profiles ${ci_profile} ci_do_doxygen)
 
-#Warning, this variable is used in cdash_status.py. If change from 
-# ${IMAGE_NAME} to something else do not forget to change it.
+# Detect site
+if(NOT DEFINED IMAGE_NAME)
+  if(DEFINED ENV{IMAGE_NAME})
+    set(IMAGE_NAME $ENV{IMAGE_NAME})
+  endif()
+endif()
 set (CTEST_SITE "${IMAGE_NAME}")
 
+# Detect "skip testing"
+if(DEFINED ENV{CI_SKIP_TESTING})
+  set(ci_skip_testing 1)
+endif()
+
 # Directory variable
 set (CTEST_SOURCE_DIRECTORY "${OTB_SOURCE_DIR}")
-set (CTEST_BINARY_DIRECTORY "${OTB_SOURCE_DIR}/build/")
-set (CTEST_INSTALL_DIRECTORY "${OTB_SOURCE_DIR}/install/")
+if(BUILD_DIR)
+  set (CTEST_BINARY_DIRECTORY "${BUILD_DIR}")
+else()
+  set (CTEST_BINARY_DIRECTORY "${OTB_SOURCE_DIR}/build/")
+endif()
+if(INSTALL_DIR)
+  set (CTEST_INSTALL_DIRECTORY "${INSTALL_DIR}")
+else()
+  set (CTEST_INSTALL_DIRECTORY "${OTB_SOURCE_DIR}/install/")
+endif()
 set (PROJECT_SOURCE_DIR "${OTB_SOURCE_DIR}")
 
 # Ctest command value
@@ -83,7 +95,7 @@ find_program(CTEST_GIT_COMMAND NAMES git git.cmd)
 # End of configuration
 
 
-ctest_start (Experimental TRACK Experimental)
+ctest_start (Experimental TRACK CI_Build)
 
 ctest_update()
 
@@ -109,10 +121,15 @@ if ( NOT _build_rv EQUAL 0 )
   message( SEND_ERROR "An error occurs during ctest_build.")
 endif()
 
-ctest_test(PARALLEL_LEVEL 8
-           RETURN_VALUE _test_rv
-           CAPTURE_CMAKE_ERROR _test_error
-           )
+if(ci_skip_testing)
+  message(STATUS "Skip testing")
+  set(_test_rv 0)
+else()
+  ctest_test(PARALLEL_LEVEL 8
+             RETURN_VALUE _test_rv
+             CAPTURE_CMAKE_ERROR _test_error
+             )
+endif()
 
 if ( NOT _test_rv EQUAL 0 )
   message( SEND_ERROR "An error occurs during ctest_test.")
diff --git a/CI/main_superbuild.cmake b/CI/main_superbuild.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..757dbb1ad39e55f75e76f157da0ddd15118c74d7
--- /dev/null
+++ b/CI/main_superbuild.cmake
@@ -0,0 +1,173 @@
+#
+# Copyright (C) 2005-2019 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( "${CMAKE_CURRENT_LIST_DIR}/macros.cmake" )
+
+# This script is a prototype for the future CI, it may evolve rapidly in a near future
+set (ENV{LANG} "C") # Only ascii output
+get_filename_component(OTB_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
+get_filename_component(CI_PROJ_DIR ${OTB_SOURCE_DIR} DIRECTORY)
+get_filename_component(CI_ROOT_DIR ${CI_PROJ_DIR} DIRECTORY)
+
+###########################################################################
+###########################################################################
+# Download xkd
+###########################################################################
+###########################################################################
+
+# How to get md5sum:
+# * concatenate all source files in one
+# * add configure result from previous job ${OTB_SOURCE_DIR}/build/CMakeCache.txt
+###########################
+
+file(READ "${OTB_SOURCE_DIR}/sb_branch.txt" BRANCH_NAME)
+
+####################################
+
+
+# git clone $REPOSITORY_URL --branch $BRANCH_NAME --depth 1 superbuild-artifact
+###############################################################################
+set ( REMOTE "https://gitlab.orfeo-toolbox.org/gbonnefille/superbuild-artifact.git")
+# set ( BRANCH_NAME "${IMAGE_NAME}/${SB_MD5}")
+
+# Look for a GIT command-line client.
+find_program(CTEST_GIT_COMMAND NAMES git git.cmd)
+
+# FIXME: Replace ${GIT} variable with $[CTEST_GIT_COMMAND}"
+set( GIT "${CTEST_GIT_COMMAND}" )
+
+execute_process(
+  COMMAND ${GIT} "clone" "${REMOTE}" "--branch" "${BRANCH_NAME}"
+  "--depth" "1" "superbuild-artifact"
+  WORKING_DIRECTORY ${CI_PROJ_DIR}
+  RESULT_VARIABLE clone_res
+  OUTPUT_VARIABLE clone_out
+  ERROR_VARIABLE clone_err
+  )
+
+if ( DEBUG )
+  message( "Clone")
+  message( "clone_res = ${clone_res}" )
+  message( "clone_out = ${clone_out}" )
+  message( "clone_err = ${clone_err}" )
+endif()
+
+if (clone_res)
+  message( SEND_ERROR "Problem in retreiving the archive")
+  return()
+endif()
+
+set (CMAKE_COMMAND "cmake")
+execute_process(
+  COMMAND ${CMAKE_COMMAND} "-E" "tar" "xf"
+  "${CI_PROJ_DIR}/superbuild-artifact/SuperBuild_Install.tar"
+  WORKING_DIRECTORY ${CI_ROOT_DIR}
+  )
+
+set( XDK_PATH "${CI_ROOT_DIR}/xdk")
+
+if ( DEBUG )
+  if ( EXISTS "${XDK_PATH}")
+    message("Tar file exists at ${XDK_PATH}")
+  else()
+    message("Something went wrong no tar file in ${XDK_PATH}")
+  endif()
+endif()
+
+###########################################################################
+###########################################################################
+# Building OTB
+###########################################################################
+###########################################################################
+
+set ( CTEST_BUILD_CONFIGURATION "Release" )
+set ( CTEST_CMAKE_GENERATOR "Unix Makefiles" )
+set ( CTEST_BUILD_FLAGS "-j8" )
+set ( CTEST_SITE "${IMAGE_NAME}" )
+
+# Find the build name and CI profile
+set_dash_build_name()
+
+# Directory variable
+set ( CTEST_SOURCE_DIRECTORY "${OTB_SOURCE_DIR}" )
+set ( CTEST_BINARY_DIRECTORY "${OTB_SOURCE_DIR}/build/" )
+set ( CTEST_INSTALL_DIRECTORY "${OTB_SOURCE_DIR}/install/" )
+set ( PROJECT_SOURCE_DIR "${OTB_SOURCE_DIR}" )
+
+set (CONFIGURE_OPTIONS  "")
+include ( "${CMAKE_CURRENT_LIST_DIR}/configure_option.cmake" )
+# SuperBuild case : one more configure option
+set ( CONFIGURE_OPTIONS
+  "${CONFIGURE_OPTIONS}-DCMAKE_PREFIX_PATH=${XDK_PATH};")
+
+# Hack because there is no more superbuild available (LIBKML)
+set ( CONFIGURE_OPTIONS
+  "${CONFIGURE_OPTIONS}-DOTB_USE_LIBKML:BOOL=OFF;" )
+
+# FIX ME this part might platform dependent
+set( GDAL_DATA "${XDK_PATH}/share/gdal" )
+set( GEOTIFF_CSV "${XDK_PATH}/share/epsg_csv" )
+set( PROJ_LIB "${XDK_PATH}/share" )
+set( CTEST_ENVIRONMENT
+"PATH=${XDK_PATH}/lib:${XDK_PATH}/bin:$ENV{PATH}
+GDAL_DATA= GDAL_DATA
+GEOTIFF_CSV= GEOTIFF_CSV
+PROJ_LIB= PROJ_LIB
+")
+
+# Sources are already checked out : do nothing for update
+set(CTEST_GIT_UPDATE_CUSTOM echo No update)
+
+ctest_start (Experimental TRACK CI_Build)
+
+ctest_update()
+
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}"
+    SOURCE "${OTB_SOURCE_DIR}"
+    OPTIONS "${CONFIGURE_OPTIONS}"
+    RETURN_VALUE _configure_rv
+    CAPTURE_CMAKE_ERROR _configure_error
+    )
+
+if ( NOT _configure_rv EQUAL 0 )
+  ctest_submit()
+  message( FATAL_ERROR "An error occurs during ctest_configure.")
+endif()
+
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}"
+            RETURN_VALUE _build_rv
+            CAPTURE_CMAKE_ERROR _build_error
+            )
+
+if ( NOT _build_rv EQUAL 0 )
+  message( SEND_ERROR "An error occurs during ctest_build.")
+endif()
+
+# Uncomment when ready for test
+ctest_test(PARALLEL_LEVEL 8
+           RETURN_VALUE _test_rv
+           CAPTURE_CMAKE_ERROR _test_error
+           )
+
+if ( NOT _test_rv EQUAL 0 )
+  message( WARNING "Some tests have failed.")
+endif()
+
+ctest_submit()
diff --git a/CI/prepare_superbuild.cmake b/CI/prepare_superbuild.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..65f420c5e865e43043e544764c599a494457f242
--- /dev/null
+++ b/CI/prepare_superbuild.cmake
@@ -0,0 +1,361 @@
+#
+# Copyright (C) 2005-2019 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.
+#
+# This script is for the superbuild build on the CI platform
+
+include( "${CMAKE_CURRENT_LIST_DIR}/macros.cmake" )
+
+set (ENV{LANG} "C") # Only ascii output
+get_filename_component(OTB_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
+get_filename_component(CI_PROJ_DIR ${OTB_SOURCE_DIR} DIRECTORY)
+get_filename_component(CI_ROOT_DIR ${CI_PROJ_DIR} DIRECTORY)
+
+# In GitLab we have :
+#   OTB_SOURCE_DIR=/builds/{project_dir}/otb
+#   CI_PROJ_DIR=/builds/{project_dir}
+#   CI_ROOT_DIR=/builds
+
+set ( DEBUG "1" )
+
+set ( SUPERBUILD_SOURCE_DIR "${OTB_SOURCE_DIR}/SuperBuild" )
+
+set ( CTEST_BUILD_CONFIGURATION "Release" )
+set ( CTEST_CMAKE_GENERATOR "Unix Makefiles" )
+set ( PROJECT_SOURCE_DIR "${SUPERBUILD_SOURCE_DIR}" )
+set ( CTEST_SOURCE_DIRECTORY "${SUPERBUILD_SOURCE_DIR}" )
+set ( CTEST_BINARY_DIRECTORY "${OTB_SOURCE_DIR}/build/" )
+set ( CTEST_SITE "${IMAGE_NAME}" )
+
+
+# Find the build name and CI profile
+set_dash_build_name()
+
+# We need a directory independent from user
+# in CI the architecture is /builds/user/otb
+# So we will go in /builds/
+# This is platform dependent, and the next step (build) also
+# depends on that, as some paths are hardcoded
+# This can be fixed with a packaging of OTB_DEPENDS
+set (CTEST_INSTALL_DIRECTORY "${CI_ROOT_DIR}/xdk/")
+
+# HACK
+# This is needed because when using return() function ctest is trying
+# to run the CTEST_COMMAND. And we need it to not produce an error
+set (CTEST_COMMAND "echo \"Exit\"") # HACK FIX ME
+set (CMAKE_COMMAND "cmake")
+
+########################################################################
+########################################################################
+# Build process
+########################################################################
+########################################################################
+
+# Look for a GIT command-line client.
+find_program(CTEST_GIT_COMMAND NAMES git git.cmd)
+
+# FIXME: Replace ${GIT} variable with $[CTEST_GIT_COMMAND}"
+set( GIT "${CTEST_GIT_COMMAND}" )
+
+# Sources are already checked out : do nothing for update
+set(CTEST_GIT_UPDATE_CUSTOM echo No update)
+
+ctest_start (Experimental TRACK CI_Prepare)
+
+ctest_update( SOURCE "${OTB_SOURCE_DIR}" )
+
+set(CTEST_BUILD_FLAGS "-j16")
+
+set ( SB_CONFIGURE_OPTIONS "")
+include( "${CMAKE_CURRENT_LIST_DIR}/../SuperBuild/CI/configure_options.cmake" )
+
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}"
+    SOURCE "${SUPERBUILD_SOURCE_DIR}"
+    OPTIONS "${SB_CONFIGURE_OPTIONS}"
+    RETURN_VALUE _configure_rv
+    CAPTURE_CMAKE_ERROR _configure_error
+    )
+
+if ( NOT _configure_rv EQUAL 0 )
+  ctest_submit()
+  message( SEND_ERROR "An error occurs during ctest_configure. Dependencies might be buggy.")
+  return()
+endif()
+
+########################################################################
+########################################################################
+# Check process
+########################################################################
+########################################################################
+# Once that we have configure our build we can check if it exists a
+# corresponding SB on superbuild-artifact
+
+# How to get md5sum:
+# * concatenate all source files in one
+# * add configure result : CMakeCache.txt
+####################################
+file( GLOB_RECURSE sb_file_list "${OTB_SOURCE_DIR}/SuperBuild/*")
+set( SB_TXT "${OTB_SOURCE_DIR}/full_sb.txt")
+foreach(sb_file  ${sb_file_list})
+  file(READ ${sb_file} CONTENTS)
+  file(APPEND ${SB_TXT} "${sb_file}${CONTENTS}")
+endforeach(sb_file)
+file(READ "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" CMAKE_ORIG)
+string(REPLACE "${CI_PROJ_DIR}" "" CMAKE_UNIFIED ${CMAKE_ORIG})
+file(APPEND ${SB_TXT} "CMakeCache.txt${CMAKE_UNIFIED}")
+file ( MD5 "${SB_TXT}" SB_MD5)
+message ( "SB_MD5 = ${SB_MD5}" )
+file (REMOVE ${SB_TXT})
+
+####################################
+
+# checkout part
+# we look for the right branch
+# Branch name cannot have a ":"
+# git ls-remote $REMOTE $BRANCH_NAME
+####################################
+file ( WRITE "${OTB_SOURCE_DIR}/sb_branch.txt" "${IMAGE_NAME}/${SB_MD5}")
+message( "Checking out git for existence of archive")
+set ( REMOTE "https://gitlab.orfeo-toolbox.org/gbonnefille/superbuild-artifact/")
+set ( BRANCH_NAME "${IMAGE_NAME}/${SB_MD5}")
+
+execute_process(
+  COMMAND ${GIT} "ls-remote" "${REMOTE}" "${BRANCH_NAME}"
+  OUTPUT_VARIABLE IS_SB_BUILD
+  )
+if ( IS_SB_BUILD )
+  message( "Superbuild is already build for ${IMAGE_NAME} with sources as ${SB_MD5}")
+  return()
+else()
+  message( "No build available, this job will build and push OTB_DEPENDS")
+endif()
+####################################
+# Back to build
+
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}"
+            TARGET "OTB_DEPENDS"
+            RETURN_VALUE _build_rv
+            NUMBER_ERRORS _build_nb_err
+            CAPTURE_CMAKE_ERROR _build_error
+            )
+
+if ( DEBUG )
+  message( "Status for build:" )
+  message("_build_rv=${_build_rv}")
+  message("_build_nb_err=${_build_nb_err}")
+  message("_build_error=${_build_error}")
+endif()
+
+if ( ( NOT ${_build_nb_err} EQUAL 0 ) OR ( ${_build_error} EQUAL -1 ))
+  ctest_submit()
+  message( FATAL_ERROR "An error occurs during ctest_build.")
+endif()
+
+ctest_submit()
+
+########################################################################
+########################################################################
+# Git process
+########################################################################
+########################################################################
+
+# WE PUSH ONLY IF BUILD SUCCEED
+# The image used will be passed to this script.
+# TODO verify that images does not have forbidden char in there name
+# TODO right now we rely on ctest_build to know whether there has been an error
+# in build, whereas SuperBuild does not necessarily return an error if something
+# goes wrong
+set ( SB_ARTIFACT_GIT "${CI_PROJ_DIR}/superbuild-artifact" )
+
+# REPOSITORY_GIT_URL and REMOTE whould be the same. Right now there are
+# different because one is https and one is ssh. Both should be ssh.
+set( REPOSITORY_GIT_URL "git@gitlab.orfeo-toolbox.org:gbonnefille/superbuild-artifact.git")
+# We clone master to have a basic configuration, mainly a correct .gitattribute
+# git clone $REMOTE --branch master --depth 1 superbuild-artifact
+execute_process(
+  COMMAND ${GIT} "clone" "${REPOSITORY_GIT_URL}"
+  "--branch" "master" "--depth" "1" "superbuild-artifact"
+  WORKING_DIRECTORY "${CI_PROJ_DIR}"
+  )
+
+# setting up the repo
+# StrictHostKeyChecking so we don't have to add the host as a known key
+# -F /dev/null so the agent is not taking a default file ~/.ssh/..
+execute_process(
+  COMMAND ${GIT} "config" "core.sshCommand"
+  "ssh -o StrictHostKeyChecking=no -F /dev/null"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE ssh_res
+  OUTPUT_VARIABLE ssh_out
+  ERROR_VARIABLE ssh_err
+  )
+
+if ( DEBUG )
+  message( "Step 1: ssh")
+  message( "ssh_res = ${ssh_res}" )
+  message( "ssh_out = ${ssh_out}" )
+  message( "ssh_err = ${ssh_err}" )
+endif()
+
+execute_process(
+  COMMAND ${GIT} "config" "user.mail" "otbbot@orfeo-toolbox.org"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE mail_res
+  OUTPUT_VARIABLE mail_out
+  ERROR_VARIABLE mail_err
+  )
+
+if ( DEBUG )
+  message( "Step 2: mail")
+  message( "mail_res = ${mail_res}" )
+  message( "mail_out = ${mail_out}" )
+  message( "mail_err = ${mail_err}" )
+endif()
+
+execute_process(
+  COMMAND ${GIT} "config" "user.name" "otbbot"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE name_res
+  OUTPUT_VARIABLE name_out
+  ERROR_VARIABLE name_err
+  )
+
+if ( DEBUG )
+  message( "Step 3: name")
+  message( "name_res = ${name_res}" )
+  message( "name_out = ${name_out}" )
+  message( "name_err = ${name_err}" )
+endif()
+
+# create a branche
+execute_process(
+  COMMAND ${GIT} "checkout" "-b" "${BRANCH_NAME}"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE co_res
+  OUTPUT_VARIABLE co_out
+  ERROR_VARIABLE co_err
+  )
+
+if ( DEBUG )
+  message( "Step 4: check-o")
+  message( "co_res = ${co_res}" )
+  message( "co_out = ${co_out}" )
+  message( "co_err = ${co_err}" )
+endif()
+
+set ( SB_TAR_NAME "SuperBuild_Install.tar" )
+
+# create the tar
+# We need to create tar in its directory to avoid weird name in file
+# "tar: Removing leading `../../' from member names"
+# WARNING
+# We are creating a tar containing xdk/.., so when extracting the archive in
+# an other environment the output file will be xdk... Obvious isn't it?
+# Well... Not for everyone...
+# May be for easier maintainability the tar name should be the same as the
+# file inside.
+execute_process(
+  COMMAND ${CMAKE_COMMAND} "-E" "tar" "cf" "${SB_TAR_NAME}"
+  -- "${CTEST_INSTALL_DIRECTORY}"
+  WORKING_DIRECTORY ${CI_ROOT_DIR}
+  )
+
+# We need to copy the tar file, as it is on a different partition in the gitlab
+# context
+file ( COPY "${CI_ROOT_DIR}/${SB_TAR_NAME}" DESTINATION "${SB_ARTIFACT_GIT}")
+
+# In a near futur it might be nice to clean up the mess we made...
+
+if ( DEBUG )
+  if (EXISTS "${SB_ARTIFACT_GIT}/${SB_TAR_NAME}")
+    message("Tar file exists in superbuild_artefact at: ${SB_ARTIFACT_GIT}/${SB_TAR_NAME}")
+  else()
+    message("Tar file does not exist")
+  endif()
+endif()
+
+# add the file
+execute_process(
+  COMMAND ${GIT} "add" "${SB_TAR_NAME}"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE add_res
+  OUTPUT_VARIABLE add_out
+  ERROR_VARIABLE add_err
+  )
+
+if ( DEBUG )
+  message( "Step 5: add")
+  message( "add_res = ${add_res}" )
+  message( "add_out = ${add_out}" )
+  message( "add_err = ${add_err}" )
+endif()
+
+
+# commit
+# We need the author because otherwise the mail is wrong
+# In our case if toto is deploying a key in superbuild-artifact repo
+# the the mail will be toto's
+execute_process(
+  COMMAND ${GIT} "commit" "--author=\"otbbot <otbbot@orfeo-toolbox.org>\""
+  "-m" "\"New Superbuild for ${SB_MD5} on ${IMAGE_NAME}\""
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE com_res
+  OUTPUT_VARIABLE com_out
+  ERROR_VARIABLE com_err
+  )
+
+if ( DEBUG )
+  message( "Step 6: com")
+  message( "com_res = ${com_res}" )
+  message( "com_out = ${com_out}" )
+  message( "com_err = ${com_err}" )
+endif()
+
+
+# This part is just for debug
+if ( DEBUG )
+  execute_process(
+    COMMAND ${GIT} "log" "-1"
+    WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+    RESULT_VARIABLE log_res
+    OUTPUT_VARIABLE log_out
+    ERROR_VARIABLE log_err
+    )
+
+  message( "Step 6bis: log")
+  message( "log_res = ${log_res}" )
+  message( "log_out = ${log_out}" )
+  message( "log_err = ${log_err}" )
+endif()
+
+# push
+# we should be able to do a simple : git push origin $BRANCH_NAME
+execute_process(
+  COMMAND ${GIT} "push" "${REPOSITORY_GIT_URL}" "${BRANCH_NAME}"
+  WORKING_DIRECTORY ${SB_ARTIFACT_GIT}
+  RESULT_VARIABLE push_res
+  OUTPUT_VARIABLE push_out
+  ERROR_VARIABLE push_err
+  )
+
+if ( DEBUG )
+  message( "Step 7: push")
+  message( "push_res = ${push_res}" )
+  message( "push_out = ${push_out}" )
+  message( "push_err = ${push_err}" )
+endif()
diff --git a/CI/ubuntu-18.04-gcc-shark.cmake b/CI/ubuntu-18.04-fast.cmake
similarity index 61%
rename from CI/ubuntu-18.04-gcc-shark.cmake
rename to CI/ubuntu-18.04-fast.cmake
index b9ef2642b4890d8be17aabb164727bb70add5120..5ba38ec80c18fcf420f77160b528c6555ee1d84e 100644
--- a/CI/ubuntu-18.04-gcc-shark.cmake
+++ b/CI/ubuntu-18.04-fast.cmake
@@ -18,7 +18,18 @@
 # limitations under the License.
 #
 
-# Configuration options for ubuntu-18.04-gcc-shark-3.1.4
+# Configuration options for ubuntu-18.04-fast
 
 set(site_option
-"opencv_INCLUDE_DIR:PATH=/usr/include")
+"opencv_INCLUDE_DIR:PATH=/usr/include
+CMAKE_C_COMPILER:STRING=clang
+CMAKE_CXX_COMPILER:STRING=clang++
+CMAKE_EXE_LINKER_FLAGS:STRING=-fuse-ld=lld
+CMAKE_MODULE_LINKER_FLAGS:STRING=-fuse-ld=lld
+CMAKE_SHARED_LINKER_FLAGS:STRING=-fuse-ld=lld
+CMAKE_C_COMPILER_LAUNCHER:STRING=ccache
+CMAKE_CXX_COMPILER_LAUNCHER:STRING=ccache
+OTB_USE_SHARK:BOOL=OFF
+BUILD_EXAMPLES:BOOL=OFF")
+
+set(ci_skip_testing ON)
diff --git a/CI/ubuntu-18.04-llvm-shark.cmake b/CI/ubuntu-18.04-llvm-shark.cmake
deleted file mode 100644
index fb3b626a3b6dc9009793d75737f89008157b8d5e..0000000000000000000000000000000000000000
--- a/CI/ubuntu-18.04-llvm-shark.cmake
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Copyright (C) 2005-2019 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.
-#
-
-# Configuration options for ubuntu-18.04-llvm-shark-3.1.4
-
-set(site_option
-"opencv_INCLUDE_DIR:PATH=/usr/include
-CMAKE_C_COMPILER:STRING=clang
-CMAKE_CXX_COMPILER:STRING=clang++
-CMAKE_EXE_LINKER_FLAGS:STRING=-fuse-ld=lld
-CMAKE_MODULE_LINKER_FLAGS:STRING=-fuse-ld=lld
-CMAKE_SHARED_LINKER_FLAGS:STRING=-fuse-ld=lld
-CMAKE_C_COMPILER_LAUNCHER:STRING=ccache
-CMAKE_CXX_COMPILER_LAUNCHER:STRING=ccache
-OTB_USE_SHARK:BOOL=OFF")
-
-if(NOT ${ci_do_cookbook} EQUAL -1)
-  set(site_option
-"${site_option}
-BUILD_COOKBOOK:BOOL=ON")
-endif()
-
-if(NOT ${ci_do_doxygen} EQUAL -1)
-  set(site_option
-"${site_option}
-BUILD_DOCUMENTATION:BOOL=ON
-OTB_DOXYGEN_ITK_TAGFILE:FILEPATH=${CTEST_BINARY_DIRECTORY}/InsightDoxygenDocTag-4.13.0
-OTB_DOXYGEN_ITK_DOXYGEN_URL:STRING=\"https://itk.org/Doxygen413/html\"
-")
-  set (ENABLE_DOXYGEN ON)
-  # The ITK doxygen tag file needs to be patched before being used for OTB
-  # See otb-devutils/Scripts/tagfile_fix.py
-  message(STATUS "Get resources for Doxygen build ...")
-  execute_process(COMMAND wget https://www.orfeo-toolbox.org/packages/archives/Doxygen/InsightDoxygenDocTag-4.13.0.gz
-                  COMMAND gzip -d InsightDoxygenDocTag-4.13.0.gz
-                  WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY})
-endif()
diff --git a/CI/ubuntu-18.04-llvm.cmake b/CI/ubuntu-18.04-llvm.cmake
index a92364f2b45d82176aa65d3d112753055421aef1..6480ab2f31b9ddb22b56a15d61ac305a85e85423 100644
--- a/CI/ubuntu-18.04-llvm.cmake
+++ b/CI/ubuntu-18.04-llvm.cmake
@@ -22,9 +22,33 @@
 
 set(site_option
 "opencv_INCLUDE_DIR:PATH=/usr/include
-OTB_USE_SHARK:BOOL=OFF
 CMAKE_C_COMPILER:STRING=clang
 CMAKE_CXX_COMPILER:STRING=clang++
 CMAKE_EXE_LINKER_FLAGS:STRING=-fuse-ld=lld
 CMAKE_MODULE_LINKER_FLAGS:STRING=-fuse-ld=lld
-CMAKE_SHARED_LINKER_FLAGS:STRING=-fuse-ld=lld")
+CMAKE_SHARED_LINKER_FLAGS:STRING=-fuse-ld=lld
+CMAKE_C_COMPILER_LAUNCHER:STRING=ccache
+CMAKE_CXX_COMPILER_LAUNCHER:STRING=ccache
+OTB_USE_SHARK:BOOL=OFF")
+
+if(NOT ${ci_do_cookbook} EQUAL -1)
+  set(site_option
+"${site_option}
+BUILD_COOKBOOK:BOOL=ON")
+endif()
+
+if(NOT ${ci_do_doxygen} EQUAL -1)
+  set(site_option
+"${site_option}
+BUILD_DOCUMENTATION:BOOL=ON
+OTB_DOXYGEN_ITK_TAGFILE:FILEPATH=${CTEST_BINARY_DIRECTORY}/InsightDoxygenDocTag-4.13.0
+OTB_DOXYGEN_ITK_DOXYGEN_URL:STRING=\"https://itk.org/Doxygen413/html\"
+")
+  set (ENABLE_DOXYGEN ON)
+  # The ITK doxygen tag file needs to be patched before being used for OTB
+  # See otb-devutils/Scripts/tagfile_fix.py
+  message(STATUS "Get resources for Doxygen build ...")
+  execute_process(COMMAND wget https://www.orfeo-toolbox.org/packages/archives/Doxygen/InsightDoxygenDocTag-4.13.0.gz
+                  COMMAND gzip -d InsightDoxygenDocTag-4.13.0.gz
+                  WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY})
+endif()
diff --git a/Modules/Applications/AppClassification/app/otbPolygonClassStatistics.cxx b/Modules/Applications/AppClassification/app/otbPolygonClassStatistics.cxx
index 95e3314e115ac5254d08d6320207b4e1a80f43fe..bbfb99010e2df503fc561fad3ba528b8b3904151 100644
--- a/Modules/Applications/AppClassification/app/otbPolygonClassStatistics.cxx
+++ b/Modules/Applications/AppClassification/app/otbPolygonClassStatistics.cxx
@@ -54,7 +54,7 @@ public:
 
   /** Filters typedef */
   typedef otb::OGRDataToClassStatisticsFilter<FloatVectorImageType,UInt8ImageType> FilterType;
-  
+
   typedef otb::StatisticsXMLFileWriter<FloatVectorImageType::PixelType> StatWriterType;
 
   typedef otb::GeometriesSet GeometriesType;
@@ -64,7 +64,6 @@ public:
 private:
   PolygonClassStatistics()
     {
-   
     }
 
   void DoInit() override
@@ -98,17 +97,17 @@ private:
     AddParameter(ParameterType_InputImage,  "mask",   "Input validity mask");
     SetParameterDescription("mask", "Validity mask (only pixels corresponding to a mask value greater than 0 will be used for statistics)");
     MandatoryOff("mask");
-    
+
     AddParameter(ParameterType_InputFilename, "vec", "Input vectors");
     SetParameterDescription("vec","Input geometries to analyze");
-    
+
     AddParameter(ParameterType_OutputFilename, "out", "Output XML statistics file");
     SetParameterDescription("out","Output file to store statistics (XML format)");
 
     AddParameter(ParameterType_ListView, "field", "Field Name");
     SetParameterDescription("field","Name of the field carrying the class name in the input vectors.");
     SetListViewSingleSelectionMode("field",true);
-    
+
     AddParameter(ParameterType_Int, "layer", "Layer Index");
     SetParameterDescription("layer", "Layer index to read in the input vector file.");
     MandatoryOff("layer");
@@ -138,16 +137,16 @@ private:
       ogr::Feature feature = layer.ogr().GetNextFeature();
 
       ClearChoices("field");
-      
+
       for(int iField=0; iField<feature.ogr().GetFieldCount(); iField++)
         {
         std::string key, item = feature.ogr().GetFieldDefnRef(iField)->GetNameRef();
         key = item;
         std::string::iterator end = std::remove_if(key.begin(),key.end(),IsNotAlphaNum);
         std::transform(key.begin(), end, key.begin(), tolower);
-        
+
         OGRFieldType fieldType = feature.ogr().GetFieldDefnRef(iField)->GetType();
-        
+
         if(fieldType == OFTString || fieldType == OFTInteger || fieldType == OFTInteger64)
           {
           std::string tmpKey="field."+key.substr(0, end - key.begin());
@@ -159,7 +158,7 @@ private:
      // Check that the extension of the output parameter is XML (mandatory for
      // StatisticsXMLFileWriter)
      // Check it here to trigger the error before polygons analysis
-     
+
      if ( HasValue("out") )
        {
        // Store filename extension
@@ -175,46 +174,39 @@ private:
 
   void DoExecute() override
   {
-  otb::ogr::DataSource::Pointer vectors = 
-    otb::ogr::DataSource::New(this->GetParameterString("vec"));
+    otb::ogr::DataSource::Pointer vectors = otb::ogr::DataSource::New(this->GetParameterString("vec"));
 
-  // Retrieve the field name
-  std::vector<int> selectedCFieldIdx = GetSelectedItems("field");
+    // Retrieve the field name
+    std::vector<int> selectedCFieldIdx = GetSelectedItems("field");
 
-  if(selectedCFieldIdx.empty())
+    if (selectedCFieldIdx.empty())
     {
     otbAppLogFATAL(<<"No field has been selected for data labelling!");
     }
 
-  std::vector<std::string> cFieldNames = GetChoiceNames("field");  
-  std::string fieldName = cFieldNames[selectedCFieldIdx.front()];
-
-  otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");
-
-  // Reproject geometries
-  FloatVectorImageType::Pointer inputImg = this->GetParameterImage("in");
-  std::string imageProjectionRef = inputImg->GetProjectionRef();
-  FloatVectorImageType::ImageKeywordlistType imageKwl =
-    inputImg->GetImageKeywordlist();
-  std::string vectorProjectionRef =
-    vectors->GetLayer(GetParameterInt("layer")).GetProjectionRef();
-
-  otb::ogr::DataSource::Pointer reprojVector = vectors;
-  GeometriesType::Pointer inputGeomSet;
-  ProjectionFilterType::Pointer geometriesProjFilter;
-  GeometriesType::Pointer outputGeomSet;
-  const OGRSpatialReference imgOGRSref = 
-        OGRSpatialReference( imageProjectionRef.c_str() );
-    const OGRSpatialReference vectorOGRSref = 
-        OGRSpatialReference( vectorProjectionRef.c_str() );
-  bool doReproj = true;
-  // don't reproject for these cases
-  if (  vectorProjectionRef.empty() 
-     || ( imgOGRSref.IsSame( &vectorOGRSref ) ) 
-     || ( imageProjectionRef.empty() && imageKwl.GetSize() == 0) )
-    doReproj = false;
-
-  if (doReproj)
+    std::vector<std::string> cFieldNames = GetChoiceNames("field");
+    std::string              fieldName   = cFieldNames[selectedCFieldIdx.front()];
+
+    otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this, "elev");
+
+    // Reproject geometries
+    FloatVectorImageType::Pointer              inputImg            = this->GetParameterImage("in");
+    std::string                                imageProjectionRef  = inputImg->GetProjectionRef();
+    FloatVectorImageType::ImageKeywordlistType imageKwl            = inputImg->GetImageKeywordlist();
+    std::string                                vectorProjectionRef = vectors->GetLayer(GetParameterInt("layer")).GetProjectionRef();
+
+    otb::ogr::DataSource::Pointer reprojVector = vectors;
+    GeometriesType::Pointer       inputGeomSet;
+    ProjectionFilterType::Pointer geometriesProjFilter;
+    GeometriesType::Pointer       outputGeomSet;
+    const OGRSpatialReference     imgOGRSref    = OGRSpatialReference(imageProjectionRef.c_str());
+    const OGRSpatialReference     vectorOGRSref = OGRSpatialReference(vectorProjectionRef.c_str());
+    bool                          doReproj      = true;
+    // don't reproject for these cases
+    if (vectorProjectionRef.empty() || (imgOGRSref.IsSame(&vectorOGRSref)) || (imageProjectionRef.empty() && imageKwl.GetSize() == 0))
+      doReproj = false;
+
+    if (doReproj)
     {
     inputGeomSet = GeometriesType::New(vectors);
     reprojVector = otb::ogr::DataSource::New();
@@ -236,7 +228,7 @@ private:
   filter->SetInput(this->GetParameterImage("in"));
   if (IsParameterEnabled("mask") && HasValue("mask"))
     {
-    filter->SetMask(this->GetParameterImage<UInt8ImageType>("mask"));
+      filter->SetMask(this->GetParameterUInt8Image("mask"));
     }
   filter->SetOGRData(reprojVector);
   filter->SetFieldName(fieldName);
@@ -245,10 +237,10 @@ private:
 
   AddProcess(filter->GetStreamer(),"Analyze polygons...");
   filter->Update();
-  
+
   FilterType::ClassCountMapType &classCount = filter->GetClassCountOutput()->Get();
   FilterType::PolygonSizeMapType &polySize = filter->GetPolygonSizeOutput()->Get();
-  
+
   StatWriterType::Pointer statWriter = StatWriterType::New();
   statWriter->SetFileName(this->GetParameterString("out"));
   statWriter->AddInputMap<FilterType::ClassCountMapType>("samplesPerClass",classCount);
diff --git a/Modules/Applications/AppClassification/app/otbSampleSelection.cxx b/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
index a4f8b1fc33a73f4e1a2f123dafd8498238f3f984..959f3c129d0c32c3f77343f249c0b18e022232de 100644
--- a/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
+++ b/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
@@ -63,7 +63,7 @@ public:
     UInt8ImageType,
     otb::RandomSampler>                             RandomSamplerType;
   typedef otb::SamplingRateCalculator               RateCalculatorType;
-  
+
   typedef std::map<std::string, unsigned long>      ClassCountMapType;
   typedef RateCalculatorType::MapRateType           MapRateType;
   typedef itk::VariableLengthVector<float> MeasurementType;
@@ -87,40 +87,41 @@ private:
 
     // Documentation
     SetDocName("Sample Selection");
-    SetDocLongDescription("The application selects a set of samples from geometries "
-      "intended for training (they should have a field giving the associated "
-      "class). \n\nFirst of all, the geometries must be analyzed by the PolygonClassStatistics application "
-      "to compute statistics about the geometries, which are summarized in an xml file. "
-      "\nThen, this xml file must be given as input to this application (parameter instats).\n\n"
-      "The input support image and the input training vectors shall be given in "
-      "parameters 'in' and 'vec' respectively. Only the sampling grid (origin, size, spacing)"
-      "will be read in the input image.\n"
-      "There are several strategies to select samples (parameter strategy) : \n\n"
-      "  - smallest (default) : select the same number of sample in each class" 
-      " so that the smallest one is fully sampled.\n"
-      "  - constant : select the same number of samples N in each class" 
-      " (with N below or equal to the size of the smallest class).\n"
-      "  - byclass : set the required number for each class manually, with an input CSV file"
-      " (first column is class name, second one is the required samples number).\n\n"
-      "  - percent: set a target global percentage of samples to use. Class proportions will be respected. \n\n"
-      "  - total: set a target total number of samples to use. Class proportions will be respected. \n\n"
-      "There is also a choice on the sampling type to performs : \n\n"
-      "  - periodic : select samples uniformly distributed\n"
-      "  - random : select samples randomly distributed\n\n"
-      "Once the strategy and type are selected, the application outputs samples positions"
-      "(parameter out).\n\n"
-      
-      "The other parameters to look at are : \n\n"
-      "  - layer : index specifying from which layer to pick geometries.\n"
-      "  - field : set the field name containing the class.\n"
-      "  - mask : an optional raster mask can be used to discard samples.\n"
-      "  - outrates : allows outputting a CSV file that summarizes the sampling rates for each class.\n"
-      
-      "\nAs with the PolygonClassStatistics application, different types  of geometry are supported : "
-      "polygons, lines, points. \nThe behavior of this application is different for each type of geometry : \n\n"
-      "  - polygon: select points whose center is inside the polygon\n"
-      "  - lines  : select points intersecting the line\n"
-      "  - points : select closest point to the provided point");
+    SetDocLongDescription(
+        "The application selects a set of samples from geometries "
+        "intended for training (they should have a field giving the associated "
+        "class). \n\nFirst of all, the geometries must be analyzed by the PolygonClassStatistics application "
+        "to compute statistics about the geometries, which are summarized in an xml file. "
+        "\nThen, this xml file must be given as input to this application (parameter instats).\n\n"
+        "The input support image and the input training vectors shall be given in "
+        "parameters 'in' and 'vec' respectively. Only the sampling grid (origin, size, spacing)"
+        "will be read in the input image.\n"
+        "There are several strategies to select samples (parameter strategy) : \n\n"
+        "  - smallest (default) : select the same number of sample in each class"
+        " so that the smallest one is fully sampled.\n"
+        "  - constant : select the same number of samples N in each class"
+        " (with N below or equal to the size of the smallest class).\n"
+        "  - byclass : set the required number for each class manually, with an input CSV file"
+        " (first column is class name, second one is the required samples number).\n\n"
+        "  - percent: set a target global percentage of samples to use. Class proportions will be respected. \n\n"
+        "  - total: set a target total number of samples to use. Class proportions will be respected. \n\n"
+        "There is also a choice on the sampling type to performs : \n\n"
+        "  - periodic : select samples uniformly distributed\n"
+        "  - random : select samples randomly distributed\n\n"
+        "Once the strategy and type are selected, the application outputs samples positions"
+        "(parameter out).\n\n"
+
+        "The other parameters to look at are : \n\n"
+        "  - layer : index specifying from which layer to pick geometries.\n"
+        "  - field : set the field name containing the class.\n"
+        "  - mask : an optional raster mask can be used to discard samples.\n"
+        "  - outrates : allows outputting a CSV file that summarizes the sampling rates for each class.\n"
+
+        "\nAs with the PolygonClassStatistics application, different types  of geometry are supported : "
+        "polygons, lines, points. \nThe behavior of this application is different for each type of geometry : \n\n"
+        "  - polygon: select points whose center is inside the polygon\n"
+        "  - lines  : select points intersecting the line\n"
+        "  - points : select closest point to the provided point");
     SetDocLimitations("None");
     SetDocAuthors("OTB-Team");
     SetDocSeeAlso(" ");
@@ -192,7 +193,7 @@ private:
     SetParameterDescription("strategy.total.v","The number of samples to generate");
     SetMinimumParameterIntValue("strategy.total.v",1);
     SetDefaultParameterInt("strategy.total.v",1000);
-    
+
     AddChoice("strategy.smallest","Set same number of samples for all classes, with the smallest class fully sampled");
     SetParameterDescription("strategy.smallest","Set same number of samples for all classes, with the smallest class fully sampled");
 
@@ -238,16 +239,16 @@ private:
       ogr::Feature feature = layer.ogr().GetNextFeature();
 
       ClearChoices("field");
-      
+
       for(int iField=0; iField<feature.ogr().GetFieldCount(); iField++)
         {
         std::string key, item = feature.ogr().GetFieldDefnRef(iField)->GetNameRef();
         key = item;
         std::string::iterator end = std::remove_if(key.begin(),key.end(),IsNotAlphaNum);
         std::transform(key.begin(), end, key.begin(), tolower);
-        
+
         OGRFieldType fieldType = feature.ogr().GetFieldDefnRef(iField)->GetType();
-        
+
         if(fieldType == OFTString || fieldType == OFTInteger || fieldType == OFTInteger64)
           {
           std::string tmpKey="field."+key.substr(0, end - key.begin());
@@ -266,27 +267,26 @@ private:
 
     // Get field name
     std::vector<int> selectedCFieldIdx = GetSelectedItems("field");
-    
+
     if(selectedCFieldIdx.empty())
       {
       otbAppLogFATAL(<<"No field has been selected for data labelling!");
       }
-    
-    std::vector<std::string> cFieldNames = GetChoiceNames("field");  
-    std::string fieldName = cFieldNames[selectedCFieldIdx.front()];
-    
-    m_ReaderStat->SetFileName(this->GetParameterString("instats"));
-    ClassCountMapType classCount = m_ReaderStat->GetStatisticMapByName<ClassCountMapType>("samplesPerClass");
-    m_RateCalculator->SetClassCount(classCount);
-    
-    switch (this->GetParameterInt("strategy"))
+
+      std::vector<std::string> cFieldNames = GetChoiceNames("field");
+      std::string              fieldName   = cFieldNames[selectedCFieldIdx.front()];
+
+      m_ReaderStat->SetFileName(this->GetParameterString("instats"));
+      ClassCountMapType classCount = m_ReaderStat->GetStatisticMapByName<ClassCountMapType>("samplesPerClass");
+      m_RateCalculator->SetClassCount(classCount);
+
+      switch (this->GetParameterInt("strategy"))
       {
       // byclass
       case 0:
         {
         otbAppLogINFO("Sampling strategy : set number of samples for each class");
-        ClassCountMapType requiredCount = 
-          otb::SamplingRateCalculator::ReadRequiredSamples(this->GetParameterString("strategy.byclass.in"));
+        ClassCountMapType requiredCount = otb::SamplingRateCalculator::ReadRequiredSamples(this->GetParameterString("strategy.byclass.in"));
         m_RateCalculator->SetNbOfSamplesByClass(requiredCount);
         }
       break;
@@ -330,12 +330,12 @@ private:
         otbAppLogFATAL("Strategy mode unknown :"<<this->GetParameterString("strategy"));
       break;
       }
-      
+
     if (IsParameterEnabled("outrates") && HasValue("outrates"))
       {
       m_RateCalculator->Write(this->GetParameterString("outrates"));
       }
-    
+
     MapRateType rates = m_RateCalculator->GetRatesByClass();
     std::ostringstream oss;
     oss << " className  requiredSamples  totalSamples  rate" << std::endl;
@@ -376,16 +376,14 @@ private:
     ProjectionFilterType::Pointer geometriesProjFilter;
     GeometriesType::Pointer outputGeomSet;
     bool doReproj = true;
-    const OGRSpatialReference imgOGRSref = 
-        OGRSpatialReference( imageProjectionRef.c_str() );
-    const OGRSpatialReference vectorOGRSref = 
-        OGRSpatialReference( vectorProjectionRef.c_str() );
+    const OGRSpatialReference     imgOGRSref    = OGRSpatialReference(imageProjectionRef.c_str());
+    const OGRSpatialReference     vectorOGRSref = OGRSpatialReference(vectorProjectionRef.c_str());
     // don't reproject for these cases
     if (  vectorProjectionRef.empty()
        || ( imgOGRSref.IsSame( &vectorOGRSref ) )
        || ( imageProjectionRef.empty() && imageKwl.GetSize() == 0) )
       doReproj = false;
-  
+
     if (doReproj)
       {
       inputGeomSet = GeometriesType::New(vectors);
@@ -407,7 +405,7 @@ private:
     // Create output dataset for sample positions
     otb::ogr::DataSource::Pointer outputSamples =
       otb::ogr::DataSource::New(this->GetParameterString("out"),otb::ogr::DataSource::Modes::Overwrite);
-    
+
     switch (this->GetParameterInt("sampler"))
       {
       // periodic
@@ -426,7 +424,7 @@ private:
         periodicFilt->SetSamplerParameters(param);
         if (IsParameterEnabled("mask") && HasValue("mask"))
           {
-          periodicFilt->SetMask(this->GetParameterImage<UInt8ImageType>("mask"));
+            periodicFilt->SetMask(this->GetParameterUInt8Image("mask"));
           }
         periodicFilt->GetStreamer()->SetAutomaticTiledStreaming(this->GetParameterInt("ram"));
         AddProcess(periodicFilt->GetStreamer(),"Selecting positions with periodic sampler...");
@@ -444,7 +442,7 @@ private:
         randomFilt->SetLayerIndex(this->GetParameterInt("layer"));
         if (IsParameterEnabled("mask") && HasValue("mask"))
           {
-          randomFilt->SetMask(this->GetParameterImage<UInt8ImageType>("mask"));
+            randomFilt->SetMask(this->GetParameterUInt8Image("mask"));
           }
         randomFilt->GetStreamer()->SetAutomaticTiledStreaming(this->GetParameterInt("ram"));
         AddProcess(randomFilt->GetStreamer(),"Selecting positions with random sampler...");
diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt
index 5ea0f486a80bf0559d85ac8e44b47fb4d4457205..2e7c752c078945a9993e9f78707ff43f6746578a 100644
--- a/Modules/Applications/AppClassification/test/CMakeLists.txt
+++ b/Modules/Applications/AppClassification/test/CMakeLists.txt
@@ -179,6 +179,9 @@ foreach(classifier ${classifierList})
     VALID    ${valid}
   )
 
+  set_tests_properties(apTvClTrainMethod${classifier}ImagesClassifierQB1 PROPERTIES
+    RESOURCE_LOCK ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1_utm31n${vector_input_format})
+
   if(${_classifier_has_baseline} EQUAL -1)
     set(valid ${ascii_confmat_comparison} ${ascii_ref_path}/${OUTCONFMATFILE} ${TEMP}/${OUTCONFMATFILE})
   else()
diff --git a/Modules/Applications/AppImageUtils/app/otbManageNoData.cxx b/Modules/Applications/AppImageUtils/app/otbManageNoData.cxx
index 561131caab6a86f6d21c50695838fb4ba0821fe2..4cd2b5f917dfdf22963006931c5bcd91b583bee8 100644
--- a/Modules/Applications/AppImageUtils/app/otbManageNoData.cxx
+++ b/Modules/Applications/AppImageUtils/app/otbManageNoData.cxx
@@ -50,7 +50,7 @@ public:
   /** Filters typedef */
   typedef otb::ImageToNoDataMaskFilter<FloatVectorImageType,UInt8ImageType> FilterType;
   typedef otb::ChangeNoDataValueFilter<FloatVectorImageType,FloatVectorImageType> ChangeNoDataFilterType;
-  
+
   typedef otb::ImageList<FloatImageType> ImageListType;
   typedef otb::VectorImageToImageListFilter<FloatVectorImageType,ImageListType> VectorToListFilterType;
   typedef otb::ImageListToVectorImageFilter<ImageListType,FloatVectorImageType> ListToVectorFilterType;
@@ -81,12 +81,12 @@ private:
 
     AddParameter(ParameterType_Bool,"usenan", "Consider NaN as no-data");
     SetParameterDescription("usenan","If active, the application will consider NaN as no-data values as well");
-   
+
     AddParameter(ParameterType_Choice,"mode","No-data handling mode");
     SetParameterDescription("mode","Allows choosing between different no-data handling options");
 
     AddChoice("mode.buildmask","Build a no-data Mask");
-    
+
     AddParameter(ParameterType_Float,"mode.buildmask.inv","Inside Value");
     SetParameterDescription("mode.buildmask.inv","Value given in the output mask to pixels that are not no data pixels");
     SetDefaultParameterInt("mode.buildmask.inv",1);
@@ -132,7 +132,7 @@ private:
  void DoExecute() override
   {
     FloatVectorImageType::Pointer inputPtr = this->GetParameterImage("in");
-    
+
     m_Filter = FilterType::New();
     m_Filter->SetInsideValue(this->GetParameterFloat("mode.buildmask.inv"));
     m_Filter->SetOutsideValue(this->GetParameterFloat("mode.buildmask.outv"));
@@ -146,7 +146,7 @@ private:
     std::vector<double> newNoData(inputPtr->GetNumberOfComponentsPerPixel(),GetParameterFloat("mode.changevalue.newv"));
 
     m_ChangeNoDataFilter->SetNewNoDataValues(newNoData);
-    
+
     if(GetParameterString("mode") == "buildmask")
       {
       SetParameterOutputImage("out",m_Filter->GetOutput());
@@ -158,7 +158,7 @@ private:
     else if (GetParameterString("mode") == "apply")
       {
       m_MaskFilters.clear();
-      UInt8ImageType::Pointer maskPtr = this->GetParameterImage<UInt8ImageType>("mode.apply.mask");
+      UInt8ImageType::Pointer  maskPtr = this->GetParameterUInt8Image("mode.apply.mask");
       unsigned int nbBands = inputPtr->GetNumberOfComponentsPerPixel();
       itk::MetaDataDictionary &dict = inputPtr->GetMetaDataDictionary();
       std::vector<bool> flags;
@@ -221,4 +221,3 @@ private:
 }
 
 OTB_APPLICATION_EXPORT(otb::Wrapper::ManageNoData)
-
diff --git a/Modules/Applications/AppProjection/test/CMakeLists.txt b/Modules/Applications/AppProjection/test/CMakeLists.txt
index e9d4c8a0de20aea3cfcbbd79a9106573c68fd173..28b843b2157b84c32720f2a218302b9e36942f2b 100644
--- a/Modules/Applications/AppProjection/test/CMakeLists.txt
+++ b/Modules/Applications/AppProjection/test/CMakeLists.txt
@@ -343,7 +343,8 @@ otb_test_application(NAME apTvPrConvertSensorToGeoPoint
                      TESTENVOPTIONS ${TEMP}/apTvPrConvertSensorToGeoPoint.txt
                      VALID  --compare-ascii ${EPSILON_7}
                         ${BASELINE_FILES}/apTvPrConvertSensorToGeoPoint.txt
-                        ${TEMP}/apTvPrConvertSensorToGeoPoint.txt)
+                        ${TEMP}/apTvPrConvertSensorToGeoPoint.txt
+                        --ignore-lines-with 2 town country)
 
 
 #----------- Superimpose TESTS ----------------
diff --git a/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx b/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx
index 8f09d36adf5f74b938dfe1e838e49aa8fbf233a5..bc414d0f2081c4d6d9a7951ea079b24318838cea 100644
--- a/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx
+++ b/Modules/Applications/AppSegmentation/app/otbLargeScaleMeanShift.cxx
@@ -33,7 +33,7 @@ namespace Wrapper
  *
  * This application gathers the 4 steps of the large-scale MeanShift
  * segmentation framework.
- * 
+ *
  */
 class LargeScaleMeanShift : public CompositeApplication
 {
@@ -191,13 +191,11 @@ private:
       if (IsParameterEnabled("mode.vector.imfield") &&
           HasValue("mode.vector.imfield"))
         {
-        GetInternalApplication("vectorization")->SetParameterInputImage("in",
-          GetParameterImage<ImageBaseType>("mode.vector.imfield"));
+          GetInternalApplication("vectorization")->SetParameterInputImage("in", GetParameterImageBase("mode.vector.imfield"));
         }
       else
         {
-        GetInternalApplication("vectorization")->SetParameterInputImage("in",
-          GetParameterImage<ImageBaseType>("in"));
+          GetInternalApplication("vectorization")->SetParameterInputImage("in", GetParameterImageBase("in"));
         }
       GetInternalApplication("vectorization")->SetParameterString("inseg",
         tmpFilenames[2]);
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
index d53f70c266f4b9e8f59aa68ee033ba2fd384dfb8..3baadd6f0f747b5f640b284fd3bd6a7aeab79254 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h
@@ -765,13 +765,13 @@ public:
   void SetParameterImageBase(const std::string & key, ImageBaseType* img, unsigned int idx = 0);
 
   /**
-  Register all ProcessObject that are linked to parameters : 
+  Register all ProcessObject that are linked to parameters :
     \li ParameterType_OutputImage
     \li ParameterType_OutputVectorData
 
-    Those ProcessObjects are stored in the m_Filters set and are deleted at the 
+    Those ProcessObjects are stored in the m_Filters set and are deleted at the
   end of ExecuteAndWriteOutput (if there are only held by the set)
-  This method can be called just before the end of a DoExecute in a derived 
+  This method can be called just before the end of a DoExecute in a derived
   class of Application.
   */
   void RegisterPipeline();
@@ -850,21 +850,7 @@ protected:
    * \li ParameterType_InputImage
    */
   template <class TImageType>
-    TImageType* GetParameterImage(std::string parameter)
-  {
-    typename TImageType::Pointer ret;
-    Parameter* param = GetParameterByKey(parameter);
-    InputImageParameter* paramDown = dynamic_cast<InputImageParameter*>(param);
-    if (paramDown)
-    {
-      return paramDown->GetImage<TImageType>();
-    }
-    else
-    {
-      itkExceptionMacro(<<parameter << " parameter can't be casted to ImageType");
-      return nullptr;
-    }
-  }
+  TImageType* GetParameterImage(std::string parameter);
 
   /** Declare a parameter as having an automatic value */
   void AutomaticValueOn(std::string paramKey);
@@ -878,16 +864,7 @@ protected:
    * \li ParameterType_OutputImage
    */
   template <class TImageType>
-    void SetParameterOutputImage(std::string parameter, TImageType* value)
-  {
-    Parameter* param = GetParameterByKey(parameter);
-
-    if (dynamic_cast<OutputImageParameter*>(param))
-      {
-      OutputImageParameter* paramDown = dynamic_cast<OutputImageParameter*>(param);
-      paramDown->SetValue(value);
-      }
-  }
+  void SetParameterOutputImage(std::string parameter, TImageType* value);
 
 private:
   /* Implement this method to add parameters */
@@ -963,9 +940,90 @@ private:
 } //end namespace otb
 
 
-//#ifndef OTB_MANUAL_INSTANTIATION
-//#include "otbWrapperApplication.hxx"
-//#endif
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbWrapperApplication.hxx"
+#endif
+
+
+namespace otb
+{
+namespace Wrapper
+{
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt8VectorImageType* Application::GetParameterImage<UInt8VectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE Int16VectorImageType* Application::GetParameterImage<Int16VectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt16VectorImageType* Application::GetParameterImage<UInt16VectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE Int32VectorImageType* Application::GetParameterImage<Int32VectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt32VectorImageType* Application::GetParameterImage<UInt32VectorImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE FloatVectorImageType* Application::GetParameterImage<FloatVectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE DoubleVectorImageType* Application::GetParameterImage<DoubleVectorImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexInt16VectorImageType* Application::GetParameterImage<ComplexInt16VectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexInt32VectorImageType* Application::GetParameterImage<ComplexInt32VectorImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexFloatVectorImageType* Application::GetParameterImage<ComplexFloatVectorImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexDoubleVectorImageType* Application::GetParameterImage<ComplexDoubleVectorImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt8RGBImageType* Application::GetParameterImage<UInt8RGBImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt8RGBAImageType* Application::GetParameterImage<UInt8RGBAImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt8ImageType* Application::GetParameterImage<UInt8ImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE Int16ImageType* Application::GetParameterImage<Int16ImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt16ImageType* Application::GetParameterImage<UInt16ImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE Int32ImageType* Application::GetParameterImage<Int32ImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE UInt32ImageType* Application::GetParameterImage<UInt32ImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE FloatImageType* Application::GetParameterImage<FloatImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE DoubleImageType* Application::GetParameterImage<DoubleImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexInt16ImageType* Application::GetParameterImage<ComplexInt16ImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexInt32ImageType* Application::GetParameterImage<ComplexInt32ImageType>(std::string);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexFloatImageType* Application::GetParameterImage<ComplexFloatImageType>(std::string);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE ComplexDoubleImageType* Application::GetParameterImage<ComplexDoubleImageType>(std::string);
+
+//
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt8VectorImageType>(std::string, UInt8VectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<Int16VectorImageType>(std::string, Int16VectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt16VectorImageType>(std::string, UInt16VectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<Int32VectorImageType>(std::string, Int32VectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt32VectorImageType>(std::string, UInt32VectorImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<FloatVectorImageType>(std::string, FloatVectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<DoubleVectorImageType>(std::string, DoubleVectorImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt16VectorImageType>(std::string,
+                                                                                                                            ComplexInt16VectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt32VectorImageType>(std::string,
+                                                                                                                            ComplexInt32VectorImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexFloatVectorImageType>(std::string,
+                                                                                                                            ComplexFloatVectorImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexDoubleVectorImageType>(std::string,
+                                                                                                                             ComplexDoubleVectorImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt8RGBImageType>(std::string, UInt8RGBImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt8RGBAImageType>(std::string, UInt8RGBAImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt8ImageType>(std::string, UInt8ImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<Int16ImageType>(std::string, Int16ImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt16ImageType>(std::string, UInt16ImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<Int32ImageType>(std::string, Int32ImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<UInt32ImageType>(std::string, UInt32ImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<FloatImageType>(std::string, FloatImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<DoubleImageType>(std::string, DoubleImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt16ImageType>(std::string, ComplexInt16ImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt32ImageType>(std::string, ComplexInt32ImageType*);
+
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexFloatImageType>(std::string, ComplexFloatImageType*);
+extern template OTBApplicationEngine_EXPORT_TEMPLATE void Application::SetParameterOutputImage<ComplexDoubleImageType>(std::string, ComplexDoubleImageType*);
+
+} // namespace Wrapper
+} // namespace otb
 
 
 #endif // otbWrapperApplication_h_
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.hxx b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..33330cd2418fa7c81e506806d6a43b3d9d583f23
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.hxx
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2005-2019 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 otbWrapperApplication_hxx
+#define otbWrapperApplication_hxx
+
+
+#include "otbWrapperApplication.h"
+
+
+namespace otb
+{
+
+
+namespace Wrapper
+{
+
+
+template <class TImageType>
+TImageType*
+Application
+::GetParameterImage(std::string parameter)
+
+{
+  typename TImageType::Pointer ret;
+  Parameter* param = GetParameterByKey(parameter);
+  InputImageParameter* paramDown = dynamic_cast<InputImageParameter*>(param);
+  if (paramDown)
+    {
+    return paramDown->GetImage<TImageType>();
+    }
+  else
+    {
+    itkExceptionMacro(<<parameter << " parameter can't be casted to ImageType");
+    return nullptr;
+    }
+}
+
+
+template <class TImageType>
+void
+Application
+::SetParameterOutputImage(std::string parameter, TImageType* value)
+{
+  Parameter* param = GetParameterByKey(parameter);
+
+  if (dynamic_cast<OutputImageParameter*>(param))
+    {
+    OutputImageParameter* paramDown = dynamic_cast<OutputImageParameter*>(param);
+    paramDown->SetValue(value);
+    }
+}
+
+
+} // End namespace Wrapper
+
+} // End namespace otb
+
+#endif
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperCastImage.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperCastImage.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e975d7adc2fea303e776ad7202cda5e7852f689
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperCastImage.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005-2019 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 otbWrapperCastimage_h
+#define otbWrapperCastimage_h
+
+
+#include "otbClampImageFilter.h"
+
+#include "OTBApplicationEngineExport.h"
+
+#include "otbWrapperTypes.h"
+
+
+namespace otb
+{
+namespace Wrapper
+{
+namespace details
+{
+
+/** \class CastImage
+ *  \brief Helper class (private) which casts and clamps input-image type into
+ *  output-image type.
+ *
+ * \ingroup OTBApplicationEngine
+ */
+template <typename TOutputImage, typename TInputImage>
+struct OTBApplicationEngine_EXPORT_TEMPLATE CastImage
+{
+  /** Input clamping */
+  using InputClampImageFilter = ClampImageFilter<TInputImage, DoubleVectorImageType>;
+
+  /** Output clamping */
+  using OutputClampImageFilter = ClampImageFilter<DoubleVectorImageType, TOutputImage>;
+
+
+  /** Constructor. */
+  CastImage(TInputImage* in) : icif(InputClampImageFilter::New()), ocif(OutputClampImageFilter::New()), out(ocif->GetOutput())
+  {
+    assert(in);
+
+    icif->SetInput(in);
+
+    ocif->SetInput(icif->GetOutput());
+  }
+
+  /** Input-image clamp filter. */
+  typename InputClampImageFilter::Pointer icif;
+
+  /** Output-image clamp filter. */
+  typename OutputClampImageFilter::Pointer ocif;
+
+  /** Output image. */
+  TOutputImage* out;
+};
+
+
+/** \class CastImage
+ *  \brief Partial template specialization which optimizes processing
+ * pipeline when input-image is DoubleVectorImageType.
+ *
+ * \ingroup OTBApplicationEngine
+ */
+template <typename TOutputImage>
+struct OTBApplicationEngine_EXPORT_TEMPLATE CastImage<TOutputImage, DoubleVectorImageType>
+{
+  /** Output clamping */
+  using OutputClampImageFilter = ClampImageFilter<DoubleVectorImageType, TOutputImage>;
+
+
+  /** Constructor. */
+  CastImage(DoubleVectorImageType* in) : ocif(OutputClampImageFilter::New()), out(ocif->GetOutput())
+  {
+    assert(in);
+
+    ocif->SetInput(in);
+  }
+
+  /** Input-image clamp filter. */
+  itk::ProcessObject::Pointer icif;
+
+  /** Output-image clamp filter. */
+  typename OutputClampImageFilter::Pointer ocif;
+
+  /** Output image. */
+  TOutputImage* out;
+};
+
+
+/** \class CastImage
+ *  \brief Template specialization which optimizes the processing
+ *  pipeline when input-image and output-image types are identical.
+ *
+ * \ingroup OTBApplicationEngine
+ */
+template <typename T>
+struct OTBApplicationEngine_EXPORT_TEMPLATE CastImage<T, T>
+{
+  CastImage(T* in) : out(in)
+  {
+    assert(in);
+  }
+
+  itk::ProcessObject::Pointer icif;
+  itk::ProcessObject::Pointer ocif;
+  T*                          out;
+};
+
+
+/** \class CastImage
+ *  \brief Template specialization which optimizes the processing
+ *  pipeline when input-image and output-image types are identical.
+ *
+ * \ingroup OTBApplicationEngine
+ */
+template <>
+struct OTBApplicationEngine_EXPORT_TEMPLATE CastImage<DoubleVectorImageType, DoubleVectorImageType>
+{
+  CastImage(DoubleVectorImageType* in) : out(in)
+  {
+    assert(in);
+  }
+
+  itk::ProcessObject::Pointer icif;
+  itk::ProcessObject::Pointer ocif;
+  DoubleVectorImageType*      out;
+};
+
+} // namespace details.
+
+} // namespace Wrapper
+
+} // namespace otb
+
+#endif
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
index 80aefb371880dc53c0272de0496152b26f0c7a79..a49e4c2bfb477da878372e778b3174755361d5d3 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.h
@@ -21,9 +21,13 @@
 #ifndef otbWrapperInputImageParameter_h
 #define otbWrapperInputImageParameter_h
 
+
 #include "otbImageFileReader.h"
-#include "itkImageBase.h"
+#include "otbClampImageFilter.h"
 #include "otbWrapperParameter.h"
+
+#include "itkImageBase.h"
+
 #include <string>
 
 namespace otb
@@ -56,27 +60,28 @@ public:
   itkGetConstReferenceMacro( FileName, std::string );
 
 
-  /** Get the input image as FloatVectorImageType. */
-  FloatVectorImageType* GetImage();
+  /** Get input-image as ImageBaseType. */
+  ImageBaseType const* GetImage() const;
+  ImageBaseType*       GetImage();
 
   /** Get the input image as XXXImageType */
-  UInt8ImageType* GetUInt8Image();
+  UInt8ImageType*  GetUInt8Image();
   UInt16ImageType* GetUInt16Image();
-  Int16ImageType* GetInt16Image();
+  Int16ImageType*  GetInt16Image();
   UInt32ImageType* GetUInt32Image();
-  Int32ImageType* GetInt32Image();
-  FloatImageType* GetFloatImage();
+  Int32ImageType*  GetInt32Image();
+  FloatImageType*  GetFloatImage();
   DoubleImageType* GetDoubleImage();
 
-  UInt8VectorImageType* GetUInt8VectorImage();
+  UInt8VectorImageType*  GetUInt8VectorImage();
   UInt16VectorImageType* GetUInt16VectorImage();
-  Int16VectorImageType* GetInt16VectorImage();
+  Int16VectorImageType*  GetInt16VectorImage();
   UInt32VectorImageType* GetUInt32VectorImage();
-  Int32VectorImageType* GetInt32VectorImage();
-  FloatVectorImageType* GetFloatVectorImage();
+  Int32VectorImageType*  GetInt32VectorImage();
+  FloatVectorImageType*  GetFloatVectorImage();
   DoubleVectorImageType* GetDoubleVectorImage();
 
-  UInt8RGBImageType* GetUInt8RGBImage();
+  UInt8RGBImageType*  GetUInt8RGBImage();
   UInt8RGBAImageType* GetUInt8RGBAImage();
 
   // Complex image
@@ -94,12 +99,8 @@ public:
   template <class TImageType>
     TImageType* GetImage();
 
-  /** Set a FloatVectorImageType image.*/
-  void SetImage(FloatVectorImageType* image);
-
   /** Set a templated image.*/
-  template <class TImageType>
-    void SetImage(TImageType* image);
+  void SetImage(ImageBaseType* image);
 
 
   /** Generic cast method that will be specified for each image type. */
@@ -120,48 +121,30 @@ protected:
   /** Destructor */
   ~InputImageParameter() override;
 
-  ImageBaseType::Pointer m_Image;
-  std::string m_FileName;
-
-  /** Readers typedefs */
-
-  typedef otb::ImageFileReader<UInt8ImageType> UInt8ReaderType;
-  typedef otb::ImageFileReader<Int16ImageType> Int16ReaderType;
-  typedef otb::ImageFileReader<UInt16ImageType> UInt16ReaderType;
-  typedef otb::ImageFileReader<Int32ImageType> Int32ReaderType;
-  typedef otb::ImageFileReader<UInt32ImageType> UInt32ReaderType;
-  typedef otb::ImageFileReader<FloatImageType> FloatReaderType;
-  typedef otb::ImageFileReader<DoubleImageType> DoubleReaderType;
-
-  typedef otb::ImageFileReader<UInt8VectorImageType> UInt8VectorReaderType;
-  typedef otb::ImageFileReader<Int16VectorImageType> Int16VectorReaderType;
-  typedef otb::ImageFileReader<UInt16VectorImageType> UInt16VectorReaderType;
-  typedef otb::ImageFileReader<Int32VectorImageType> Int32VectorReaderType;
-  typedef otb::ImageFileReader<UInt32VectorImageType> UInt32VectorReaderType;
-  typedef otb::ImageFileReader<FloatVectorImageType> FloatVectorReaderType;
-  typedef otb::ImageFileReader<DoubleVectorImageType> DoubleVectorReaderType;
+private:
+  InputImageParameter(const Parameter&) = delete;
+  void operator=(const Parameter&) = delete;
 
+  std::string                 m_FileName;
+  itk::ProcessObject::Pointer m_Reader;
 
-  typedef otb::ImageFileReader<UInt8RGBImageType>  UInt8RGBReaderType;
-  typedef otb::ImageFileReader<UInt8RGBAImageType> UInt8RGBAReaderType;
+  ImageBaseType::Pointer m_Image;
 
-  // Complex
-  typedef otb::ImageFileReader<ComplexInt16ImageType> ComplexInt16ReaderType;
-  typedef otb::ImageFileReader<ComplexInt32ImageType> ComplexInt32ReaderType;
-  typedef otb::ImageFileReader<ComplexFloatImageType> ComplexFloatReaderType;
-  typedef otb::ImageFileReader<ComplexDoubleImageType> ComplexDoubleReaderType;
+  itk::ProcessObject::Pointer m_InputCaster;
+  itk::ProcessObject::Pointer m_OutputCaster;
 
-  typedef otb::ImageFileReader<ComplexInt16VectorImageType> ComplexInt16VectorReaderType;
-  typedef otb::ImageFileReader<ComplexInt32VectorImageType> ComplexInt32VectorReaderType;
-  typedef otb::ImageFileReader<ComplexFloatVectorImageType> ComplexFloatVectorReaderType;
-  typedef otb::ImageFileReader<ComplexDoubleVectorImageType> ComplexDoubleVectorReaderType;
+private:
+  /** */
+  template <typename T>
+  using InputClampImageFilter = ClampImageFilter<T, otb::Wrapper::DoubleVectorImageType>;
 
-  itk::ProcessObject::Pointer m_Reader;
-  itk::ProcessObject::Pointer m_Caster;
+  /** */
+  template <typename T>
+  using OutputClampImageFilter = ClampImageFilter<otb::Wrapper::DoubleVectorImageType, T>;
 
-private:
-  InputImageParameter(const Parameter &) = delete;
-  void operator =(const Parameter&) = delete;
+  /** */
+  template <typename TOutputImage, typename TInputImage>
+  TOutputImage* Cast(TInputImage*);
 
   /** Store the loaded image filename */
   std::string m_PreviousFileName;
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.hxx b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.hxx
index eb0f507910c6baf093bcb2297784fa6bad00f35c..37ffbd7efae807466a60d05f708ea29ac271c49f 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.hxx
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperInputImageParameter.hxx
@@ -23,7 +23,7 @@
 
 #include "otbWrapperInputImageParameter.h"
 
-#include "otbClampImageFilter.h"
+#include "otbWrapperCastImage.h"
 
 namespace otb
 {
@@ -31,7 +31,70 @@ namespace Wrapper
 {
 
 
-#define INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION 0
+#define CLAMP_IMAGE_IF( Out, In, image_base )	\
+  {							\
+    In * in_image = dynamic_cast< In * >( image_base );	\
+							\
+    if( in_image )						\
+      return Cast< Out, In >( in_image );			\
+  }
+
+#define CLAMP_IMAGE_BASE( T, image_base )				\
+  {									\
+    CLAMP_IMAGE_IF( T, UInt8VectorImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, Int16VectorImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, UInt16VectorImageType, image_base );	\
+    CLAMP_IMAGE_IF( T, Int32VectorImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, UInt32VectorImageType, image_base );	\
+									\
+    CLAMP_IMAGE_IF( T, FloatVectorImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, DoubleVectorImageType, image_base );	\
+									\
+    CLAMP_IMAGE_IF( T, ComplexInt16VectorImageType, image_base );	\
+    CLAMP_IMAGE_IF( T, ComplexInt32VectorImageType, image_base );	\
+									\
+    CLAMP_IMAGE_IF( T, ComplexFloatVectorImageType, image_base );	\
+    CLAMP_IMAGE_IF( T, ComplexDoubleVectorImageType, image_base );	\
+    									\
+    CLAMP_IMAGE_IF( T, UInt8RGBImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, UInt8RGBAImageType, image_base );		\
+									\
+    CLAMP_IMAGE_IF( T, UInt8ImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, Int16ImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, UInt16ImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, Int32ImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, UInt32ImageType, image_base );		\
+									\
+    CLAMP_IMAGE_IF( T, FloatImageType, image_base );		\
+    CLAMP_IMAGE_IF( T, DoubleImageType, image_base );		\
+									\
+    CLAMP_IMAGE_IF( T, ComplexInt16ImageType, image_base );	\
+    CLAMP_IMAGE_IF( T, ComplexInt32ImageType, image_base );	\
+									\
+    CLAMP_IMAGE_IF( T, ComplexFloatImageType, image_base );	\
+    CLAMP_IMAGE_IF( T, ComplexDoubleImageType, image_base );	\
+									\
+    return nullptr;							\
+  }
+
+
+template< typename TOutputImage,
+	  typename TInputImage >
+TOutputImage *
+InputImageParameter
+::Cast( TInputImage * image )
+{
+  details::CastImage< TOutputImage, TInputImage > clamp( image );
+
+  if( clamp.ocif )
+    clamp.ocif->UpdateOutputInformation();
+
+  m_InputCaster = clamp.icif;
+  m_OutputCaster = clamp.ocif;
+
+  return clamp.out;
+}
+
 
 template <class TImageType>
 TImageType*
@@ -68,10 +131,6 @@ InputImageParameter::GetImage()
       }
     else
       {
-#if INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION
-      return dynamic_cast< TImageType* >( m_Image.GetPointer() );
-
-#else // INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION
       // In this case, the reader and the image should already be there
       if (m_Image.IsNull())
         {
@@ -89,7 +148,6 @@ InputImageParameter::GetImage()
           itkExceptionMacro("Cannot ask a different image type");
           }
         }
-#endif // INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION
       }
     }
 
@@ -98,119 +156,10 @@ InputImageParameter::GetImage()
     //////////////////////// Image case:
     if (m_Image.IsNull())
       {
-#if INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION
-      itkExceptionMacro("No input image or filename detected...");
-#else
       return nullptr;
-#endif
       }
     else
-      {
-      if (dynamic_cast<UInt8ImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt8ImageType, TImageType> ();
-        }
-      else if (dynamic_cast<Int16ImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<Int16ImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt16ImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt16ImageType, TImageType> ();
-        }
-      else if (dynamic_cast<Int32ImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<Int32ImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt32ImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt32ImageType, TImageType> ();
-        }
-      else if (dynamic_cast<FloatImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<FloatImageType, TImageType> ();
-        }
-      else if (dynamic_cast<DoubleImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<DoubleImageType, TImageType> ();
-        }
-      else if (dynamic_cast<ComplexInt16ImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexInt16ImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexInt32ImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexInt32ImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexFloatImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexFloatImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexDoubleImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexDoubleImageType, TImageType>();
-        }
-      else if (dynamic_cast<UInt8VectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt8VectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<Int16VectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<Int16VectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt16VectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt16VectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<Int32VectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<Int32VectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt32VectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt32VectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<FloatVectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<FloatVectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<DoubleVectorImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<DoubleVectorImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt8RGBAImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt8RGBAImageType, TImageType> ();
-        }
-      else if (dynamic_cast<UInt8RGBImageType*> (m_Image.GetPointer()))
-        {
-        return CastImage<UInt8RGBImageType, TImageType> ();
-        }
-      else if (dynamic_cast<ComplexInt16VectorImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexInt16VectorImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexInt32VectorImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexInt32VectorImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexFloatVectorImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexFloatVectorImageType, TImageType>();
-        }
-      else if (dynamic_cast<ComplexDoubleVectorImageType*>(m_Image.GetPointer()))
-        {
-        return CastImage<ComplexDoubleVectorImageType, TImageType>();
-        }
-      else
-        {
-#if INPUT_IMAGE_PARAMETER_GET_IMAGE_EXCEPTION
-        itkExceptionMacro("Unknown image type");
-#else
-	return nullptr;
-#endif
-        }
-      }
+      CLAMP_IMAGE_BASE( TImageType, m_Image.GetPointer() );
     }
 }
 
@@ -221,41 +170,6 @@ ImageBaseType*
 InputImageParameter::GetImage<ImageBaseType>();
 
 
-template <class TInputImage, class TOutputImage>
-TOutputImage*
-InputImageParameter::CastImage()
-{
-  if ( dynamic_cast<TOutputImage*> (m_Image.GetPointer()) )
-    {
-    return dynamic_cast<TOutputImage*> (m_Image.GetPointer());
-    }
-  else
-    {
-    TInputImage* realInputImage = dynamic_cast<TInputImage*>(m_Image.GetPointer());
-
-    typedef ClampImageFilter<TInputImage, TOutputImage> CasterType;
-    typename CasterType::Pointer caster = CasterType::New();
-
-    caster->SetInput(realInputImage);
-    caster->UpdateOutputInformation();
-
-    m_Image = caster->GetOutput();
-    m_Caster = caster;
-
-    return caster->GetOutput();
-    } 
-  // itkExceptionMacro("Cast from "<<typeid(TInputImage).name()<<" to "<<typeid(TOutputImage).name()<<" not authorized.");
-}
-
-template <class TInputImage>
-void
-InputImageParameter::SetImage(TInputImage* image)
-{
-  m_UseFilename = false;
-  m_Image = image;
-}
-
-
 } // End namespace Wrapper
 } // End namespace otb
 
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
index 5a454d57bae108501f0822770616775ed914034e..ec7a1a8f859118d6d63c12872476647fe54b062d 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperOutputImageParameter.h
@@ -27,6 +27,7 @@
 #include "otbImageFileWriter.h"
 #include <string>
 
+
 namespace otb
 {
 namespace Wrapper
@@ -126,36 +127,34 @@ protected:
   /** Destructor */
   ~OutputImageParameter() override;
 
-  template <class TInput>
-    int SwitchInput(TInput *img);
-
-  //FloatVectorImageType::Pointer m_Image;
-  ImageBaseType::Pointer m_Image;
-  std::string            m_FileName;
-  ImagePixelType         m_PixelType;
-  ImagePixelType         m_DefaultPixelType;
-
 private:
   OutputImageParameter(const Parameter &) = delete;
   void operator =(const Parameter&) = delete;
 
-  unsigned int                  m_RAMValue;
+  /** Switch TInputImage according to expected output type. */
+  template <typename TInputImage>
+  void SwitchInput(TInputImage*);
+
+  /** */
+  template <typename TOutputImage, typename TInputImage>
+  void ClampAndWriteVectorImage(TInputImage*);
 
-  itk::ProcessObject::Pointer m_Caster;
+  // FloatVectorImageType::Pointer m_Image;
+  ImageBaseType::Pointer m_Image;
+
+  itk::ProcessObject::Pointer m_InputCaster;
+  itk::ProcessObject::Pointer m_OutputCaster;
 
   itk::ProcessObject::Pointer m_Writer;
 
-}; // End class OutputImage Parameter
+  std::string m_FileName;
 
-// Declare specialisation for UInt8RGBAImageType
-template <>
-int
-OutputImageParameter::SwitchInput(UInt8RGBAImageType *img);
+  ImagePixelType m_PixelType;
+  ImagePixelType m_DefaultPixelType;
 
-// Declare specialisation for UInt8RGBImageType
-template <>
-int
-OutputImageParameter::SwitchInput(UInt8RGBImageType *img);
+  unsigned int m_RAMValue;
+
+}; // End class OutputImage Parameter
 
 } // End namespace Wrapper
 } // End namespace otb
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperParameter.h
index 0a93e62995f0dba21b7f35d89457d963d29b9c7e..6ab769e5eca20ac6d8c7b575680e32ca0b0de784 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperParameter.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperParameter.h
@@ -21,13 +21,18 @@
 #ifndef otbWrapperParameter_h
 #define otbWrapperParameter_h
 
-#include "otbMacro.h"
-#include "itkObjectFactory.h"
 
-#include "otbWrapperTypes.h"
 #include "OTBApplicationEngineExport.h"
+#include "otbMacro.h"
+#include "otbWrapperTypes.h"
+
+
+#include <itkObjectFactory.h>
+
+
 #include <string>
 
+
 namespace otb
 {
 namespace Wrapper
@@ -65,11 +70,11 @@ public:
   /** Set/get the parameter key */
   virtual void SetKey(const std::string&);
   virtual const char* GetKey() const;
-  
+
   /** Set the parameter Active flag */
   virtual void SetActive(bool flag);
   bool GetActive(bool recurseParents = false) const;
-  
+
   /** Set the parameter Mandatory flag */
   virtual void SetMandatory(bool flag);
   virtual bool GetMandatory() const;
@@ -78,19 +83,19 @@ public:
 
   /** Set the parameter AutomaticValue flag (which is the opposite of UserValue)*/
   virtual void SetAutomaticValue(bool flag);
- 
+
   /** Get the parameter AutomaticValue flag */
   virtual bool GetAutomaticValue() const;
-  
+
   /** Toogle ON the parameter AutomaticValue flag */
   void AutomaticValueOn();
-  
+
   /** Toogle OFF the parameter AutomaticValue flag */
   void AutomaticValueOff();
 
   /** Set the user access level */
   virtual void SetUserLevel(const UserLevel level);
-  
+
   /** Get the user access level */
   virtual UserLevel GetUserLevel() const;
 
@@ -104,7 +109,7 @@ public:
    * nothing
    */
   virtual void Reset();
-  
+
   virtual bool HasValue() const = 0;
 
   virtual bool HasUserValue() const;
diff --git a/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt b/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
index 6f0b8809cb026b1b4143277ac45e41c4d9d62529..fb220c564fbe628d9e9469f6f3f438352caa6454 100644
--- a/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
+++ b/Modules/Wrappers/ApplicationEngine/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+
 #
 # Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 #
@@ -57,6 +58,7 @@ set( OTBApplicationEngine_SRC
   otbWrapperBoolParameter.cxx
   otbWrapperMetaDataHelper.cxx
   otbWrapperParameter.cxx
+  otbWrapperCastImage.cxx
   otbWrapperTypes.cxx
   )
 
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
index 8c0d624ae5e2f79bf323b3c41d3821d0ad38a5b3..4297ae946d62476a88847a9974cd5aff72526fb3 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
@@ -71,6 +71,80 @@ ExceptionObject(file, line, message, loc)
 namespace Wrapper
 {
 
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt8VectorImageType* Application::GetParameterImage<UInt8VectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE Int16VectorImageType* Application::GetParameterImage<Int16VectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt16VectorImageType* Application::GetParameterImage<UInt16VectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE Int32VectorImageType* Application::GetParameterImage<Int32VectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt32VectorImageType* Application::GetParameterImage<UInt32VectorImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE FloatVectorImageType* Application::GetParameterImage<FloatVectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE DoubleVectorImageType* Application::GetParameterImage<DoubleVectorImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexInt16VectorImageType* Application::GetParameterImage<ComplexInt16VectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexInt32VectorImageType* Application::GetParameterImage<ComplexInt32VectorImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexFloatVectorImageType* Application::GetParameterImage<ComplexFloatVectorImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexDoubleVectorImageType* Application::GetParameterImage<ComplexDoubleVectorImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt8RGBImageType* Application::GetParameterImage<UInt8RGBImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt8RGBAImageType* Application::GetParameterImage<UInt8RGBAImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt8ImageType* Application::GetParameterImage<UInt8ImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE Int16ImageType* Application::GetParameterImage<Int16ImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt16ImageType* Application::GetParameterImage<UInt16ImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE Int32ImageType* Application::GetParameterImage<Int32ImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE UInt32ImageType* Application::GetParameterImage<UInt32ImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE FloatImageType* Application::GetParameterImage<FloatImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE DoubleImageType* Application::GetParameterImage<DoubleImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexInt16ImageType* Application::GetParameterImage<ComplexInt16ImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexInt32ImageType* Application::GetParameterImage<ComplexInt32ImageType>(std::string);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexFloatImageType* Application::GetParameterImage<ComplexFloatImageType>(std::string);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE ComplexDoubleImageType* Application::GetParameterImage<ComplexDoubleImageType>(std::string);
+
+//
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt8VectorImageType>(std::string, UInt8VectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<Int16VectorImageType>(std::string, Int16VectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt16VectorImageType>(std::string, UInt16VectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<Int32VectorImageType>(std::string, Int32VectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt32VectorImageType>(std::string, UInt32VectorImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<FloatVectorImageType>(std::string, FloatVectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<DoubleVectorImageType>(std::string, DoubleVectorImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt16VectorImageType>(std::string,
+                                                                                                                              ComplexInt16VectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt32VectorImageType>(std::string,
+                                                                                                                              ComplexInt32VectorImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexFloatVectorImageType>(std::string,
+                                                                                                                              ComplexFloatVectorImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexDoubleVectorImageType>(std::string,
+                                                                                                                               ComplexDoubleVectorImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt8RGBImageType>(std::string, UInt8RGBImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt8RGBAImageType>(std::string, UInt8RGBAImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt8ImageType>(std::string, UInt8ImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<Int16ImageType>(std::string, Int16ImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt16ImageType>(std::string, UInt16ImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<Int32ImageType>(std::string, Int32ImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<UInt32ImageType>(std::string, UInt32ImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<FloatImageType>(std::string, FloatImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<DoubleImageType>(std::string, DoubleImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt16ImageType>(std::string, ComplexInt16ImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexInt32ImageType>(std::string, ComplexInt32ImageType*);
+
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexFloatImageType>(std::string, ComplexFloatImageType*);
+template OTBApplicationEngine_EXPORT_EXPLICIT_TEMPLATE void Application::SetParameterOutputImage<ComplexDoubleImageType>(std::string, ComplexDoubleImageType*);
+
+
 void Application::SetName( const std::string & name )
 {
   m_Name = name;
@@ -466,8 +540,7 @@ Application::RegisterPipeline()
     if ( GetParameterType(key) == ParameterType_OutputImage )
       {
       Parameter* param = GetParameterByKey(key);
-      OutputImageParameter * outP = 
-        dynamic_cast< OutputImageParameter * >( param );
+      OutputImageParameter* outP    = dynamic_cast<OutputImageParameter*>(param);
       itk::ImageBase< 2 > * outData = outP->GetValue();
       if ( outData )
         dataStack.push(outData);
@@ -475,8 +548,7 @@ Application::RegisterPipeline()
     else if ( GetParameterType(key) == ParameterType_OutputVectorData )
       {
       Parameter* param = GetParameterByKey(key);
-      OutputVectorDataParameter * outP = 
-        dynamic_cast< OutputVectorDataParameter * >( param );
+      OutputVectorDataParameter* outP    = dynamic_cast<OutputVectorDataParameter*>(param);
       VectorDataType * outData = outP->GetValue();
       if ( outData )
         dataStack.push(outData);
@@ -484,8 +556,7 @@ Application::RegisterPipeline()
     else if ( GetParameterType(key) == ParameterType_InputImage )
       {
       Parameter* param = GetParameterByKey(key);
-      InputImageParameter * inP = 
-        dynamic_cast< InputImageParameter * >( param );
+      InputImageParameter* inP   = dynamic_cast<InputImageParameter*>(param);
       if ( !inP->HasValue() )
         continue;
       ImageBaseType * inData = inP->GetImage< ImageBaseType >();
@@ -495,13 +566,12 @@ Application::RegisterPipeline()
     else if ( GetParameterType(key) == ParameterType_InputImageList )
       {
       Parameter * param = GetParameterByKey(key);
-      InputImageListParameter * inP = 
-        dynamic_cast< InputImageListParameter * > ( param );
+      InputImageListParameter* inP   = dynamic_cast<InputImageListParameter*>(param);
       if ( !inP->HasValue() )
         continue;
       const FloatVectorImageListType * list = inP->GetImageList();
-      for ( auto it = list->Begin() ; it != list->End() ; ++it ) 
-        {
+      for (auto it = list->Begin(); it != list->End(); ++it)
+      {
         FloatVectorImageType * inData = it.Get().GetPointer();
         if ( inData && !inputData.count(inData) )
           inputData.insert(inData);
@@ -546,10 +616,9 @@ Application::RegisterPipeline()
     // if current is a list push every of its members in datastack
     if ( dynamic_cast< DataObjectListInterface *> (current) )
       {
-      DataObjectListInterface * list = 
-        dynamic_cast< DataObjectListInterface *> (current);
-      int length = list->Size();
-      for ( int i = 0 ; i < length ; i++ )
+        DataObjectListInterface* list   = dynamic_cast<DataObjectListInterface*>(current);
+        int                      length = list->Size();
+        for (int i = 0; i < length; i++)
         {
         itk::DataObject * newData = list->GetNthDataObject(i);
         if ( !current || inputData.count( current ) )
@@ -627,10 +696,9 @@ void Application::FreeRessources()
       // If input is a list
       if ( dynamic_cast< DataObjectListInterface *> (data.GetPointer()) )
         {
-        DataObjectListInterface * list = 
-          dynamic_cast< DataObjectListInterface *> (data.GetPointer());
-        int length = list->Size();
-        for ( int i = 0 ; i < length ; i++ )
+          DataObjectListInterface* list   = dynamic_cast<DataObjectListInterface*>(data.GetPointer());
+          int                      length = list->Size();
+          for (int i = 0; i < length; i++)
           {
           itk::DataObject * newData = list->GetNthDataObject(i);
           if ( !newData || dataSet.count( newData ) )
@@ -693,7 +761,7 @@ int Application::Execute()
   m_IsInPrivateDo = true;
   this->DoExecute();
   m_IsInPrivateDo = false;
-  
+
   // Ensure that all output image parameter have called UpdateOutputInformation()
   for (auto it = paramList.begin(); it != paramList.end(); ++it)
     {
@@ -806,7 +874,7 @@ int Application::ExecuteAndWriteOutput()
 
   this->AfterExecuteAndWriteOutputs();
   m_Chrono.Stop();
-  
+
   FreeRessources();
   m_Filters.clear();
   return status;
@@ -1513,7 +1581,7 @@ Application::SetParameterImageBase(const std::string & key, ImageBaseType* img,
   if (dynamic_cast<InputImageParameter*>(param))
     {
     InputImageParameter* paramDown = dynamic_cast<InputImageParameter*>(param);
-    paramDown->SetImage<ImageBaseType>(img);
+    paramDown->SetImage(img);
     }
   else if (dynamic_cast<InputImageListParameter*>(param))
     {
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperCastImage.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperCastImage.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..347954c65e2bc783195d69db17d8a7619f42a0c1
--- /dev/null
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperCastImage.cxx
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2005-2019 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 "otbWrapperCastImage.h"
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
index 65d6d6780585ceaa9bb696d18dbbc1da3b39f6dd..6959aba4ff523f3d14717e52babe45c43efae7b7 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperInputImageParameter.cxx
@@ -24,6 +24,7 @@
 #include "otbWrapperInputImageParameterMacros.h"
 #include "otb_boost_string_header.h"
 
+
 namespace otb
 {
 
@@ -62,12 +63,18 @@ InputImageParameter::SetFromFileName(const std::string& filename)
 }
 
 
-FloatVectorImageType*
-InputImageParameter::GetImage()
+ImageBaseType* InputImageParameter ::GetImage()
+{
+  return m_Image.GetPointer();
+}
+
+
+ImageBaseType const* InputImageParameter ::GetImage() const
 {
-  return this->GetImage<FloatVectorImageType>();
+  return m_Image.GetPointer();
 }
 
+
 template <>
 ImageBaseType*
 InputImageParameter::GetImage<ImageBaseType>()
@@ -81,21 +88,18 @@ InputImageParameter::GetImage<ImageBaseType>()
 otbGetImageMacro(UInt8RGBImage);
 otbGetImageMacro(UInt8RGBAImage);
 
-void
-InputImageParameter::SetImage(FloatVectorImageType* image)
+
+void InputImageParameter ::SetImage(ImageBaseType* image)
 {
   m_UseFilename = false;
-  this->SetImage<FloatVectorImageType>( image );
+  m_Image       = image;
 }
 
 
 bool
 InputImageParameter::HasValue() const
 {
-  if( m_FileName.empty() && m_Image.IsNull() )
-    return false;
-  else
-    return true;
+  return !m_FileName.empty() || !m_Image.IsNull();
 }
 
 void
@@ -104,7 +108,8 @@ InputImageParameter
 {
   m_Image  = nullptr;
   m_Reader = nullptr;
-  m_Caster = nullptr;
+  m_InputCaster     = nullptr;
+  m_OutputCaster    = nullptr;
   m_FileName = "";
   m_PreviousFileName="";
   m_UseFilename = true;
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
index 7dcd30d0bfebe934c618c9a9ea43fc6d6e65b191..39b36a355b29517de756b0193206a053434fff36 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperOutputImageParameter.cxx
@@ -19,35 +19,54 @@
  */
 
 #include "otbWrapperOutputImageParameter.h"
+
 #include "otbClampImageFilter.h"
 #include "otbImageIOFactory.h"
-#include "itksys/SystemTools.hxx"
+#include "otbWrapperCastImage.h"
 
 #ifdef OTB_USE_MPI
-
 #include "otbMPIConfig.h"
 #include "otbMPIVrtWriter.h"
-
 #ifdef OTB_USE_SPTW
 #include "otbSimpleParallelTiffWriter.h"
 #endif
-
 #endif
 
+#include "itksys/SystemTools.hxx"
+
+
+#define CAST_IMAGE_BASE(T, image_base)     \
+  {                                        \
+    T* img = dynamic_cast<T*>(image_base); \
+                                           \
+    if (img)                               \
+    {                                      \
+      SwitchInput<T>(img);                 \
+                                           \
+      return;                              \
+    }                                      \
+  }
+
+
 namespace otb
 {
 namespace Wrapper
 {
 
-OutputImageParameter::OutputImageParameter()
-  : m_PixelType(ImagePixelType_float),
-    m_DefaultPixelType(ImagePixelType_float),
-    m_RAMValue(0),
-    m_Caster(nullptr),
-    m_Writer(nullptr)
+
+// Declare specialisation for UInt8RGBAImageType
+template <>
+void OutputImageParameter::SwitchInput(UInt8RGBAImageType*);
+
+// Declare specialisation for UInt8RGBImageType
+template <>
+void OutputImageParameter::SwitchInput(UInt8RGBImageType*);
+
+
+OutputImageParameter::OutputImageParameter() : m_PixelType(ImagePixelType_float), m_DefaultPixelType(ImagePixelType_float), m_RAMValue(0)
 {
-  this->SetName("Output Image");
-  this->SetKey("out");
+  SetName("Output Image");
+  SetKey("out");
 }
 
 
@@ -57,6 +76,9 @@ OutputImageParameter::~OutputImageParameter()
 
 std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
 {
+  // TODO: Could be replaced by constant static string array e.g.:
+  // return PIXEL_TYPE_NAME[ type ];
+
   std::string ret;
   switch(type)
     {
@@ -122,6 +144,9 @@ std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
 bool
 OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePixelType &type)
 {
+  // TODO: Could be replaced std::find_if() in constant static string
+  // array (see ::ConvertPixelTypeToString().
+
   if (value == "uint8")
     type = ImagePixelType_uint8;
   else if (value == "int16")
@@ -149,278 +174,207 @@ OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePi
   return true;
 }
 
-void OutputImageParameter::InitializeWriters()
+
+void OutputImageParameter ::InitializeWriters()
 {
-  ImageBaseType* imgBase = m_Image.GetPointer();
-  // Guess the image type
-  std::string className(m_Image->GetNameOfClass());
-  if (className == "VectorImage")
-    {
-    UInt8VectorImageType* imgUInt8 = dynamic_cast<UInt8VectorImageType*>(imgBase);
-    if (imgUInt8 && SwitchInput(imgUInt8)) return;
+  ImageBaseType* image = m_Image.GetPointer();
 
-    Int16VectorImageType* imgInt16 = dynamic_cast<Int16VectorImageType*>(imgBase);
-    if (imgInt16 && SwitchInput(imgInt16)) return;
+  CAST_IMAGE_BASE(UInt8VectorImageType, image);
+  CAST_IMAGE_BASE(Int16VectorImageType, image);
+  CAST_IMAGE_BASE(UInt16VectorImageType, image);
+  CAST_IMAGE_BASE(Int32VectorImageType, image);
+  CAST_IMAGE_BASE(UInt32VectorImageType, image);
 
-    UInt16VectorImageType* imgUInt16 = dynamic_cast<UInt16VectorImageType*>(imgBase);
-    if (imgUInt16 && SwitchInput(imgUInt16)) return;
+  CAST_IMAGE_BASE(FloatVectorImageType, image);
+  CAST_IMAGE_BASE(DoubleVectorImageType, image);
 
-    Int32VectorImageType* imgInt32 = dynamic_cast<Int32VectorImageType*>(imgBase);
-    if (imgInt32 && SwitchInput(imgInt32)) return;
+  CAST_IMAGE_BASE(ComplexInt16VectorImageType, image);
+  CAST_IMAGE_BASE(ComplexInt32VectorImageType, image);
+  CAST_IMAGE_BASE(ComplexFloatVectorImageType, image);
+  CAST_IMAGE_BASE(ComplexDoubleVectorImageType, image);
 
-    UInt32VectorImageType* imgUInt32 = dynamic_cast<UInt32VectorImageType*>(imgBase);
-    if (imgUInt32 && SwitchInput(imgUInt32)) return;
+  CAST_IMAGE_BASE(UInt8ImageType, image);
+  CAST_IMAGE_BASE(Int16ImageType, image);
+  CAST_IMAGE_BASE(UInt16ImageType, image);
+  CAST_IMAGE_BASE(Int32ImageType, image);
+  CAST_IMAGE_BASE(UInt32ImageType, image);
 
-    FloatVectorImageType* imgFloat = dynamic_cast<FloatVectorImageType*>(imgBase);
-    if (imgFloat && SwitchInput(imgFloat)) return;
+  CAST_IMAGE_BASE(FloatImageType, image);
+  CAST_IMAGE_BASE(DoubleImageType, image);
 
-    DoubleVectorImageType* imgDouble = dynamic_cast<DoubleVectorImageType*>(imgBase);
-    if (imgDouble && SwitchInput(imgDouble)) return;
+  CAST_IMAGE_BASE(ComplexInt16ImageType, image);
+  CAST_IMAGE_BASE(ComplexInt32ImageType, image);
+  CAST_IMAGE_BASE(ComplexFloatImageType, image);
+  CAST_IMAGE_BASE(ComplexDoubleImageType, image);
 
-    ComplexInt16VectorImageType* imgCInt16 = dynamic_cast<ComplexInt16VectorImageType*>(imgBase);
-    if (imgCInt16 && SwitchInput(imgCInt16)) return;
+  CAST_IMAGE_BASE(UInt8RGBImageType, image);
+  CAST_IMAGE_BASE(UInt8RGBAImageType, image);
 
-    ComplexInt32VectorImageType* imgCInt32 = dynamic_cast<ComplexInt32VectorImageType*>(imgBase);
-    if (imgCInt32 && SwitchInput(imgCInt32)) return;
+  itkExceptionMacro("Unknown image-base type.");
+}
 
-    ComplexFloatVectorImageType* imgCFloat = dynamic_cast<ComplexFloatVectorImageType*>(imgBase);
-    if (imgCFloat && SwitchInput(imgCFloat)) return;
 
-    ComplexDoubleVectorImageType* imgCDouble = dynamic_cast<ComplexDoubleVectorImageType*>(imgBase);
-    if (imgCDouble && SwitchInput(imgCDouble)) return;
-    }
-  else
-    {
-    UInt8ImageType* imgUInt8 = dynamic_cast<UInt8ImageType*>(imgBase);
-    if (imgUInt8 && SwitchInput(imgUInt8)) return;
+template <typename TOutputImage, typename TInputImage>
+void OutputImageParameter ::ClampAndWriteVectorImage(TInputImage* in)
+{
+  assert(in);
+  assert(!m_FileName.empty());
 
-    Int16ImageType* imgInt16 = dynamic_cast<Int16ImageType*>(imgBase);
-    if (imgInt16 && SwitchInput(imgInt16)) return;
+  // Use metaprogramming to choose optimized pipeline.
+  details::CastImage<TOutputImage, TInputImage> clamp(in);
 
-    UInt16ImageType* imgUInt16 = dynamic_cast<UInt16ImageType*>(imgBase);
-    if (imgUInt16 && SwitchInput(imgUInt16)) return;
 
-    Int32ImageType* imgInt32 = dynamic_cast<Int32ImageType*>(imgBase);
-    if (imgInt32 && SwitchInput(imgInt32)) return;
+#ifdef OTB_USE_MPI
 
-    UInt32ImageType* imgUInt32 = dynamic_cast<UInt32ImageType*>(imgBase);
-    if (imgUInt32 && SwitchInput(imgUInt32)) return;
+  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();
 
-    FloatImageType* imgFloat = dynamic_cast<FloatImageType*>(imgBase);
-    if (imgFloat && SwitchInput(imgFloat)) return;
+  if (mpiConfig->GetNbProcs() > 1)
+  {
+    std::string extension = itksys::SystemTools::GetFilenameExtension(m_FileName);
 
-    DoubleImageType* imgDouble = dynamic_cast<DoubleImageType*>(imgBase);
-    if (imgDouble && SwitchInput(imgDouble)) return;
+    if (extension == ".vrt")
+    {
+      // Use the MPIVrtWriter
 
-    ComplexInt16ImageType* imgCInt16 = dynamic_cast<ComplexInt16ImageType*>(imgBase);
-    if (imgCInt16 && SwitchInput(imgCInt16)) return;
+      auto vrtWriter = otb::MPIVrtWriter<TOutputImage>::New();
 
-    ComplexInt32ImageType* imgCInt32 = dynamic_cast<ComplexInt32ImageType*>(imgBase);
-    if (imgCInt32 && SwitchInput(imgCInt32)) return;
+      vrtWriter->SetInput(clamp.out);
+      vrtWriter->SetFileName(m_FileName);
+      vrtWriter->SetAvailableRAM(m_RAMValue);
 
-    ComplexFloatImageType* imgCFloat = dynamic_cast<ComplexFloatImageType*>(imgBase);
-    if (imgCFloat && SwitchInput(imgCFloat)) return;
+      // Change internal state only when everything has been setup
+      // without raising exception.
 
-    ComplexDoubleImageType* imgCDouble = dynamic_cast<ComplexDoubleImageType*>(imgBase);
-    if (imgCDouble && SwitchInput(imgCDouble)) return;
+      m_InputCaster  = clamp.icif;
+      m_OutputCaster = clamp.ocif;
 
-    UInt8RGBImageType* imgRGB = dynamic_cast<UInt8RGBImageType*>(imgBase);
-    if (imgRGB && SwitchInput(imgRGB)) return;
+      m_Writer = vrtWriter;
 
-    UInt8RGBAImageType* imgRGBA = dynamic_cast<UInt8RGBAImageType*>(imgBase);
-    if (imgRGBA && SwitchInput(imgRGBA)) return;
+      return;
     }
 
-  itkExceptionMacro("Unknown image type");
-}
-
+#ifdef OTB_USE_SPTW
 
-template <typename TInput, typename TOutput> 
-std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> 
-ClampAndWriteVectorImage( TInput * in ,
-                    const std::string & filename , 
-                    const unsigned int & ramValue )
-{
-  std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> ret;
-  typedef ClampImageFilter < TInput , TOutput > ClampFilterType;
-  typename ClampFilterType::Pointer clampFilter ( ClampFilterType::New() );
+    else if (extension == ".tif")
+    {
+      // Use simple parallel tiff writer
 
-  clampFilter->SetInput( in);
-  ret.first = clampFilter.GetPointer();
-  
-  bool useStandardWriter = true;
+      auto sptWriter = otb::SimpleParallelTiffWriter<TOutputImage>::New();
 
-  #ifdef OTB_USE_MPI
+      sptWriter->SetFileName(m_FileName);
+      sptWriter->SetInput(clamp.out);
+      sptWriter->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
 
-  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();
+      // Change internal state only when everything has been setup
+      // without raising exception.
 
-  if (mpiConfig->GetNbProcs() > 1)
-    {
-    useStandardWriter = false;
+      m_InputCaster  = clamp.icif;
+      m_OutputCaster = clamp.ocif;
 
-    // Get file extension
-    std::string extension = itksys::SystemTools::GetFilenameExtension(filename);
+      m_Writer = sptWriter;
 
-    if(extension == ".vrt")
-      {
-      // Use the MPIVrtWriter
-      typedef otb::MPIVrtWriter<TOutput> VRTWriterType;
+      return;
+    }
 
-      typename VRTWriterType::Pointer vrtWriter = VRTWriterType::New();
-      vrtWriter->SetInput(clampFilter->GetOutput());
-      vrtWriter->SetFileName(filename);
-      vrtWriter->SetAvailableRAM(ramValue);
-      ret.second = vrtWriter.GetPointer();
-      }
-    #ifdef OTB_USE_SPTW
-    else if (extension == ".tif")
-      {
-      // Use simple parallel tiff writer
-      typedef otb::SimpleParallelTiffWriter<TOutput> SPTWriterType;
+#endif // OTB_USE_SPTW
 
-      typename SPTWriterType::Pointer sptWriter = SPTWriterType::New();
-      sptWriter->SetFileName(filename);
-      sptWriter->SetInput(clampFilter->GetOutput());
-      sptWriter->GetStreamingManager()->SetDefaultRAM(ramValue);
-      ret.second = sptWriter.GetPointer();
-      }
-    
-    #endif
     else
       {
-      itkGenericExceptionMacro("File format "<<extension<<" not supported for parallel writing with MPI. Supported formats are .vrt and .tif. Extended filenames are not supported.");
+        itkGenericExceptionMacro("File format " << extension
+                                                << " not supported for parallel writing with MPI. Supported formats are "
+                                                   ".vrt and .tif. Extended filenames are not supported.");
       }
-  
-    }
-  
-  #endif
-  
-  if(useStandardWriter)
-    {
-    typename otb::ImageFileWriter<TOutput>::Pointer writer =
-      otb::ImageFileWriter<TOutput>::New();
-    writer->SetFileName( filename );
-    writer->SetInput(clampFilter->GetOutput());
-    writer->GetStreamingManager()->SetDefaultRAM(ramValue);
-    ret.second = writer.GetPointer();
     }
 
-  return ret;
+#endif // OTB_USE_MPI
+
+    //
+    // Use default OTB writer.
+
+    auto writer = otb::ImageFileWriter<TOutputImage>::New();
+
+    writer->SetFileName(m_FileName);
+    writer->SetInput(clamp.out);
+    writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
+
+    // Change internal state only when everything has been setup
+    // without raising exception.
+
+    m_InputCaster  = clamp.icif;
+    m_OutputCaster = clamp.ocif;
+
+    m_Writer = writer;
 }
 
-template <class TInput>
-int
-OutputImageParameter::SwitchInput(TInput *img)
+
+template <typename TInputImage>
+void OutputImageParameter ::SwitchInput(TInputImage* image)
 {
-  if (! img) return 0;
+  assert(image);
 
-  std::pair<itk::ProcessObject::Pointer,itk::ProcessObject::Pointer> ret;
-  switch(m_PixelType )
-    {
-    case ImagePixelType_uint8:
-    {
-    ret = ClampAndWriteVectorImage< TInput , UInt8VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+  switch (m_PixelType)
+  {
+  case ImagePixelType_uint8:
+    ClampAndWriteVectorImage<UInt8VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_int16:
-    {
-    ret = ClampAndWriteVectorImage< TInput , Int16VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_int16:
+    ClampAndWriteVectorImage<Int16VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_uint16:
-    {
-    ret = ClampAndWriteVectorImage< TInput , UInt16VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_uint16:
+    ClampAndWriteVectorImage<UInt16VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_int32:
-    {
-    ret = ClampAndWriteVectorImage< TInput , Int32VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_int32:
+
+    ClampAndWriteVectorImage<Int32VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_uint32:
-    {
-    ret = ClampAndWriteVectorImage< TInput , UInt32VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_uint32:
+    ClampAndWriteVectorImage<UInt32VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_float:
-    {
-    ret = ClampAndWriteVectorImage< TInput , FloatVectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_float:
+    ClampAndWriteVectorImage<FloatVectorImageType>(image);
     break;
-    }
-    case ImagePixelType_double:
-    {
-    ret = ClampAndWriteVectorImage< TInput , DoubleVectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
+
+  case ImagePixelType_double:
+    ClampAndWriteVectorImage<DoubleVectorImageType>(image);
     break;
-    }
-    case ImagePixelType_cint16:
-    {
-    ret = ClampAndWriteVectorImage < TInput , ComplexInt16VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue ); 
+
+  case ImagePixelType_cint16:
+    ClampAndWriteVectorImage<ComplexInt16VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_cint32:
-    {
-    ret = ClampAndWriteVectorImage < TInput , ComplexInt32VectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue ); 
+
+  case ImagePixelType_cint32:
+    ClampAndWriteVectorImage<ComplexInt32VectorImageType>(image);
     break;
-    }
-    case ImagePixelType_cfloat:
-    {
-    ret = ClampAndWriteVectorImage < TInput , ComplexFloatVectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue ); 
+
+  case ImagePixelType_cfloat:
+    ClampAndWriteVectorImage<ComplexFloatVectorImageType>(image);
     break;
-    }
+
     case ImagePixelType_cdouble:
-    {
-    ret = ClampAndWriteVectorImage < TInput , ComplexDoubleVectorImageType > (
-      img ,
-      m_FileName ,
-      m_RAMValue );
-    break;
-    }
+      ClampAndWriteVectorImage<ComplexDoubleVectorImageType>(image);
+      break;
+
     default:
+      assert(false && "Unexpected image-type.");
       break;
     }
-  // Save the caster and writer
-  m_Caster = ret.first;
-  m_Writer = ret.second;
-  return 1;
 }
 
+
 void
 OutputImageParameter::Write()
 {
   m_Writer->Update();
 
   // Clean internal filters
-  m_Caster = nullptr;
+  m_InputCaster  = nullptr;
+  m_OutputCaster = nullptr;
+
   m_Writer = nullptr;
 }
 
@@ -444,11 +398,9 @@ OutputImageParameter::SetValue(ImageBaseType* image)
   SetActive(true);
 }
 
-bool
-OutputImageParameter::HasValue() const
+bool OutputImageParameter ::HasValue() const
 {
-  std::string filename(this->GetFileName());
-  return !filename.empty();
+  return !m_FileName.empty();
 }
 
 std::string
@@ -493,43 +445,38 @@ OutputImageParameter::CheckFileName(bool fixMissingExtension)
 }
 
 // Specialization for UInt8RGBAImageType
+
 template <>
-int
-OutputImageParameter::SwitchInput(UInt8RGBAImageType *img)
+void OutputImageParameter ::SwitchInput(UInt8RGBAImageType* img)
 {
-  if (! img) return 0;
-  if( m_PixelType == ImagePixelType_uint8 )
-    {
-    typename otb::ImageFileWriter<UInt8RGBAImageType>::Pointer writer =
-      otb::ImageFileWriter<UInt8RGBAImageType>::New();
-    writer->SetFileName( this->GetFileName() );
-    writer->SetInput(img);
-    writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
-    m_Writer = writer.GetPointer();
-    }
-   else
-     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");
-  return 1;
+  assert(img);
+
+  if (m_PixelType != ImagePixelType_uint8)
+    itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");
+
+  auto writer = otb::ImageFileWriter<UInt8RGBAImageType>::New();
+
+  writer->SetFileName(GetFileName());
+  writer->SetInput(img);
+  writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
+
+  m_Writer = writer;
 }
 
 // Specialization for UInt8RGBImageType
 template <>
-int
-OutputImageParameter::SwitchInput(UInt8RGBImageType *img)
+void OutputImageParameter ::SwitchInput(UInt8RGBImageType* img)
 {
-  if (! img) return 0;
-  if( m_PixelType == ImagePixelType_uint8 )
-    {
-    typename otb::ImageFileWriter<UInt8RGBImageType>::Pointer writer =
-      otb::ImageFileWriter<UInt8RGBImageType>::New();
-    writer->SetFileName( this->GetFileName() );
-    writer->SetInput(img);
-    writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
-    m_Writer = writer.GetPointer();
-    }
-   else
-     itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");
-  return 1;
+  if (m_PixelType != ImagePixelType_uint8)
+    itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");
+
+  auto writer = otb::ImageFileWriter<UInt8RGBImageType>::New();
+
+  writer->SetFileName(GetFileName());
+  writer->SetInput(img);
+  writer->GetStreamingManager()->SetDefaultRAM(m_RAMValue);
+
+  m_Writer = writer;
 }
 
 void OutputImageParameter::SetFileName (const char* filename)
diff --git a/SuperBuild/CI/configure_options.cmake b/SuperBuild/CI/configure_options.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..7b1b1e2e9deb0e7d7780b43edd31425f8c1be895
--- /dev/null
+++ b/SuperBuild/CI/configure_options.cmake
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2005-2019 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.
+#
+# For know OTB_DEPENDS is build with default value
+
+set ( cmake_configure_option
+"CMAKE_BUILD_TYPE=${CTEST_BUILD_CONFIGURATION}
+CMAKE_INSTALL_PREFIX:PATH=${CTEST_INSTALL_DIRECTORY}")
+
+set ( temporary_option
+"OTB_USE_LIBKML=OFF
+OTB_USE_MPI=OFF")
+
+set(concat_options
+"${cmake_configure_option}
+${temporary_option}
+")
+
+#Transform the previous string in list
+string (REPLACE "\n" ";" sb_options ${concat_options})
+
+foreach(item ${sb_options})
+  set( SB_CONFIGURE_OPTIONS "${SB_CONFIGURE_OPTIONS}-D${item};")
+endforeach(item)
diff --git a/SuperBuild/CMakeLists.txt b/SuperBuild/CMakeLists.txt
index a4d361d3aecbe6c35fd496837d27b1db35070653..27f42a751b0c8966d6775369645e9c39a43b6b80 100644
--- a/SuperBuild/CMakeLists.txt
+++ b/SuperBuild/CMakeLists.txt
@@ -18,6 +18,8 @@
 # limitations under the License.
 #
 
+## COMMMENT to dirty superbuild artifact. TAG: 1.
+
 cmake_minimum_required(VERSION 3.3.0)
 
 project(OTB-SuperBuild)