diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 25c72acc11ed237b4b04cfe55956b2a6e3354117..766ffcb44eaa7ccb634c8bb3148b2c71e9a5796d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -351,43 +351,43 @@ ubuntu-xdk-report:
     - job: ubuntu-xdk-qa-static-analysis
       artifacts: true
 
-#------------------------- Conda packages jobs ---------------------------------
-conda-linux-build:
-  extends: .common
-  stage: build
-  only:
-    - nightly
-    - /^release-[0-9]+\.[0-9]+$/@orfeotoolbox/otb
-  image: $BUILD_IMAGE_REGISTRY/otb-conda-build:latest
-  allow_failure: true
-  script:
-    - export otb_tag=${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
-    - ./CI/conda_build.sh
-  after_script: []
-  needs:
-    - job: fast-build
-      artifacts: false
-  artifacts:
-    when: always
-    expire_in: 24 hrs
-    paths:
-      - conda-bld/*
+# #------------------------- Conda packages jobs ---------------------------------
+# conda-linux-build:
+#   extends: .common
+#   stage: build
+#   only:
+#     - nightly
+#     - /^release-[0-9]+\.[0-9]+$/@orfeotoolbox/otb
+#   image: $BUILD_IMAGE_REGISTRY/otb-conda-build:latest
+#   allow_failure: true
+#   script:
+#     - export otb_tag=${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}
+#     - ./CI/conda_build.sh
+#   after_script: []
+#   needs:
+#     - job: fast-build
+#       artifacts: false
+#   artifacts:
+#     when: always
+#     expire_in: 24 hrs
+#     paths:
+#       - conda-bld/*
 
-conda-linux-deploy:
-  extends: .general
-  stage: deploy
-  only:
-    - /^release-[0-9]+\.[0-9]+$/@orfeotoolbox/otb
-  image: $BUILD_IMAGE_REGISTRY/otb-conda-build:latest
-  before_script:
-    # Provision efficiently the local LFS cache before checkout
-    - git lfs fetch origin $CI_COMMIT_SHA
-    - git checkout -f -q $CI_COMMIT_SHA
-  script:
-    - ./CI/conda_deploy.sh
-  needs:
-    - job: conda-linux-build
-      artifacts: yes
+# conda-linux-deploy:
+#   extends: .general
+#   stage: deploy
+#   only:
+#     - /^release-[0-9]+\.[0-9]+$/@orfeotoolbox/otb
+#   image: $BUILD_IMAGE_REGISTRY/otb-conda-build:latest
+#   before_script:
+#     # Provision efficiently the local LFS cache before checkout
+#     - git lfs fetch origin $CI_COMMIT_SHA
+#     - git checkout -f -q $CI_COMMIT_SHA
+#   script:
+#     - ./CI/conda_deploy.sh
+#   needs:
+#     - job: conda-linux-build
+#       artifacts: yes
 
 #---------------------------- Deploy job ---------------------------------------
 deploy:
diff --git a/.gitlab/issue_templates/documentation_changes.md b/.gitlab/issue_templates/documentation_changes.md
index d7189ba97f930404138940cb9d9bef4dcf7a963d..516ab7ab946eea7fc908ed9154390b6b2706b7fc 100644
--- a/.gitlab/issue_templates/documentation_changes.md
+++ b/.gitlab/issue_templates/documentation_changes.md
@@ -5,3 +5,5 @@ Can be a combination of CookBook, doxygen, blog, applications doc, websites
 ### Change requested
 
 Describe precisely the changes that are required.
+
+/label ~documentation 
diff --git a/.gitlab/issue_templates/release.md b/.gitlab/issue_templates/release.md
index fce450b8453dea9babc99fb33f604ed9faa10f89..7bf07303f9b8ae81e7ff0d17707916b7df7f70aa 100644
--- a/.gitlab/issue_templates/release.md
+++ b/.gitlab/issue_templates/release.md
@@ -1,5 +1,7 @@
 We are ready to release OTB version MAJOR.MINOR.PATCH. The following steps need to be done:
 
+## Release Candidate
+
 ### 1. Branches
 
 * [ ] **(if major or minor release)** Feature freeze: [create the new release branch](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#create-release-branch)
@@ -8,21 +10,58 @@ We are ready to release OTB version MAJOR.MINOR.PATCH. The following steps need
 
 ### 2. Housekeeping
 * [ ] In this story, make a list of blocking issues for the release (if any)
-* [ ] [Update the SuperBuild archive](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#superbuild-archive) (if needed)
 * [ ] Update release notes (walk the GitLab MR merged history and log all improvements)
 * [ ] Update the date in RELEASE_NOTES.txt
+* [ ] Check [SonarQube](https://sonar.orfeo-toolbox.org/dashboard?id=orfeotoolbox-otb)
+* [ ] Run Debian [spelling](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#spelling-check) checker
+* [ ] Run shellcheck script from [OTB-Devutils/Scripts/](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb-devutils/blob/master/Scripts/run_shellcheck.sh)
+* [ ] [Update translation](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#translation-for-monteverdi-mapla) for Monteverdi and Mapla
+* [ ] [Sanity check the binary packages](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#standalone-packages-sanity-check)
+    * [ ] Windows
+    * [ ] Linux
+    * [ ] Mac
+    * [ ] Test QGIS on qgis docker image
+
+### 3. Actual release
+
+Once all blocking issues are closed, and the previous steps are done:
+* [ ] [Tag the release candidate](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#release-tag)
+* [ ] Update GIT_TAG for all official remote modules (if needed)
+
+### 4. Publish and plan next release
+* [ ]   [Prepare and upload source packages](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#prepare-and-upload-source-packages)
+* [ ]   [Promote staging packages](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#promote-staging-packages)
+* [ ]   [Update documentation](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#update-documentation)
+    * [ ] Cookbook
+    * [ ] Doxygen
+* [ ] [Update the SuperBuild archive](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#superbuild-archive)
+* [ ] Release Candidate announcement on the forum
+
+## Release
+
+### 1. Branches
+
+* [ ] Make sure the version number in `CMakeLists.txt` is MAJOR.MINOR.PATCH
+
+### 2. Housekeeping
+* [ ] In this story, make a list of blocking issues for the release (if any)
+* [ ] Fix compilation warnings on CI
+* [ ] Update release notes (walk the GitLab MR merged history and log all improvements)
+* [ ] Update the date in RELEASE_NOTES.txt
+* [ ] Check [SonarQube](https://sonar.orfeo-toolbox.org/dashboard?id=orfeotoolbox-otb)
 * [ ] Run Debian [spelling](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#spelling-check) checker
 * [ ] Run shellcheck script from [OTB-Devutils/Scripts/](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb-devutils/blob/master/Scripts/run_shellcheck.sh)
 * [ ] [Update translation](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#translation-for-monteverdi-mapla) for Monteverdi and Mapla
 * [ ] [Sanity check the binary packages](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#standalone-packages-sanity-check)
-    * [ ]  Windows
-    * [ ]  Linux
-    * [ ]  Mac
+    * [ ] Windows
+    * [ ] Linux
+    * [ ] Mac
+    * [ ] Test QGIS on qgis docker image
 
 ### 3. Actual release
 
 Once all blocking issues are closed, and the previous steps are done:
-* [ ] [Tag the release or RC](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#release-tag)
+* [ ] [Tag the release](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#release-tag)
 * [ ] **(if major or minor release)**: Merge the release into develop
 * [ ] **(if it's the latest release)**: Merge the release into master
 * [ ] **(if patch release)**: Backport fixes
@@ -36,11 +75,12 @@ Once all blocking issues are closed, and the previous steps are done:
     * [ ] Doxygen
     * [ ] WordPress page "Home" and "Download" pages
 * [ ] Upload OTB source archive to [Zenodo](https://zenodo.org/) to create a unique Digital Object Identifier (DOI)
-* [ ] Send email to mailing list to announce the release
-* [ ] Release announcement on the blog
-* [ ] Announcement on social networks (twitter, google+)
+* [ ] [Update the SuperBuild archive](https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/wikis/Help-for-release-actions#superbuild-archive)
+* [ ] Release announcement
+    * [ ] On the [forum](https://forum.orfeo-toolbox.org/)
+    * [ ] On the [blog](https://www.orfeo-toolbox.org/blog/)
+	* [ ] On [Twitter](https://twitter.com/orfeotoolbox)
 * [ ] Forward announcement to news_item@osgeo.org ([OSGeo news](https://www.osgeo.org/foundation-news/))
-* [ ] Plan the next release (nominate new release manager, setup PSC meeting on IRC)
 * [ ] Remove public branches related to MR or bugfix merged before the release
 
 /label ~story
diff --git a/.mailmap b/.mailmap
index ddb74cbf386ca0365db492ffc9f2739b8e155cca..bd42eb271375706fd84d5da83fa1ec6aac743add 100644
--- a/.mailmap
+++ b/.mailmap
@@ -12,6 +12,7 @@ Aurélie Emilien <aurelie.emilien@c-s.fr>
 Aurélie Emilien <aurelie.emilien@c-s.fr>                  Aurelie Emilien <aurelie.emilien@c-s.fr>
 Bas Couwenberg <sebastic@debian.org>
 Bas Couwenberg <sebastic@debian.org>                      Bas Couwenberg <sebastic@xs4all.nl>
+Brad Hards <bradh@frogmouth.net>
 Carole Amiot <carole.amiot@cnes.fr>
 Carole Amiot <carole.amiot@cnes.fr>                       Carole Amiot <carole.amiot@thales-services.fr>
 Caroline Ruffel <caroline.ruffel@c-s.fr>
@@ -58,7 +59,8 @@ Julien Michel <julien.michel@cnes.fr>                     Julien Michel <julien.
 Julien Osman <julien.osman@csgroup.eu>                    Julien Osman <julien.osman@c-s.fr>
 Laurențiu Nicola <lnicola@dend.ro>                        Laurentiu Nicola <lnicola@dend.ro>
 Laurențiu Nicola <lnicola@dend.ro>                        Laurențiu Nicola <grayshade@gmail.com>
-Luc Hermitte <luc.hermitte@c-s.fr>                        Luc Hermitte <luc.hermitte@cnes.fr>
+Luc Hermitte <luc.hermitte@csgroup.eu>                    Luc Hermitte <luc.hermitte@cnes.fr>
+Luc Hermitte <luc.hermitte@csgroup.eu>                    Luc Hermitte <luc.hermitte@c-s.fr>
 Ludovic Hussonnois <ludovic.hussonnois@c-s.fr>
 Manuel Grizonnet <manuel.grizonnet@cnes.fr>
 Manuel Grizonnet <manuel.grizonnet@cnes.fr>               Grizonnet Manuel <manuel.grizonnet@cnes.fr>
diff --git a/CI/configure_options.cmake b/CI/configure_options.cmake
index 25a271891b89603e51890ff0530f7c49369d9d9c..2f10ee0e995d0e8fe4e6a8430ee96701fef5c849 100644
--- a/CI/configure_options.cmake
+++ b/CI/configure_options.cmake
@@ -70,7 +70,7 @@ if(XDK_PATH)
 set(cmake_configure_option
 "${cmake_configure_option}
 CMAKE_PREFIX_PATH=${XDK_PATH}")
-foreach(remote_module OTBTemporalGapFilling SertitObject otbGRM DiapOTBModule)
+foreach(remote_module OTBTemporalGapFilling SertitObject otbGRM DiapOTBModule S1TilingSupportApplications)
   set(cmake_configure_option
 "${cmake_configure_option}
 Module_${remote_module}:BOOL=ON")
diff --git a/CMake/GetVersionFromGitTag.cmake b/CMake/GetVersionFromGitTag.cmake
index 331635c2bdacd5c0661082a7e23ace31371c9db0..0b6c5804d2456184a6b5ea34c85f89277c8fffae 100644
--- a/CMake/GetVersionFromGitTag.cmake
+++ b/CMake/GetVersionFromGitTag.cmake
@@ -1,3 +1,26 @@
+#
+# Copyright (C) 2005-2020 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 cmake module is based on a module written by Nuno Fachada, below is the
+# original header of the module:
+
 #
 # This cmake module sets the project version and partial version
 # variables by analysing the git tag and commit history. It expects git
@@ -32,7 +55,7 @@
 # Author: Nuno Fachada
 
 
-function(get_package_name root_repo_dir project_version_string)
+function(get_package_name root_repo_dir project project_version_string)
   
   if(EXISTS "${root_repo_dir}/.git")  
     find_package(Git)
@@ -40,12 +63,6 @@ function(get_package_name root_repo_dir project_version_string)
       message(ERROR "git not found. Make sure git can be found in your PATH")
       return()
     endif()
-    
-    message(STATUS "PROJECT_NAME: ${PROJECT_NAME}")
-    message(STATUS "VERSION MINOR: ${${PROJECT_NAME}_VERSION_MAJOR}")
-    message(STATUS "VERSION MAJOR: ${${PROJECT_NAME}_VERSION_MINOR}")
-    message(STATUS "VERSION PATCH: ${${PROJECT_NAME}_VERSION_PATCH}")
-
 
     if(DEFINED ENV{CI_COMMIT_REF_NAME})
       set(branch_name "$ENV{CI_COMMIT_REF_NAME}")
@@ -65,7 +82,7 @@ function(get_package_name root_repo_dir project_version_string)
 
     if("${branch_name}" MATCHES "^release-[0-9]+\\.[0-9]+\$")
 
-      set(${project_version_string} "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}" PARENT_SCOPE)
+      set(${project_version_string} "${${project}_VERSION_MAJOR}.${${project}_VERSION_MINOR}.${${project}_VERSION_PATCH}" PARENT_SCOPE)
 
     else()
       if(DEFINED ENV{CI_COMMIT_SHORT_SHA})
@@ -73,9 +90,9 @@ function(get_package_name root_repo_dir project_version_string)
       else()
         execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
           WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-          OUTPUT_VARIABLE ${PROJECT_NAME}_COMMIT_SHA_STRING
+          OUTPUT_VARIABLE ${project}_COMMIT_SHA_STRING
           OUTPUT_STRIP_TRAILING_WHITESPACE)
-        set(${project_version_string} "${branch_name}-${${PROJECT_NAME}_COMMIT_SHA_STRING}" PARENT_SCOPE)
+        set(${project_version_string} "${branch_name}-${${project}_COMMIT_SHA_STRING}" PARENT_SCOPE)
       endif()
 
     endif()
@@ -99,7 +116,7 @@ function(get_package_name root_repo_dir project_version_string)
     
     message(STATUS "M: ${_VERSION_MAJOR}, m: ${_VERSION_MINOR}, p: ${_VERSION_PATCH}")
 
-	  set(${project_version_string} "${PROJECT_VERSION_STRING}" PARENT_SCOPE)
+    set(${project_version_string} "${PROJECT_VERSION_STRING}" PARENT_SCOPE)
     
   endif()
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8df73beca3627a8fca350c2c0e1d672dd271a38..a47074959c402d9f1b0592c82b45618b256017b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,14 +133,11 @@ set(main_project_name ${_OTBModuleMacros_DEFAULT_LABEL})
 #-----------------------------------------------------------------------------
 # OTB version number.
 set(OTB_VERSION_MAJOR "7")
-set(OTB_VERSION_MINOR "1")
+set(OTB_VERSION_MINOR "2")
 set(OTB_VERSION_PATCH "0")
 set(OTB_VERSION_STRING "${OTB_VERSION_MAJOR}.${OTB_VERSION_MINOR}.${OTB_VERSION_PATCH}")
 
-get_package_name(${OTB_SOURCE_DIR} OTB_VERSION_STRING2)
-
-message(STATUS "## ${OTB_VERSION_STRING2} ##")
-
+get_package_name(${OTB_SOURCE_DIR} ${PROJECT_NAME} OTB_VERSION_STRING2)
 
 # Monteverdi version number (follows OTB)
 set( Monteverdi_VERSION_MAJOR ${OTB_VERSION_MAJOR} )
diff --git a/Data/Baseline/OTB-Applications/Images/ResetMarginBaseline100x100.tiff b/Data/Baseline/OTB-Applications/Images/ResetMarginBaseline100x100.tiff
new file mode 100644
index 0000000000000000000000000000000000000000..d687d442d20c144ca775fc32122e54b49b28cb8e
--- /dev/null
+++ b/Data/Baseline/OTB-Applications/Images/ResetMarginBaseline100x100.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2c8358d04f4d40cdbf08c836bba4ff725c7f8d1d0daeef8c2d336090a240c928
+size 33041
diff --git a/Data/Baseline/OTB-Applications/Images/s1a_33NWB_vv_DES_007_20200108txxxxxx_100x100.tif b/Data/Baseline/OTB-Applications/Images/s1a_33NWB_vv_DES_007_20200108txxxxxx_100x100.tif
new file mode 100644
index 0000000000000000000000000000000000000000..59d9650a2bcb8118befd5086d260404eb043aa20
--- /dev/null
+++ b/Data/Baseline/OTB-Applications/Images/s1a_33NWB_vv_DES_007_20200108txxxxxx_100x100.tif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c1b49117a90f751d70f80f1c79975a6a45fbd278d349e2e77844050f641774c5
+size 34870
diff --git a/Data/Baseline/OTB/Images/apTvUtQuicklookWithGCP.1.tif b/Data/Baseline/OTB/Images/apTvUtQuicklookWithGCP.1.tif
new file mode 100644
index 0000000000000000000000000000000000000000..75d4e4f6a4ad8aed07ee9bdd04f8e5cc79e622d9
--- /dev/null
+++ b/Data/Baseline/OTB/Images/apTvUtQuicklookWithGCP.1.tif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d4022ef746f67015198c6e43952085ad483ec3608eefb241360a58d241d5c3ed
+size 10375
diff --git a/Data/Input/ResetMarginInput100x100.tiff b/Data/Input/ResetMarginInput100x100.tiff
new file mode 100644
index 0000000000000000000000000000000000000000..ee84e4b93e759fea4c9dcd6d686ca45bf3277231
--- /dev/null
+++ b/Data/Input/ResetMarginInput100x100.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a1354f27b0141d6e7c58fcce825e4f988dc135aeed0a45a051aeb658c6bcf653
+size 50506
diff --git a/Data/Input/s1a_33NWB_vv_DES_007_20200108t044150_100x100.tif b/Data/Input/s1a_33NWB_vv_DES_007_20200108t044150_100x100.tif
new file mode 100644
index 0000000000000000000000000000000000000000..4d4e02c34b593dc88073746cf5beb77a285832c6
--- /dev/null
+++ b/Data/Input/s1a_33NWB_vv_DES_007_20200108t044150_100x100.tif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:99bde32908be865a70b59524ad0ca0e984490a1d46b4675d714e740209dba608
+size 19628
diff --git a/Data/Input/s1a_33NWB_vv_DES_007_20200108t044215_100x100.tif b/Data/Input/s1a_33NWB_vv_DES_007_20200108t044215_100x100.tif
new file mode 100644
index 0000000000000000000000000000000000000000..23e2b6bd7248c933144770a5ce760844430a5365
--- /dev/null
+++ b/Data/Input/s1a_33NWB_vv_DES_007_20200108t044215_100x100.tif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:53a6a9e06b772c692f581117289168b14f077fab863280202a1bc9a9160e6043
+size 16763
diff --git a/Documentation/Cookbook/rst/Monteverdi.rst b/Documentation/Cookbook/rst/Monteverdi.rst
index f2ca1637aadf30fc481bcbcd5c33d53bd5ad5cf5..be875dca7dee320a8895a1167324f1e5f40464cc 100644
--- a/Documentation/Cookbook/rst/Monteverdi.rst
+++ b/Documentation/Cookbook/rst/Monteverdi.rst
@@ -235,7 +235,7 @@ placed exactly at the same position in the screenshots).
 .. _BM:
 .. figure:: Art/MonteverdiImages/BM.png
 
-:numref:`BM`: Comparision of histograms before and after applying BandMath.
+:numref:`BM`: Comparison of histograms before and after applying BandMath.
 
 Segmentation
 ~~~~~~~~~~~~
diff --git a/Modules/Applications/AppImageUtils/app/CMakeLists.txt b/Modules/Applications/AppImageUtils/app/CMakeLists.txt
index 8f2981b694625cefc5396bbdb254da448b500607..626dd520ec9bfb7873c6c763be5c893c02de151a 100644
--- a/Modules/Applications/AppImageUtils/app/CMakeLists.txt
+++ b/Modules/Applications/AppImageUtils/app/CMakeLists.txt
@@ -92,3 +92,13 @@ OTB_CREATE_APPLICATION(
   NAME           Mosaic
   SOURCES        otbMosaic.cxx
   LINK_LIBRARIES ${${otb-module}_LIBRARIES})
+
+OTB_CREATE_APPLICATION(
+  NAME           ResetMargin
+  SOURCES        otbResetMargin.cxx
+  LINK_LIBRARIES ${${otb-module}_LIBRARIES})
+
+OTB_CREATE_APPLICATION(
+  NAME           Synthetize
+  SOURCES        otbSynthetize.cxx
+  LINK_LIBRARIES ${${otb-module}_LIBRARIES})
diff --git a/Modules/Applications/AppImageUtils/app/otbResetMargin.cxx b/Modules/Applications/AppImageUtils/app/otbResetMargin.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b3e7aced605f7974c6d9fff37dfe600912937737
--- /dev/null
+++ b/Modules/Applications/AppImageUtils/app/otbResetMargin.cxx
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005-2020 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 "otbResetMarginFilter.h"
+#include "otbWrapperApplication.h"
+#include "otbWrapperApplicationFactory.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+/**
+ * Application that fills margins to 0.
+ *
+ * This application is similar to ExtractROI with the difference the margin is
+ * kept, and filled with 0.
+ *
+ * This application is used to implement the _cut_ processing in S1Tiling
+ * chain.
+ *
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ */
+class ResetMargin : public Application
+{
+public:
+  using Self    = ResetMargin;
+  using Pointer = itk::SmartPointer<Self>;
+
+  itkNewMacro(Self);
+  itkTypeMacro(ResetMargin, otb::Wrapper::Application);
+
+private:
+  void DoInit() override
+  {
+    SetName("ResetMargin");
+
+    SetDescription("This is the ResetMargin application");
+    SetDocLongDescription(
+        "This application is similar to ExtractROI in the sense it extracts a Region of Interrest.\n"
+        "However, the region outside of the ROI isn't trimmed, but set to 0.\n"
+        "\n"
+        "The filter set lines of index < threshold.y, and of index >= threshold.y to 0\n"
+        "The filter set columns of index < threshold.x, and of index >= threshold.x to 0");
+
+    SetDocLimitations("This application only works on scalar (and complex) images.");
+    SetDocAuthors("Luc Hermitte (CS Group)");
+    SetDocSeeAlso("ManageNoData, ExtractROI");
+    AddDocTag(Tags::Manip);
+
+    AddParameter(ParameterType_InputImage,  "in",   "Input image");
+    SetParameterDescription("in", "Scalar Input image");
+
+    AddParameter(ParameterType_OutputImage, "out", "Output Image");
+    SetParameterDescription("out", "Scalar Output image");
+
+    AddParameter(ParameterType_Group, "threshold", "threshold group");
+    AddParameter(ParameterType_Group, "threshold.y", "threshold group");
+    MandatoryOff("threshold");
+    MandatoryOff("threshold.y");
+    AddParameter(ParameterType_Int, "threshold.x", "Column index threshold");
+    SetParameterDescription("threshold.x", "Column index threshold");
+    SetDefaultParameterInt("threshold.x", 0);
+
+    AddParameter(ParameterType_Int, "threshold.y.start", "Top line index threshold");
+    SetParameterDescription("threshold.y.start", "Top line index threshold");
+    SetDefaultParameterInt("threshold.y.start", 0);
+
+    AddParameter(ParameterType_Int, "threshold.y.end", "Bottom line index threshold");
+    SetParameterDescription("threshold.y.end", "Bottom line index threshold");
+    SetDefaultParameterInt("threshold.y.end", 0);
+
+    SetMinimumParameterIntValue("threshold.x",       0);
+    SetMinimumParameterIntValue("threshold.y.start", 0);
+    SetMinimumParameterIntValue("threshold.y.end",   0);
+
+    AddRAMParameter();
+
+    SetDocExampleParameterValue("in", "ResetMarginInput100x100.tiff");
+    SetDocExampleParameterValue("threshold.x",       "10");
+    SetDocExampleParameterValue("threshold.y.start", "12");
+    SetDocExampleParameterValue("threshold.y.end",    "25");
+    SetDocExampleParameterValue("out", "ResetMargin.tiff");
+    SetOfficialDocLink();
+  }
+
+  void DoUpdateParameters() override
+  {}
+
+  void DoExecute() override
+  {
+    auto const thrX = GetParameterInt("threshold.x");
+    auto const thrYtop = GetParameterInt("threshold.y.start");
+    auto const thrYbot = GetParameterInt("threshold.y.end");
+    if (thrX < 0)
+      itkExceptionMacro("The column threshold is expected to be positive");
+    if (thrYtop < 0)
+      itkExceptionMacro("The top line threshold is expected to be positive");
+    if (thrYbot < 0)
+      itkExceptionMacro("The bottom line threshold is expected to be positive");
+    if (thrX == 0 && thrYtop == 0 && thrYbot == 0)
+      itkExceptionMacro("Don't use ResetMargin to clamp nothing!");
+
+    auto filter = ResetMarginFilter<FloatImageType>::New();
+    assert(thrX >= 0);
+    assert(thrYtop >= 0);
+    assert(thrYbot >= 0);
+    filter->SetThresholdX(thrX);
+    filter->SetThresholdYtop(thrYtop);
+    filter->SetThresholdYbot(thrYbot);
+    filter->SetInput(GetParameterFloatImage("in"));
+
+    SetParameterOutputImage("out", filter->GetOutput());
+    RegisterPipeline();
+  }
+
+};
+
+} // otb::Wrapper namespace
+} // otb namespace
+
+OTB_APPLICATION_EXPORT(otb::Wrapper::ResetMargin)
diff --git a/Modules/Applications/AppImageUtils/app/otbSynthetize.cxx b/Modules/Applications/AppImageUtils/app/otbSynthetize.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..027a70908b176daf768a629215c7bdc17a465655
--- /dev/null
+++ b/Modules/Applications/AppImageUtils/app/otbSynthetize.cxx
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005-2020 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 "otbSynthetizeFilter.h"
+#include "otbWrapperApplication.h"
+#include "otbWrapperApplicationFactory.h"
+#include "otbImageFileReader.h"
+#include <set>
+
+namespace otb
+{
+namespace Wrapper
+{
+
+/**
+ * This application synthetizes/reduces multiple inputs into a single one.
+ * In that particular case, for each output pixel, this application will
+ * consider the corresponding pixels from all the input images, and keep the
+ * first one that isn't equal to 0.
+ *
+ * This application is used to implement the _concatenate_ processing in
+ * S1Tiling chain.
+ *
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \todo find a better name for the application. Alas `otbConcatenate` is
+ * already used...
+ */
+class Synthetize : public Application
+{
+public:
+  using Self    = Synthetize;
+  using Pointer = itk::SmartPointer<Self>;
+
+  itkNewMacro(Self);
+  itkTypeMacro(Synthetize, otb::Wrapper::Application);
+
+private:
+  using ReaderType = otb::ImageFileReader<FloatImageType>;
+
+  void DoInit() override
+  {
+    SetName("Synthetize");
+
+    SetDescription("This is the Synthetize application");
+    SetDocLongDescription("Concatenate a list of images of the same size into a single single-channel image.\n\
+        It keeps the first non-null pixel value found in the input list.");
+
+    SetDocLimitations("This application will break incoming pipelines.");
+    SetDocAuthors("Luc Hermitte (CS Group)");
+    SetDocSeeAlso("");
+    AddDocTag(Tags::Manip);
+
+    AddParameter(ParameterType_StringList,  "il",  "Input images list");
+    SetParameterDescription("il", "Input image list");
+
+    AddParameter(ParameterType_OutputImage, "out", "Output Image");
+    SetParameterDescription("out","Output image.");
+
+    AddRAMParameter();
+
+    SetDocExampleParameterValue("il", "s1a_33NWB_vv_DES_007_20200108t044150.tif s1a_33NWB_vv_DES_007_20200108t044215.tif");
+    SetDocExampleParameterValue("out", "s1a_33NWB_vv_DES_007_20200108txxxxxx.tif");
+    SetOfficialDocLink();
+  }
+
+  void DoUpdateParameters() override
+  {}
+
+  void DoExecute() override
+  {
+    // Get the input image list
+    auto inNameList = GetParameterStringList("il");
+
+    // checking the input images list validity
+    auto const nbImages = inNameList.size();
+
+    if (nbImages == 0)
+    {
+      itkExceptionMacro("No input Image set...; please set at least one input image");
+    }
+
+    auto functor = [](auto input) {
+      assert(!input.empty());
+      auto const wh = std::find_if(
+          input.begin(), input.end()-1,
+          [](auto v){ return v != 0;});
+      return *wh;
+    };
+    auto filter = MakeSynthetizeFilter<FloatImageType, FloatImageType>(functor);
+
+    for (unsigned int i = 0; i < nbImages; i++)
+    {
+      // Given the explicit use of a Reader, this application cannot be used in
+      // a in-memory pipeline
+      auto reader = ReaderType::New();
+      // currentImage->SetExtendedFileName(inNameList[i]);
+      reader->SetFileName(inNameList[i]);
+      auto currentImage = reader->GetOutput();
+      currentImage->UpdateOutputInformation();
+
+      otbAppLogINFO(<< "Image #" << i + 1 << " has " << currentImage->GetNumberOfComponentsPerPixel() << " components");
+
+      filter->SetInput(i, currentImage);
+      m_Cache.insert(reader);
+    }
+
+    SetParameterOutputImage("out", filter->GetOutput());
+    RegisterPipeline(); // TODO: check!!
+  }
+
+  // Needed to register the inputs handled manually
+  // and not with a VectorImageList through GetParameterImageList
+  std::set<ReaderType::Pointer> m_Cache;
+};
+
+} // otb::Wrapper namespace
+} // otb namespace
+
+OTB_APPLICATION_EXPORT(otb::Wrapper::Synthetize)
diff --git a/Modules/Applications/AppImageUtils/test/CMakeLists.txt b/Modules/Applications/AppImageUtils/test/CMakeLists.txt
index 350b31b3df4c05aaa499ac0625e17ab3972729e0..6ad99ac2c011201cae2f6084b744f41ab64e4af7 100644
--- a/Modules/Applications/AppImageUtils/test/CMakeLists.txt
+++ b/Modules/Applications/AppImageUtils/test/CMakeLists.txt
@@ -120,6 +120,18 @@ otb_test_application(NAME apTvUtExtractROIExtentFitVect
                              ${OTBAPP_BASELINE}/apTvUtExtractROI.tif
                              ${TEMP}/apTvUtExtractROIExtentFitVect.tif)
 
