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