From: Jochen Sprickerhof Date: Fri, 14 Aug 2020 19:55:24 +0000 (+0200) Subject: New upstream version 1.11.1+dfsg X-Git-Tag: archive/raspbian/1.14.0+dfsg-2+rpi1^2~10^2~4 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=5709ff5a246ba14d3ce28d5c6a4f0d1c4d2e0f0f;p=pcl.git New upstream version 1.11.1+dfsg --- diff --git a/.ci/azure-pipelines/azure-pipelines.yaml b/.ci/azure-pipelines/azure-pipelines.yaml index 77796e3a..a0bf28f0 100644 --- a/.ci/azure-pipelines/azure-pipelines.yaml +++ b/.ci/azure-pipelines/azure-pipelines.yaml @@ -4,6 +4,8 @@ resources: image: pointcloudlibrary/fmt - container: env1604 image: pointcloudlibrary/env:16.04 + - container: env1804 + image: pointcloudlibrary/env:18.04 - container: env2004 image: pointcloudlibrary/env:20.04 - container: doc @@ -14,29 +16,143 @@ stages: displayName: Formatting jobs: - template: formatting.yaml - - stage: build_ubuntu - displayName: Build Ubuntu + + - stage: build_gcc + displayName: Build GCC dependsOn: formatting jobs: - - template: build-ubuntu.yaml - - stage: build_osx - displayName: Build macOS + - job: ubuntu + displayName: Ubuntu + pool: + vmImage: 'Ubuntu 16.04' + strategy: + matrix: + 16.04 GCC: + CONTAINER: env1604 + CC: gcc + CXX: g++ + BUILD_GPU: OFF + CMAKE_ARGS: '-DPCL_WARNINGS_ARE_ERRORS=ON' + 20.04 GCC: + CONTAINER: env2004 + CC: gcc + CXX: g++ + BUILD_GPU: OFF + CMAKE_ARGS: '' + container: $[ variables['CONTAINER'] ] + timeoutInMinutes: 0 + variables: + BUILD_DIR: '$(Agent.BuildDirectory)/build' + CMAKE_CXX_FLAGS: '-Wall -Wextra' + steps: + - template: build/ubuntu.yaml + + - stage: build_clang + displayName: Build Clang dependsOn: formatting jobs: - - template: build-macos.yaml - - stage: build_windows - displayName: Build Windows + - job: osx + displayName: macOS + pool: + vmImage: '$(VMIMAGE)' + strategy: + matrix: + Catalina 10.15: + VMIMAGE: 'macOS-10.15' + OSX_VERSION: '10.15' + Mojave 10.14: + VMIMAGE: 'macOS-10.14' + OSX_VERSION: '10.14' + timeoutInMinutes: 0 + variables: + BUILD_DIR: '$(Agent.WorkFolder)/build' + GOOGLE_TEST_DIR: '$(Agent.WorkFolder)/googletest' + CMAKE_CXX_FLAGS: '-Wall -Wextra -Wabi -Werror -Wno-error=deprecated-declarations' + steps: + - template: build/macos.yaml + - job: ubuntu + displayName: Ubuntu + # Placement of Ubuntu Clang job after macOS ensures an extra parallel job doesn't need to be created. + # Total time per run remains same since macOS is quicker so it finishes earlier, and remaining time is used by this job + # Therefore, number of parallel jobs and total run time of entire pipeline remains unchanged even after addition of this job + dependsOn: osx + condition: succeededOrFailed() + pool: + vmImage: 'Ubuntu 16.04' + strategy: + matrix: + 18.04 Clang: + CONTAINER: env1804 + CC: clang + CXX: clang++ + BUILD_GPU: ON + CMAKE_ARGS: '' + container: $[ variables['CONTAINER'] ] + timeoutInMinutes: 0 + variables: + BUILD_DIR: '$(Agent.BuildDirectory)/build' + CMAKE_CXX_FLAGS: '-Wall -Wextra' + steps: + - template: build/ubuntu.yaml + - job: ubuntu_indices + displayName: Ubuntu Indices + # Test 64 bit & unsigned indices + dependsOn: osx + condition: succeededOrFailed() + pool: + vmImage: 'Ubuntu 16.04' + strategy: + matrix: + 18.04 Clang: + CONTAINER: env1804 + CC: clang + CXX: clang++ + INDEX_SIGNED: OFF + INDEX_SIZE: 64 + CMAKE_ARGS: '' + container: $[ variables['CONTAINER'] ] + timeoutInMinutes: 0 + variables: + BUILD_DIR: '$(Agent.BuildDirectory)/build' + CMAKE_CXX_FLAGS: '-Wall -Wextra' + steps: + - template: build/ubuntu_indices.yaml + + - stage: build_msvc + displayName: Build MSVC dependsOn: formatting jobs: - - template: build-windows.yaml + - job: vs2017 + displayName: Windows VS2017 Build + pool: + vmImage: 'vs2017-win2016' + strategy: + matrix: + x86: + PLATFORM: 'x86' + ARCHITECTURE: 'x86' + GENERATOR: 'Visual Studio 15 2017' + x64: + PLATFORM: 'x64' + ARCHITECTURE: 'x86_amd64' + GENERATOR: 'Visual Studio 15 2017 Win64' + timeoutInMinutes: 0 + variables: + BUILD_DIR: '$(Agent.WorkFolder)\build' + CONFIGURATION: 'Release' + VCPKG_ROOT: 'C:\vcpkg' + steps: + - template: build/windows.yaml + - stage: documentation displayName: Documentation dependsOn: [] jobs: - template: documentation.yaml + - stage: tutorials displayName: Tutorials - dependsOn: build_ubuntu + dependsOn: build_gcc jobs: - template: tutorials.yaml diff --git a/.ci/azure-pipelines/build-macos.yaml b/.ci/azure-pipelines/build-macos.yaml deleted file mode 100644 index 6176b518..00000000 --- a/.ci/azure-pipelines/build-macos.yaml +++ /dev/null @@ -1,65 +0,0 @@ -jobs: - - job: osx - displayName: macOS - pool: - vmImage: '$(VMIMAGE)' - strategy: - matrix: - Catalina 10.15: - VMIMAGE: 'macOS-10.15' - OSX_VERSION: '10.15' - Mojave 10.14: - VMIMAGE: 'macOS-10.14' - OSX_VERSION: '10.14' - timeoutInMinutes: 0 - variables: - BUILD_DIR: '$(Agent.WorkFolder)/build' - GOOGLE_TEST_DIR: '$(Agent.WorkFolder)/googletest' - CMAKE_CXX_FLAGS: '-Wall -Wextra -Werror -Wabi' - steps: - - checkout: self - # find the commit hash on a quick non-forced update too - fetchDepth: 10 - - script: | - brew install pkg-config qt5 libpcap brewsci/science/openni libomp - brew install vtk --with-qt --without-python@2 - brew install --only-dependencies pcl - git clone https://github.com/abseil/googletest.git $GOOGLE_TEST_DIR # the official endpoint changed to abseil/googletest - cd $GOOGLE_TEST_DIR && git checkout release-1.8.1 - displayName: 'Install Dependencies' - - script: | - mkdir $BUILD_DIR && cd $BUILD_DIR - # Surface switched off due to OpenGL deprecation on Mac - cmake $(Build.SourcesDirectory) \ - -DCMAKE_BUILD_TYPE="Release" \ - -DCMAKE_OSX_SYSROOT="/Library/Developer/CommandLineTools/SDKs/MacOSX$(OSX_VERSION).sdk" \ - -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ - -DGTEST_SRC_DIR="$GOOGLE_TEST_DIR/googletest" \ - -DGTEST_INCLUDE_DIR="$GOOGLE_TEST_DIR/googletest/include" \ - -DQt5_DIR=/usr/local/opt/qt5/lib/cmake/Qt5 \ - -DPCL_ONLY_CORE_POINT_TYPES=ON \ - -DBUILD_simulation=ON \ - -DBUILD_surface=OFF \ - -DBUILD_global_tests=ON \ - -DBUILD_examples=ON \ - -DBUILD_tools=ON \ - -DBUILD_apps=ON \ - -DBUILD_apps_3d_rec_framework=ON \ - -DBUILD_apps_cloud_composer=ON \ - -DBUILD_apps_in_hand_scanner=ON \ - -DBUILD_apps_modeler=ON \ - -DBUILD_apps_point_cloud_editor=ON - displayName: 'CMake Configuration' - - script: | - cd $BUILD_DIR - cmake --build . -- -j2 - displayName: 'Build Library' - - script: cd $BUILD_DIR && cmake --build . -- tests - displayName: 'Run Unit Tests' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'CTest' - testResultsFiles: '**/Test*.xml' - searchFolder: '$(Agent.WorkFolder)/build' - condition: succeededOrFailed() - diff --git a/.ci/azure-pipelines/build-ubuntu.yaml b/.ci/azure-pipelines/build-ubuntu.yaml deleted file mode 100644 index aec0d860..00000000 --- a/.ci/azure-pipelines/build-ubuntu.yaml +++ /dev/null @@ -1,69 +0,0 @@ -jobs: - - job: ubuntu - displayName: Ubuntu - pool: - vmImage: 'Ubuntu 16.04' - strategy: - matrix: - # 16.04 Clang: - # CONTAINER: env1604 - # CC: clang - # CXX: clang++ - # CMAKE_ARGS: '-DPCL_WARNINGS_ARE_ERRORS=ON' - # 20.04 Clang: - # CONTAINER: env2004 - # CC: clang - # CXX: clang++ - # CMAKE_ARGS: '' - 16.04 GCC: - CONTAINER: env1604 - CC: gcc - CXX: g++ - CMAKE_ARGS: '-DPCL_WARNINGS_ARE_ERRORS=ON' - 20.04 GCC: - CONTAINER: env2004 - CC: gcc - CXX: g++ - CMAKE_ARGS: '' - container: $[ variables['CONTAINER'] ] - timeoutInMinutes: 0 - variables: - BUILD_DIR: '$(Agent.BuildDirectory)/build' - CMAKE_CXX_FLAGS: '-Wall -Wextra' - steps: - - checkout: self - # find the commit hash on a quick non-forced update too - fetchDepth: 10 - - script: | - mkdir $BUILD_DIR && cd $BUILD_DIR - cmake $(Build.SourcesDirectory) $(CMAKE_ARGS) \ - -DCMAKE_BUILD_TYPE="Release" \ - -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ - -DPCL_ONLY_CORE_POINT_TYPES=ON \ - -DBUILD_simulation=ON \ - -DBUILD_surface_on_nurbs=ON \ - -DBUILD_global_tests=ON \ - -DBUILD_examples=ON \ - -DBUILD_tools=ON \ - -DBUILD_apps=ON \ - -DBUILD_apps_3d_rec_framework=ON \ - -DBUILD_apps_cloud_composer=ON \ - -DBUILD_apps_in_hand_scanner=ON \ - -DBUILD_apps_modeler=ON \ - -DBUILD_apps_point_cloud_editor=ON - # Temporary fix to ensure no tests are skipped - cmake $(Build.SourcesDirectory) - displayName: 'CMake Configuration' - - script: | - cd $BUILD_DIR - cmake --build . -- -j2 - displayName: 'Build Library' - - script: | - cd $BUILD_DIR && cmake --build . -- tests - displayName: 'Run Unit Tests' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'CTest' - testResultsFiles: '**/Test*.xml' - searchFolder: '$(Agent.BuildDirectory)/build' - condition: succeededOrFailed() diff --git a/.ci/azure-pipelines/build-windows.yaml b/.ci/azure-pipelines/build-windows.yaml deleted file mode 100644 index 07cc01a5..00000000 --- a/.ci/azure-pipelines/build-windows.yaml +++ /dev/null @@ -1,65 +0,0 @@ -jobs: - - job: vs2017 - displayName: Windows VS2017 Build - pool: - vmImage: 'vs2017-win2016' - strategy: - matrix: - x86: - PLATFORM: 'x86' - ARCHITECTURE: 'x86' - GENERATOR: 'Visual Studio 15 2017' - x64: - PLATFORM: 'x64' - ARCHITECTURE: 'x86_amd64' - GENERATOR: 'Visual Studio 15 2017 Win64' - timeoutInMinutes: 0 - variables: - BUILD_DIR: '$(Agent.WorkFolder)\build' - CONFIGURATION: 'Release' - VCPKG_ROOT: 'C:\vcpkg' - steps: - - checkout: self - # find the commit hash on a quick non-forced update too - fetchDepth: 10 - - script: | - echo ##vso[task.setvariable variable=BOOST_ROOT]%BOOST_ROOT_1_69_0% - displayName: 'Set BOOST_ROOT Environment Variable' - - script: | - echo ##vso[task.prependpath]%BOOST_ROOT_1_69_0%\lib - displayName: 'Include Boost Libraries In System PATH' - - script: | - set - displayName: 'Print Environment Variables' - - script: | - vcpkg.exe install eigen3 flann gtest qhull --triplet %PLATFORM%-windows && vcpkg.exe list - displayName: 'Install C++ Dependencies Via Vcpkg' - - script: | - rmdir %VCPKG_ROOT%\downloads /S /Q - rmdir %VCPKG_ROOT%\packages /S /Q - displayName: 'Free Up Space' - - script: | - mkdir %BUILD_DIR% && cd %BUILD_DIR% - cmake $(Build.SourcesDirectory) ^ - -G"%GENERATOR%" ^ - -DCMAKE_BUILD_TYPE="Release" ^ - -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake ^ - -DVCPKG_APPLOCAL_DEPS=ON ^ - -DPCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32=ON ^ - -DPCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32=ON ^ - -DPCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32=ON ^ - -DBUILD_global_tests=ON ^ - -DBUILD_tools=OFF ^ - -DBUILD_surface_on_nurbs=ON - displayName: 'CMake Configuration' - - script: cd %BUILD_DIR% && cmake --build . --config %CONFIGURATION% - displayName: 'Build Library' - - script: cd %BUILD_DIR% && cmake --build . --target tests --config %CONFIGURATION% - displayName: 'Run Unit Tests' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'CTest' - testResultsFiles: '**/Test*.xml' - searchFolder: '$(Agent.WorkFolder)\build' - condition: succeededOrFailed() - diff --git a/.ci/azure-pipelines/build/macos.yaml b/.ci/azure-pipelines/build/macos.yaml new file mode 100644 index 00000000..985aaa35 --- /dev/null +++ b/.ci/azure-pipelines/build/macos.yaml @@ -0,0 +1,43 @@ +steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - script: | + brew install cmake pkg-config boost eigen flann glew libusb qhull vtk glew qt5 libpcap libomp brewsci/science/openni + git clone https://github.com/abseil/googletest.git $GOOGLE_TEST_DIR # the official endpoint changed to abseil/googletest + cd $GOOGLE_TEST_DIR && git checkout release-1.8.1 + displayName: 'Install Dependencies' + - script: | + mkdir $BUILD_DIR && cd $BUILD_DIR + cmake $(Build.SourcesDirectory) \ + -DCMAKE_BUILD_TYPE="MinSizeRel" \ + -DCMAKE_OSX_SYSROOT="/Library/Developer/CommandLineTools/SDKs/MacOSX$(OSX_VERSION).sdk" \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ + -DGTEST_SRC_DIR="$GOOGLE_TEST_DIR/googletest" \ + -DGTEST_INCLUDE_DIR="$GOOGLE_TEST_DIR/googletest/include" \ + -DQt5_DIR=/usr/local/opt/qt5/lib/cmake/Qt5 \ + -DPCL_ONLY_CORE_POINT_TYPES=ON \ + -DBUILD_simulation=ON \ + -DBUILD_global_tests=ON \ + -DBUILD_examples=ON \ + -DBUILD_tools=ON \ + -DBUILD_apps=ON \ + -DBUILD_apps_3d_rec_framework=ON \ + -DBUILD_apps_cloud_composer=ON \ + -DBUILD_apps_in_hand_scanner=ON \ + -DBUILD_apps_modeler=ON \ + -DBUILD_apps_point_cloud_editor=ON + displayName: 'CMake Configuration' + - script: | + cd $BUILD_DIR + cmake --build . -- -j2 + displayName: 'Build Library' + - script: cd $BUILD_DIR && cmake --build . -- tests + displayName: 'Run Unit Tests' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'CTest' + testResultsFiles: '**/Test*.xml' + searchFolder: '$(Agent.WorkFolder)/build' + condition: succeededOrFailed() + diff --git a/.ci/azure-pipelines/build/ubuntu.yaml b/.ci/azure-pipelines/build/ubuntu.yaml new file mode 100644 index 00000000..559dfddd --- /dev/null +++ b/.ci/azure-pipelines/build/ubuntu.yaml @@ -0,0 +1,44 @@ +steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - script: | + mkdir $BUILD_DIR && cd $BUILD_DIR + cmake $(Build.SourcesDirectory) $(CMAKE_ARGS) \ + -DCMAKE_BUILD_TYPE="MinSizeRel" \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ + -DPCL_ONLY_CORE_POINT_TYPES=ON \ + -DPCL_DISABLE_GPU_TESTS=ON \ + -DBUILD_simulation=ON \ + -DBUILD_surface_on_nurbs=ON \ + -DBUILD_global_tests=ON \ + -DBUILD_examples=ON \ + -DBUILD_tools=ON \ + -DBUILD_apps=ON \ + -DBUILD_apps_3d_rec_framework=ON \ + -DBUILD_apps_cloud_composer=ON \ + -DBUILD_apps_in_hand_scanner=ON \ + -DBUILD_apps_modeler=ON \ + -DBUILD_apps_point_cloud_editor=ON \ + -DBUILD_CUDA=$BUILD_GPU \ + -DBUILD_GPU=$BUILD_GPU \ + -DBUILD_cuda_io=$BUILD_GPU \ + -DBUILD_gpu_tracking=$BUILD_GPU \ + -DBUILD_gpu_surface=$BUILD_GPU \ + -DBUILD_gpu_people=$BUILD_GPU + # Temporary fix to ensure no tests are skipped + cmake $(Build.SourcesDirectory) + displayName: 'CMake Configuration' + - script: | + cd $BUILD_DIR + cmake --build . -- -j2 + displayName: 'Build Library' + - script: | + cd $BUILD_DIR && cmake --build . -- tests + displayName: 'Run Unit Tests' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'CTest' + testResultsFiles: '**/Test*.xml' + searchFolder: '$(Agent.BuildDirectory)/build' + condition: succeededOrFailed() diff --git a/.ci/azure-pipelines/build/ubuntu_indices.yaml b/.ci/azure-pipelines/build/ubuntu_indices.yaml new file mode 100644 index 00000000..28f8340d --- /dev/null +++ b/.ci/azure-pipelines/build/ubuntu_indices.yaml @@ -0,0 +1,34 @@ +steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - script: | + mkdir $BUILD_DIR && cd $BUILD_DIR + cmake $(Build.SourcesDirectory) $(CMAKE_ARGS) \ + -DCMAKE_BUILD_TYPE="MinSizeRel" \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ + -DPCL_ONLY_CORE_POINT_TYPES=ON \ + -DPCL_INDEX_SIGNED=$INDEX_SIGNED \ + -DPCL_INDEX_SIZE=$INDEX_SIZE \ + -DBUILD_geometry=OFF \ + -DBUILD_tools=OFF \ + -DBUILD_kdtree=OFF \ + -DBUILD_ml=OFF \ + -DBUILD_octree=OFF \ + -DBUILD_global_tests=ON + # Temporary fix to ensure no tests are skipped + cmake $(Build.SourcesDirectory) + displayName: 'CMake Configuration' + - script: | + cd $BUILD_DIR + cmake --build . -- -j2 + displayName: 'Build Library' + - script: | + cd $BUILD_DIR && cmake --build . -- tests + displayName: 'Run Unit Tests' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'CTest' + testResultsFiles: '**/Test*.xml' + searchFolder: '$(Agent.BuildDirectory)/build' + condition: succeededOrFailed() diff --git a/.ci/azure-pipelines/build/windows.yaml b/.ci/azure-pipelines/build/windows.yaml new file mode 100644 index 00000000..b2a884c0 --- /dev/null +++ b/.ci/azure-pipelines/build/windows.yaml @@ -0,0 +1,45 @@ +steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - script: | + echo ##vso[task.setvariable variable=BOOST_ROOT]%BOOST_ROOT_1_69_0% + displayName: 'Set BOOST_ROOT Environment Variable' + - script: | + echo ##vso[task.prependpath]%BOOST_ROOT_1_69_0%\lib + displayName: 'Include Boost Libraries In System PATH' + - script: | + set + displayName: 'Print Environment Variables' + - script: | + vcpkg.exe install eigen3 flann gtest qhull --triplet %PLATFORM%-windows && vcpkg.exe list + displayName: 'Install C++ Dependencies Via Vcpkg' + - script: | + rmdir %VCPKG_ROOT%\downloads /S /Q + rmdir %VCPKG_ROOT%\packages /S /Q + displayName: 'Free Up Space' + - script: | + mkdir %BUILD_DIR% && cd %BUILD_DIR% + cmake $(Build.SourcesDirectory) ^ + -G"%GENERATOR%" ^ + -DCMAKE_BUILD_TYPE="MinSizeRel" ^ + -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake ^ + -DVCPKG_APPLOCAL_DEPS=ON ^ + -DPCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32=ON ^ + -DPCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32=ON ^ + -DPCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32=ON ^ + -DBUILD_global_tests=ON ^ + -DBUILD_tools=OFF ^ + -DBUILD_surface_on_nurbs=ON + displayName: 'CMake Configuration' + - script: cd %BUILD_DIR% && cmake --build . --config %CONFIGURATION% + displayName: 'Build Library' + - script: cd %BUILD_DIR% && cmake --build . --target tests --config %CONFIGURATION% + displayName: 'Run Unit Tests' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'CTest' + testResultsFiles: '**/Test*.xml' + searchFolder: '$(Agent.WorkFolder)\build' + condition: succeededOrFailed() + diff --git a/.ci/azure-pipelines/documentation.yaml b/.ci/azure-pipelines/documentation.yaml index f6f93d15..9eaacba3 100644 --- a/.ci/azure-pipelines/documentation.yaml +++ b/.ci/azure-pipelines/documentation.yaml @@ -27,7 +27,6 @@ jobs: mkdir $BUILD_DIR && cd $BUILD_DIR cmake $(Build.SourcesDirectory) \ -DDOXYGEN_USE_SHORT_NAMES=OFF \ - -DSPHINX_HTML_FILE_SUFFIX=php \ -DWITH_DOCS=ON \ -DWITH_TUTORIALS=ON displayName: 'CMake Configuration' diff --git a/.ci/azure-pipelines/env.yml b/.ci/azure-pipelines/env.yml index d55079df..d3c6f7aa 100644 --- a/.ci/azure-pipelines/env.yml +++ b/.ci/azure-pipelines/env.yml @@ -42,7 +42,7 @@ jobs: Ubuntu 16.04: CUDA_VERSION: 9.2 UBUNTU_DISTRO: 16.04 - USE_CUDA: true + USE_CUDA: false VTK_VERSION: 6 tag: 16.04 Ubuntu 18.04: diff --git a/.ci/azure-pipelines/release.yaml b/.ci/azure-pipelines/release.yaml new file mode 100644 index 00000000..225c846f --- /dev/null +++ b/.ci/azure-pipelines/release.yaml @@ -0,0 +1,213 @@ +# Release PCL steps: +# 1. Check tests: +# * debian:latest +# * perception_pcl +# 2. Package for +# * MacOS +# * tar source release +# * Windows Installers + +trigger: none + +resources: +- repo: self + +variables: + dockerHub: "PointCloudLibrary@hub.docker.com" + dockerHubID: "pointcloudlibrary" + # VERSION and RC need to be provided via the UI + # UI priority is the lowest and can't override the file data + # RC: 0 # number of pre-release + # VERSION: 1.99 + +stages: +- stage: Info + displayName: "Version" + jobs: + - job: additional_info + displayName: "More Info" + pool: + vmImage: 'ubuntu-latest' + steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - script: | + echo "Prev release: $(git tag | sort -rV | head -1 | cut -d- -f 2)" + echo "Current release: "$(VERSION)-rc$(RC) + if [ -z $VERSION ] || [ -z $RC ]; then + echo "Bad version and release candidate number" + exit 3 + fi + displayName: "Test for and display version info" +- stage: Debian + dependsOn: ["Info"] + jobs: + - job: BuildDebian + displayName: "Build Debian Latest" + timeoutInMinutes: 360 + pool: + vmImage: 'ubuntu-latest' + variables: + tag: "release" + steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - task: Docker@2 + displayName: "Build docker image" + inputs: + command: build + arguments: | + --no-cache + -t $(dockerHubID)/release:$(tag) + dockerfile: '$(Build.SourcesDirectory)/.dev/docker/release/Dockerfile' + tags: "$(tag)" +- stage: ROS + dependsOn: ["Info"] + jobs: + - job: PerceptionPCL + displayName: "perception_pcl compile" + timeoutInMinutes: 360 + pool: + vmImage: 'ubuntu-latest' + strategy: + matrix: + # Only ROS Melodic works with current releases of PCL + # Kinetic has stopped supporting any version later than PCL 1.7.2 + ROS Melodic: + flavor: "melodic" + variables: + tag: "ros" + steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + - task: Docker@2 + displayName: "Build docker image" + inputs: + command: build + arguments: | + --no-cache + --build-arg flavor=$(flavor) + -t $(dockerHubID)/release:$(tag) + dockerfile: '$(Build.SourcesDirectory)/.dev/docker/perception_pcl_ros/Dockerfile' + buildContext: '$(Build.SourcesDirectory)/.dev/docker/perception_pcl_ros' + tags: "$(tag)" +- stage: Prepare + dependsOn: ["Debian", "ROS"] + jobs: + - job: src_code + displayName: "Package Source Code" + timeoutInMinutes: 360 + pool: + vmImage: 'ubuntu-latest' + variables: + PUBLISH_LOCATION: '$(Build.ArtifactStagingDirectory)' + SOURCE_LOCATION: '$(Build.SourcesDirectory)' + steps: + - checkout: self + # find the commit hash on a quick non-forced update too + fetchDepth: 10 + path: 'pcl' + - task: Bash@3 + displayName: "Remove git files" + inputs: + targetType: 'inline' + script: 'rm -fr ./.git' + workingDirectory: '$(SOURCE_LOCATION)' + failOnStderr: true + - task: ArchiveFiles@2 + displayName: "Create release archive (.tar.gz)" + inputs: + rootFolderOrFile: '$(SOURCE_LOCATION)' + includeRootFolder: true + archiveType: 'tar' + archiveFile: '$(PUBLISH_LOCATION)/source.tar.gz' + replaceExistingArchive: true + verbose: true + - task: ArchiveFiles@2 + displayName: "Create release archive (.zip)" + inputs: + rootFolderOrFile: '$(SOURCE_LOCATION)' + includeRootFolder: true + archiveType: 'zip' + archiveFile: '$(PUBLISH_LOCATION)/source.zip' + replaceExistingArchive: true + verbose: true + - script: | + for file in $(ls "$(PUBLISH_LOCATION)/"); do + sha256sum "$(PUBLISH_LOCATION)"/"${file}" >> $(PUBLISH_LOCATION)/sha256_checksums.txt + sha512sum "$(PUBLISH_LOCATION)"/"${file}" >> $(PUBLISH_LOCATION)/sha512_checksums.txt + done + echo "SHA 256 Checksums:" + cat $(PUBLISH_LOCATION)/sha256_checksums.txt + echo "SHA 512 Checksums:" + cat $(PUBLISH_LOCATION)/sha512_checksums.txt + displayName: "Generate checksum" + - task: PublishBuildArtifacts@1 + displayName: "Publish archive" + inputs: + PathtoPublish: '$(PUBLISH_LOCATION)/' + ArtifactName: 'source' + publishLocation: 'Container' + - job: changelog + displayName: Generate Change Log + pool: + vmImage: 'ubuntu-latest' + variables: + CHANGELOG: '$(Build.ArtifactStagingDirectory)/changelog.md' + steps: + - checkout: none + - script: | + cat > $(CHANGELOG) < + + libpcl-all-dev + 0.1.0 + + Standalone, large scale, open project for 2D/3D image and point cloud processing + + + + kunal_tyagi + + BSD + + http://github.com/PointCloudLibrary/pcl + + kunal_tyagi + + catkin + libeigen3-dev + libflann-dev + + gtest + doxygen + catkin + + + + + + diff --git a/.dev/docker/release/Dockerfile b/.dev/docker/release/Dockerfile new file mode 100644 index 00000000..b7afd81b --- /dev/null +++ b/.dev/docker/release/Dockerfile @@ -0,0 +1,62 @@ +FROM debian:testing + +ARG VTK_VERSION=7 +ENV DEBIAN_FRONTEND=noninteractive + +# Add sources so we can just install build-dependencies of PCL +RUN sed -i 's/^deb \(.*\)$/deb \1\ndeb-src \1/' /etc/apt/sources.list \ + && apt update \ + && apt install -y \ + bash \ + cmake \ + dpkg-dev \ + git \ + g++ \ + libboost-date-time-dev \ + libboost-filesystem-dev \ + libboost-iostreams-dev \ + libeigen3-dev \ + libflann-dev \ + libglew-dev \ + libgtest-dev \ + libopenni-dev \ + libopenni2-dev \ + libproj-dev \ + libqhull-dev \ + libqt5opengl5-dev \ + libusb-1.0-0-dev \ + libvtk${VTK_VERSION}-dev \ + libvtk${VTK_VERSION}-qt-dev \ + qtbase5-dev \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# CMake flags are from dpkg helper +# PCL config is from debian repo: +# https://salsa.debian.org/science-team/pcl/-/blob/master/debian/rules +# MinSizeRel is used for the CI and should have no impact on releaseability +RUN cd \ + && git clone --depth=1 https://github.com/PointCloudLibrary/pcl \ + && mkdir pcl/build \ + && cd pcl/build \ + && export DEB_BUILD_MAINT_OPTIONS='hardening=+all' \ + && export DEB_CFLAGS_MAINT_APPEND="-Wall -pedantic" \ + && export DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed" \ + && cmake .. \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_CXX_FLAGS:STRING="`dpkg-buildflags --get CXXFLAGS`" \ + -DCMAKE_EXE_LINKER_FLAGS:STRING="`dpkg-buildflags --get LDFLAGS`" \ + -DCMAKE_SHARED_LINKER_FLAGS:STRING="`dpkg-buildflags --get LDFLAGS`" \ + -DCMAKE_SKIP_RPATH=ON -DPCL_ENABLE_SSE=OFF \ + -DBUILD_TESTS=OFF -DBUILD_apps=ON -DBUILD_common=ON \ + -DBUILD_examples=ON -DBUILD_features=ON -DBUILD_filters=ON \ + -DBUILD_geometry=ON -DBUILD_global_tests=OFF -DBUILD_io=ON \ + -DBUILD_kdtree=ON -DBUILD_keypoints=ON -DBUILD_octree=ON \ + -DBUILD_registration=ON -DBUILD_sample_consensus=ON \ + -DBUILD_search=ON -DBUILD_segmentation=ON -DBUILD_surface=ON \ + -DBUILD_tools=ON -DBUILD_tracking=ON -DBUILD_visualization=ON \ + -DBUILD_apps_cloud_composer=OFF -DBUILD_apps_modeler=ON \ + -DBUILD_apps_point_cloud_editor=ON -DBUILD_apps_in_hand_scanner=ON \ + && make install -j2 \ + && cd \ + && rm -fr pcl diff --git a/.dev/format.sh b/.dev/format.sh index c3ccba70..6acff827 100755 --- a/.dev/format.sh +++ b/.dev/format.sh @@ -8,7 +8,7 @@ format() { # don't use a directory with whitespace - local whitelist="apps/modeler 2d ml octree simulation stereo" + local whitelist="apps/3d_rec_framework apps/modeler 2d ml octree simulation stereo tracking" local PCL_DIR="${2}" local formatter="${1}" diff --git a/.dev/scripts/bump_post_release.bash b/.dev/scripts/bump_post_release.bash new file mode 100755 index 00000000..a89235c6 --- /dev/null +++ b/.dev/scripts/bump_post_release.bash @@ -0,0 +1,11 @@ +#! /usr/bin/env bash + +new_version=$(git tag | sort -rV | head -1 | cut -d- -f 2).99 + +# Mac users either use gsed or add "" after -i +if ls | grep README -q; then + sed -i "s,VERSION [0-9.]*),VERSION ${new_version})," CMakeLists.txt +else + echo "Don't think this is the root directory" 1>&2 + exit 4 +fi diff --git a/.dev/scripts/bump_release.bash b/.dev/scripts/bump_release.bash new file mode 100755 index 00000000..770e23a1 --- /dev/null +++ b/.dev/scripts/bump_release.bash @@ -0,0 +1,16 @@ +#! /usr/bin/env bash + +if [ $# != 1 ]; then + echo "Need (only) the release version" 1>&2 + exit 3 +fi + +# Mac users either use gsed or add "" after -i +new_version="$1" +if ls | grep README -q; then + sed -i "s,[0-9]\+\.[0-9]\+\.[0-9]\+,${new_version}," README.md + sed -i "s,VERSION [0-9.]*),VERSION ${new_version})," CMakeLists.txt +else + echo "Don't think this is the root directory" 1>&2 + exit 4 +fi diff --git a/.dev/scripts/generate_changelog.py b/.dev/scripts/generate_changelog.py index 11390a32..ee473387 100755 --- a/.dev/scripts/generate_changelog.py +++ b/.dev/scripts/generate_changelog.py @@ -46,7 +46,7 @@ import re CATEGORIES = { - "new feature": ("New features", ""), + "new feature": ("New features", "added to PCL"), "deprecation": ( "Deprecation", "of public APIs, scheduled to be removed after two minor releases", diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..406107e8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +blank_issues_enabled: true + +contact_links: +- name: Learn using Tutorials + url: https://pcl-tutorials.readthedocs.io/en/master/ + about: Read the tutorials to learn how to use PCL better +- name: Get help on Discord + url: https://discord.gg/JFFMAXS + about: Have a quick question about PCL or how to use PCL in your project? +- name: Get help on StackOverflow + url: https://stackoverflow.com/tags/point-cloud-library/ + about: Need some support to use PCL in your project? diff --git a/.github/stale.yml b/.github/stale.yml index e5004002..58cdf615 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -5,15 +5,18 @@ daysUntilStale: 30 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 7 +daysUntilClose: false # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: - - "needs: author reply" - - "needs: more work" +onlyLabels: [] # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: [] +exemptLabels: + - "kind: todo" + - "needs: code review" + - "needs: feedback" + - "needs: pr merge" + - "needs: testing" # Set to true to ignore issues in a project (defaults to false) exemptProjects: false @@ -29,7 +32,7 @@ staleLabel: "status: stale" # Comment to post when marking as stale. Set to `false` to disable markComment: > - This issue has been automatically marked as stale because it has not had any activity in the past month. It will be closed if no further activity occurs. + Marking this as stale due to 30 days of inactivity. It will be closed in 7 days if no further activity occurs. # Comment to post when removing the stale label. # unmarkComment: > @@ -49,4 +52,4 @@ limitPerRun: 30 pulls: daysUntilClose: false markComment: > - This pull request has been automatically marked as stale because it has not had any activity in the past month. Commenting or adding a new commit to the pull request will revert this. + Marking this as stale due to 30 days of inactivity. Commenting or adding a new commit to the pull request will revert this. diff --git a/2d/include/pcl/2d/impl/edge.hpp b/2d/include/pcl/2d/impl/edge.hpp index 6bbe9ef6..22bdd74a 100644 --- a/2d/include/pcl/2d/impl/edge.hpp +++ b/2d/include/pcl/2d/impl/edge.hpp @@ -39,7 +39,7 @@ #include #include -#include // rad2deg() +#include // for rad2deg namespace pcl { diff --git a/CHANGES.md b/CHANGES.md index 01a7ad91..533d35f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,92 @@ # ChangeList +## = 1.11.1 (13.08.2020) = + +Apart from the usual serving of bug-fixes and speed improvements, PCL 1.11.1 brings in +better support for CUDA, more uniform behavior in code as well as cmake, and an +experimental feature: `functor_filter`. + +### Notable changes + +**New features** *added to PCL* + +* **[ci]** Add support for CUDA in CI [[#4101](https://github.com/PointCloudLibrary/pcl/pull/4101)] +* **[common]** Add always-unsigned index type `uindex_t` dependent on `index_t` [[#4205](https://github.com/PointCloudLibrary/pcl/pull/4205)] +* **[filters]** Add a filter accepting a functor to reduce boiler plate code for simple filters [[#3890](https://github.com/PointCloudLibrary/pcl/pull/3890)] + +### Changes grouped by module + +#### CMake: + +* Update `pcl_find_boost` to allow compilation with Boost 1.73 and 1.72 [[#4080](https://github.com/PointCloudLibrary/pcl/pull/4080)] +* Fix NSIS Template for NSIS3 [[#4093](https://github.com/PointCloudLibrary/pcl/pull/4093)] +* Add option to choose `pcl::index_t` while compiling [[#4166](https://github.com/PointCloudLibrary/pcl/pull/4166)] +* Fix name warnings for PCAP, libusb and Ensenso. [[#4182](https://github.com/PointCloudLibrary/pcl/pull/4182)] +* Fixes compile error on MSVC by disabling Whole Program Optimization [[#4197](https://github.com/PointCloudLibrary/pcl/pull/4197)] + +#### libpcl_common: + +* Remove use of dynamic allocation in `GaussianKernel::convolve{Rows,Cols}` [[#4092](https://github.com/PointCloudLibrary/pcl/pull/4092)] +* Replace usage of `std::vector` with `Indices` [[#3989](https://github.com/PointCloudLibrary/pcl/pull/3989)] +* Update `PointCloud` to conform to requirements of `ReversibleContainer` [[#3980](https://github.com/PointCloudLibrary/pcl/pull/3980)] +* **[new feature]** Add always-unsigned index type `uindex_t` dependent on `index_t` [[#4205](https://github.com/PointCloudLibrary/pcl/pull/4205)] +* Adding `data` member function to `PointCloud` [[#4216](https://github.com/PointCloudLibrary/pcl/pull/4216)] +* Switch `int` to `index_t` for field index variables in `pclBase`, add `pcl::UNAVAILABLE` for same [[#4211](https://github.com/PointCloudLibrary/pcl/pull/4211)] +* Added `resize` with 2 arguments to `PointCloud` [[#4225](https://github.com/PointCloudLibrary/pcl/pull/4225)] +* Adding `max_size` to PointCloud [[#4254](https://github.com/PointCloudLibrary/pcl/pull/4254)] +* Support multiple arguments in `pcl::utils::ignore()` [[#4269](https://github.com/PointCloudLibrary/pcl/pull/4269)] + +#### libpcl_features: + +* Fix feature histogram constructor bug [[#4234](https://github.com/PointCloudLibrary/pcl/pull/4234)] +* Fix regression in Organized Edge Detection (introduced in PCL 1.10.1) [[#4311](https://github.com/PointCloudLibrary/pcl/pull/4311)] + +#### libpcl_filters: + +* reduce computations involved in iterating over the pointcloud for `FastBilateral{OMP}` [[#4134](https://github.com/PointCloudLibrary/pcl/pull/4134)] +* **[new feature]** Add a filter accepting a functor to reduce boiler plate code for simple filters [[#3890](https://github.com/PointCloudLibrary/pcl/pull/3890)] +* Refatoring VoxelGridCovariance to make it multi-thread safe (and more) [[#4251](https://github.com/PointCloudLibrary/pcl/pull/4251)] + +#### libpcl_gpu: + +* Replace volatile shared memory with shfl_sync in KNNSearch [[#4306](https://github.com/PointCloudLibrary/pcl/pull/4306)] +* Fix octree radiusSearch [[#4146](https://github.com/PointCloudLibrary/pcl/pull/4146)] + +#### libpcl_io: + +* Better conversion of depth data + focal length into X,Y,Z point data [[#4128](https://github.com/PointCloudLibrary/pcl/pull/4128)] +* Add iterator include for back_iterator to support VS2019 [[#4319](https://github.com/PointCloudLibrary/pcl/pull/4319)] + +#### libpcl_outofcore: + +* Fix compile issue in OutofcoreOctreeBase::setLODFilter after switching from boost::shared_ptr to std::shared_ptr [[#4081](https://github.com/PointCloudLibrary/pcl/pull/4081)] + +#### libpcl_registration: + +* Fix bug in NDT step interval convergence criteria [[#4181](https://github.com/PointCloudLibrary/pcl/pull/4181)] + +#### libpcl_segmentation: + +* Clean FLANN includes [[#4025](https://github.com/PointCloudLibrary/pcl/pull/4025)] +* Update angle between 2 planes to be the smallest angle between them [[#4161](https://github.com/PointCloudLibrary/pcl/pull/4161)] + +#### libpcl_simulation: + +* Don't prefix in shaders. [[#4209](https://github.com/PointCloudLibrary/pcl/pull/4209)] + +#### libpcl_visualization: + +* Fix error: misplaced deprecation attributes in `vtkVertexBufferObject{,Mapper}` [[#4079](https://github.com/PointCloudLibrary/pcl/pull/4079)] + +#### PCL Docs: + +* Fix typo in FPFH documentation, $$p_k$$ was used instead of $$p_i$$ [[#4112](https://github.com/PointCloudLibrary/pcl/pull/4112)] +* Fix typos in PFH estimation tutorial [[#4111](https://github.com/PointCloudLibrary/pcl/pull/4111)] + +#### CI: + +* **[new feature]** Add support for CUDA in CI [[#4101](https://github.com/PointCloudLibrary/pcl/pull/4101)] + ## = 1.11.0 (11.05.2020) = Starting with PCL 1.11, PCL uses `std::shared_ptr` and `std::weak_ptr` instead of the @@ -3062,7 +3149,7 @@ pcl::OrganizedDataIndex -> pcl::search::OrganizedNeighbor * added new templated methods for `nearestKSearch` and `radiusSearch` for situations when PointT is different than the one the KdTree object was created with (e.g., KdTree vs nearestKSearch (PointT2 &p...) * added two new methods for `getApproximateIndices` where given a reference cloud of point type T1 we're trying to find the corresponding indices in a different cloud of point type T2 * refactorized a lot of code in search and octree to make it look more consistent with the rest of the API -* fixed a bug in octree_search which was semantically doing something bad: for each `radiusSearch`/`nearestKSearch`/`approxNearestSearch` call with a PointCloudConstPtr, the octree was getting recreated. Changed the API to be consistent with the rest of PCL (including pcl_search and pcl_kdtree) where we pass in a PointCloud instead of a PointCloudConstPtr which simply calls searchMethod (cloud.points[i], ...) +* fixed a bug in octree_search which was semantically doing something bad: for each `radiusSearch`/`nearestKSearch`/`approxNearestSearch` call with a PointCloudConstPtr, the octree was getting recreated. Changed the API to be consistent with the rest of PCL (including pcl_search and pcl_kdtree) where we pass in a PointCloud instead of a PointCloudConstPtr which simply calls searchMethod (cloud[i], ...) * minor code optimizations * renamed organized_neighbor.h header in pcl_search (unreleased, therefore API changes OK!) to organized.h * disabled the auto-search tuning as it wasn't really working. must clean this up further @@ -3117,7 +3204,7 @@ pcl::OrganizedDataIndex -> pcl::search::OrganizedNeighbor * added unit test for `getIntersectedVoxelCentersRecursive` * added method `getIntersectedVoxelIndices` for getting indices of intersected voxels and updated unit test * refactorized a lot of code in search and octree to make it look more consistent with the rest of the API -* fixed a bug in octree_search which was semantically doing something bad: for each `radiusSearch`/`nearestKSearch`/`approxNearestSearch` call with a PointCloudConstPtr, the octree was getting recreated. Changed the API to be consistent with the rest of PCL (including pcl_search and pcl_kdtree) where we pass in a PointCloud instead of a PointCloudConstPtr which simply calls searchMethod (cloud.points[i], ...) +* fixed a bug in octree_search which was semantically doing something bad: for each `radiusSearch`/`nearestKSearch`/`approxNearestSearch` call with a PointCloudConstPtr, the octree was getting recreated. Changed the API to be consistent with the rest of PCL (including pcl_search and pcl_kdtree) where we pass in a PointCloud instead of a PointCloudConstPtr which simply calls searchMethod (cloud[i], ...) * minor code optimizations * renamed organized_neighbor.h header in pcl_search (unreleased, therefore API changes OK!) to organized.h * disabled the auto-search tuning as it wasn't really working. must clean this up further diff --git a/CMakeLists.txt b/CMakeLists.txt index aa59b760..e5aa7f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "build type default to RelWithDebInfo, set to Release to improve performance" FORCE) endif() -project(PCL VERSION 1.11.0) +project(PCL VERSION 1.11.1) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) ### ---[ Find universal dependencies @@ -130,10 +130,12 @@ if(CMAKE_COMPILER_IS_MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /wd4800 /wd4521 /wd4251 /wd4275 /wd4305 /wd4355 ${SSE_FLAGS_STR}") # Add extra code generation/link optimizations - if(CMAKE_MSVC_CODE_LINK_OPTIMIZATION) + if(CMAKE_MSVC_CODE_LINK_OPTIMIZATION AND (NOT BUILD_CUDA) AND (NOT BUILD_GPU)) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + else() + message("Global optimizations /GL has been turned off, as it doesn't work with nvcc/thrust") endif() # /MANIFEST:NO") # please, don't disable manifest generation, otherwise crash at start for vs2008 @@ -256,7 +258,10 @@ endif() ### ---[ Find universal dependencies # OpenMP (optional) -find_package(OpenMP COMPONENTS C CXX) +option(WITH_OPENMP "Build with parallelization using OpenMP" TRUE) +if(WITH_OPENMP) + find_package(OpenMP COMPONENTS C CXX) +endif() if(OpenMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..a56d83c1 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +pointclouds.org \ No newline at end of file diff --git a/PCLConfig.cmake.in b/PCLConfig.cmake.in index 9f78fcfa..349ad7c4 100644 --- a/PCLConfig.cmake.in +++ b/PCLConfig.cmake.in @@ -101,7 +101,7 @@ macro(find_boost) endif() set(Boost_ADDITIONAL_VERSIONS "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@.@Boost_SUBMINOR_VERSION@" "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@" - "1.71.0" "1.71" "1.70.0" "1.70" + "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55") diff --git a/README.md b/README.md index 26de07d4..9ae34aae 100644 --- a/README.md +++ b/README.md @@ -5,32 +5,33 @@ [![Release][release-image]][releases] [![License][license-image]][license] -[release-image]: https://img.shields.io/badge/release-1.11.0-green.svg?style=flat +[release-image]: https://img.shields.io/badge/release-1.11.1-green.svg?style=flat [releases]: https://github.com/PointCloudLibrary/pcl/releases [license-image]: https://img.shields.io/badge/license-BSD-green.svg?style=flat [license]: https://github.com/PointCloudLibrary/pcl/blob/master/LICENSE.txt -:bangbang:Website:bangbang: +Website ------- -The original website (http://pointclouds.org) is down currently :broken_heart:, but a new one is back up https://pointcloudlibrary.github.io/ :heart: and open to [contributions](https://github.com/PointCloudLibrary/PointCloudLibrary.github.io) :hammer_and_wrench:. +The new website is now online at https://pointclouds.org and is open to [contributions](https://github.com/PointCloudLibrary/PointCloudLibrary.github.io) :hammer_and_wrench:. If you really need access to the old website, please use [the copy made by the internet archive](https://web.archive.org/web/20191017164724/http://www.pointclouds.org/). Please be aware that the website was hacked before and could still be hosting some malicious code. Continuous integration ---------------------- [ci-latest-build]: https://dev.azure.com/PointCloudLibrary/pcl/_build/latest?definitionId=9&branchName=master -[ci-ubuntu-16.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Ubuntu&jobName=Ubuntu&configuration=Ubuntu%2016.04%20GCC&label=Ubuntu%2016.04 -[ci-ubuntu-20.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Ubuntu&jobName=Ubuntu&configuration=Ubuntu%2020.04%20GCC&label=Ubuntu%2020.04 -[ci-windows-x86]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Windows&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x86&label=Windows%20VS2017%20x86 -[ci-windows-x64]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Windows&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x64&label=Windows%20VS2017%20x64 -[ci-macos-10.14]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20macOS&jobName=macOS&configuration=macOS%20Mojave%2010.14&label=macOS%20Mojave%2010.14 -[ci-macos-10.15]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20macOS&jobName=macOS&configuration=macOS%20Catalina%2010.15&label=macOS%20Catalina%2010.15 +[ci-ubuntu-16.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20GCC&jobName=Ubuntu&configuration=Ubuntu%2016.04%20GCC&label=Ubuntu%2016.04%20GCC +[ci-ubuntu-18.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=Ubuntu&configuration=Ubuntu%2018.04%20Clang&label=Ubuntu%2018.04%20Clang +[ci-ubuntu-20.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20GCC&jobName=Ubuntu&configuration=Ubuntu%2020.04%20GCC&label=Ubuntu%2020.04%20GCC +[ci-windows-x86]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x86&label=Windows%20VS2017%20x86 +[ci-windows-x64]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x64&label=Windows%20VS2017%20x64 +[ci-macos-10.14]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=macOS&configuration=macOS%20Mojave%2010.14&label=macOS%20Mojave%2010.14 +[ci-macos-10.15]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=macOS&configuration=macOS%20Catalina%2010.15&label=macOS%20Catalina%2010.15 Build Platform | Status ------------------------ | ------------------------------------------------------------------------------------------------- | -Ubuntu | [![Status][ci-ubuntu-16.04]][ci-latest-build]
[![Status][ci-ubuntu-20.04]][ci-latest-build] | +Ubuntu | [![Status][ci-ubuntu-16.04]][ci-latest-build]
[![Status][ci-ubuntu-18.04]][ci-latest-build]
[![Status][ci-ubuntu-20.04]][ci-latest-build] | Windows | [![Status][ci-windows-x86]][ci-latest-build]
[![Status][ci-windows-x64]][ci-latest-build] | macOS | [![Status][ci-macos-10.14]][ci-latest-build]
[![Status][ci-macos-10.15]][ci-latest-build] | @@ -44,7 +45,7 @@ Community [discord-image]: https://img.shields.io/discord/694824801977630762?color=7289da&label=community%20chat&logo=discord&style=plastic [discord-server]: https://discord.gg/JFFMAXS [website-status]: https://img.shields.io/website/https/pointcloudlibrary.github.io.svg?down_color=red&down_message=is%20down&up_color=green&up_message=is%20new -[website]: https://pointcloudlibrary.github.io/ +[website]: https://pointclouds.org/ [so-question-count]: https://img.shields.io/stackexchange/stackoverflow/t/point-cloud-library.svg?logo=stackoverflow [stackoverflow]: https://stackoverflow.com/questions/tagged/point-cloud-library @@ -73,14 +74,14 @@ PCL is released under the terms of the BSD license, and thus free for commercial Compiling --------- Please refer to the platform specific tutorials: - - [Linux](http://www.pointclouds.org/documentation/tutorials/compiling_pcl_posix.php) - - [Mac OS X](http://www.pointclouds.org/documentation/tutorials/compiling_pcl_macosx.php) - - [Microsoft Windows](http://www.pointclouds.org/documentation/tutorials/compiling_pcl_windows.php) + - [Linux](https://pcl-tutorials.readthedocs.io/en/latest/compiling_pcl_posix.html) + - [Mac OS X](https://pcl-tutorials.readthedocs.io/en/latest/compiling_pcl_macosx.html) + - [Microsoft Windows](https://pcl-tutorials.readthedocs.io/en/latest/compiling_pcl_windows.html) Documentation ------------- -- [Tutorials](http://www.pointclouds.org/documentation/tutorials/) -- [PCL trunk documentation](https://pointcloudlibrary.github.io/documentation/) (updated nightly) +- [Tutorials](https://pcl-tutorials.readthedocs.io/) +- [PCL trunk documentation](https://pointclouds.org/documentation/) Contributing ------------ @@ -96,14 +97,3 @@ for Q&A as well as support for troubleshooting, installation and debugging. Do remember to tag your questions with the tag `point-cloud-library`. * [Discord Server](https://discord.gg/JFFMAXS) for live chat with other members of the PCL community and casual discussions - - - - diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/crh_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/crh_estimator.h index 1517b179..be96e4ef 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/crh_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/crh_estimator.h @@ -13,81 +13,82 @@ #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class CRHEstimation : public GlobalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using GlobalEstimator::normal_estimator_; + using GlobalEstimator::normals_; + + std::shared_ptr> feature_estimator_; + using CRHPointCloud = pcl::PointCloud>; + std::vector crh_histograms_; + +public: + CRHEstimation() {} + + void + setFeatureEstimator( + std::shared_ptr>& feature_estimator) + { + feature_estimator_ = feature_estimator; + } + + void + estimate(PointInTPtr& in, + PointInTPtr& processed, + std::vector, + Eigen::aligned_allocator>>& signatures, + std::vector>& + centroids) override { - template - class CRHEstimation : public GlobalEstimator - { - - using PointInTPtr = typename pcl::PointCloud::Ptr; - using GlobalEstimator::normal_estimator_; - using GlobalEstimator::normals_; - - std::shared_ptr> feature_estimator_; - using CRHPointCloud = pcl::PointCloud >; - std::vector< CRHPointCloud::Ptr > crh_histograms_; - - public: - - CRHEstimation () - { - - } - - void - setFeatureEstimator(std::shared_ptr>& feature_estimator) { - feature_estimator_ = feature_estimator; - } - - void - estimate (PointInTPtr & in, PointInTPtr & processed, - std::vector, Eigen::aligned_allocator > > & signatures, - std::vector > & centroids) override - { - - if (!feature_estimator_) - { - PCL_ERROR("CRHEstimation needs a global estimator... please provide one\n"); - return; - } - - feature_estimator_->estimate(in, processed, signatures, centroids); - - if(!feature_estimator_->computedNormals()) { - normals_.reset(new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals_); - } else { - feature_estimator_->getNormals(normals_); - } - - crh_histograms_.resize(signatures.size()); - - using CRHEstimation = pcl::CRHEstimation >; - CRHEstimation crh; - crh.setInputCloud(processed); - crh.setInputNormals(normals_); - - for (std::size_t idx = 0; idx < signatures.size (); idx++) - { - Eigen::Vector4f centroid4f(centroids[idx][0],centroids[idx][1],centroids[idx][2],0); - crh.setCentroid(centroid4f); - crh_histograms_[idx].reset(new CRHPointCloud()); - crh.compute (*crh_histograms_[idx]); - } - - } - - void getCRHHistograms(std::vector< CRHPointCloud::Ptr > & crh_histograms) { - crh_histograms = crh_histograms_; - } - - bool - computedNormals () override - { - return true; - } - }; + + if (!feature_estimator_) { + PCL_ERROR("CRHEstimation needs a global estimator... please provide one\n"); + return; + } + + feature_estimator_->estimate(in, processed, signatures, centroids); + + if (!feature_estimator_->computedNormals()) { + normals_.reset(new pcl::PointCloud); + normal_estimator_->estimate(in, processed, normals_); + } + else { + feature_estimator_->getNormals(normals_); + } + + crh_histograms_.resize(signatures.size()); + + using CRHEstimation = pcl::CRHEstimation>; + CRHEstimation crh; + crh.setInputCloud(processed); + crh.setInputNormals(normals_); + + for (std::size_t idx = 0; idx < signatures.size(); idx++) { + Eigen::Vector4f centroid4f( + centroids[idx][0], centroids[idx][1], centroids[idx][2], 0); + crh.setCentroid(centroid4f); + crh_histograms_[idx].reset(new CRHPointCloud()); + crh.compute(*crh_histograms_[idx]); + } + } + + void + getCRHHistograms(std::vector& crh_histograms) + { + crh_histograms = crh_histograms_; } -} + + bool + computedNormals() override + { + return true; + } +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/cvfh_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/cvfh_estimator.h index 50469cd7..97583935 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/cvfh_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/cvfh_estimator.h @@ -12,152 +12,150 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class CVFHEstimation : public GlobalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using GlobalEstimator::normal_estimator_; + using GlobalEstimator::normals_; + float eps_angle_threshold_; + float curvature_threshold_; + float cluster_tolerance_factor_; + bool normalize_bins_; + bool adaptative_MLS_; + +public: + CVFHEstimation() { - template - class CVFHEstimation : public GlobalEstimator + eps_angle_threshold_ = 0.13f; + curvature_threshold_ = 0.035f; + normalize_bins_ = true; + cluster_tolerance_factor_ = 3.f; + } + + void + setCVFHParams(float p1, float p2, float p3) + { + eps_angle_threshold_ = p1; + curvature_threshold_ = p2; + cluster_tolerance_factor_ = p3; + } + + void + setAdaptativeMLS(bool b) + { + adaptative_MLS_ = b; + } + + void + estimate(PointInTPtr& in, + PointInTPtr& processed, + typename pcl::PointCloud::CloudVectorType& signatures, + std::vector>& + centroids) override + { + + if (!normal_estimator_) { + PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); + return; + } + + pcl::MovingLeastSquares mls; + if (adaptative_MLS_) { + typename search::KdTree::Ptr tree; + Eigen::Vector4f centroid_cluster; + pcl::compute3DCentroid(*in, centroid_cluster); + float dist_to_sensor = centroid_cluster.norm(); + float sigma = dist_to_sensor * 0.01f; + mls.setSearchMethod(tree); + mls.setSearchRadius(sigma); + mls.setUpsamplingMethod(mls.SAMPLE_LOCAL_PLANE); + mls.setUpsamplingRadius(0.002); + mls.setUpsamplingStepSize(0.001); + } + + normals_.reset(new pcl::PointCloud); { + normal_estimator_->estimate(in, processed, normals_); + } - using PointInTPtr = typename pcl::PointCloud::Ptr; - using GlobalEstimator::normal_estimator_; - using GlobalEstimator::normals_; - float eps_angle_threshold_; - float curvature_threshold_; - float cluster_tolerance_factor_; - bool normalize_bins_; - bool adaptative_MLS_; + if (adaptative_MLS_) { + mls.setInputCloud(processed); - public: + PointInTPtr filtered(new pcl::PointCloud); + mls.process(*filtered); - CVFHEstimation () + processed.reset(new pcl::PointCloud); + normals_.reset(new pcl::PointCloud); { - eps_angle_threshold_ = 0.13f; - curvature_threshold_ = 0.035f; - normalize_bins_ = true; - cluster_tolerance_factor_ = 3.f; + filtered->is_dense = false; + normal_estimator_->estimate(filtered, processed, normals_); } - - void setCVFHParams(float p1, float p2, float p3) { - eps_angle_threshold_ = p1; - curvature_threshold_ = p2; - cluster_tolerance_factor_ = p3; + } + + using CVFHEstimation = pcl::CVFHEstimation; + pcl::PointCloud cvfh_signatures; + typename pcl::search::KdTree::Ptr cvfh_tree( + new pcl::search::KdTree); + + CVFHEstimation cvfh; + cvfh.setSearchMethod(cvfh_tree); + cvfh.setInputCloud(processed); + cvfh.setInputNormals(normals_); + + cvfh.setEPSAngleThreshold(eps_angle_threshold_); + cvfh.setCurvatureThreshold(curvature_threshold_); + cvfh.setNormalizeBins(normalize_bins_); + + float radius = normal_estimator_->normal_radius_; + float cluster_tolerance_radius = + normal_estimator_->grid_resolution_ * cluster_tolerance_factor_; + + if (normal_estimator_->compute_mesh_resolution_) { + radius = normal_estimator_->mesh_resolution_ * normal_estimator_->factor_normals_; + cluster_tolerance_radius = + normal_estimator_->mesh_resolution_ * cluster_tolerance_factor_; + + if (normal_estimator_->do_voxel_grid_) { + radius *= normal_estimator_->factor_voxel_grid_; + cluster_tolerance_radius *= normal_estimator_->factor_voxel_grid_; } + } - void setAdaptativeMLS(bool b) { - adaptative_MLS_ = b; - } + cvfh.setClusterTolerance(cluster_tolerance_radius); + cvfh.setRadiusNormals(radius); + cvfh.setMinPoints(100); - void - estimate (PointInTPtr & in, PointInTPtr & processed, - typename pcl::PointCloud::CloudVectorType & signatures, - std::vector > & centroids) override - { + cvfh.compute(cvfh_signatures); - if (!normal_estimator_) - { - PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); - return; - } - - pcl::MovingLeastSquares mls; - if(adaptative_MLS_) { - typename search::KdTree::Ptr tree; - Eigen::Vector4f centroid_cluster; - pcl::compute3DCentroid (*in, centroid_cluster); - float dist_to_sensor = centroid_cluster.norm(); - float sigma = dist_to_sensor * 0.01f; - mls.setSearchMethod(tree); - mls.setSearchRadius (sigma); - mls.setUpsamplingMethod (mls.SAMPLE_LOCAL_PLANE); - mls.setUpsamplingRadius (0.002); - mls.setUpsamplingStepSize (0.001); - } - - normals_.reset (new pcl::PointCloud); - { - normal_estimator_->estimate (in, processed, normals_); - } - - if(adaptative_MLS_) { - mls.setInputCloud(processed); - - PointInTPtr filtered(new pcl::PointCloud); - mls.process(*filtered); - - processed.reset(new pcl::PointCloud); - normals_.reset (new pcl::PointCloud); - { - filtered->is_dense = false; - normal_estimator_->estimate (filtered, processed, normals_); - } - } - - /*normals_.reset(new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals_);*/ - - using CVFHEstimation = pcl::CVFHEstimation; - pcl::PointCloud cvfh_signatures; - typename pcl::search::KdTree::Ptr cvfh_tree (new pcl::search::KdTree); - - CVFHEstimation cvfh; - cvfh.setSearchMethod (cvfh_tree); - cvfh.setInputCloud (processed); - cvfh.setInputNormals (normals_); - - cvfh.setEPSAngleThreshold (eps_angle_threshold_); - cvfh.setCurvatureThreshold (curvature_threshold_); - cvfh.setNormalizeBins (normalize_bins_); - - float radius = normal_estimator_->normal_radius_; - float cluster_tolerance_radius = normal_estimator_->grid_resolution_ * cluster_tolerance_factor_; - - if (normal_estimator_->compute_mesh_resolution_) - { - radius = normal_estimator_->mesh_resolution_ * normal_estimator_->factor_normals_; - cluster_tolerance_radius = normal_estimator_->mesh_resolution_ * cluster_tolerance_factor_; - - if (normal_estimator_->do_voxel_grid_) - { - radius *= normal_estimator_->factor_voxel_grid_; - cluster_tolerance_radius *= normal_estimator_->factor_voxel_grid_; - } - } - - cvfh.setClusterTolerance (cluster_tolerance_radius); - cvfh.setRadiusNormals (radius); - cvfh.setMinPoints (100); - - //std::cout << "Res:" << normal_estimator_->mesh_resolution_ << " Radius normals:" << radius << " Cluster tolerance:" << cluster_tolerance_radius << " " << eps_angle_threshold_ << " " << curvature_threshold_ << std::endl; - - cvfh.compute (cvfh_signatures); - - for (std::size_t i = 0; i < cvfh_signatures.points.size (); i++) - { - pcl::PointCloud vfh_signature; - vfh_signature.points.resize (1); - vfh_signature.width = vfh_signature.height = 1; - for (int d = 0; d < 308; ++d) - vfh_signature.points[0].histogram[d] = cvfh_signatures.points[i].histogram[d]; - - signatures.push_back (vfh_signature); - } - - cvfh.getCentroidClusters (centroids); - //std::cout << "centroids size:" << centroids.size () << std::endl; + for (std::size_t i = 0; i < cvfh_signatures.size(); i++) { + pcl::PointCloud vfh_signature; + vfh_signature.points.resize(1); + vfh_signature.width = vfh_signature.height = 1; + for (int d = 0; d < 308; ++d) + vfh_signature[0].histogram[d] = cvfh_signatures[i].histogram[d]; - } + signatures.push_back(vfh_signature); + } - bool - computedNormals () override - { - return true; - } + cvfh.getCentroidClusters(centroids); + } - void setNormalizeBins(bool b) { - normalize_bins_ = b; - } - }; + bool + computedNormals() override + { + return true; } -} + + void + setNormalizeBins(bool b) + { + normalize_bins_ = b; + } +}; // namespace rec_3d_framework + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/esf_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/esf_estimator.h index ac759442..353cc82a 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/esf_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/esf_estimator.h @@ -10,48 +10,48 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework - { - template - class ESFEstimation : public GlobalEstimator - { +namespace pcl { +namespace rec_3d_framework { + +template +class ESFEstimation : public GlobalEstimator { - using PointInTPtr = typename pcl::PointCloud::Ptr; + using PointInTPtr = typename pcl::PointCloud::Ptr; - public: - void - estimate (PointInTPtr & in, PointInTPtr & processed, - typename pcl::PointCloud::CloudVectorType & signatures, - std::vector > & centroids) override - { +public: + void + estimate(PointInTPtr& in, + PointInTPtr& processed, + typename pcl::PointCloud::CloudVectorType& signatures, + std::vector>& + centroids) override + { - using ESFEstimation = pcl::ESFEstimation; - pcl::PointCloud ESF_signature; + using ESFEstimation = pcl::ESFEstimation; + pcl::PointCloud ESF_signature; - ESFEstimation esf; - esf.setInputCloud (in); - esf.compute (ESF_signature); + ESFEstimation esf; + esf.setInputCloud(in); + esf.compute(ESF_signature); - signatures.resize (1); - centroids.resize (1); + signatures.resize(1); + centroids.resize(1); - signatures[0] = ESF_signature; + signatures[0] = ESF_signature; - Eigen::Vector4f centroid4f; - pcl::compute3DCentroid (*in, centroid4f); - centroids[0] = Eigen::Vector3f (centroid4f[0], centroid4f[1], centroid4f[2]); + Eigen::Vector4f centroid4f; + pcl::compute3DCentroid(*in, centroid4f); + centroids[0] = Eigen::Vector3f(centroid4f[0], centroid4f[1], centroid4f[2]); - pcl::copyPointCloud(*in, *processed); - //processed = in; - } + pcl::copyPointCloud(*in, *processed); + } - bool - computedNormals () override - { - return false; - } - }; + bool + computedNormals() override + { + return false; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/global_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/global_estimator.h index badf27c0..2918e9f8 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/global_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/global_estimator.h @@ -11,39 +11,48 @@ #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class GlobalEstimator { +protected: + bool computed_normals_; + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + + std::shared_ptr> + normal_estimator_; + + pcl::PointCloud::Ptr normals_; + +public: + virtual ~GlobalEstimator() = default; + + virtual void + estimate(PointInTPtr& in, + PointInTPtr& processed, + std::vector, + Eigen::aligned_allocator>>& signatures, + std::vector>& + centroids) = 0; + + virtual bool + computedNormals() = 0; + + void + setNormalEstimator( + std::shared_ptr>& ne) { - template - class GlobalEstimator { - protected: - bool computed_normals_; - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - - std::shared_ptr> normal_estimator_; - - pcl::PointCloud::Ptr normals_; - - public: - virtual - ~GlobalEstimator() = default; - - virtual void - estimate (PointInTPtr & in, PointInTPtr & processed, std::vector, Eigen::aligned_allocator< - pcl::PointCloud > > & signatures, std::vector > & centroids)=0; - - virtual bool computedNormals() = 0; - - void setNormalEstimator(std::shared_ptr>& ne) { - normal_estimator_ = ne; - } - - void getNormals(pcl::PointCloud::Ptr & normals) { - normals = normals_; - } + normal_estimator_ = ne; + } - }; + void + getNormals(pcl::PointCloud::Ptr& normals) + { + normals = normals_; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/ourcvfh_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/ourcvfh_estimator.h index 3d99e6ff..85e5c264 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/ourcvfh_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/ourcvfh_estimator.h @@ -12,187 +12,182 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class OURCVFHEstimator : public GlobalEstimator { + +protected: + using PointInTPtr = typename pcl::PointCloud::Ptr; + using GlobalEstimator::normal_estimator_; + using GlobalEstimator::normals_; + float eps_angle_threshold_; + float curvature_threshold_; + float cluster_tolerance_factor_; + bool normalize_bins_; + bool adaptative_MLS_; + float refine_factor_; + + std::vector valid_roll_transforms_; + std::vector> transforms_; + std::vector cluster_indices_; + +public: + OURCVFHEstimator() { - template - class OURCVFHEstimator : public GlobalEstimator + eps_angle_threshold_ = 0.13f; + curvature_threshold_ = 0.035f; + normalize_bins_ = true; + cluster_tolerance_factor_ = 3.f; + adaptative_MLS_ = false; + } + + void + setCVFHParams(float p1, float p2, float p3) + { + eps_angle_threshold_ = p1; + curvature_threshold_ = p2; + cluster_tolerance_factor_ = p3; + } + + void + setAdaptativeMLS(bool b) + { + adaptative_MLS_ = b; + } + + void + setRefineClustersParam(float p4) + { + refine_factor_ = p4; + } + + void + getValidTransformsVec(std::vector& valid) + { + valid = valid_roll_transforms_; + } + + void + getTransformsVec( + std::vector>& trans) + { + trans = transforms_; + } + + void + estimate(PointInTPtr& in, + PointInTPtr& processed, + typename pcl::PointCloud::CloudVectorType& signatures, + std::vector>& + centroids) override + { + + valid_roll_transforms_.clear(); + transforms_.clear(); + + if (!normal_estimator_) { + PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); + return; + } + + pcl::MovingLeastSquares mls; + if (adaptative_MLS_) { + typename search::KdTree::Ptr tree; + Eigen::Vector4f centroid_cluster; + pcl::compute3DCentroid(*in, centroid_cluster); + float dist_to_sensor = centroid_cluster.norm(); + float sigma = dist_to_sensor * 0.01f; + mls.setSearchMethod(tree); + mls.setSearchRadius(sigma); + mls.setUpsamplingMethod(mls.SAMPLE_LOCAL_PLANE); + mls.setUpsamplingRadius(0.002); + mls.setUpsamplingStepSize(0.001); + } + + normals_.reset(new pcl::PointCloud); + { + normal_estimator_->estimate(in, processed, normals_); + } + + if (adaptative_MLS_) { + mls.setInputCloud(processed); + + PointInTPtr filtered(new pcl::PointCloud); + mls.process(*filtered); + + processed.reset(new pcl::PointCloud); + normals_.reset(new pcl::PointCloud); { + filtered->is_dense = false; + normal_estimator_->estimate(filtered, processed, normals_); + } + } + + using OURCVFHEstimation = + pcl::OURCVFHEstimation; + pcl::PointCloud cvfh_signatures; + typename pcl::search::KdTree::Ptr cvfh_tree( + new pcl::search::KdTree); + + OURCVFHEstimation cvfh; + cvfh.setSearchMethod(cvfh_tree); + cvfh.setInputCloud(processed); + cvfh.setInputNormals(normals_); + cvfh.setEPSAngleThreshold(eps_angle_threshold_); + cvfh.setCurvatureThreshold(curvature_threshold_); + cvfh.setNormalizeBins(normalize_bins_); + cvfh.setRefineClusters(refine_factor_); + + float radius = normal_estimator_->normal_radius_; + float cluster_tolerance_radius = + normal_estimator_->grid_resolution_ * cluster_tolerance_factor_; + + if (normal_estimator_->compute_mesh_resolution_) { + radius = normal_estimator_->mesh_resolution_ * normal_estimator_->factor_normals_; + cluster_tolerance_radius = + normal_estimator_->mesh_resolution_ * cluster_tolerance_factor_; + + if (normal_estimator_->do_voxel_grid_) { + radius *= normal_estimator_->factor_voxel_grid_; + cluster_tolerance_radius *= normal_estimator_->factor_voxel_grid_; + } + } + + cvfh.setClusterTolerance(cluster_tolerance_radius); + cvfh.setRadiusNormals(radius); + cvfh.setMinPoints(100); + cvfh.compute(cvfh_signatures); + + for (const auto& point : cvfh_signatures.points) { + pcl::PointCloud vfh_signature; + vfh_signature.points.resize(1); + vfh_signature.width = vfh_signature.height = 1; + for (int d = 0; d < 308; ++d) + vfh_signature[0].histogram[d] = point.histogram[d]; + + signatures.push_back(vfh_signature); + } + + cvfh.getCentroidClusters(centroids); + cvfh.getTransforms(transforms_); + cvfh.getValidTransformsVec(valid_roll_transforms_); + cvfh.getClusterIndices(cluster_indices_); + } + + bool + computedNormals() override + { + return true; + } - protected: - using PointInTPtr = typename pcl::PointCloud::Ptr; - using GlobalEstimator::normal_estimator_; - using GlobalEstimator::normals_; - float eps_angle_threshold_; - float curvature_threshold_; - float cluster_tolerance_factor_; - bool normalize_bins_; - bool adaptative_MLS_; - float refine_factor_; - - std::vector valid_roll_transforms_; - std::vector > transforms_; - std::vector cluster_indices_; - - public: - - OURCVFHEstimator () - { - eps_angle_threshold_ = 0.13f; - curvature_threshold_ = 0.035f; - normalize_bins_ = true; - cluster_tolerance_factor_ = 3.f; - adaptative_MLS_ = false; - } - - void - setCVFHParams (float p1, float p2, float p3) - { - eps_angle_threshold_ = p1; - curvature_threshold_ = p2; - cluster_tolerance_factor_ = p3; - } - - void - setAdaptativeMLS (bool b) - { - adaptative_MLS_ = b; - } - - void - setRefineClustersParam (float p4) - { - refine_factor_ = p4; - } - - void - getValidTransformsVec (std::vector & valid) - { - valid = valid_roll_transforms_; - } - - void - getTransformsVec (std::vector > & trans) - { - trans = transforms_; - } - - void - estimate (PointInTPtr & in, PointInTPtr & processed, typename pcl::PointCloud::CloudVectorType & signatures, - std::vector > & centroids) override - { - - valid_roll_transforms_.clear (); - transforms_.clear (); - - if (!normal_estimator_) - { - PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); - return; - } - - pcl::MovingLeastSquares mls; - if (adaptative_MLS_) - { - typename search::KdTree::Ptr tree; - Eigen::Vector4f centroid_cluster; - pcl::compute3DCentroid (*in, centroid_cluster); - float dist_to_sensor = centroid_cluster.norm (); - float sigma = dist_to_sensor * 0.01f; - mls.setSearchMethod (tree); - mls.setSearchRadius (sigma); - mls.setUpsamplingMethod (mls.SAMPLE_LOCAL_PLANE); - mls.setUpsamplingRadius (0.002); - mls.setUpsamplingStepSize (0.001); - } - - normals_.reset (new pcl::PointCloud); - { - normal_estimator_->estimate (in, processed, normals_); - } - - if (adaptative_MLS_) - { - mls.setInputCloud (processed); - - PointInTPtr filtered (new pcl::PointCloud); - mls.process (*filtered); - - processed.reset (new pcl::PointCloud); - normals_.reset (new pcl::PointCloud); - { - filtered->is_dense = false; - normal_estimator_->estimate (filtered, processed, normals_); - } - } - - /*normals_.reset(new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals_);*/ - - using OURCVFHEstimation = pcl::OURCVFHEstimation; - pcl::PointCloud cvfh_signatures; - typename pcl::search::KdTree::Ptr cvfh_tree (new pcl::search::KdTree); - - OURCVFHEstimation cvfh; - cvfh.setSearchMethod (cvfh_tree); - cvfh.setInputCloud (processed); - cvfh.setInputNormals (normals_); - cvfh.setEPSAngleThreshold (eps_angle_threshold_); - cvfh.setCurvatureThreshold (curvature_threshold_); - cvfh.setNormalizeBins (normalize_bins_); - cvfh.setRefineClusters(refine_factor_); - - float radius = normal_estimator_->normal_radius_; - float cluster_tolerance_radius = normal_estimator_->grid_resolution_ * cluster_tolerance_factor_; - - if (normal_estimator_->compute_mesh_resolution_) - { - radius = normal_estimator_->mesh_resolution_ * normal_estimator_->factor_normals_; - cluster_tolerance_radius = normal_estimator_->mesh_resolution_ * cluster_tolerance_factor_; - - if (normal_estimator_->do_voxel_grid_) - { - radius *= normal_estimator_->factor_voxel_grid_; - cluster_tolerance_radius *= normal_estimator_->factor_voxel_grid_; - } - } - - cvfh.setClusterTolerance (cluster_tolerance_radius); - cvfh.setRadiusNormals (radius); - cvfh.setMinPoints (100); - cvfh.compute (cvfh_signatures); - - //std::cout << "Res:" << normal_estimator_->mesh_resolution_ << " Radius normals:" << radius << " Cluster tolerance:" << cluster_tolerance_radius << " " << eps_angle_threshold_ << " " << curvature_threshold_ << std::endl; - - for (const auto &point : cvfh_signatures.points) - { - pcl::PointCloud vfh_signature; - vfh_signature.points.resize (1); - vfh_signature.width = vfh_signature.height = 1; - for (int d = 0; d < 308; ++d) - vfh_signature.points[0].histogram[d] = point.histogram[d]; - - signatures.push_back (vfh_signature); - } - - cvfh.getCentroidClusters (centroids); - cvfh.getTransforms(transforms_); - cvfh.getValidTransformsVec(valid_roll_transforms_); - cvfh.getClusterIndices(cluster_indices_); - } - - bool - computedNormals () override - { - return true; - } - - void - setNormalizeBins (bool b) - { - normalize_bins_ = b; - } - }; + void + setNormalizeBins(bool b) + { + normalize_bins_ = b; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/vfh_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/vfh_estimator.h index 2ad9e378..18897c02 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/vfh_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/global/vfh_estimator.h @@ -11,62 +11,62 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework - { - template - class VFHEstimation : public GlobalEstimator - { +namespace pcl { +namespace rec_3d_framework { - using PointInTPtr = typename pcl::PointCloud::Ptr; - using GlobalEstimator::normal_estimator_; - using GlobalEstimator::normals_; +template +class VFHEstimation : public GlobalEstimator { - public: - void - estimate (PointInTPtr & in, PointInTPtr & processed, - typename pcl::PointCloud::CloudVectorType & signatures, - std::vector > & centroids) override - { + using PointInTPtr = typename pcl::PointCloud::Ptr; + using GlobalEstimator::normal_estimator_; + using GlobalEstimator::normals_; - if (!normal_estimator_) - { - PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); - return; - } +public: + void + estimate(PointInTPtr& in, + PointInTPtr& processed, + typename pcl::PointCloud::CloudVectorType& signatures, + std::vector>& + centroids) override + { - normals_.reset(new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals_); + if (!normal_estimator_) { + PCL_ERROR("This feature needs normals... please provide a normal estimator\n"); + return; + } - using VFHEstimation = pcl::VFHEstimation; - pcl::PointCloud vfh_signature; + normals_.reset(new pcl::PointCloud); + normal_estimator_->estimate(in, processed, normals_); - VFHEstimation vfh; - typename pcl::search::KdTree::Ptr vfh_tree (new pcl::search::KdTree); - vfh.setSearchMethod (vfh_tree); - vfh.setInputCloud (processed); - vfh.setInputNormals (normals_); - vfh.setNormalizeBins (true); - vfh.setNormalizeDistance (true); - vfh.compute (vfh_signature); + using VFHEstimation = pcl::VFHEstimation; + pcl::PointCloud vfh_signature; - signatures.resize (1); - centroids.resize (1); + VFHEstimation vfh; + typename pcl::search::KdTree::Ptr vfh_tree( + new pcl::search::KdTree); + vfh.setSearchMethod(vfh_tree); + vfh.setInputCloud(processed); + vfh.setInputNormals(normals_); + vfh.setNormalizeBins(true); + vfh.setNormalizeDistance(true); + vfh.compute(vfh_signature); - signatures[0] = vfh_signature; + signatures.resize(1); + centroids.resize(1); - Eigen::Vector4f centroid4f; - pcl::compute3DCentroid (*in, centroid4f); - centroids[0] = Eigen::Vector3f (centroid4f[0], centroid4f[1], centroid4f[2]); + signatures[0] = vfh_signature; - } + Eigen::Vector4f centroid4f; + pcl::compute3DCentroid(*in, centroid4f); + centroids[0] = Eigen::Vector3f(centroid4f[0], centroid4f[1], centroid4f[2]); + } - bool - computedNormals () override - { - return true; - } - }; + bool + computedNormals() override + { + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/colorshot_local_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/colorshot_local_estimator.h index 506bf63d..f9d4d0e9 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/colorshot_local_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/colorshot_local_estimator.h @@ -12,80 +12,80 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class ColorSHOTLocalEstimation : public LocalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + + using LocalEstimator::support_radius_; + using LocalEstimator::normal_estimator_; + using LocalEstimator::keypoint_extractor_; + +public: + bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) { - template - class ColorSHOTLocalEstimation : public LocalEstimator - { - - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - - using LocalEstimator::support_radius_; - using LocalEstimator::normal_estimator_; - using LocalEstimator::keypoint_extractor_; - - public: - bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures) - { - - if (!normal_estimator_) - { - PCL_ERROR("SHOTLocalEstimation :: This feature needs normals... please provide a normal estimator\n"); - return false; - } - - if (keypoint_extractor_.size() == 0) - { - PCL_ERROR("SHOTLocalEstimation :: This feature needs a keypoint extractor... please provide one\n"); - return false; - } - - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - normals.reset (new pcl::PointCloud); - { - pcl::ScopeTime t ("Compute normals"); - normal_estimator_->estimate (in, processed, normals); - } - - //compute keypoints - computeKeypoints(processed, keypoints, normals); - - if (keypoints->points.size () == 0) - { - PCL_WARN("ColorSHOTLocalEstimation :: No keypoints were found\n"); - return false; - } - - //compute signatures - using SHOTEstimator = pcl::SHOTColorEstimation; - typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); - - pcl::PointCloud::Ptr shots (new pcl::PointCloud); - SHOTEstimator shot_estimate; - shot_estimate.setSearchMethod (tree); - shot_estimate.setInputNormals (normals); - shot_estimate.setInputCloud (keypoints); - shot_estimate.setSearchSurface(processed); - shot_estimate.setRadiusSearch (support_radius_); - shot_estimate.compute (*shots); - signatures->resize (shots->points.size ()); - signatures->width = static_cast (shots->points.size ()); - signatures->height = 1; - - int size_feat = sizeof(signatures->points[0].histogram) / sizeof(float); - - for (std::size_t k = 0; k < shots->points.size (); k++) - for (int i = 0; i < size_feat; i++) - signatures->points[k].histogram[i] = shots->points[k].descriptor[i]; - - return true; - - } - - }; + + if (!normal_estimator_) { + PCL_ERROR("SHOTLocalEstimation :: This feature needs normals... " + "please provide a normal estimator\n"); + return false; + } + + if (keypoint_extractor_.size() == 0) { + PCL_ERROR("SHOTLocalEstimation :: This feature needs a keypoint extractor... " + "please provide one\n"); + return false; + } + + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + normals.reset(new pcl::PointCloud); + { + pcl::ScopeTime t("Compute normals"); + normal_estimator_->estimate(in, processed, normals); + } + + // compute keypoints + computeKeypoints(processed, keypoints, normals); + + if (keypoints->size() == 0) { + PCL_WARN("ColorSHOTLocalEstimation :: No keypoints were found\n"); + return false; + } + + // compute signatures + using SHOTEstimator = + pcl::SHOTColorEstimation; + typename pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + + pcl::PointCloud::Ptr shots(new pcl::PointCloud); + SHOTEstimator shot_estimate; + shot_estimate.setSearchMethod(tree); + shot_estimate.setInputNormals(normals); + shot_estimate.setInputCloud(keypoints); + shot_estimate.setSearchSurface(processed); + shot_estimate.setRadiusSearch(support_radius_); + shot_estimate.compute(*shots); + signatures->resize(shots->size()); + signatures->width = shots->size(); + signatures->height = 1; + + int size_feat = sizeof((*signatures)[0].histogram) / sizeof(float); + + for (std::size_t k = 0; k < shots->size(); k++) + for (int i = 0; i < size_feat; i++) + (*signatures)[k].histogram[i] = (*shots)[k].descriptor[i]; + + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator.h index dfc8f943..c4106401 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator.h @@ -11,80 +11,81 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class FPFHLocalEstimation : public LocalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + using KeypointCloud = pcl::PointCloud; + + using LocalEstimator::support_radius_; + using LocalEstimator::normal_estimator_; + using LocalEstimator::keypoint_extractor_; + +public: + bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) override { - template - class FPFHLocalEstimation : public LocalEstimator - { - - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - using KeypointCloud = pcl::PointCloud; - - using LocalEstimator::support_radius_; - using LocalEstimator::normal_estimator_; - using LocalEstimator::keypoint_extractor_; - - public: - bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures) override - { - - if (!normal_estimator_) - { - PCL_ERROR("FPFHLocalEstimation :: This feature needs normals... please provide a normal estimator\n"); - return false; - } - - if (keypoint_extractor_.empty ()) - { - PCL_ERROR("FPFHLocalEstimation :: This feature needs a keypoint extractor... please provide one\n"); - return false; - } - - //compute normals - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals); - - this->computeKeypoints(processed, keypoints, normals); - std::cout << " " << normals->points.size() << " " << processed->points.size() << std::endl; - - if (keypoints->points.empty ()) - { - PCL_WARN("FPFHLocalEstimation :: No keypoints were found\n"); - return false; - } - - assert (processed->points.size () == normals->points.size ()); - - //compute signatures - using FPFHEstimator = pcl::FPFHEstimation; - typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); - - pcl::PointCloud::Ptr fpfhs (new pcl::PointCloud); - FPFHEstimator fpfh_estimate; - fpfh_estimate.setSearchMethod (tree); - fpfh_estimate.setInputCloud (keypoints); - fpfh_estimate.setSearchSurface(processed); - fpfh_estimate.setInputNormals (normals); - fpfh_estimate.setRadiusSearch (support_radius_); - fpfh_estimate.compute (*fpfhs); - - signatures->resize (fpfhs->points.size ()); - signatures->width = static_cast (fpfhs->points.size ()); - signatures->height = 1; - - int size_feat = 33; - for (std::size_t k = 0; k < fpfhs->points.size (); k++) - for (int i = 0; i < size_feat; i++) - signatures->points[k].histogram[i] = fpfhs->points[k].histogram[i]; - - return true; - - } - - }; + + if (!normal_estimator_) { + PCL_ERROR("FPFHLocalEstimation :: This feature needs normals... " + "please provide a normal estimator\n"); + return false; + } + + if (keypoint_extractor_.empty()) { + PCL_ERROR("FPFHLocalEstimation :: This feature needs a keypoint extractor... " + "please provide one\n"); + return false; + } + + // compute normals + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + normal_estimator_->estimate(in, processed, normals); + + this->computeKeypoints(processed, keypoints, normals); + std::cout << " " << normals->size() << " " << processed->size() << std::endl; + + if (keypoints->points.empty()) { + PCL_WARN("FPFHLocalEstimation :: No keypoints were found\n"); + return false; + } + + assert(processed->size() == normals->size()); + + // compute signatures + using FPFHEstimator = + pcl::FPFHEstimation; + typename pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + + pcl::PointCloud::Ptr fpfhs( + new pcl::PointCloud); + FPFHEstimator fpfh_estimate; + fpfh_estimate.setSearchMethod(tree); + fpfh_estimate.setInputCloud(keypoints); + fpfh_estimate.setSearchSurface(processed); + fpfh_estimate.setInputNormals(normals); + fpfh_estimate.setRadiusSearch(support_radius_); + fpfh_estimate.compute(*fpfhs); + + signatures->resize(fpfhs->size()); + signatures->width = fpfhs->size(); + signatures->height = 1; + + int size_feat = 33; + for (std::size_t k = 0; k < fpfhs->size(); k++) + for (int i = 0; i < size_feat; i++) + (*signatures)[k].histogram[i] = (*fpfhs)[k].histogram[i]; + + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator_omp.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator_omp.h index 83efea13..d2ef140d 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator_omp.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/fpfh_local_estimator_omp.h @@ -11,82 +11,83 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class FPFHLocalEstimationOMP : public LocalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + using KeypointCloud = pcl::PointCloud; + + using LocalEstimator::support_radius_; + using LocalEstimator::normal_estimator_; + using LocalEstimator::keypoint_extractor_; + +public: + bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) { - template - class FPFHLocalEstimationOMP : public LocalEstimator - { - - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - using KeypointCloud = pcl::PointCloud; - - using LocalEstimator::support_radius_; - using LocalEstimator::normal_estimator_; - using LocalEstimator::keypoint_extractor_; - - public: - bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures) - { - - if (!normal_estimator_) - { - PCL_ERROR("FPFHLocalEstimation :: This feature needs normals... please provide a normal estimator\n"); - return false; - } - - if (keypoint_extractor_.size() == 0) - { - PCL_ERROR("FPFHLocalEstimation :: This feature needs a keypoint extractor... please provide one\n"); - return false; - } - - //compute normals - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - normal_estimator_->estimate (in, processed, normals); - - //compute keypoints - computeKeypoints(processed, keypoints, normals); - std::cout << " " << normals->points.size() << " " << processed->points.size() << std::endl; - - if (keypoints->points.size () == 0) - { - PCL_WARN("FPFHLocalEstimation :: No keypoints were found\n"); - return false; - } - - assert (processed->points.size () == normals->points.size ()); - - //compute signatures - using FPFHEstimator = pcl::FPFHEstimationOMP; - typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); - - pcl::PointCloud::Ptr fpfhs (new pcl::PointCloud); - FPFHEstimator fpfh_estimate; - fpfh_estimate.setNumberOfThreads(8); - fpfh_estimate.setSearchMethod (tree); - fpfh_estimate.setInputCloud (keypoints); - fpfh_estimate.setSearchSurface(processed); - fpfh_estimate.setInputNormals (normals); - fpfh_estimate.setRadiusSearch (support_radius_); - fpfh_estimate.compute (*fpfhs); - - signatures->resize (fpfhs->points.size ()); - signatures->width = static_cast (fpfhs->points.size ()); - signatures->height = 1; - - int size_feat = 33; - for (std::size_t k = 0; k < fpfhs->points.size (); k++) - for (int i = 0; i < size_feat; i++) - signatures->points[k].histogram[i] = fpfhs->points[k].histogram[i]; - - return true; - - } - - }; + + if (!normal_estimator_) { + PCL_ERROR("FPFHLocalEstimation :: This feature needs normals... " + "please provide a normal estimator\n"); + return false; + } + + if (keypoint_extractor_.size() == 0) { + PCL_ERROR("FPFHLocalEstimation :: This feature needs a keypoint extractor... " + "please provide one\n"); + return false; + } + + // compute normals + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + normal_estimator_->estimate(in, processed, normals); + + // compute keypoints + computeKeypoints(processed, keypoints, normals); + std::cout << " " << normals->size() << " " << processed->size() << std::endl; + + if (keypoints->size() == 0) { + PCL_WARN("FPFHLocalEstimation :: No keypoints were found\n"); + return false; + } + + assert(processed->size() == normals->size()); + + // compute signatures + using FPFHEstimator = + pcl::FPFHEstimationOMP; + typename pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + + pcl::PointCloud::Ptr fpfhs( + new pcl::PointCloud); + FPFHEstimator fpfh_estimate; + fpfh_estimate.setNumberOfThreads(8); + fpfh_estimate.setSearchMethod(tree); + fpfh_estimate.setInputCloud(keypoints); + fpfh_estimate.setSearchSurface(processed); + fpfh_estimate.setInputNormals(normals); + fpfh_estimate.setRadiusSearch(support_radius_); + fpfh_estimate.compute(*fpfhs); + + signatures->resize(fpfhs->size()); + signatures->width = fpfhs->size(); + signatures->height = 1; + + int size_feat = 33; + for (std::size_t k = 0; k < fpfhs->size(); k++) + for (int i = 0; i < size_feat; i++) + (*signatures)[k].histogram[i] = (*fpfhs)[k].histogram[i]; + + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h index e88d8122..d78c4eec 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h @@ -9,454 +9,445 @@ #include #include -#include #include #include #include +#include #include -namespace pcl -{ - template<> - struct SIFTKeypointFieldSelector - { - inline float - operator () (const PointXYZ & p) const - { - return p.z; - } - }; -} +namespace pcl { -namespace pcl -{ - namespace rec_3d_framework +template <> +struct SIFTKeypointFieldSelector { + inline float + operator()(const PointXYZ& p) const { + return p.z; + } +}; - template - class KeypointExtractor - { - protected: - using PointInTPtr = typename pcl::PointCloud::Ptr; - using PointOutTPtr = typename pcl::PointCloud::Ptr; - typename pcl::PointCloud::Ptr input_; - float radius_; - - public: - virtual - ~KeypointExtractor() = default; - - void - setInputCloud (PointInTPtr & input) - { - input_ = input; - } +} // namespace pcl - void - setSupportRadius (float f) - { - radius_ = f; - } +namespace pcl { +namespace rec_3d_framework { + +template +class KeypointExtractor { +protected: + using PointInTPtr = typename pcl::PointCloud::Ptr; + using PointOutTPtr = typename pcl::PointCloud::Ptr; + typename pcl::PointCloud::Ptr input_; + float radius_; + +public: + virtual ~KeypointExtractor() = default; + + void + setInputCloud(PointInTPtr& input) + { + input_ = input; + } + + void + setSupportRadius(float f) + { + radius_ = f; + } - virtual void - compute (PointOutTPtr & keypoints) = 0; + virtual void + compute(PointOutTPtr& keypoints) = 0; - virtual void - setNormals (const pcl::PointCloud::Ptr & /*normals*/) - { + virtual void + setNormals(const pcl::PointCloud::Ptr& /*normals*/) + {} + virtual bool + needNormals() + { + return false; + } +}; + +template +class UniformSamplingExtractor : public KeypointExtractor { +private: + using PointInTPtr = typename pcl::PointCloud::Ptr; + bool filter_planar_; + using KeypointExtractor::input_; + using KeypointExtractor::radius_; + float sampling_density_; + std::shared_ptr>> neighborhood_indices_; + std::shared_ptr>> neighborhood_dist_; + + void + filterPlanar(PointInTPtr& input, PointInTPtr& keypoints_cloud) + { + pcl::PointCloud filtered_keypoints; + // create a search object + typename pcl::search::Search::Ptr tree; + if (input->isOrganized()) + tree.reset(new pcl::search::OrganizedNeighbor()); + else + tree.reset(new pcl::search::KdTree(false)); + tree->setInputCloud(input); + + neighborhood_indices_.reset(new std::vector>); + neighborhood_indices_->resize(keypoints_cloud->size()); + neighborhood_dist_.reset(new std::vector>); + neighborhood_dist_->resize(keypoints_cloud->size()); + + filtered_keypoints.points.resize(keypoints_cloud->size()); + int good = 0; + + for (std::size_t i = 0; i < keypoints_cloud->size(); i++) { + + if (tree->radiusSearch((*keypoints_cloud)[i], + radius_, + (*neighborhood_indices_)[good], + (*neighborhood_dist_)[good])) { + + EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; + Eigen::Vector4f xyz_centroid; + EIGEN_ALIGN16 Eigen::Vector3f eigenValues; + EIGEN_ALIGN16 Eigen::Matrix3f eigenVectors; + + // compute planarity of the region + computeMeanAndCovarianceMatrix( + *input, (*neighborhood_indices_)[good], covariance_matrix, xyz_centroid); + pcl::eigen33(covariance_matrix, eigenVectors, eigenValues); + + float eigsum = eigenValues.sum(); + if (!std::isfinite(eigsum)) { + PCL_ERROR("Eigen sum is not finite\n"); } - virtual bool - needNormals () - { - return false; + if ((std::abs(eigenValues[0] - eigenValues[1]) < 1.5e-4) || + (eigsum != 0 && std::abs(eigenValues[0] / eigsum) > 1.e-2)) { + // region is not planar, add to filtered keypoint + (*keypoints_cloud)[good] = (*keypoints_cloud)[i]; + good++; } + } + } - }; - - template - class UniformSamplingExtractor : public KeypointExtractor - { - private: - using PointInTPtr = typename pcl::PointCloud::Ptr; - bool filter_planar_; - using KeypointExtractor::input_; - using KeypointExtractor::radius_; - float sampling_density_; - std::shared_ptr>> neighborhood_indices_; - std::shared_ptr>> neighborhood_dist_; - - void - filterPlanar (PointInTPtr & input, PointInTPtr & keypoints_cloud) - { - pcl::PointCloud filtered_keypoints; - //create a search object - typename pcl::search::Search::Ptr tree; - if (input->isOrganized ()) - tree.reset (new pcl::search::OrganizedNeighbor ()); - else - tree.reset (new pcl::search::KdTree (false)); - tree->setInputCloud (input); - - neighborhood_indices_.reset (new std::vector >); - neighborhood_indices_->resize (keypoints_cloud->points.size ()); - neighborhood_dist_.reset (new std::vector >); - neighborhood_dist_->resize (keypoints_cloud->points.size ()); - - filtered_keypoints.points.resize (keypoints_cloud->points.size ()); - int good = 0; - - for (std::size_t i = 0; i < keypoints_cloud->points.size (); i++) - { - - if (tree->radiusSearch (keypoints_cloud->points[i], radius_, (*neighborhood_indices_)[good], (*neighborhood_dist_)[good])) - { - - EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; - Eigen::Vector4f xyz_centroid; - EIGEN_ALIGN16 Eigen::Vector3f eigenValues; - EIGEN_ALIGN16 Eigen::Matrix3f eigenVectors; - - //compute planarity of the region - computeMeanAndCovarianceMatrix (*input, (*neighborhood_indices_)[good], covariance_matrix, xyz_centroid); - pcl::eigen33 (covariance_matrix, eigenVectors, eigenValues); - - float eigsum = eigenValues.sum (); - if (!std::isfinite(eigsum)) - { - PCL_ERROR("Eigen sum is not finite\n"); - } - - if ((std::abs (eigenValues[0] - eigenValues[1]) < 1.5e-4) || (eigsum != 0 && std::abs (eigenValues[0] / eigsum) > 1.e-2)) - { - //region is not planar, add to filtered keypoint - keypoints_cloud->points[good] = keypoints_cloud->points[i]; - good++; - } - } - } - - neighborhood_indices_->resize (good); - neighborhood_dist_->resize (good); - keypoints_cloud->points.resize (good); - - neighborhood_indices_->clear (); - neighborhood_dist_->clear (); + neighborhood_indices_->resize(good); + neighborhood_dist_->resize(good); + keypoints_cloud->points.resize(good); - } + neighborhood_indices_->clear(); + neighborhood_dist_->clear(); + } - public: +public: + void + setFilterPlanar(bool b) + { + filter_planar_ = b; + } - void - setFilterPlanar (bool b) - { - filter_planar_ = b; - } + void + setSamplingDensity(float f) + { + sampling_density_ = f; + } - void - setSamplingDensity (float f) - { - sampling_density_ = f; - } + void + compute(PointInTPtr& keypoints) override + { + keypoints.reset(new pcl::PointCloud); - void - compute (PointInTPtr & keypoints) override - { - keypoints.reset (new pcl::PointCloud); + pcl::UniformSampling keypoint_extractor; + keypoint_extractor.setRadiusSearch(sampling_density_); + keypoint_extractor.setInputCloud(input_); - pcl::UniformSampling keypoint_extractor; - keypoint_extractor.setRadiusSearch (sampling_density_); - keypoint_extractor.setInputCloud (input_); + keypoint_extractor.filter(*keypoints); - keypoint_extractor.filter (*keypoints); + if (filter_planar_) + filterPlanar(input_, keypoints); + } +}; - if (filter_planar_) - filterPlanar (input_, keypoints); - } - }; - - template - class SIFTKeypointExtractor : public KeypointExtractor - { - using PointInTPtr = typename pcl::PointCloud::Ptr; - using KeypointExtractor::input_; - using KeypointExtractor::radius_; - - public: - void - compute (PointInTPtr & keypoints) - { - keypoints.reset (new pcl::PointCloud); - - typename pcl::PointCloud::Ptr intensity_keypoints (new pcl::PointCloud); - pcl::SIFTKeypoint sift3D; - sift3D.setScales (0.003f, 3, 2); - sift3D.setMinimumContrast (0.1f); - sift3D.setInputCloud (input_); - sift3D.setSearchSurface (input_); - sift3D.compute (*intensity_keypoints); - pcl::copyPointCloud (*intensity_keypoints, *keypoints); - } - }; - - template - class SIFTSurfaceKeypointExtractor : public KeypointExtractor - { - using PointInTPtr = typename pcl::PointCloud::Ptr; - pcl::PointCloud::Ptr normals_; - using KeypointExtractor::input_; - using KeypointExtractor::radius_; - - bool - needNormals () - { - return true; - } +template +class SIFTKeypointExtractor : public KeypointExtractor { + using PointInTPtr = typename pcl::PointCloud::Ptr; + using KeypointExtractor::input_; + using KeypointExtractor::radius_; - void - setNormals (const pcl::PointCloud::Ptr & normals) - { - normals_ = normals; - } +public: + void + compute(PointInTPtr& keypoints) + { + keypoints.reset(new pcl::PointCloud); + + typename pcl::PointCloud::Ptr intensity_keypoints( + new pcl::PointCloud); + pcl::SIFTKeypoint sift3D; + sift3D.setScales(0.003f, 3, 2); + sift3D.setMinimumContrast(0.1f); + sift3D.setInputCloud(input_); + sift3D.setSearchSurface(input_); + sift3D.compute(*intensity_keypoints); + pcl::copyPointCloud(*intensity_keypoints, *keypoints); + } +}; - public: - void - compute (PointInTPtr & keypoints) - { - if (normals_ == 0 || (normals_->points.size () != input_->points.size ())) - PCL_WARN("SIFTSurfaceKeypointExtractor -- Normals are not valid\n"); - - keypoints.reset (new pcl::PointCloud); - - typename pcl::PointCloud::Ptr input_cloud (new pcl::PointCloud); - input_cloud->width = input_->width; - input_cloud->height = input_->height; - input_cloud->points.resize (input_->width * input_->height); - for (std::size_t i = 0; i < input_->points.size (); i++) - { - input_cloud->points[i].getVector3fMap () = input_->points[i].getVector3fMap (); - input_cloud->points[i].getNormalVector3fMap () = normals_->points[i].getNormalVector3fMap (); - } - - typename pcl::PointCloud::Ptr intensity_keypoints (new pcl::PointCloud); - pcl::SIFTKeypoint sift3D; - sift3D.setScales (0.003f, 3, 2); - sift3D.setMinimumContrast (0.0); - sift3D.setInputCloud (input_cloud); - sift3D.setSearchSurface (input_cloud); - sift3D.compute (*intensity_keypoints); - pcl::copyPointCloud (*intensity_keypoints, *keypoints); - } - }; - - template - class HarrisKeypointExtractor : public KeypointExtractor - { - - pcl::PointCloud::Ptr normals_; - using PointInTPtr = typename pcl::PointCloud::Ptr; - using KeypointExtractor::input_; - using KeypointExtractor::radius_; - typename pcl::HarrisKeypoint3D::ResponseMethod m_; - float non_max_radius_; - float threshold_; - - public: - - HarrisKeypointExtractor () - { - m_ = pcl::HarrisKeypoint3D::HARRIS; - non_max_radius_ = 0.01f; - threshold_ = 0.f; - } +template +class SIFTSurfaceKeypointExtractor : public KeypointExtractor { + using PointInTPtr = typename pcl::PointCloud::Ptr; + pcl::PointCloud::Ptr normals_; + using KeypointExtractor::input_; + using KeypointExtractor::radius_; - bool - needNormals () - { - return true; - } + bool + needNormals() + { + return true; + } - void - setNormals (const pcl::PointCloud::Ptr & normals) - { - normals_ = normals; - } + void + setNormals(const pcl::PointCloud::Ptr& normals) + { + normals_ = normals; + } - void - setThreshold(float t) { - threshold_ = t; - } +public: + void + compute(PointInTPtr& keypoints) + { + if (normals_ == 0 || (normals_->size() != input_->size())) + PCL_WARN("SIFTSurfaceKeypointExtractor -- Normals are not valid\n"); + + keypoints.reset(new pcl::PointCloud); + + typename pcl::PointCloud::Ptr input_cloud( + new pcl::PointCloud); + input_cloud->width = input_->width; + input_cloud->height = input_->height; + input_cloud->points.resize(input_->width * input_->height); + for (std::size_t i = 0; i < input_->points.size(); i++) { + (*input_cloud)[i].getVector3fMap() = (*input_)[i].getVector3fMap(); + (*input_cloud)[i].getNormalVector3fMap() = (*normals_)[i].getNormalVector3fMap(); + } + + typename pcl::PointCloud::Ptr intensity_keypoints( + new pcl::PointCloud); + pcl::SIFTKeypoint sift3D; + sift3D.setScales(0.003f, 3, 2); + sift3D.setMinimumContrast(0.0); + sift3D.setInputCloud(input_cloud); + sift3D.setSearchSurface(input_cloud); + sift3D.compute(*intensity_keypoints); + pcl::copyPointCloud(*intensity_keypoints, *keypoints); + } +}; - void - setResponseMethod (typename pcl::HarrisKeypoint3D::ResponseMethod m) - { - m_ = m; - } +template +class HarrisKeypointExtractor : public KeypointExtractor { - void - setNonMaximaRadius(float r) { - non_max_radius_ = r; - } + pcl::PointCloud::Ptr normals_; + using PointInTPtr = typename pcl::PointCloud::Ptr; + using KeypointExtractor::input_; + using KeypointExtractor::radius_; + typename pcl::HarrisKeypoint3D::ResponseMethod m_; + float non_max_radius_; + float threshold_; + +public: + HarrisKeypointExtractor() + { + m_ = pcl::HarrisKeypoint3D::HARRIS; + non_max_radius_ = 0.01f; + threshold_ = 0.f; + } - void - compute (PointInTPtr & keypoints) - { - keypoints.reset (new pcl::PointCloud); + bool + needNormals() + { + return true; + } - if (normals_ == 0 || (normals_->points.size () != input_->points.size ())) - PCL_WARN("HarrisKeypointExtractor -- Normals are not valid\n"); + void + setNormals(const pcl::PointCloud::Ptr& normals) + { + normals_ = normals; + } - typename pcl::PointCloud::Ptr intensity_keypoints (new pcl::PointCloud); + void + setThreshold(float t) + { + threshold_ = t; + } - pcl::HarrisKeypoint3D harris; - harris.setNonMaxSupression (true); - harris.setRefine (false); - harris.setThreshold (threshold_); - harris.setInputCloud (input_); - harris.setNormals (normals_); - harris.setRadius (non_max_radius_); - harris.setRadiusSearch (non_max_radius_); - harris.setMethod (m_); - harris.compute (*intensity_keypoints); + void + setResponseMethod( + typename pcl::HarrisKeypoint3D::ResponseMethod m) + { + m_ = m; + } - pcl::copyPointCloud (*intensity_keypoints, *keypoints); - } - }; + void + setNonMaximaRadius(float r) + { + non_max_radius_ = r; + } - template - class SUSANKeypointExtractor : public KeypointExtractor - { + void + compute(PointInTPtr& keypoints) + { + keypoints.reset(new pcl::PointCloud); + + if (normals_ == 0 || (normals_->size() != input_->size())) + PCL_WARN("HarrisKeypointExtractor -- Normals are not valid\n"); + + typename pcl::PointCloud::Ptr intensity_keypoints( + new pcl::PointCloud); + + pcl::HarrisKeypoint3D harris; + harris.setNonMaxSupression(true); + harris.setRefine(false); + harris.setThreshold(threshold_); + harris.setInputCloud(input_); + harris.setNormals(normals_); + harris.setRadius(non_max_radius_); + harris.setRadiusSearch(non_max_radius_); + harris.setMethod(m_); + harris.compute(*intensity_keypoints); + + pcl::copyPointCloud(*intensity_keypoints, *keypoints); + } +}; - pcl::PointCloud::Ptr normals_; - using PointInTPtr = typename pcl::PointCloud::Ptr; - using KeypointExtractor::input_; - using KeypointExtractor::radius_; +template +class SUSANKeypointExtractor : public KeypointExtractor { - public: + pcl::PointCloud::Ptr normals_; + using PointInTPtr = typename pcl::PointCloud::Ptr; + using KeypointExtractor::input_; + using KeypointExtractor::radius_; - SUSANKeypointExtractor () - { +public: + SUSANKeypointExtractor() {} - } + bool + needNormals() + { + return true; + } - bool - needNormals () - { - return true; - } + void + setNormals(const pcl::PointCloud::Ptr& normals) + { + normals_ = normals; + } - void - setNormals (const pcl::PointCloud::Ptr & normals) - { - normals_ = normals; - } + void + compute(PointInTPtr& keypoints) + { + keypoints.reset(new pcl::PointCloud); + + if (normals_ == 0 || (normals_->size() != input_->size())) + PCL_WARN("SUSANKeypointExtractor -- Normals are not valid\n"); - void - compute (PointInTPtr & keypoints) - { - keypoints.reset (new pcl::PointCloud); + typename pcl::PointCloud::Ptr intensity_keypoints( + new pcl::PointCloud); - if (normals_ == 0 || (normals_->points.size () != input_->points.size ())) - PCL_WARN("SUSANKeypointExtractor -- Normals are not valid\n"); + pcl::SUSANKeypoint susan; + susan.setNonMaxSupression(true); + susan.setInputCloud(input_); + susan.setNormals(normals_); + susan.setRadius(0.01f); + susan.setRadiusSearch(0.01f); + susan.compute(*intensity_keypoints); - typename pcl::PointCloud::Ptr intensity_keypoints (new pcl::PointCloud); + pcl::copyPointCloud(*intensity_keypoints, *keypoints); + } +}; - pcl::SUSANKeypoint susan; - susan.setNonMaxSupression (true); - susan.setInputCloud (input_); - susan.setNormals (normals_); - susan.setRadius (0.01f); - susan.setRadiusSearch (0.01f); - susan.compute (*intensity_keypoints); +template +class LocalEstimator { +protected: + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; - pcl::copyPointCloud (*intensity_keypoints, *keypoints); - } - }; - - template - class LocalEstimator - { - protected: - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - - std::shared_ptr> normal_estimator_; - std::vector>> keypoint_extractor_; //this should be a vector - float support_radius_; - //bool filter_planar_; - - bool adaptative_MLS_; - - std::shared_ptr>> neighborhood_indices_; - std::shared_ptr>> neighborhood_dist_; - - void - computeKeypoints (PointInTPtr & cloud, PointInTPtr & keypoints, pcl::PointCloud::Ptr & normals) - { - keypoints.reset (new pcl::PointCloud); - for (std::size_t i = 0; i < keypoint_extractor_.size (); i++) - { - keypoint_extractor_[i]->setInputCloud (cloud); - if (keypoint_extractor_[i]->needNormals ()) - keypoint_extractor_[i]->setNormals (normals); - - keypoint_extractor_[i]->setSupportRadius (support_radius_); - - PointInTPtr detected_keypoints; - keypoint_extractor_[i]->compute (detected_keypoints); - *keypoints += *detected_keypoints; - } - } + std::shared_ptr> + normal_estimator_; + std::vector>> keypoint_extractor_; + float support_radius_; - public: + bool adaptative_MLS_; - LocalEstimator () - { - adaptative_MLS_ = false; - keypoint_extractor_.clear (); - } + std::shared_ptr>> neighborhood_indices_; + std::shared_ptr>> neighborhood_dist_; - virtual - ~LocalEstimator() = default; + void + computeKeypoints(PointInTPtr& cloud, + PointInTPtr& keypoints, + pcl::PointCloud::Ptr& normals) + { + keypoints.reset(new pcl::PointCloud); + for (std::size_t i = 0; i < keypoint_extractor_.size(); i++) { + keypoint_extractor_[i]->setInputCloud(cloud); + if (keypoint_extractor_[i]->needNormals()) + keypoint_extractor_[i]->setNormals(normals); + + keypoint_extractor_[i]->setSupportRadius(support_radius_); + + PointInTPtr detected_keypoints; + keypoint_extractor_[i]->compute(detected_keypoints); + *keypoints += *detected_keypoints; + } + } - void - setAdaptativeMLS (bool b) - { - adaptative_MLS_ = b; - } +public: + LocalEstimator() + { + adaptative_MLS_ = false; + keypoint_extractor_.clear(); + } - virtual bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures)=0; + virtual ~LocalEstimator() = default; - void - setNormalEstimator (std::shared_ptr> & ne) - { - normal_estimator_ = ne; - } + void + setAdaptativeMLS(bool b) + { + adaptative_MLS_ = b; + } - /** - * \brief Right now only uniformSampling keypoint extractor is allowed - */ - void - addKeypointExtractor (std::shared_ptr>& ke) - { - keypoint_extractor_.push_back (ke); - } + virtual bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) = 0; - void - setKeypointExtractors (std::vector>>& ke) - { - keypoint_extractor_ = ke; - } + void + setNormalEstimator( + std::shared_ptr>& ne) + { + normal_estimator_ = ne; + } - void - setSupportRadius (float r) - { - support_radius_ = r; - } + /** + * \brief Right now only uniformSampling keypoint extractor is allowed + */ + void + addKeypointExtractor(std::shared_ptr>& ke) + { + keypoint_extractor_.push_back(ke); + } + + void + setKeypointExtractors(std::vector>>& ke) + { + keypoint_extractor_ = ke; + } - }; + void + setSupportRadius(float r) + { + support_radius_ = r; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator.h index 06f5cc06..9fef4505 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator.h @@ -12,130 +12,113 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class SHOTLocalEstimation : public LocalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + + using LocalEstimator::support_radius_; + using LocalEstimator::normal_estimator_; + using LocalEstimator::keypoint_extractor_; + using LocalEstimator::adaptative_MLS_; + +public: + bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) override { - template - class SHOTLocalEstimation : public LocalEstimator - { - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - - using LocalEstimator::support_radius_; - using LocalEstimator::normal_estimator_; - using LocalEstimator::keypoint_extractor_; - using LocalEstimator::adaptative_MLS_; - - public: - bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures) override - { - - if (!normal_estimator_) - { - PCL_ERROR("SHOTLocalEstimation :: This feature needs normals... please provide a normal estimator\n"); - return false; - } - - if (keypoint_extractor_.empty ()) - { - PCL_ERROR("SHOTLocalEstimation :: This feature needs a keypoint extractor... please provide one\n"); - return false; - } - - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - pcl::MovingLeastSquares mls; - if(adaptative_MLS_) { - typename search::KdTree::Ptr tree; - Eigen::Vector4f centroid_cluster; - pcl::compute3DCentroid (*in, centroid_cluster); - float dist_to_sensor = centroid_cluster.norm(); - float sigma = dist_to_sensor * 0.01f; - mls.setSearchMethod(tree); - mls.setSearchRadius (sigma); - mls.setUpsamplingMethod (mls.SAMPLE_LOCAL_PLANE); - mls.setUpsamplingRadius (0.002); - mls.setUpsamplingStepSize (0.001); - } - - normals.reset (new pcl::PointCloud); - { - pcl::ScopeTime t ("Compute normals"); - normal_estimator_->estimate (in, processed, normals); - } - - if(adaptative_MLS_) { - mls.setInputCloud(processed); - - PointInTPtr filtered(new pcl::PointCloud); - mls.process(*filtered); - - processed.reset(new pcl::PointCloud); - normals.reset (new pcl::PointCloud); - { - pcl::ScopeTime t ("Compute normals after MLS"); - filtered->is_dense = false; - normal_estimator_->estimate (filtered, processed, normals); - } - } - - //compute normals - //pcl::PointCloud::Ptr normals (new pcl::PointCloud); - //normal_estimator_->estimate (in, processed, normals); - - //compute keypoints - this->computeKeypoints(processed, keypoints, normals); - std::cout << " " << normals->points.size() << " " << processed->points.size() << std::endl; - - //compute keypoints - /*keypoint_extractor_->setInputCloud (processed); - if(keypoint_extractor_->needNormals()) - keypoint_extractor_->setNormals(normals); - - std::cout << " " << normals->points.size() << " " << processed->points.size() << std::endl; - - keypoint_extractor_->setSupportRadius(support_radius_); - keypoint_extractor_->compute (keypoints);*/ - - if (keypoints->points.empty ()) - { - PCL_WARN("SHOTLocalEstimation :: No keypoints were found\n"); - return false; - } - - std::cout << keypoints->points.size() << " " << normals->points.size() << " " << processed->points.size() << std::endl; - //compute signatures - using SHOTEstimator = pcl::SHOTEstimation; - typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); - - pcl::PointCloud::Ptr shots (new pcl::PointCloud); - - SHOTEstimator shot_estimate; - shot_estimate.setSearchMethod (tree); - shot_estimate.setInputCloud (keypoints); - shot_estimate.setSearchSurface(processed); - shot_estimate.setInputNormals (normals); - shot_estimate.setRadiusSearch (support_radius_); - shot_estimate.compute (*shots); - signatures->resize (shots->points.size ()); - signatures->width = static_cast (shots->points.size ()); - signatures->height = 1; - - int size_feat = sizeof(signatures->points[0].histogram) / sizeof(float); - - for (std::size_t k = 0; k < shots->points.size (); k++) - for (int i = 0; i < size_feat; i++) - signatures->points[k].histogram[i] = shots->points[k].descriptor[i]; - - return true; - - } - - private: - - - }; + if (!normal_estimator_) { + PCL_ERROR("SHOTLocalEstimation :: This feature needs normals... " + "please provide a normal estimator\n"); + return false; + } + + if (keypoint_extractor_.empty()) { + PCL_ERROR("SHOTLocalEstimation :: This feature needs a keypoint extractor... " + "please provide one\n"); + return false; + } + + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + pcl::MovingLeastSquares mls; + if (adaptative_MLS_) { + typename search::KdTree::Ptr tree; + Eigen::Vector4f centroid_cluster; + pcl::compute3DCentroid(*in, centroid_cluster); + float dist_to_sensor = centroid_cluster.norm(); + float sigma = dist_to_sensor * 0.01f; + mls.setSearchMethod(tree); + mls.setSearchRadius(sigma); + mls.setUpsamplingMethod(mls.SAMPLE_LOCAL_PLANE); + mls.setUpsamplingRadius(0.002); + mls.setUpsamplingStepSize(0.001); + } + + normals.reset(new pcl::PointCloud); + { + pcl::ScopeTime t("Compute normals"); + normal_estimator_->estimate(in, processed, normals); + } + + if (adaptative_MLS_) { + mls.setInputCloud(processed); + + PointInTPtr filtered(new pcl::PointCloud); + mls.process(*filtered); + + processed.reset(new pcl::PointCloud); + normals.reset(new pcl::PointCloud); + { + pcl::ScopeTime t("Compute normals after MLS"); + filtered->is_dense = false; + normal_estimator_->estimate(filtered, processed, normals); + } + } + + // compute keypoints + this->computeKeypoints(processed, keypoints, normals); + std::cout << " " << normals->size() << " " << processed->size() << std::endl; + + if (keypoints->points.empty()) { + PCL_WARN("SHOTLocalEstimation :: No keypoints were found\n"); + return false; + } + + std::cout << keypoints->size() << " " << normals->size() << " " << processed->size() + << std::endl; + // compute signatures + using SHOTEstimator = pcl::SHOTEstimation; + typename pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + + pcl::PointCloud::Ptr shots(new pcl::PointCloud); + + SHOTEstimator shot_estimate; + shot_estimate.setSearchMethod(tree); + shot_estimate.setInputCloud(keypoints); + shot_estimate.setSearchSurface(processed); + shot_estimate.setInputNormals(normals); + shot_estimate.setRadiusSearch(support_radius_); + shot_estimate.compute(*shots); + signatures->resize(shots->size()); + signatures->width = shots->size(); + signatures->height = 1; + + int size_feat = sizeof((*signatures)[0].histogram) / sizeof(float); + + for (std::size_t k = 0; k < shots->size(); k++) + for (int i = 0; i < size_feat; i++) + (*signatures)[k].histogram[i] = (*shots)[k].descriptor[i]; + + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator_omp.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator_omp.h index a0f1282e..3b86d64a 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator_omp.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/shot_local_estimator_omp.h @@ -12,142 +12,134 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +template +class SHOTLocalEstimationOMP : public LocalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; + using FeatureTPtr = typename pcl::PointCloud::Ptr; + using KeypointCloud = pcl::PointCloud; + + using LocalEstimator::support_radius_; + using LocalEstimator::normal_estimator_; + using LocalEstimator::keypoint_extractor_; + using LocalEstimator::neighborhood_indices_; + using LocalEstimator::neighborhood_dist_; + using LocalEstimator::adaptative_MLS_; + +public: + bool + estimate(PointInTPtr& in, + PointInTPtr& processed, + PointInTPtr& keypoints, + FeatureTPtr& signatures) override { - template - class SHOTLocalEstimationOMP : public LocalEstimator + if (!normal_estimator_) { + PCL_ERROR("SHOTLocalEstimationOMP :: This feature needs normals... please " + "provide a normal estimator\n"); + return false; + } + + if (keypoint_extractor_.empty()) { + PCL_ERROR("SHOTLocalEstimationOMP :: This feature needs a keypoint extractor... " + "please provide one\n"); + return false; + } + + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + pcl::MovingLeastSquares mls; + if (adaptative_MLS_) { + typename search::KdTree::Ptr tree; + Eigen::Vector4f centroid_cluster; + pcl::compute3DCentroid(*in, centroid_cluster); + float dist_to_sensor = centroid_cluster.norm(); + float sigma = dist_to_sensor * 0.01f; + mls.setSearchMethod(tree); + mls.setSearchRadius(sigma); + mls.setUpsamplingMethod(mls.SAMPLE_LOCAL_PLANE); + mls.setUpsamplingRadius(0.002); + mls.setUpsamplingStepSize(0.001); + } + + normals.reset(new pcl::PointCloud); + { + pcl::ScopeTime t("Compute normals"); + normal_estimator_->estimate(in, processed, normals); + } + + if (adaptative_MLS_) { + mls.setInputCloud(processed); + + PointInTPtr filtered(new pcl::PointCloud); + mls.process(*filtered); + + processed.reset(new pcl::PointCloud); + normals.reset(new pcl::PointCloud); { - - using PointInTPtr = typename pcl::PointCloud::Ptr; - using FeatureTPtr = typename pcl::PointCloud::Ptr; - using KeypointCloud = pcl::PointCloud; - - using LocalEstimator::support_radius_; - using LocalEstimator::normal_estimator_; - using LocalEstimator::keypoint_extractor_; - using LocalEstimator::neighborhood_indices_; - using LocalEstimator::neighborhood_dist_; - using LocalEstimator::adaptative_MLS_; - - public: - bool - estimate (PointInTPtr & in, PointInTPtr & processed, PointInTPtr & keypoints, FeatureTPtr & signatures) override - { - if (!normal_estimator_) - { - PCL_ERROR("SHOTLocalEstimationOMP :: This feature needs normals... please provide a normal estimator\n"); - return false; - } - - if (keypoint_extractor_.empty ()) - { - PCL_ERROR("SHOTLocalEstimationOMP :: This feature needs a keypoint extractor... please provide one\n"); - return false; - } - - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - pcl::MovingLeastSquares mls; - if (adaptative_MLS_) - { - typename search::KdTree::Ptr tree; - Eigen::Vector4f centroid_cluster; - pcl::compute3DCentroid (*in, centroid_cluster); - float dist_to_sensor = centroid_cluster.norm (); - float sigma = dist_to_sensor * 0.01f; - mls.setSearchMethod (tree); - mls.setSearchRadius (sigma); - mls.setUpsamplingMethod (mls.SAMPLE_LOCAL_PLANE); - mls.setUpsamplingRadius (0.002); - mls.setUpsamplingStepSize (0.001); - } - - normals.reset (new pcl::PointCloud); - { - pcl::ScopeTime t ("Compute normals"); - normal_estimator_->estimate (in, processed, normals); - } - - if (adaptative_MLS_) - { - mls.setInputCloud (processed); - - PointInTPtr filtered (new pcl::PointCloud); - mls.process (*filtered); - - processed.reset (new pcl::PointCloud); - normals.reset (new pcl::PointCloud); - { - pcl::ScopeTime t ("Compute normals after MLS"); - filtered->is_dense = false; - normal_estimator_->estimate (filtered, processed, normals); - } - } - - this->computeKeypoints(processed, keypoints, normals); - std::cout << " " << normals->points.size() << " " << processed->points.size() << std::endl; - - if (keypoints->points.empty ()) - { - PCL_WARN("SHOTLocalEstimationOMP :: No keypoints were found\n"); - return false; - } - - //compute signatures - using SHOTEstimator = pcl::SHOTEstimationOMP; - typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); - tree->setInputCloud (processed); - - pcl::PointCloud::Ptr shots (new pcl::PointCloud); - SHOTEstimator shot_estimate; - shot_estimate.setNumberOfThreads (8); - shot_estimate.setSearchMethod (tree); - shot_estimate.setInputCloud (keypoints); - shot_estimate.setSearchSurface(processed); - shot_estimate.setInputNormals (normals); - shot_estimate.setRadiusSearch (support_radius_); - - { - pcl::ScopeTime t ("Compute SHOT"); - shot_estimate.compute (*shots); - } - - signatures->resize (shots->points.size ()); - signatures->width = static_cast (shots->points.size ()); - signatures->height = 1; - - int size_feat = sizeof(signatures->points[0].histogram) / sizeof(float); - - int good = 0; - for (const auto &point : shots->points) - { - - int NaNs = 0; - for (int i = 0; i < size_feat; i++) - { - if (!std::isfinite(point.descriptor[i])) - NaNs++; - } - - if (NaNs == 0) - { - for (int i = 0; i < size_feat; i++) - { - signatures->points[good].histogram[i] = point.descriptor[i]; - } - - good++; - } - } - - signatures->resize (good); - signatures->width = good; - - return true; - + pcl::ScopeTime t("Compute normals after MLS"); + filtered->is_dense = false; + normal_estimator_->estimate(filtered, processed, normals); + } + } + + this->computeKeypoints(processed, keypoints, normals); + std::cout << " " << normals->size() << " " << processed->size() << std::endl; + + if (keypoints->points.empty()) { + PCL_WARN("SHOTLocalEstimationOMP :: No keypoints were found\n"); + return false; + } + + // compute signatures + using SHOTEstimator = pcl::SHOTEstimationOMP; + typename pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + tree->setInputCloud(processed); + + pcl::PointCloud::Ptr shots(new pcl::PointCloud); + SHOTEstimator shot_estimate; + shot_estimate.setNumberOfThreads(8); + shot_estimate.setSearchMethod(tree); + shot_estimate.setInputCloud(keypoints); + shot_estimate.setSearchSurface(processed); + shot_estimate.setInputNormals(normals); + shot_estimate.setRadiusSearch(support_radius_); + + { + pcl::ScopeTime t("Compute SHOT"); + shot_estimate.compute(*shots); + } + + signatures->resize(shots->size()); + signatures->width = shots->size(); + signatures->height = 1; + + int size_feat = sizeof((*signatures)[0].histogram) / sizeof(float); + + int good = 0; + for (const auto& point : shots->points) { + + int NaNs = 0; + for (int i = 0; i < size_feat; i++) { + if (!std::isfinite(point.descriptor[i])) + NaNs++; + } + + if (NaNs == 0) { + for (int i = 0; i < size_feat; i++) { + (*signatures)[good].histogram[i] = point.descriptor[i]; } - }; + good++; + } + } + signatures->resize(good); + signatures->width = good; + + return true; } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h index 49ddcc5d..b1a7f539 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h @@ -7,290 +7,260 @@ #pragma once +#include +#include +#include #include #include -#include -#include -#include -#include // for pcl::make_shared +#include // for pcl::make_shared +#include // for pcl::index_t + +namespace pcl { +namespace rec_3d_framework { + +template +class PreProcessorAndNormalEstimator { + + using PointInTPtr = typename pcl::PointCloud::Ptr; -namespace pcl -{ - namespace rec_3d_framework + float + computeMeshResolution(PointInTPtr& input) { - template - class PreProcessorAndNormalEstimator - { + using KdTreeInPtr = typename pcl::KdTree::Ptr; + KdTreeInPtr tree = pcl::make_shared>(false); + tree->setInputCloud(input); - using PointInTPtr = typename pcl::PointCloud::Ptr; + std::vector nn_indices(9); + std::vector nn_distances(9); + std::vector src_indices; - float - computeMeshResolution (PointInTPtr & input) - { - using KdTreeInPtr = typename pcl::KdTree::Ptr; - KdTreeInPtr tree = pcl::make_shared > (false); - tree->setInputCloud (input); + float sum_distances = 0.0; + std::vector avg_distances(input->size()); + // Iterate through the source data set + for (std::size_t i = 0; i < input->size(); ++i) { + tree->nearestKSearch((*input)[i], 9, nn_indices, nn_distances); - std::vector nn_indices (9); - std::vector nn_distances (9); - std::vector src_indices; + float avg_dist_neighbours = 0.0; + for (std::size_t j = 1; j < nn_indices.size(); j++) + avg_dist_neighbours += std::sqrt(nn_distances[j]); - float sum_distances = 0.0; - std::vector avg_distances (input->points.size ()); - // Iterate through the source data set - for (std::size_t i = 0; i < input->points.size (); ++i) - { - tree->nearestKSearch (input->points[i], 9, nn_indices, nn_distances); + avg_dist_neighbours /= static_cast(nn_indices.size()); - float avg_dist_neighbours = 0.0; - for (std::size_t j = 1; j < nn_indices.size (); j++) - avg_dist_neighbours += std::sqrt (nn_distances[j]); + avg_distances[i] = avg_dist_neighbours; + sum_distances += avg_dist_neighbours; + } - avg_dist_neighbours /= static_cast (nn_indices.size ()); + std::sort(avg_distances.begin(), avg_distances.end()); + float avg = avg_distances[static_cast(avg_distances.size()) / 2 + 1]; + return avg; + } - avg_distances[i] = avg_dist_neighbours; - sum_distances += avg_dist_neighbours; - } +public: + bool compute_mesh_resolution_; + bool do_voxel_grid_; + bool remove_outliers_; - std::sort (avg_distances.begin (), avg_distances.end ()); - float avg = avg_distances[static_cast (avg_distances.size ()) / 2 + 1]; - return avg; - } + // this values are used when CMR=false + float grid_resolution_; + float normal_radius_; - public: + // this are used when CMR=true + float factor_normals_; + float factor_voxel_grid_; + float mesh_resolution_; - bool compute_mesh_resolution_; - bool do_voxel_grid_; - bool remove_outliers_; + PreProcessorAndNormalEstimator() + { + remove_outliers_ = do_voxel_grid_ = compute_mesh_resolution_ = false; + } - //this values are used when CMR=false - float grid_resolution_; - float normal_radius_; + void + setFactorsForCMR(float f1, float f2) + { + factor_voxel_grid_ = f1; + factor_normals_ = f2; + } - //this are used when CMR=true - float factor_normals_; - float factor_voxel_grid_; - float mesh_resolution_; + void + setValuesForCMRFalse(float f1, float f2) + { + grid_resolution_ = f1; + normal_radius_ = f2; + } - PreProcessorAndNormalEstimator () - { - remove_outliers_ = do_voxel_grid_ = compute_mesh_resolution_ = false; - } + void + setDoVoxelGrid(bool b) + { + do_voxel_grid_ = b; + } - void - setFactorsForCMR (float f1, float f2) - { - factor_voxel_grid_ = f1; - factor_normals_ = f2; - } + void + setRemoveOutliers(bool b) + { + remove_outliers_ = b; + } - void - setValuesForCMRFalse (float f1, float f2) - { - grid_resolution_ = f1; - normal_radius_ = f2; - } + void + setCMR(bool b) + { + compute_mesh_resolution_ = b; + } - void - setDoVoxelGrid (bool b) - { - do_voxel_grid_ = b; - } + void + estimate(PointInTPtr& in, + PointInTPtr& out, + pcl::PointCloud::Ptr& normals) + { + if (compute_mesh_resolution_) { + mesh_resolution_ = computeMeshResolution(in); + std::cout << "compute mesh resolution:" << mesh_resolution_ << std::endl; + } + + if (do_voxel_grid_) { + pcl::ScopeTime t("Voxel grid..."); + float voxel_grid_size = grid_resolution_; + if (compute_mesh_resolution_) { + voxel_grid_size = mesh_resolution_ * factor_voxel_grid_; + } + + pcl::VoxelGrid grid_; + grid_.setInputCloud(in); + grid_.setLeafSize(voxel_grid_size, voxel_grid_size, voxel_grid_size); + grid_.setDownsampleAllData(true); + grid_.filter(*out); + } + else { + out = in; + } + + if (out->points.empty()) { + PCL_WARN("NORMAL estimator: Cloud has no points after voxel grid, " + "won't be able to compute normals!\n"); + return; + } + + if (remove_outliers_) { + pcl::ScopeTime t("remove_outliers_..."); + PointInTPtr out2(new pcl::PointCloud()); + float radius = normal_radius_; + if (compute_mesh_resolution_) { + radius = mesh_resolution_ * factor_normals_; + if (do_voxel_grid_) + radius *= factor_voxel_grid_; + } + + // in synthetic views the render grazes some parts of the objects + // thus creating a very sparse set of points that causes the normals to be very + // noisy remove these points + pcl::RadiusOutlierRemoval sor; + sor.setInputCloud(out); + sor.setRadiusSearch(radius); + sor.setMinNeighborsInRadius(16); + sor.filter(*out2); + out = out2; + } + + if (out->points.empty()) { + PCL_WARN("NORMAL estimator: Cloud has no points after removing outliers...!\n"); + return; + } + + float radius = normal_radius_; + if (compute_mesh_resolution_) { + radius = mesh_resolution_ * factor_normals_; + if (do_voxel_grid_) + radius *= factor_voxel_grid_; + } + + if (out->isOrganized()) { + pcl::IntegralImageNormalEstimation n3d; + n3d.setNormalEstimationMethod(n3d.COVARIANCE_MATRIX); + n3d.setInputCloud(out); + n3d.setRadiusSearch(radius); + n3d.setKSearch(0); + { + pcl::ScopeTime t("compute normals..."); + n3d.compute(*normals); + } + } + else { - void - setRemoveOutliers (bool b) - { - remove_outliers_ = b; + // check nans before computing normals + { + pcl::ScopeTime t("check nans..."); + pcl::index_t j = 0; + for (const auto& point : *out) { + if (!isXYZFinite(point)) + continue; + + (*out)[j] = point; + j++; } - void - setCMR (bool b) - { - compute_mesh_resolution_ = b; + if (j != static_cast(out->size())) { + PCL_ERROR("Contain nans..."); } - void - estimate (PointInTPtr & in, PointInTPtr & out, pcl::PointCloud::Ptr & normals) - { - if (compute_mesh_resolution_) - { - mesh_resolution_ = computeMeshResolution (in); - std::cout << "compute mesh resolution:" << mesh_resolution_ << std::endl; - } - - if (do_voxel_grid_) - { - pcl::ScopeTime t ("Voxel grid..."); - float voxel_grid_size = grid_resolution_; - if (compute_mesh_resolution_) - { - voxel_grid_size = mesh_resolution_ * factor_voxel_grid_; - } - - pcl::VoxelGrid grid_; - grid_.setInputCloud (in); - grid_.setLeafSize (voxel_grid_size, voxel_grid_size, voxel_grid_size); - grid_.setDownsampleAllData (true); - grid_.filter (*out); - } - else - { - out = in; - } - - if (out->points.empty ()) - { - PCL_WARN("NORMAL estimator: Cloud has no points after voxel grid, won't be able to compute normals!\n"); - return; - } - - if (remove_outliers_) - { - pcl::ScopeTime t ("remove_outliers_..."); - PointInTPtr out2 (new pcl::PointCloud ()); - float radius = normal_radius_; - if (compute_mesh_resolution_) - { - radius = mesh_resolution_ * factor_normals_; - if (do_voxel_grid_) - radius *= factor_voxel_grid_; - } - - //in synthetic views the render grazes some parts of the objects - //thus creating a very sparse set of points that causes the normals to be very noisy - //remove these points - pcl::RadiusOutlierRemoval sor; - sor.setInputCloud (out); - sor.setRadiusSearch (radius); - sor.setMinNeighborsInRadius (16); - sor.filter (*out2); - out = out2; - - } - - if (out->points.empty ()) - { - PCL_WARN("NORMAL estimator: Cloud has no points after removing outliers...!\n"); - return; - } - - float radius = normal_radius_; - if (compute_mesh_resolution_) - { - radius = mesh_resolution_ * factor_normals_; - if (do_voxel_grid_) - radius *= factor_voxel_grid_; - } - - if (out->isOrganized ()) - { - pcl::IntegralImageNormalEstimation n3d; - n3d.setNormalEstimationMethod (n3d.COVARIANCE_MATRIX); - //n3d.setNormalEstimationMethod (n3d.AVERAGE_3D_GRADIENT); - n3d.setInputCloud (out); - n3d.setRadiusSearch (radius); - n3d.setKSearch (0); - //n3d.setMaxDepthChangeFactor(0.02f); - //n3d.setNormalSmoothingSize(15.0f); - { - pcl::ScopeTime t ("compute normals..."); - n3d.compute (*normals); - } - } - else - { - - //check nans before computing normals - { - pcl::ScopeTime t ("check nans..."); - int j = 0; - for (std::size_t i = 0; i < out->points.size (); ++i) - { - if (!std::isfinite (out->points[i].x) || !std::isfinite (out->points[i].y) || !std::isfinite (out->points[i].z)) - continue; - - out->points[j] = out->points[i]; - j++; - } - - if (j != static_cast (out->points.size ())) - { - PCL_ERROR("Contain nans..."); - } - - out->points.resize (j); - out->width = j; - out->height = 1; - } - - pcl::NormalEstimation n3d; - typename pcl::search::KdTree::Ptr normals_tree (new pcl::search::KdTree); - normals_tree->setInputCloud (out); - n3d.setRadiusSearch (radius); - n3d.setSearchMethod (normals_tree); - n3d.setInputCloud (out); - { - pcl::ScopeTime t ("compute normals not organized..."); - n3d.compute (*normals); - } - } - - //check nans... - if (!out->isOrganized ()) - { - pcl::ScopeTime t ("check nans..."); - int j = 0; - for (std::size_t i = 0; i < normals->points.size (); ++i) - { - if (!std::isfinite (normals->points[i].normal_x) || !std::isfinite (normals->points[i].normal_y) - || !std::isfinite (normals->points[i].normal_z)) - continue; - - normals->points[j] = normals->points[i]; - out->points[j] = out->points[i]; - j++; - } - - normals->points.resize (j); - normals->width = j; - normals->height = 1; - - out->points.resize (j); - out->width = j; - out->height = 1; - } - else - { - //is is organized, we set the xyz points to NaN - pcl::ScopeTime t ("check nans organized..."); - bool NaNs = false; - for (std::size_t i = 0; i < normals->points.size (); ++i) - { - if (std::isfinite (normals->points[i].normal_x) && std::isfinite (normals->points[i].normal_y) - && std::isfinite (normals->points[i].normal_z)) - continue; - - NaNs = true; - - out->points[i].x = out->points[i].y = out->points[i].z = std::numeric_limits::quiet_NaN (); - } - - if (NaNs) - { - PCL_WARN("normals contain NaNs\n"); - out->is_dense = false; - } - } - - /*for (std::size_t i = 0; i < out->points.size (); i++) - { - int r, g, b; - r = static_cast (out->points[i].r); - g = static_cast (out->points[i].g); - b = static_cast (out->points[i].b); - std::cout << "in normal estimator:" << r << " " << g << " " << b << std::endl; - }*/ - } - }; + out->points.resize(j); + out->width = j; + out->height = 1; + } + + pcl::NormalEstimation n3d; + typename pcl::search::KdTree::Ptr normals_tree( + new pcl::search::KdTree); + normals_tree->setInputCloud(out); + n3d.setRadiusSearch(radius); + n3d.setSearchMethod(normals_tree); + n3d.setInputCloud(out); + { + pcl::ScopeTime t("compute normals not organized..."); + n3d.compute(*normals); + } + } + + // check nans... + if (!out->isOrganized()) { + pcl::ScopeTime t("check nans..."); + int j = 0; + for (std::size_t i = 0; i < normals->size(); ++i) { + if (!isNormalFinite((*normals)[i])) + continue; + + (*normals)[j] = (*normals)[i]; + (*out)[j] = (*out)[i]; + j++; + } + + normals->points.resize(j); + normals->width = j; + normals->height = 1; + + out->points.resize(j); + out->width = j; + out->height = 1; + } + else { + // is is organized, we set the xyz points to NaN + pcl::ScopeTime t("check nans organized..."); + bool NaNs = false; + for (std::size_t i = 0; i < normals->size(); ++i) { + if (!isNormalFinite((*normals)[i])) + continue; + + NaNs = true; + + (*out)[i].x = (*out)[i].y = (*out)[i].z = + std::numeric_limits::quiet_NaN(); + } + + if (NaNs) { + PCL_WARN("normals contain NaNs\n"); + out->is_dense = false; + } + } } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/mesh_source.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/mesh_source.h index 6eaa85f6..8c3238dd 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/mesh_source.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/mesh_source.h @@ -8,275 +8,260 @@ #pragma once #include +#include #include #include #include -#include #include #include -namespace pcl -{ - namespace rec_3d_framework - { +namespace pcl { +namespace rec_3d_framework { - /** - * \brief Data source class based on mesh models - * \author Aitor Aldoma - */ - - template - class MeshSource : public Source - { - using SourceT = Source; - using ModelT = Model; - - using SourceT::path_; - using SourceT::models_; - using SourceT::createTrainingDir; - using SourceT::getModelsInDirectory; - using SourceT::model_scale_; - - int tes_level_; - int resolution_; - float radius_sphere_; - float view_angle_; - bool gen_organized_; - std::function campos_constraints_func_; - - public: - - using SourceT::setFilterDuplicateViews; - - MeshSource () : - SourceT () - { - gen_organized_ = false; - } +/** + * \brief Data source class based on mesh models + * \author Aitor Aldoma + */ - void - setTesselationLevel (int lev) - { - tes_level_ = lev; - } +template +class MeshSource : public Source { + using SourceT = Source; + using ModelT = Model; - void - setCamPosConstraints (std::function & bb) - { - campos_constraints_func_ = bb; - } + using SourceT::createTrainingDir; + using SourceT::getModelsInDirectory; + using SourceT::model_scale_; + using SourceT::models_; + using SourceT::path_; - void - setResolution (int res) - { - resolution_ = res; - } + int tes_level_; + int resolution_; + float radius_sphere_; + float view_angle_; + bool gen_organized_; + std::function campos_constraints_func_; - void - setRadiusSphere (float r) - { - radius_sphere_ = r; - } +public: + using SourceT::setFilterDuplicateViews; - void - setViewAngle (float a) - { - view_angle_ = a; - } + MeshSource() : SourceT() { gen_organized_ = false; } - void - loadOrGenerate (std::string & dir, std::string & model_path, ModelT & model) - { - std::stringstream pathmodel; - pathmodel << dir << "/" << model.class_ << "/" << model.id_; - bf::path trained_dir = pathmodel.str (); - - model.views_.reset (new std::vector::Ptr>); - model.poses_.reset (new std::vector >); - model.self_occlusions_.reset (new std::vector); - model.assembled_.reset (new pcl::PointCloud); - uniform_sampling (model_path, 100000, *model.assembled_, model_scale_); - - if (bf::exists (trained_dir)) - { - //load views, poses and self-occlusions - std::vector < std::string > view_filenames; - int number_of_views = 0; - for (const auto& dir_entry : bf::directory_iterator(trained_dir)) - { - //check if its a directory, then get models in it - if (!(bf::is_directory (dir_entry))) - { - //check that it is a ply file and then add, otherwise ignore.. - std::vector < std::string > strs; - std::vector < std::string > strs_; - - std::string file = (dir_entry.path ().filename ()).string(); - - boost::split (strs, file, boost::is_any_of (".")); - boost::split (strs_, file, boost::is_any_of ("_")); - - std::string extension = strs[strs.size () - 1]; - - if (extension == "pcd" && strs_[0] == "view") - { - view_filenames.push_back ((dir_entry.path ().filename ()).string()); - - number_of_views++; - } - } - } - - for (const auto &view_filename : view_filenames) - { - std::stringstream view_file; - view_file << pathmodel.str () << "/" << view_filename; - typename pcl::PointCloud::Ptr cloud (new pcl::PointCloud ()); - pcl::io::loadPCDFile (view_file.str (), *cloud); - - model.views_->push_back (cloud); - - std::string file_replaced1 (view_filename); - boost::replace_all (file_replaced1, "view", "pose"); - boost::replace_all (file_replaced1, ".pcd", ".txt"); - - std::string file_replaced2 (view_filename); - boost::replace_all (file_replaced2, "view", "entropy"); - boost::replace_all (file_replaced2, ".pcd", ".txt"); - - //read pose as well - std::stringstream pose_file; - pose_file << pathmodel.str () << "/" << file_replaced1; - - Eigen::Matrix4f pose; - PersistenceUtils::readMatrixFromFile (pose_file.str (), pose); - - model.poses_->push_back (pose); - - //read entropy as well - std::stringstream entropy_file; - entropy_file << pathmodel.str () << "/" << file_replaced2; - float entropy = 0; - PersistenceUtils::readFloatFromFile (entropy_file.str (), entropy); - model.self_occlusions_->push_back (entropy); - - } + void + setTesselationLevel(int lev) + { + tes_level_ = lev; + } - } - else - { - //load PLY model and scale it - vtkSmartPointer reader = vtkSmartPointer::New (); - reader->SetFileName (model_path.c_str ()); - - vtkSmartPointer trans = vtkSmartPointer::New (); - trans->Scale (model_scale_, model_scale_, model_scale_); - trans->Modified (); - trans->Update (); - - vtkSmartPointer filter_scale = vtkSmartPointer::New (); - filter_scale->SetTransform (trans); - filter_scale->SetInputConnection (reader->GetOutputPort ()); - filter_scale->Update (); - - vtkSmartPointer mapper = filter_scale->GetOutput (); - - //generate views - pcl::apps::RenderViewsTesselatedSphere render_views; - render_views.setResolution (resolution_); - render_views.setUseVertices (false); - render_views.setRadiusSphere (radius_sphere_); - render_views.setComputeEntropies (true); - render_views.setTesselationLevel (tes_level_); - render_views.setViewAngle (view_angle_); - render_views.addModelFromPolyData (mapper); - render_views.setGenOrganized (gen_organized_); - render_views.setCamPosConstraints (campos_constraints_func_); - render_views.generateViews (); - - std::vector::Ptr> views_xyz_orig; - std::vector < Eigen::Matrix4f, Eigen::aligned_allocator > poses; - std::vector entropies; - - render_views.getViews (views_xyz_orig); - render_views.getPoses (poses); - render_views.getEntropies (entropies); - - model.views_.reset (new std::vector::Ptr> ()); - model.poses_.reset (new std::vector > ()); - model.self_occlusions_.reset (new std::vector ()); - - for (std::size_t i = 0; i < views_xyz_orig.size (); i++) - { - model.views_->push_back (views_xyz_orig[i]); - model.poses_->push_back (poses[i]); - model.self_occlusions_->push_back (entropies[i]); - } - - std::stringstream direc; - direc << dir << "/" << model.class_ << "/" << model.id_; - this->createClassAndModelDirectories (dir, model.class_, model.id_); - - for (std::size_t i = 0; i < model.views_->size (); i++) - { - //save generated model for future use - std::stringstream path_view; - path_view << direc.str () << "/view_" << i << ".pcd"; - pcl::io::savePCDFileBinary (path_view.str (), *(model.views_->at (i))); - - std::stringstream path_pose; - path_pose << direc.str () << "/pose_" << i << ".txt"; - - pcl::rec_3d_framework::PersistenceUtils::writeMatrixToFile (path_pose.str (), model.poses_->at (i)); - - std::stringstream path_entropy; - path_entropy << direc.str () << "/entropy_" << i << ".txt"; - pcl::rec_3d_framework::PersistenceUtils::writeFloatToFile (path_entropy.str (), model.self_occlusions_->at (i)); - } - - loadOrGenerate (dir, model_path, model); + void + setCamPosConstraints(std::function& bb) + { + campos_constraints_func_ = bb; + } - } - } + void + setResolution(int res) + { + resolution_ = res; + } - /** - * \brief Creates the model representation of the training set, generating views if needed - */ - void - generate (std::string & training_dir) override - { - - //create training dir fs if not existent - createTrainingDir (training_dir); - - //get models in directory - std::vector < std::string > files; - std::string start; - std::string ext = std::string ("ply"); - bf::path dir = path_; - getModelsInDirectory (dir, start, files, ext); - - models_.reset (new std::vector); - - for (const auto &filename : files) - { - ModelT m; - this->getIdAndClassFromFilename (filename, m.id_, m.class_); - - //check which of them have been trained using training_dir and the model_id_ - //load views, poses and self-occlusions for those that exist - //generate otherwise - std::cout << filename << std::endl; - std::string path_model = path_ + '/' + filename; - loadOrGenerate (training_dir, path_model, m); - - models_->push_back (m); + void + setRadiusSphere(float r) + { + radius_sphere_ = r; + } + + void + setViewAngle(float a) + { + view_angle_ = a; + } + + void + loadOrGenerate(std::string& dir, std::string& model_path, ModelT& model) + { + std::stringstream pathmodel; + pathmodel << dir << "/" << model.class_ << "/" << model.id_; + bf::path trained_dir = pathmodel.str(); + + model.views_.reset(new std::vector::Ptr>); + model.poses_.reset( + new std::vector>); + model.self_occlusions_.reset(new std::vector); + model.assembled_.reset(new pcl::PointCloud); + uniform_sampling(model_path, 100000, *model.assembled_, model_scale_); + + if (bf::exists(trained_dir)) { + // load views, poses and self-occlusions + std::vector view_filenames; + int number_of_views = 0; + for (const auto& dir_entry : bf::directory_iterator(trained_dir)) { + // check if its a directory, then get models in it + if (!(bf::is_directory(dir_entry))) { + // check that it is a ply file and then add, otherwise ignore.. + std::vector strs; + std::vector strs_; + + std::string file = (dir_entry.path().filename()).string(); + + boost::split(strs, file, boost::is_any_of(".")); + boost::split(strs_, file, boost::is_any_of("_")); + + std::string extension = strs[strs.size() - 1]; + + if (extension == "pcd" && strs_[0] == "view") { + view_filenames.push_back((dir_entry.path().filename()).string()); + + number_of_views++; } } - }; + } + + for (const auto& view_filename : view_filenames) { + std::stringstream view_file; + view_file << pathmodel.str() << "/" << view_filename; + typename pcl::PointCloud::Ptr cloud(new pcl::PointCloud()); + pcl::io::loadPCDFile(view_file.str(), *cloud); + + model.views_->push_back(cloud); + + std::string file_replaced1(view_filename); + boost::replace_all(file_replaced1, "view", "pose"); + boost::replace_all(file_replaced1, ".pcd", ".txt"); + + std::string file_replaced2(view_filename); + boost::replace_all(file_replaced2, "view", "entropy"); + boost::replace_all(file_replaced2, ".pcd", ".txt"); + + // read pose as well + std::stringstream pose_file; + pose_file << pathmodel.str() << "/" << file_replaced1; + + Eigen::Matrix4f pose; + PersistenceUtils::readMatrixFromFile(pose_file.str(), pose); + + model.poses_->push_back(pose); + + // read entropy as well + std::stringstream entropy_file; + entropy_file << pathmodel.str() << "/" << file_replaced2; + float entropy = 0; + PersistenceUtils::readFloatFromFile(entropy_file.str(), entropy); + model.self_occlusions_->push_back(entropy); + } + } + else { + // load PLY model and scale it + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName(model_path.c_str()); + + vtkSmartPointer trans = vtkSmartPointer::New(); + trans->Scale(model_scale_, model_scale_, model_scale_); + trans->Modified(); + trans->Update(); + + vtkSmartPointer filter_scale = + vtkSmartPointer::New(); + filter_scale->SetTransform(trans); + filter_scale->SetInputConnection(reader->GetOutputPort()); + filter_scale->Update(); + + vtkSmartPointer mapper = filter_scale->GetOutput(); + + // generate views + pcl::apps::RenderViewsTesselatedSphere render_views; + render_views.setResolution(resolution_); + render_views.setUseVertices(false); + render_views.setRadiusSphere(radius_sphere_); + render_views.setComputeEntropies(true); + render_views.setTesselationLevel(tes_level_); + render_views.setViewAngle(view_angle_); + render_views.addModelFromPolyData(mapper); + render_views.setGenOrganized(gen_organized_); + render_views.setCamPosConstraints(campos_constraints_func_); + render_views.generateViews(); + + std::vector::Ptr> views_xyz_orig; + std::vector> poses; + std::vector entropies; + + render_views.getViews(views_xyz_orig); + render_views.getPoses(poses); + render_views.getEntropies(entropies); + + model.views_.reset(new std::vector::Ptr>()); + model.poses_.reset(new std::vector>()); + model.self_occlusions_.reset(new std::vector()); + + for (std::size_t i = 0; i < views_xyz_orig.size(); i++) { + model.views_->push_back(views_xyz_orig[i]); + model.poses_->push_back(poses[i]); + model.self_occlusions_->push_back(entropies[i]); + } + + std::stringstream direc; + direc << dir << "/" << model.class_ << "/" << model.id_; + this->createClassAndModelDirectories(dir, model.class_, model.id_); + + for (std::size_t i = 0; i < model.views_->size(); i++) { + // save generated model for future use + std::stringstream path_view; + path_view << direc.str() << "/view_" << i << ".pcd"; + pcl::io::savePCDFileBinary(path_view.str(), *(model.views_->at(i))); + + std::stringstream path_pose; + path_pose << direc.str() << "/pose_" << i << ".txt"; + + pcl::rec_3d_framework::PersistenceUtils::writeMatrixToFile(path_pose.str(), + model.poses_->at(i)); + + std::stringstream path_entropy; + path_entropy << direc.str() << "/entropy_" << i << ".txt"; + pcl::rec_3d_framework::PersistenceUtils::writeFloatToFile( + path_entropy.str(), model.self_occlusions_->at(i)); + } + + loadOrGenerate(dir, model_path, model); + } + } + + /** + * \brief Creates the model representation of the training set, generating views if + * needed + */ + void + generate(std::string& training_dir) override + { + + // create training dir fs if not existent + createTrainingDir(training_dir); + + // get models in directory + std::vector files; + std::string start; + std::string ext = std::string("ply"); + bf::path dir = path_; + getModelsInDirectory(dir, start, files, ext); + + models_.reset(new std::vector); + + for (const auto& filename : files) { + ModelT m; + this->getIdAndClassFromFilename(filename, m.id_, m.class_); + + // check which of them have been trained using training_dir and the model_id_ + // load views, poses and self-occlusions for those that exist + // generate otherwise + std::cout << filename << std::endl; + std::string path_model = path_ + '/' + filename; + loadOrGenerate(training_dir, path_model, m); + + models_->push_back(m); + } } -} +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h index 6635ebcc..06319ec4 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h @@ -12,343 +12,307 @@ #include #include -namespace pcl -{ - namespace rec_3d_framework - { - - /** - * \brief Data source class based on partial views from sensor. - * In this case, the training data is obtained directly from a depth sensor. - * The filesystem should contain pcd files (representing a view of an object in - * camera coordinates) and each view needs to be associated with a txt file - * containing a 4x4 matrix representing the transformation from camera coordinates - * to a global object coordinates frame. - * \author Aitor Aldoma - */ - - template - class RegisteredViewsSource : public Source - { - using SourceT = Source; - using ModelT = Model; - - using SourceT::path_; - using SourceT::models_; - using SourceT::createTrainingDir; - using SourceT::getModelsInDirectory; - using SourceT::model_scale_; - - std::string view_prefix_; - int pose_files_order_; //0 is row, 1 is column - - public: - RegisteredViewsSource () - { - view_prefix_ = std::string ("view"); - pose_files_order_ = 0; - } - - void - setPrefix (std::string & pre) - { - view_prefix_ = pre; - } - - void - setPoseRowOrder (int o) - { - pose_files_order_ = o; - } - - void - getViewsFilenames (bf::path & path_with_views, std::vector & view_filenames) - { - int number_of_views = 0; - for (const auto& dir_entry : bf::directory_iterator(path_with_views)) - { - if (!(bf::is_directory (dir_entry))) - { - std::vector < std::string > strs; - std::vector < std::string > strs_; - - std::string file = (dir_entry.path ().filename ()).string(); - - boost::split (strs, file, boost::is_any_of (".")); - boost::split (strs_, file, boost::is_any_of ("_")); - - std::string extension = strs[strs.size () - 1]; +namespace pcl { +namespace rec_3d_framework { + +/** + * \brief Data source class based on partial views from sensor. + * In this case, the training data is obtained directly from a depth sensor. + * The filesystem should contain pcd files (representing a view of an object in + * camera coordinates) and each view needs to be associated with a txt file + * containing a 4x4 matrix representing the transformation from camera coordinates + * to a global object coordinates frame. + * \author Aitor Aldoma + */ - if (extension == "pcd" && (strs_[0].compare (view_prefix_) == 0)) - { - view_filenames.push_back ((dir_entry.path ().filename ()).string()); +template +class RegisteredViewsSource : public Source { + using SourceT = Source; + using ModelT = Model; - number_of_views++; - } - } - } - } + using SourceT::createTrainingDir; + using SourceT::getModelsInDirectory; + using SourceT::model_scale_; + using SourceT::models_; + using SourceT::path_; - void - assembleModelFromViewsAndPoses(ModelT & model, std::vector > & poses) { - for(std::size_t i=0; i < model.views_->size(); i++) { - Eigen::Matrix4f inv = poses[i]; - typename pcl::PointCloud::Ptr global_cloud(new pcl::PointCloud); - pcl::transformPointCloud(*(model.views_->at(i)),*global_cloud, inv); - *(model.assembled_) += *global_cloud; - } - } + std::string view_prefix_; + int pose_files_order_; // 0 is row, 1 is column - void - loadOrGenerate (std::string & dir, std::string & model_path, ModelT & model) - { - std::stringstream pathmodel; - pathmodel << dir << "/" << model.class_ << "/" << model.id_; - bf::path trained_dir = pathmodel.str (); +public: + RegisteredViewsSource() + { + view_prefix_ = std::string("view"); + pose_files_order_ = 0; + } - model.views_.reset (new std::vector::Ptr>); - model.poses_.reset (new std::vector >); - model.self_occlusions_.reset (new std::vector); + void + setPrefix(std::string& pre) + { + view_prefix_ = pre; + } - if (bf::exists (trained_dir)) - { - //load views and poses - std::vector < std::string > view_filenames; - int number_of_views = 0; - for (const auto& dir_entry : bf::directory_iterator(trained_dir)) - { - //check if its a directory, then get models in it - if (!(bf::is_directory (*itr))) - { - //check that it is a ply file and then add, otherwise ignore.. - std::vector < std::string > strs; - std::vector < std::string > strs_; + void + setPoseRowOrder(int o) + { + pose_files_order_ = o; + } - std::string file = (dir_entry.path ().filename ()).string(); + void + getViewsFilenames(bf::path& path_with_views, std::vector& view_filenames) + { + int number_of_views = 0; + for (const auto& dir_entry : bf::directory_iterator(path_with_views)) { + if (!(bf::is_directory(dir_entry))) { + std::vector strs; + std::vector strs_; - boost::split (strs, file, boost::is_any_of (".")); - boost::split (strs_, file, boost::is_any_of ("_")); + std::string file = (dir_entry.path().filename()).string(); - std::string extension = strs[strs.size () - 1]; + boost::split(strs, file, boost::is_any_of(".")); + boost::split(strs_, file, boost::is_any_of("_")); - if (extension == "pcd" && strs_[0] == "view") - { - view_filenames.push_back ((dir_entry.path ().filename ()).string()); - number_of_views++; - } - } - } + std::string extension = strs[strs.size() - 1]; - std::vector > poses_to_assemble_; + if (extension == "pcd" && (strs_[0].compare(view_prefix_) == 0)) { + view_filenames.push_back((dir_entry.path().filename()).string()); - for (std::size_t i = 0; i < view_filenames.size (); i++) - { - std::stringstream view_file; - view_file << pathmodel.str () << "/" << view_filenames[i]; - typename pcl::PointCloud::Ptr cloud (new pcl::PointCloud ()); - pcl::io::loadPCDFile (view_file.str (), *cloud); + number_of_views++; + } + } + } + } - model.views_->push_back (cloud); + void + assembleModelFromViewsAndPoses( + ModelT& model, + std::vector>& poses) + { + for (std::size_t i = 0; i < model.views_->size(); i++) { + Eigen::Matrix4f inv = poses[i]; + typename pcl::PointCloud::Ptr global_cloud( + new pcl::PointCloud); + pcl::transformPointCloud(*(model.views_->at(i)), *global_cloud, inv); + *(model.assembled_) += *global_cloud; + } + } - std::string file_replaced1 (view_filenames[i]); - boost::replace_all (file_replaced1, "view", "pose"); - boost::replace_all (file_replaced1, ".pcd", ".txt"); + void + loadOrGenerate(std::string& dir, std::string& model_path, ModelT& model) + { + std::stringstream pathmodel; + pathmodel << dir << "/" << model.class_ << "/" << model.id_; + bf::path trained_dir = pathmodel.str(); + + model.views_.reset(new std::vector::Ptr>); + model.poses_.reset( + new std::vector>); + model.self_occlusions_.reset(new std::vector); + + if (bf::exists(trained_dir)) { + // load views and poses + std::vector view_filenames; + int number_of_views = 0; + for (const auto& dir_entry : bf::directory_iterator(trained_dir)) { + // check if its a directory, then get models in it + if (!(bf::is_directory(*itr))) { + // check that it is a ply file and then add, otherwise ignore.. + std::vector strs; + std::vector strs_; + + std::string file = (dir_entry.path().filename()).string(); + + boost::split(strs, file, boost::is_any_of(".")); + boost::split(strs_, file, boost::is_any_of("_")); + + std::string extension = strs[strs.size() - 1]; + + if (extension == "pcd" && strs_[0] == "view") { + view_filenames.push_back((dir_entry.path().filename()).string()); + number_of_views++; + } + } + } - //read pose as well - std::stringstream pose_file; - pose_file << pathmodel.str () << "/" << file_replaced1; - Eigen::Matrix4f pose; - PersistenceUtils::readMatrixFromFile (pose_file.str (), pose); + std::vector> + poses_to_assemble_; - if(pose_files_order_ != 0) { - //std::cout << "Transpose..." << std::endl; + for (std::size_t i = 0; i < view_filenames.size(); i++) { + std::stringstream view_file; + view_file << pathmodel.str() << "/" << view_filenames[i]; + typename pcl::PointCloud::Ptr cloud(new pcl::PointCloud()); + pcl::io::loadPCDFile(view_file.str(), *cloud); - Eigen::Matrix4f pose_trans = pose.transpose(); - poses_to_assemble_.push_back(pose_trans); - //pose = pose_trans; - //std::cout << pose << std::endl; - } + model.views_->push_back(cloud); - //std::cout << "pose being push backed to model" << std::endl; - std::cout << pose << std::endl; + std::string file_replaced1(view_filenames[i]); + boost::replace_all(file_replaced1, "view", "pose"); + boost::replace_all(file_replaced1, ".pcd", ".txt"); - //the recognizer assumes transformation from M to CC - Eigen::Matrix4f inv = pose.inverse(); - model.poses_->push_back (inv); + // read pose as well + std::stringstream pose_file; + pose_file << pathmodel.str() << "/" << file_replaced1; + Eigen::Matrix4f pose; + PersistenceUtils::readMatrixFromFile(pose_file.str(), pose); - model.self_occlusions_->push_back (-1.f); + if (pose_files_order_ != 0) { + Eigen::Matrix4f pose_trans = pose.transpose(); + poses_to_assemble_.push_back(pose_trans); + } - } + std::cout << pose << std::endl; - model.assembled_.reset (new pcl::PointCloud); - assembleModelFromViewsAndPoses(model, poses_to_assemble_); + // the recognizer assumes transformation from M to CC + Eigen::Matrix4f inv = pose.inverse(); + model.poses_->push_back(inv); - /*pcl::visualization::PCLVisualizer vis ("results"); - pcl::visualization::PointCloudColorHandlerCustom random_handler (model.assembled_, 255, 0, 0); - vis.addPointCloud (model.assembled_, random_handler, "points"); + model.self_occlusions_->push_back(-1.f); + } - Eigen::Matrix4f view_transformation = model.poses_->at(0).inverse(); - typename pcl::PointCloud::Ptr view_trans(new pcl::PointCloud); - pcl::transformPointCloud(*(model.views_->at(0)), *view_trans, view_transformation); + model.assembled_.reset(new pcl::PointCloud); + assembleModelFromViewsAndPoses(model, poses_to_assemble_); + } + else { - pcl::visualization::PointCloudColorHandlerCustom random_handler2 (view_trans, 0, 255, 0); - vis.addPointCloud (view_trans, random_handler2, "view"); + // we just need to copy the views to the training directory + std::stringstream direc; + direc << dir << "/" << model.class_ << "/" << model.id_; + createClassAndModelDirectories(dir, model.class_, model.id_); - vis.addCoordinateSystem(0.1); - vis.spin ();*/ + std::vector view_filenames; + bf::path model_dir = model_path; - } - else - { + getViewsFilenames(model_dir, view_filenames); + std::cout << view_filenames.size() << std::endl; - //we just need to copy the views to the training directory - std::stringstream direc; - direc << dir << "/" << model.class_ << "/" << model.id_; - createClassAndModelDirectories (dir, model.class_, model.id_); + for (std::size_t i = 0; i < view_filenames.size(); i++) { + std::stringstream view_file; + view_file << model_path << "/" << view_filenames[i]; + typename pcl::PointCloud::Ptr cloud(new pcl::PointCloud()); + pcl::io::loadPCDFile(view_file.str(), *cloud); - std::vector < std::string > view_filenames; - bf::path model_dir = model_path; + std::cout << view_file.str() << std::endl; - getViewsFilenames (model_dir, view_filenames); - std::cout << view_filenames.size () << std::endl; + std::stringstream path_view; + path_view << direc.str() << "/view_" << i << ".pcd"; + pcl::io::savePCDFileBinary(path_view.str(), *cloud); - for (std::size_t i = 0; i < view_filenames.size (); i++) - { - std::stringstream view_file; - view_file << model_path << "/" << view_filenames[i]; - typename pcl::PointCloud::Ptr cloud (new pcl::PointCloud ()); - pcl::io::loadPCDFile (view_file.str (), *cloud); + std::string file_replaced1(view_file.str()); + boost::replace_all(file_replaced1, view_prefix_, "pose"); + boost::replace_all(file_replaced1, ".pcd", ".txt"); - std::cout << view_file.str () << std::endl; + Eigen::Matrix4f pose; + PersistenceUtils::readMatrixFromFile(file_replaced1, pose); - std::stringstream path_view; - path_view << direc.str () << "/view_" << i << ".pcd"; - pcl::io::savePCDFileBinary (path_view.str (), *cloud); + std::cout << pose << std::endl; - std::string file_replaced1 (view_file.str ()); - boost::replace_all (file_replaced1, view_prefix_, "pose"); - boost::replace_all (file_replaced1, ".pcd", ".txt"); + if (pose_files_order_ == 0) { + std::cout << "Transpose..." << std::endl; + Eigen::Matrix4f pose_trans = pose.transpose(); + pose = pose_trans; + std::cout << pose << std::endl; + } - Eigen::Matrix4f pose; - PersistenceUtils::readMatrixFromFile (file_replaced1, pose); + std::stringstream path_pose; + path_pose << direc.str() << "/pose_" << i << ".txt"; + pcl::rec_3d_framework::PersistenceUtils::writeMatrixToFile(path_pose.str(), + pose); + } - std::cout << pose << std::endl; + loadOrGenerate(dir, model_path, model); + } + } - if(pose_files_order_ == 0) { - std::cout << "Transpose..." << std::endl; - Eigen::Matrix4f pose_trans = pose.transpose(); - pose = pose_trans; - std::cout << pose << std::endl; - } + bool + isleafDirectory(bf::path& path) + { + bool no_dirs_inside = true; + for (const auto& dir_entry : bf::directory_iterator(path)) { + if (bf::is_directory(dir_entry)) { + no_dirs_inside = false; + } + } + + return no_dirs_inside; + } - std::stringstream path_pose; - path_pose << direc.str () << "/pose_" << i << ".txt"; - pcl::rec_3d_framework::PersistenceUtils::writeMatrixToFile (path_pose.str (), pose); - } + void + getModelsInDirectory(bf::path& dir, + std::string& rel_path_so_far, + std::vector& relative_paths) + { + for (const auto& dir_entry : bf::directory_iterator(dir)) { + // check if its a directory, then get models in it + if (bf::is_directory(dir_entry)) { + std::string so_far = + rel_path_so_far + (dir_entry.path().filename()).string() + "/"; + bf::path curr_path = dir_entry.path(); + + if (isleafDirectory(curr_path)) { + std::string path = rel_path_so_far + (dir_entry.path().filename()).string(); + relative_paths.push_back(path); + } + else { + getModelsInDirectory(curr_path, so_far, relative_paths); + } + } + } + } - loadOrGenerate (dir, model_path, model); + /** + * \brief Creates the model representation of the training set, generating views if + * needed + */ + void + generate(std::string& training_dir) + { - } + // create training dir fs if not existent + createTrainingDir(training_dir); + + // get models in directory + std::vector files; + std::string start = ""; + bf::path dir = path_; + getModelsInDirectory(dir, start, files); + + models_.reset(new std::vector); + + for (std::size_t i = 0; i < files.size(); i++) { + ModelT m; + + std::vector strs; + boost::split(strs, files[i], boost::is_any_of("/\\")); + std::string name = strs[strs.size() - 1]; + + if (strs.size() == 1) { + m.id_ = strs[0]; + } + else { + std::stringstream ss; + for (int i = 0; i < (static_cast(strs.size()) - 1); i++) { + ss << strs[i]; + if (i != (static_cast(strs.size()) - 1)) + ss << "/"; } - bool - isleafDirectory (bf::path & path) - { - bool no_dirs_inside = true; - for (const auto& dir_entry : bf::directory_iterator(path)) - { - if (bf::is_directory (dir_entry)) - { - no_dirs_inside = false; - } - } + m.class_ = ss.str(); + m.id_ = strs[strs.size() - 1]; + } - return no_dirs_inside; - } + std::cout << m.class_ << " . " << m.id_ << std::endl; + // check which of them have been trained using training_dir and the model_id_ + // load views, poses and self-occlusions for those that exist + // generate otherwise - void - getModelsInDirectory (bf::path & dir, std::string & rel_path_so_far, std::vector & relative_paths) - { - for (const auto& dir_entry : bf::directory_iterator(dir)) - { - //check if its a directory, then get models in it - if (bf::is_directory (dir_entry)) - { - std::string so_far = rel_path_so_far + (dir_entry.path ().filename ()).string() + "/"; - bf::path curr_path = dir_entry.path (); - - if (isleafDirectory (curr_path)) - { - std::string path = rel_path_so_far + (dir_entry.path ().filename ()).string(); - relative_paths.push_back (path); - } - else - { - getModelsInDirectory (curr_path, so_far, relative_paths); - } - } - } - } + std::stringstream model_path; + model_path << path_ << "/" << files[i]; + std::string path_model = model_path.str(); + loadOrGenerate(training_dir, path_model, m); - /** - * \brief Creates the model representation of the training set, generating views if needed - */ - void - generate (std::string & training_dir) - { - - //create training dir fs if not existent - createTrainingDir (training_dir); - - //get models in directory - std::vector < std::string > files; - std::string start = ""; - bf::path dir = path_; - getModelsInDirectory (dir, start, files); - - models_.reset (new std::vector); - - for (std::size_t i = 0; i < files.size (); i++) - { - ModelT m; - - std::vector < std::string > strs; - boost::split (strs, files[i], boost::is_any_of ("/\\")); - std::string name = strs[strs.size () - 1]; - - if (strs.size () == 1) - { - m.id_ = strs[0]; - } - else - { - std::stringstream ss; - for (int i = 0; i < (static_cast (strs.size ()) - 1); i++) - { - ss << strs[i]; - if (i != (static_cast (strs.size ()) - 1)) - ss << "/"; - } - - m.class_ = ss.str (); - m.id_ = strs[strs.size () - 1]; - } - - std::cout << m.class_ << " . " << m.id_ << std::endl; - //check which of them have been trained using training_dir and the model_id_ - //load views, poses and self-occlusions for those that exist - //generate otherwise - - std::stringstream model_path; - model_path << path_ << "/" << files[i]; - std::string path_model = model_path.str (); - loadOrGenerate (training_dir, path_model, m); - - models_->push_back (m); - - //std::cout << files[i] << std::endl; - } - } - }; + models_->push_back(m); + } } -} +}; +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/source.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/source.h index 2b241084..a3f45ee4 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/source.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/source.h @@ -7,277 +7,275 @@ #pragma once -#include -#include -#include #include -#include #include +#include +#include + +#include +#include namespace bf = boost::filesystem; -namespace pcl -{ - namespace rec_3d_framework +namespace pcl { +namespace rec_3d_framework { + +/** + * \brief Model representation + * \author Aitor Aldoma + */ + +template +class Model { + using PointTPtr = typename pcl::PointCloud::Ptr; + using PointTPtrConst = typename pcl::PointCloud::ConstPtr; + +public: + std::shared_ptr> views_; + std::shared_ptr< + std::vector>> + poses_; + std::shared_ptr> self_occlusions_; + std::string id_; + std::string class_; + PointTPtr assembled_; + typename std::map voxelized_assembled_; + + bool + operator==(const Model& other) const { + return (id_ == other.id_) && (class_ == other.class_); + } - /** - * \brief Model representation - * \author Aitor Aldoma - */ - - template - class Model - { - using PointTPtr = typename pcl::PointCloud::Ptr; - using PointTPtrConst = typename pcl::PointCloud::ConstPtr; - - public: - std::shared_ptr> views_; - std::shared_ptr>> poses_; - std::shared_ptr> self_occlusions_; - std::string id_; - std::string class_; - PointTPtr assembled_; - typename std::map voxelized_assembled_; - - bool - operator== (const Model &other) const - { - return (id_ == other.id_) && (class_ == other.class_); - } + PointTPtrConst + getAssembled(float resolution) + { + if (resolution <= 0) + return assembled_; + + typename std::map::iterator it = + voxelized_assembled_.find(resolution); + if (it == voxelized_assembled_.end()) { + PointTPtr voxelized(new pcl::PointCloud); + pcl::VoxelGrid grid_; + grid_.setInputCloud(assembled_); + grid_.setLeafSize(resolution, resolution, resolution); + grid_.setDownsampleAllData(true); + grid_.filter(*voxelized); + + PointTPtrConst voxelized_const(new pcl::PointCloud(*voxelized)); + voxelized_assembled_[resolution] = voxelized_const; + return voxelized_const; + } + + return it->second; + } +}; - PointTPtrConst - getAssembled (float resolution) - { - if(resolution <= 0) - return assembled_; - - typename std::map::iterator it = voxelized_assembled_.find (resolution); - if (it == voxelized_assembled_.end ()) - { - PointTPtr voxelized (new pcl::PointCloud); - pcl::VoxelGrid grid_; - grid_.setInputCloud (assembled_); - grid_.setLeafSize (resolution, resolution, resolution); - grid_.setDownsampleAllData(true); - grid_.filter (*voxelized); - - PointTPtrConst voxelized_const (new pcl::PointCloud (*voxelized)); - voxelized_assembled_[resolution] = voxelized_const; - return voxelized_const; - } +/** + * \brief Abstract data source class, manages filesystem, incremental training, etc. + * \author Aitor Aldoma + */ - return it->second; - } - }; - - /** - * \brief Abstract data source class, manages filesystem, incremental training, etc. - * \author Aitor Aldoma - */ - - template - class Source - { - - protected: - using ModelT = Model; - std::string path_; - std::shared_ptr> models_; - float model_scale_; - bool filter_duplicate_views_; - bool load_views_; - - void - getIdAndClassFromFilename (const std::string & filename, std::string & id, std::string & classname) - { - - std::vector < std::string > strs; - boost::split (strs, filename, boost::is_any_of ("/\\")); - std::string name = strs[strs.size () - 1]; - - std::stringstream ss; - for (int i = 0; i < (static_cast (strs.size ()) - 1); i++) - { - ss << strs[i]; - if (i != (static_cast (strs.size ()) - 1)) - ss << "/"; - } +template +class Source { + +protected: + using ModelT = Model; + std::string path_; + std::shared_ptr> models_; + float model_scale_; + bool filter_duplicate_views_; + bool load_views_; + + void + getIdAndClassFromFilename(const std::string& filename, + std::string& id, + std::string& classname) + { - classname = ss.str (); - id = name.substr (0, name.length () - 4); - } + std::vector strs; + boost::split(strs, filename, boost::is_any_of("/\\")); + std::string name = strs[strs.size() - 1]; - void - createTrainingDir (std::string & training_dir) - { - bf::path trained_dir = training_dir; - if (!bf::exists (trained_dir)) - bf::create_directory (trained_dir); - } + std::stringstream ss; + for (int i = 0; i < (static_cast(strs.size()) - 1); i++) { + ss << strs[i]; + if (i != (static_cast(strs.size()) - 1)) + ss << "/"; + } - void - createClassAndModelDirectories (std::string & training_dir, std::string & class_str, std::string & id_str) - { - std::vector < std::string > strs; - boost::split (strs, class_str, boost::is_any_of ("/\\")); - - std::stringstream ss; - ss << training_dir << "/"; - for (const auto &str : strs) - { - ss << str << "/"; - bf::path trained_dir = ss.str (); - if (!bf::exists (trained_dir)) - bf::create_directory (trained_dir); - } + classname = ss.str(); + id = name.substr(0, name.length() - 4); + } - ss << id_str; - bf::path trained_dir = ss.str (); - if (!bf::exists (trained_dir)) - bf::create_directory (trained_dir); - } + void + createTrainingDir(std::string& training_dir) + { + bf::path trained_dir = training_dir; + if (!bf::exists(trained_dir)) + bf::create_directory(trained_dir); + } - public: + void + createClassAndModelDirectories(std::string& training_dir, + std::string& class_str, + std::string& id_str) + { + std::vector strs; + boost::split(strs, class_str, boost::is_any_of("/\\")); + + std::stringstream ss; + ss << training_dir << "/"; + for (const auto& str : strs) { + ss << str << "/"; + bf::path trained_dir = ss.str(); + if (!bf::exists(trained_dir)) + bf::create_directory(trained_dir); + } + + ss << id_str; + bf::path trained_dir = ss.str(); + if (!bf::exists(trained_dir)) + bf::create_directory(trained_dir); + } - Source() { - load_views_ = true; - } +public: + Source() { load_views_ = true; } - virtual - ~Source() = default; + virtual ~Source() = default; - float - getScale () - { - return model_scale_; - } + float + getScale() + { + return model_scale_; + } - void - setModelScale (float s) - { - model_scale_ = s; - } + void + setModelScale(float s) + { + model_scale_ = s; + } - void setFilterDuplicateViews(bool f) { - filter_duplicate_views_ = f; - std::cout << "setting filter duplicate views to " << f << std::endl; - } + void + setFilterDuplicateViews(bool f) + { + filter_duplicate_views_ = f; + std::cout << "setting filter duplicate views to " << f << std::endl; + } - void - getModelsInDirectory (bf::path & dir, std::string & rel_path_so_far, std::vector & relative_paths, std::string & ext) - { - for (const auto& dir_entry : bf::directory_iterator(dir)) - { - //check if its a directory, then get models in it - if (bf::is_directory (dir_entry)) - { - std::string so_far = rel_path_so_far + (dir_entry.path ().filename ()).string() + "/"; - - bf::path curr_path = dir_entry.path (); - getModelsInDirectory (curr_path, so_far, relative_paths, ext); - } - else - { - //check that it is a ply file and then add, otherwise ignore.. - std::vector < std::string > strs; - std::string file = (dir_entry.path ().filename ()).string(); - - boost::split (strs, file, boost::is_any_of (".")); - std::string extension = strs[strs.size () - 1]; - - if (extension == ext) - { - std::string path = rel_path_so_far + (dir_entry.path ().filename ()).string(); - - relative_paths.push_back (path); - } - } - } + void + getModelsInDirectory(bf::path& dir, + std::string& rel_path_so_far, + std::vector& relative_paths, + std::string& ext) + { + for (const auto& dir_entry : bf::directory_iterator(dir)) { + // check if its a directory, then get models in it + if (bf::is_directory(dir_entry)) { + std::string so_far = + rel_path_so_far + (dir_entry.path().filename()).string() + "/"; + + bf::path curr_path = dir_entry.path(); + getModelsInDirectory(curr_path, so_far, relative_paths, ext); } + else { + // check that it is a ply file and then add, otherwise ignore.. + std::vector strs; + std::string file = (dir_entry.path().filename()).string(); + + boost::split(strs, file, boost::is_any_of(".")); + std::string extension = strs[strs.size() - 1]; - void - voxelizeAllModels (float resolution) - { - for (std::size_t i = 0; i < models_->size (); i++) - { - models_->at (i).getAssembled (resolution); + if (extension == ext) { + std::string path = rel_path_so_far + (dir_entry.path().filename()).string(); + + relative_paths.push_back(path); } } + } + } - /** - * \brief Generate model representation - */ - virtual void - generate (std::string & training_dir)=0; - - /** - * \brief Get the generated model - */ - std::shared_ptr> - getModels () - { - return models_; - } + void + voxelizeAllModels(float resolution) + { + for (std::size_t i = 0; i < models_->size(); i++) { + models_->at(i).getAssembled(resolution); + } + } - std::shared_ptr> - getModels (std::string & model_id) - { - - typename std::vector::iterator it = models_->begin (); - while (it != models_->end ()) - { - if (model_id != (*it).id_) - { - it = models_->erase (it); - } - else - { - it++; - } - } + /** + * \brief Generate model representation + */ + virtual void + generate(std::string& training_dir) = 0; + + /** + * \brief Get the generated model + */ + std::shared_ptr> + getModels() + { + return models_; + } - return models_; - } + std::shared_ptr> + getModels(std::string& model_id) + { - bool - modelAlreadyTrained (ModelT m, std::string & base_dir, std::string & descr_name) - { - std::stringstream dir; - dir << base_dir << "/" << m.class_ << "/" << m.id_ << "/" << descr_name; - bf::path desc_dir = dir.str (); - std::cout << dir.str () << std::endl; - return bf::exists (desc_dir); + typename std::vector::iterator it = models_->begin(); + while (it != models_->end()) { + if (model_id != (*it).id_) { + it = models_->erase(it); } - - std::string - getModelDescriptorDir (ModelT m, std::string & base_dir, std::string & descr_name) - { - std::stringstream dir; - dir << base_dir << "/" << m.class_ << "/" << m.id_ << "/" << descr_name; - return dir.str (); + else { + it++; } + } - void - removeDescDirectory (ModelT m, std::string & base_dir, std::string & descr_name) - { - std::string dir = getModelDescriptorDir (m, base_dir, descr_name); + return models_; + } - bf::path desc_dir = dir; - if (bf::exists (desc_dir)) - bf::remove_all (desc_dir); - } + bool + modelAlreadyTrained(ModelT m, std::string& base_dir, std::string& descr_name) + { + std::stringstream dir; + dir << base_dir << "/" << m.class_ << "/" << m.id_ << "/" << descr_name; + bf::path desc_dir = dir.str(); + std::cout << dir.str() << std::endl; + return bf::exists(desc_dir); + } - void - setPath (std::string & path) - { - path_ = path; - } + std::string + getModelDescriptorDir(ModelT m, std::string& base_dir, std::string& descr_name) + { + std::stringstream dir; + dir << base_dir << "/" << m.class_ << "/" << m.id_ << "/" << descr_name; + return dir.str(); + } - void setLoadViews(bool load) { - load_views_ = load; - } - }; + void + removeDescDirectory(ModelT m, std::string& base_dir, std::string& descr_name) + { + std::string dir = getModelDescriptorDir(m, base_dir, descr_name); + + bf::path desc_dir = dir; + if (bf::exists(desc_dir)) + bf::remove_all(desc_dir); + } + + void + setPath(std::string& path) + { + path_ = path; } -} + + void + setLoadViews(bool load) + { + load_views_ = load; + } +}; + +} // namespace rec_3d_framework +} // namespace pcl diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h index f8cad7e0..981cc5d6 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h @@ -7,216 +7,211 @@ #pragma once +#include +#include +#include + #include -#include -#include -#include +namespace pcl { +namespace rec_3d_framework { + +template +class PCL_EXPORTS GlobalClassifier { +public: + using PointInTPtr = typename pcl::PointCloud::Ptr; -namespace pcl -{ - namespace rec_3d_framework + virtual void + setNN(int nn) = 0; + + virtual void + getCategory(std::vector& categories) = 0; + + virtual void + getConfidence(std::vector& conf) = 0; + + virtual void + classify() = 0; + + virtual void + setIndices(std::vector& indices) = 0; + + virtual void + setInputCloud(const PointInTPtr& cloud) = 0; +}; + +/** + * \brief Nearest neighbor search based classification of PCL point type features. + * FLANN is used to identify a neighborhood, based on which different scoring schemes + * can be employed to obtain likelihood values for a specified list of classes. + * Available features: ESF, VFH, CVFH + * See apps/3d_rec_framework/tools/apps/global_classification.cpp for usage + * \author Aitor Aldoma + */ + +template