+#----------- Clamp ROI tests  ----------------
+otb_test_application(NAME apTvUtResetMargin
+                     APP  ResetMargin
+                     OPTIONS -in ${INPUTDATA}/ResetMarginInput100x100.tiff
+                             -out ${TEMP}/apTvUtResetMargin.tif
+                             -threshold.x       10
+                             -threshold.y.start 12
+                             -threshold.y.end   25
+                     VALID   --compare-image ${NOTOL}
+                             ${OTBAPP_BASELINE}/ResetMarginBaseline100x100.tiff
+                             ${TEMP}/apTvUtResetMargin.tif)
+
 #----------- Rescale TESTS ----------------
 otb_test_application(NAME  apTvUtRescaleTest
                      APP  Rescale
@@ -203,6 +215,11 @@ otb_test_application(NAME apTvUtQuicklookROI1Channel
                              ${TEMP}/apTvUtQuicklookROI1Channel.tif
                      )
 
+# this tests has two baseline to take into account the bug described in
+# https://github.com/opengeospatial/ogc_api_coverages/issues/92
+# (half pixel shift applied in the wrong direction to GCPs with the PixelIsPoint convention)
+# The first baseline corresponds to the gdal < 3.1.3 case, 
+# and the second baseline correspond to gdal >= 3.1.3 case.
 otb_test_application(NAME apTvUtQuicklookWithGCP
                      APP Quicklook
                      OPTIONS -in ${INPUTDATA}/spot5SubWithGcps.tif
@@ -252,6 +269,16 @@ otb_test_application(NAME apTvUtConcatenateImages_1Image
                              ${TEMP}/apTvUtConcatenateImages_1Image.tif)
 
 
+#----------- Synthetize TESTS ----------------
+otb_test_application(NAME apTvUtSynthetize
+                     APP  Synthetize
+                     OPTIONS -il ${INPUTDATA}/s1a_33NWB_vv_DES_007_20200108t044150_100x100.tif
+                                 ${INPUTDATA}/s1a_33NWB_vv_DES_007_20200108t044215_100x100.tif
+                             -out ${TEMP}/apTvUtSynthetize.tif
+                     VALID   --compare-image ${NOTOL}
+                             ${OTBAPP_BASELINE}/s1a_33NWB_vv_DES_007_20200108txxxxxx_100x100.tif
+                             ${TEMP}/apTvUtSynthetize.tif)
+
 #----------- MultiResolutionPyramid TESTS ----------------
 
 #----------- PixelValue TESTS ----------------
@@ -443,8 +470,8 @@ otb_test_application(NAME apTvUtSplitImage
 #----------- Mosaic TESTS ----------------
 otb_test_application(NAME MosaicTestLargeFeathering
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestLargeFeathering.tif uint8 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestLargeFeathering.tif uint8
                              -comp.feather large
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestLargeFeathering.tif
@@ -453,9 +480,9 @@ otb_test_application(NAME MosaicTestLargeFeathering
 
 otb_test_application(NAME MosaicTestSlimFeathering
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestSlimFeathering.tif uint8 
-                             -comp.feather slim 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestSlimFeathering.tif uint8
+                             -comp.feather slim
                              -comp.feather.slim.length 100
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestSlimFeathering.tif
@@ -464,9 +491,9 @@ otb_test_application(NAME MosaicTestSlimFeathering
 
 otb_test_application(NAME MosaicTestSimpleWithHarmoBandRmse
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestSimpleWithHarmoBandRmse.tif uint8 
-                             -harmo.method band 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestSimpleWithHarmoBandRmse.tif uint8
+                             -harmo.method band
                              -harmo.cost rmse
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestSimpleWithHarmoBandRmse.tif
@@ -474,9 +501,9 @@ otb_test_application(NAME MosaicTestSimpleWithHarmoBandRmse
 
 otb_test_application(NAME MosaicTestSimpleWithHarmoRgbRmse
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestSimpleWithHarmoRgbRmse.tif uint8 
-                             -harmo.method rgb 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestSimpleWithHarmoRgbRmse.tif uint8
+                             -harmo.method rgb
                              -harmo.cost rmse
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestSimpleWithHarmoRgbRmse.tif
@@ -484,18 +511,18 @@ otb_test_application(NAME MosaicTestSimpleWithHarmoRgbRmse
 
 otb_test_application(NAME MosaicTestSimpleWithCutline
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestSimpleWithCutline.tif uint8 
-                             -vdcut ${INPUTDATA}/SP67_FR_subset_1_cutline.shp ${INPUTDATA}/SP67_FR_subset_2_cutline.shp 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestSimpleWithCutline.tif uint8
+                             -vdcut ${INPUTDATA}/SP67_FR_subset_1_cutline.shp ${INPUTDATA}/SP67_FR_subset_2_cutline.shp
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestSimpleWithCutline.tif
                              ${TEMP}/apTvMosaicTestSimpleWithCutline.tif)
 
 otb_test_application(NAME MosaicTestSimpleWithVdstats
                      APP  Mosaic
-                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif 
-                             -out ${TEMP}/apTvMosaicTestSimpleWithVdstats.tif uint8 
-                             -vdstats ${INPUTDATA}/SP67_FR_subset_1_cutline.shp ${INPUTDATA}/SP67_FR_subset_2_cutline.shp 
+                     OPTIONS -il ${INPUTDATA}/SP67_FR_subset_1.tif ${INPUTDATA}/SP67_FR_subset_2.tif
+                             -out ${TEMP}/apTvMosaicTestSimpleWithVdstats.tif uint8
+                             -vdstats ${INPUTDATA}/SP67_FR_subset_1_cutline.shp ${INPUTDATA}/SP67_FR_subset_2_cutline.shp
                      VALID   --compare-image ${EPSILON_8}
                              ${BASELINE}/apTvMosaicTestSimpleWithVdstats.tif
                              ${TEMP}/apTvMosaicTestSimpleWithVdstats.tif)
diff --git a/Modules/Applications/AppTextures/app/otbPantexTextureExtraction.cxx b/Modules/Applications/AppTextures/app/otbPantexTextureExtraction.cxx
index 9da40763cb4f34e7f71544562cd9379a8e60e85f..692a02b7ca66dc5f1918bca7fd6995c17d4657c8 100644
--- a/Modules/Applications/AppTextures/app/otbPantexTextureExtraction.cxx
+++ b/Modules/Applications/AppTextures/app/otbPantexTextureExtraction.cxx
@@ -89,7 +89,7 @@ private:
 
     AddParameter(ParameterType_Float, "min", "Image minimum");
     SetParameterDescription("min", "Input image minimum. If this parameter is not set, the application will compute "
-                            "the minumum of the image.");
+                            "the minimum of the image.");
     MandatoryOff("min");
 
     AddParameter(ParameterType_Float, "max", "Image maximum");
diff --git a/Modules/Core/Common/include/otbInterval.h b/Modules/Core/Common/include/otbInterval.h
new file mode 100644
index 0000000000000000000000000000000000000000..f37c2c04343ec95cdf73b81079ddebcc981730dc
--- /dev/null
+++ b/Modules/Core/Common/include/otbInterval.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005-2020 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 otbInterval_h
+#define otbInterval_h
+
+#include "itkIntTypes.h"
+#include <algorithm>
+#include <cassert>
+#include <ostream>
+
+namespace otb
+{
+/** Simplified index interval.
+ * Inspired by `boost::numeric::interval`.
+ *
+ * \invariant Can be empty.
+ * \invariant lower <= upper
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+class Interval
+{
+public:
+  using IndexType = itk::IndexValueType;
+  using SizeType  = itk::SizeValueType;
+
+  /** Init constructor from the pair of its extremities. */
+  constexpr Interval(IndexType l, IndexType u) noexcept
+    : m_lower(l), m_upper(u)
+    {
+#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
+      assert(l <= u);
+#endif
+    }
+
+  /** Alternate factory function from a position and a length. */
+  static constexpr Interval OfLength(IndexType low, SizeType len) noexcept{
+    return Interval{low, IndexType(low+len)};
+  }
+
+  constexpr SizeType size() const noexcept
+  { return m_upper - m_lower; }
+
+  constexpr bool empty() const noexcept
+  { return m_lower == m_upper; }
+
+  constexpr IndexType lower() const noexcept
+  { return m_lower; }
+
+  constexpr IndexType upper() const noexcept
+  { return m_upper; }
+
+  /** Computes the intersection between two interals.
+   * @return their intersection
+   * @return {0,0} if theyr don't intersect.
+   *
+   * @note this function is an hidden friend
+   */
+  friend constexpr Interval intersect(
+      Interval const& lhs, Interval const& rhs) noexcept
+  {
+#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
+    auto const low = std::max(lhs.lower(), rhs.lower());
+    auto const upp = std::min(lhs.upper(), rhs.upper());
+
+    return low <= upp ? Interval{low, upp} : Interval{0,0};
+#else
+    // MSVC version supported is not C++14 compliant
+    return std::max(lhs.lower(), rhs.lower()) <= std::min(lhs.upper(), rhs.upper())
+      ? Interval{std::max(lhs.lower(), rhs.lower()), std::min(lhs.upper(), rhs.upper())}
+      : Interval{0,0};
+#endif
+  }
+
+  /** Stream inserter for intervals.
+   * @note this function is an hidden friend
+   */
+  friend std::ostream & operator<<(std::ostream & os, Interval const& v)
+  {
+    return os << '[' << v.lower() << ".." << v.upper() << '[';
+  }
+
+private:
+  IndexType m_lower;
+  IndexType m_upper;
+};
+} // otb namespace
+
+#endif  // otbInterval_h
diff --git a/Modules/Core/Common/include/otbLogHelpers.h b/Modules/Core/Common/include/otbLogHelpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..f205a69355f5a61e6bee762ff66f41dc71eaaaa2
--- /dev/null
+++ b/Modules/Core/Common/include/otbLogHelpers.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005-2020 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 otbLogHelpers_h
+#define otbLogHelpers_h
+
+#include "itkImageRegion.h"
+#include <ostream>
+
+namespace otb
+{
+
+/** Helper class to log region in a more human readable way:
+ * e.g.
+ * \code
+ x ∈ [0..42[, y ∈ [12..24[, size=42x12 @(0, 12)
+ * \endcode
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+struct NeatRegionLogger
+{
+  using RegionType = itk::ImageRegion<2u>;
+  NeatRegionLogger(RegionType const& region) : m_region(region) {}
+
+  friend std::ostream & operator<<(std::ostream & os, NeatRegionLogger const& r)
+  {
+    auto const& size = r.m_region.GetSize();
+    auto const& idx  = r.m_region.GetIndex();
+    auto const  idx_x1  = idx[0];
+    int  const  idx_x2  = idx[0] + size[0];
+    int  const  idx_y1  = idx[1];
+    auto const  idx_y2  = idx[1] + size[1];
+    os
+      << "x ∈ ["<<idx_x1 << ".." << idx_x2 << '['
+      << ", y ∈ ["<<idx_y1 << ".." << idx_y2 << '['
+      << ", size=" << size[0]<<'x'<<size[1] << " @("<<idx_x1<<", "<<idx_y1<<')'
+      ;
+    return os ;
+  }
+  RegionType const& m_region;
+};
+} // otb namespace
+
+#endif  // otbLogHelpers_h
diff --git a/Modules/Core/Common/include/otbSpan.h b/Modules/Core/Common/include/otbSpan.h
new file mode 100644
index 0000000000000000000000000000000000000000..93d27f4617b16dfd6c502625f7e8b1b36668b090
--- /dev/null
+++ b/Modules/Core/Common/include/otbSpan.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2005-2020 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 Span_h
+#define Span_h
+
+#include <type_traits>
+#include <iterator>
+#include <limits>
+#include <cassert>
+
+namespace otb
+{
+#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
+  // In C++ (only; fixed in C++14), constexpr implies const on member
+  // functions, and OTB support VC++14 which is not C++14 compliant on this
+  // topic.
+  // Hence the workaround...
+  // TODO: get rid with this hack along VC++14
+#  define OTB_MB_CSTXPR constexpr
+#else
+#  define OTB_MB_CSTXPR
+#endif
+
+/** Span class inspired by C++20 standard.
+ *
+ * \invariant `size() == 0 or data() != nullptr`
+ *
+ * \note Unlike C++20 `std::span` this implementation doesn't follow Lakos
+ * Rule but instead non-throwing functions are `noexcept` as suggested in
+ * https://wg21.link/p1656. Beware to not expect `operator[]` to always be
+ * `noexcept` as it won't be anymore once this class is deprecated in favour
+ * of `std::span` in a few years.
+ *
+ * \note This implementation only support spans with dynamic extents. Static
+ * extents are not supported (yet?)
+ *
+ * \todo fix RW / RO interface
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename T> struct Span
+{
+  /**\name Typedefs */
+  //@{
+  using element_type           = T;
+  using value_type             = std::remove_cv_t<T>;
+  using index_type             = std::size_t;
+  using difference_type        = std::ptrdiff_t;
+  using pointer                = T*;
+  using const_pointer          = T const*;
+  using reference              = T&;
+  using const_reference        = T const&;
+  using iterator               = T*;
+  using const_iterator         = T const*;
+  using reverse_iterator       = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  //@}
+
+  /**\name Constructors */
+  //@{
+  constexpr Span() noexcept = default;
+  constexpr Span(pointer ptr, index_type count) noexcept
+    : m_buffer(ptr), m_size(count)
+    {
+      assert(! (!ptr) xor (!count));
+    }
+  constexpr Span(pointer first, pointer last) noexcept
+    : Span(first, last - first)
+    {
+      assert(! (!first) xor (!last));
+      assert(first <= last);
+    }
+  template <std::size_t N> constexpr Span(element_type (&arr)[N]) noexcept
+    : Span(arr, N)
+    {}
+
+  /** Converting constructor from a contiguous container.
+   * \pre The Container shall be contiguous
+   * \warning The lifetime of the span shall not exceed the one of the container.
+   * Be sure to not store the span locally, and initialize it from a rvalue.
+   * The use case where a span is initialized from a rvalue shall be restricted
+   * to function parameters.
+   * \code
+   * std::vector<T> f();
+   * void g(Span<T> sp);
+   * ...
+   * Span<T> sp(f()); // NO!!! Use after release
+   * g(f());          // OK!!
+   * \endcode
+   *
+   * \todo static_assert the container is contiguous
+   */
+  template <class Container> constexpr Span(Container&& cont) noexcept
+    : Span(cont.data(), cont.size())
+    {
+      // We cannot use op[] which has an assertion sometimes.
+      // assert(&const[size()] == (&cont[0] + size()));
+      // Beside, it's not noexcept.
+    }
+  template <class U> constexpr Span(const otb::Span<U>& s) noexcept
+    : Span(s.data(), s.size())
+    {}
+  constexpr Span(const Span& other) noexcept = default;
+  //@}
+
+  /// shallow assignment
+  Span& operator=(Span const&) noexcept = default;
+
+  /// No-op destructor
+  ~Span() = default;
+
+  /**\name Iterators */
+  //@{
+  OTB_MB_CSTXPR iterator   begin ()       noexcept { return data(); }
+  OTB_MB_CSTXPR iterator   end   ()       noexcept { return data()+size(); }
+  constexpr const_iterator begin () const noexcept { return data(); }
+  constexpr const_iterator end   () const noexcept { return data()+size(); }
+  constexpr const_iterator cbegin() const noexcept { return data(); }
+  constexpr const_iterator cend  () const noexcept { return data()+size(); }
+
+  OTB_MB_CSTXPR reverse_iterator   rbegin ()       noexcept { return reverse_iterator(end()); }
+  OTB_MB_CSTXPR reverse_iterator   rend   ()       noexcept { return reverse_iterator(begin()); }
+  constexpr const_reverse_iterator crbegin() const noexcept { return reverse_const_iterator(cend()); }
+  constexpr const_reverse_iterator crend  () const noexcept { return reverse_const_iterator(cbegin()); }
+  //@}
+
+  /**\name Element access */
+  //@{
+  OTB_MB_CSTXPR pointer     data ()       noexcept { return m_buffer; }
+  constexpr const_pointer   data () const noexcept { return m_buffer; }
+  OTB_MB_CSTXPR reference   front()       noexcept { assert(!empty()); return *data(); }
+  constexpr const_reference front() const noexcept { assert(!empty()); return *data(); }
+  OTB_MB_CSTXPR reference   back ()       noexcept { assert(!empty()); return *data()+size()-1; }
+  constexpr const_reference back () const noexcept { assert(!empty()); return *data()+size()-1; }
+
+  OTB_MB_CSTXPR reference   operator[](index_type p)       noexcept
+  {
+    assert(p < size());
+    return data()[p];
+  }
+  constexpr const_reference operator[](index_type p) const noexcept
+  {
+    assert(p < size());
+    return data()[p];
+  }
+  //@}
+
+  /**\name Observers */
+  //@{
+  constexpr index_type size () const noexcept { return m_size; }
+  constexpr bool       empty() const noexcept { return size() == 0; }
+  //@}
+
+  /**\name Subviews */
+  //@{
+  constexpr Span first(index_type n) const noexcept
+  { assert(n < size()); return Span(data(), n);}
+  constexpr Span last(index_type n) const noexcept
+  { assert(n < size()); return Span(data()-n, n);}
+
+  constexpr Span subspan(index_type offset, index_type count = std::numeric_limits<index_type>::max()) const noexcept
+  {
+    assert(offset <= size());
+    if (count == std::numeric_limits<index_type>::max())
+    {
+      count = size() - offset;
+    }
+
+    assert(count <= (size() - offset));
+    return Span(data()+offset, count);
+
+  }
+  //@}
+
+private:
+  pointer    m_buffer = nullptr;
+  index_type m_size   = 0;
+};
+
+/**
+ * Helper function to make a span from a range defined with pointers.
+ * Compensate the fact we are not have access to C++17 `span{ptr1, ptr2}`.
+ * \tparam T  Auto deduced type of the elements
+ * \param[in] first  start of the memory zone
+ * \param[in] last   end of the memory zone
+ * \return a span over `[first, last)`
+ * \throw None
+ * \pre `NOT first != nullptr XOR last != nullptr`
+ * \pre `first < last`
+ * \pre `[first, last)` can be iterated
+ * \see `otb::Span<>`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename T>
+inline
+auto make_span(T* first, T* last) noexcept
+{
+  return Span<T>(first, last);
+}
+
+/**
+ * Helper function to make a span from a range defined with a pointer plus a
+ * size.
+ * Compensate the fact we are not have access to C++17 `span{ptr, count}`.
+ * \tparam T  Auto deduced type of the elements
+ * \param[in] first  start of the memory zone
+ * \param[in] count  number of elements in the span.
+ * \return a span over `[first, first+count)`
+ * \throw None
+ * \pre `NOT first != nullptr XOR count != 0`
+ * \see `otb::Span<>`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename T>
+inline
+auto make_span(T* first, std::size_t count) noexcept
+{
+  return Span<T>(first, count);
+}
+
+/**
+ * Helper function to make a span from a static array.
+ * Compensate the fact we are not have access to C++17 `span{array}`.
+ * \tparam T  Auto deduced type of the elements
+ * \tparam N  Auto deduced number of elements in the array
+ * \param[in] array  static array
+ * \return a span over `[&array[0], &array[N])`
+ * \throw None
+ * \see `otb::Span<>`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename T, std::size_t N>
+inline
+auto make_span(T (&arr)[N]) noexcept
+{
+  return Span<T>(arr);
+}
+
+/**
+ * Helper function to make a span from a contiguous container.
+ * Compensate the fact we are not have access to C++17 `span{container}`.
+ * \tparam ContiguousContainer  Auto deduced type of the container
+ * \param[in] cont  container of contiguous elements
+ * \return a span over `[c.data(), c.size())`
+ * \throw None
+ * \see `otb::Span<>`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename ContiguousContainer>
+inline
+auto make_span(ContiguousContainer & c) noexcept
+{
+  return Span<decltype(*c.data())>(c);
+}
+
+}
+// otb namespace
+
+
+#endif // Span_h
diff --git a/Modules/Core/Common/include/otbZipIterator.h b/Modules/Core/Common/include/otbZipIterator.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4bce7b6a9c8425a79ff224e74487d953475ccba
--- /dev/null
+++ b/Modules/Core/Common/include/otbZipIterator.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2005-2020 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 otbZipIterator_h
+#define otbZipIterator_h
+
+#include "otbSpan.h"
+#include "itkMacro.h"
+#include <type_traits>
+#include <vector>
+#include <cassert>
+
+namespace otb
+{
+namespace internals
+{
+
+struct ConstTag {};
+struct MutableTag {};
+
+/**
+ * Wrapper to present list of iterators as a single iterator.
+ *
+ * \invariant This class shall not be inherited.
+ * \invariant All sub iterators are always synchronised (same region, size...)
+ * \invariant `!m_iterators.empty()`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ */
+template <typename TImageIterator, typename ConstOrMutable>
+class ZipIterator
+{
+public:
+  /**\name ITK Constants and Typedefs */
+  //@{
+  /** Iterator type for zipped iterators. */
+  using ImageIteratorType     = TImageIterator;
+
+  /** Image type alias support */
+  using ImageType             = typename TImageIterator::ImageType;
+
+  /** Dimension of the image the iterator walks.  This constant is needed so
+   * functions that are templated over image iterator type (as opposed to
+   * being templated over pixel type and dimension) can have compile time
+   * access to the dimension of the image that the iterator walks. */
+  static constexpr unsigned int ImageIteratorDimension = ImageIteratorType::ImageIteratorDimension;
+
+  using Self                  = ZipIterator;
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacroNoParent(ZipIterator);
+
+  /** Index type alias support */
+  using IndexType             = typename ImageIteratorType::IndexType;
+
+  /** Size type alias support */
+  using SizeType              = typename ImageIteratorType::SizeType;
+
+  /** Offset type alias support */
+  using OffsetType            = typename ImageIteratorType::OffsetType;
+
+  /** Region type alias support */
+  using RegionType            = typename ImageIteratorType::RegionType;
+
+  /** PixelContainer type alias support. Used to refer to the container for
+   * the pixel data. While this was already typdef'ed in the superclass
+   * it needs to be redone here for this subclass to compile properly with gcc. */
+  using PixelContainer        = typename ImageIteratorType::PixelContainer;
+  using PixelContainerPointer = typename PixelContainer::Pointer;
+
+  /** Internal Pixel Type */
+  using InternalPixelType     = typename ImageIteratorType::InternalPixelType;
+
+  /** External Pixel Type */
+  using PixelType             = typename ImageIteratorType::PixelType;
+
+  /**  Accessor type that convert data between internal and external
+   *  representations. */
+  using AccessorType          = typename ImageIteratorType::AccessorType;
+  using AccessorFunctorType   = typename ImageIteratorType::AccessorFunctorType;
+  //@}
+
+  /**\name Constructions & Destruction
+   *
+   * This class follows the rule of 0/5
+   */
+  //@{
+  ZipIterator           ()                   = default;
+  ~ZipIterator          ()                   = default;
+  ZipIterator           (ZipIterator const&) = default;
+  ZipIterator           (ZipIterator     &&) = default;
+  ZipIterator& operator=(ZipIterator const&) = default;
+  ZipIterator& operator=(ZipIterator     &&) = default;
+
+  /** Conversion constructor.
+   * Converts from mutable to const iterator
+   * \see https://quuxplusone.github.io/blog/2018/12/01/const-iterator-antipatterns/
+   */
+  template <bool IsConst_ = std::is_same<ConstOrMutable, ConstTag>::value, class = std::enable_if<IsConst_>>
+  ZipIterator(ZipIterator<ImageIteratorType, MutableTag> const& rhs)
+    : m_iterators(rhs.m_iterators())
+    {}
+
+  /** Conversion move constructor.
+   * Move converts from mutable to const iterator
+   * \see https://quuxplusone.github.io/blog/2018/12/01/const-iterator-antipatterns/
+   */
+  template <bool IsConst_ = std::is_same<ConstOrMutable, ConstTag>::value, class = std::enable_if<IsConst_>>
+  ZipIterator(ZipIterator<ImageIteratorType, MutableTag> && rhs)
+    : m_iterators(move(rhs.m_iterators()))
+    {}
+
+  /**
+   * Init Constructor.
+   * Constructs a `ZipIterator` from a list of Images and a Region.
+   * \param[in,out] images  List of images
+   * \param[in]     region  Region to iterate over
+   * \pre There should be at least one image
+   */
+  ZipIterator(Span<ImageType * const> images, RegionType const& region)
+  {
+    assert(! images.empty());
+    m_iterators.reserve(images.size());
+
+    for (auto & im: images)
+      m_iterators.emplace_back(im, region);
+  }
+
+  // static_assert(std::is_copy_constructible<Self>::value, "Requires copy construction");
+  // static_assert(std::is_trivially_copy_constructible<Self>::value, "Requires trivial copy construction");
+  //@}
+
+  /**\name Comparison */
+  //@{
+  friend bool operator==(ZipIterator const& lhs, ZipIterator const& rhs)
+  {
+    assert(!lhs.m_iterators.empty());
+    assert(lhs.m_iterators.size() == rhs.m_iterators.size());
+
+    return lhs.m_iterators.front() == rhs.m_iterators.front();
+  }
+  friend bool operator!=(ZipIterator const& lhs, ZipIterator const& rhs)
+  { return ! (lhs == rhs); }
+
+  friend bool operator<=(ZipIterator const& lhs, ZipIterator const& rhs)
+  {
+    assert(!lhs.m_iterators.empty());
+    assert(lhs.m_iterators.size() == rhs.m_iterators.size());
+
+    return lhs.m_iterators.front() <= rhs.m_iterators.front();
+  }
+  friend bool operator<(ZipIterator const& lhs, ZipIterator const& rhs)
+  {
+    assert(!lhs.m_iterators.empty());
+    assert(lhs.m_iterators.size() == rhs.m_iterators.size());
+
+    return lhs.m_iterators.front() < rhs.m_iterators.front();
+  }
+  friend bool operator>=(ZipIterator const& lhs, ZipIterator const& rhs)
+  { return ! (lhs < rhs); }
+  friend bool operator>(ZipIterator const& lhs, ZipIterator const& rhs)
+  { return ! (lhs <= rhs); }
+  //@}
+
+  /**\name ITK iterator interface */
+  //@{
+  // What about GetIndex() and SetIndex ?
+  /** Fetch the region iterated by the iterator. */
+  auto const& GetRegion() const
+  {
+    assert(!m_iterators.empty());
+    return m_iterators.front().GetRegion();
+  }
+
+  /** Set the region iterated by the iterator. */
+  void SetRegion(RegionType const& region)
+  {
+    for (auto & it : m_iterators)
+      it.SetRegion(region);
+  }
+
+  /** Moves the iterator to the begin of the region iterated. */
+  Self& GoToBegin() {
+    for (auto & it : m_iterators)
+      it.GoToBegin();
+    return *this;
+  }
+  /** Moves the iterator to the end of the region iterated. */
+  Self& GoToEnd() {
+    for (auto & it : m_iterators)
+      it.GoToEnd();
+    return *this;
+  }
+
+  /** Tells whether the iterator is at the begin of the region iterated. */
+  bool IsAtBegin() const {
+    assert(!m_iterators.empty());
+    return m_iterators.front().IsAtBegin();
+  }
+
+  /** Tells the iterator is at the end of the region iterated. */
+  bool IsAtEnd() const {
+    assert(!m_iterators.empty());
+    return m_iterators.front().IsAtEnd();
+  }
+
+  /** Pre-increment the iterator.
+   * As post-increment is less efficient, it hasn't been provided.
+   */
+  Self& operator++() {
+    assert(!IsAtEnd());
+    for (auto & it : m_iterators)
+      ++it;
+    return *this;
+  }
+  /** Removed post-increment operator.
+   * Please use the  preincrement operator!
+   */
+  Self operator++(int) = delete;
+
+  /** Internal typedef to the type holding the list of ITK iterators. */
+  using ImageIteratorList_t = std::vector<ImageIteratorType>;
+  /** Internal Pixel Proxy Type returned by `ZipIterator`.
+   * \author Luc Hermitte (CS Group)
+   * \copyright CNES
+   * \ingroup OTBCommon
+   */
+  struct PixelListProxy
+  {
+    /** Init constructor.
+     * @param[in] iterators List of ITK iterators
+     */
+    explicit PixelListProxy(ImageIteratorList_t const& iterators) noexcept
+      : m_iterators(iterators)
+      {}
+    bool empty()   const noexcept {return m_iterators.empty();}
+    auto size()    const noexcept {return m_iterators.size();}
+
+    /** Internal C++ iterator over the components of the Pixel Proxy.
+     * \author Luc Hermitte (CS Group)
+     * \copyright CNES
+     * \ingroup OTBCommon
+     */
+    struct iterator__
+    {
+      using difference_type   = typename ImageIteratorList_t::difference_type;
+      using value_type        = decltype(typename ImageIteratorList_t::const_iterator{}->Get());
+      using pointer           = value_type*;
+      using reference         = value_type&;
+      using iterator_category = std::forward_iterator_tag;
+
+      explicit iterator__(typename ImageIteratorList_t::const_iterator ref)
+        : reference_to_value(ref){}
+      friend bool operator==(iterator__ const& lhs, iterator__ const& rhs) noexcept
+      { return lhs.reference_to_value == rhs.reference_to_value;}
+      friend bool operator!=(iterator__ const& lhs, iterator__ const& rhs) noexcept
+      { return ! (lhs == rhs);}
+      iterator__ & operator++() noexcept {
+        ++reference_to_value;
+        return *this;
+      }
+      iterator__ & operator--() noexcept {
+        --reference_to_value;
+        return *this;
+      }
+      iterator__ operator+(std::ptrdiff_t offset) const noexcept{
+        return iterator__{reference_to_value + offset};
+      }
+      iterator__ operator-(std::ptrdiff_t offset) const noexcept{
+        return iterator__{reference_to_value - offset};
+      }
+      decltype(auto) operator*() const {
+        return reference_to_value->Get();
+      }
+
+    private:
+      typename ImageIteratorList_t::const_iterator reference_to_value;
+    };
+
+    auto begin()         noexcept { return iterator__(m_iterators.begin()); }
+    auto end()           noexcept { return iterator__{m_iterators.end()}; }
+    auto begin()   const noexcept { return iterator__{m_iterators.begin()}; }
+    auto end()     const noexcept { return iterator__{m_iterators.end()}; }
+    auto cbegin()  const noexcept { return iterator__{m_iterators.cbegin()}; }
+    auto cend()    const noexcept { return iterator__{m_iterators.cend()}; }
+
+    decltype(auto) operator[](std::size_t idx) const {
+      assert(idx < size());
+      return m_iterators[idx].Get();
+    }
+    decltype(auto) operator[](std::size_t idx)       {
+      assert(idx < size());
+      return m_iterators[idx].Get();
+    }
+
+    decltype(auto) front() const {
+      assert(!empty());
+      return m_iterators.front().Get();
+    }
+    decltype(auto) front()       {
+      assert(!empty());
+      return m_iterators.front().Get();
+    }
+    decltype(auto) back() const {
+      assert(!empty());
+      return m_iterators.back().Get();
+    }
+    decltype(auto) back()       {
+      assert(!empty());
+      return m_iterators.back().Get();
+    }
+  private:
+    ImageIteratorList_t const& m_iterators;
+  };
+
+  /** Fetches the value of the current pixel.
+   * \return an iterable proxy over the pixel made of all images.
+   */
+  PixelListProxy Get() const {
+    return PixelListProxy{m_iterators};
+  }
+
+  //@}
+
+  /**\name Mutable Iterator Interface */
+  //@{
+  template <typename MultiCompPixelType>
+  void Set(MultiCompPixelType const& p)
+  {
+    assert(p.size() == m_iterators.size());
+    for (std::size_t i = 0; i!=m_iterators.size(); ++i)
+    {
+      m_iterators[i].Set(p[i]);
+    }
+  }
+  // PixelType & Value(); -- cannot be defined and still preserve direct access
+  // to memory => we don't provide it.
+
+  // ImageType * GetImages();
+  //@}
+
+  /**\name ScanLine Iterator Interface */
+  //@{
+  /** Moves iterator to next line. */
+  Self& NextLine() {
+    for (auto & it : m_iterators)
+      it.NextLine();
+    return *this;
+  }
+  /** Moves iterator to the beginning of the current line. */
+  Self& GoToBeginOfLine() {
+    for (auto & it : m_iterators)
+      it.GoToBeginOfLine();
+    return *this;
+  }
+  /** Moves iterator to the end of the current line. */
+  Self& GoToEndOfLine() {
+    for (auto & it : m_iterators)
+      it.GoToEndOfLine();
+    return *this;
+  }
+  /** Tells whether the iterator is a the end of a line.
+   * \pre `!m_iterators.empty()`
+   */
+  bool IsAtEndOfLine() const {
+    assert(!m_iterators.empty());
+    // Const qualifier has been added to ScanLineIterator::IsAtEndOfLine in ITK
+    // 5.1 => Use const_cast in the mean time...
+    return const_cast<typename ImageIteratorList_t::value_type &>(m_iterators.front()).IsAtEndOfLine();
+  }
+  //@}
+
+private:
+  ImageIteratorList_t m_iterators;
+};
+
+} // otb::internal namespace
+
+/** Typedef for a ZipIterator.
+ * ZipIterator presents a single iterator over a list of image iterators.
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ * \see `otb::internals::ZipIterator<>`
+ */
+template <typename TImageIterator>
+using ZipIterator      = internals::ZipIterator<TImageIterator, internals::MutableTag>;
+/** Typedef for a ZipConstIterator.
+ * ZipConstIterator presents a single iterator over a list of const image iterators.
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \ingroup OTBCommon
+ * \see `otb::internals::ZipIterator<>`
+ */
+template <typename TImageIterator>
+using ZipConstIterator = internals::ZipIterator<TImageIterator, internals::ConstTag>;
+
+} // otb namespace
+
+#endif  // otbZipIterator_h
diff --git a/Modules/Core/Functor/include/otbSynthetizeFilter.h b/Modules/Core/Functor/include/otbSynthetizeFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..88393bcf1a445174233e5e87a67d7e68bea98b0f
--- /dev/null
+++ b/Modules/Core/Functor/include/otbSynthetizeFilter.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2005-2020 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 otbSynthetizeFilter_h
+#define otbSynthetizeFilter_h
+
+#include "otbZipIterator.h"
+#include "itkImageToImageFilter.h"
+#include "itkImageScanlineConstIterator.h"
+#include "itkImageScanlineIterator.h"
+#include "itkProgressReporter.h"
+
+namespace otb
+{
+/**
+ * Filter that reduces/synthetize multiple input into a single output.
+ *
+ * This filter makes sure to avoid VectorImages. Instead it works on a
+ * collection of scalar images.
+ * \tparam TInputImage   Type of the input images
+ * \tparam TOutputImage  Type of the output image
+ * \tparam TFunctor      Type of the functor, meant to be auto-deduced by
+ * `MakeSynthetizeFilter()`
+ *
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ * \see for instance `otb::Wrapper::Synthetize`
+ */
+template <typename TInputImage, typename TOutputImage, typename TFunctor>
+class SynthetizeFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage>
+{
+public:
+
+  /**\name Convenient typedefs for simplifying declarations */
+  //@{
+  using InputImageType  = TInputImage;
+  using OutputImageType = TOutputImage;
+  using FunctorType     = TFunctor;
+  //@}
+
+  /**\name Extract dimension from input and output images */
+  //@{
+  itkStaticConstMacro(InputImageDimension,  unsigned int, InputImageType::ImageDimension);
+  itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension);
+  //@}
+  /**\name Standard class typedefs */
+  //@{
+  using Self            = SynthetizeFilter;
+  using Superclass      = itk::ImageToImageFilter<InputImageType, OutputImageType>;
+  using Pointer         = itk::SmartPointer<Self>;
+  using ConstPointer    = itk::SmartPointer<const Self>;
+  //@}
+
+  /** Method for creation through the object factory. */
+  static Pointer New(FunctorType functor)
+  {
+    Pointer smartPtr = new Self(std::move(functor));
+    smartPtr->UnRegister();
+    return smartPtr;
+  }
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(SynthetizeFilter, ImageToImageFilter);
+
+  /**\name Image typedef support */
+  //@{
+  using InputPixelType        = typename InputImageType::PixelType;
+  using OutputPixelType       = typename OutputImageType::PixelType;
+  using InputRealType         = typename itk::NumericTraits<InputPixelType>::RealType;
+  using InputImageRegionType  = typename InputImageType::RegionType;
+  using OutputImageRegionType = typename OutputImageType::RegionType;
+  using InputSizeType         = typename InputImageType::SizeType;
+  using OutputIndexType       = typename OutputImageType::IndexType;
+  using OutputSizeType        = typename OutputImageType::SizeType;
+
+  static_assert(InputImageDimension == OutputImageDimension, "Images have the same number of components");
+
+  using DataObjectPointerArraySizeType = itk::ProcessObject::DataObjectPointerArraySizeType;
+   //@}
+
+  /**\name Access to N-th Input
+   *
+   * Set/Get the nth filter input with or without a specified associated
+   * variable name.
+   */
+  //@{
+  using Superclass::SetNthInput;
+  using Superclass::GetInput;
+
+  /** Return a pointer on the nth filter input */
+  InputImageType* GetNthInput(DataObjectPointerArraySizeType idx)
+  {
+    return const_cast<InputImageType*>(this->GetInput(idx));
+  }
+
+  /** Returns a vector of input images. */
+  std::vector<InputImageType const*> GetInputs() const
+  {
+    std::vector<InputImageType const*> res;
+    auto const  nbInputImages = this->GetNumberOfInputs();
+    res.reserve(nbInputImages);
+    for (std::size_t i = 0 ; i != nbInputImages ; ++i)
+      res.push_back(this->GetInput(i));
+    return res;
+  }
+  //@}
+
+protected:
+  /** Init constructor. */
+  explicit SynthetizeFilter(FunctorType functor)
+    : m_functor(functor){}
+  ~SynthetizeFilter() = default;
+
+  /** Overrides `GenerateOutputInformation` to check images consistency. */
+  void GenerateOutputInformation() override
+  {
+    Superclass::GenerateOutputInformation();
+    CheckInputImageDimensions();
+  }
+
+  // void GenerateInputRequestedRegion() override;
+  // +-> TODO: detect neighborhood to apply pad radius
+
+  /**
+   * Main computation function called by each thread.
+   * \param[in] outputRegionForThread  Specified output region to compute
+   * \param[in] threadId               Id of the computing threads
+   */
+  void ThreadedGenerateData(
+      OutputImageRegionType const& outputRegionForThread,
+      itk::ThreadIdType            threadId) override
+  {
+    using ImageScanlineConstIteratorType = itk::ImageScanlineConstIterator<InputImageType const>;
+    // using OutImageScanlineConstIteratorType = itk::ImageScanlineIterator<OutputImageType>;
+    using OutputIterator  = itk::ImageScanlineIterator<OutputImageType>;
+    using InputIterator   = ZipConstIterator<ImageScanlineConstIteratorType>;
+
+    auto const regSizeY = outputRegionForThread.GetSize()[1];
+    itk::ProgressReporter progress( this, threadId, outputRegionForThread.GetNumberOfPixels() / regSizeY );
+
+    InputIterator  inputIterator(this->GetInputs(), outputRegionForThread);
+    OutputIterator outputIterator(this->GetOutput(), outputRegionForThread);
+
+    inputIterator.GoToBegin();
+    outputIterator.GoToBegin();
+    for (
+        ; !inputIterator.IsAtEnd()
+        ; inputIterator.NextLine(), outputIterator.NextLine())
+    {
+      assert(! outputIterator.IsAtEnd());
+      // inputIterator.GoToBeginOfLine();
+      // outputIterator.GoToBeginOfLine();
+      for (
+          ; !inputIterator.IsAtEndOfLine()
+          ; ++inputIterator, ++outputIterator)
+      {
+        assert(!outputIterator.IsAtEndOfLine());
+
+        outputIterator.Set(m_functor(inputIterator.Get()));
+      }
+      progress.CompletedPixel(); // Completed...Line()
+    }
+  }
+
+private:
+
+  void CheckInputImageDimensions()
+  {
+    // Check if input image dimensions match
+    auto const  nbInputImages = this->GetNumberOfInputs();
+    auto const& inputSize = this->GetInput(0)->GetLargestPossibleRegion().GetSize();
+
+    for (auto p = 1U; p < nbInputImages; ++p)
+    {
+      auto const& regionSize = this->GetInput(p)->GetLargestPossibleRegion().GetSize();
+      if (inputSize != regionSize)
+      {
+        itkExceptionMacro(<< "Input images must have the same dimensions.\n"
+            << "band #1 is [" << inputSize[0] << ";" << inputSize[1] << "]\n"
+            << "band #" << p + 1 << " is [" << this->GetInput(p)->GetLargestPossibleRegion().GetSize(0) << ";"
+            << regionSize << "]");
+      }
+    }
+  }
+
+  /** Internal functor.
+   * Can only be set at filter creation through call to `New`.
+   */
+  FunctorType m_functor;
+
+};
+
+/**
+ * Factory function for `SynthetizeFilter`.
+ * `SynthetizeFilter` objects are best made thanks to this factory function
+ * that'll automatically deduce the type of the functor parameter.
+ *
+ * Actually, there is no other to create a `SynthetizeFilter<>` that'll call a
+ * lambda on each pixel.
+ * \tparam TInputImage  Type of the input images
+ * \tparam TOutputImage Type of the output image
+ * \tparam TFunctor     Type of the functor
+ * \param[in] functor   The functor
+ *
+ * \return a new `SynthetizeFilter` object.
+ * \sa `SynthetizeFilter`
+ */
+template <typename TInputImage, typename TOutputImage, typename TFunctor>
+auto MakeSynthetizeFilter(TFunctor functor)
+{
+  auto filter = SynthetizeFilter<TInputImage, TOutputImage, TFunctor>::New(std::move(functor));
+  return filter;
+}
+
+} // otb namespace
+
+#ifndef OTB_MANUAL_INSTANTIATION
+// #include "otbSynthetizeFilter.hxx"
+#endif
+
+#endif  // otbSynthetizeFilter_h
diff --git a/Modules/Core/Metadata/include/otbGeometryMetadata.h b/Modules/Core/Metadata/include/otbGeometryMetadata.h
index ccd902ecce298e49760467685d104a208386760a..802ae6c3e23d07f937607da12e7adf3bbb4ad3c6 100644
--- a/Modules/Core/Metadata/include/otbGeometryMetadata.h
+++ b/Modules/Core/Metadata/include/otbGeometryMetadata.h
@@ -161,6 +161,25 @@ struct OTBMetadata_EXPORT RPCParam
     oss << "]";
     return oss.str();
   };
+  
+  // Equality comparison operator (hidden friend idiom)
+  friend bool operator==(const RPCParam & lhs, const RPCParam & rhs)
+  {
+    return lhs.LineOffset == rhs.LineOffset
+        && lhs.SampleOffset == rhs.SampleOffset
+        && lhs.LatOffset == rhs.LatOffset
+        && lhs.LonOffset == rhs.LonOffset
+        && lhs.HeightOffset == rhs.HeightOffset
+        && lhs.LineScale == rhs.LineScale
+        && lhs.SampleScale == rhs.SampleScale
+        && lhs.LatScale == rhs.LatScale
+        && lhs.LonScale == rhs.LonScale
+        && lhs.HeightScale == rhs.HeightScale
+        && std::equal(std::begin(lhs.LineNum), std::end(lhs.LineNum), std::begin(rhs.LineNum))
+        && std::equal(std::begin(lhs.LineDen), std::end(lhs.LineDen), std::begin(rhs.LineDen))
+        && std::equal(std::begin(lhs.SampleNum), std::end(lhs.SampleNum), std::begin(rhs.SampleNum))
+        && std::equal(std::begin(lhs.SampleDen), std::end(lhs.SampleDen), std::begin(rhs.SampleDen));
+  }
 
 };
 
diff --git a/Modules/Core/Metadata/include/otbMetaDataKey.h b/Modules/Core/Metadata/include/otbMetaDataKey.h
index 88656b521e166ff8b9ac3ed6eb82c91956f36a69..1dfbe1e7cfebbcb8f233b93447f454756de79351 100644
--- a/Modules/Core/Metadata/include/otbMetaDataKey.h
+++ b/Modules/Core/Metadata/include/otbMetaDataKey.h
@@ -238,8 +238,15 @@ struct OTBMetadata_EXPORT Time : tm
 
   friend OTBMetadata_EXPORT std::istream& operator>>(std::istream& is, Time& val);
 
+  friend OTBMetadata_EXPORT bool operator==(const Time & lhs, const Time & rhs)
+  {
+    tm tmLhs = lhs;
+    tm tmRhs = rhs;
+    return mktime(&tmLhs) + lhs.frac_sec == mktime(&tmRhs) + rhs.frac_sec;
+  }
 };
 
+
 struct LUTAxis
 {
   /** number of measurements on this axis */
@@ -252,6 +259,14 @@ struct LUTAxis
   std::vector<double> Values;
   /** Export to JSON */
   std::string ToJSON(bool multiline=false) const;
+
+  friend bool operator==(const LUTAxis & lhs, const LUTAxis & rhs)
+  {
+    return lhs.Size == rhs.Size
+        && lhs.Origin == rhs.Origin
+        && lhs.Spacing == rhs.Spacing
+        && lhs.Values == rhs.Values;
+  }
 };
 
 template <unsigned int VDim> class LUT
@@ -266,8 +281,24 @@ public:
   std::string OTBMetadata_EXPORT ToString() const;
 
   void OTBMetadata_EXPORT FromString(std::string);
+
+  friend bool operator==(const LUT<VDim> & lhs, const LUT<VDim> & rhs)
+  {
+    return std::equal(std::begin(lhs.Array), std::end(lhs.Array), std::begin(rhs.Array) ) 
+            && lhs.Array == rhs.Array;
+  }
+
 };
 
+
+template <unsigned int VDim>
+std::ostream& operator<<(std::ostream& os, const LUT<VDim>& val)
+{
+  os << val.ToString();
+  return os;
+}
+
+
 typedef LUT<1> LUT1D;
 
 typedef LUT<2> LUT2D;
@@ -300,6 +331,32 @@ extern OTBMetadata_EXPORT MDL1DBmType MDL1DNames;
 typedef boost::bimap<MDL2D, std::string> MDL2DBmType;
 extern OTBMetadata_EXPORT MDL2DBmType MDL2DNames;
 
+template<class T>
+std::string EnumToString(T t);
+
+template<>
+std::string EnumToString(MDGeom value);
+
+template<>
+std::string EnumToString(MDNum value);
+
+template<>
+std::string EnumToString(MDStr value);
+
+template<>
+std::string EnumToString(MDL1D value);
+
+template<>
+std::string EnumToString(MDL2D value);
+
+template<>
+std::string EnumToString(MDTime value);
+
+// Specialization for extra keys
+template<>
+std::string EnumToString(std::string value);
+
+
 } // end namespace MetaData
 
 namespace Utils
diff --git a/Modules/Core/Metadata/src/otbMetaDataKey.cxx b/Modules/Core/Metadata/src/otbMetaDataKey.cxx
index 0a21706a52ffcbec153b4c12589c1dc7803c5b70..dab051fcb7ce812dddc8506665f3516489f37d75 100644
--- a/Modules/Core/Metadata/src/otbMetaDataKey.cxx
+++ b/Modules/Core/Metadata/src/otbMetaDataKey.cxx
@@ -192,6 +192,7 @@ std::istream& operator>>(std::istream& is, Time& val)
 
 #undef _OTB_ISTREAM_EXPECT
 
+
 std::string LUTAxis::ToJSON(bool multiline) const
 {
   std::ostringstream oss;
@@ -399,6 +400,54 @@ MDGeomBmType MDGeomNames = bimapGenerator<MDGeom>(std::map<MDGeom, std::string>
   {MDGeom::Adjustment,     "Adjustment"}
 });
 
+template<>
+std::string EnumToString(MDGeom value)
+{
+  return MetaData::MDGeomNames.left.at(value);
+}
+
+template<>
+std::string EnumToString(MDNum value)
+{
+  return MetaData::MDNumNames.left.at(value);
+}
+
+template<>
+std::string EnumToString(MDStr value)
+{
+  return MetaData::MDStrNames.left.at(value);
+}
+
+template<>
+std::string EnumToString(MDL1D value)
+{
+  return MetaData::MDL1DNames.left.at(value);
+}
+
+template<>
+std::string EnumToString(MDL2D value)
+{
+  return MetaData::MDL2DNames.left.at(value);
+}
+
+template<>
+std::string EnumToString(MDTime value)
+{
+  return MetaData::MDTimeNames.left.at(value);
+}
+
+// Specialization for extra keys
+template<>
+std::string EnumToString(std::string value)
+{
+  return value;
+}
+
+
+
+
+
+
 } // end namespace MetaData
 
 } // end namespace otb
diff --git a/Modules/Core/Metadata/src/otbOpticalImageMetadataInterface.cxx b/Modules/Core/Metadata/src/otbOpticalImageMetadataInterface.cxx
index 647ba5c571273887d86e11ff3b3d805afa2776da..f9a54f8754d842f76994b0eb88e6a7785ba9fce9 100644
--- a/Modules/Core/Metadata/src/otbOpticalImageMetadataInterface.cxx
+++ b/Modules/Core/Metadata/src/otbOpticalImageMetadataInterface.cxx
@@ -103,7 +103,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
     this->m_Imd.Add(MDNum::SunElevation, this->GetSunElevation());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -111,7 +111,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::SunAzimuth, this->GetSunAzimuth());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -119,7 +119,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::SatElevation, this->GetSatElevation());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -127,7 +127,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::SatAzimuth, this->GetSatAzimuth());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -135,7 +135,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::PhysicalBias, this->GetPhysicalBias());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -143,7 +143,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::PhysicalGain, this->GetPhysicalGain());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -151,7 +151,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::SolarIrradiance, this->GetSolarIrradiance());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -159,7 +159,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::FirstWavelength, this->GetFirstWavelengths());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
@@ -167,7 +167,7 @@ bool OpticalImageMetadataInterface::ConvertImageKeywordlistToImageMetadata()
   {
 	  this->m_Imd.Add(MDNum::LastWavelength,  this->GetLastWavelengths());
   }
-  catch (const itk::ExceptionObject)
+  catch (const itk::ExceptionObject &)
   {
     result = false;
   }
diff --git a/Modules/Core/Transform/include/otbGenericRSTransform.h b/Modules/Core/Transform/include/otbGenericRSTransform.h
index 9ffa943b83c2dbcfebbbb7a572dcd3c89130ae60..e0ac8ba8eb0a3eda5e76c894ec9a3b6f5bb50c3e 100644
--- a/Modules/Core/Transform/include/otbGenericRSTransform.h
+++ b/Modules/Core/Transform/include/otbGenericRSTransform.h
@@ -100,7 +100,9 @@ public:
   itkSetStringMacro(OutputProjectionRef);
   itkGetStringMacro(OutputProjectionRef);
 
-  /** Set/Get Dictionary*/
+  /** Set/Get Dictionary
+   * \deprecated
+   */
   const itk::MetaDataDictionary& GetInputDictionary() const
   {
     return m_InputDictionary;
@@ -123,7 +125,9 @@ public:
     this->Modified();
   }
 
-  /** Set/Get Keywordlist*/
+  /** Set/Get Keywordlist
+   * \deprecated
+   */
 
   itkGetMacro(InputKeywordList, ImageKeywordlist);
   void SetInputKeywordList(const ImageKeywordlist& kwl)
diff --git a/Modules/Core/Transform/include/otbImageToGenericRSOutputParameters.h b/Modules/Core/Transform/include/otbImageToGenericRSOutputParameters.h
index 9a8ea947b0a7dca09aefa2bd2afa649ca3ee9d17..1a17eac31c9222d9f6a7ab77b27a38d0bb90a4d7 100644
--- a/Modules/Core/Transform/include/otbImageToGenericRSOutputParameters.h
+++ b/Modules/Core/Transform/include/otbImageToGenericRSOutputParameters.h
@@ -148,7 +148,9 @@ public:
     return m_Transform->GetOutputProjectionRef();
   }
 
-  /** Set/Get Input Keywordlist*/
+  /** Set/Get Input Keywordlist
+   * \deprecated
+   */
   void SetInputKeywordList(const ImageKeywordlist& kwl)
   {
     m_Transform->SetOutputKeywordList(kwl);
diff --git a/Modules/Core/Transform/include/otbSensorModelBase.h b/Modules/Core/Transform/include/otbSensorModelBase.h
index 3c223f852012a252091495ab0814ea2ec34e60d6..9071bce41fcfd8eb311e2e603a28585aaa879227 100644
--- a/Modules/Core/Transform/include/otbSensorModelBase.h
+++ b/Modules/Core/Transform/include/otbSensorModelBase.h
@@ -73,6 +73,7 @@ public:
   /*
    * Set the Imagekeywordlist and affect the ossim projection ( m_Model)
    * Return false if not model found.
+   * \deprecated
    */
   virtual void SetImageGeometry(const ImageKeywordlist& image_kwl);
 
diff --git a/Modules/Filtering/ImageManipulation/include/otbGridResampleImageFilter.hxx b/Modules/Filtering/ImageManipulation/include/otbGridResampleImageFilter.hxx
index 7097361de8252f0e1baee2896ac051baf1648efa..1cd4211ca901dd5cc978f47c9abf57c592f37612 100644
--- a/Modules/Filtering/ImageManipulation/include/otbGridResampleImageFilter.hxx
+++ b/Modules/Filtering/ImageManipulation/include/otbGridResampleImageFilter.hxx
@@ -41,8 +41,8 @@ GridResampleImageFilter<TInputImage, TOutputImage, TInterpolatorPrecision>::Grid
     m_OutputOrigin(),
     m_OutputSpacing(),
     m_EdgePaddingValue(),
-    m_CheckOutputBounds(true),
     m_InterpolationMargin(0.0),
+    m_CheckOutputBounds(true),
     m_Interpolator(),
     m_ReachableOutputRegion()
 {
diff --git a/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.h b/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..1619aaf036af7798f1362840e950913ad8b83a44
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005-2020 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 otbResetMarginFilter_h
+#define otbResetMarginFilter_h
+
+#include "itkImageToImageFilter.h"
+
+namespace otb
+{
+/**
+ * Region clamping filter.
+ * This filter is a kind of ROI pass filter. Data within the ROI is kept with
+ * its original value. Data outside ROI is forced to 0.
+ *
+ * Also, this filter propagate the exact ROI upstream in the pipeline. This
+ * way, if it's piped after another filter, the upstream filter isn't executed
+ * on the data outside the ROI.
+ *
+ * \tparam TImage  Image type.
+ * \sa `otb::ExtractROI<>`
+ * \author Luc Hermitte (CS Group)
+ * \copyright CNES
+ */
+template <typename TImage>
+class ResetMarginFilter : public itk::ImageToImageFilter<TImage, TImage>
+{
+public:
+
+  /**\name Convenient typedefs for simplifying declarations */
+  //@{
+  using InputImageType  = TImage;
+  using OutputImageType = TImage;
+  //@}
+
+  /**\name Extract dimension from input and output images */
+  //@{
+  itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension);
+  itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension);
+  //@}
+  /**\name Standard class typedefs */
+  //@{
+  using Self            = ResetMarginFilter;
+  using Superclass      = itk::ImageToImageFilter<InputImageType, OutputImageType>;
+  using Pointer         = itk::SmartPointer<Self>;
+  using ConstPointer    = itk::SmartPointer<const Self>;
+  //@}
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(ResetMarginFilter, unused);
+
+  /**\name Image typedef support */
+  //@{
+  using InputPixelType        = typename InputImageType::PixelType;
+  using OutputPixelType       = typename OutputImageType::PixelType;
+  using InputRealType         = typename itk::NumericTraits<InputPixelType>::RealType;
+  using InputImageRegionType  = typename InputImageType::RegionType;
+  using OutputImageRegionType = typename OutputImageType::RegionType;
+  using InputIndexType        = typename InputImageType::IndexType;
+  using InputSizeType         = typename InputImageType::SizeType;
+  using OutputIndexType       = typename OutputImageType::IndexType;
+  using OutputSizeType        = typename OutputImageType::SizeType;
+
+  static_assert(InputImageDimension == OutputImageDimension, "Images have the same number of components");
+   //@}
+
+  /** Column threshold setter. */
+  void SetThresholdX(long threshold) noexcept
+  { m_thresholdX = threshold; }
+  /** Column threshold getter. */
+  long GetThresholdX() const noexcept
+  { return m_thresholdX;}
+
+  /** Top line threshold setter. */
+  void SetThresholdYtop(long threshold) noexcept
+  { m_thresholdYtop = threshold; }
+  /** Top line threshold getter. */
+  long GetThresholdYtop() const noexcept
+  { return m_thresholdYtop;}
+
+  /** Bottom line threshold setter. */
+  void SetThresholdYbot(long threshold) noexcept
+  { m_thresholdYbot = threshold; }
+  /** Bottom line threshold getter. */
+  long GetThresholdYbot() const noexcept
+  { return m_thresholdYbot;}
+
+protected:
+  /// Hidden constructor
+  ResetMarginFilter() = default;
+
+  InputImageType      * GetInputImage()       { return const_cast<InputImageType*>(this->GetInput()); }
+  InputImageType const* GetInputImage() const { return this->GetInput(); }
+
+  /** otbResetMarginFilter doesn't need an input requested region as large as the
+   * output requested region.
+   * \sa ImageToImageFilter::GenerateInputRequestedRegion()
+   */
+  void CallCopyOutputRegionToInputRegion(
+      InputImageRegionType       & destRegion,
+      OutputImageRegionType const& srcRegion) override
+  {
+    destRegion = OutputRegionToInputRegion(srcRegion);
+  }
+
+  /**
+   * Functional implementation of `CallCopyOutputRegionToInputRegion()`.
+   */
+  InputImageRegionType OutputRegionToInputRegion(
+      OutputImageRegionType const& srcRegion);
+
+  /**
+   * Main computation function called by each thread.
+   * \param[in] outputRegionForThread  Specified output region to compute
+   * \param[in] threadId               Id of the computing threads
+   */
+  void ThreadedGenerateData(
+      OutputImageRegionType const& outputRegionForThread,
+      itk::ThreadIdType            threadId) override;
+
+private:
+  long m_thresholdX    = 0;
+  long m_thresholdYtop = 0;
+  long m_thresholdYbot = 0;
+};
+
+} // otb namespace
+
+#ifndef OTB_MANUAL_INSTANTIATION
+#include "otbResetMarginFilter.hxx"
+#endif
+
+#endif  // otbResetMarginFilter_h
diff --git a/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.hxx b/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..0c35e1ad6700064f9edfdec2de34dcf28bad44b8
--- /dev/null
+++ b/Modules/Filtering/ImageManipulation/include/otbResetMarginFilter.hxx
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2005-2020 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 otbResetMarginFilter_hxx
+#define otbResetMarginFilter_hxx
+
+#include "otbResetMarginFilter.h"
+#include "otbInterval.h"
+#include "otbMacro.h"
+#include "otbLogHelpers.h"
+#include "itkImageScanlineConstIterator.h"
+#include "itkImageScanlineIterator.h"
+#include "itkProgressReporter.h"
+#include <boost/numeric/interval.hpp>
+#include <algorithm>
+#include <cassert>
+#include <ostream>
+
+template <typename T, typename P>
+inline
+std::ostream & operator<<(std::ostream & os, boost::numeric::interval<T,P> const& v)
+{
+  return os << '[' << v.lower() << ".." << v.upper() << '[';
+}
+
+namespace otb
+{
+
+template<typename TImage>
+void
+ResetMarginFilter<TImage>
+::ThreadedGenerateData(
+    OutputImageRegionType const& outputRegionForThread,
+    itk::ThreadIdType            threadId)
+{
+  // otbMsgDevMacro("ThreadedGenerateData begin("<<NeatRegionLogger{outputRegionForThread}<<")");
+  using InputIterator   = itk::ImageScanlineConstIterator<InputImageType const>;
+  using OutputIterator  = itk::ImageScanlineIterator<OutputImageType>;
+
+  auto const* input  = this->GetInput();
+  auto      * output = this->GetOutput();
+  assert(input);
+  assert(output);
+  InputIterator  inputIterator (input,  OutputRegionToInputRegion(outputRegionForThread));
+  OutputIterator outputIterator(output, outputRegionForThread);
+
+  auto const& imgRegion = output->GetLargestPossibleRegion();
+  auto const  imgSizeX  = imgRegion.GetSize()[0];
+  auto const  imgSizeY  = imgRegion.GetSize()[1];
+  itk::IndexValueType const  imgEndX   = imgRegion.GetIndex()[0] + imgSizeX;
+  itk::IndexValueType const  imgEndY   = imgRegion.GetIndex()[1] + imgSizeY;
+
+  auto const& size      = outputRegionForThread.GetSize();
+  auto const& index     = outputRegionForThread.GetIndex();
+  auto const  sizeX     = size[0];
+  auto const  sizeY     = size[1];
+  auto const  startX    = index[0];
+  auto const  startY    = index[1];
+  itk::IndexValueType const  endX      = startX + sizeX;
+  itk::IndexValueType const  endY      = startY + sizeY;
+  auto const  thrX1     = std::min<itk::IndexValueType>(endX, m_thresholdX);
+  auto const  thrX2     = std::min<itk::IndexValueType>(endX, imgEndX - m_thresholdX);
+  auto const  thrY1     = std::min<itk::IndexValueType>(endY, m_thresholdYtop);
+  auto const  thrY2     = std::min<itk::IndexValueType>(endY, imgEndY - m_thresholdYbot);
+
+  assert(thrX1 <= endX && "Iterations shall stay within requested region");
+  assert(thrX2 <= endX && "Iterations shall stay within requested region");
+  assert(thrY1 <= endY && "Iterations shall stay within requested region");
+  assert(thrY2 <= endY && "Iterations shall stay within requested region");
+
+  // using interval_t = boost::numeric::interval<long>;
+  using interval_t = Interval;
+  auto const region      = interval_t{startX, endX};
+  auto const zero_left   = intersect(interval_t{startX, thrX1}, region);
+  auto const copy_middle = intersect(interval_t{thrX1, thrX2},  region);
+  auto const zero_right  = intersect(interval_t{thrX2, endX},   region);
+  otbMsgDevMacro("X in " << zero_left   << " <<-- 0");
+  otbMsgDevMacro("X in " << copy_middle << " <<-- copy input");
+  otbMsgDevMacro("X in " << zero_right  << " <<-- 0");
+  otbMsgDevMacro("Y in ["<<startY<<".."<<thrY1<<"[  <<--- 0");
+
+  auto const nb_z_l = zero_left.upper()   - zero_left.lower();
+  auto const nb_c_m = copy_middle.upper() - copy_middle.lower();
+  auto const nb_z_r = zero_right.upper()  - zero_right.lower();
+  assert(nb_z_l + nb_c_m + nb_z_r == sizeX);
+
+  itk::ProgressReporter progress( this, threadId, outputRegionForThread.GetNumberOfPixels() / sizeY );
+  outputIterator.GoToBegin();
+
+  // TODO: Can we consider that lines are contiguous in memory?
+  // If so, we could have only 2 fill_n and one copy_n!
+  auto y = startY;
+  for (
+      ; y < thrY1
+      ; ++y, outputIterator.NextLine())
+  {
+    // If there is any trimming of first lines, the inputIterator iterator will
+    // directly point to the right region. we shall not increment it!
+    // otbMsgDevMacro("o(" << y << ") <-- 0");
+    assert(! outputIterator.IsAtEnd());
+    outputIterator.GoToBeginOfLine();
+    std::fill_n(&outputIterator.Value(), sizeX, OutputPixelType{});
+    progress.CompletedPixel(); // Completed...Line()
+  }
+  assert(y == thrY1 || y == startY);
+  otbMsgDevMacro("Y in ["<<thrY1<<".."<<thrY2<<"[  <<--- Input");
+  inputIterator.GoToBegin();
+  for (
+      ; y < thrY2
+      ; ++y, inputIterator.NextLine(), outputIterator.NextLine())
+  {
+    // otbMsgDevMacro("o(" << y << ") <-- Input");
+    assert(! inputIterator.IsAtEnd());
+    assert(! outputIterator.IsAtEnd());
+    inputIterator.GoToBeginOfLine();
+    outputIterator.GoToBeginOfLine();
+    auto const t1 = std::fill_n(&outputIterator.Value(), nb_z_l, OutputPixelType{});
+    // If there is any trimming of first columns, the inputIterator iterator
+    // will directly point to the right region. we shall not apply an offset!
+    auto const t2 = std::copy_n(&inputIterator.Value(), nb_c_m, t1);
+    std::fill_n(t2, nb_z_r, OutputPixelType{});
+    progress.CompletedPixel(); // Completed...Line()
+  }
+  assert(y == thrY2 || y == startY);
+  otbMsgDevMacro("Y in ["<<thrY2<<".."<<endY<<"[  <<--- 0");
+  for (
+      ; y < endY
+      ; ++y, outputIterator.NextLine())
+  {
+    // If there is any trimming of last lines, the inputIterator iterator will
+    // directly point to the right region. we shall not increment it!
+    // otbMsgDevMacro("o(" << y << ") <-- 0");
+    assert(! outputIterator.IsAtEnd());
+    outputIterator.GoToBeginOfLine();
+    std::fill_n(&outputIterator.Value(), sizeX, OutputPixelType{});
+    progress.CompletedPixel(); // Completed...Line()
+  }
+  assert(y == endY);
+  otbMsgDevMacro("ThreadedGenerateData end");
+}
+
+template<typename TImage>
+typename ResetMarginFilter<TImage>::InputImageRegionType
+ResetMarginFilter<TImage>
+::OutputRegionToInputRegion(OutputImageRegionType const& srcRegion)
+{
+  auto const* output = this->GetOutput();
+  assert(output);
+
+  auto const& maxRegion = output->GetLargestPossibleRegion();
+  auto const& maxSize   = maxRegion.GetSize();
+  auto const& maxStart  = maxRegion.GetIndex();
+
+  auto const& reqRegion = srcRegion;
+  auto const& reqSize   = reqRegion.GetSize();
+  auto const& reqStart  = reqRegion.GetIndex();
+
+  // using interval_t = boost::numeric::interval<long>;
+  using interval_t = Interval;
+  auto const maxRegionX = interval_t{
+    maxStart[0]+m_thresholdX,
+    static_cast<itk::IndexValueType>(maxStart[0]+maxSize[0]-m_thresholdX)
+  };
+  auto const maxRegionY = interval_t{
+    maxStart[1]+m_thresholdYtop,
+    static_cast<itk::IndexValueType>(maxStart[1]+maxSize[1]-m_thresholdYbot)
+  };
+
+  auto const reqRegionX = interval_t::OfLength(reqStart[0], reqSize[0]);
+  auto const reqRegionY = interval_t::OfLength(reqStart[1], reqSize[1]);
+#if 0
+  otbMsgDevMacro("OutputRegionToInputRegion: "
+      << "out="<< NeatRegionLogger{reqRegion}
+      << ";    max: x="<<maxRegionX << "  y="<<maxRegionY
+      << ";    req: x="<<reqRegionX << "  y="<<reqRegionY
+      );
+#endif
+
+  auto const inRegionX = intersect(reqRegionX, maxRegionX);
+  auto const inRegionY = intersect(reqRegionY, maxRegionY);
+  // otbMsgDevMacro(" --> ∩X: " << inRegionX << " ∩Y: " << inRegionY);
+
+  const InputIndexType inStart{inRegionX.lower(), inRegionY.lower()};
+  assert(inRegionX.lower() <= inRegionX.upper());
+  assert(inRegionY.lower() <= inRegionY.upper());
+  const InputSizeType inSize{
+    static_cast<unsigned long>(inRegionX.upper()-inRegionX.lower()),
+    static_cast<unsigned long>(inRegionY.upper()-inRegionY.lower())
+  };
+  auto const inRegion = InputImageRegionType{inStart, inSize};
+  otbMsgDevMacro("OutputRegionToInputRegion: out="<< NeatRegionLogger{reqRegion}<<"   --> in="<<NeatRegionLogger{inRegion});
+  return inRegion;
+}
+
+} // otb namespace
+
+#endif  // otbResetMarginFilter_hxx
+
diff --git a/Modules/Filtering/ImageManipulation/include/otbSpectralInformationDivergenceFunctor.h b/Modules/Filtering/ImageManipulation/include/otbSpectralInformationDivergenceFunctor.h
index 5e52e0b4a23d9b0e3d61bc633aaf78606c0901ab..a45546995001f51ab0a0a38409b27283644eb666 100644
--- a/Modules/Filtering/ImageManipulation/include/otbSpectralInformationDivergenceFunctor.h
+++ b/Modules/Filtering/ImageManipulation/include/otbSpectralInformationDivergenceFunctor.h
@@ -25,6 +25,7 @@
 #include <algorithm>
 #include <vector>
 #include <numeric>
+#include <stdexcept>
 
 namespace otb
 {
@@ -37,7 +38,7 @@ namespace Functor
  *  Du, Yingzi & Chang, Chein-I & Ren, Hsuan & Chang, Chein-Chi & Jensen, James & D'Amico, Francis. (2004). "
       "New Hyperspectral Discrimination Measure for Spectral Characterization. Optical Engineering - OPT ENG. 43."
       " 1777-1786. 10.1117/1.1766301.
- * 
+ *
  * \ingroup OTBImageManipulation
  */
 template <class TInput, class TReference, class TOutput>
@@ -46,17 +47,17 @@ class SpectralInformationDivergenceFunctor
 public:
   SpectralInformationDivergenceFunctor() = default;
   virtual ~SpectralInformationDivergenceFunctor() = default;
-  
+
   using OutputValueType = typename TOutput::ValueType;
-  
+
   // Binary operator
   inline TOutput operator()(const TInput& input) const
   {
     TOutput res;
     res.SetSize(m_ReferenceProbabilities.size());
-    
+
     auto inputProbability = ComputeProbabilityMassFunction(input);
-    
+
     for (unsigned int i = 0; i< m_ReferenceProbabilities.size(); i++)
     {
       res[i] = ComputeSpectralInformationDivergence(inputProbability, m_ReferenceProbabilities[i]);
@@ -80,19 +81,19 @@ public:
       m_ReferenceProbabilities.push_back(ComputeProbabilityMassFunction(pixel));
     }
   }
-  
+
 private:
   inline TInput ComputeProbabilityMassFunction(TInput const & input) const
   {
     for (unsigned int i = 0; i < input.Size(); i++)
     {
       // Input pixel should be non negative (e.g. reflectance, radiance)
-      if (input[i] <= 0) 
+      if (input[i] <= 0)
       {
         throw std::runtime_error("Input pixels of the spectral information divergence algorithm should be strictly positive.");
       }
     }
-    
+
     return input / std::accumulate(&input[0], &input[input.Size()], 0.0);
   }
 
@@ -108,7 +109,7 @@ private:
     return sid;
   }
 
-  /** Probability mass function associated with the reference pixel */ 
+  /** Probability mass function associated with the reference pixel */
   std::vector<TReference> m_ReferenceProbabilities;
 };
 
diff --git a/Modules/Filtering/Projection/include/otbGenericRSResampleImageFilter.h b/Modules/Filtering/Projection/include/otbGenericRSResampleImageFilter.h
index 0fd11cdabe94a3215ca5b475f70cbf9ade550c0c..0bdf9b11d514bba30129dfca86b3cafa0b58acdd 100644
--- a/Modules/Filtering/Projection/include/otbGenericRSResampleImageFilter.h
+++ b/Modules/Filtering/Projection/include/otbGenericRSResampleImageFilter.h
@@ -141,7 +141,6 @@ public:
 
   /**
    * Set/Get input & output projections.
-   * Set/Get input & output keywordlist
    * The macro are not used here cause the input and the output are
    * inversed.
    */
@@ -167,7 +166,9 @@ public:
     return m_Transform->GetInputProjectionRef();
   }
 
-  /** Set/Get Input Keywordlist*/
+  /** Set/Get Input Keywordlist
+   * \deprecated
+   */
   void SetInputKeywordList(const ImageKeywordlist& kwl)
   {
     m_Transform->SetOutputKeywordList(kwl);
@@ -178,7 +179,9 @@ public:
     return m_Transform->GetOutputKeywordList();
   }
 
-  /** Set/Get output Keywordlist*/
+  /** Set/Get output Keywordlist
+   * \deprecated
+   */
   void SetOutputKeywordList(const ImageKeywordlist& kwl)
   {
     m_Transform->SetInputKeywordList(kwl);
diff --git a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx
index a7f35d2830be205ba91436c9d507a06d502880b8..364f587dc1b972df4a54e7bdbfb913bb1e71f6d9 100644
--- a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx
+++ b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx
@@ -225,7 +225,7 @@ void ExtendedFilenameToWriterOptions::SetExtendedFileName(const std::string& ext
 	{
 	  code = std::stoi(map["epsg"]);
 	}
-	catch(const std::invalid_argument& e)
+	catch(const std::invalid_argument&)
 	{
 	  itkWarningMacro("Invalid value ("
                       << map["epsg"]
diff --git a/Modules/IO/ImageIO/test/CMakeLists.txt b/Modules/IO/ImageIO/test/CMakeLists.txt
index 3a8be81881a79c08c480e3608760e1c8a6b859e1..3bc5cbfe531fdd4e02ffcfba6405a64fae9f052a 100644
--- a/Modules/IO/ImageIO/test/CMakeLists.txt
+++ b/Modules/IO/ImageIO/test/CMakeLists.txt
@@ -1306,3 +1306,14 @@ otb_add_test(NAME ioTvCompoundMetadataReaderTest
   otbWriteGeomFile
   ${INPUTDATA}/QB_Toulouse_combo.vrt
   ${TEMP}/ioTvCompoundMetadataReaderTest.tif)
+
+
+
+
+otb_add_test(NAME ioTvCompareMetadataTest COMMAND otbImageIOTestDriver
+  --compare-metadata ${EPSILON_9}
+  LARGEINPUT{SENTINEL1/S1A_S6_SLC__1SSV_20150619T195043}
+  LARGEINPUT{SENTINEL1/S1A_S6_SLC__1SSV_20150619T195043}
+  otbImageFileReaderRGBTest
+  ${INPUTDATA}/couleurs_extrait.png
+  ${TEMP}/ioImageFileReaderRGB_PNG2PNG.png )
diff --git a/Modules/IO/TestKernel/src/otbTestHelper.cxx b/Modules/IO/TestKernel/src/otbTestHelper.cxx
index 426db29ec55f9132f696067765210cddf108d657..fc00fe17d69512c41dd403199413caf2e0cb7720 100644
--- a/Modules/IO/TestKernel/src/otbTestHelper.cxx
+++ b/Modules/IO/TestKernel/src/otbTestHelper.cxx
@@ -1418,7 +1418,98 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
   return ret;
 }
 
-int TestHelper::RegressionTestMetaData(const char* testImageFilename, const char* baselineImageFilename, const double /*toleranceDiffPixelImage*/) const
+namespace
+{
+/** \fn CompareMetadataDict
+  \brief Compare two metadata dictionaries key by key. Dictionaries are assumed to be associative containers (e.g. std::map)
+  \param[in] baselineMap : reference metadata dictionary
+  \param[in] testMap : metadata dictionary to be compared
+  \param[in] reportErrors : print difference between dictionaries into srd::cerr
+  \param[in] untestedKeys : list of keys that should be ignored during comparison
+  \param[in] p bianry predicate used to compare elements (mapped type) of the two input maps
+  \return number of different elements.
+*/
+template <class MapType, class BinaryPredicate >
+int CompareMetadataDict( const MapType & baselineMap, 
+                         const MapType & testMap,
+                          bool reportErrors,
+                          std::vector< typename MapType::key_type> untestedKeys,
+                          const BinaryPredicate & p)
+{
+  auto first1 = testMap.begin();
+  auto last1 = testMap.end();
+  auto first2 = baselineMap.begin();
+  auto last2 = baselineMap.end();
+
+  if (std::distance(first1, last1) != std::distance(first2, last2))
+  {
+    if (reportErrors)
+    {
+      std::cerr << "Input metadata dictionaries have different sizes" << std::endl;
+    }
+
+    return 1;
+  }
+
+  int errorCount = 0;
+
+  while (first1 != last1)
+  {
+    if (std::find(untestedKeys.begin(), untestedKeys.end(), first1->first) == untestedKeys.end())
+    {
+      if (first1->first != first2->first)
+      {
+        errorCount++;
+        if (reportErrors)
+        {
+          std::cerr << "Metadata key " << otb::MetaData::EnumToString(first1->first) 
+                      << " does not match between test and baseline images: "
+                      << std::endl;
+        }
+        return errorCount;
+      }
+
+
+      if (!p(first1->second, first2->second))
+      {
+        errorCount++;
+        if (reportErrors)
+          std::cerr << "Metadata " << otb::MetaData::EnumToString(first1->first) 
+                    << " does not match between test and baseline images: "
+                    << std::endl
+                    << "Baseline image: " 
+                    << first1->second
+                    << std::endl
+                    << "Test image: " 
+                    << first2->second 
+                    << std::endl;
+      }
+    }
+    
+    ++first1;
+    ++first2;
+  }
+
+  return errorCount;
+}
+
+
+
+template <class MapType>
+int CompareMetadataDict( const MapType & baselineMap, 
+                         const MapType & testMap,
+                          bool reportErrors,
+                          std::vector< typename MapType::key_type> untestedKeys)
+{
+  auto p = []( const typename MapType::mapped_type & rhs, 
+               const typename MapType::mapped_type & lhs) 
+          {return rhs == lhs;};
+  return CompareMetadataDict(baselineMap, testMap, reportErrors, untestedKeys, p);
+}
+
+}
+
+int TestHelper::RegressionTestMetaData(const char* testImageFilename, const char* baselineImageFilename, const double tolerance) const
 {
   // Use the factory mechanism to read the test and baseline files and convert them to double
   typedef otb::Image<double, ITK_TEST_DIMENSION_MAX> ImageType;
@@ -1449,6 +1540,7 @@ int TestHelper::RegressionTestMetaData(const char* testImageFilename, const char
   }
 
   unsigned int errcount = 0;
+
   // The sizes of the baseline and test image must match
   ImageType::SizeType baselineSize;
   baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
@@ -1583,12 +1675,84 @@ int TestHelper::RegressionTestMetaData(const char* testImageFilename, const char
       }
     }
   }
+  
+  const auto & baselineImageMetadata = blImPtr->GetImageMetadata();
+  const auto & testImageMetadata = testImPtr->GetImageMetadata();
+
+  // Compare string keys (strict equality)
+  errcount += CompareMetadataDict(baselineImageMetadata.StringKeys,
+                                    testImageMetadata.StringKeys,
+                                    m_ReportErrors,
+                                    {});
+
+  // Compare numeric keys
+  auto compareDouble = [tolerance](double lhs, double rhs)
+        {return fabs(lhs - rhs) 
+                <= ( (fabs(lhs) < fabs(rhs) ? fabs(rhs) : fabs(lhs)) * tolerance);};
+
+  // Don't test TileHints and datatype, as these metadata are written by gdal drivers, not otb.
+  std::vector<MDNum> untestedMDNum  = {MDNum::TileHintX, MDNum::TileHintY, MDNum::DataType};
+  errcount += CompareMetadataDict(baselineImageMetadata.NumericKeys,
+                                    testImageMetadata.NumericKeys,
+                                    m_ReportErrors,
+                                    untestedMDNum,
+                                    compareDouble);
+
+  // Compare time keys (strict equality)
+  errcount += CompareMetadataDict(baselineImageMetadata.TimeKeys, 
+                                    testImageMetadata.TimeKeys,
+                                    m_ReportErrors,
+                                    {});
+
+
+  // Compare LUTs (strict equality)
+  errcount += CompareMetadataDict(baselineImageMetadata.LUT1DKeys, 
+                                    testImageMetadata.LUT1DKeys,
+                                    m_ReportErrors,
+                                    {});
+
+  errcount += CompareMetadataDict(baselineImageMetadata.LUT2DKeys, 
+                                    testImageMetadata.LUT2DKeys,
+                                    m_ReportErrors,
+                                    {});
+
+
+  // Compare extra keys (strict equality)
+  errcount += CompareMetadataDict(baselineImageMetadata.ExtraKeys, 
+                                    testImageMetadata.ExtraKeys,
+                                    m_ReportErrors,
+                                    {});
+
+
+  if (baselineImageMetadata.Has(MDGeom::RPC))
+  {
+    if (!testImageMetadata.Has(MDGeom::RPC))
+    {
+      errcount++;
+      if (m_ReportErrors)
+      {
+        std::cerr << "Test image does not have RPC coefficients" << std::endl;
+      }
+
+    }
+    if (!(boost::any_cast<Projection::RPCParam>(baselineImageMetadata[MDGeom::RPC]) 
+          == boost::any_cast<Projection::RPCParam>(testImageMetadata[MDGeom::RPC])))
+    {
+      errcount++;
+      if (m_ReportErrors)
+      {
+        std::cerr << "RPC parameters mismatch between baseline and test images" << std::endl;
+      }
+    }
+  }
+  
   if (errcount > 0)
   {
     std::cout << "<DartMeasurement name=\"MetadataError\" type=\"numeric/int\">";
     std::cout << errcount;
     std::cout << "</DartMeasurement>" << std::endl;
   }
+
   return errcount;
 }
 
diff --git a/Modules/IO/TestKernel/src/otbTestTools.cxx b/Modules/IO/TestKernel/src/otbTestTools.cxx
index f391f1ce03b903421bee21a3c7082e6892cdb3d9..45b853276020790c91389010dbdfebc7767d9bac 100644
--- a/Modules/IO/TestKernel/src/otbTestTools.cxx
+++ b/Modules/IO/TestKernel/src/otbTestTools.cxx
@@ -79,7 +79,7 @@ void PrintMetadataBase(ImageMetadataBase imdb, std::ostream& oss)
 void PrintMetadata(ImageMetadata imd, std::ostream& oss)
 {
   PrintMetadataBase(imd, oss);
-  for (ImageMetadataBase imdb : imd.Bands)
+  for (const ImageMetadataBase & imdb : imd.Bands)
     PrintMetadataBase(imdb, oss);
 }
 
diff --git a/Modules/IO/TestKernel/test/CMakeLists.txt b/Modules/IO/TestKernel/test/CMakeLists.txt
index 2800ab8599d0d9c342c8a18c22f203f9701612f9..2320848aa4efa212b87fb85ddd3f478522a62f6e 100644
--- a/Modules/IO/TestKernel/test/CMakeLists.txt
+++ b/Modules/IO/TestKernel/test/CMakeLists.txt
@@ -29,7 +29,8 @@ set(OTBTestKernelTests
   otbCompareAsciiTests.cxx
   otbCopyTest.cxx
   otbCompareAsciiTestsEpsilon3_WhiteSpace.cxx
-  otbTestKernelTestDriver.cxx )
+  otbTestKernelTestDriver.cxx 
+  otbDummyTest.cxx)
 
 add_executable(otbTestKernelTestDriver ${OTBTestKernelTests})
 target_link_libraries(otbTestKernelTestDriver ${OTBTestKernel-Test_LIBRARIES})
@@ -205,3 +206,18 @@ otb_add_test(NAME tsTvCompareImages_DifferentSizes COMMAND otbTestKernelTestDriv
   ${TEMP}/tsTvCompareImages_DifferentSizes.tif
   )
 set_property(TEST tsTvCompareImages_DifferentSizes PROPERTY WILL_FAIL true)
+
+otb_add_test(NAME tsTvCompareMetadata1 COMMAND otbTestKernelTestDriver
+  --compare-metadata 0
+  LARGEINPUT{SENTINEL1/S1A_S6_SLC__1SSV_20150619T195043}
+  LARGEINPUT{SENTINEL1/S1A_S6_SLC__1SSV_20150619T195043}
+  otbDummyTest
+  )
+
+otb_add_test(NAME tsTvCompareMetadata2 COMMAND otbTestKernelTestDriver
+  --compare-metadata 0
+  ${OTB_DATA_LARGEINPUT_ROOT}/PLEIADES-PRE/TLSE_JP2_ORTHO_DIMAPv2_PMS-N_lossy_12bits/IMG_PHR1Z_PMS_N_001/IMG_PHR1A_PMS-N_201006181052297_ORT_IPU_20111011_0619-001_R1C1.JP2
+  ${OTB_DATA_LARGEINPUT_ROOT}/PLEIADES-PRE/TLSE_TIFF_ORTHO_DIMAPv2_MS_lossless_8bits/IMG_PHR1A_MS_002/IMG_PHR1A_MS_201006181052297_ORT_IPU_20111109_7807-004_R1C1.TIF
+  otbDummyTest
+  )
+set_property(TEST tsTvCompareMetadata2 PROPERTY WILL_FAIL true)
\ No newline at end of file
diff --git a/Modules/IO/TestKernel/test/otbDummyTest.cxx b/Modules/IO/TestKernel/test/otbDummyTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..19a8d604cd8eb917f35a3a79c9ff64148eda2939
--- /dev/null
+++ b/Modules/IO/TestKernel/test/otbDummyTest.cxx
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2020 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 <iostream>
+
+// This test does nothing. It is used to test the TestKernel module
+int otbDummyTest(int argc, char* argv[])
+{ 
+  if (argc != 1)
+  {
+    std::cerr << argv[0] << "does not take any additional parameter" << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/IO/TestKernel/test/otbTestKernelTestDriver.cxx b/Modules/IO/TestKernel/test/otbTestKernelTestDriver.cxx
index 62863ae2488982a1525099afd6d604a1378572f3..356e3c73d1ba065d4e15d69446fb1b79b201c12e 100644
--- a/Modules/IO/TestKernel/test/otbTestKernelTestDriver.cxx
+++ b/Modules/IO/TestKernel/test/otbTestKernelTestDriver.cxx
@@ -31,4 +31,5 @@ void RegisterTests()
   REGISTER_TEST(otbCompareAsciiTests);
   REGISTER_TEST(otbCompareAsciiTestsEpsilon3_WhiteSpace);
   REGISTER_TEST(otbCopyTest);
+  REGISTER_TEST(otbDummyTest);
 }
diff --git a/Modules/Remote/S1TilingSupportApplications.remote.cmake b/Modules/Remote/S1TilingSupportApplications.remote.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..7bafd6d7c2cf6bbab0c34b582fa56b0681c04d4e
--- /dev/null
+++ b/Modules/Remote/S1TilingSupportApplications.remote.cmake
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2005-2020 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.
+#
+# Contact: Thierry Koleck  <thierry.koleck@cnes.fr>
+
+
+otb_fetch_module(S1TilingSupportApplications
+  "Speckle filtering of a time-serie of SAR images using the multichanel Quegan-like filter
+A more detailed description can be found on the project website:
+https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications
+"
+  GIT_REPOSITORY https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications
+  # Commit on master branch
+  GIT_TAG 2.0.0
+)
diff --git a/Modules/ThirdParty/6S/src/6SV1.0B/AEROSO.c b/Modules/ThirdParty/6S/src/6SV1.0B/AEROSO.c
index 6f4d8070e7233bf2e9b08f570b18cb33bfc48b4f..3cd88258102e08735ee71fe70b67bcd94d51cc73 100644
--- a/Modules/ThirdParty/6S/src/6SV1.0B/AEROSO.c
+++ b/Modules/ThirdParty/6S/src/6SV1.0B/AEROSO.c
@@ -19,7 +19,7 @@ Extern struct {
 #define num_quad__1 num_quad__
 
 /*OTB */
-/*Extern*/ struct {
+Extern struct {
     doublereal ph[20000]	/* was [20][1000] */, qh[20000]	/* was [20][
 	    1000] */, uh[20000]	/* was [20][1000] */;
 } sixs_aerbas__;
@@ -27,7 +27,7 @@ Extern struct {
 #define sixs_aerbas__1 sixs_aerbas__
 
 /*OTB */
-/*Extern*/ struct {
+Extern struct {
     doublereal phasel[20000]	/* was [20][1000] */, qhasel[20000]	/* 
 	    was [20][1000] */, uhasel[20000]	/* was [20][1000] */;
 } sixs_phase__;
@@ -35,14 +35,14 @@ Extern struct {
 #define sixs_phase__1 sixs_phase__
 
 /*OTB */
-/*Extern*/ struct {
+Extern struct {
     doublereal ext[20], ome[20], gasym[20], phase[20], qhase[20], uhase[20];
 } sixs_aer__;
 
 #define sixs_aer__1 sixs_aer__
 
 /*OTB */
-/*Extern*/ struct {
+Extern struct {
     doublereal ex[80]	/* was [4][20] */, sc[80]	/* was [4][20] */, 
 	    asy[80]	/* was [4][20] */, vi[4];
 } sixs_coef__;
diff --git a/Modules/ThirdParty/6S/src/6SV1.0B/DISCOM.c b/Modules/ThirdParty/6S/src/6SV1.0B/DISCOM.c
index 4057cba8d169764bd54345ed50b5ab15b3ecac85..c331b2d1053b50f2deb36dea2fc0cda6410717c8 100644
--- a/Modules/ThirdParty/6S/src/6SV1.0B/DISCOM.c
+++ b/Modules/ThirdParty/6S/src/6SV1.0B/DISCOM.c
@@ -26,7 +26,7 @@ Extern struct {
 #define sixs_phase__1 sixs_phase__
 
 /*OTB */
-/*Extern*/ struct {
+Extern struct {
     doublereal pha[1000], qha[1000], uha[1000], alphal[1001], betal[1001], 
 	    gammal[1001], zetal[1001];
 } sixs_polar__;
diff --git a/Modules/ThirdParty/6S/src/CMakeLists.txt b/Modules/ThirdParty/6S/src/CMakeLists.txt
index e174445c96777dc7ab7360a8d4440e39f5dc7b21..013d404e7ecd17e1b08967844596745c57bcfe90 100644
--- a/Modules/ThirdParty/6S/src/CMakeLists.txt
+++ b/Modules/ThirdParty/6S/src/CMakeLists.txt
@@ -66,6 +66,20 @@ list(REMOVE_ITEM LIBF2C_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/libf2c/main.c" )
 list(REMOVE_ITEM LIBF2C_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/libf2c/getarg_.c" )
 list(REMOVE_ITEM LIBF2C_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/libf2c/iargc_.c" )
 
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/aeroprof_com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/multorder_com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_del__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_ier__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/num_quad__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_aer__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_disc__com.c" )
+
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_planesim__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/mie_in__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_atm__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_ffu__com.c" )
+list(REMOVE_ITEM OTB6S_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/6SV1.0B/sixs_test__com.c" )
+
 # Main code source
 set(OTB6S_MAIN_SRCS
   otb_main6S_function.c                # otb 6S main function
diff --git a/Modules/ThirdParty/6S/src/otb_main6S_function.c b/Modules/ThirdParty/6S/src/otb_main6S_function.c
index af18dffe850da0e4c6c8a7642a467e5b9ee636b5..bde8627b6396064ebb231475fccebfb601878a72 100644
--- a/Modules/ThirdParty/6S/src/otb_main6S_function.c
+++ b/Modules/ThirdParty/6S/src/otb_main6S_function.c
@@ -13,7 +13,7 @@ extern "C" {
 /* Common Block Declarations */
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     integer nquad;
 } num_quad__;
@@ -21,7 +21,7 @@ struct {
 #define num_quad__1 num_quad__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     integer num_z__;
     doublereal alt_z__[101], taer_z__[101], taer55_z__[101];
@@ -30,7 +30,7 @@ struct {
 #define aeroprof_1 aeroprof_
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     integer iwr;
     logical ier;
@@ -39,7 +39,7 @@ struct {
 #define sixs_ier__1 sixs_ier__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal rmax, rmin;
     integer icp;
@@ -52,7 +52,7 @@ struct {
 #define mie_in__1 mie_in__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     integer igmax;
 } multorder_;
@@ -60,7 +60,7 @@ struct {
 #define multorder_1 multorder_
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal zpl[34], ppl[34], tpl[34], whpl[34], wopl[34];
 } sixs_planesim__;
@@ -68,7 +68,7 @@ struct {
 #define sixs_planesim__1 sixs_planesim__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal xacc;
 } sixs_test__;
@@ -76,7 +76,7 @@ struct {
 #define sixs_test__1 sixs_test__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal s[1501], wlinf, wlsup;
 } sixs_ffu__;
@@ -84,7 +84,7 @@ struct {
 #define sixs_ffu__1 sixs_ffu__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal delta, sigma;
 } sixs_del__;
@@ -92,7 +92,7 @@ struct {
 #define sixs_del__1 sixs_del__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal z__[34], p[34], t[34], wh[34], wo[34];
 } sixs_atm__;
@@ -100,7 +100,7 @@ struct {
 #define sixs_atm__1 sixs_atm__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal ext[20], ome[20], gasym[20], phase[20], qhase[20], uhase[20];
 } sixs_aer__;
@@ -108,7 +108,7 @@ struct {
 #define sixs_aer__1 sixs_aer__
 
 /*OTB */
-/*Extern*/
+Extern
 struct {
     doublereal roatm[60]	/* was [3][20] */, dtdir[60]	/* was [3][20]
 	     */, dtdif[60]	/* was [3][20] */, utdir[60]	/* was [3][20]
diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/AlosPalsar/AlosPalsarData.h b/Modules/ThirdParty/OssimPlugins/src/ossim/AlosPalsar/AlosPalsarData.h
index 2822a4fd68d58bb1369e2c1e3c7867e8ef217309..efd2e2801651cd3ff78cdb9b1afbe88e4abdd9e1 100644
--- a/Modules/ThirdParty/OssimPlugins/src/ossim/AlosPalsar/AlosPalsarData.h
+++ b/Modules/ThirdParty/OssimPlugins/src/ossim/AlosPalsar/AlosPalsarData.h
@@ -28,6 +28,7 @@
 #define AlosPalsarData_h
 
 #include <map>
+#include <iostream>
 
 class ossimKeywordlist;
 
diff --git a/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h b/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
index 662ae8f26ce52395715b34d0427bc2aacf0ee45f..b3f47ec26f03fdf45ec34fef5729a03a8ea94ede 100644
--- a/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
+++ b/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
@@ -433,9 +433,9 @@ HistogramModel
 template <typename TImageModel>
 void HistogramModel::template_BuildModel_M(BuildContext*)
 {
-  QTime lMain;
-  QTime lPass1;
-  QTime lPass2;
+  QElapsedTimer lMain;
+  QElapsedTimer lPass1;
+  QElapsedTimer lPass2;
 
   lMain.start();
 
diff --git a/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx b/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
index e72f6d7b3a638f81d0e5a0f365a7cad40af8b090..658600e6422fc36da73b70ac8d2a691a1ef8335b 100644
--- a/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
+++ b/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
@@ -332,7 +332,7 @@ void HistogramModel::virtual_Read(QIODevice* device)
 
   qDebug() << tr("%1: Reading histogram...").arg(QDateTime::currentDateTime().toString(Qt::ISODate));
 
-  QTime time;
+  QElapsedTimer time;
   time.start();
 
 
@@ -385,7 +385,7 @@ void HistogramModel::virtual_Write(QIODevice& device) const
 
   qDebug() << tr("%1: Writing histogram...").arg(QDateTime::currentDateTime().toString(Qt::ISODate));
 
-  QTime time;
+  QElapsedTimer time;
   time.start();
 
 #if 0
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdHistogramPlotPicker.cxx b/Modules/Visualization/MonteverdiGui/src/mvdHistogramPlotPicker.cxx
index baf0cdb134dca30d4b30a2d458a6e401dba9d9a9..badc027e1626b69796152686320d1db8a2b9aeb5 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdHistogramPlotPicker.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdHistogramPlotPicker.cxx
@@ -214,10 +214,10 @@ QwtText HistogramPlotPicker::trackerTextF(const QPointF& point) const
     return QwtPlotPicker::trackerTextF(point);
 
   if (!isActive())
-    return QwtText(QString().sprintf("%.4f, %.4f", point.x(), point.y()));
+    return QwtText(QString("%.4f, %.4f").arg(point.x()).arg(point.y()));
 
   QString text;
-  text.sprintf("%.4f", point.x());
+  text = QString("%.4f").arg(point.x());
 
   CountType start = 0;
   CountType stop  = 0;
@@ -232,7 +232,7 @@ QwtText HistogramPlotPicker::trackerTextF(const QPointF& point) const
 
         Find(m_PlotCurves[i], point.x(), c0, c1, cf);
 
-        text.append(QString().sprintf("\n[%.4f; %.4f[, %.0f", c0, c1, cf));
+        text.append(QString("\n[%.4f; %.4f[, %.0f").arg(c0).arg(c1).arg(cf));
       }
 
   return text;
diff --git a/Modules/Wrappers/SWIG/src/otbApplication.i b/Modules/Wrappers/SWIG/src/otbApplication.i
index 34b964dc5142d7b08698fa753212d75fd6f1568a..03ecf560ce300f7a82398986bcb5d4b080523ea0 100644
--- a/Modules/Wrappers/SWIG/src/otbApplication.i
+++ b/Modules/Wrappers/SWIG/src/otbApplication.i
@@ -19,7 +19,7 @@
  */
 
 
-%module otbApplication
+%module("threads"=1) otbApplication
 
 %{
 #include "itkBase.includes"
@@ -259,22 +259,22 @@ public:
 #if SWIGPYTHON
   Logger* GetLogger();
 #endif
-  unsigned long itk::Object::AddObserver(const EventObject & event, 
+  unsigned long itk::Object::AddObserver(const EventObject & event,
                                           Command * command);
 
   bool IsDeprecated();
 
 #if SWIGPYTHON
-  %extend 
+  %extend
     {
-    /** SetupLogger : Add the PythonLogOutput and setup the progress 
+    /** SetupLogger : Add the PythonLogOutput and setup the progress
      * reporting for the application */
     %pythoncode
       {
       def SetupLogger(self):
           logger = self.GetLogger()
           logger.AddLogOutput(_libraryLogOutput.GetPointer())
-          
+
           self.progressReportManager = ProgressReporterManager_New()
           self.progressReportManager.SetLogOutputCallback(_libraryLogCallback)
           self.AddObserver(AddProcessToWatchEvent(),
@@ -726,7 +726,7 @@ class ApplicationProxy(object):
       """
       if (name == "thisown"):
         return self.this.own()
-        
+
       if hasattr(Application, "__swig_getmethods__"):
         method = Application.__swig_getmethods__.get(name, None)
         if method:
@@ -757,7 +757,7 @@ class ApplicationProxy(object):
       if (name == "progressReportManager"):
         super().__setattr__(name, value)
         return
-      
+
       if hasattr(Application, "__swig_setmethods__"):
         method = Application.__swig_setmethods__.get(name, None)
         if method:
@@ -813,7 +813,7 @@ class ApplicationProxy(object):
       ImagePixelType_cfloat : SetVectorImageFromCFloatNumpyArray_,
       ImagePixelType_cdouble : SetVectorImageFromCDoubleNumpyArray_,
       }
-    
+
     def SetImageFromNumpyArray(self, paramKey, npArray, index=0):
       """
       This method takes a numpy array and set ImageIOBase of
diff --git a/Modules/Wrappers/SWIG/src/python/itkPyCommand.cxx b/Modules/Wrappers/SWIG/src/python/itkPyCommand.cxx
index 9f6acb0104b05d07bbeea2fcdfd61660ccd2c03c..23c417949dfe3ebb48c397c6cf031ae6f956f850 100644
--- a/Modules/Wrappers/SWIG/src/python/itkPyCommand.cxx
+++ b/Modules/Wrappers/SWIG/src/python/itkPyCommand.cxx
@@ -21,6 +21,27 @@
 
 #include "itkPyCommand.h"
 
+namespace
+{
+// Wrapper to automatics obtain and release GIL
+// RAII idiom
+class PyGILStateEnsure
+{
+public:
+  PyGILStateEnsure()
+    {
+      m_GIL = PyGILState_Ensure();
+    }
+  ~PyGILStateEnsure()
+    {
+      PyGILState_Release(m_GIL);
+    }
+private:
+  PyGILState_STATE m_GIL;
+};
+} // end anonymous namespace
+
+
 namespace itk
 {
 
@@ -33,6 +54,7 @@ PyCommand::~PyCommand()
 {
   if (this->obj)
   {
+    PyGILStateEnsure gil;
     Py_DECREF(this->obj);
   }
   this->obj = nullptr;
@@ -42,6 +64,7 @@ void PyCommand::SetCommandCallable(PyObject* theObj)
 {
   if (theObj != this->obj)
   {
+    PyGILStateEnsure gil;
     if (this->obj)
     {
       // get rid of our reference
@@ -89,6 +112,7 @@ void PyCommand::PyExecute()
   }
   else
   {
+    PyGILStateEnsure gil;
     PyObject* result;
 
     result = PyEval_CallObject(this->obj, (PyObject*)nullptr);
diff --git a/Modules/Wrappers/SWIG/src/python/otbPythonLogOutput.cxx b/Modules/Wrappers/SWIG/src/python/otbPythonLogOutput.cxx
index a924de7a165950cc42e840de268f4fc989a4da14..6a36c88c4cb8a2f99532188d068d718c3d623287 100644
--- a/Modules/Wrappers/SWIG/src/python/otbPythonLogOutput.cxx
+++ b/Modules/Wrappers/SWIG/src/python/otbPythonLogOutput.cxx
@@ -34,6 +34,8 @@ void PythonLogOutput::Write(double timestamp)
 
 void PythonLogOutput::Write(std::string const& content)
 {
+  // Note : Reacuiring the GIL before calling the callback doesn' seems to be
+  // necessary with thread=1 and director classes
   m_Callback->Call(content);
 }
 
diff --git a/Packaging/CMakeLists.txt b/Packaging/CMakeLists.txt
index 4a92a0d123aa2bac513e92b2a96308cf8d75563b..e4ba25158fed15615e4dfca3be97326814174762 100644
--- a/Packaging/CMakeLists.txt
+++ b/Packaging/CMakeLists.txt
@@ -106,11 +106,8 @@ if(OTB_TARGET_SYSTEM_ARCH_IS_X64)
 set(PACKAGE_ARCH "64")
 endif()
 
-
 include(${PACKAGE_OTB_SRC_DIR}/CMake/GetVersionFromGitTag.cmake)
-get_package_name(${PACKAGE_OTB_SRC_DIR} OTB_VERSION_STRING2)
-message(STATUS "OTB_VERSION_STRING2 : ${OTB_VERSION_STRING2}")
-
+get_package_name(${PACKAGE_OTB_SRC_DIR} PKG_OTB OTB_VERSION_STRING2)
 
 # This directory is important.
 # We stage/keep files that goes into final package in this directory
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index ff9974ee400b20c09cc65b642d9ce48b8aab3221..50a130783ab0c52a9b73f9363ee5eab16af13247 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,3 +1,51 @@
+OTB-v 7.2.0 - Changes since version 7.1.0 (October 02nd, 2020)
+----------------------------------------------------------------
+
+Features added:
+
+   * !736: Integrate S1Tiling support apps as official remote module by Luc Hermitte
+   * !709: Add \"epsg\" filename extension by Julien Osman
+   * !708: Spectral angle classification by Cédric Traizet
+   * !704: Pantex texture extraction application by Cédric Traizet
+
+Bugs fixed:
+
+   * !726: "Release the Python Global Interpreter Lock (GIL) during execution" by Luc Hermitte, Julien Osman and Cédric Traizet
+   * !730: Freetype and libPNG detection in QT5 by Cédric Traizet
+   * !727: FIX: StreamingMosaicFilter childs can have a different number of components per pixel at output by Rémi Cresson
+   * !725: Fix superbuild with OpenCV4 by Cédric Traizet
+   * !720: Fix spatial reference equality tests by Cédric Traizet
+   * !714: BUG: #2046 Add an epsilon margin to compute the m_ReachableOutputRegion by Julien Osman
+   * !705: Initialize seed with std::time if not user-supplied by Guillaume Pernot
+   * !696: Fix warnings by Cédric Traizet
+
+Refactoring:
+
+   * !731: Update MuParser in Superbuild by Cédric Traizet and Julie Brossard
+   * !715: Update GDAL version in superbuild (3.1.0) by Cédric Traizet
+   * !711: Updates QT5, ITK and pcre by Cédric Traizet
+   * !698: ENH: Use std::move instead of boost::move by Laurențiu Nicola
+   * !694: Update ul_lon/lat, ur_lon/lat, lr_lon/lat and ll_lon/lat for CosmoSkymed Sensor by Gaëlle USSEGLIO
+   * !683: Refactor compare image by Cédric Traizet
+
+CI:
+
+   * !721: Deploy Doxygen documentation in CI by Cédric Traizet
+   * !719: Fix Centos CI build by Cédric Traizet
+
+Documentation:
+
+   * !754: Fix spelling errors by Bas Couwenberg
+   * !738: Update PSC informations by Julien Osman
+   * !735: Correct menu instructions to open application-browser in Monteverdi by Julien Osman
+   * !728: DOC: Deprecate methods that will be removed in OTB 8.0.0 by Julien Osman
+   * !722: Clean QGIS interface documentation according migration into QGIS documentation by Mickael Savinaud
+   * !716: Error in the documenation of the QGIS plugin by Cédric Traizet
+   * !713: Update documentation for QGIS, Python and multiwriter by Cédric Traizet
+   * !702: DOC: correct filthy typo by Rémi Cresson
+   * !695: DOC: Fixed typos by guillaume pernot
+
+
 OTB-v 7.1.0 - Changes since version 7.0.0 (March 16th, 2020)
 ----------------------------------------------------------------
 
diff --git a/SuperBuild/CMake/External_gdal.cmake b/SuperBuild/CMake/External_gdal.cmake
index d099e1d63d94388cc8477714f564e2fa32e0c3b0..0ad9f33756eaccafc39bf568ac6a8c4f1cdb4262 100644
--- a/SuperBuild/CMake/External_gdal.cmake
+++ b/SuperBuild/CMake/External_gdal.cmake
@@ -81,6 +81,7 @@ if(UNIX)
     --with-ingres=no
     --with-jp2mrsid=no
     --with-kakadu=no
+    --with-kea=no
     --with-jasper=no
     --with-libgrass=no
     --with-mrsid=no
diff --git a/SuperBuild/CMake/External_itk.cmake b/SuperBuild/CMake/External_itk.cmake
index 491b68fa869dd4b8e5613a8202f0ec9a8143fb80..7d1d09d0d1398cb9796bb98f32d811e7e90c162d 100644
--- a/SuperBuild/CMake/External_itk.cmake
+++ b/SuperBuild/CMake/External_itk.cmake
@@ -146,8 +146,8 @@ set(_SB_ITK_DIR ${SB_INSTALL_PREFIX}/lib/cmake/ITK-${SB_ITK_VERSION_MAJOR}.${SB_
 
 ExternalProject_Add(ITK
   PREFIX ITK
-  URL "https://sourceforge.net/projects/itk/files/itk/4.13/InsightToolkit-4.13.2.tar.gz"
-  URL_MD5 1b6ae17dbd605d6c36564cc3d2cc1ee8
+  URL "https://github.com/InsightSoftwareConsortium/ITK/archive/v4.13.3.tar.gz"
+  URL_MD5 cc0e2d9b243f28db84b8b4a45a23f9d7
   SOURCE_DIR ${ITK_SB_SRC}
   BINARY_DIR ${ITK_SB_BUILD_DIR}
   INSTALL_DIR ${SB_INSTALL_PREFIX}
diff --git a/SuperBuild/CMake/External_openssl.cmake b/SuperBuild/CMake/External_openssl.cmake
index 6f27644f0a396a31769097eb201c23a9709ebe58..e33bb5d1e22ed8d355337ac511ba9ada20e3d0fd 100644
--- a/SuperBuild/CMake/External_openssl.cmake
+++ b/SuperBuild/CMake/External_openssl.cmake
@@ -77,6 +77,7 @@ else(UNIX)
     ${SB_ENV_CONFIGURE_CMD}
     ${OPENSSL_SB_SRC}/config ${OPENSSL_BUILD_ARCH}
     "--prefix=${SB_INSTALL_PREFIX}"
+    "--libdir=lib"
     shared
     zlib
     zlib-dynamic
diff --git a/SuperBuild/CMake/External_proj.cmake b/SuperBuild/CMake/External_proj.cmake
index dc014e321a2d7ed19ea2aa4b690d354891ad5672..d44c76b5cdb078be739cc86990d057cc04dbbabf 100644
--- a/SuperBuild/CMake/External_proj.cmake
+++ b/SuperBuild/CMake/External_proj.cmake
@@ -28,7 +28,7 @@ ADDTO_DEPENDENCIES_IF_NOT_SYSTEM(PROJ SQLITE)
 ExternalProject_Add(PROJ
   DEPENDS ${PROJ_DEPENDENCIES}
   PREFIX PROJ
-  URL "http://download.osgeo.org/proj/proj-6.2.1.tar.gz"
+  URL "http://download.osgeo.org/proj/proj-6.2.1.tar.gz"  # If we update PROJ to v7+, check option PROJ_TESTS!
   URL_MD5 9f874e227d221daf95f7858dc55dfa3e
   BINARY_DIR ${PROJ_SB_SRC}
   INSTALL_DIR ${SB_INSTALL_PREFIX}
@@ -40,6 +40,7 @@ ExternalProject_Add(PROJ
   -DBUILD_FRAMEWORKS_AND_BUNDLE:BOOL=FALSE
   -DPROJ_LIB_SUBDIR:STRING=lib
   -DPROJ_INCLUDE_SUBDIR:STRING=include
+  -DPROJ_TESTS:BOOL=OFF  # Starting with PROJ 7.0, the PROJ_TESTS option has been renamed into BUILD_TESTING
   CMAKE_COMMAND ${SB_CMAKE_COMMAND}
   LOG_DOWNLOAD 1
   LOG_CONFIGURE 1
diff --git a/SuperBuild/CMake/External_qt5.cmake b/SuperBuild/CMake/External_qt5.cmake
index 0cac35eaa222b28b4bf05ff6516e40bc08092d05..3991df39761a12048443b8e17ab80c1ae4b00c59 100644
--- a/SuperBuild/CMake/External_qt5.cmake
+++ b/SuperBuild/CMake/External_qt5.cmake
@@ -98,7 +98,11 @@ if(UNIX)
     set(QT5_SB_CONFIG "${QT5_SB_CONFIG} -no-framework")
   else()
       #Linux
-      set(QT5_SB_CONFIG "${QT5_SB_CONFIG} -no-glib -no-fontconfig")
+      # -no-use-gold-linker: https://bugreports.qt.io/browse/QTBUG-66571 
+      # Without this option the gold linker is forced if it is available
+      # In more recent versions the default linker is used instead, and this
+      # option has been removed.
+      set(QT5_SB_CONFIG "${QT5_SB_CONFIG} -no-glib -no-fontconfig -no-use-gold-linker")
   endif()
   #common for all unix
   set(QT5_SB_CONFIG "${QT5_SB_CONFIG} -no-dbus -no-icu -v")
@@ -130,8 +134,8 @@ configure_file( ${QT5_CONFIGURE_COMMAND_IN} ${QT5_CONFIGURE_COMMAND} @ONLY )
 
 ExternalProject_Add(QT5
   PREFIX QT5
-  URL "https://download.qt.io/archive/qt/5.14/5.14.1/single/qt-everywhere-src-5.14.1.tar.xz"
-  URL_MD5 781c3179410aff7ef84607214e1e91b4
+  URL "https://download.qt.io/new_archive/qt/5.11/5.11.3/single/qt-everywhere-src-5.11.3.tar.xz"
+  URL_MD5 02b353bfe7a40a8dc4274e1d17226d2b
   BINARY_DIR ${QT5_SB_BUILD_DIR}
   INSTALL_DIR ${SB_INSTALL_PREFIX}
   DOWNLOAD_DIR ${DOWNLOAD_LOCATION}
diff --git a/SuperBuild/CMake/External_qwt.cmake b/SuperBuild/CMake/External_qwt.cmake
index 9e97c83228f7d17c30c31c2695cf37d6f69633d1..0bf4da29f63bd9cec07fc8ffc04391a0f7dcaa40 100644
--- a/SuperBuild/CMake/External_qwt.cmake
+++ b/SuperBuild/CMake/External_qwt.cmake
@@ -55,8 +55,8 @@ endif()
 
 ExternalProject_Add(QWT
   PREFIX QWT
-  URL "http://downloads.sourceforge.net/project/qwt/qwt/6.1.3/qwt-6.1.3.zip"
-  URL_MD5 558911df37aee4c0c3049860e967401c
+  URL "http://downloads.sourceforge.net/project/qwt/qwt/6.1.5/qwt-6.1.5.zip"
+  URL_MD5 61a8cae35ab6201d916304ec4a6f06b8
   SOURCE_DIR ${QWT_SB_SRC}
   BINARY_DIR ${QWT_SB_SRC}
   INSTALL_DIR ${SB_INSTALL_PREFIX}
diff --git a/SuperBuild/patches/ITK/itk-3-gcc9-all.diff b/SuperBuild/patches/ITK/itk-3-gcc9-all.diff
deleted file mode 100644
index 100fac60e22f388dc84d478dc5a145031b2f27b9..0000000000000000000000000000000000000000
--- a/SuperBuild/patches/ITK/itk-3-gcc9-all.diff
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/SuperBuild/patches/ITK/itk-3-gcc9-all.diff b/SuperBuild/patches/ITK/itk-3-gcc9-all.diff
-new file mode 100644
-index 0000000000..7ff9131d9d
---- /dev/null
-+++ b/SuperBuild/patches/ITK/itk-3-gcc9-all.diff
-@@ -0,0 +1,20 @@
-+--- InsightToolkit-4.13.1.orig/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_compiler.h	2018-08-09 00:55:23.000000000 +0200
-++++ InsightToolkit-4.13.1/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_compiler.h	2019-11-12 15:49:33.893603688 +0100
-+@@ -97,6 +97,17 @@
-+ #  else
-+ #   define VCL_GCC_80
-+ #  endif
-++# elif (__GNUC__==9)
-++#  define VCL_GCC_9
-++#  if (__GNUC_MINOR__ > 2 )
-++#   define VCL_GCC_92
-++#  elif (__GNUC_MINOR__ > 1 )
-++#   define VCL_GCC_92
-++#  elif (__GNUC_MINOR__ > 0 )
-++#   define VCL_GCC_91
-++#  else
-++#   define VCL_GCC_90
-++#  endif
-+ # else
-+ #  error "Dunno about this gcc"
-+ # endif
diff --git a/SuperBuild/patches/ITK/itk-3-remove-gcc-version-debian-medteam-all.diff b/SuperBuild/patches/ITK/itk-3-remove-gcc-version-debian-medteam-all.diff
new file mode 100644
index 0000000000000000000000000000000000000000..4ee28397620219480fc06559b42dcdba41a9ef6b
--- /dev/null
+++ b/SuperBuild/patches/ITK/itk-3-remove-gcc-version-debian-medteam-all.diff
@@ -0,0 +1,104 @@
+--- a/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_compiler.h
++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/vcl_compiler.h
+@@ -43,85 +43,7 @@
+ #endif
+ 
+ #if defined(__GNUC__) && !defined(__ICC) // icc 8.0 defines __GNUC__
+-# define VCL_GCC
+-# if (__GNUC__ < 4)
+-#  error "forget it."
+-# elif (__GNUC__==4)
+-#  define VCL_GCC_4
+-#  if (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_41
+-#  else
+-#   define VCL_GCC_40
+-#  endif
+-# elif (__GNUC__==5)
+-#  define VCL_GCC_5
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_53
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_52
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_51
+-#  else
+-#   define VCL_GCC_50
+-#  endif
+-# elif (__GNUC__==6)
+-#  define VCL_GCC_6
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_63
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_62
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_61
+-#  else
+-#   define VCL_GCC_60
+-#  endif
+-# elif (__GNUC__==7)
+-#  define VCL_GCC_7
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_73
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_72
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_71
+-#  else
+-#   define VCL_GCC_70
+-#  endif
+-# elif (__GNUC__==8)
+-#  define VCL_GCC_8
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_83
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_82
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_81
+-#  else
+-#   define VCL_GCC_80
+-#  endif
+-# elif (__GNUC__==9)
+-#  define VCL_GCC_9
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_93
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_92
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_91
+-#  else
+-#   define VCL_GCC_90
+-#  endif
+-# elif (__GNUC__==10)
+-#  define VCL_GCC_10
+-#  if (__GNUC_MINOR__ > 2 )
+-#   define VCL_GCC_103
+-#  elif (__GNUC_MINOR__ > 1 )
+-#   define VCL_GCC_102
+-#  elif (__GNUC_MINOR__ > 0 )
+-#   define VCL_GCC_101
+-#  else
+-#   define VCL_GCC_100
+-#  endif
+-# else
+-#  error "Dunno about this gcc"
+-# endif
++# define VCL_GCC_73
+ #endif
+ 
+ #if defined(_WIN32) || defined(WIN32)
+--- a/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_preprocessor.cxx
++++ b/Modules/ThirdParty/VNL/src/vxl/vcl/tests/test_preprocessor.cxx
+@@ -64,6 +64,12 @@
+   ++minor_count;
+ #endif
+ 
++#ifdef VCL_GCC_73
++  ++compiler_count;
++  ++major_count;
++  ++minor_count;
++#endif
++
+ #ifdef VCL_VC
+   ++compiler_count;
+ #endif
diff --git a/SuperBuild/patches/QT5/qt5-1-jpeg-detection-win.diff b/SuperBuild/patches/QT5/qt5-1-jpeg-detection-win.diff
new file mode 100644
index 0000000000000000000000000000000000000000..b6449ca8678cb816e9abee75b3239508378813f6
--- /dev/null
+++ b/SuperBuild/patches/QT5/qt5-1-jpeg-detection-win.diff
@@ -0,0 +1,13 @@
+--- qt-everywhere-src-5.10.1/qtbase/src/gui/configure.json	2018-02-08 19:24:48.000000000 +0100
++++ QT5/qtbase/src/gui/configure.json	2018-04-10 11:50:15.631526687 +0200
+@@ -278,8 +278,7 @@
+                 "main": "jpeg_create_compress(cinfo);"
+             },
+             "sources": [
+-                { "libs": "-llibjpeg", "condition": "config.msvc" },
+-                { "libs": "-ljpeg", "condition": "!config.msvc" }
++                { "libs": "-ljpeg" }
+             ]
+         },
+         "libpng": {
+
diff --git a/SuperBuild/patches/QT5/qt5-2-png-freetype-detection-all.diff b/SuperBuild/patches/QT5/qt5-2-png-freetype-detection-all.diff
index 25ed6ae8602e71e71803ae8187d92e5f3908f750..3b6d5f0d01d40c49d604ae25157907e876025fa1 100644
--- a/SuperBuild/patches/QT5/qt5-2-png-freetype-detection-all.diff
+++ b/SuperBuild/patches/QT5/qt5-2-png-freetype-detection-all.diff
@@ -1,29 +1,24 @@
-diff -burN  qt-everywhere-src-5.14.1_orig/qtbase/src/gui/configure.json qt-everywhere-src-5.14.1/qtbase/src/gui/configure.json--- qt-everywhere-src-5.14.1_orig/qtbase/src/gui/configure.json   2020-07-27 18:13:35.779000908 +0200
-+++ qt-everywhere-src-5.14.1/qtbase/src/gui/configure.json  2020-07-27 18:18:11.226987484 +0200
-@@ -239,10 +239,10 @@
+--- qt-everywhere-src-5.10.1/qtbase/src/gui/configure.json  2018-02-08 19:24:48.000000000 +0100
++++ QT5/src/QT5/qtbase/src/gui/configure.json   2018-04-10 14:34:05.529668610 +0200
+@@ -158,8 +158,8 @@
+                 ]
              },
-             "headers": "ft2build.h",
              "sources": [
 -                { "type": "pkgConfig", "args": "freetype2" },
-                 { "type": "freetype", "libs": "-lfreetype", "condition": "!config.wasm" },
-                 { "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" },
--                { "libs": "-lfreetype" }
-+                { "libs": "-lfreetype" },
+-                { "type": "freetype", "libs": "-lfreetype" }
++                { "type": "freetype", "libs": "-lfreetype" },
 +                { "type": "pkgConfig", "args": "freetype2" }
-             ],
-             "use": [
-                 { "lib": "zlib", "condition": "features.system-zlib" }
-@@ -397,12 +397,12 @@
+             ]
+         },
+         "fontconfig": {
+@@ -289,9 +289,9 @@
+                 "main": "(void) png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);"
              },
-             "headers": "png.h",
              "sources": [
 -                { "type": "pkgConfig", "args": "libpng" },
-                 { "libs": "-llibpng16", "condition": "config.msvc" },
++                { "libs": "-lpng", "condition": "!config.msvc" },
                  { "libs": "-llibpng", "condition": "config.msvc" },
-                 { "libs": "-lpng16", "condition": "!config.msvc" },
-                 { "libs": "-lpng", "condition": "!config.msvc" },
--                { "libs": "-s USE_LIBPNG=1", "condition": "config.wasm" }
-+                { "libs": "-s USE_LIBPNG=1", "condition": "config.wasm" },
+-                { "libs": "-lpng", "condition": "!config.msvc" }
 +                { "type": "pkgConfig", "args": "libpng" }
              ],
              "use": [
diff --git a/SuperBuild/patches/QT5/qt5-1-opengl_include_dir-macx.diff b/SuperBuild/patches/QT5/qt5-3-opengl_include_dir-macx.diff
similarity index 100%
rename from SuperBuild/patches/QT5/qt5-1-opengl_include_dir-macx.diff
rename to SuperBuild/patches/QT5/qt5-3-opengl_include_dir-macx.diff
diff --git a/SuperBuild/patches/QT5/qt5-3-undefined-references-linux.diff b/SuperBuild/patches/QT5/qt5-4-undefined-references-linux.diff
similarity index 73%
rename from SuperBuild/patches/QT5/qt5-3-undefined-references-linux.diff
rename to SuperBuild/patches/QT5/qt5-4-undefined-references-linux.diff
index 97b3de7f49974133a2c97f7a3a8ff8db0147e072..2beb06c57b39023aad8dd378303a68f433b8ee16 100644
--- a/SuperBuild/patches/QT5/qt5-3-undefined-references-linux.diff
+++ b/SuperBuild/patches/QT5/qt5-4-undefined-references-linux.diff
@@ -65,3 +65,26 @@ diff -burN  qt-everywhere-src-5.14.1/qttools/src/assistant/assistant/assistant.p
 +LIBS += -lpng
  
  load(qt_app)
+
+--- qt-everywhere-src-5.11.3-orig/qttools/src/assistant/qcollectiongenerator/qcollectiongenerator.pro   2018-11-23 08:41:24.000000000 +0100
++++ qt-everywhere-src-5.11.3/qttools/src/assistant/qcollectiongenerator/qcollectiongenerator.pro    2020-09-04 15:42:48.968480227 +0200
+@@ -1,5 +1,8 @@
+ QT += network help-private
+ TARGET = qcollectiongenerator
++
++LIBS += -lpng
++
+ SOURCES += ../shared/helpgenerator.cpp \
+     main.cpp \
+     ../shared/collectionconfiguration.cpp
+
+--- qt-everywhere-src-5.11.3-orig/qttools/src/assistant/qhelpconverter/qhelpconverter.pro   2018-11-23 08:41:24.000000000 +0100
++++ qt-everywhere-src-5.11.3/qttools/src/assistant/qhelpconverter/qhelpconverter.pro    2020-09-04 15:48:05.003811338 +0200
+@@ -1,5 +1,7 @@
+ QT += help widgets
+ 
++LIBS += -lpng
++
+ SOURCES += conversionwizard.cpp \
+            inputpage.cpp \
+            generalpage.cpp \
diff --git a/SuperBuild/patches/QT5/qt5-5-gcc9-mersenne_twister-all.diff b/SuperBuild/patches/QT5/qt5-5-gcc9-mersenne_twister-all.diff
new file mode 100644
index 0000000000000000000000000000000000000000..f9f1bcfbf464b253d6970300bf6da48fa1159756
--- /dev/null
+++ b/SuperBuild/patches/QT5/qt5-5-gcc9-mersenne_twister-all.diff
@@ -0,0 +1,13 @@
+--- a/qtbase/src/corelib/global/qrandom.cpp
++++ b/qtbase/src/corelib/global/qrandom.cpp
+@@ -218,6 +218,7 @@ struct QRandomGenerator::SystemGenerator
+ #endif // Q_OS_WINRT
+ 
+     static SystemGenerator &self();
++    typedef quint32 result_type;
+     void generate(quint32 *begin, quint32 *end) Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept);
+ 
+     // For std::mersenne_twister_engine implementations that use something
+-- 
+2.16.3
+
diff --git a/SuperBuild/patches/QWT/qwt-1-releaseBuild-all.diff b/SuperBuild/patches/QWT/qwt-1-releaseBuild-all.diff
index 3d4f6a55954d6fbeeb3a69ba3d66ac4faa7fd9c5..ad34cd24bdfcf46174ac2699e8bfd285ab5c184c 100644
--- a/SuperBuild/patches/QWT/qwt-1-releaseBuild-all.diff
+++ b/SuperBuild/patches/QWT/qwt-1-releaseBuild-all.diff
@@ -8,7 +8,7 @@ diff -burN qwt-6.1.3-orig/qwtbuild.pri qwt-6.1.3/qwtbuild.pri
 -    # On Windows you can't mix release and debug libraries.
 -    # The designer is built in release mode. If you like to use it
 -    # you need a release version. For your own application development you
--    # might need a debug version. 
+-    # might need a debug version.
 -    # Enable debug_and_release + build_all if you want to build both.
  
 -    CONFIG           += debug_and_release