Compare commits

..
Author SHA1 Message Date
matlabbe 4d8c1d8b90 bump 0.20.18 2022-01-28 17:12:24 -05:00
matlabbe 315350dbfc CCCorelib: updated wrong output check. Updated RGBD/MaxOdomCacheSize approach to work properly with Rtabmap/CreateIntermediateNodes=true. 2022-01-28 14:48:32 -05:00
matlabbe 02140f92db fixed build 2022-01-27 22:55:59 -05:00
matlabbe 402afc07ed ExportDialog: added ground normals up option, added camera projection mask and decimation options. Export CLI: added --ground_normals_up and --cam_projection_mask options, changed --bin option by --ascii option (now binary by default). DBViewer: warn when scan from depth option is enabled but there is no depth. 2022-01-27 17:57:56 -05:00
matlabbe a8e5bbf415 export: added --texture_roi_ratios option 2022-01-26 20:12:04 -05:00
matlabbe 5b3a7d5674 Localization: fixed always rejected localization when proximity and global loop closures are both detected at the same time at two different locations (clearing proximity detections from odometry cache if global loop closures are good). 2022-01-26 15:39:09 -05:00
matlabbe d56692640e DBViewer: fixed grid cell size in 3D View. Memory/Grid, using Icp/PointToPlaneGroundNormalsUp parameter when normals are computed. Grid: fixed 2D noHit ray tracing. 2022-01-25 18:10:43 -05:00
Ben 2dc7b59b05 allow negative min disparity in StereoBM dialog (#817) 2022-01-24 17:02:47 -05:00
Ben bbe10bca39 fix missing curl install in focal dockerfile (#816)
* add missing curl install to focal dockerfile

* add missing apt-get update
2022-01-24 16:44:39 -05:00
matlabbe e2dc3ac67e OctoMap: fixed empty occupancy not correctly updated when ray tracing is done on more than one local map 2022-01-23 16:29:11 -05:00
matlabbe 83d1e27b81 Refactored graph::getPosesInRadius -> graph::findNearestPoses. Labels can be removed: added Remove label option in MainWindow. In localization mode, label set with id=0 is set to nearest node of current pose. 2022-01-20 18:56:38 -05:00
matlabbe 3c215b9b4d android: fixed driver preference for arcore 2022-01-20 10:57:39 -05:00
matlabbe bdaed2f362 Tango: fixed google tango driver not selected automatically on first use 2022-01-19 20:24:23 -05:00
matlabbe e048d8ae72 Fixed compilation error without octomap 2022-01-19 19:53:49 -05:00
matlabbe 5b868d665f Grid/Sensor=2: fixed viewpoint offset bug of the camera. 2022-01-19 19:27:32 -05:00
matlabbe a56373f66d GUI/ExportClouds: fixed color of scans having RGB instead of intensity. 2022-01-19 16:59:43 -05:00
matlabbe 5ec73bee8d ios: improved significantly rendering performance 2022-01-19 02:11:38 -05:00
matlabbe b1dd44526d ios: fixed background camera not shown in landscape mode (iPhone) 2022-01-17 22:06:35 -05:00
matlabbe de62bbb9b7 Grid: don't filter max range before doing ray tracing (to ray trace empty space). 2022-01-17 14:22:11 -05:00
matlabbe 7a5c50cb0e Fixed compilation warnings 2022-01-16 15:27:52 -05:00
matlabbe 9622fe8393 Parameters: set default Icp/PointToPlaneRadius to 0 to avoid 'Both radius and K defined' error when using 3d lidar. 2022-01-16 12:56:18 -05:00
matlabbe 5f55f63443 report: ignoring landmarks after optimization to avoid errors when exporting poses 2022-01-15 22:02:45 -05:00
matlabbe aa0e6ef692 GUI:Export Poses: fixed poses!=stamps issue when there are landmarks (landmarks now only exported with g2o format) 2022-01-15 21:49:40 -05:00
matlabbe 03a106ea36 Fixed build without g2o 2022-01-15 13:00:12 -05:00
matlabbe 29a2b64a0c RGBD/NeighborLinkRefining: do one proximity detection by time if intermediate nodes are added. Optimized radiusFiltering(). Updated default parameters of proportionalRadiusFiltering(). 2022-01-14 18:47:57 -05:00
matlabbe 51f6b32f47 Fixed windows build (https://ci.appveyor.com/project/matlabbe/rtabmap/builds/42207812) 2022-01-14 14:33:32 -05:00
matlabbe 9e0173f4cb Export: added random sample filter, added proportional radius filter, refactored when normals are computed (now after the clouds are assembled and voxelized), moved ceiling and floor filtering inside assembling loop. 2022-01-14 13:36:01 -05:00
matlabbe 12c2dd707c Localization with Reg/Force3DoF=true, fixed how graph optimization errors are computed (use only x,y,yaw). 2022-01-12 16:59:03 -05:00
matlabbe fcec98105d Added RGBD/ProximityMergedScanCovFactor parameter. Localization: fixed output height when Reg/Force3DoF=true but input poses are 6DoF. Transform: added is3DoF() and is4DoF() functions. GTSAM: when Reg/Force3DoF=true, copy input roll,pitch,z values for output poses. RegIcp: fixed working memory dir '~' conversion. RGBD/ProximityGlobalScanMap: fixed map::at error when some nodes don't have scans. 2022-01-12 16:14:42 -05:00
matlabbe a4ec95963e Fixed a debug information 2022-01-11 15:59:53 -05:00
matlabbe 49353b134c LaserScan: fixed destination format when source is empty with operator+ 2022-01-11 15:32:30 -05:00
Tim Clephas f69085304e List dependencies only once (#812) 2022-01-11 10:40:48 -05:00
Marvin Stüde 3f797e02e3 Adds Boost serialization package for libpointmatcher case (#810) 2022-01-07 13:11:12 -05:00
matlabbe ab50ba0b6c Fixed android30 2022-01-05 21:39:27 -05:00
matlabbe 528b640a18 workflows: added android30 docker image 2022-01-04 20:54:53 -05:00
matlabbe 4d8a7b4659 CameraTango: fixed opencv4 errors 2022-01-04 20:49:03 +00:00
matlabbe ba6575fcb9 Added android30 build 2022-01-04 14:55:32 -05:00
matlabbe 1173f06bc8 android: fixed opencv4 deprecated errors 2022-01-04 19:46:20 +00:00
matlabbe a08fce2068 ios: added requestReview() 2022-01-03 20:57:41 -05:00
matlabbe d8324a11d5 android: fixed sharing file exiting bug, fixed camera not correctly set back to device default on reset settings. 2022-01-03 17:51:23 -05:00
matlabbe a6c9b3babe 💄 changed some cmake warnings in info 2022-01-03 16:33:21 -05:00
matlabbe 145430cafd Fixed noetic build (g2o error) 2022-01-03 16:05:11 -05:00
matlabbe 5194f40794 Fixed g2o build error with melodic/noetic versions 2022-01-03 15:37:06 -05:00
matlabbe 129bbf8f98 ios: added placeholder R in Library view for db not having preview (like recovered database) 2022-01-03 13:44:29 -05:00
matlabbe a9d4a16ba4 bump ios version 0.20.17 2022-01-02 23:40:46 -05:00
matlabbe b2f13c2772 android: fixed g2o seg fault (CACHE_SE3_OFFSET not registered) 2022-01-02 23:30:55 -05:00
matlabbe f3ace6c86a Added recovery feature to android 2022-01-02 18:09:57 -05:00
matlabbe 3147b4ab56 ios: added recovery feature 2022-01-02 17:08:44 -05:00
matlabbe fcde52c6bf ios: set First-P. View by default 2021-12-30 15:37:46 -05:00
matlabbe 5b31a4725d Update README.md 2021-12-29 19:05:35 -05:00
matlabbe e4955ee386 GUI: fixed mynteye raw images support error 2021-12-29 16:12:02 -05:00
matlabbe e5b4973ddc GUI: Added Orbbec Astra icon 2021-12-29 15:53:40 -05:00
matlabbe f3095a2e0a Calibration dialog: fixed right panel width size. Win32: packaging missing cudnn dlls (when torch is used) 2021-12-29 15:13:13 -05:00
matlabbe 044145926f ios: incremented build number 2021-12-28 18:35:55 -05:00
matlabbe a3823594a4 Converted an assert to an error. 2021-12-26 14:53:22 -05:00
matlabbe 3071da42f3 Optimizer: don't fix roll/pitch on root node if gravity constraints are fed 2021-12-25 16:57:03 -05:00
matlabbe 93ee8f9b30 Working dir path: convert ~ to Home for convenience. Localization: don't show "cannot optimize" warning when RGBD/MaxOdomCacheSize=0 2021-12-24 18:24:44 -05:00
matlabbe 7ca881453e RGBD/StartAtOrigin: set first node of the graph, not Identity 2021-12-20 17:01:08 -05:00
matlabbe 8662eb0dd7 Statistics: added OdomCache data for debugging 2021-12-18 18:53:59 -05:00
matlabbe 33130890fd Localization: Improved resulting pose in case there are gravity constraints. iOS: clear odom trace when not visible, fixed opt mesh not correctly aligned with graph on loading when switching RGBD/OptimizeFromGraphEnd. 2021-12-18 15:37:49 -05:00
matlabbe bca8b30832 Localization 2d Slam: automatically rotate landmark links to have z-axis up for correct 3DoF optimization. When RGBD/MaxOdomCacheSize is used, wait for at least 2 temporal localizations before adjusting the pose (to avoid big jumps when only one constraint is used). 2021-12-17 11:00:37 -05:00
matlabbe 6eb81cbb72 Added RGBD/MaxOdomCacheSize option to iOS App. 2021-12-12 20:40:28 -05:00
matlabbe 0e62050824 rtabmap: fixed graph re-optimized with only virtual links in localization mode (which can make gtsam crash because of under constrained covariance) 2021-12-12 13:07:02 -05:00
matlabbe cf5e90238b Statistics: added LoopOdom_correction stats for landmark detections. 2021-12-10 21:58:11 -05:00
matlabbe 8cf12c6135 Improved localization mode accuracy (decreasing jumps on consecutive loop closures or landmark detections). Updated usage of parameter RGBD/MaxOdomCacheSize (default 0->10) 2021-12-10 17:48:36 -05:00
matlabbe 4ab0090ecd Support feature-only rectification when using external extracted features. 2021-12-06 09:26:10 -05:00
matlabbe 580e35afb1 Fixed missing 3D keypoints when RGBD/LoopClosureReextractFeatures=true and Reg/Strategy=1 (https://github.com/introlab/rtabmap_ros/issues/668). DBViewer: fixed wrong poses optimization with GTSAM when showing scans of loop closures by proximity by space (multiscan) while there are GPS priors. 2021-12-05 17:38:53 -05:00
matlabbe 12906f4490 DBViewer: export poses: added explicit otion for ground truth if available 2021-12-03 13:43:53 -05:00
matlabbe baae713471 Fixed unknown lines for octomap 2D grid projection. (https://github.com/introlab/rtabmap_ros/issues/684) 2021-11-30 20:34:51 -05:00
matlabbe 67710ef94c Export: optimized camera projection RAM usage. Added --texture_angle and --cam_projection_decimation options. 2021-11-21 17:10:57 -05:00
matlabbe 090ae0c444 DbViewer: added option to show disparity instead of right image in main views for stereo data 2021-11-20 16:36:54 -05:00
matlabbe 6684bafe34 fixed typo 2021-11-16 18:22:45 -05:00
matlabbe 5fcbe2ed70 iOS: fixed install script (#785 #741) 2021-11-16 18:11:40 -05:00
matlabbe 459c7b2bd7 Export: added --min_cluster option. 2021-11-16 11:58:55 -05:00
matlabbe 9ae2c46546 CMake: fixed build without Python and Ceres if WITH_PYTHON and WITH_CERES are OFF (even if found by third party libraries, related to #783). 2021-11-15 18:00:17 -05:00
matlabbe 7af2a27e89 Improved log error when ROI is set with SuperPoint (https://github.com/introlab/rtabmap_ros/issues/676) 2021-11-14 20:26:42 -05:00
matlabbe dbecaac809 Moved bin dir inside build directory (#784)
* Moved bin directory inside build directory (to make easier different builds with same source directory)

* Switched include order to avoid problems with remaining Version.h still in source directory taen before the one in binary dir. Fixed android build (updated res tool search path).

* workflow-cmake: fixed path to bin directory
2021-11-14 19:29:37 -05:00
matlabbe 6c07a670ee Added OdometryOpen3D 2021-11-13 19:45:57 -05:00
matlabbe 4ba805b5b3 Report: fixed landmarks not used during optimization. Reprocess: added --nolandmark option to ignore landmarks in input database. 2021-11-12 12:47:54 -05:00
matlabbe b002e85e0f Update ProgressDialog.h
Typo param name should be in seconds, not milliseconds.
2021-11-09 17:36:34 -05:00
matlabbe ec2aa5c952 OpenNI2: depth shift can be negative. MainWindow: postProcessing() refactoring (split with and without dialog). 2021-11-09 10:16:12 -05:00
matlabbe 06150c697f Fixed #750 2021-11-08 14:20:21 -05:00
matlabbe 38bcb0060c CMake: set default to OFF for some optional dependencies that require specific versions or patches before integrating with rtabmap, otherwise there could be seg faults on runtime even if compilation worked. 2021-11-08 13:47:27 -05:00
225 changed files with 5580 additions and 2096 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Info - name: Info
working-directory: ${{github.workspace}}/bin working-directory: ${{github.workspace}}/build/bin
run: | run: |
source /opt/ros/${{ matrix.ros_distro }}/setup.bash source /opt/ros/${{ matrix.ros_distro }}/setup.bash
./rtabmap-console --version ./rtabmap-console --version
+7 -1
View File
@@ -11,7 +11,7 @@ jobs:
strategy: strategy:
matrix: matrix:
docker_tag: [xenial, bionic, focal, android23, android24, android26] docker_tag: [xenial, bionic, focal, android23, android24, android26, android30]
include: include:
- docker_tag: xenial - docker_tag: xenial
docker_tags: | docker_tags: |
@@ -56,6 +56,12 @@ jobs:
docker_platforms: | docker_platforms: |
linux/amd64 linux/amd64
docker_path: 'bionic/android/rtabmap_api26' docker_path: 'bionic/android/rtabmap_api26'
- docker_tag: android30
docker_tags: |
introlab3it/rtabmap:android30
docker_platforms: |
linux/amd64
docker_path: 'bionic/android/rtabmap_api30'
steps: steps:
- -
+83 -41
View File
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
####################### #######################
SET(RTABMAP_MAJOR_VERSION 0) SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 20) SET(RTABMAP_MINOR_VERSION 20)
SET(RTABMAP_PATCH_VERSION 15) SET(RTABMAP_PATCH_VERSION 18)
SET(RTABMAP_VERSION SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION}) ${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
@@ -123,9 +123,9 @@ OPTION( BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON )
####### OUTPUT DIR ####### ####### OUTPUT DIR #######
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
# Avoid Visual Studio bin/Release and bin/Debug sub directories # Avoid Visual Studio bin/Release and bin/Debug sub directories
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
@@ -181,12 +181,13 @@ option(WITH_DC1394 "Include dc1394 support" ON)
option(WITH_G2O "Include g2o support" ON) option(WITH_G2O "Include g2o support" ON)
option(WITH_GTSAM "Include GTSAM support" ON) option(WITH_GTSAM "Include GTSAM support" ON)
option(WITH_TORO "Include TORO support" ON) option(WITH_TORO "Include TORO support" ON)
option(WITH_CERES "Include Ceres support" ON) option(WITH_CERES "Include Ceres support" OFF)
option(WITH_VERTIGO "Include Vertigo support" ON) option(WITH_VERTIGO "Include Vertigo support" ON)
option(WITH_CVSBA "Include cvsba support" ON) option(WITH_CVSBA "Include cvsba support" OFF)
option(WITH_POINTMATCHER "Include libpointmatcher support" ON) option(WITH_POINTMATCHER "Include libpointmatcher support" ON)
option(WITH_CCCORELIB "Include CCCoreLib support" ON) option(WITH_CCCORELIB "Include CCCoreLib support" OFF)
option(WITH_LOAM "Include LOAM support" ON) option(WITH_OPEN3D "Include Open3D support" OFF)
option(WITH_LOAM "Include LOAM support" OFF)
option(WITH_FLOAM "Include FLOAM support" OFF) option(WITH_FLOAM "Include FLOAM support" OFF)
option(WITH_FLYCAPTURE2 "Include FlyCapture2/Triclops support" ON) option(WITH_FLYCAPTURE2 "Include FlyCapture2/Triclops support" ON)
option(WITH_ZED "Include ZED sdk support" ON) option(WITH_ZED "Include ZED sdk support" ON)
@@ -195,19 +196,19 @@ option(WITH_REALSENSE "Include RealSense support" ON)
option(WITH_REALSENSE_SLAM "Include RealSenseSlam support" ON) option(WITH_REALSENSE_SLAM "Include RealSenseSlam support" ON)
option(WITH_REALSENSE2 "Include RealSense support" ON) option(WITH_REALSENSE2 "Include RealSense support" ON)
option(WITH_MYNTEYE "Include mynteye-s support" ON) option(WITH_MYNTEYE "Include mynteye-s support" ON)
option(WITH_DEPTHAI "Include depthai-core support" ON) option(WITH_DEPTHAI "Include depthai-core support" OFF)
option(WITH_OCTOMAP "Include Octomap support" ON) option(WITH_OCTOMAP "Include Octomap support" ON)
option(WITH_CPUTSDF "Include CPUTSDF support" ON) option(WITH_CPUTSDF "Include CPUTSDF support" OFF)
option(WITH_OPENCHISEL "Include open_chisel support" ON) option(WITH_OPENCHISEL "Include open_chisel support" OFF)
option(WITH_ALICE_VISION "Include AliceVision support" OFF) option(WITH_ALICE_VISION "Include AliceVision support" OFF)
option(WITH_FOVIS "Include FOVIS support" ON) option(WITH_FOVIS "Include FOVIS support" OFF)
option(WITH_VISO2 "Include VISO2 support" ON) option(WITH_VISO2 "Include VISO2 support" OFF)
option(WITH_DVO "Include DVO support" ON) option(WITH_DVO "Include DVO support" OFF)
option(WITH_ORB_SLAM "Include ORB_SLAM2 or ORB_SLAM3 support" ON) option(WITH_ORB_SLAM "Include ORB_SLAM2 or ORB_SLAM3 support" OFF)
option(WITH_OKVIS "Include OKVIS support" ON) option(WITH_OKVIS "Include OKVIS support" OFF)
option(WITH_MSCKF_VIO "Include MSCKF_VIO support" OFF) option(WITH_MSCKF_VIO "Include MSCKF_VIO support" OFF)
option(WITH_VINS "Include VINS-Fusion support" ON) option(WITH_VINS "Include VINS-Fusion support" OFF)
option(WITH_OPENVINS "Include OpenVINS support" ON) option(WITH_OPENVINS "Include OpenVINS support" OFF)
option(WITH_MADGWICK "Include Madgwick IMU filtering support" ON) option(WITH_MADGWICK "Include Madgwick IMU filtering support" ON)
option(WITH_FASTCV "Include FastCV support" ON) option(WITH_FASTCV "Include FastCV support" ON)
option(WITH_OPENMP "Include OpenMP support" ON) option(WITH_OPENMP "Include OpenMP support" ON)
@@ -432,16 +433,29 @@ IF(WITH_DC1394)
ENDIF(WITH_DC1394) ENDIF(WITH_DC1394)
IF(WITH_G2O) IF(WITH_G2O)
FIND_PACKAGE(g2o QUIET NO_MODULE) FIND_PACKAGE(g2o QUIET NO_MODULE)
IF(g2o_FOUND) IF(g2o_FOUND)
MESSAGE(STATUS "Found g2o (targets)") MESSAGE(STATUS "Found g2o (targets)")
SET(G2O_FOUND ${g2o_FOUND}) SET(G2O_FOUND ${g2o_FOUND})
SET(G2O_CPP11 1) get_target_property(G2O_INCLUDES g2o::core INTERFACE_INCLUDE_DIRECTORIES)
MESSAGE(STATUS "g2o include dir: ${G2O_INCLUDES}")
FIND_FILE(G2O_FACTORY_FILE g2o/core/factory.h
PATHS ${G2O_INCLUDES}
NO_DEFAULT_PATH)
FILE(READ ${G2O_FACTORY_FILE} TMPTXT)
STRING(FIND "${TMPTXT}" "shared_ptr" matchres)
IF(${matchres} EQUAL -1)
MESSAGE(STATUS "Old g2o factory version detected without shared ptr (factory file: ${G2O_FACTORY_FILE}).")
SET(G2O_CPP11 2)
ELSE()
MESSAGE(STATUS "Latest g2o factory version detected with shared ptr (factory file: ${G2O_FACTORY_FILE}).")
SET(G2O_CPP11 1)
ENDIF()
ELSE() ELSE()
FIND_PACKAGE(G2O QUIET) FIND_PACKAGE(G2O QUIET)
IF(G2O_FOUND) IF(G2O_FOUND)
MESSAGE(STATUS "Found g2o: ${G2O_INCLUDE_DIRS}") MESSAGE(STATUS "Found g2o: ${G2O_INCLUDE_DIRS}")
ENDIF(G2O_FOUND) ENDIF(G2O_FOUND)
ENDIF() ENDIF()
ENDIF(WITH_G2O) ENDIF(WITH_G2O)
@@ -474,7 +488,7 @@ ENDIF(WITH_POINTMATCHER)
IF(libpointmatcher_FOUND OR GTSAM_FOUND) IF(libpointmatcher_FOUND OR GTSAM_FOUND)
find_package(Boost COMPONENTS thread filesystem system program_options date_time REQUIRED) find_package(Boost COMPONENTS thread filesystem system program_options date_time REQUIRED)
IF(Boost_MINOR_VERSION GREATER 47) IF(Boost_MINOR_VERSION GREATER 47)
find_package(Boost COMPONENTS thread filesystem system program_options date_time chrono timer REQUIRED) find_package(Boost COMPONENTS thread filesystem system program_options date_time chrono timer serialization REQUIRED)
ENDIF(Boost_MINOR_VERSION GREATER 47) ENDIF(Boost_MINOR_VERSION GREATER 47)
IF(WIN32) IF(WIN32)
MESSAGE(STATUS "Boost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}") MESSAGE(STATUS "Boost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}")
@@ -489,6 +503,19 @@ IF(WITH_CCCORELIB)
ENDIF(CCCoreLib_FOUND) ENDIF(CCCoreLib_FOUND)
ENDIF(WITH_CCCORELIB) ENDIF(WITH_CCCORELIB)
IF(WITH_OPEN3D)
IF(${CMAKE_VERSION} VERSION_LESS "3.19.0")
MESSAGE(WARNING "Open3D requires CMake version >=3.19 (current is ${CMAKE_VERSION})")
ELSE()
# Build Open3D like this to avoid linker errors in rtabmap:
# cmake -DBUILD_SHARED_LIBS=ON -DGLIBCXX_USE_CXX11_ABI=ON -DCMAKE_BUILD_TYPE=Release ..
find_package(Open3D QUIET)
IF(Open3D_FOUND)
MESSAGE(STATUS "Found Open3D: ${Open3DINCLUDE_DIRS}")
ENDIF(Open3D_FOUND)
ENDIF()
ENDIF(WITH_OPEN3D)
IF(WITH_LOAM) IF(WITH_LOAM)
find_package(loam_velodyne QUIET) find_package(loam_velodyne QUIET)
IF(loam_velodyne_FOUND) IF(loam_velodyne_FOUND)
@@ -695,7 +722,7 @@ IF(WITH_ORB_SLAM AND NOT G2O_FOUND)
ENDIF(WITH_ORB_SLAM AND NOT G2O_FOUND) ENDIF(WITH_ORB_SLAM AND NOT G2O_FOUND)
IF(NOT MSVC) IF(NOT MSVC)
IF(loam_velodyne_FOUND OR floam_FOUND OR PCL_VERSION VERSION_GREATER "1.9.1" OR TORCH_FOUND OR G2O_FOUND OR CCCoreLib_FOUND) IF(loam_velodyne_FOUND OR floam_FOUND OR PCL_VERSION VERSION_GREATER "1.9.1" OR TORCH_FOUND OR G2O_FOUND OR CCCoreLib_FOUND OR Open3D_FOUND)
#LOAM, PCL>=1.10, latest g2o and CCCoreLib require c++14 #LOAM, PCL>=1.10, latest g2o and CCCoreLib require c++14
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
@@ -705,7 +732,7 @@ IF(NOT MSVC)
ELSE() ELSE()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler if you want to use LOAM, latest PCL or g2o.") message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler if you want to use LOAM, latest PCL or g2o.")
ENDIF() ENDIF()
ENDIF(loam_velodyne_FOUND OR floam_FOUND OR PCL_VERSION VERSION_GREATER "1.9.1" OR TORCH_FOUND OR G2O_FOUND OR CCCoreLib_FOUND) ENDIF(loam_velodyne_FOUND OR floam_FOUND OR PCL_VERSION VERSION_GREATER "1.9.1" OR TORCH_FOUND OR G2O_FOUND OR CCCoreLib_FOUND OR Open3D_FOUND)
IF( (NOT (${CMAKE_CXX_STANDARD} STREQUAL "14")) AND ( IF( (NOT (${CMAKE_CXX_STANDARD} STREQUAL "14")) AND (
G2O_FOUND OR G2O_FOUND OR
@@ -790,6 +817,7 @@ ENDIF()
IF(NOT G2O_FOUND) IF(NOT G2O_FOUND)
SET(G2O "//") SET(G2O "//")
SET(G2O_CPP_CONF "//")
ELSE() ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${G2O_LIBRARIES}) SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${G2O_LIBRARIES})
IF(NOT G2O_CPP11) IF(NOT G2O_CPP11)
@@ -801,9 +829,9 @@ IF(NOT GTSAM_FOUND)
ELSE() ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${GTSAM_LIBRARIES}) SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${GTSAM_LIBRARIES})
ENDIF() ENDIF()
IF(NOT CERES_FOUND) IF(NOT WITH_CERES OR NOT CERES_FOUND)
SET(CERES "//") SET(CERES "//")
ENDIF(NOT CERES_FOUND) ENDIF(NOT WITH_CERES OR NOT CERES_FOUND)
IF(NOT WITH_TORO) IF(NOT WITH_TORO)
SET(TORO "//") SET(TORO "//")
ENDIF(NOT WITH_TORO) ENDIF(NOT WITH_TORO)
@@ -821,6 +849,9 @@ ENDIF(NOT libpointmatcher_FOUND)
IF(NOT CCCoreLib_FOUND) IF(NOT CCCoreLib_FOUND)
SET(CCCORELIB "//") SET(CCCORELIB "//")
ENDIF(NOT CCCoreLib_FOUND) ENDIF(NOT CCCoreLib_FOUND)
IF(NOT Open3D_FOUND)
SET(OPEN3D "//")
ENDIF(NOT Open3D_FOUND)
IF(NOT FastCV_FOUND) IF(NOT FastCV_FOUND)
SET(FASTCV "//") SET(FASTCV "//")
ENDIF(NOT FastCV_FOUND) ENDIF(NOT FastCV_FOUND)
@@ -965,7 +996,7 @@ ENDIF()
IF(NOT TORCH_FOUND) IF(NOT TORCH_FOUND)
SET(TORCH "//") SET(TORCH "//")
ENDIF() ENDIF()
IF(NOT Python3_FOUND) IF(NOT WITH_PYTHON OR NOT Python3_FOUND)
SET(PYTHON "//") SET(PYTHON "//")
ENDIF() ENDIF()
IF(ADD_VTK_GUI_SUPPORT_QT_TO_CONF) IF(ADD_VTK_GUI_SUPPORT_QT_TO_CONF)
@@ -981,7 +1012,7 @@ IF(NOT WITH_MADGWICK)
SET(MADGWICK "//") SET(MADGWICK "//")
ENDIF() ENDIF()
CONFIGURE_FILE(Version.h.in ${PROJECT_SOURCE_DIR}/corelib/include/${PROJECT_PREFIX}/core/Version.h) CONFIGURE_FILE(Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/corelib/include/${PROJECT_PREFIX}/core/Version.h)
ADD_SUBDIRECTORY( utilite ) ADD_SUBDIRECTORY( utilite )
ADD_SUBDIRECTORY( corelib ) ADD_SUBDIRECTORY( corelib )
@@ -1025,7 +1056,8 @@ file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}
file(RELATIVE_PATH REL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") file(RELATIVE_PATH REL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
# ... for the build tree # ... for the build tree
set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/corelib/include" set(CONF_INCLUDE_DIRS "${PROJECT_BINARY_DIR}/corelib/include"
"${PROJECT_SOURCE_DIR}/corelib/include"
"${PROJECT_SOURCE_DIR}/guilib/include" "${PROJECT_SOURCE_DIR}/guilib/include"
"${PROJECT_SOURCE_DIR}/utilite/include") "${PROJECT_SOURCE_DIR}/utilite/include")
set(CONF_LIB_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") set(CONF_LIB_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
@@ -1236,7 +1268,7 @@ ELSE()
MESSAGE(STATUS " With SupertPoint = NO (libtorch not found)") MESSAGE(STATUS " With SupertPoint = NO (libtorch not found)")
ENDIF() ENDIF()
IF(Python3_FOUND) IF(WITH_PYTHON AND Python3_FOUND)
MESSAGE(STATUS " With Python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR} = YES (License: PSF)") MESSAGE(STATUS " With Python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR} = YES (License: PSF)")
ELSEIF(NOT WITH_PYTHON) ELSEIF(NOT WITH_PYTHON)
MESSAGE(STATUS " With Python3 = NO (WITH_PYTHON=OFF)") MESSAGE(STATUS " With Python3 = NO (WITH_PYTHON=OFF)")
@@ -1290,12 +1322,12 @@ ELSE()
MESSAGE(STATUS " *With GTSAM = NO (GTSAM not found)") MESSAGE(STATUS " *With GTSAM = NO (GTSAM not found)")
ENDIF() ENDIF()
IF(CERES_FOUND) IF(WITH_CERES AND CERES_FOUND)
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD)") MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD)")
ELSEIF(NOT WITH_CERES) ELSEIF(NOT WITH_CERES)
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = NO (WITH_CERES=OFF)") MESSAGE(STATUS " *With Ceres = NO (WITH_CERES=OFF)")
ELSE() ELSE()
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = NO (Ceres not found)") MESSAGE(STATUS " *With Ceres = NO (Ceres not found)")
ENDIF() ENDIF()
IF(G2O_FOUND OR GTSAM_FOUND) IF(G2O_FOUND OR GTSAM_FOUND)
@@ -1332,6 +1364,16 @@ ELSE()
MESSAGE(STATUS " With CCCoreLib = NO (CCCoreLib not found)") MESSAGE(STATUS " With CCCoreLib = NO (CCCoreLib not found)")
ENDIF() ENDIF()
IF(Open3D_FOUND)
MESSAGE(STATUS " With Open3D = YES (License: MIT)")
ELSEIF(NOT WITH_OPEN3D)
MESSAGE(STATUS " With Open3D = NO (WITH_OPEN3D=OFF)")
ELSEIF(${CMAKE_VERSION} VERSION_LESS "3.19.0")
MESSAGE(STATUS " With Open3D = NO (Open3D requires CMake>=3.19)")
ELSE()
MESSAGE(STATUS " With Open3D = NO (Open3D not found)")
ENDIF()
MESSAGE(STATUS "") MESSAGE(STATUS "")
MESSAGE(STATUS " Reconstruction Approaches:") MESSAGE(STATUS " Reconstruction Approaches:")
IF(octomap_FOUND) IF(octomap_FOUND)
@@ -1566,12 +1608,12 @@ ENDIF()
MESSAGE(STATUS "Show all options with: cmake -LA | grep WITH_") MESSAGE(STATUS "Show all options with: cmake -LA | grep WITH_")
MESSAGE(STATUS "--------------------------------------------") MESSAGE(STATUS "--------------------------------------------")
IF(NOT GTSAM_FOUND AND NOT G2O_FOUND AND NOT WITH_TORO AND NOT CERES_FOUND) IF(NOT GTSAM_FOUND AND NOT G2O_FOUND AND NOT WITH_TORO AND NOT WITH_CERES AND NOT CERES_FOUND)
MESSAGE(SEND_ERROR "No graph optimizer found! You should have at least one of these options: MESSAGE(SEND_ERROR "No graph optimizer found! You should have at least one of these options:
g2o (https://github.com/RainerKuemmerle/g2o) g2o (https://github.com/RainerKuemmerle/g2o)
GTSAM (https://collab.cc.gatech.edu/borg/gtsam) GTSAM (https://collab.cc.gatech.edu/borg/gtsam)
Ceres (http://ceres-solver.org) Ceres (http://ceres-solver.org)
set -DWITH_TORO=ON") set -DWITH_TORO=ON")
ENDIF(NOT GTSAM_FOUND AND NOT G2O_FOUND AND NOT WITH_TORO AND NOT CERES_FOUND) ENDIF(NOT GTSAM_FOUND AND NOT G2O_FOUND AND NOT WITH_TORO AND NOT WITH_CERES AND NOT CERES_FOUND)
# vim: set et ft=cmake fenc=utf-8 ff=unix sts=0 sw=2 ts=2 : # vim: set et ft=cmake fenc=utf-8 ff=unix sts=0 sw=2 ts=2 :
+2 -2
View File
@@ -1,4 +1,4 @@
rtabmap ![.](https://ga-beacon-279122.nn.r.appspot.com/UA-56986679-3/github-main?pixel) rtabmap
======= =======
[![RTAB-Map Logo](https://raw.githubusercontent.com/introlab/rtabmap/master/guilib/src/images/RTAB-Map100.png)](http://introlab.github.io/rtabmap) [![RTAB-Map Logo](https://raw.githubusercontent.com/introlab/rtabmap/master/guilib/src/images/RTAB-Map100.png)](http://introlab.github.io/rtabmap)
@@ -7,7 +7,7 @@ rtabmap ![.](https://ga-beacon-279122.nn.r.appspot.com/UA-56986679-3/github-main
[![License][license-image]][license] [![License][license-image]][license]
Linux: [![Build Status](https://github.com/introlab/rtabmap/actions/workflows/cmake.yml/badge.svg)](https://github.com/introlab/rtabmap/actions/workflows/cmake.yml) [![docker](https://github.com/introlab/rtabmap/actions/workflows/docker.yml/badge.svg)](https://github.com/introlab/rtabmap/actions/workflows/docker.yml) Windows: [![Build status](https://ci.appveyor.com/api/projects/status/hr73xspix9oqa26h/branch/master?svg=true)](https://ci.appveyor.com/project/matlabbe/rtabmap/branch/master) Linux: [![Build Status](https://github.com/introlab/rtabmap/actions/workflows/cmake.yml/badge.svg)](https://github.com/introlab/rtabmap/actions/workflows/cmake.yml) [![docker](https://github.com/introlab/rtabmap/actions/workflows/docker.yml/badge.svg)](https://github.com/introlab/rtabmap/actions/workflows/docker.yml) Windows: [![Build status](https://ci.appveyor.com/api/projects/status/hr73xspix9oqa26h/branch/master?svg=true)](https://ci.appveyor.com/project/matlabbe/rtabmap/branch/master)
[release-image]: https://img.shields.io/badge/release-0.20.8-green.svg?style=flat [release-image]: https://img.shields.io/badge/release-0.20.16-green.svg?style=flat
[releases]: https://github.com/introlab/rtabmap/releases [releases]: https://github.com/introlab/rtabmap/releases
[license-image]: https://img.shields.io/badge/license-BSD-green.svg?style=flat [license-image]: https://img.shields.io/badge/license-BSD-green.svg?style=flat
+2 -1
View File
@@ -40,7 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@NONFREE@#define RTABMAP_NONFREE @NONFREE@#define RTABMAP_NONFREE
@TORO@#define RTABMAP_TORO @TORO@#define RTABMAP_TORO
@G2O@#define RTABMAP_G2O @G2O@#define RTABMAP_G2O
@G2O_CPP_CONF@#define RTABMAP_G2O_CPP11 @G2O_CPP_CONF@#define RTABMAP_G2O_CPP11 @G2O_CPP11@
@GTSAM@#define RTABMAP_GTSAM @GTSAM@#define RTABMAP_GTSAM
@CERES@#define RTABMAP_CERES @CERES@#define RTABMAP_CERES
@VERTIGO@#define RTABMAP_VERTIGO @VERTIGO@#define RTABMAP_VERTIGO
@@ -52,6 +52,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@CVSBA@#define RTABMAP_CVSBA @CVSBA@#define RTABMAP_CVSBA
@POINTMATCHER@#define RTABMAP_POINTMATCHER @POINTMATCHER@#define RTABMAP_POINTMATCHER
@CCCORELIB@#define RTABMAP_CCCORELIB @CCCORELIB@#define RTABMAP_CCCORELIB
@OPEN3D@#define RTABMAP_OPEN3D
@FASTCV@#define RTABMAP_FASTCV @FASTCV@#define RTABMAP_FASTCV
@PDAL@#define RTABMAP_PDAL @PDAL@#define RTABMAP_PDAL
@LOAM@#define RTABMAP_LOAM @LOAM@#define RTABMAP_LOAM
+16 -1
View File
@@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -17,6 +18,11 @@
<!-- This is the platform API where depth16 support in android was introduced. --> <!-- This is the platform API where depth16 support in android was introduced. -->
<uses-sdk android:minSdkVersion="@ANDROID_NATIVE_API_LEVEL@" /> <uses-sdk android:minSdkVersion="@ANDROID_NATIVE_API_LEVEL@" />
<queries>
<package android:name="com.google.ar.core" />
<package android:name="com.huawei.ar.engine" />
</queries>
<!-- This .apk has no Java code itself, so set hasCode to false. --> <!-- This .apk has no Java code itself, so set hasCode to false. -->
<application <application
@@ -42,7 +48,16 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<action android:name="android.intent.action.OPEN_DOCUMENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/octet-stream" />
<data android:pathPattern=".*\.db" />
</intent-filter>
</activity> </activity>
<activity android:name="SettingsActivity" android:label="@string/settings" android:screenOrientation="fullSensor"/> <activity android:name="SettingsActivity" android:label="@string/settings" android:screenOrientation="fullSensor"/>
+1
View File
@@ -3,6 +3,7 @@ SET(INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/tango-gl/include ${CMAKE_CURRENT_SOURCE_DIR}/tango-gl/include
${CMAKE_CURRENT_SOURCE_DIR}/third-party/include ${CMAKE_CURRENT_SOURCE_DIR}/third-party/include
${PROJECT_BINARY_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/corelib/include ${PROJECT_SOURCE_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/utilite/include ${PROJECT_SOURCE_DIR}/utilite/include
${OpenCV_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}
+2 -2
View File
@@ -520,11 +520,11 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
cv::Mat yuv(height+height/2, width, CV_8UC1); cv::Mat yuv(height+height/2, width, CV_8UC1);
memcpy(yuv.data, plane_data, data_length); memcpy(yuv.data, plane_data, data_length);
memcpy(yuv.data+data_length, plane_uv_data, height/2*width); memcpy(yuv.data+data_length, plane_uv_data, height/2*width);
cv::cvtColor(yuv, rgb, CV_YUV2BGR_NV21); cv::cvtColor(yuv, rgb, cv::COLOR_YUV2BGR_NV21);
} }
else else
{ {
cv::cvtColor(cv::Mat(height+height/2, width, CV_8UC1, (void*)plane_data), rgb, CV_YUV2BGR_NV21); cv::cvtColor(cv::Mat(height+height/2, width, CV_8UC1, (void*)plane_data), rgb, cv::COLOR_YUV2BGR_NV21);
} }
std::vector<cv::KeyPoint> kpts; std::vector<cv::KeyPoint> kpts;
+1 -1
View File
@@ -244,7 +244,7 @@ SensorData CameraAREngine::captureImage(CameraInfo * info)
cv::Mat outputRGB; cv::Mat outputRGB;
if(imageData != nullptr && len>0) if(imageData != nullptr && len>0)
{ {
cv::cvtColor(cv::Mat(height+height/2, width, CV_8UC1, (void*)imageData), outputRGB, CV_YUV2BGR_NV21); cv::cvtColor(cv::Mat(height+height/2, width, CV_8UC1, (void*)imageData), outputRGB, cv::COLOR_YUV2BGR_NV21);
} }
//Depth //Depth
+1 -1
View File
@@ -171,7 +171,7 @@ void CameraMobile::setData(const SensorData & data, const Transform & pose, cons
if(textureId_ != 0 && texCoord != 0) if(textureId_ != 0 && texCoord != 0)
{ {
cv::Mat rgbImage; cv::Mat rgbImage;
cv::cvtColor(data.imageRaw(), rgbImage, CV_BGR2RGBA); cv::cvtColor(data.imageRaw(), rgbImage, cv::COLOR_BGR2RGBA);
glBindTexture(GL_TEXTURE_2D, textureId_); glBindTexture(GL_TEXTURE_2D, textureId_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+3 -3
View File
@@ -478,15 +478,15 @@ void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
LOGD("tangoColorType=%d", tangoColorType); LOGD("tangoColorType=%d", tangoColorType);
if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_RGBA_8888) if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_RGBA_8888)
{ {
cv::cvtColor(tangoImage, rgb, CV_RGBA2BGR); cv::cvtColor(tangoImage, rgb, cv::COLOR_RGBA2BGR);
} }
else if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_YV12) else if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_YV12)
{ {
cv::cvtColor(tangoImage, rgb, CV_YUV2BGR_YV12); cv::cvtColor(tangoImage, rgb, cv::COLOR_YUV2BGR_YV12);
} }
else if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP) else if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP)
{ {
cv::cvtColor(tangoImage, rgb, CV_YUV2BGR_NV21); cv::cvtColor(tangoImage, rgb, cv::COLOR_YUV2BGR_NV21);
} }
else if(tangoColorType == 35) else if(tangoColorType == 35)
{ {
+103 -39
View File
@@ -64,6 +64,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/Memory.h> #include <rtabmap/core/Memory.h>
#include <rtabmap/core/GainCompensator.h> #include <rtabmap/core/GainCompensator.h>
#include <rtabmap/core/DBDriver.h> #include <rtabmap/core/DBDriver.h>
#include <rtabmap/core/Recovery.h>
#include <pcl/common/common.h> #include <pcl/common/common.h>
#include <pcl/filters/extract_indices.h> #include <pcl/filters/extract_indices.h>
#include <pcl/io/ply_io.h> #include <pcl/io/ply_io.h>
@@ -82,6 +83,43 @@ static JavaVM *jvm;
static jobject RTABMapActivity = 0; static jobject RTABMapActivity = 0;
#endif #endif
#ifdef __ANDROID__
#ifndef DISABLE_LOG
//ref: https://codelab.wordpress.com/2014/11/03/how-to-use-standard-output-streams-for-logging-in-android-apps/
static int pfd[2];
static pthread_t thr;
static void *thread_func(void*)
{
ssize_t rdsz;
char buf[128];
while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
if(buf[rdsz - 1] == '\n') --rdsz;
buf[rdsz] = 0; /* add null-terminator */
__android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf);
}
return 0;
}
int start_logger()
{
/* make stdout line-buffered and stderr unbuffered */
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
/* create the pipe and redirect stdout and stderr */
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
/* spawn the logging thread */
if(pthread_create(&thr, 0, thread_func, 0) == -1)
return -1;
pthread_detach(thr);
return 0;
}
#endif
#endif
rtabmap::ParametersMap RTABMapApp::getRtabmapParameters() rtabmap::ParametersMap RTABMapApp::getRtabmapParameters()
{ {
rtabmap::ParametersMap parameters; rtabmap::ParametersMap parameters;
@@ -243,6 +281,12 @@ RTABMapApp::RTABMapApp() :
this->registerToEventsManager(); this->registerToEventsManager();
LOGI("RTABMapApp::RTABMapApp() end"); LOGI("RTABMapApp::RTABMapApp() end");
#ifdef __ANDROID__
#ifndef DISABLE_LOG
start_logger();
#endif
#endif
} }
#ifndef __ANDROID__ // __APPLE__ #ifndef __ANDROID__ // __APPLE__
@@ -305,9 +349,9 @@ void RTABMapApp::setScreenRotation(int displayRotation, int cameraRotation)
} }
} }
int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMemory, bool optimize, const std::string & databaseSource) int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMemory, bool optimize, bool clearDatabase)
{ {
LOGW("Opening database %s (inMemory=%d, optimize=%d)", databasePath.c_str(), databaseInMemory?1:0, optimize?1:0); LOGW("Opening database %s (inMemory=%d, optimize=%d, clearDatabase=%d)", databasePath.c_str(), databaseInMemory?1:0, optimize?1:0, clearDatabase?1:0);
this->unregisterFromEventsManager(); // to ignore published init events when closing rtabmap this->unregisterFromEventsManager(); // to ignore published init events when closing rtabmap
status_.first = rtabmap::RtabmapEventInit::kInitializing; status_.first = rtabmap::RtabmapEventInit::kInitializing;
rtabmapMutex_.lock(); rtabmapMutex_.lock();
@@ -360,11 +404,11 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
std::vector<std::vector<Eigen::Vector2f> > texCoords; std::vector<std::vector<Eigen::Vector2f> > texCoords;
#endif #endif
cv::Mat textures; cv::Mat textures;
if(!databaseSource.empty()) if(!databasePath.empty() && UFile::exists(databasePath) && !clearDatabase)
{ {
UEventsManager::post(new rtabmap::RtabmapEventInit(rtabmap::RtabmapEventInit::kInfo, "Loading optimized cloud/mesh...")); UEventsManager::post(new rtabmap::RtabmapEventInit(rtabmap::RtabmapEventInit::kInfo, "Loading optimized cloud/mesh..."));
rtabmap::DBDriver * driver = rtabmap::DBDriver::create(); rtabmap::DBDriver * driver = rtabmap::DBDriver::create();
if(driver->openConnection(databaseSource)) if(driver->openConnection(databasePath))
{ {
cloudMat = driver->loadOptimizedMesh(&polygons, &texCoords, &textures); cloudMat = driver->loadOptimizedMesh(&polygons, &texCoords, &textures);
if(!cloudMat.empty()) if(!cloudMat.empty())
@@ -416,13 +460,11 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
} }
UEventsManager::post(new rtabmap::RtabmapEventInit(rtabmap::RtabmapEventInit::kInfo, "Loading database...")); UEventsManager::post(new rtabmap::RtabmapEventInit(rtabmap::RtabmapEventInit::kInfo, "Loading database..."));
LOGI("Erasing database \"%s\"...", databasePath.c_str()); if(clearDatabase)
UFile::erase(databasePath); {
if(!databaseSource.empty()) LOGI("Erasing database \"%s\"...", databasePath.c_str());
{ UFile::erase(databasePath);
LOGI("Copying database source \"%s\" to \"%s\"...", databaseSource.c_str(), databasePath.c_str()); }
UFile::copy(databaseSource, databasePath);
}
//Rtabmap //Rtabmap
mapToOdom_.setIdentity(); mapToOdom_.setIdentity();
@@ -448,7 +490,7 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
poses, poses,
links, links,
true, true,
true, false, // Make sure poses are the same than optimized mesh (in case we switched RGBD/OptimizedFromGraphEnd)
&signatures, &signatures,
true, true,
true, true,
@@ -593,7 +635,7 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
if(renderingTextureDecimation_>1) if(renderingTextureDecimation_>1)
{ {
cv::Size reducedSize(data.imageRaw().cols/renderingTextureDecimation_, data.imageRaw().rows/renderingTextureDecimation_); cv::Size reducedSize(data.imageRaw().cols/renderingTextureDecimation_, data.imageRaw().rows/renderingTextureDecimation_);
cv::resize(data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, CV_INTER_LINEAR); cv::resize(data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
} }
else else
{ {
@@ -1199,7 +1241,12 @@ int RTABMapApp::Render()
std::list<rtabmap::RtabmapEvent*> rtabmapEvents; std::list<rtabmap::RtabmapEvent*> rtabmapEvents;
try try
{ {
UTimer fpsTime; if(camera_ == 0)
{
// We are not doing continous drawing, just measure single draw
fpsTime_.restart();
}
#ifdef DEBUG_RENDERING_PERFORMANCE #ifdef DEBUG_RENDERING_PERFORMANCE
UTimer time; UTimer time;
#endif #endif
@@ -1399,7 +1446,14 @@ int RTABMapApp::Render()
} }
else if(rtabmapThread_ && rtabmapThread_->isRunning() && landmark!=0) else if(rtabmapThread_ && rtabmapThread_->isRunning() && landmark!=0)
{ {
main_scene_.setBackgroundColor(1, 0.65f, 0); // orange if(rejected)
{
main_scene_.setBackgroundColor(0.5, 0.325f, 0); // dark orange
}
else
{
main_scene_.setBackgroundColor(1, 0.65f, 0); // orange
}
} }
else if(rtabmapThread_ && rtabmapThread_->isRunning() && rejected>0) else if(rtabmapThread_ && rtabmapThread_->isRunning() && rejected>0)
{ {
@@ -1439,12 +1493,12 @@ int RTABMapApp::Render()
main_scene_.setMeshRendering(main_scene_.hasMesh(g_optMeshId), main_scene_.hasTexture(g_optMeshId)); main_scene_.setMeshRendering(main_scene_.hasMesh(g_optMeshId), main_scene_.hasTexture(g_optMeshId));
fpsTime.restart();
main_scene_.setFrustumVisible(camera_!=0); main_scene_.setFrustumVisible(camera_!=0);
lastDrawnCloudsCount_ = main_scene_.Render(uvsTransformed, arViewMatrix, arProjectionMatrix); lastDrawnCloudsCount_ = main_scene_.Render(uvsTransformed, arViewMatrix, arProjectionMatrix);
if(renderingTime_ < fpsTime.elapsed()) double fpsTime = fpsTime_.ticks();
if(renderingTime_ < fpsTime)
{ {
renderingTime_ = fpsTime.elapsed(); renderingTime_ = fpsTime;
} }
// revert state // revert state
@@ -1571,7 +1625,7 @@ int RTABMapApp::Render()
{ {
cv::Size reducedSize(textureRaw.cols/renderingTextureDecimation_, textureRaw.rows/renderingTextureDecimation_); cv::Size reducedSize(textureRaw.cols/renderingTextureDecimation_, textureRaw.rows/renderingTextureDecimation_);
LOGD("resize image from %dx%d to %dx%d", textureRaw.cols, textureRaw.rows, reducedSize.width, reducedSize.height); LOGD("resize image from %dx%d to %dx%d", textureRaw.cols, textureRaw.rows, reducedSize.width, reducedSize.height);
cv::resize(textureRaw, iter->second.texture, reducedSize, 0, 0, CV_INTER_LINEAR); cv::resize(textureRaw, iter->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
} }
else else
{ {
@@ -1856,7 +1910,7 @@ int RTABMapApp::Render()
if(renderingTextureDecimation_ > 1) if(renderingTextureDecimation_ > 1)
{ {
cv::Size reducedSize(data.imageRaw().cols/renderingTextureDecimation_, data.imageRaw().rows/renderingTextureDecimation_); cv::Size reducedSize(data.imageRaw().cols/renderingTextureDecimation_, data.imageRaw().rows/renderingTextureDecimation_);
cv::resize(data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, CV_INTER_LINEAR); cv::resize(data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
#ifdef DEBUG_RENDERING_PERFORMANCE #ifdef DEBUG_RENDERING_PERFORMANCE
LOGW("resize image from %dx%d to %dx%d (%fs)", data.imageRaw().cols, data.imageRaw().rows, reducedSize.width, reducedSize.height, time.ticks()); LOGW("resize image from %dx%d to %dx%d (%fs)", data.imageRaw().cols, data.imageRaw().rows, reducedSize.width, reducedSize.height, time.ticks());
#endif #endif
@@ -2046,13 +2100,13 @@ int RTABMapApp::Render()
notifyDataLoaded = true; notifyDataLoaded = true;
} }
fpsTime.restart(); main_scene_.setFrustumVisible(camera_!=0);
main_scene_.setFrustumVisible(camera_!=0);
lastDrawnCloudsCount_ = main_scene_.Render(uvsTransformed, arViewMatrix, arProjectionMatrix, occlusionMesh, true); lastDrawnCloudsCount_ = main_scene_.Render(uvsTransformed, arViewMatrix, arProjectionMatrix, occlusionMesh, true);
if(renderingTime_ < fpsTime.elapsed()) double fpsTime = fpsTime_.ticks();
if(renderingTime_ < fpsTime)
{ {
renderingTime_ = fpsTime.elapsed(); renderingTime_ = fpsTime;
} }
if(rtabmapEvents.size()) if(rtabmapEvents.size())
{ {
@@ -2089,7 +2143,7 @@ int RTABMapApp::Render()
cv::Mat image(h, w, CV_8UC4); cv::Mat image(h, w, CV_8UC4);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.data); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.data);
cv::flip(image, image, 0); cv::flip(image, image, 0);
cv::cvtColor(image, image, CV_RGBA2BGRA); cv::cvtColor(image, image, cv::COLOR_RGBA2BGRA);
cv::Mat roi; cv::Mat roi;
if(w>h) if(w>h)
{ {
@@ -2108,16 +2162,6 @@ int RTABMapApp::Render()
screenshotReady_.release(); screenshotReady_.release();
} }
if((openingDatabase_ && !visualizingMesh_) || exporting_ || postProcessing_)
{
// throttle rendering max 5Hz if we are doing some processing
double renderTime = fpsTime.elapsed();
if(0.2 - renderTime > 0.0)
{
uSleep((0.2 - renderTime)*1000);
}
}
if((rtabmapThread_==0 || !rtabmapThread_->isRunning()) && lastPostRenderEventTime_ > 0.0) if((rtabmapThread_==0 || !rtabmapThread_->isRunning()) && lastPostRenderEventTime_ > 0.0)
{ {
double interval = UTimer::now() - lastPostRenderEventTime_; double interval = UTimer::now() - lastPostRenderEventTime_;
@@ -2550,6 +2594,26 @@ void RTABMapApp::save(const std::string & databasePath)
} }
} }
bool RTABMapApp::recover(const std::string & from, const std::string & to)
{
std::string errorMsg;
if(!databaseRecovery(from, false, &errorMsg, &progressionStatus_))
{
LOGE("Recovery Error: %s", errorMsg.c_str());
return false;
}
else
{
LOGI("Renaming %s to %s", from.c_str(), to.c_str());
if(UFile::rename(from, to) != 0)
{
LOGE("Failed renaming %s to %s", from.c_str(), to.c_str());
return false;
}
return true;
}
}
void RTABMapApp::cancelProcessing() void RTABMapApp::cancelProcessing()
{ {
UWARN("Processing canceled!"); UWARN("Processing canceled!");
@@ -3704,14 +3768,14 @@ void RTABMapApp::postOdometryEvent(
cv::Mat yuv(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1); cv::Mat yuv(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1);
memcpy(yuv.data, yPlane, yPlaneLen); memcpy(yuv.data, yPlane, yPlaneLen);
memcpy(yuv.data+yPlaneLen, vPlane, rgbHeight/2*rgbWidth); memcpy(yuv.data+yPlaneLen, vPlane, rgbHeight/2*rgbWidth);
cv::cvtColor(yuv, outputRGB, CV_YUV2BGR_NV21); cv::cvtColor(yuv, outputRGB, cv::COLOR_YUV2BGR_NV21);
} }
else else
{ {
#ifdef __ANDROID__ #ifdef __ANDROID__
cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (void*)yPlane), outputRGB, CV_YUV2BGR_NV21); cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (void*)yPlane), outputRGB, cv::COLOR_YUV2BGR_NV21);
#else // __APPLE__ #else // __APPLE__
cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (void*)yPlane), outputRGB, CV_YUV2RGB_NV21); cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (void*)yPlane), outputRGB, cv::COLOR_YUV2RGB_NV21);
#endif #endif
} }
+4 -1
View File
@@ -75,7 +75,7 @@ class RTABMapApp : public UEventsHandler {
void setScreenRotation(int displayRotation, int cameraRotation); void setScreenRotation(int displayRotation, int cameraRotation);
int openDatabase(const std::string & databasePath, bool databaseInMemory, bool optimize, const std::string & databaseSource=std::string()); int openDatabase(const std::string & databasePath, bool databaseInMemory, bool optimize, bool clearDatabase);
bool isBuiltWith(int cameraDriver) const; bool isBuiltWith(int cameraDriver) const;
#ifdef __ANDROID__ #ifdef __ANDROID__
@@ -153,6 +153,7 @@ class RTABMapApp : public UEventsHandler {
void addEnvSensor(int type, float value); void addEnvSensor(int type, float value);
void save(const std::string & databasePath); void save(const std::string & databasePath);
bool recover(const std::string & from, const std::string & to);
void cancelProcessing(); void cancelProcessing();
bool exportMesh( bool exportMesh(
float cloudVoxelSize, float cloudVoxelSize,
@@ -265,6 +266,8 @@ class RTABMapApp : public UEventsHandler {
// main_scene_ includes all drawable object for visualizing Tango device's // main_scene_ includes all drawable object for visualizing Tango device's
// movement and point cloud. // movement and point cloud.
Scene main_scene_; Scene main_scene_;
UTimer fpsTime_;
std::list<rtabmap::RtabmapEvent*> rtabmapEvents_; std::list<rtabmap::RtabmapEvent*> rtabmapEvents_;
std::list<rtabmap::OdometryEvent> odomEvents_; std::list<rtabmap::OdometryEvent> odomEvents_;
+10 -10
View File
@@ -89,13 +89,13 @@ Java_com_introlab_rtabmap_RTABMapLib_setScreenRotation(
JNIEXPORT int JNICALL JNIEXPORT int JNICALL
Java_com_introlab_rtabmap_RTABMapLib_openDatabase( Java_com_introlab_rtabmap_RTABMapLib_openDatabase(
JNIEnv* env, jclass, jlong native_application, jstring databasePath, bool databaseInMemory, bool optimize) JNIEnv* env, jclass, jlong native_application, jstring databasePath, bool databaseInMemory, bool optimize, bool clearDatabase)
{ {
std::string databasePathC; std::string databasePathC;
GetJStringContent(env,databasePath,databasePathC); GetJStringContent(env,databasePath,databasePathC);
if(native_application) if(native_application)
{ {
return native(native_application)->openDatabase(databasePathC, databaseInMemory, optimize); return native(native_application)->openDatabase(databasePathC, databaseInMemory, optimize, clearDatabase);
} }
else else
{ {
@@ -104,17 +104,17 @@ Java_com_introlab_rtabmap_RTABMapLib_openDatabase(
} }
} }
JNIEXPORT int JNICALL JNIEXPORT bool JNICALL
Java_com_introlab_rtabmap_RTABMapLib_openDatabase2( Java_com_introlab_rtabmap_RTABMapLib_recover(
JNIEnv* env, jclass, jlong native_application, jstring databaseSource, jstring databasePath, bool databaseInMemory, bool optimize) JNIEnv* env, jclass, jlong native_application, jstring from, jstring to)
{ {
if(native_application) if(native_application)
{ {
std::string databasePathC; std::string toC;
GetJStringContent(env,databasePath,databasePathC); GetJStringContent(env,to,toC);
std::string databaseSourceC; std::string fromC;
GetJStringContent(env,databaseSource,databaseSourceC); GetJStringContent(env,from,fromC);
return native(native_application)->openDatabase(databasePathC, databaseInMemory, optimize, databaseSourceC); return native(native_application)->recover(fromC, toC);
} }
else else
{ {
+252 -131
View File
@@ -309,8 +309,8 @@ PointCloudDrawable::PointCloudDrawable(
float gainR, float gainR,
float gainG, float gainG,
float gainB) : float gainB) :
vertex_buffers_(0), vertex_buffer_(0),
textures_(0), texture_(0),
nPoints_(0), nPoints_(0),
pose_(rtabmap::Transform::getIdentity()), pose_(rtabmap::Transform::getIdentity()),
poseGl_(1.0f), poseGl_(1.0f),
@@ -320,14 +320,16 @@ PointCloudDrawable::PointCloudDrawable(
gainG_(gainG), gainG_(gainG),
gainB_(gainB) gainB_(gainB)
{ {
index_buffers_.resize(6, 0);
index_buffers_count_.resize(6, 0);
updateCloud(cloud, indices); updateCloud(cloud, indices);
} }
PointCloudDrawable::PointCloudDrawable( PointCloudDrawable::PointCloudDrawable(
const rtabmap::Mesh & mesh, const rtabmap::Mesh & mesh,
bool createWireframe) : bool createWireframe) :
vertex_buffers_(0), vertex_buffer_(0),
textures_(0), texture_(0),
nPoints_(0), nPoints_(0),
pose_(rtabmap::Transform::getIdentity()), pose_(rtabmap::Transform::getIdentity()),
poseGl_(1.0f), poseGl_(1.0f),
@@ -337,64 +339,83 @@ PointCloudDrawable::PointCloudDrawable(
gainG_(1.0f), gainG_(1.0f),
gainB_(1.0f) gainB_(1.0f)
{ {
index_buffers_.resize(6, 0);
index_buffers_count_.resize(6, 0);
updateMesh(mesh, createWireframe); updateMesh(mesh, createWireframe);
} }
PointCloudDrawable::~PointCloudDrawable() PointCloudDrawable::~PointCloudDrawable()
{ {
LOGI("Freeing cloud buffer %d", vertex_buffers_); LOGI("Freeing cloud buffer %d", vertex_buffer_);
if (vertex_buffers_) if (vertex_buffer_)
{ {
glDeleteBuffers(1, &vertex_buffers_); glDeleteBuffers(1, &vertex_buffer_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
vertex_buffers_ = 0; vertex_buffer_ = 0;
} }
if (textures_) if (texture_)
{ {
glDeleteTextures(1, &textures_); glDeleteTextures(1, &texture_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
textures_ = 0; texture_ = 0;
} }
for(size_t i=0; i<index_buffers_.size(); ++i)
{
if(index_buffers_[i])
{
glDeleteBuffers(1, &index_buffers_[i]);
index_buffers_[i] = 0;
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()");
}
}
} }
void PointCloudDrawable::updatePolygons(const std::vector<pcl::Vertices> & polygons, const std::vector<pcl::Vertices> & polygonsLowRes, bool createWireframe) void PointCloudDrawable::updatePolygons(const std::vector<pcl::Vertices> & polygons, const std::vector<pcl::Vertices> & polygonsLowRes, bool createWireframe)
{ {
for(int i=0; i<4; ++i)
{
if(index_buffers_[i])
{
glDeleteBuffers(1, &index_buffers_[i]);
index_buffers_[i] = 0;
tango_gl::util::CheckGlError("PointCloudDrawable::updatePolygons() clearing polygon buffers");
}
}
//LOGD("Update polygons"); //LOGD("Update polygons");
polygons_.clear();
polygonLines_.clear();
polygonsLowRes_.clear();
polygonLinesLowRes_.clear();
if(polygons.size() && organizedToDenseIndices_.size()) if(polygons.size() && organizedToDenseIndices_.size())
{ {
unsigned int polygonSize = polygons[0].vertices.size(); size_t polygonSize = polygons[0].vertices.size();
UASSERT(polygonSize == 3); UASSERT(polygonSize == 3);
polygons_.resize(polygons.size() * polygonSize); std::vector<std::vector<GLuint> > indexes(4);
indexes[0].resize(polygons.size() * polygonSize);
if(createWireframe) if(createWireframe)
polygonLines_.resize(polygons_.size()*2); indexes[2].resize(indexes[0].size()*2);
int oi = 0; int oi = 0;
int li = 0; int li = 0;
for(unsigned int i=0; i<polygons.size(); ++i) for(size_t i=0; i<polygons.size(); ++i)
{ {
UASSERT(polygons[i].vertices.size() == polygonSize); UASSERT(polygons[i].vertices.size() == polygonSize);
for(unsigned int j=0; j<polygonSize; ++j) for(unsigned int j=0; j<polygonSize; ++j)
{ {
polygons_[oi++] = organizedToDenseIndices_.at(polygons[i].vertices[j]); indexes[0][oi++] = organizedToDenseIndices_.at(polygons[i].vertices[j]);
if(createWireframe) if(createWireframe)
{ {
polygonLines_[li++] = organizedToDenseIndices_.at(polygons[i].vertices[j]); indexes[2][li++] = organizedToDenseIndices_.at(polygons[i].vertices[j]);
polygonLines_[li++] = organizedToDenseIndices_.at(polygons[i].vertices[(j+1) % polygonSize]); indexes[2][li++] = organizedToDenseIndices_.at(polygons[i].vertices[(j+1) % polygonSize]);
} }
} }
} }
if(polygonsLowRes.size()) if(polygonsLowRes.size())
{ {
unsigned int polygonSize = polygonsLowRes[0].vertices.size(); size_t polygonSize = polygonsLowRes[0].vertices.size();
UASSERT(polygonSize == 3); UASSERT(polygonSize == 3);
polygonsLowRes_.resize(polygonsLowRes.size() * polygonSize); indexes[1].resize(polygonsLowRes.size() * polygonSize);
if(createWireframe) if(createWireframe)
polygonLinesLowRes_.resize(polygonsLowRes_.size()*2); indexes[3].resize(indexes[1].size()*2);
int oi = 0; int oi = 0;
int li = 0; int li = 0;
for(unsigned int i=0; i<polygonsLowRes.size(); ++i) for(unsigned int i=0; i<polygonsLowRes.size(); ++i)
@@ -402,15 +423,44 @@ void PointCloudDrawable::updatePolygons(const std::vector<pcl::Vertices> & polyg
UASSERT(polygonsLowRes[i].vertices.size() == polygonSize); UASSERT(polygonsLowRes[i].vertices.size() == polygonSize);
for(unsigned int j=0; j<polygonSize; ++j) for(unsigned int j=0; j<polygonSize; ++j)
{ {
polygonsLowRes_[oi++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]); indexes[1][oi++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]);
if(createWireframe) if(createWireframe)
{ {
polygonLinesLowRes_[li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]); indexes[3][li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[j]);
polygonLinesLowRes_[li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[(j+1)%polygonSize]); indexes[3][li++] = organizedToDenseIndices_.at(polygonsLowRes[i].vertices[(j+1)%polygonSize]);
} }
} }
} }
} }
// Generate index buffers
for(size_t i=0; i<indexes.size(); ++i)
{
if(!indexes[i].empty())
{
glGenBuffers(1, &index_buffers_[i]);
if(!index_buffers_[i])
{
LOGE("OpenGL: could not generate index buffer %ld\n", i);
return;
}
LOGD("Adding polygon index %ld size=%ld", i, indexes[i].size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * indexes[i].size(), indexes[i].data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
index_buffers_count_[i] = (int)indexes[i].size();
GLint error = glGetError();
if(error != GL_NO_ERROR)
{
LOGE("OpenGL: Could not allocate indexes (0x%x)\n", error);
index_buffers_[i] = 0;
return;
}
}
}
} }
} }
@@ -418,43 +468,51 @@ void PointCloudDrawable::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Pt
{ {
UASSERT(cloud.get() && !cloud->empty()); UASSERT(cloud.get() && !cloud->empty());
nPoints_ = 0; nPoints_ = 0;
polygons_.clear();
polygonsLowRes_.clear();
verticesLowRes_.clear();
verticesLowLowRes_.clear();
aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000); aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000);
aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000); aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000);
if (vertex_buffers_) if (vertex_buffer_)
{ {
glDeleteBuffers(1, &vertex_buffers_); glDeleteBuffers(1, &vertex_buffer_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::updateCloud() clear vertex buffer");
vertex_buffers_ = 0; vertex_buffer_ = 0;
} }
if (textures_) if (texture_)
{ {
glDeleteTextures(1, &textures_); glDeleteTextures(1, &texture_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::updateCloud() clear texture buffer");
textures_ = 0; texture_ = 0;
} }
for(size_t i=0; i<index_buffers_.size(); ++i)
{
if(index_buffers_[i])
{
glDeleteBuffers(1, &index_buffers_[i]);
index_buffers_[i] = 0;
tango_gl::util::CheckGlError("PointCloudDrawable::updateCloud() clear index buffer");
}
}
glGenBuffers(1, &vertex_buffers_); glGenBuffers(1, &vertex_buffer_);
if(!vertex_buffers_) if(!vertex_buffer_)
{ {
LOGE("OpenGL: could not generate vertex buffers\n"); LOGE("OpenGL: could not generate vertex buffers\n");
return; return;
} }
LOGI("Creating cloud buffer %d", vertex_buffers_); LOGI("Creating cloud buffer %d", vertex_buffer_);
std::vector<float> vertices; std::vector<float> vertices;
int totalPoints = 0; size_t totalPoints = 0;
std::vector<GLuint> verticesLowRes;
std::vector<GLuint> verticesLowLowRes;
if(indices.get() && indices->size()) if(indices.get() && indices->size())
{ {
totalPoints = indices->size(); totalPoints = indices->size();
vertices.resize(indices->size()*4); vertices.resize(indices->size()*4);
verticesLowRes_.resize(cloud->isOrganized()?totalPoints:0); verticesLowRes.resize(cloud->isOrganized()?totalPoints:0);
verticesLowLowRes_.resize(cloud->isOrganized()?totalPoints:0); verticesLowLowRes.resize(cloud->isOrganized()?totalPoints:0);
int oi_low = 0; int oi_low = 0;
int oi_lowlow = 0; int oi_lowlow = 0;
for(unsigned int i=0; i<indices->size(); ++i) for(unsigned int i=0; i<indices->size(); ++i)
@@ -471,23 +529,23 @@ void PointCloudDrawable::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Pt
{ {
if(indices->at(i)%LOW_DEC == 0 && (indices->at(i)/cloud->width) % LOW_DEC == 0) if(indices->at(i)%LOW_DEC == 0 && (indices->at(i)/cloud->width) % LOW_DEC == 0)
{ {
verticesLowRes_[oi_low++] = i; verticesLowRes[oi_low++] = i;
} }
if(indices->at(i)%LOWLOW_DEC == 0 && (indices->at(i)/cloud->width) % LOWLOW_DEC == 0) if(indices->at(i)%LOWLOW_DEC == 0 && (indices->at(i)/cloud->width) % LOWLOW_DEC == 0)
{ {
verticesLowLowRes_[oi_lowlow++] = i; verticesLowLowRes[oi_lowlow++] = i;
} }
} }
} }
verticesLowRes_.resize(oi_low); verticesLowRes.resize(oi_low);
verticesLowLowRes_.resize(oi_lowlow); verticesLowLowRes.resize(oi_lowlow);
} }
else else
{ {
totalPoints = cloud->size(); totalPoints = cloud->size();
vertices.resize(cloud->size()*4); vertices.resize(cloud->size()*4);
verticesLowRes_.resize(cloud->isOrganized()?totalPoints:0); verticesLowRes.resize(cloud->isOrganized()?totalPoints:0);
verticesLowLowRes_.resize(cloud->isOrganized()?totalPoints:0); verticesLowLowRes.resize(cloud->isOrganized()?totalPoints:0);
int oi_low = 0; int oi_low = 0;
int oi_lowlow = 0; int oi_lowlow = 0;
for(unsigned int i=0; i<cloud->size(); ++i) for(unsigned int i=0; i<cloud->size(); ++i)
@@ -504,19 +562,19 @@ void PointCloudDrawable::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Pt
{ {
if(i%LOW_DEC == 0 && (i/cloud->width) % LOW_DEC == 0) if(i%LOW_DEC == 0 && (i/cloud->width) % LOW_DEC == 0)
{ {
verticesLowRes_[oi_low++] = i; verticesLowRes[oi_low++] = i;
} }
if(i%LOWLOW_DEC == 0 && (i/cloud->width) % LOWLOW_DEC == 0) if(i%LOWLOW_DEC == 0 && (i/cloud->width) % LOWLOW_DEC == 0)
{ {
verticesLowLowRes_[oi_lowlow++] = i; verticesLowLowRes[oi_lowlow++] = i;
} }
} }
} }
verticesLowRes_.resize(oi_low); verticesLowRes.resize(oi_low);
verticesLowLowRes_.resize(oi_lowlow); verticesLowLowRes.resize(oi_lowlow);
} }
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -524,11 +582,40 @@ void PointCloudDrawable::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Pt
if(error != GL_NO_ERROR) if(error != GL_NO_ERROR)
{ {
LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error); LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error);
vertex_buffers_ = 0; vertex_buffer_ = 0;
return; return;
} }
// vertex index buffers
for(size_t i=4; i<5; ++i)
{
if((i==4 && !verticesLowRes.empty()) ||
(i==5 && !verticesLowLowRes.empty()))
{
glGenBuffers(1, &index_buffers_[i]);
if(!index_buffers_[i])
{
LOGE("OpenGL: could not generate index buffer %ld\n", i);
return;
}
index_buffers_count_[i] = i==4?(int)verticesLowRes.size():(int)verticesLowLowRes.size();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * index_buffers_count_[i], i==4?verticesLowRes.data():verticesLowLowRes.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
nPoints_ = totalPoints; GLint error = glGetError();
if(error != GL_NO_ERROR)
{
LOGE("OpenGL: Could not allocate indexes (0x%x)\n", error);
index_buffers_[i] = 0;
return;
}
}
}
nPoints_ = (int)totalPoints;
} }
void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWireframe) void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWireframe)
@@ -538,12 +625,22 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000); aabbMinModel_ = aabbMinWorld_ = pcl::PointXYZ(1000,1000,1000);
aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000); aabbMaxModel_ = aabbMaxWorld_ = pcl::PointXYZ(-1000,-1000,-1000);
if (vertex_buffers_) if (vertex_buffer_)
{ {
glDeleteBuffers(1, &vertex_buffers_); glDeleteBuffers(1, &vertex_buffer_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::updateMesh() clear vertex buffer");
vertex_buffers_ = 0; vertex_buffer_ = 0;
} }
for(size_t i=0; i<index_buffers_.size(); ++i)
{
if(index_buffers_[i])
{
glDeleteBuffers(1, &index_buffers_[i]);
index_buffers_[i] = 0;
tango_gl::util::CheckGlError("PointCloudDrawable::updateMesh() clear index buffer");
}
}
gainR_ = mesh.gains[0]; gainR_ = mesh.gains[0];
gainG_ = mesh.gains[1]; gainG_ = mesh.gains[1];
@@ -552,17 +649,17 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
bool textureUpdate = false; bool textureUpdate = false;
if(!mesh.texture.empty() && mesh.texture.type() == CV_8UC3) if(!mesh.texture.empty() && mesh.texture.type() == CV_8UC3)
{ {
if (textures_) if (texture_)
{ {
glDeleteTextures(1, &textures_); glDeleteTextures(1, &texture_);
tango_gl::util::CheckGlError("PointCloudDrawable::~PointCloudDrawable()"); tango_gl::util::CheckGlError("PointCloudDrawable::updateMesh() clear texture buffer");
textures_ = 0; texture_ = 0;
} }
textureUpdate = true; textureUpdate = true;
} }
glGenBuffers(1, &vertex_buffers_); glGenBuffers(1, &vertex_buffer_);
if(!vertex_buffers_) if(!vertex_buffer_)
{ {
LOGE("OpenGL: could not generate vertex buffers\n"); LOGE("OpenGL: could not generate vertex buffers\n");
return; return;
@@ -570,10 +667,10 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
if(textureUpdate) if(textureUpdate)
{ {
glGenTextures(1, &textures_); glGenTextures(1, &texture_);
if(!textures_) if(!texture_)
{ {
vertex_buffers_ = 0; vertex_buffer_ = 0;
LOGE("OpenGL: could not generate texture buffers\n"); LOGE("OpenGL: could not generate texture buffers\n");
return; return;
} }
@@ -591,11 +688,13 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
polygonsLowRes = mesh.polygonsLowRes; // only in organized we keep the low res polygonsLowRes = mesh.polygonsLowRes; // only in organized we keep the low res
organizedToDenseIndices_ = std::vector<unsigned int>(mesh.cloud->width*mesh.cloud->height, -1); organizedToDenseIndices_ = std::vector<unsigned int>(mesh.cloud->width*mesh.cloud->height, -1);
totalPoints = (int)mesh.indices->size(); totalPoints = (int)mesh.indices->size();
verticesLowRes_.resize(totalPoints); std::vector<GLuint> verticesLowRes;
verticesLowLowRes_.resize(totalPoints); std::vector<GLuint> verticesLowLowRes;
verticesLowRes.resize(totalPoints);
verticesLowLowRes.resize(totalPoints);
int oi_low = 0; int oi_low = 0;
int oi_lowlow = 0; int oi_lowlow = 0;
if(textures_ && polygons.size()) if(texture_ && polygons.size())
{ {
int items = hasNormals_?9:6; int items = hasNormals_?9:6;
vertices = std::vector<float>(mesh.indices->size()*items); vertices = std::vector<float>(mesh.indices->size()*items);
@@ -628,11 +727,11 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0) if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0)
{ {
verticesLowRes_[oi_low++] = i; verticesLowRes[oi_low++] = i;
} }
if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0) if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0)
{ {
verticesLowLowRes_[oi_lowlow++] = i; verticesLowLowRes[oi_lowlow++] = i;
} }
} }
} }
@@ -663,20 +762,48 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0) if(mesh.indices->at(i)%LOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOW_DEC == 0)
{ {
verticesLowRes_[oi_low++] = i; verticesLowRes[oi_low++] = i;
} }
if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0) if(mesh.indices->at(i)%LOWLOW_DEC == 0 && (mesh.indices->at(i)/mesh.cloud->width) % LOWLOW_DEC == 0)
{ {
verticesLowLowRes_[oi_lowlow++] = i; verticesLowLowRes[oi_lowlow++] = i;
} }
} }
} }
verticesLowRes_.resize(oi_low); verticesLowRes.resize(oi_low);
verticesLowLowRes_.resize(oi_lowlow); verticesLowLowRes.resize(oi_lowlow);
// vertex index buffers
for(size_t i=4; i<5; ++i)
{
if((i==4 && !verticesLowRes.empty()) ||
(i==5 && !verticesLowLowRes.empty()))
{
glGenBuffers(1, &index_buffers_[i]);
if(!index_buffers_[i])
{
LOGE("OpenGL: could not generate index buffer %ld\n", i);
return;
}
index_buffers_count_[i] = i==4?(int)verticesLowRes.size():(int)verticesLowLowRes.size();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * index_buffers_count_[i], i==4?verticesLowRes.data():verticesLowLowRes.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
GLint error = glGetError();
if(error != GL_NO_ERROR)
{
LOGE("OpenGL: Could not allocate indexes (0x%x)\n", error);
index_buffers_[i] = 0;
return;
}
}
}
} }
else // assume dense mesh with texCoords set to polygons else // assume dense mesh with texCoords set to polygons
{ {
if(textures_ && polygons.size()) if(texture_ && polygons.size())
{ {
//LOGD("Dense mesh with texture (%d texCoords %d points %d polygons %dx%d)", //LOGD("Dense mesh with texture (%d texCoords %d points %d polygons %dx%d)",
// (int)mesh.texCoords.size(), (int)mesh.cloud->size(), (int)mesh.polygons.size(), texture.cols, texture.rows); // (int)mesh.texCoords.size(), (int)mesh.cloud->size(), (int)mesh.polygons.size(), texture.cols, texture.rows);
@@ -743,7 +870,7 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
} }
else else
{ {
totalPoints = mesh.cloud->size(); totalPoints = (int)mesh.cloud->size();
//LOGD("Dense mesh"); //LOGD("Dense mesh");
int items = hasNormals_?7:4; int items = hasNormals_?7:4;
organizedToDenseIndices_ = std::vector<unsigned int>(totalPoints, -1); organizedToDenseIndices_ = std::vector<unsigned int>(totalPoints, -1);
@@ -771,7 +898,7 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
} }
} }
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (int)vertices.size(), (const void *)vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -779,11 +906,11 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
if(error != GL_NO_ERROR) if(error != GL_NO_ERROR)
{ {
LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error); LOGE("OpenGL: Could not allocate point cloud (0x%x)\n", error);
vertex_buffers_ = 0; vertex_buffer_ = 0;
return; return;
} }
if(textures_ && textureUpdate) if(texture_ && textureUpdate)
{ {
//GLint maxTextureSize = 0; //GLint maxTextureSize = 0;
//glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
@@ -793,13 +920,13 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
//LOGW("maxTextureUnits=%d", maxTextureUnits); //LOGW("maxTextureUnits=%d", maxTextureUnits);
// gen texture from image // gen texture from image
glBindTexture(GL_TEXTURE_2D, textures_); glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
cv::Mat rgbImage; cv::Mat rgbImage;
cv::cvtColor(mesh.texture, rgbImage, CV_BGR2RGBA); cv::cvtColor(mesh.texture, rgbImage, cv::COLOR_BGR2RGBA);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); //glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@@ -811,20 +938,17 @@ void PointCloudDrawable::updateMesh(const rtabmap::Mesh & mesh, bool createWiref
if(error != GL_NO_ERROR) if(error != GL_NO_ERROR)
{ {
LOGE("OpenGL: Could not allocate texture (0x%x)\n", error); LOGE("OpenGL: Could not allocate texture (0x%x)\n", error);
textures_ = 0; texture_ = 0;
glDeleteBuffers(1, &vertex_buffers_); glDeleteBuffers(1, &vertex_buffer_);
vertex_buffers_ = 0; vertex_buffer_ = 0;
return; return;
} }
} }
nPoints_ = totalPoints; nPoints_ = totalPoints;
if(polygons_.size() != polygons.size()) updatePolygons(polygons, polygonsLowRes, createWireframe);
{
updatePolygons(polygons, polygonsLowRes, createWireframe);
}
if(!pose_.isNull()) if(!pose_.isNull())
{ {
@@ -886,14 +1010,14 @@ void PointCloudDrawable::Render(
bool packDepthToColorChannel, bool packDepthToColorChannel,
bool wireFrame) const bool wireFrame) const
{ {
if(vertex_buffers_ && nPoints_ && visible_ && !shaderPrograms_.empty()) if(vertex_buffer_ && nPoints_ && visible_ && !shaderPrograms_.empty())
{ {
if(packDepthToColorChannel || !hasNormals_) if(packDepthToColorChannel || !hasNormals_)
{ {
lighting = false; lighting = false;
} }
if(packDepthToColorChannel || !(meshRendering && textureRendering && textures_)) if(packDepthToColorChannel || !(meshRendering && textureRendering && texture_))
{ {
textureRendering = false; textureRendering = false;
} }
@@ -996,7 +1120,7 @@ void PointCloudDrawable::Render(
// Texture activate unit 0 // Texture activate unit 0
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
// Bind the texture to this unit. // Bind the texture to this unit.
glBindTexture(GL_TEXTURE_2D, textures_); glBindTexture(GL_TEXTURE_2D, texture_);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLuint texture_handle = glGetUniformLocation(program, "uTexture"); GLuint texture_handle = glGetUniformLocation(program, "uTexture");
glUniform1i(texture_handle, 0); glUniform1i(texture_handle, 0);
@@ -1012,8 +1136,8 @@ void PointCloudDrawable::Render(
} }
tango_gl::util::CheckGlError("Pointcloud::Render() common"); tango_gl::util::CheckGlError("Pointcloud::Render() common");
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffers_); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
if(textures_) if(texture_)
{ {
glVertexAttribPointer(attribute_vertex, 3, GL_FLOAT, GL_FALSE, (hasNormals_?9:6)*sizeof(GLfloat), 0); glVertexAttribPointer(attribute_vertex, 3, GL_FLOAT, GL_FALSE, (hasNormals_?9:6)*sizeof(GLfloat), 0);
if(textureRendering) if(textureRendering)
@@ -1044,53 +1168,49 @@ void PointCloudDrawable::Render(
tango_gl::util::CheckGlError("Pointcloud::Render() set attribute pointer"); tango_gl::util::CheckGlError("Pointcloud::Render() set attribute pointer");
UTimer drawTime; UTimer drawTime;
if(textureRendering) if((textureRendering || meshRendering) && index_buffers_[0])
{ {
if(distanceToCameraSqr<16.0f || polygonsLowRes_.empty()) float dist = meshRendering?50.0f:16.0f;
if(distanceToCameraSqr<dist || index_buffers_[1]==0)
{ {
wireFrame = wireFrame && polygonLines_.size(); wireFrame = wireFrame && index_buffers_[2];
if(wireFrame) if(wireFrame)
glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data()); {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[2]);
glDrawElements(GL_LINES, index_buffers_count_[2], GL_UNSIGNED_INT, 0);
}
else else
glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data()); {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[0]);
glDrawElements(GL_TRIANGLES, index_buffers_count_[0], GL_UNSIGNED_INT, 0);
}
} }
else else
{ {
wireFrame = wireFrame && polygonLinesLowRes_.size(); wireFrame = wireFrame && index_buffers_[3];
if(wireFrame) if(wireFrame)
glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data()); {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[3]);
glDrawElements(GL_LINES, index_buffers_count_[3], GL_UNSIGNED_INT, 0);
}
else else
glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data()); {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[1]);
glDrawElements(GL_TRIANGLES, index_buffers_count_[1], GL_UNSIGNED_INT, 0);
}
} }
} }
else if(meshRendering && polygons_.size()) else if(index_buffers_[4])
{ {
if(distanceToCameraSqr<50.0f || polygonsLowRes_.empty()) if(distanceToCameraSqr>600.0f && index_buffers_[5])
{ {
wireFrame = wireFrame && polygonLines_.size(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[5]);
if(wireFrame) glDrawElements(GL_POINTS, index_buffers_count_[5], GL_UNSIGNED_INT, 0);
glDrawElements(GL_LINES, polygonLines_.size(), GL_UNSIGNED_INT, polygonLines_.data());
else
glDrawElements(GL_TRIANGLES, polygons_.size(), GL_UNSIGNED_INT, polygons_.data());
}
else
{
wireFrame = wireFrame && polygonLinesLowRes_.size();
if(wireFrame)
glDrawElements(GL_LINES, polygonLinesLowRes_.size(), GL_UNSIGNED_INT, polygonLinesLowRes_.data());
else
glDrawElements(GL_TRIANGLES, polygonsLowRes_.size(), GL_UNSIGNED_INT, polygonsLowRes_.data());
}
}
else if(!verticesLowRes_.empty())
{
if(distanceToCameraSqr>600.0f)
{
glDrawElements(GL_POINTS, verticesLowLowRes_.size(), GL_UNSIGNED_INT, verticesLowLowRes_.data());
} }
else if(distanceToCameraSqr>150.0f) else if(distanceToCameraSqr>150.0f)
{ {
glDrawElements(GL_POINTS, verticesLowRes_.size(), GL_UNSIGNED_INT, verticesLowRes_.data()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffers_[4]);
glDrawElements(GL_POINTS, index_buffers_count_[4], GL_UNSIGNED_INT, 0);
} }
else else
{ {
@@ -1106,6 +1226,7 @@ void PointCloudDrawable::Render(
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0); glUseProgram(0);
tango_gl::util::CheckGlError("Pointcloud::Render() cleaning"); tango_gl::util::CheckGlError("Pointcloud::Render() cleaning");
+6 -10
View File
@@ -70,8 +70,8 @@ private:
rtabmap::Transform getPose() const {return pose_;} rtabmap::Transform getPose() const {return pose_;}
const glm::mat4 & getPoseGl() const {return poseGl_;} const glm::mat4 & getPoseGl() const {return poseGl_;}
bool isVisible() const {return visible_;} bool isVisible() const {return visible_;}
bool hasMesh() const {return polygons_.size()!=0;} bool hasMesh() const {return index_buffers_[0] != 0;}
bool hasTexture() const {return textures_ != 0;} bool hasTexture() const {return texture_ != 0;}
float getMinHeight() const {return minHeight_;} float getMinHeight() const {return minHeight_;}
const pcl::PointXYZ & aabbMinModel() const {return aabbMinModel_;} const pcl::PointXYZ & aabbMinModel() const {return aabbMinModel_;}
const pcl::PointXYZ & aabbMaxModel() const {return aabbMaxModel_;} const pcl::PointXYZ & aabbMaxModel() const {return aabbMaxModel_;}
@@ -115,14 +115,10 @@ private:
private: private:
// Vertex buffer of the point cloud geometry. // Vertex buffer of the point cloud geometry.
GLuint vertex_buffers_; GLuint vertex_buffer_;
GLuint textures_; GLuint texture_;
std::vector<GLuint> polygons_; std::vector<GLuint> index_buffers_;
std::vector<GLuint> polygonsLowRes_; std::vector<int> index_buffers_count_;
std::vector<GLuint> polygonLines_;
std::vector<GLuint> polygonLinesLowRes_;
std::vector<GLuint> verticesLowRes_;
std::vector<GLuint> verticesLowLowRes_;
int nPoints_; int nPoints_;
rtabmap::Transform pose_; rtabmap::Transform pose_;
glm::mat4 poseGl_; glm::mat4 poseGl_;
+32 -32
View File
@@ -102,7 +102,7 @@ Scene::Scene() :
screenHeight_(0), screenHeight_(0),
doubleTapOn_(false) doubleTapOn_(false)
{ {
depthTextures_[0] = depthTextures_[1] = 0; depthTexture_ = 0;
gesture_camera_ = new tango_gl::GestureCamera(); gesture_camera_ = new tango_gl::GestureCamera();
gesture_camera_->SetCameraType( gesture_camera_->SetCameraType(
tango_gl::GestureCamera::kThirdPersonFollow); tango_gl::GestureCamera::kThirdPersonFollow);
@@ -179,8 +179,8 @@ void Scene::DeleteResources() {
fboId_ = 0; fboId_ = 0;
glDeleteRenderbuffers(1, &rboId_); glDeleteRenderbuffers(1, &rboId_);
rboId_ = 0; rboId_ = 0;
glDeleteTextures(2, depthTextures_); glDeleteTextures(1, &depthTexture_);
depthTextures_[0] = depthTextures_[1] = 0; depthTexture_ = 0;
} }
clear(); clear();
@@ -234,8 +234,8 @@ void Scene::SetupViewPort(int w, int h) {
fboId_ = 0; fboId_ = 0;
glDeleteRenderbuffers(1, &rboId_); glDeleteRenderbuffers(1, &rboId_);
rboId_ = 0; rboId_ = 0;
glDeleteTextures(2, depthTextures_); glDeleteTextures(1, &depthTexture_);
depthTextures_[0] = depthTextures_[1] = 0; depthTexture_ = 0;
} }
GLint originid = 0; GLint originid = 0;
@@ -247,8 +247,8 @@ void Scene::SetupViewPort(int w, int h) {
glBindFramebuffer(GL_FRAMEBUFFER, fboId_); glBindFramebuffer(GL_FRAMEBUFFER, fboId_);
// Create depth texture // Create depth texture
glGenTextures(2, depthTextures_); glGenTextures(1, &depthTexture_);
glBindTexture(GL_TEXTURE_2D, depthTextures_[0]); glBindTexture(GL_TEXTURE_2D, depthTexture_);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -256,21 +256,13 @@ void Scene::SetupViewPort(int w, int h) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, depthTextures_[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &rboId_); glGenRenderbuffers(1, &rboId_);
glBindRenderbuffer(GL_RENDERBUFFER, rboId_); glBindRenderbuffer(GL_RENDERBUFFER, rboId_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Set the texture to be at the color attachment point of the FBO (we pack depth 32 bits in color) // Set the texture to be at the color attachment point of the FBO (we pack depth 32 bits in color)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTextures_[0], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTexture_, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId_); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId_);
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -349,8 +341,9 @@ std::vector<glm::vec4> computeFrustumPlanes(const glm::mat4 & mat, bool normaliz
/** /**
* Tells whether or not b is intersecting f. * Tells whether or not b is intersecting f.
* http://www.txutxi.com/?p=584 * http://www.txutxi.com/?p=584
* @param f Viewing frustum. * @param planes Viewing frustum.
* @param b An axis aligned bounding box. * @param boxMin The axis aligned bounding box min.
* @param boxMax The axis aligned bounding box max.
* @return True if b intersects f, false otherwise. * @return True if b intersects f, false otherwise.
*/ */
bool intersectFrustumAABB( bool intersectFrustumAABB(
@@ -389,7 +382,8 @@ bool intersectFrustumAABB(
} }
//Should only be called in OpenGL thread! //Should only be called in OpenGL thread!
int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat4 arProjectionMatrix, const rtabmap::Mesh & occlusionMesh, bool mapping) { int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat4 arProjectionMatrix, const rtabmap::Mesh & occlusionMesh, bool mapping)
{
UASSERT(gesture_camera_ != 0); UASSERT(gesture_camera_ != 0);
if(currentPose_ == 0) if(currentPose_ == 0)
@@ -428,7 +422,7 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
if(renderBackgroundCamera) if(renderBackgroundCamera)
{ {
if(projectionMatrix[0][0] > arProjectionMatrix[0][0]-0.2) if(projectionMatrix[0][0] > arProjectionMatrix[0][0]-0.3)
{ {
projectionMatrix = arProjectionMatrix; projectionMatrix = arProjectionMatrix;
viewMatrix = arViewMatrix; viewMatrix = arViewMatrix;
@@ -486,9 +480,15 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
} }
UTimer timer; bool onlineBlending =
(!meshRendering_ &&
occlusionMesh.cloud.get() &&
occlusionMesh.cloud->size()) ||
(blending_ &&
gesture_camera_->GetCameraType()!=tango_gl::GestureCamera::kTopOrtho &&
mapRendering_ && meshRendering_ &&
(cloudsToDraw.size() > 1 || (renderBackgroundCamera && wireFrame_)));
bool onlineBlending = (!meshRendering_ && occlusionMesh.cloud.get() && occlusionMesh.cloud->size()) || (blending_ && gesture_camera_->GetCameraType()!=tango_gl::GestureCamera::kTopOrtho && mapRendering_ && meshRendering_);
if(onlineBlending && fboId_) if(onlineBlending && fboId_)
{ {
GLint originid = 0; GLint originid = 0;
@@ -499,7 +499,7 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
glClearColor(0, 0, 0, 0); glClearColor(0, 0, 0, 0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// Draw scene // Draw scene
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter) for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
{ {
@@ -511,16 +511,12 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
(*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, false, false, distanceToCameraSqr, 0, 0, 0, 0, 0, true); (*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, false, false, distanceToCameraSqr, 0, 0, 0, 0, 0, true);
} }
glBindTexture(GL_TEXTURE_2D, depthTextures_[1]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth_, screenHeight_);
glBindTexture(GL_TEXTURE_2D, 0);
if(!meshRendering_ && occlusionMesh.cloud.get() && occlusionMesh.cloud->size()) if(!meshRendering_ && occlusionMesh.cloud.get() && occlusionMesh.cloud->size())
{ {
PointCloudDrawable drawable(occlusionMesh); PointCloudDrawable drawable(occlusionMesh);
drawable.Render(projectionMatrix, viewMatrix, true, pointSize_, false, false, 0, 0, 0, 0, 0, 0, true); drawable.Render(projectionMatrix, viewMatrix, true, pointSize_, false, false, 0, 0, 0, 0, 0, 0, true);
} }
// back to normal window-system-provided framebuffer // back to normal window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, originid); // unbind glBindFramebuffer(GL_FRAMEBUFFER, originid); // unbind
} }
@@ -559,7 +555,7 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
glClearColor(r_, g_, b_, 1.0f); glClearColor(r_, g_, b_, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(renderBackgroundCamera && !onlineBlending) if(renderBackgroundCamera && (!onlineBlending || !meshRendering_))
{ {
background_renderer_->Draw(uvsTransformed, 0, screenWidth_, screenHeight_, false); background_renderer_->Draw(uvsTransformed, 0, screenWidth_, screenHeight_, false);
@@ -594,6 +590,10 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
{ {
trace_->Render(projectionMatrix, viewMatrix); trace_->Render(projectionMatrix, viewMatrix);
} }
else
{
trace_->ClearVertexArray();
}
} }
if(gridVisible_ && !renderBackgroundCamera) if(gridVisible_ && !renderBackgroundCamera)
@@ -629,14 +629,14 @@ int Scene::Render(const float * uvsTransformed, glm::mat4 arViewMatrix, glm::mat
cloud->getPose().z() - openglCamera.z()); cloud->getPose().z() - openglCamera.z());
float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2]; float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2];
cloud->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, meshRenderingTexture_, lighting_, distanceToCameraSqr, onlineBlending?depthTextures_[0]:0, screenWidth_, screenHeight_, gesture_camera_->getNearClipPlane(), gesture_camera_->getFarClipPlane(), false, wireFrame_); cloud->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, meshRenderingTexture_, lighting_, distanceToCameraSqr, onlineBlending?depthTexture_:0, screenWidth_, screenHeight_, gesture_camera_->getNearClipPlane(), gesture_camera_->getFarClipPlane(), false, wireFrame_);
} }
if(onlineBlending) if(onlineBlending)
{ {
if(renderBackgroundCamera) if(renderBackgroundCamera && meshRendering_)
{ {
background_renderer_->Draw(uvsTransformed, depthTextures_[1], screenWidth_, screenHeight_, meshRendering_?mapping:false); background_renderer_->Draw(uvsTransformed, depthTexture_, screenWidth_, screenHeight_, mapping);
} }
glDisable (GL_BLEND); glDisable (GL_BLEND);
+1 -1
View File
@@ -208,7 +208,7 @@ class Scene {
float b_; float b_;
GLuint fboId_; GLuint fboId_;
GLuint rboId_; GLuint rboId_;
GLuint depthTextures_[2]; // 0=objects+occlusion 1=objects only GLuint depthTexture_; // 0=objects+occlusion
GLsizei screenWidth_; GLsizei screenWidth_;
GLsizei screenHeight_; GLsizei screenHeight_;
bool doubleTapOn_; bool doubleTapOn_;
+1 -1
View File
@@ -183,7 +183,7 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
case kFirstPerson: case kFirstPerson:
SetOrthoMode(false); SetOrthoMode(false);
SetFieldOfView(kLowestFov); SetFieldOfView(kLowestFov);
SetNearFarClipPlanes(0.1, 50); SetNearFarClipPlanes(0.25, 25);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f)); SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)); SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
cam_cur_dist_ = 0.0f; cam_cur_dist_ = 0.0f;
+5 -3
View File
@@ -19,7 +19,7 @@
<string name="light_off">Lighting</string> <string name="light_off">Lighting</string>
<string name="wireframe">Wireframe</string> <string name="wireframe">Wireframe</string>
<string name="close_visualization">Close Visualization</string> <string name="close_visualization">Close Visualization</string>
<string name="save_to_file">Export to File&#8230;</string> <string name="save_to_file">Export OBJ/PLY&#8230;</string>
<string name="share_to_sketchfab">Share to Sketchfab&#8230;</string> <string name="share_to_sketchfab">Share to Sketchfab&#8230;</string>
<string name="start">Start</string> <string name="start">Start</string>
<string name="nodes">"Nodes (WM): "</string> <string name="nodes">"Nodes (WM): "</string>
@@ -80,7 +80,7 @@
<string name="pref_default_fisheye">false</string> <string name="pref_default_fisheye">false</string>
<string name="pref_key_camera_driver">pref_key_camera_driver</string> <string name="pref_key_camera_driver">pref_key_camera_driver</string>
<string name="pref_default_camera_driver">0</string> <string name="pref_default_camera_driver">-1</string>
<string name="pref_key_depth_from_motion">pref_key_depth_from_motion</string> <string name="pref_key_depth_from_motion">pref_key_depth_from_motion</string>
<string name="pref_default_depth_from_motion">false</string> <string name="pref_default_depth_from_motion">false</string>
<string name="pref_key_arcore_localization_filtering_speed">pref_key_arcore_localization_filtering_speed</string> <string name="pref_key_arcore_localization_filtering_speed">pref_key_arcore_localization_filtering_speed</string>
@@ -108,7 +108,7 @@
<string name="pref_key_features_type">pref_key_features_type</string> <string name="pref_key_features_type">pref_key_features_type</string>
<string name="pref_default_features_type">6</string> <string name="pref_default_features_type">6</string>
<string name="pref_key_optimizer">pref_key_optimizer</string> <string name="pref_key_optimizer">pref_key_optimizer</string>
<string name="pref_default_optimizer">1</string> <string name="pref_default_optimizer">2</string>
<string name="pref_key_optimize_end">pref_key_optimize_end</string> <string name="pref_key_optimize_end">pref_key_optimize_end</string>
<string name="pref_default_optimize_end">true</string> <string name="pref_default_optimize_end">true</string>
<string name="pref_key_marker_detection">pref_key_marker_detection</string> <string name="pref_key_marker_detection">pref_key_marker_detection</string>
@@ -381,12 +381,14 @@
<string name="pref_summary_db_in_memory">The database is kept in RAM for fast access. Set to false to reduce RAM used at the cost of slower access. This parameter is applied on reset or when a database is opened.</string> <string name="pref_summary_db_in_memory">The database is kept in RAM for fast access. Set to false to reduce RAM used at the cost of slower access. This parameter is applied on reset or when a database is opened.</string>
<string-array name="pref_camera_driver_keys"> <string-array name="pref_camera_driver_keys">
<item>"Auto"</item>
<item>"Google Tango NDK"</item> <item>"Google Tango NDK"</item>
<item>"ARCore NDK"</item> <item>"ARCore NDK"</item>
<item>"AREngine NDK"</item> <item>"AREngine NDK"</item>
<item>"ARCore Java"</item> <item>"ARCore Java"</item>
</string-array> </string-array>
<string-array name="pref_camera_driver_values"> <string-array name="pref_camera_driver_values">
<item>"-1"</item>
<item>"0"</item> <item>"0"</item>
<item>"1"</item> <item>"1"</item>
<item>"2"</item> <item>"2"</item>
@@ -688,7 +688,7 @@ public class ARCoreSharedCamera {
if(mToast!=null && previousAnchorPose != null) if(mToast!=null && previousAnchorPose != null)
{ {
String msg = "Tracking lost! If you are mapping, you will need to relocalize before continuing."; String msg = "Tracking lost! If you are mapping, you will need to relocalize before continuing.";
if(!mToast.getView().isShown()) if(mToast.getView() == null || !mToast.getView().isShown())
{ {
mToast.makeText(mActivity.getApplicationContext(), mToast.makeText(mActivity.getApplicationContext(),
msg, Toast.LENGTH_LONG).show(); msg, Toast.LENGTH_LONG).show();
@@ -736,7 +736,7 @@ public class ARCoreSharedCamera {
+ "because of high speed detected (%f m/s) causing a jump! You can change " + "because of high speed detected (%f m/s) causing a jump! You can change "
+ "ARCore localization filtering speed in Settings->Mapping if you are " + "ARCore localization filtering speed in Settings->Mapping if you are "
+ "indeed moving as fast.", speed); + "indeed moving as fast.", speed);
if(!mToast.getView().isShown()) if(mToast.getView() == null || !mToast.getView().isShown())
{ {
mToast.makeText(mActivity.getApplicationContext(), msg, Toast.LENGTH_LONG).show(); mToast.makeText(mActivity.getApplicationContext(), msg, Toast.LENGTH_LONG).show();
} }
@@ -2,6 +2,7 @@ package com.introlab.rtabmap;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -25,6 +26,8 @@ import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener; import android.content.DialogInterface.OnShowListener;
@@ -35,6 +38,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.hardware.Camera; import android.hardware.Camera;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
@@ -46,6 +50,7 @@ import android.hardware.display.DisplayManager;
import android.location.Location; import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.media.MediaScannerConnection;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@@ -56,6 +61,8 @@ import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.content.FileProvider; import android.support.v4.content.FileProvider;
import android.text.InputType; import android.text.InputType;
@@ -256,6 +263,8 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
ARCoreSharedCamera mArCoreCamera = null; ARCoreSharedCamera mArCoreCamera = null;
int mCameraDriver = 0; int mCameraDriver = 0;
private String mIntentDbToOpen = null;
//Tango Service connection. //Tango Service connection.
boolean mCameraServiceConnectionUsed = false; boolean mCameraServiceConnectionUsed = false;
@@ -294,7 +303,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
} }
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
// Handle this if you need to gracefully shutdown/retry // Handle this if you need to gracefully shutsaveDatabasedown/retry
// in the event that Tango itself crashes/gets upgraded while running. // in the event that Tango itself crashes/gets upgraded while running.
mToast.makeText(getApplicationContext(), mToast.makeText(getApplicationContext(),
String.format("Tango disconnected!"), mToast.LENGTH_LONG).show(); String.format("Tango disconnected!"), mToast.LENGTH_LONG).show();
@@ -494,10 +503,11 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
mWorkingDirectoryHuman = ""; mWorkingDirectoryHuman = "";
mTotalLoopClosures = 0; mTotalLoopClosures = 0;
mLastFastMovementNotificationStamp = System.currentTimeMillis()/1000; mLastFastMovementNotificationStamp = System.currentTimeMillis()/1000;
if(Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED)==0) if(Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED)==0 &&
getActivity().getExternalFilesDirs(null).length >=1)
{ {
File extStore = Environment.getExternalStorageDirectory(); File extStore = getActivity().getExternalFilesDirs(null)[0];
mWorkingDirectory = extStore.getAbsolutePath() + "/" + getString(R.string.app_name) + "/"; mWorkingDirectory = extStore.getAbsolutePath() + "/" + getString(R.string.app_name) + "/";
extStore = new File(mWorkingDirectory); extStore = new File(mWorkingDirectory);
extStore.mkdirs(); extStore.mkdirs();
@@ -507,7 +517,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
{ {
// show warning that data cannot be saved! // show warning that data cannot be saved!
mToast.makeText(getApplicationContext(), mToast.makeText(getApplicationContext(),
String.format("Failed to get external storage path (SD-CARD, state=%s). Saving disabled.", String.format("Failed to get external storage path (state=%s). Saving disabled.",
Environment.getExternalStorageState()), mToast.LENGTH_LONG).show(); Environment.getExternalStorageState()), mToast.LENGTH_LONG).show();
} }
@@ -574,33 +584,141 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
DISABLE_LOG = !( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) ); DISABLE_LOG = !( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
if (!PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
PermissionHelper.requestPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
else
{
postCreate();
}
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver)); String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver));
mCameraDriver = Integer.parseInt(cameraDriverStr); mCameraDriver = Integer.parseInt(cameraDriverStr);
isArCoreAvailable(); isArCoreAvailable();
isArEngineAvailable(); isArEngineAvailable();
if (!PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
PermissionHelper.requestPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
else
{
// Get intent, action and MIME type
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("application/octet-stream".equals(type)) {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (imageUri != null) {
String fileName = getFileName(imageUri);
Log.i(TAG, "Intent received: " + imageUri.getPath() + " Name:" + fileName);
if(fileName.endsWith(".db"))
{
File file = new File(mWorkingDirectory+fileName);
if(file.exists())
{
mToast.makeText(this, fileName + " already exists in RTAB-Map's library! Cannot be copied.", mToast.LENGTH_LONG).show();
}
else
{
copy(imageUri, file);
mIntentDbToOpen = fileName;
}
}
}
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
if (type.startsWith("application/")) {
ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (imageUris != null) {
boolean added = false;
for(Uri imageUri: imageUris)
{
String fileName = getFileName(imageUri);
Log.i(TAG, "Intent received: " + imageUri.getPath() + " Name:" + fileName);
if(fileName.endsWith(".db"))
{
File file = new File(mWorkingDirectory+"/"+getFileName(imageUri));
if(!file.exists())
{
copy(imageUri, file);
added = true;
}
else
{
Log.e(TAG, fileName + " already exists in RTAB-Map's library! Cannot be copied.");
}
}
}
if(added)
{
openDatabase();
}
}
}
}
postCreate();
}
} }
public void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
public void copy(Uri uri, File file)
{
InputStream in;
try {
in = getApplicationContext().getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
public String getFileName(Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
// Should be called only if read/write permissions are granted! // Should be called only if read/write permissions are granted!
private void postCreate() private void postCreate()
{ {
Log.i(TAG, "postCreate()"); Log.i(TAG, "postCreate()");
String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB;
(new File(tmpDatabase)).delete();
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false);
final String[] files = Util.loadFileList(mWorkingDirectory, true); final String[] files = Util.loadFileList(mWorkingDirectory, true);
if(files.length == 0) if(files.length == 0)
{ {
@@ -613,6 +731,17 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
Log.i(TAG, String.format("updateCameraDriverSettings() mCameraDriver=%d RTABMapLib.isBuiltWith(%d)=%d", mCameraDriver, mCameraDriver, RTABMapLib.isBuiltWith(nativeApplication, mCameraDriver)?1:0)); Log.i(TAG, String.format("updateCameraDriverSettings() mCameraDriver=%d RTABMapLib.isBuiltWith(%d)=%d", mCameraDriver, mCameraDriver, RTABMapLib.isBuiltWith(nativeApplication, mCameraDriver)?1:0));
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver));
mCameraDriver = Integer.parseInt(cameraDriverStr);
if(mCameraDriver == -1)
{
// Prioritize tango if available
mCameraDriver = 0;
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.pref_key_camera_driver), "0");
editor.commit();
}
if(mCameraDriver == 0 && (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION) || !RTABMapLib.isBuiltWith(nativeApplication, 0))) if(mCameraDriver == 0 && (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION) || !RTABMapLib.isBuiltWith(nativeApplication, 0)))
{ {
@@ -1167,7 +1296,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
final boolean depthFromMotion = sharedPref.getBoolean(getString(R.string.pref_key_depth_from_motion), Boolean.parseBoolean(getString(R.string.pref_default_depth_from_motion))); final boolean depthFromMotion = sharedPref.getBoolean(getString(R.string.pref_key_depth_from_motion), Boolean.parseBoolean(getString(R.string.pref_default_depth_from_motion)));
mCameraDriver = Integer.parseInt(cameraDriverStr); mCameraDriver = Integer.parseInt(cameraDriverStr);
if(!DISABLE_LOG) Log.i(TAG, String.format("startCamera() driver=%d", mCameraDriver)); Log.i(TAG, String.format("startCamera() driver=%d", mCameraDriver));
if(mCameraDriver == 0) // Tango if(mCameraDriver == 0) // Tango
{ {
// Check if the Tango Core is out dated. // Check if the Tango Core is out dated.
@@ -1490,7 +1619,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
} }
updateState(mState); updateState(mState);
return true; return true;
} }
@@ -1992,6 +2121,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
final int loopDetected = RTABMapLib.postProcessing(nativeApplication, -1); final int loopDetected = RTABMapLib.postProcessing(nativeApplication, -1);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
updateState(State.STATE_IDLE);
if(mExportProgressDialog.isShowing()) if(mExportProgressDialog.isShowing())
{ {
mExportProgressDialog.dismiss(); mExportProgressDialog.dismiss();
@@ -2024,8 +2154,6 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
mProgressDialog.dismiss(); mProgressDialog.dismiss();
mToast.makeText(getActivity(), String.format("Optimization canceled"), mToast.LENGTH_LONG).show(); mToast.makeText(getActivity(), String.format("Optimization canceled"), mToast.LENGTH_LONG).show();
} }
updateState(State.STATE_IDLE);
} }
}); });
} }
@@ -2144,7 +2272,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
mButtonCloseVisualization.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE); mButtonCloseVisualization.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE);
mButtonCloseVisualization.setEnabled(true); mButtonCloseVisualization.setEnabled(true);
mButtonSaveOnDevice.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE); mButtonSaveOnDevice.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE);
mButtonShareOnSketchfab.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE); //mButtonShareOnSketchfab.setVisibility(mHudVisible && mState != State.STATE_VISUALIZING_CAMERA?View.VISIBLE:View.INVISIBLE);
mButtonLibrary.setVisibility(View.INVISIBLE); mButtonLibrary.setVisibility(View.INVISIBLE);
mButtonNewScan.setVisibility(View.INVISIBLE); mButtonNewScan.setVisibility(View.INVISIBLE);
mItemSave.setEnabled(mState != State.STATE_VISUALIZING_CAMERA); mItemSave.setEnabled(mState != State.STATE_VISUALIZING_CAMERA);
@@ -2217,6 +2345,12 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
{ {
mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
} }
if(mState == State.STATE_WELCOME && mIntentDbToOpen != null)
{
openDatabase(mIntentDbToOpen, false);
mIntentDbToOpen = null;
}
} }
private void startMapping() { private void startMapping() {
@@ -2626,7 +2760,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity()); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory))); boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB; String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB;
RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false); RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false, true);
mItemLocalizationMode.setEnabled(!mItemDataRecorderMode.isChecked()); mItemLocalizationMode.setEnabled(!mItemDataRecorderMode.isChecked());
@@ -2780,16 +2914,110 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
mOpenedDatabasePath = ""; mOpenedDatabasePath = "";
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory))); boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB; final String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB;
RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false);
File newFile = new File(tmpDatabase);
if(!(mState == State.STATE_CAMERA || mState ==State.STATE_MAPPING)) final int fileSizeMB = (int)newFile.length()/(1024 * 1024);
if(!(mState == State.STATE_CAMERA || mState ==State.STATE_MAPPING) &&
newFile.exists() &&
fileSizeMB>1) // >1MB
{ {
setCamera(1); AlertDialog d2 = new AlertDialog.Builder(getActivity())
startCamera(String.format("Hold Tight! Initializing Camera Service...\n" .setCancelable(false)
+ "Tip: If the camera is still drifting just after the mapping has started, do \"Reset\".")); .setTitle("Recovery")
.setMessage(String.format("The previous session (%d MB) was not correctly saved, do you want to recover it?", fileSizeMB))
.setNegativeButton("Ignore", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
(new File(tmpDatabase)).delete();
newScan();
}
})
.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
final String fileName = new SimpleDateFormat("yyMMdd-HHmmss").format(new Date()) + ".db";
final String outputDbPath = mWorkingDirectory + fileName;
mExportProgressDialog.setTitle("Recovering");
mExportProgressDialog.setMessage(String.format("Please wait while recovering data..."));
mExportProgressDialog.setProgress(0);
final State previousState = mState;
mExportProgressDialog.show();
updateState(State.STATE_PROCESSING);
Thread exportThread = new Thread(new Runnable() {
public void run() {
final long startTime = System.currentTimeMillis()/1000;
final boolean success = RTABMapLib.recover(
nativeApplication,
tmpDatabase,
outputDbPath);
runOnUiThread(new Runnable() {
public void run() {
if(mExportProgressDialog.isShowing())
{
if(success)
{
AlertDialog d2 = new AlertDialog.Builder(getActivity())
.setCancelable(false)
.setTitle("Database saved!")
.setMessage(String.format("Database \"%s\" (%d MB) successfully saved!", fileName, fileSizeMB))
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
openDatabase(fileName, false);
}
})
.create();
d2.setCanceledOnTouchOutside(true);
d2.show();
}
else
{
updateState(previousState);
mToast.makeText(getActivity(), String.format("Recovery failed!"), mToast.LENGTH_LONG).show();
}
mExportProgressDialog.dismiss();
}
else
{
mToast.makeText(getActivity(), String.format("Recovery canceled"), mToast.LENGTH_LONG).show();
updateState(previousState);
}
}
});
}
});
exportThread.start();
refreshSystemMediaScanDataBase(getActivity(), outputDbPath);
}
})
.create();
d2.setCanceledOnTouchOutside(false);
d2.show();
}
else
{
RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false, true);
if(!(mState == State.STATE_CAMERA || mState ==State.STATE_MAPPING))
{
setCamera(0);
startCamera(String.format("Hold Tight! Initializing Camera Service...\n"
+ "Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
}
} }
} }
private void openDatabase() private void openDatabase()
{ {
@@ -3215,7 +3443,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
context.sendBroadcast(mediaScanIntent); context.sendBroadcast(mediaScanIntent);
} }
private void saveDatabase(String fileName) private void saveDatabase(final String fileName)
{ {
final String newDatabasePath = mWorkingDirectory + fileName + ".db"; final String newDatabasePath = mWorkingDirectory + fileName + ".db";
final String newDatabasePathHuman = mWorkingDirectoryHuman + fileName + ".db"; final String newDatabasePathHuman = mWorkingDirectoryHuman + fileName + ".db";
@@ -3247,7 +3475,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
mSavedStamp = System.currentTimeMillis(); mSavedStamp = System.currentTimeMillis();
msg = String.format("Database saved to \"%s\".", newDatabasePathHuman); msg = String.format("Database saved to \"%s\".", newDatabasePathHuman);
} }
// build notification // build notification
Intent intent = new Intent(getActivity(), RTABMapActivity.class); Intent intent = new Intent(getActivity(), RTABMapActivity.class);
// use System.currentTimeMillis() to have a unique ID for the pending intent // use System.currentTimeMillis() to have a unique ID for the pending intent
@@ -3280,7 +3508,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
AlertDialog d2 = new AlertDialog.Builder(getActivity()) AlertDialog d2 = new AlertDialog.Builder(getActivity())
.setCancelable(false) .setCancelable(false)
.setTitle("Database saved!") .setTitle("Database saved!")
.setMessage(String.format("Database \"%s\" (%d MB) successfully saved on the SD-CARD!", newDatabasePathHuman, fileSizeMB)) .setMessage(String.format("Database \"%s\" (%d MB) successfully saved!", newDatabasePathHuman, fileSizeMB))
.setPositiveButton("OK", new DialogInterface.OnClickListener() { .setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
resetNoTouchTimer(true); resetNoTouchTimer(true);
@@ -3334,30 +3562,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
dialog.dismiss(); dialog.dismiss();
if(!fileName.isEmpty()) if(!fileName.isEmpty())
{ {
File newFile = new File(mWorkingDirectory + RTABMAP_EXPORT_DIR + fileName + ".zip"); writeExportedFiles(fileName);
if(newFile.exists())
{
AlertDialog ad = new AlertDialog.Builder(getActivity())
.setCancelable(false)
.setTitle("File Already Exists")
.setMessage("Do you want to overwrite the existing file?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
writeExportedFiles(fileName);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
saveOnDevice();
}
}).create();
ad.setCanceledOnTouchOutside(false);
ad.show();
}
else
{
writeExportedFiles(fileName);
}
} }
} }
}); });
@@ -3371,7 +3576,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
{ {
Log.i(TAG, String.format("Write exported mesh to \"%s\"", fileName)); Log.i(TAG, String.format("Write exported mesh to \"%s\"", fileName));
mProgressDialog.setTitle("Saving to sd-card"); mProgressDialog.setTitle("Exporting");
mProgressDialog.setMessage(String.format("Compressing the files...")); mProgressDialog.setMessage(String.format("Compressing the files..."));
mProgressDialog.show(); mProgressDialog.show();
@@ -3397,8 +3602,23 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
} }
File exportDir = new File(mWorkingDirectory + RTABMAP_EXPORT_DIR); File exportDir = new File(mWorkingDirectory + RTABMAP_EXPORT_DIR);
exportDir.mkdirs(); exportDir.mkdirs();
// cleanup old zip
fileNames = Util.loadFileList(mWorkingDirectory + RTABMAP_EXPORT_DIR, false);
if(!DISABLE_LOG) Log.i(TAG, String.format("Deleting %d files in \"%s\"", fileNames.length, mWorkingDirectory + RTABMAP_EXPORT_DIR));
for(int i=0; i<fileNames.length; ++i)
{
File f = new File(mWorkingDirectory + RTABMAP_EXPORT_DIR + "/" + fileNames[i]);
if(f.delete())
{
if(!DISABLE_LOG) Log.i(TAG, String.format("Deleted \"%s\"", f.getPath()));
}
else
{
if(!DISABLE_LOG) Log.i(TAG, String.format("Failed deleting \"%s\"", f.getPath()));
}
}
final String pathHuman = mWorkingDirectoryHuman + RTABMAP_EXPORT_DIR + fileName + ".zip";
final String zipOutput = mWorkingDirectory+RTABMAP_EXPORT_DIR+fileName+".zip"; final String zipOutput = mWorkingDirectory+RTABMAP_EXPORT_DIR+fileName+".zip";
if(RTABMapLib.writeExportedMesh(nativeApplication, mWorkingDirectory + RTABMAP_TMP_DIR, RTABMAP_TMP_FILENAME)) if(RTABMapLib.writeExportedMesh(nativeApplication, mWorkingDirectory + RTABMAP_TMP_DIR, RTABMAP_TMP_FILENAME))
{ {
@@ -3424,7 +3644,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
final String msg = e.getMessage(); final String msg = e.getMessage();
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! Error=%s", pathHuman, msg), mToast.LENGTH_LONG).show(); mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! Error=%s", fileName, msg), mToast.LENGTH_LONG).show();
} }
}); });
} }
@@ -3440,29 +3660,41 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
final File f = new File(zipOutput); final File f = new File(zipOutput);
final int fileSizeMB = (int)f.length()/(1024 * 1024); final int fileSizeMB = (int)f.length()/(1024 * 1024);
AlertDialog d = new AlertDialog.Builder(getActivity()) // Save to public Documents/RTAB-Map folder
.setCancelable(false) /*ContentValues values = new ContentValues();
.setTitle("Mesh Saved!") values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); //file name
.setMessage(String.format("Mesh \"%s\" (%d MB) successfully exported on the SD-CARD! Share it?", pathHuman, fileSizeMB)) values.put(MediaStore.MediaColumns.MIME_TYPE, "application/zip"); //file extension, will automatically add to file
.setPositiveButton("Yes", new DialogInterface.OnClickListener() { values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS + "/RTAB-Map"); //end "/" is not mandatory
public void onClick(DialogInterface dialog, int which) { Uri uri = getContentResolver().insert(MediaStore.Files.getContentUri("external"),values);
// Send to... if (uri != null) {
Intent shareIntent = new Intent(); OutputStream out;
shareIntent.setAction(Intent.ACTION_SEND); try {
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f)); out = getApplicationContext().getContentResolver().openOutputStream(uri);
shareIntent.setType("application/zip");
startActivity(Intent.createChooser(shareIntent, "Sharing...")); InputStream in = new FileInputStream(zipOutput);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
f.delete(); // remove private file
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
} */
resetNoTouchTimer(true); // Send to...
} Intent shareIntent = new Intent();
}) shareIntent.setAction(Intent.ACTION_SEND);
.setNegativeButton("No", new DialogInterface.OnClickListener() { shareIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", f));
public void onClick(DialogInterface dialog, int which) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
resetNoTouchTimer(true); shareIntent.setType("application/zip");
} startActivity(Intent.createChooser(shareIntent, "Sharing..."));
}).create();
d.setCanceledOnTouchOutside(false); resetNoTouchTimer(true);
d.show();
} }
}); });
} }
@@ -3471,7 +3703,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
mProgressDialog.dismiss(); mProgressDialog.dismiss();
mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled.", pathHuman), mToast.LENGTH_LONG).show(); mToast.makeText(getActivity(), String.format("Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled.", fileName), mToast.LENGTH_LONG).show();
resetNoTouchTimer(true); resetNoTouchTimer(true);
} }
}); });
@@ -3498,8 +3730,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
Thread openThread = new Thread(new Runnable() { Thread openThread = new Thread(new Runnable() {
public void run() { public void run() {
final String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB; final int status = RTABMapLib.openDatabase(nativeApplication, mOpenedDatabasePath, databaseInMemory, optimize, false);
final int status = RTABMapLib.openDatabase2(nativeApplication, mOpenedDatabasePath, tmpDatabase, databaseInMemory, optimize);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
@@ -3578,20 +3809,6 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
openThread.start(); openThread.start();
} }
public void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
private void shareToSketchfab() private void shareToSketchfab()
{ {
if (!PermissionHelper.hasPermission(this, Manifest.permission.INTERNET)) { if (!PermissionHelper.hasPermission(this, Manifest.permission.INTERNET)) {
@@ -34,9 +34,10 @@ public class RTABMapLib
public static native void setScreenRotation(long nativeApplication, int displayRotation, int cameraRotation); public static native void setScreenRotation(long nativeApplication, int displayRotation, int cameraRotation);
public static native int openDatabase(long nativeApplication, String databasePath, boolean databaseInMemory, boolean optimize); public static native int openDatabase(long nativeApplication, String databasePath, boolean databaseInMemory, boolean optimize, boolean clearDatabase);
public static native int openDatabase2(long nativeApplication, String databaseSource, String databasePath, boolean databaseInMemory, boolean optimize);
public static native boolean recover(long nativeApplication, String from, String to);
public static native boolean isBuiltWith(long nativeApplication, int cameraDriver); public static native boolean isBuiltWith(long nativeApplication, int cameraDriver);
public static native boolean startCamera(long nativeApplication, IBinder binder, Context context, Activity activity, int driver); public static native boolean startCamera(long nativeApplication, IBinder binder, Context context, Activity activity, int driver);
public static native void stopCamera(long nativeApplication); public static native void stopCamera(long nativeApplication);
+5 -4
View File
@@ -979,9 +979,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_USE_OPTIMIZATION_PROFILE = NO;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 13;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 3RRB6NV8U9; DEVELOPMENT_TEAM = 3RRB6NV8U9;
EXCLUDED_ARCHS = ""; EXCLUDED_ARCHS = "";
@@ -1006,7 +1007,7 @@
"$(PROJECT_DIR)/RTABMapApp/Libraries/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/lib",
"$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib",
); );
MARKETING_VERSION = 0.20.12; MARKETING_VERSION = 0.20.17;
OTHER_CFLAGS = ""; OTHER_CFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap; PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1038,7 +1039,7 @@
CLANG_USE_OPTIMIZATION_PROFILE = NO; CLANG_USE_OPTIMIZATION_PROFILE = NO;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 13;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 3RRB6NV8U9; DEVELOPMENT_TEAM = 3RRB6NV8U9;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1063,7 +1064,7 @@
"$(PROJECT_DIR)/RTABMapApp/Libraries/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/lib",
"$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib",
); );
MARKETING_VERSION = 0.20.12; MARKETING_VERSION = 0.20.17;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = ""; OTHER_CFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap; PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap;
@@ -39,6 +39,7 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
enableGPUFrameCaptureMode = "2"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="zah-iI-EPt"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="zah-iI-EPt">
<device id="retina3_5" orientation="portrait" appearance="light"/> <device id="retina3_5" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<capability name="Image references" minToolsVersion="12.0"/> <capability name="Image references" minToolsVersion="12.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
+13 -5
View File
@@ -55,9 +55,11 @@ cd $pwd
# FLANN # FLANN
echo "wget flann..." echo "wget flann..."
curl -L http://www.cs.ubc.ca/research/flann/uploads/FLANN/flann-1.8.4-src.zip -o flann-1.8.4-src.zip git clone https://github.com/flann-lib/flann.git
unzip -qq flann-1.8.4-src.zip cd flann
cd flann-1.8.4-src git checkout 1.8.4
curl -L https://gist.githubusercontent.com/matlabbe/c858ba36fb85d5e44d8667dfb3543e12/raw/8fc40aa9bc3267604869444020476a49f14ab424/flann_ios.patch -o flann_ios.patch
git apply flann_ios.patch
mkdir build mkdir build
cd build cd build
# comment "add_subdirectory( test )" in top CMakeLists.txt # comment "add_subdirectory( test )" in top CMakeLists.txt
@@ -66,7 +68,7 @@ cmake -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_O
cmake --build . --config Release -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO" cmake --build . --config Release -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO"
cmake --build . --config Release --target install -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO" cmake --build . --config Release --target install -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO"
cd $pwd cd $pwd
#rm -r flann-1.8.4-src.zip flann-1.8.4-src #rm -r flann
# GTSAM # GTSAM
git clone https://bitbucket.org/gtborg/gtsam.git git clone https://bitbucket.org/gtborg/gtsam.git
@@ -134,6 +136,8 @@ cd $pwd
git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv.git
cd opencv cd opencv
git checkout tags/3.4.2 git checkout tags/3.4.2
curl -L https://gist.githubusercontent.com/matlabbe/fdc3ab4854f3a68fbde7277f543b4e5b/raw/f340839c09165056d3845645df24b76507542fd2/opencv_ios.patch -o opencv_ios.patch
git apply opencv_ios.patch
mkdir build mkdir build
cd build cd build
# add "add_definitions(-DPNG_ARM_NEON_OPT=0)" in 3rdparty/libpng/CMakeLists.txt # add "add_definitions(-DPNG_ARM_NEON_OPT=0)" in 3rdparty/libpng/CMakeLists.txt
@@ -145,6 +149,10 @@ cd $pwd
mkdir rtabmap mkdir rtabmap
cd rtabmap cd rtabmap
cmake -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_SYSROOT=$sysroot -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DCMAKE_C_FLAGS=-fembed-bitcode -DCMAKE_CXX_FLAGS=-fembed-bitcode -DCMAKE_INSTALL_PREFIX=$prefix -DCMAKE_FIND_ROOT_PATH=$prefix -DWITH_QT=OFF -DBUILD_APP=OFF -DBUILD_TOOLS=OFF -DWITH_TORO=OFF -DWITH_VERTIGO=OFF -DWITH_MADGWICK=OFF -DWITH_ORB_OCTREE=OFF -DBUILD_EXAMPLES=OFF ../../../../.. cmake -DANDROID_PREBUILD=ON ../../../../..
cmake --build . --config Release
mkdir ios
cd ios
cmake -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_SYSROOT=$sysroot -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DCMAKE_C_FLAGS=-fembed-bitcode -DCMAKE_CXX_FLAGS=-fembed-bitcode -DCMAKE_INSTALL_PREFIX=$prefix -DCMAKE_FIND_ROOT_PATH=$prefix -DWITH_QT=OFF -DBUILD_APP=OFF -DBUILD_TOOLS=OFF -DWITH_TORO=OFF -DWITH_VERTIGO=OFF -DWITH_MADGWICK=OFF -DWITH_ORB_OCTREE=OFF -DBUILD_EXAMPLES=OFF ../../../../../..
cmake --build . --config Release cmake --build . --config Release
cmake --build . --config Release --target install cmake --build . --config Release --target install
+27 -15
View File
@@ -69,24 +69,11 @@ void setScreenRotationNative(const void *object, int displayRotation)
} }
} }
int openDatabaseNative(const void *object, const char * databasePath, bool databaseInMemory, bool optimize) int openDatabaseNative(const void *object, const char * databasePath, bool databaseInMemory, bool optimize, bool clearDatabase)
{ {
if(object) if(object)
{ {
return native(object)->openDatabase(databasePath, databaseInMemory, optimize); return native(object)->openDatabase(databasePath, databaseInMemory, optimize, clearDatabase);
}
else
{
UERROR("object is null!");
return -1;
}
}
int openDatabase2Native(const void *object, const char * databaseSource, const char * databasePath, bool databaseInMemory, bool optimize)
{
if(object)
{
return native(object)->openDatabase(databasePath, databaseInMemory, optimize, databaseSource);
} }
else else
{ {
@@ -107,6 +94,31 @@ void saveNative(const void *object, const char * databasePath)
} }
} }
bool recoverNative(const void *object, const char * from, const char * to)
{
if(object)
{
return native(object)->recover(from, to);
}
else
{
UERROR("object is null!");
}
return false;
}
void cancelProcessingNative(const void *object)
{
if(object)
{
native(object)->cancelProcessing();
}
else
{
UERROR("object is null!");
}
}
int postProcessingNative(const void *object, int approach) int postProcessingNative(const void *object, int approach)
{ {
if(object) if(object)
+3 -2
View File
@@ -32,9 +32,10 @@ void setupCallbacksNative(const void *object, void * classPtr,
float, float, float, float, float, float)); float, float, float, float, float, float));
void destroyNativeApplication(const void *object); void destroyNativeApplication(const void *object);
void setScreenRotationNative(const void *object, int displayRotation); void setScreenRotationNative(const void *object, int displayRotation);
int openDatabaseNative(const void *object, const char * databasePath, bool databaseInMemory, bool optimize); int openDatabaseNative(const void *object, const char * databasePath, bool databaseInMemory, bool optimize, bool clearDatabase);
int openDatabase2Native(const void *object, const char * databaseSource, const char * databasePath, bool databaseInMemory, bool optimize);
void saveNative(const void *object, const char * databasePath); void saveNative(const void *object, const char * databasePath);
bool recoverNative(const void *object, const char * from, const char * to);
void cancelProcessingNative(const void * object);
int postProcessingNative(const void *object, int approach); int postProcessingNative(const void *object, int approach);
bool exportMeshNative( bool exportMeshNative(
const void *object, const void *object,
+15 -11
View File
@@ -113,17 +113,9 @@ class RTABMap {
setupGraphicNative(native_rtabmap, Int32(size.width), Int32(size.height)); setupGraphicNative(native_rtabmap, Int32(size.width), Int32(size.height));
} }
func openDatabase(databasePath:String, databaseInMemory:Bool, optimize:Bool) -> Int { func openDatabase(databasePath:String, databaseInMemory:Bool, optimize:Bool, clearDatabase: Bool) -> Int {
databasePath.utf8CString.withUnsafeBufferPointer { buffer -> Int in databasePath.utf8CString.withUnsafeBufferPointer { buffer -> Int in
return Int(openDatabaseNative(native_rtabmap, buffer.baseAddress, databaseInMemory, optimize)) return Int(openDatabaseNative(native_rtabmap, buffer.baseAddress, databaseInMemory, optimize, clearDatabase))
}
}
func openDatabase(databaseSource:String, databasePath:String, databaseInMemory:Bool, optimize:Bool) -> Int {
databasePath.utf8CString.withUnsafeBufferPointer { buffer -> Int in
databaseSource.utf8CString.withUnsafeBufferPointer { bufferSource -> Int in
return Int(openDatabase2Native(native_rtabmap, bufferSource.baseAddress, buffer.baseAddress, databaseInMemory, optimize))
}
} }
} }
@@ -133,6 +125,18 @@ class RTABMap {
} }
} }
func recover(from: String, to: String) -> Bool {
from.utf8CString.withUnsafeBufferPointer { bufferFrom -> Bool in
to.utf8CString.withUnsafeBufferPointer { bufferTo -> Bool in
return recoverNative(native_rtabmap, bufferFrom.baseAddress, bufferTo.baseAddress)
}
}
}
func cancelProcessing() {
cancelProcessingNative(native_rtabmap);
}
func postProcessing(approach: Int) -> Int { func postProcessing(approach: Int) -> Int {
return Int(postProcessingNative(native_rtabmap, Int32(approach))) return Int(postProcessingNative(native_rtabmap, Int32(approach)))
} }
@@ -486,7 +490,7 @@ func getPreviewImage(databasePath: String) -> UIImage?
let bitmap = CIImage(bitmapData: data, bytesPerRow: Int(image.width*image.channels), size: CGSize(width: Int(image.width), height: Int(image.height)), format: CIFormat.BGRA8, colorSpace: nil) let bitmap = CIImage(bitmapData: data, bytesPerRow: Int(image.width*image.channels), size: CGSize(width: Int(image.width), height: Int(image.height)), format: CIFormat.BGRA8, colorSpace: nil)
return UIImage(ciImage: bitmap) return UIImage(ciImage: bitmap)
} }
return nil return UIImage(named: "RTAB-Map1024")
} }
return imageOut return imageOut
} }
+153 -10
View File
@@ -8,6 +8,7 @@
import GLKit import GLKit
import ARKit import ARKit
import Zip import Zip
import StoreKit
extension Array { extension Array {
func size() -> Int { func size() -> Int {
@@ -41,6 +42,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
private var mMaxFeatures: Int = 0 private var mMaxFeatures: Int = 0
private var mLoopThr = 0.11 private var mLoopThr = 0.11
private var mReviewRequested = false
// UI states // UI states
private enum State { private enum State {
case STATE_WELCOME, // Camera/Motion off - showing only buttons open and start new scan case STATE_WELCOME, // Camera/Motion off - showing only buttons open and start new scan
@@ -1340,6 +1343,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
rtabmap!.setMappingParameter(key: "Vis/FeatureType", value: defaults.string(forKey: "FeatureType")!); rtabmap!.setMappingParameter(key: "Vis/FeatureType", value: defaults.string(forKey: "FeatureType")!);
rtabmap!.setMappingParameter(key: "Mem/NotLinkedNodesKept", value: defaults.bool(forKey: "SaveAllFramesInDatabase") ? "true" : "false"); rtabmap!.setMappingParameter(key: "Mem/NotLinkedNodesKept", value: defaults.bool(forKey: "SaveAllFramesInDatabase") ? "true" : "false");
rtabmap!.setMappingParameter(key: "RGBD/OptimizeFromGraphEnd", value: defaults.bool(forKey: "OptimizationfromGraphEnd") ? "true" : "false"); rtabmap!.setMappingParameter(key: "RGBD/OptimizeFromGraphEnd", value: defaults.bool(forKey: "OptimizationfromGraphEnd") ? "true" : "false");
rtabmap!.setMappingParameter(key: "RGBD/MaxOdomCacheSize", value: defaults.string(forKey: "MaximumOdometryCacheSize")!);
rtabmap!.setMappingParameter(key: "Optimizer/Strategy", value: defaults.string(forKey: "GraphOptimizer")!); rtabmap!.setMappingParameter(key: "Optimizer/Strategy", value: defaults.string(forKey: "GraphOptimizer")!);
rtabmap!.setMappingParameter(key: "RGBD/ProximityBySpace", value: defaults.string(forKey: "ProximityDetection")!); rtabmap!.setMappingParameter(key: "RGBD/ProximityBySpace", value: defaults.string(forKey: "ProximityDetection")!);
@@ -1413,12 +1417,19 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
present(alertController, animated: true) present(alertController, animated: true)
setGLCamera(type: 1); setGLCamera(type: 0);
startCamera(); startCamera();
} }
func newScan() func newScan()
{ {
print("databases.size() = \(databases.size())")
if(databases.count >= 5 && !mReviewRequested && self.depthSupported)
{
SKStoreReviewController.requestReviewInCurrentScene()
mReviewRequested = true
}
if(mState == State.STATE_VISUALIZING) if(mState == State.STATE_VISUALIZING)
{ {
closeVisualization() closeVisualization()
@@ -1427,14 +1438,120 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
mMapNodes = 0; mMapNodes = 0;
self.openedDatabasePath = nil self.openedDatabasePath = nil
let tmpDatabase = self.getTmpDirectory().appendingPathComponent(self.RTABMAP_TMP_DB) let tmpDatabase = self.getTmpDirectory().appendingPathComponent(self.RTABMAP_TMP_DB)
let inMemory = UserDefaults.standard.bool(forKey: "DatabaseInMemory") let inMemory = UserDefaults.standard.bool(forKey: "DatabaseInMemory")
self.rtabmap!.openDatabase(databasePath: tmpDatabase.path, databaseInMemory: inMemory, optimize: false) if(!(self.mState == State.STATE_CAMERA || self.mState == State.STATE_MAPPING) &&
FileManager.default.fileExists(atPath: tmpDatabase.path) &&
if(!(self.mState == State.STATE_CAMERA || self.mState == State.STATE_MAPPING)) tmpDatabase.fileSize > 1024*1024) // > 1MB
{ {
self.setGLCamera(type: 1); dismiss(animated: true, completion: {
self.startCamera(); let msg = "The previous session (\(tmpDatabase.fileSizeString)) was not correctly saved, do you want to recover it?"
let alert = UIAlertController(title: "Recovery", message: msg, preferredStyle: .alert)
let alertActionNo = UIAlertAction(title: "Ignore", style: .destructive) {
(UIAlertAction) -> Void in
do {
try FileManager.default.removeItem(at: tmpDatabase)
}
catch {
print("Could not clear tmp database: \(error)")
}
self.newScan()
}
alert.addAction(alertActionNo)
let alertActionCancel = UIAlertAction(title: "Cancel", style: .cancel) {
(UIAlertAction) -> Void in
// do nothing
}
alert.addAction(alertActionCancel)
let alertActionYes = UIAlertAction(title: "Yes", style: .default) {
(UIAlertAction2) -> Void in
let fileName = Date().getFormattedDate(format: "yyMMdd-HHmmss") + ".db"
let outputDbPath = self.getDocumentDirectory().appendingPathComponent(fileName).path
var indicator: UIActivityIndicatorView?
let alertView = UIAlertController(title: "Recovering", message: "Please wait while recovering data...", preferredStyle: .alert)
let alertViewActionCancel = UIAlertAction(title: "Cancel", style: .cancel) {
(UIAlertAction) -> Void in
self.dismiss(animated: true, completion: {
self.progressView = nil
indicator = UIActivityIndicatorView(style: .large)
indicator?.frame = CGRect(x: 0.0, y: 0.0, width: 60.0, height: 60.0)
indicator?.center = self.view.center
self.view.addSubview(indicator!)
indicator?.bringSubviewToFront(self.view)
indicator?.startAnimating()
self.rtabmap!.cancelProcessing();
})
}
alertView.addAction(alertViewActionCancel)
let previousState = self.mState
self.updateState(state: .STATE_PROCESSING);
self.present(alertView, animated: true, completion: {
// Add your progressbar after alert is shown (and measured)
let margin:CGFloat = 8.0
let rect = CGRect(x: margin, y: 84.0, width: alertView.view.frame.width - margin * 2.0 , height: 2.0)
self.progressView = UIProgressView(frame: rect)
self.progressView!.progress = 0
self.progressView!.tintColor = self.view.tintColor
alertView.view.addSubview(self.progressView!)
var success : Bool = false
DispatchQueue.background(background: {
success = self.rtabmap!.recover(from: tmpDatabase.path, to: outputDbPath)
}, completion:{
if(indicator != nil)
{
indicator!.stopAnimating()
indicator!.removeFromSuperview()
}
if self.progressView != nil
{
self.dismiss(animated: self.openedDatabasePath == nil, completion: {
if(success)
{
let alertSaved = UIAlertController(title: "Database saved!", message: String(format: "Database \"%@\" successfully recovered!", fileName), preferredStyle: .alert)
let yes = UIAlertAction(title: "OK", style: .default) {
(UIAlertAction) -> Void in
self.openDatabase(fileUrl: URL(fileURLWithPath: outputDbPath))
}
alertSaved.addAction(yes)
self.present(alertSaved, animated: true, completion: nil)
}
else
{
self.updateState(state: previousState);
self.showToast(message: "Recovery failed!", seconds: 4)
}
})
}
else
{
self.showToast(message: "Recovery canceled", seconds: 2)
self.updateState(state: previousState);
}
})
})
}
alert.addAction(alertActionYes)
self.present(alert, animated: true, completion: nil)
})
}
else
{
self.rtabmap!.openDatabase(databasePath: tmpDatabase.path, databaseInMemory: inMemory, optimize: false, clearDatabase: true)
if(!(self.mState == State.STATE_CAMERA || self.mState == State.STATE_MAPPING))
{
self.setGLCamera(type: 0);
self.startCamera();
}
} }
} }
@@ -1518,12 +1635,19 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
self.openedDatabasePath = URL(fileURLWithPath: filePath) self.openedDatabasePath = URL(fileURLWithPath: filePath)
let alert = UIAlertController(title: "Database saved!", message: String(format: "Database \"%@\" successfully saved on the SD-CARD!", fileName), preferredStyle: .alert) let alert = UIAlertController(title: "Database saved!", message: String(format: "Database \"%@\" successfully saved!", fileName), preferredStyle: .alert)
let yes = UIAlertAction(title: "OK", style: .default) { let yes = UIAlertAction(title: "OK", style: .default) {
(UIAlertAction) -> Void in (UIAlertAction) -> Void in
} }
alert.addAction(yes) alert.addAction(yes)
self.present(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
do {
let tmpDatabase = self.getTmpDirectory().appendingPathComponent(self.RTABMAP_TMP_DB)
try FileManager.default.removeItem(at: tmpDatabase)
}
catch {
print("Could not clear tmp database: \(error)")
}
self.updateDatabases() self.updateDatabases()
self.updateState(state: previousState) self.updateState(state: previousState)
}) })
@@ -1559,6 +1683,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
indicator?.bringSubviewToFront(self.view) indicator?.bringSubviewToFront(self.view)
indicator?.startAnimating() indicator?.startAnimating()
self.rtabmap!.cancelProcessing()
}) })
})) }))
@@ -1663,6 +1789,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
alertView.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in alertView.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
self.dismiss(animated: true) self.dismiss(animated: true)
self.progressView = nil self.progressView = nil
self.rtabmap!.cancelProcessing()
})) }))
let previousState = mState let previousState = mState
@@ -1799,7 +1926,6 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
stopMapping(ignoreSaving: true) stopMapping(ignoreSaving: true)
} }
let tmpDatabase = self.getTmpDirectory().appendingPathComponent(self.RTABMAP_TMP_DB)
openedDatabasePath = fileUrl; openedDatabasePath = fileUrl;
let fileName: String = self.openedDatabasePath!.lastPathComponent let fileName: String = self.openedDatabasePath!.lastPathComponent
@@ -1811,7 +1937,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
updateState(state: .STATE_PROCESSING); updateState(state: .STATE_PROCESSING);
var status = 0 var status = 0
DispatchQueue.background(background: { DispatchQueue.background(background: {
status = self.rtabmap!.openDatabase(databaseSource: self.openedDatabasePath!.path, databasePath: tmpDatabase.path, databaseInMemory: true, optimize: false) status = self.rtabmap!.openDatabase(databasePath: self.openedDatabasePath!.path, databaseInMemory: true, optimize: false, clearDatabase: false)
}, completion:{ }, completion:{
// main thread // main thread
if(status == -1) { if(status == -1) {
@@ -1973,6 +2099,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
alertView.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in alertView.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
self.dismiss(animated: true) self.dismiss(animated: true)
self.progressView = nil self.progressView = nil
self.rtabmap!.cancelProcessing()
})) }))
let previousState = mState; let previousState = mState;
@@ -2210,6 +2337,14 @@ extension Date {
dateformat.dateFormat = format dateformat.dateFormat = format
return dateformat.string(from: self) return dateformat.string(from: self)
} }
var millisecondsSince1970:Int64 {
Int64((self.timeIntervalSince1970 * 1000.0).rounded())
}
init(milliseconds:Int64) {
self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
}
} }
extension DispatchQueue { extension DispatchQueue {
@@ -2322,3 +2457,11 @@ extension UserDefaults {
setDefaultsFromSettingsBundle() setDefaultsFromSettingsBundle()
} }
} }
extension SKStoreReviewController {
public static func requestReviewInCurrentScene() {
if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
requestReview(in: scene)
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@
<string> <string>
======= RTAB-Map ======= ======= RTAB-Map =======
RTAB-Map - https://github.com/introlab/rtabmap RTAB-Map - https://github.com/introlab/rtabmap
Copyright (c) 2010-2021, Mathieu Labbe - IntRoLab - Universite de Sherbrooke, all rights reserved. Copyright (c) 2010-2022, Mathieu Labbe - IntRoLab - Universite de Sherbrooke, all rights reserved.
Copyright (c) XXX, contributors, all rights reserved. Copyright (c) XXX, contributors, all rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
+44
View File
@@ -552,6 +552,50 @@
<key>DefaultValue</key> <key>DefaultValue</key>
<true/> <true/>
</dict> </dict>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>FooterText</key>
<string>Used only in localization mode (when clicking First-P. View during visualization). This is used to get smoother localizations and to verify localization transforms (when Max Optimization Error is not disabled) to make sure we don't teleport to a location very similar to one we previously localized on.</string>
</dict>
<dict>
<key>Type</key>
<string>PSMultiValueSpecifier</string>
<key>Title</key>
<string>Maximum odometry cache size</string>
<key>Key</key>
<string>MaximumOdometryCacheSize</string>
<key>DefaultValue</key>
<string>10</string>
<key>Titles</key>
<array>
<string>500</string>
<string>200</string>
<string>100</string>
<string>75</string>
<string>50</string>
<string>40</string>
<string>30</string>
<string>20</string>
<string>10</string>
<string>5</string>
<string>Disabled</string>
</array>
<key>Values</key>
<array>
<string>500</string>
<string>200</string>
<string>100</string>
<string>75</string>
<string>50</string>
<string>40</string>
<string>30</string>
<string>20</string>
<string>10</string>
<string>5</string>
<string>0</string>
</array>
</dict>
<dict> <dict>
<key>Type</key> <key>Type</key>
<string>PSGroupSpecifier</string> <string>PSGroupSpecifier</string>
+3 -3
View File
@@ -14,7 +14,7 @@
</dict> </dict>
<dict> <dict>
<key>DefaultValue</key> <key>DefaultValue</key>
<integer>2</integer> <integer>1</integer>
<key>Key</key> <key>Key</key>
<string>PointCloudDensity</string> <string>PointCloudDensity</string>
<key>Title</key> <key>Title</key>
@@ -454,7 +454,7 @@
</dict> </dict>
<dict> <dict>
<key>FooterText</key> <key>FooterText</key>
<string>Copyright (c) 2010-2021, Mathieu Labbe - IntRoLab - Université de Sherbrooke. All rights reserved.</string> <string>Copyright (c) 2010-2022, Mathieu Labbe - IntRoLab - Université de Sherbrooke. All rights reserved.</string>
<key>Title</key> <key>Title</key>
<string>About</string> <string>About</string>
<key>Type</key> <key>Type</key>
@@ -462,7 +462,7 @@
</dict> </dict>
<dict> <dict>
<key>DefaultValue</key> <key>DefaultValue</key>
<string>0.20.12</string> <string>0.20.17</string>
<key>Key</key> <key>Key</key>
<string>Version</string> <string>Version</string>
<key>Title</key> <key>Title</key>
+24 -5
View File
@@ -4,6 +4,7 @@ SET(SRC_FILES
) )
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${PROJECT_BINARY_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/utilite/include ${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include ${PROJECT_SOURCE_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/guilib/include ${PROJECT_SOURCE_DIR}/guilib/include
@@ -134,6 +135,24 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
COMPONENT runtime) COMPONENT runtime)
ENDIF(WIN32) ENDIF(WIN32)
ENDIF(k4a_FOUND) ENDIF(k4a_FOUND)
IF(Torch_FOUND)
# Install needed cudnn_ops_infer64_8.dll and cudnn_cnn_infer64_8.dll
# TODO: should be a more general way to include them if version is different
IF(WIN32 AND CUDA_FOUND)
find_file(CUDNN_OPS_DLL NAMES cudnn_ops_infer64_8.dll)
find_file(CUDNN_CNN_DLL NAMES cudnn_cnn_infer64_8.dll)
IF(CUDNN_OPS_DLL AND CUDNN_CNN_DLL)
MESSAGE(STATUS "Found ${CUDNN_OPS_DLL}")
MESSAGE(STATUS "Found ${CUDNN_CNN_DLL}")
INSTALL(FILES ${CUDNN_OPS_DLL} ${CUDNN_CNN_DLL}
DESTINATION ${plugin_dest_dir}
COMPONENT runtime)
ELSE()
MESSAGE(AUTHOR_WARNING "Using Torch with CUDA, but cudnn_ops_infer64_8.dll and cudnn_cnn_infer64_8.dll are not found on the PATH, so it won't be added to package.")
ENDIF()
ENDIF(WIN32 AND CUDA_FOUND)
ENDIF(Torch_FOUND)
# Install needed Qt plugins by copying directories from the qt installation # Install needed Qt plugins by copying directories from the qt installation
# One can cull what gets copied by using 'REGEX "..." EXCLUDE' # One can cull what gets copied by using 'REGEX "..." EXCLUDE'
@@ -153,17 +172,17 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
list(GET loc_list 1 plugin_type) list(GET loc_list 1 plugin_type)
IF(NOT plugin_root) IF(NOT plugin_root)
get_filename_component(plugin_root ${plugin_dir} DIRECTORY) get_filename_component(plugin_root ${plugin_dir} DIRECTORY)
ENDIF(NOT plugin_root) ENDIF(NOT plugin_root)
#MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}/plugins${plugin_type}\"") #MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}/plugins${plugin_type}\"")
INSTALL(FILES ${plugin_loc} INSTALL(FILES ${plugin_loc}
DESTINATION ${plugin_dest_dir}/plugins${plugin_type} DESTINATION ${plugin_dest_dir}/plugins${plugin_type}
COMPONENT runtime) COMPONENT runtime)
endforeach() endforeach()
IF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0) IF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0)
IF(WIN32) IF(WIN32)
SET(plugin_loc "${plugin_root}/styles/qwindowsvistastyle.dll") SET(plugin_loc "${plugin_root}/styles/qwindowsvistastyle.dll")
ELSEIF(APPLE) ELSEIF(APPLE)
SET(plugin_loc "${plugin_root}/styles/libqmacstyle.dylib") SET(plugin_loc "${plugin_root}/styles/libqmacstyle.dylib")
ENDIF() ENDIF()
IF(EXISTS ${plugin_loc}) IF(EXISTS ${plugin_loc})
get_filename_component(plugin_dir ${plugin_loc} DIRECTORY) get_filename_component(plugin_dir ${plugin_loc} DIRECTORY)
-5
View File
@@ -1,5 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
!data
+16 -3
View File
@@ -1,4 +1,5 @@
#Pre-requisites: Look for csparse #Pre-requisites: Look for csparse
MESSAGE(STATUS "RTAB-Map's cmake g2o find module used for convenience (for older g2o versions)")
FIND_PATH(CSPARSE_INCLUDE_DIR NAMES cs.h PATH_SUFFIXES suitesparse csparse EXTERNAL/suitesparse EXTERNAL/csparse g2o/EXTERNAL/suitesparse g2o/EXTERNAL/csparse FIND_PATH(CSPARSE_INCLUDE_DIR NAMES cs.h PATH_SUFFIXES suitesparse csparse EXTERNAL/suitesparse EXTERNAL/csparse g2o/EXTERNAL/suitesparse g2o/EXTERNAL/csparse
PATHS "C:\\Program Files\\g2o\\include\\EXTERNAL") PATHS "C:\\Program Files\\g2o\\include\\EXTERNAL")
FIND_LIBRARY(CSPARSE_LIBRARY NAMES cxsparse g2o_ext_csparse FIND_LIBRARY(CSPARSE_LIBRARY NAMES cxsparse g2o_ext_csparse
@@ -21,6 +22,10 @@ FIND_FILE(G2O_CONFIG_FILE g2o/config.h
PATHS ${G2O_INCLUDE_DIR} PATHS ${G2O_INCLUDE_DIR}
NO_DEFAULT_PATH) NO_DEFAULT_PATH)
FIND_FILE(G2O_FACTORY_FILE g2o/core/factory.h
PATHS ${G2O_INCLUDE_DIR}
NO_DEFAULT_PATH)
#ifdef G2O_NUMBER_FORMAT_STR #ifdef G2O_NUMBER_FORMAT_STR
#define G2O_CPP11 // we assume that if G2O_NUMBER_FORMAT_STR is defined, this is the new g2o code with c++11 interface #define G2O_CPP11 // we assume that if G2O_NUMBER_FORMAT_STR is defined, this is the new g2o code with c++11 interface
#endif #endif
@@ -83,7 +88,7 @@ ENDIF(G2O_SOLVER_CHOLMOD OR G2O_SOLVER_CSPARSE OR G2O_SOLVER_DENSE OR G2O_SOLVER
# G2O itself declared found if we found the core libraries and at least one solver # G2O itself declared found if we found the core libraries and at least one solver
SET(G2O_FOUND "NO") SET(G2O_FOUND "NO")
IF(G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_CONFIG_FILE AND G2O_SOLVERS_FOUND) IF(G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_CONFIG_FILE AND G2O_FACTORY_FILE AND G2O_SOLVERS_FOUND)
SET(G2O_INCLUDE_DIRS ${G2O_INCLUDE_DIR}) SET(G2O_INCLUDE_DIRS ${G2O_INCLUDE_DIR})
SET(G2O_LIBRARIES SET(G2O_LIBRARIES
${G2O_CORE_LIBRARY} ${G2O_CORE_LIBRARY}
@@ -120,8 +125,16 @@ IF(G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_CONFIG_FIL
SET(G2O_CPP11 0) SET(G2O_CPP11 0)
ELSE() ELSE()
MESSAGE(WARNING "Latest g2o version detected with c++11 interface (config file: ${G2O_CONFIG_FILE}). Make sure g2o is built with \"-DBUILD_WITH_MARCH_NATIVE=OFF\" to avoid segmentation faults caused by Eigen.") MESSAGE(WARNING "Latest g2o version detected with c++11 interface (config file: ${G2O_CONFIG_FILE}). Make sure g2o is built with \"-DBUILD_WITH_MARCH_NATIVE=OFF\" to avoid segmentation faults caused by Eigen.")
SET(G2O_CPP11 1) FILE(READ ${G2O_FACTORY_FILE} TMPTXT)
STRING(FIND "${TMPTXT}" "shared_ptr" matchres)
IF(${matchres} EQUAL -1)
MESSAGE(STATUS "Old g2o factory version detected without shared ptr (factory file: ${G2O_FACTORY_FILE}).")
SET(G2O_CPP11 2)
ELSE()
MESSAGE(STATUS "Latest g2o factory version detected with shared ptr (factory file: ${G2O_FACTORY_FILE}).")
SET(G2O_CPP11 1)
ENDIF()
ENDIF() ENDIF()
SET(G2O_FOUND "YES") SET(G2O_FOUND "YES")
ENDIF(G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_CONFIG_FILE AND G2O_SOLVERS_FOUND) ENDIF(G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_CONFIG_FILE AND G2O_FACTORY_FILE AND G2O_SOLVERS_FOUND)
-1
View File
@@ -1 +0,0 @@
/Version.h
+36 -30
View File
@@ -125,7 +125,8 @@ void RTABMAP_EXP computeMaxGraphErrors(
float & maxLinearError, float & maxLinearError,
float & maxAngularError, float & maxAngularError,
const Link ** maxLinearErrorLink = 0, const Link ** maxLinearErrorLink = 0,
const Link ** maxAngularErrorLink = 0); const Link ** maxAngularErrorLink = 0,
bool for3DoF = false);
std::vector<double> RTABMAP_EXP getMaxOdomInf(const std::multimap<int, Link> & links); std::vector<double> RTABMAP_EXP getMaxOdomInf(const std::multimap<int, Link> & links);
@@ -133,7 +134,8 @@ std::multimap<int, Link>::iterator RTABMAP_EXP findLink(
std::multimap<int, Link> & links, std::multimap<int, Link> & links,
int from, int from,
int to, int to,
bool checkBothWays = true); bool checkBothWays = true,
Link::Type type = Link::kUndef);
std::multimap<int, int>::iterator RTABMAP_EXP findLink( std::multimap<int, int>::iterator RTABMAP_EXP findLink(
std::multimap<int, int> & links, std::multimap<int, int> & links,
int from, int from,
@@ -265,54 +267,58 @@ std::list<std::pair<int, Transform> > RTABMAP_EXP computePath(
float angularVelocity = 0.0f); // rad/sec float angularVelocity = 0.0f); // rad/sec
/** /**
* Get the nearest node of the target pose * Find the nearest node of the target pose
* @param nodes the nodes to search for * @param nodes the nodes to search for
* @param targetPose the target pose to search around * @param targetPose the target pose to search around
* @param distance squared distance of the nearest node found (optional) * @param distance squared distance of the nearest node found (optional)
* @return the node id. * @return the node id.
*/ */
int RTABMAP_EXP findNearestNode( int RTABMAP_EXP findNearestNode(
const std::map<int, rtabmap::Transform> & nodes, const std::map<int, rtabmap::Transform> & poses,
const rtabmap::Transform & targetPose, const rtabmap::Transform & targetPose,
float * distance = 0); float * distance = 0);
/** /**
* Get K nearest nodes of the target pose * Find the nearest nodes of the query pose or node
* @param nodes the nodes to search for
* @param targetPose the target pose to search around
* @param k number of nearest neighbors to search for
* @return the node ids with squared distance to target pose.
*/
std::map<int, float> RTABMAP_EXP findNearestNodes(
const std::map<int, rtabmap::Transform> & nodes,
const rtabmap::Transform & targetPose,
int k);
/**
* Get nodes near the query
* @param nodeId the query id * @param nodeId the query id
* @param nodes the nodes to search for * @param nodes the nodes to search for
* @param radius radius to search for (m) * @param radius radius to search for (m), if 0, k should be > 0.
* @param k max nearest neighbors (0=all inside the radius)
* @return the nodes with squared distance to query node. * @return the nodes with squared distance to query node.
*/ */
std::map<int, float> RTABMAP_EXP getNodesInRadius( std::map<int, float> RTABMAP_EXP findNearestNodes(
int nodeId, int nodeId,
const std::map<int, Transform> & nodes, const std::map<int, Transform> & poses,
float radius); float radius,
std::map<int, float> RTABMAP_EXP getNodesInRadius( float angle = 0.0f,
int k=0);
std::map<int, float> RTABMAP_EXP findNearestNodes(
const Transform & targetPose, const Transform & targetPose,
const std::map<int, Transform> & nodes, const std::map<int, Transform> & poses,
float radius); float radius,
std::map<int, Transform> RTABMAP_EXP getPosesInRadius( float angle = 0.0f,
int k=0);
std::map<int, Transform> RTABMAP_EXP findNearestPoses(
int nodeId, int nodeId,
const std::map<int, Transform> & nodes, const std::map<int, Transform> & poses,
float radius, float radius,
float angle = 0.0f); float angle = 0.0f,
std::map<int, Transform> RTABMAP_EXP getPosesInRadius( int k=0);
std::map<int, Transform> RTABMAP_EXP findNearestPoses(
const Transform & targetPose, const Transform & targetPose,
const std::map<int, Transform> & nodes, const std::map<int, Transform> & poses,
float radius, float radius,
float angle = 0.0f); float angle = 0.0f,
int k=0);
// typedef hack to avoid error with RTABMAP_DEPRECATED
typedef std::map<int, float> _mapIntFloat;
typedef std::map<int, Transform> _mapIntTransform;
RTABMAP_DEPRECATED(_mapIntFloat RTABMAP_EXP findNearestNodes(const std::map<int, rtabmap::Transform> & nodes, const rtabmap::Transform & targetPose, int k), "Use new findNearestNodes() interface with radius=0, angle=0.");
RTABMAP_DEPRECATED(_mapIntFloat RTABMAP_EXP getNodesInRadius(int nodeId, const std::map<int, Transform> & nodes, float radius), "Renamed to findNearestNodes()");
RTABMAP_DEPRECATED(_mapIntFloat RTABMAP_EXP getNodesInRadius(const Transform & targetPose, const std::map<int, Transform> & nodes, float radius), "Renamed to findNearestNodes()");
RTABMAP_DEPRECATED(_mapIntTransform RTABMAP_EXP getPosesInRadius(int nodeId, const std::map<int, Transform> & nodes, float radius, float angle = 0.0f), "Renamed to findNearestNodes()");
RTABMAP_DEPRECATED(_mapIntTransform RTABMAP_EXP getPosesInRadius(const Transform & targetPose, const std::map<int, Transform> & nodes, float radius, float angle = 0.0f), "Renamed to findNearestNodes()");
float RTABMAP_EXP computePathLength( float RTABMAP_EXP computePathLength(
const std::vector<std::pair<int, Transform> > & path, const std::vector<std::pair<int, Transform> > & path,
+1
View File
@@ -320,6 +320,7 @@ private:
float _laserScanVoxelSize; float _laserScanVoxelSize;
int _laserScanNormalK; int _laserScanNormalK;
float _laserScanNormalRadius; float _laserScanNormalRadius;
float _laserScanGroundNormalsUp;
bool _reextractLoopClosureFeatures; bool _reextractLoopClosureFeatures;
bool _localBundleOnLoopClosure; bool _localBundleOnLoopClosure;
float _rehearsalMaxDistance; float _rehearsalMaxDistance;
@@ -122,6 +122,7 @@ private:
bool projMapFrame_; bool projMapFrame_;
float maxObstacleHeight_; float maxObstacleHeight_;
int normalKSearch_; int normalKSearch_;
float groundNormalsUp_;
float maxGroundAngle_; float maxGroundAngle_;
float clusterRadius_; float clusterRadius_;
int minClusterSize_; int minClusterSize_;
+2
View File
@@ -74,6 +74,8 @@ public:
void expandNode(); void expandNode();
bool createChild(unsigned int i); bool createChild(unsigned int i);
void updateOccupancyTypeChildren();
private: private:
int nodeRefId_; int nodeRefId_;
int type_; // -1=undefined, 0=empty, 100=obstacle, 1=ground int type_; // -1=undefined, 0=empty, 100=obstacle, 1=ground
+2 -1
View File
@@ -55,7 +55,8 @@ public:
kTypeMSCKF = 8, kTypeMSCKF = 8,
kTypeVINS = 9, kTypeVINS = 9,
kTypeOpenVINS = 10, kTypeOpenVINS = 10,
kTypeFLOAM = 11 kTypeFLOAM = 11,
kTypeOpen3D = 12
}; };
public: public:
+2 -1
View File
@@ -75,7 +75,8 @@ public:
const std::map<int, Transform> & posesIn, const std::map<int, Transform> & posesIn,
const std::multimap<int, Link> & linksIn, const std::multimap<int, Link> & linksIn,
std::map<int, Transform> & posesOut, std::map<int, Transform> & posesOut,
std::multimap<int, Link> & linksOut) const; std::multimap<int, Link> & linksOut,
bool adjustPosesWithConstraints = true) const;
public: public:
virtual ~Optimizer() {} virtual ~Optimizer() {}
+10 -5
View File
@@ -202,7 +202,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Mem, ImageKept, bool, false, "Keep raw images in RAM."); RTABMAP_PARAM(Mem, ImageKept, bool, false, "Keep raw images in RAM.");
RTABMAP_PARAM(Mem, BinDataKept, bool, true, "Keep binary data in db."); RTABMAP_PARAM(Mem, BinDataKept, bool, true, "Keep binary data in db.");
RTABMAP_PARAM(Mem, RawDescriptorsKept, bool, true, "Raw descriptors kept in memory."); RTABMAP_PARAM(Mem, RawDescriptorsKept, bool, true, "Raw descriptors kept in memory.");
RTABMAP_PARAM(Mem, MapLabelsAdded, bool, true, "Create map labels. The first node of a map will be labelled as \"map#\" where # is the map ID."); RTABMAP_PARAM(Mem, MapLabelsAdded, bool, true, "Create map labels. The first node of a map will be labeled as \"map#\" where # is the map ID.");
RTABMAP_PARAM(Mem, SaveDepth16Format, bool, false, "Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters)."); RTABMAP_PARAM(Mem, SaveDepth16Format, bool, false, "Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).");
RTABMAP_PARAM(Mem, NotLinkedNodesKept, bool, true, "Keep not linked nodes in db (rehearsed nodes and deleted nodes)."); RTABMAP_PARAM(Mem, NotLinkedNodesKept, bool, true, "Keep not linked nodes in db (rehearsed nodes and deleted nodes).");
RTABMAP_PARAM(Mem, IntermediateNodeDataKept, bool, false, "Keep intermediate node data in db."); RTABMAP_PARAM(Mem, IntermediateNodeDataKept, bool, false, "Keep intermediate node data in db.");
@@ -373,7 +373,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(RGBD, CreateOccupancyGrid, bool, false, "Create local occupancy grid maps. See \"Grid\" group for parameters."); RTABMAP_PARAM(RGBD, CreateOccupancyGrid, bool, false, "Create local occupancy grid maps. See \"Grid\" group for parameters.");
RTABMAP_PARAM(RGBD, MarkerDetection, bool, false, "Detect static markers to be added as landmarks for graph optimization. If input data have already landmarks, this will be ignored. See \"Marker\" group for parameters."); RTABMAP_PARAM(RGBD, MarkerDetection, bool, false, "Detect static markers to be added as landmarks for graph optimization. If input data have already landmarks, this will be ignored. See \"Marker\" group for parameters.");
RTABMAP_PARAM(RGBD, LoopCovLimited, bool, false, "Limit covariance of non-neighbor links to minimum covariance of neighbor links. In other words, if covariance of a loop closure link is smaller than the minimum covariance of odometry links, its covariance is set to minimum covariance of odometry links."); RTABMAP_PARAM(RGBD, LoopCovLimited, bool, false, "Limit covariance of non-neighbor links to minimum covariance of neighbor links. In other words, if covariance of a loop closure link is smaller than the minimum covariance of odometry links, its covariance is set to minimum covariance of odometry links.");
RTABMAP_PARAM(RGBD, MaxOdomCacheSize, int, 0, uFormat("Maximum odometry cache size. Used only in localization mode (when %s=false) and when %s!=0. This is used to verify localization transforms to make sure we don't teleport to a location very similar to one we previously localized on. When the cache is full, the whole cache is cleared and the next localization is automatically accepted without verification. Set 0 to disable caching.", kMemIncrementalMemory().c_str(), kRGBDOptimizeMaxError().c_str())); RTABMAP_PARAM(RGBD, MaxOdomCacheSize, int, 10, uFormat("Maximum odometry cache size. Used only in localization mode (when %s=false). This is used to get smoother localizations and to verify localization transforms (when %s!=0) to make sure we don't teleport to a location very similar to one we previously localized on. Set 0 to disable caching.", kMemIncrementalMemory().c_str(), kRGBDOptimizeMaxError().c_str()));
// Local/Proximity loop closure detection // Local/Proximity loop closure detection
RTABMAP_PARAM(RGBD, ProximityByTime, bool, false, "Detection over all locations in STM."); RTABMAP_PARAM(RGBD, ProximityByTime, bool, false, "Detection over all locations in STM.");
@@ -385,7 +385,8 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(RGBD, ProximityPathRawPosesUsed, bool, true, "When comparing to a local path for one-to-many proximity detection, merge the scans using the odometry poses (with neighbor link optimizations) instead of the ones in the optimized local graph."); RTABMAP_PARAM(RGBD, ProximityPathRawPosesUsed, bool, true, "When comparing to a local path for one-to-many proximity detection, merge the scans using the odometry poses (with neighbor link optimizations) instead of the ones in the optimized local graph.");
RTABMAP_PARAM(RGBD, ProximityAngle, float, 45, "Maximum angle (degrees) for one-to-one proximity detection."); RTABMAP_PARAM(RGBD, ProximityAngle, float, 45, "Maximum angle (degrees) for one-to-one proximity detection.");
RTABMAP_PARAM(RGBD, ProximityOdomGuess, bool, false, "Use odometry as motion guess for one-to-one proximity detection."); RTABMAP_PARAM(RGBD, ProximityOdomGuess, bool, false, "Use odometry as motion guess for one-to-one proximity detection.");
RTABMAP_PARAM(RGBD, ProximityGlobalScanMap, bool, false, uFormat("Create a global assembled map from laser scans for one-to-many proximity detection, replacing the original one-to-many proximity detection (i.e., detection against local paths). Only used in localization mode (%s=false), otherwise original one-to-many proximity detection is done. Note also that if graph is modified (i.e., memory management is enabled or robot jumps from one disjoint session to another in same database), the global scan map is cleared and one-to-many proximity detection is reverted to original approach.", kMemIncrementalMemory().c_str(), kRGBDProximityPathRawPosesUsed().c_str())); RTABMAP_PARAM(RGBD, ProximityGlobalScanMap, bool, false, uFormat("Create a global assembled map from laser scans for one-to-many proximity detection, replacing the original one-to-many proximity detection (i.e., detection against local paths). Only used in localization mode (%s=false), otherwise original one-to-many proximity detection is done. Note also that if graph is modified (i.e., memory management is enabled or robot jumps from one disjoint session to another in same database), the global scan map is cleared and one-to-many proximity detection is reverted to original approach.", kMemIncrementalMemory().c_str()));
RTABMAP_PARAM(RGBD, ProximityMergedScanCovFactor, double, 100.0, uFormat("Covariance factor for one-to-many proximity detection (when %s>0 and scans are used).", kRGBDProximityPathMaxNeighbors().c_str()));
// Graph optimization // Graph optimization
#ifdef RTABMAP_GTSAM #ifdef RTABMAP_GTSAM
@@ -432,7 +433,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(GTSAM, Optimizer, int, 1, "0=Levenberg 1=GaussNewton 2=Dogleg"); RTABMAP_PARAM(GTSAM, Optimizer, int, 1, "0=Levenberg 1=GaussNewton 2=Dogleg");
// Odometry // Odometry
RTABMAP_PARAM(Odom, Strategy, int, 0, "0=Frame-to-Map (F2M) 1=Frame-to-Frame (F2F) 2=Fovis 3=viso2 4=DVO-SLAM 5=ORB_SLAM2 6=OKVIS 7=LOAM 8=MSCKF_VIO 9=VINS-Fusion 10=OpenVINS 11=FLOAM"); RTABMAP_PARAM(Odom, Strategy, int, 0, "0=Frame-to-Map (F2M) 1=Frame-to-Frame (F2F) 2=Fovis 3=viso2 4=DVO-SLAM 5=ORB_SLAM2 6=OKVIS 7=LOAM 8=MSCKF_VIO 9=VINS-Fusion 10=OpenVINS 11=FLOAM 12=Open3D");
RTABMAP_PARAM(Odom, ResetCountdown, int, 0, "Automatically reset odometry after X consecutive images on which odometry cannot be computed (value=0 disables auto-reset)."); RTABMAP_PARAM(Odom, ResetCountdown, int, 0, "Automatically reset odometry after X consecutive images on which odometry cannot be computed (value=0 disables auto-reset).");
RTABMAP_PARAM(Odom, Holonomic, bool, true, "If the robot is holonomic (strafing commands can be issued). If not, y value will be estimated from x and yaw values (y=x*tan(yaw))."); RTABMAP_PARAM(Odom, Holonomic, bool, true, "If the robot is holonomic (strafing commands can be issued). If not, y value will be estimated from x and yaw values (y=x*tan(yaw)).");
RTABMAP_PARAM(Odom, FillInfoData, bool, true, "Fill info with data (inliers/outliers features)."); RTABMAP_PARAM(Odom, FillInfoData, bool, true, "Fill info with data (inliers/outliers features).");
@@ -572,6 +573,10 @@ class RTABMAP_EXP Parameters
// Odometry VINS // Odometry VINS
RTABMAP_PARAM_STR(OdomVINS, ConfigPath, "", "Path of VINS config file."); RTABMAP_PARAM_STR(OdomVINS, ConfigPath, "", "Path of VINS config file.");
// Odometry Open3D
RTABMAP_PARAM(OdomOpen3D, MaxDepth, float, 3.0, "Maximum depth.");
RTABMAP_PARAM(OdomOpen3D, Method, int, 0, "Registration method: 0=PointToPlane, 1=Intensity, 2=Hybrid.");
// Common registration parameters // Common registration parameters
RTABMAP_PARAM(Reg, RepeatOnce, bool, true, "Do a second registration with the output of the first registration as guess. Only done if no guess was provided for the first registration (like on loop closure). It can be useful if the registration approach used can use a guess to get better matches."); RTABMAP_PARAM(Reg, RepeatOnce, bool, true, "Do a second registration with the output of the first registration as guess. Only done if no guess was provided for the first registration (like on loop closure). It can be useful if the registration approach used can use a guess to get better matches.");
RTABMAP_PARAM(Reg, Strategy, int, 0, "0=Vis, 1=Icp, 2=VisIcp"); RTABMAP_PARAM(Reg, Strategy, int, 0, "0=Vis, 1=Icp, 2=VisIcp");
@@ -665,7 +670,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP."); RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP.");
#endif #endif
RTABMAP_PARAM(Icp, PointToPlaneK, int, 5, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals."); RTABMAP_PARAM(Icp, PointToPlaneK, int, 5, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals.");
RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 1.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals."); RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 0.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals.");
RTABMAP_PARAM(Icp, PointToPlaneGroundNormalsUp, float, 0.0, "Invert normals on ground if they are pointing down (useful for ring-like 3D LiDARs). 0 means disabled, 1 means only normals perfectly aligned with -z axis. This is only done with 3D scans."); RTABMAP_PARAM(Icp, PointToPlaneGroundNormalsUp, float, 0.0, "Invert normals on ground if they are pointing down (useful for ring-like 3D LiDARs). 0 means disabled, 1 means only normals perfectly aligned with -z axis. This is only done with 3D scans.");
RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, uFormat("Minimum structural complexity (0.0=low, 1.0=high) of the scan to do PointToPlane registration, otherwise PointToPoint registration is done instead and strategy from %s is used. This check is done only when %s=true.", kIcpPointToPlaneLowComplexityStrategy().c_str(), kIcpPointToPlane().c_str())); RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, uFormat("Minimum structural complexity (0.0=low, 1.0=high) of the scan to do PointToPlane registration, otherwise PointToPoint registration is done instead and strategy from %s is used. This check is done only when %s=true.", kIcpPointToPlaneLowComplexityStrategy().c_str(), kIcpPointToPlane().c_str()));
RTABMAP_PARAM(Icp, PointToPlaneLowComplexityStrategy, int, 1, uFormat("If structural complexity is below %s: set to 0 to so that the transform is automatically rejected, set to 1 to limit ICP correction in axes with most constraints (e.g., for a corridor-like environment, the resulting transform will be limited in y and yaw, x will taken from the guess), set to 2 to accept \"as is\" the transform computed by PointToPoint.", kIcpPointToPlaneMinComplexity().c_str())); RTABMAP_PARAM(Icp, PointToPlaneLowComplexityStrategy, int, 1, uFormat("If structural complexity is below %s: set to 0 to so that the transform is automatically rejected, set to 1 to limit ICP correction in axes with most constraints (e.g., for a corridor-like environment, the resulting transform will be limited in y and yaw, x will taken from the guess), set to 2 to accept \"as is\" the transform computed by PointToPoint.", kIcpPointToPlaneMinComplexity().c_str()));
+3 -3
View File
@@ -196,8 +196,8 @@ public:
bool withGrid = false, bool withGrid = false,
bool withWords = true, bool withWords = true,
bool withGlobalDescriptors = true) const; bool withGlobalDescriptors = true) const;
std::map<int, Transform> getNodesInRadius(const Transform & pose, float radius); // If radius=0, RGBD/LocalRadius is used. Can return landmarks. std::map<int, Transform> getNodesInRadius(const Transform & pose, float radius, int k=0, std::map<int, float> * distsSqr=0); // If radius=0 and k=0, RGBD/LocalRadius is used. Can return landmarks.
std::map<int, Transform> getNodesInRadius(int nodeId, float radius); // If nodeId==0, return poses around latest node. If radius=0, RGBD/LocalRadius is used. Can return landmarks and use landmark id (negative) as request. std::map<int, Transform> getNodesInRadius(int nodeId, float radius, int k=0, std::map<int, float> * distsSqr=0); // If nodeId==0, return poses around latest node. If radius=0 and k=0, RGBD/LocalRadius is used. Can return landmarks and use landmark id (negative) as request.
int detectMoreLoopClosures( int detectMoreLoopClosures(
float clusterRadiusMax = 0.5f, float clusterRadiusMax = 0.5f,
float clusterAngle = M_PI/6.0f, float clusterAngle = M_PI/6.0f,
@@ -307,6 +307,7 @@ private:
bool _proximityRawPosesUsed; bool _proximityRawPosesUsed;
float _proximityAngle; float _proximityAngle;
bool _proximityOdomGuess; bool _proximityOdomGuess;
double _proximityMergedScanCovFactor;
std::string _databasePath; std::string _databasePath;
bool _optimizeFromGraphEnd; bool _optimizeFromGraphEnd;
float _optimizationMaxError; float _optimizationMaxError;
@@ -361,7 +362,6 @@ private:
std::map<int, Transform> _globalScanMapPoses; std::map<int, Transform> _globalScanMapPoses;
std::map<int, Transform> _odomCachePoses; // used in localization mode to reject loop closures std::map<int, Transform> _odomCachePoses; // used in localization mode to reject loop closures
std::multimap<int, Link> _odomCacheConstraints; // used in localization mode to reject loop closures std::multimap<int, Link> _odomCacheConstraints; // used in localization mode to reject loop closures
std::map<int, Transform> _odomCacheAddLink; // used in localization mode when adding external link
std::vector<float> _odomCorrectionAcc; std::vector<float> _odomCorrectionAcc;
// Planning stuff // Planning stuff
+2 -1
View File
@@ -73,7 +73,8 @@ public:
kCmdResume, kCmdResume,
kCmdGoal, // params: [string] label or [int] location ID kCmdGoal, // params: [string] label or [int] location ID
kCmdCancelGoal, kCmdCancelGoal,
kCmdLabel // params: [string] label, [int] location ID kCmdLabel, // params: [string] label, [int] location ID
kCmdRemoveLabel // params: [string] label
}; };
public: public:
RtabmapEventCmd(Cmd cmd, const ParametersMap & parameters = ParametersMap()) : RtabmapEventCmd(Cmd cmd, const ParametersMap & parameters = ParametersMap()) :
+2 -1
View File
@@ -68,7 +68,8 @@ public:
kStateTriggeringMap, kStateTriggeringMap,
kStateSettingGoal, kStateSettingGoal,
kStateCancellingGoal, kStateCancellingGoal,
kStateLabelling kStateLabelling,
kStateRemovingLabel
}; };
public: public:
@@ -147,6 +147,8 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(Memory, Rehearsal_id,); RTABMAP_STATS(Memory, Rehearsal_id,);
RTABMAP_STATS(Memory, Rehearsal_merged,); RTABMAP_STATS(Memory, Rehearsal_merged,);
RTABMAP_STATS(Memory, Local_graph_size,); RTABMAP_STATS(Memory, Local_graph_size,);
RTABMAP_STATS(Memory, Odom_cache_poses,);
RTABMAP_STATS(Memory, Odom_cache_links,);
RTABMAP_STATS(Memory, Small_movement,); RTABMAP_STATS(Memory, Small_movement,);
RTABMAP_STATS(Memory, Fast_movement,); RTABMAP_STATS(Memory, Fast_movement,);
RTABMAP_STATS(Memory, Odometry_variance_ang,); RTABMAP_STATS(Memory, Odometry_variance_ang,);
@@ -254,6 +256,8 @@ public:
void setCurrentGoalId(int goal) {_currentGoalId=goal;} void setCurrentGoalId(int goal) {_currentGoalId=goal;}
void setReducedIds(const std::map<int, int> & reducedIds) {_reducedIds = reducedIds;} void setReducedIds(const std::map<int, int> & reducedIds) {_reducedIds = reducedIds;}
void setWmState(const std::vector<int> & state) {_wmState = state;} void setWmState(const std::vector<int> & state) {_wmState = state;}
void setOdomCachePoses(const std::map<int, Transform> & poses) {_odomCachePoses = poses;}
void setOdomCacheConstraints(const std::multimap<int, Link> & constraints) {_odomCacheConstraints = constraints;}
// getters // getters
bool extended() const {return _extended;} bool extended() const {return _extended;}
@@ -281,6 +285,8 @@ public:
int currentGoalId() const {return _currentGoalId;} int currentGoalId() const {return _currentGoalId;}
const std::map<int, int> & reducedIds() const {return _reducedIds;} const std::map<int, int> & reducedIds() const {return _reducedIds;}
const std::vector<int> & wmState() const {return _wmState;} const std::vector<int> & wmState() const {return _wmState;}
const std::map<int, Transform> & odomCachePoses() const {return _odomCachePoses;}
const std::multimap<int, Link> & odomCacheConstraints() const {return _odomCacheConstraints;}
const std::map<std::string, float> & data() const {return _data;} const std::map<std::string, float> & data() const {return _data;}
@@ -316,6 +322,9 @@ private:
std::vector<int> _wmState; std::vector<int> _wmState;
std::map<int, Transform> _odomCachePoses;
std::multimap<int, Link> _odomCacheConstraints;
// Format for statistics (Plottable statistics must go in that map) : // Format for statistics (Plottable statistics must go in that map) :
// {"Group/Name/Unit", value} // {"Group/Name/Unit", value}
// Example : {"Timing/Total time/ms", 500.0f} // Example : {"Timing/Total time/ms", 500.0f}
+2
View File
@@ -104,6 +104,8 @@ public:
Transform translation() const; Transform translation() const;
Transform to3DoF() const; Transform to3DoF() const;
Transform to4DoF() const; Transform to4DoF() const;
bool is3DoF() const;
bool is4DoF() const;
cv::Mat rotationMatrix() const; cv::Mat rotationMatrix() const;
cv::Mat translationMatrix() const; cv::Mat translationMatrix() const;
@@ -126,6 +126,7 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
UDEBUG("Cluster radius=%f", clusterRadius_); UDEBUG("Cluster radius=%f", clusterRadius_);
UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0); UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0);
UDEBUG("maxGroundHeight=%f", maxGroundHeight_); UDEBUG("maxGroundHeight=%f", maxGroundHeight_);
UDEBUG("groundNormalsUp=%f", groundNormalsUp_);
util3d::segmentObstaclesFromGround<PointT>( util3d::segmentObstaclesFromGround<PointT>(
cloud, cloud,
indices, indices,
@@ -138,7 +139,8 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
flatObstaclesDetected_, flatObstaclesDetected_,
maxGroundHeight_, maxGroundHeight_,
flatObstacles, flatObstacles,
Eigen::Vector4f(viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0), 1)); Eigen::Vector4f(viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0), 1),
groundNormalsUp_);
UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0)); UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0));
//UWARN("Saving ground.pcd and obstacles.pcd"); //UWARN("Saving ground.pcd and obstacles.pcd");
//pcl::io::savePCDFile("ground.pcd", *cloud, *groundIndices); //pcl::io::savePCDFile("ground.pcd", *cloud, *groundIndices);
@@ -166,7 +168,11 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
// Do radius filtering after voxel filtering ( a lot faster) // Do radius filtering after voxel filtering ( a lot faster)
if(noiseFilteringRadius_ > 0.0 && noiseFilteringMinNeighbors_ > 0) if(noiseFilteringRadius_ > 0.0 && noiseFilteringMinNeighbors_ > 0)
{ {
UDEBUG(""); UDEBUG("Radius filtering (%ld ground %ld obstacles, radius=%f k=%d)",
groundIndices->size(),
obstaclesIndices->size()+(flatObstacles?(*flatObstacles)->size():0),
noiseFilteringRadius_,
noiseFilteringMinNeighbors_);
if(groundIndices->size()) if(groundIndices->size())
{ {
groundIndices = rtabmap::util3d::radiusFiltering(cloud, groundIndices, noiseFilteringRadius_, noiseFilteringMinNeighbors_); groundIndices = rtabmap::util3d::radiusFiltering(cloud, groundIndices, noiseFilteringRadius_, noiseFilteringMinNeighbors_);
@@ -179,6 +185,9 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
{ {
*flatObstacles = rtabmap::util3d::radiusFiltering(cloud, *flatObstacles, noiseFilteringRadius_, noiseFilteringMinNeighbors_); *flatObstacles = rtabmap::util3d::radiusFiltering(cloud, *flatObstacles, noiseFilteringRadius_, noiseFilteringMinNeighbors_);
} }
UDEBUG("Radius filtering end (%ld ground %ld obstacles)",
groundIndices->size(),
obstaclesIndices->size()+(flatObstacles?(*flatObstacles)->size():0));
if(groundIndices->empty() && obstaclesIndices->empty()) if(groundIndices->empty() && obstaclesIndices->empty())
{ {
@@ -63,7 +63,8 @@ void segmentObstaclesFromGround(
bool segmentFlatObstacles, bool segmentFlatObstacles,
float maxGroundHeight, float maxGroundHeight,
pcl::IndicesPtr * flatObstacles, pcl::IndicesPtr * flatObstacles,
const Eigen::Vector4f & viewPoint) const Eigen::Vector4f & viewPoint,
float groundNormalsUp)
{ {
ground.reset(new std::vector<int>); ground.reset(new std::vector<int>);
obstacles.reset(new std::vector<int>); obstacles.reset(new std::vector<int>);
@@ -81,7 +82,8 @@ void segmentObstaclesFromGround(
groundNormalAngle, groundNormalAngle,
Eigen::Vector4f(0,0,1,0), Eigen::Vector4f(0,0,1,0),
normalKSearch, normalKSearch,
viewPoint); viewPoint,
groundNormalsUp);
if(segmentFlatObstacles && flatSurfaces->size()) if(segmentFlatObstacles && flatSurfaces->size())
{ {
@@ -205,7 +207,8 @@ void segmentObstaclesFromGround(
bool segmentFlatObstacles, bool segmentFlatObstacles,
float maxGroundHeight, float maxGroundHeight,
pcl::IndicesPtr * flatObstacles, pcl::IndicesPtr * flatObstacles,
const Eigen::Vector4f & viewPoint) const Eigen::Vector4f & viewPoint,
float groundNormalsUp)
{ {
pcl::IndicesPtr indices(new std::vector<int>); pcl::IndicesPtr indices(new std::vector<int>);
segmentObstaclesFromGround<PointT>( segmentObstaclesFromGround<PointT>(
@@ -220,7 +223,8 @@ void segmentObstaclesFromGround(
segmentFlatObstacles, segmentFlatObstacles,
maxGroundHeight, maxGroundHeight,
flatObstacles, flatObstacles,
viewPoint); viewPoint,
groundNormalsUp);
} }
template<typename PointT> template<typename PointT>
@@ -0,0 +1,59 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODOMETRYOPEN3D_H_
#define ODOMETRYOPEN3D_H_
#include <rtabmap/core/Odometry.h>
namespace rtabmap {
class RTABMAP_EXP OdometryOpen3D : public Odometry
{
public:
OdometryOpen3D(const rtabmap::ParametersMap & parameters = rtabmap::ParametersMap());
virtual ~OdometryOpen3D();
virtual void reset(const Transform & initialPose = Transform::getIdentity());
virtual Odometry::Type getType() {return Odometry::kTypeOpen3D;}
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
private:
#ifdef RTABMAP_OPEN3D
rtabmap::SensorData keyFrame_;
Transform lastKeyFramePose_;
int method_;
float maxDepth_;
float keyFrameThr_;
#endif
};
}
#endif /* ODOMETRYOPEN3D_H_ */
@@ -42,16 +42,7 @@ public:
static bool isCholmodAvailable(); static bool isCholmodAvailable();
public: public:
OptimizerG2O(const ParametersMap & parameters = ParametersMap()) : OptimizerG2O(const ParametersMap & parameters = ParametersMap());
Optimizer(parameters),
solver_(Parameters::defaultg2oSolver()),
optimizer_(Parameters::defaultg2oOptimizer()),
pixelVariance_(Parameters::defaultg2oPixelVariance()),
robustKernelDelta_(Parameters::defaultg2oRobustKernelDelta()),
baseline_(Parameters::defaultg2oBaseline())
{
parseParameters(parameters);
}
virtual ~OptimizerG2O() {} virtual ~OptimizerG2O() {}
virtual Type type() const {return kTypeG2O;} virtual Type type() const {return kTypeG2O;}
+2
View File
@@ -313,6 +313,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > RTABMAP_EXP projectC
float maxDistance = 0.0f, float maxDistance = 0.0f,
float maxAngle = 0.0f, float maxAngle = 0.0f,
const std::vector<float> & roiRatios = std::vector<float>(), const std::vector<float> & roiRatios = std::vector<float>(),
const cv::Mat & projMask = cv::Mat(),
bool distanceToCamPolicy = false, bool distanceToCamPolicy = false,
const ProgressState * state = 0); const ProgressState * state = 0);
/** /**
@@ -326,6 +327,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > RTABMAP_EXP projectC
float maxDistance = 0.0f, float maxDistance = 0.0f,
float maxAngle = 0.0f, float maxAngle = 0.0f,
const std::vector<float> & roiRatios = std::vector<float>(), const std::vector<float> & roiRatios = std::vector<float>(),
const cv::Mat & projMask = cv::Mat(),
bool distanceToCamPolicy = false, bool distanceToCamPolicy = false,
const ProgressState * state = 0); const ProgressState * state = 0);
+121 -8
View File
@@ -160,9 +160,21 @@ inline pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr uniformSampling(
pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP randomSampling( pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
int samples); int samples);
pcl::PointCloud<pcl::PointNormal>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
int samples);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP randomSampling( pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
int samples); int samples);
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
int samples);
pcl::PointCloud<pcl::PointXYZI>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
int samples);
pcl::PointCloud<pcl::PointXYZINormal>::Ptr RTABMAP_EXP randomSampling(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
int samples);
pcl::IndicesPtr RTABMAP_EXP passThrough( pcl::IndicesPtr RTABMAP_EXP passThrough(
@@ -449,6 +461,99 @@ pcl::IndicesPtr RTABMAP_EXP radiusFiltering(
float radiusSearch, float radiusSearch,
int minNeighborsInRadius); int minNeighborsInRadius);
/* for convenience */
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
/**
* @brief Filter points based on distance from their viewpoint.
*
* @param cloud the input cloud.
* @param indices the input indices of the cloud to check, if empty, all points in the cloud are checked.
* @param viewpointIndices should be same size than the input cloud, it tells the viewpoint index in viewpoints for each point.
* @param viewpoints the viewpoints.
* @param factor will determine the search radius based on the distance from a point and its viewpoint. Setting it higher will filter points farther from accurate points (but processing time will be also higher).
* @param neighborScale will scale the search radius of neighbors found around a point. Setting it higher will accept more noisy points close to accurate points (but processing time will be also higher).
* @return the indices of the points satisfying the parameters.
*/
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
pcl::IndicesPtr RTABMAP_EXP proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor=0.01f,
float neighborScale=2.0f);
/** /**
* For convenience. * For convenience.
*/ */
@@ -592,13 +697,15 @@ pcl::IndicesPtr RTABMAP_EXP normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
/** /**
* @brief Given a normal and a maximum angle error, keep all points of the cloud * @brief Given a normal and a maximum angle error, keep all points of the cloud
@@ -622,42 +729,48 @@ pcl::IndicesPtr RTABMAP_EXP normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud, const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
pcl::IndicesPtr RTABMAP_EXP normalFiltering( pcl::IndicesPtr RTABMAP_EXP normalFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint); const Eigen::Vector4f & viewpoint,
float groundNormalsUp = 0.0f);
/** /**
* For convenience. * For convenience.
@@ -152,7 +152,8 @@ void segmentObstaclesFromGround(
bool segmentFlatObstacles = false, bool segmentFlatObstacles = false,
float maxGroundHeight = 0.0f, float maxGroundHeight = 0.0f,
pcl::IndicesPtr * flatObstacles = 0, pcl::IndicesPtr * flatObstacles = 0,
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0)); const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
float groundNormalsUp = 0);
template<typename PointT> template<typename PointT>
void segmentObstaclesFromGround( void segmentObstaclesFromGround(
const typename pcl::PointCloud<PointT>::Ptr & cloud, const typename pcl::PointCloud<PointT>::Ptr & cloud,
@@ -165,7 +166,8 @@ void segmentObstaclesFromGround(
bool segmentFlatObstacles = false, bool segmentFlatObstacles = false,
float maxGroundHeight = 0.0f, float maxGroundHeight = 0.0f,
pcl::IndicesPtr * flatObstacles = 0, pcl::IndicesPtr * flatObstacles = 0,
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0)); const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
float groundNormalsUp = 0);
template<typename PointT> template<typename PointT>
void occupancy2DFromGroundObstacles( void occupancy2DFromGroundObstacles(
+12 -3
View File
@@ -481,18 +481,27 @@ void RTABMAP_EXP adjustNormalsToViewPoints(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices, const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud); pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
float groundNormalsUp = 0.0f);
void RTABMAP_EXP adjustNormalsToViewPoints( void RTABMAP_EXP adjustNormalsToViewPoints(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices, const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud); pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
float groundNormalsUp = 0.0f);
void RTABMAP_EXP adjustNormalsToViewPoints(
const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
float groundNormalsUp = 0.0f);
void RTABMAP_EXP adjustNormalsToViewPoints( void RTABMAP_EXP adjustNormalsToViewPoints(
const std::map<int, Transform> & viewpoints, const std::map<int, Transform> & viewpoints,
const LaserScan & rawScan, const LaserScan & rawScan,
const std::vector<int> & viewpointIds, const std::vector<int> & viewpointIds,
LaserScan & scan); LaserScan & scan,
float groundNormalsUp = 0.0f);
pcl::PolygonMesh::Ptr RTABMAP_EXP meshDecimation(const pcl::PolygonMesh::Ptr & mesh, float factor); pcl::PolygonMesh::Ptr RTABMAP_EXP meshDecimation(const pcl::PolygonMesh::Ptr & mesh, float factor);
+35 -17
View File
@@ -93,6 +93,7 @@ SET(SRC_FILES
odometry/OdometryMSCKF.cpp odometry/OdometryMSCKF.cpp
odometry/OdometryVINS.cpp odometry/OdometryVINS.cpp
odometry/OdometryOpenVINS.cpp odometry/OdometryOpenVINS.cpp
odometry/OdometryOpen3D.cpp
IMU.cpp IMU.cpp
IMUThread.cpp IMUThread.cpp
@@ -142,6 +143,7 @@ IF(MSVC)
ENDIF(MSVC) ENDIF(MSVC)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}/../include
${PROJECT_SOURCE_DIR}/utilite/include ${PROJECT_SOURCE_DIR}/utilite/include
${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
@@ -193,7 +195,7 @@ IF(TORCH_FOUND)
) )
ENDIF(TORCH_FOUND) ENDIF(TORCH_FOUND)
IF(Python3_FOUND) IF(WITH_PYTHON AND Python3_FOUND)
SET(LIBRARIES SET(LIBRARIES
${LIBRARIES} ${LIBRARIES}
Python3::Python Python3::Python
@@ -209,7 +211,7 @@ IF(Python3_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/python ${CMAKE_CURRENT_SOURCE_DIR}/python
${INCLUDE_DIRS} ${INCLUDE_DIRS}
) )
ENDIF(Python3_FOUND) ENDIF(WITH_PYTHON AND Python3_FOUND)
@@ -371,18 +373,22 @@ ENDIF(WITH_TORO)
IF(G2O_FOUND) IF(G2O_FOUND)
IF(g2o_FOUND) IF(g2o_FOUND)
SET(LIBRARIES SET(LIBRARIES ${LIBRARIES}
${LIBRARIES}
g2o::core g2o::core
g2o::solver_cholmod
g2o::solver_eigen g2o::solver_eigen
g2o::solver_pcg g2o::solver_pcg
g2o::solver_csparse
g2o::csparse_extension
g2o::types_slam2d g2o::types_slam2d
g2o::types_slam3d g2o::types_slam3d
g2o::types_sba g2o::types_sba)
) IF(TARGET g2o::solver_csparse)
SET(LIBRARIES ${LIBRARIES}
g2o::solver_csparse
g2o::csparse_extension)
ENDIF(TARGET g2o::solver_csparse)
IF(TARGET g2o::solver_cholmod)
SET(LIBRARIES ${LIBRARIES}
g2o::solver_cholmod)
ENDIF(TARGET g2o::solver_cholmod)
ELSE() ELSE()
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${INCLUDE_DIRS} ${INCLUDE_DIRS}
@@ -393,13 +399,11 @@ IF(G2O_FOUND)
${G2O_LIBRARIES} ${G2O_LIBRARIES}
) )
ENDIF() ENDIF()
SET(SRC_FILES SET(SRC_FILES ${SRC_FILES}
${SRC_FILES}
optimizer/g2o/edge_se3_xyzprior.cpp optimizer/g2o/edge_se3_xyzprior.cpp
) )
IF(WITH_VERTIGO) IF(WITH_VERTIGO)
SET(SRC_FILES SET(SRC_FILES ${SRC_FILES}
${SRC_FILES}
optimizer/vertigo/g2o/edge_se2Switchable.cpp optimizer/vertigo/g2o/edge_se2Switchable.cpp
optimizer/vertigo/g2o/edge_se3Switchable.cpp optimizer/vertigo/g2o/edge_se3Switchable.cpp
optimizer/vertigo/g2o/edge_switchPrior.cpp optimizer/vertigo/g2o/edge_switchPrior.cpp
@@ -420,7 +424,7 @@ IF(cvsba_FOUND)
) )
ENDIF(cvsba_FOUND) ENDIF(cvsba_FOUND)
IF(CERES_FOUND) IF(WITH_CERES AND CERES_FOUND)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${INCLUDE_DIRS} ${INCLUDE_DIRS}
${CERES_INCLUDE_DIRS} ${CERES_INCLUDE_DIRS}
@@ -429,7 +433,7 @@ IF(CERES_FOUND)
${LIBRARIES} ${LIBRARIES}
${CERES_LIBRARIES} ${CERES_LIBRARIES}
) )
ENDIF(CERES_FOUND) ENDIF(WITH_CERES AND CERES_FOUND)
IF(libpointmatcher_FOUND) IF(libpointmatcher_FOUND)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
@@ -449,6 +453,13 @@ IF(CCCoreLib_FOUND)
) )
ENDIF(CCCoreLib_FOUND) ENDIF(CCCoreLib_FOUND)
IF(Open3D_FOUND)
SET(LIBRARIES
${LIBRARIES}
Open3D::Open3D
)
ENDIF(Open3D_FOUND)
IF(FastCV_FOUND) IF(FastCV_FOUND)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${INCLUDE_DIRS} ${INCLUDE_DIRS}
@@ -709,10 +720,10 @@ endforeach(arg ${RESOURCES})
#MESSAGE(STATUS "RESOURCES = ${RESOURCES}") #MESSAGE(STATUS "RESOURCES = ${RESOURCES}")
#MESSAGE(STATUS "RESOURCES_HEADERS = ${RESOURCES_HEADERS}") #MESSAGE(STATUS "RESOURCES_HEADERS = ${RESOURCES_HEADERS}")
IF(ANDROID) IF(ANDROID OR IOS)
IF(NOT RTABMAP_RES_TOOL) IF(NOT RTABMAP_RES_TOOL)
find_host_program(RTABMAP_RES_TOOL rtabmap-res_tool PATHS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) find_host_program(RTABMAP_RES_TOOL rtabmap-res_tool PATHS ${PROJECT_BINARY_DIR}/../bin)
IF(NOT RTABMAP_RES_TOOL) IF(NOT RTABMAP_RES_TOOL)
MESSAGE( FATAL_ERROR "RTABMAP_RES_TOOL is not defined (it is the path to \"rtabmap-res_tool\" application created by a non-Android build)." ) MESSAGE( FATAL_ERROR "RTABMAP_RES_TOOL is not defined (it is the path to \"rtabmap-res_tool\" application created by a non-Android build)." )
ENDIF(NOT RTABMAP_RES_TOOL) ENDIF(NOT RTABMAP_RES_TOOL)
@@ -765,4 +776,11 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include/
COMPONENT devel COMPONENT devel
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
PATTERN ".svn" EXCLUDE) PATTERN ".svn" EXCLUDE)
# For generated Version.h
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../include/
DESTINATION "${INSTALL_INCLUDE_DIR}"
COMPONENT devel
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
PATTERN ".svn" EXCLUDE)
+12 -1
View File
@@ -2089,7 +2089,18 @@ std::vector<cv::KeyPoint> SuperPointTorch::generateKeypointsImpl(const cv::Mat &
{ {
#ifdef RTABMAP_TORCH #ifdef RTABMAP_TORCH
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
UASSERT_MSG(roi.x==0 && roi.y ==0, "Not supporting ROI"); if(roi.x!=0 || roi.y !=0)
{
UERROR("SuperPoint: Not supporting ROI (%d,%d,%d,%d). Make sure %s, %s, %s, %s, %s, %s are all set to default values.",
roi.x, roi.y, roi.width, roi.height,
Parameters::kKpRoiRatios().c_str(),
Parameters::kVisRoiRatios().c_str(),
Parameters::kVisGridRows().c_str(),
Parameters::kVisGridCols().c_str(),
Parameters::kKpGridRows().c_str(),
Parameters::kKpGridCols().c_str());
return std::vector<cv::KeyPoint>();
}
return superPoint_->detect(image, mask); return superPoint_->detect(image, mask);
#else #else
UWARN("RTAB-Map is not built with Torch support so SuperPoint Torch feature cannot be used!"); UWARN("RTAB-Map is not built with Torch support so SuperPoint Torch feature cannot be used!");
+99 -123
View File
@@ -898,7 +898,8 @@ void computeMaxGraphErrors(
float & maxLinearError, float & maxLinearError,
float & maxAngularError, float & maxAngularError,
const Link ** maxLinearErrorLink, const Link ** maxLinearErrorLink,
const Link ** maxAngularErrorLink) const Link ** maxAngularErrorLink,
bool for3DoF)
{ {
maxLinearErrorRatio = -1; maxLinearErrorRatio = -1;
maxAngularErrorRatio = -1; maxAngularErrorRatio = -1;
@@ -918,7 +919,7 @@ void computeMaxGraphErrors(
float linearError = uMax3( float linearError = uMax3(
fabs(iter->second.transform().x() - t.x()), fabs(iter->second.transform().x() - t.x()),
fabs(iter->second.transform().y() - t.y()), fabs(iter->second.transform().y() - t.y()),
fabs(iter->second.transform().z() - t.z())); for3DoF?0:fabs(iter->second.transform().z() - t.z()));
UASSERT(iter->second.transVariance(false)>0.0); UASSERT(iter->second.transVariance(false)>0.0);
float stddevLinear = sqrt(iter->second.transVariance(false)); float stddevLinear = sqrt(iter->second.transVariance(false));
float linearErrorRatio = linearError/stddevLinear; float linearErrorRatio = linearError/stddevLinear;
@@ -937,8 +938,8 @@ void computeMaxGraphErrors(
t.getEulerAngles(opt_roll, opt_pitch, opt_yaw); t.getEulerAngles(opt_roll, opt_pitch, opt_yaw);
iter->second.transform().getEulerAngles(link_roll, link_pitch, link_yaw); iter->second.transform().getEulerAngles(link_roll, link_pitch, link_yaw);
float angularError = uMax3( float angularError = uMax3(
fabs(opt_roll - link_roll), for3DoF?0:fabs(opt_roll - link_roll),
fabs(opt_pitch - link_pitch), for3DoF?0:fabs(opt_pitch - link_pitch),
fabs(opt_yaw - link_yaw)); fabs(opt_yaw - link_yaw));
angularError = angularError>M_PI?2*M_PI-angularError:angularError; angularError = angularError>M_PI?2*M_PI-angularError:angularError;
UASSERT(iter->second.rotVariance(false)>0.0); UASSERT(iter->second.rotVariance(false)>0.0);
@@ -989,12 +990,13 @@ std::multimap<int, Link>::iterator findLink(
std::multimap<int, Link> & links, std::multimap<int, Link> & links,
int from, int from,
int to, int to,
bool checkBothWays) bool checkBothWays,
Link::Type type)
{ {
std::multimap<int, Link>::iterator iter = links.find(from); std::multimap<int, Link>::iterator iter = links.find(from);
while(iter != links.end() && iter->first == from) while(iter != links.end() && iter->first == from)
{ {
if(iter->second.to() == to) if(iter->second.to() == to && (type==Link::kUndef || type == iter->second.type()))
{ {
return iter; return iter;
} }
@@ -1007,7 +1009,7 @@ std::multimap<int, Link>::iterator findLink(
iter = links.find(to); iter = links.find(to);
while(iter != links.end() && iter->first == to) while(iter != links.end() && iter->first == to)
{ {
if(iter->second.to() == from) if(iter->second.to() == from && (type==Link::kUndef || type == iter->second.type()))
{ {
return iter; return iter;
} }
@@ -1335,7 +1337,7 @@ std::map<int, Transform> radiusPosesFiltering(
//pcl::IndicesPtr indicesOut(new std::vector<int>); //pcl::IndicesPtr indicesOut(new std::vector<int>);
//indicesOut->insert(indicesOut->end(), indicesKept.begin(), indicesKept.end()); //indicesOut->insert(indicesOut->end(), indicesKept.begin(), indicesKept.end());
UINFO("Cloud filtered In = %d, Out = %d", cloud->size(), indicesKept.size()); UINFO("Cloud filtered In = %d, Out = %d (radius=%f angle=%f keepLatest=%d)", cloud->size(), indicesKept.size(), radius, angle, keepLatest?1:0);
//pcl::io::savePCDFile("duplicateIn.pcd", *cloud); //pcl::io::savePCDFile("duplicateIn.pcd", *cloud);
//pcl::io::savePCDFile("duplicateOut.pcd", *cloud, *indicesOut); //pcl::io::savePCDFile("duplicateOut.pcd", *cloud, *indicesOut);
@@ -2078,12 +2080,12 @@ std::list<std::pair<int, Transform> > computePath(
} }
int findNearestNode( int findNearestNode(
const std::map<int, rtabmap::Transform> & nodes, const std::map<int, rtabmap::Transform> & poses,
const rtabmap::Transform & targetPose, const rtabmap::Transform & targetPose,
float * distance) float * distance)
{ {
int id = 0; int id = 0;
std::map<int, float> nearestNodes = findNearestNodes(nodes, targetPose, 1); std::map<int, float> nearestNodes = findNearestNodes(targetPose, poses, 0, 0, 1);
if(!nearestNodes.empty()) if(!nearestNodes.empty())
{ {
id = nearestNodes.begin()->first; id = nearestNodes.begin()->first;
@@ -2095,70 +2097,44 @@ int findNearestNode(
return id; return id;
} }
// return <id, sqrd distance>, excluding query
std::map<int, float> findNearestNodes( std::map<int, float> findNearestNodes(
const std::map<int, rtabmap::Transform> & nodes, int nodeId,
const rtabmap::Transform & targetPose, const std::map<int, Transform> & poses,
float radius,
float angle,
int k) int k)
{ {
std::map<int, float> nearestIds; UASSERT(uContains(poses, nodeId));
if(nodes.size() && !targetPose.isNull())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(nodes.size());
std::vector<int> ids(nodes.size());
int oi = 0;
for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
{
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
ids[oi++] = iter->first;
}
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>); std::map<int, Transform> nodesMinusTarget = poses;
kdTree->setInputCloud(cloud); Transform targetPose = poses.at(nodeId);
std::vector<int> ind;
std::vector<float> dist;
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
kdTree->nearestKSearch(pt, k, ind, dist);
for(unsigned int i=0; i<ind.size(); ++i)
{
nearestIds.insert(std::make_pair(ids[ind[i]], dist[i]));
}
}
return nearestIds;
}
// return <id, sqrd distance>, excluding query
std::map<int, float> getNodesInRadius(
int nodeId,
const std::map<int, Transform> & nodes,
float radius)
{
UASSERT(uContains(nodes, nodeId));
std::map<int, Transform> nodesMinusTarget = nodes;
Transform targetPose = nodes.at(nodeId);
nodesMinusTarget.erase(nodeId); nodesMinusTarget.erase(nodeId);
return getNodesInRadius(targetPose, nodesMinusTarget, radius); return findNearestNodes(targetPose, nodesMinusTarget, radius, angle, k);
} }
// return <id, sqrd distance>, excluding query // return <id, sqrd distance>
std::map<int, float> getNodesInRadius( std::map<int, float> findNearestNodes(
const Transform & targetPose, const Transform & targetPose,
const std::map<int, Transform> & nodes, const std::map<int, Transform> & poses,
float radius) float radius,
float angle,
int k)
{ {
UASSERT(radius>=0.0f);
UASSERT(k>=0);
UASSERT(radius > 0.0f || k>0);
std::map<int, float> foundNodes; std::map<int, float> foundNodes;
if(nodes.empty()) if(poses.empty())
{ {
return foundNodes; return foundNodes;
} }
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(nodes.size()); cloud->resize(poses.size());
std::vector<int> ids(nodes.size()); std::vector<int> ids(poses.size());
int oi = 0; int oi = 0;
for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter) for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{ {
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z()); (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str()); UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
@@ -2175,89 +2151,33 @@ std::map<int, float> getNodesInRadius(
std::vector<int> ind; std::vector<int> ind;
std::vector<float> sqrdDist; std::vector<float> sqrdDist;
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z()); pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0); if(radius>0.0f)
for(unsigned int i=0; i<ind.size(); ++i)
{ {
if(ind[i] >=0) kdTree->radiusSearch(pt, radius, ind, sqrdDist, k);
{ }
foundNodes.insert(std::make_pair(ids[ind[i]], sqrdDist[i])); else
} {
kdTree->nearestKSearch(pt, k, ind, sqrdDist);
} }
}
UDEBUG("found nodes=%d", (int)foundNodes.size());
return foundNodes;
}
// return <id, Transform>, excluding query
std::map<int, Transform> getPosesInRadius(
int nodeId,
const std::map<int, Transform> & nodes,
float radius,
float angle)
{
UASSERT(uContains(nodes, nodeId));
std::map<int, Transform> nodesMinusTarget = nodes;
Transform targetPose = nodes.at(nodeId);
nodesMinusTarget.erase(nodeId);
return getPosesInRadius(targetPose, nodesMinusTarget, radius, angle);
}
// return <id, Transform>, excluding query
std::map<int, Transform> getPosesInRadius(
const Transform & targetPose,
const std::map<int, Transform> & nodes,
float radius,
float angle)
{
std::map<int, Transform> foundNodes;
if(nodes.empty())
{
return foundNodes;
}
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(nodes.size());
std::vector<int> ids(nodes.size());
int oi = 0;
for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
{
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
ids[oi] = iter->first;
++oi;
}
cloud->resize(oi);
ids.resize(oi);
if(cloud->size())
{
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
kdTree->setInputCloud(cloud);
std::vector<int> ind;
std::vector<float> sqrdDist;
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0);
Eigen::Vector3f vA = targetPose.toEigen3f().linear()*Eigen::Vector3f(1,0,0); Eigen::Vector3f vA = targetPose.toEigen3f().linear()*Eigen::Vector3f(1,0,0);
for(unsigned int i=0; i<ind.size(); ++i) for(unsigned int i=0; i<ind.size(); ++i)
{ {
if(ind[i] >=0) if(ind[i] >=0)
{ {
if(angle > 0.0f) if(angle > 0.0f)
{ {
const Transform & checkT = nodes.at(ids[ind[i]]); const Transform & checkT = poses.at(ids[ind[i]]);
// same orientation? // same orientation?
Eigen::Vector3f vB = checkT.toEigen3f().linear()*Eigen::Vector3f(1,0,0); Eigen::Vector3f vB = checkT.toEigen3f().linear()*Eigen::Vector3f(1,0,0);
double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0)); double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
if(a <= angle) if(a <= angle)
{ {
foundNodes.insert(std::make_pair(ids[ind[i]], nodes.at(ids[ind[i]]))); foundNodes.insert(std::make_pair(ids[ind[i]], sqrdDist[i]));
} }
} }
else else
{ {
foundNodes.insert(std::make_pair(ids[ind[i]], nodes.at(ids[ind[i]]))); foundNodes.insert(std::make_pair(ids[ind[i]], sqrdDist[i]));
} }
} }
} }
@@ -2266,6 +2186,62 @@ std::map<int, Transform> getPosesInRadius(
return foundNodes; return foundNodes;
} }
// return <id, Transform>, excluding query
std::map<int, Transform> findNearestPoses(
int nodeId,
const std::map<int, Transform> & poses,
float radius,
float angle,
int k)
{
UASSERT(uContains(poses, nodeId));
std::map<int, Transform> nodesMinusTarget = poses;
Transform targetPose = poses.at(nodeId);
nodesMinusTarget.erase(nodeId);
return findNearestPoses(targetPose, nodesMinusTarget, radius, angle, k);
}
// return <id, Transform>
std::map<int, Transform> findNearestPoses(
const Transform & targetPose,
const std::map<int, Transform> & poses,
float radius,
float angle,
int k)
{
std::map<int, float> nearestNodes = findNearestNodes(targetPose, poses, radius, angle, k);
std::map<int, Transform> foundPoses;
for(std::map<int, float>::iterator iter=nearestNodes.begin(); iter!=nearestNodes.end(); ++iter)
{
foundPoses.insert(*poses.find(iter->first));
}
UDEBUG("found nodes=%d", (int)foundPoses.size());
return foundPoses;
}
// deprecated stuff
std::map<int, float> findNearestNodes(const std::map<int, rtabmap::Transform> & nodes, const rtabmap::Transform & targetPose, int k)
{
return findNearestNodes(targetPose, nodes, 0, 0, k);
}
std::map<int, float> getNodesInRadius(int nodeId, const std::map<int, Transform> & nodes, float radius)
{
return findNearestNodes(nodeId, nodes, radius);
}
std::map<int, float> getNodesInRadius(const Transform & targetPose, const std::map<int, Transform> & nodes, float radius)
{
return findNearestNodes(targetPose, nodes, radius);
}
std::map<int, Transform> getPosesInRadius(int nodeId, const std::map<int, Transform> & nodes, float radius, float angle)
{
return findNearestPoses(nodeId, nodes, radius, angle);
}
std::map<int, Transform> getPosesInRadius(const Transform & targetPose, const std::map<int, Transform> & nodes, float radius, float angle)
{
return findNearestPoses(targetPose, nodes, radius, angle);
}
float computePathLength( float computePathLength(
const std::vector<std::pair<int, Transform> > & path, const std::vector<std::pair<int, Transform> > & path,
unsigned int fromIndex, unsigned int fromIndex,
+3 -3
View File
@@ -368,8 +368,8 @@ LaserScan LaserScan::clone() const
float & LaserScan::field(unsigned int pointIndex, unsigned int channelOffset) float & LaserScan::field(unsigned int pointIndex, unsigned int channelOffset)
{ {
UASSERT(pointIndex < data_.cols); UASSERT(pointIndex < (unsigned int)data_.cols);
UASSERT(channelOffset < data_.channels()); UASSERT(channelOffset < (unsigned int)data_.channels());
return data_.ptr<float>(0, pointIndex)[channelOffset]; return data_.ptr<float>(0, pointIndex)[channelOffset];
} }
@@ -387,7 +387,7 @@ LaserScan LaserScan::operator+(const LaserScan & scan)
{ {
if(this->empty()) if(this->empty())
{ {
dest = LaserScan(scan.data().clone(), 0, 0, this->format()); dest = scan.clone();
} }
else else
{ {
+218 -15
View File
@@ -98,6 +98,7 @@ Memory::Memory(const ParametersMap & parameters) :
_laserScanVoxelSize(Parameters::defaultMemLaserScanVoxelSize()), _laserScanVoxelSize(Parameters::defaultMemLaserScanVoxelSize()),
_laserScanNormalK(Parameters::defaultMemLaserScanNormalK()), _laserScanNormalK(Parameters::defaultMemLaserScanNormalK()),
_laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()), _laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()),
_laserScanGroundNormalsUp(Parameters::defaultIcpPointToPlaneGroundNormalsUp()),
_reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()), _reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()),
_localBundleOnLoopClosure(Parameters::defaultRGBDLocalBundleOnLoopClosure()), _localBundleOnLoopClosure(Parameters::defaultRGBDLocalBundleOnLoopClosure()),
_rehearsalMaxDistance(Parameters::defaultRGBDLinearUpdate()), _rehearsalMaxDistance(Parameters::defaultRGBDLinearUpdate()),
@@ -565,6 +566,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
Parameters::parse(params, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize); Parameters::parse(params, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize);
Parameters::parse(params, Parameters::kMemLaserScanNormalK(), _laserScanNormalK); Parameters::parse(params, Parameters::kMemLaserScanNormalK(), _laserScanNormalK);
Parameters::parse(params, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius); Parameters::parse(params, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius);
Parameters::parse(params, Parameters::kIcpPointToPlaneGroundNormalsUp(), _laserScanGroundNormalsUp);
Parameters::parse(params, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures); Parameters::parse(params, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures);
Parameters::parse(params, Parameters::kRGBDLocalBundleOnLoopClosure(), _localBundleOnLoopClosure); Parameters::parse(params, Parameters::kRGBDLocalBundleOnLoopClosure(), _localBundleOnLoopClosure);
Parameters::parse(params, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance); Parameters::parse(params, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance);
@@ -2523,6 +2525,14 @@ int Memory::getSignatureIdByLabel(const std::string & label, bool lookInDatabase
if(id == 0 && _dbDriver && lookInDatabase) if(id == 0 && _dbDriver && lookInDatabase)
{ {
_dbDriver->getNodeIdByLabel(label, id); _dbDriver->getNodeIdByLabel(label, id);
if(_signatures.find(id) != _signatures.end())
{
// The signature is already in WM, but label was not
// found above. It means the label has been cleared in
// current session (not yet saved to database), so return
// not found.
id = 0;
}
} }
} }
return id; return id;
@@ -2532,15 +2542,35 @@ bool Memory::labelSignature(int id, const std::string & label)
{ {
// verify that this label is not used // verify that this label is not used
int idFound=getSignatureIdByLabel(label); int idFound=getSignatureIdByLabel(label);
if(idFound == 0 && label.empty() && _labels.find(id)==_labels.end())
{
UWARN("Trying to remove label from node %d but it has already no label", id);
return false;
}
if(idFound == 0 || idFound == id) if(idFound == 0 || idFound == id)
{ {
Signature * s = this->_getSignature(id); Signature * s = this->_getSignature(id);
if(s) if(s)
{ {
uInsert(_labels, std::make_pair(s->id(), label)); if(label.empty())
{
UWARN("Label \"%s\" removed from node %d", _labels.at(id).c_str(), id);
_labels.erase(id);
}
else
{
if(_labels.find(id)!=_labels.end())
{
UWARN("Label \"%s\" set to node %d (previously labeled \"%s\")", label.c_str(), id, _labels.at(id).c_str());
}
else
{
UWARN("Label \"%s\" set to node %d", label.c_str(), id);
}
uInsert(_labels, std::make_pair(s->id(), label));
}
s->setLabel(label); s->setLabel(label);
_linksChanged = s->isSaved(); // HACK to get label updated in Localization mode _linksChanged = s->isSaved(); // HACK to get label updated in Localization mode
UWARN("Label \"%s\" set to node %d", label.c_str(), id);
return true; return true;
} }
else if(_dbDriver) else if(_dbDriver)
@@ -2551,9 +2581,25 @@ bool Memory::labelSignature(int id, const std::string & label)
_dbDriver->loadSignatures(ids,signatures); _dbDriver->loadSignatures(ids,signatures);
if(signatures.size()) if(signatures.size())
{ {
uInsert(_labels, std::make_pair(signatures.front()->id(), label)); if(label.empty())
{
UWARN("Label \"%s\" removed from node %d", _labels.at(id).c_str(), id);
_labels.erase(id);
}
else
{
if(_labels.find(id)!=_labels.end())
{
UWARN("Label \"%s\" set to node %d (previously labeled \"%s\")", label.c_str(), id, _labels.at(id).c_str());
}
else
{
UWARN("Label \"%s\" set to node %d", label.c_str(), id);
}
uInsert(_labels, std::make_pair(id, label));
}
signatures.front()->setLabel(label); signatures.front()->setLabel(label);
UWARN("Label \"%s\" set to node %d", label.c_str(), id);
_dbDriver->asyncSave(signatures.front()); // move it again to trash _dbDriver->asyncSave(signatures.front()); // move it again to trash
return true; return true;
} }
@@ -2565,7 +2611,7 @@ bool Memory::labelSignature(int id, const std::string & label)
} }
else if(idFound) else if(idFound)
{ {
UWARN("Node %d has already label \"%s\"", idFound, label.c_str()); UWARN("Another node %d has already label \"%s\", cannot set it to node %d", idFound, label.c_str(), id);
} }
return false; return false;
} }
@@ -2732,13 +2778,13 @@ Transform Memory::computeTransform(
// make sure we have all data needed // make sure we have all data needed
// load binary data from database if not in RAM (if image is already here, scan and userData should be or they are null) // load binary data from database if not in RAM (if image is already here, scan and userData should be or they are null)
if(((_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) && fromS.sensorData().imageCompressed().empty()) || if(((_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull())) && fromS.sensorData().imageCompressed().empty()) ||
(_registrationPipeline->isScanRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().laserScanCompressed().isEmpty()) || (_registrationPipeline->isScanRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().laserScanCompressed().isEmpty()) ||
(_registrationPipeline->isUserDataRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().userDataCompressed().empty())) (_registrationPipeline->isUserDataRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().userDataCompressed().empty()))
{ {
fromS.sensorData() = getNodeData(fromS.id(), true, true, true, true); fromS.sensorData() = getNodeData(fromS.id(), true, true, true, true);
} }
if(((_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) && toS.sensorData().imageCompressed().empty()) || if(((_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull())) && toS.sensorData().imageCompressed().empty()) ||
(_registrationPipeline->isScanRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().laserScanCompressed().isEmpty()) || (_registrationPipeline->isScanRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().laserScanCompressed().isEmpty()) ||
(_registrationPipeline->isUserDataRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().userDataCompressed().empty())) (_registrationPipeline->isUserDataRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().userDataCompressed().empty()))
{ {
@@ -2748,27 +2794,27 @@ Transform Memory::computeTransform(
cv::Mat imgBuf, depthBuf, userBuf; cv::Mat imgBuf, depthBuf, userBuf;
LaserScan laserBuf; LaserScan laserBuf;
fromS.sensorData().uncompressData( fromS.sensorData().uncompressData(
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&imgBuf:0, (_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull()))?&imgBuf:0,
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&depthBuf:0, (_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull()))?&depthBuf:0,
_registrationPipeline->isScanRequired()?&laserBuf:0, _registrationPipeline->isScanRequired()?&laserBuf:0,
_registrationPipeline->isUserDataRequired()?&userBuf:0); _registrationPipeline->isUserDataRequired()?&userBuf:0);
toS.sensorData().uncompressData( toS.sensorData().uncompressData(
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&imgBuf:0, (_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull()))?&imgBuf:0,
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&depthBuf:0, (_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull()))?&depthBuf:0,
_registrationPipeline->isScanRequired()?&laserBuf:0, _registrationPipeline->isScanRequired()?&laserBuf:0,
_registrationPipeline->isUserDataRequired()?&userBuf:0); _registrationPipeline->isUserDataRequired()?&userBuf:0);
// compute transform fromId -> toId // compute transform fromId -> toId
std::vector<int> inliersV; std::vector<int> inliersV;
if((_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) || if((_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull())) ||
(fromS.getWords().size() && toS.getWords().size()) || (fromS.getWords().size() && toS.getWords().size()) ||
(!guess.isNull() && !_registrationPipeline->isImageRequired())) (!guess.isNull() && !_registrationPipeline->isImageRequired()))
{ {
Signature tmpFrom = fromS; Signature tmpFrom = fromS;
Signature tmpTo = toS; Signature tmpTo = toS;
if(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) if(_reextractLoopClosureFeatures && (_registrationPipeline->isImageRequired() || guess.isNull()))
{ {
UDEBUG(""); UDEBUG("");
tmpFrom.removeAllWords(); tmpFrom.removeAllWords();
@@ -4666,6 +4712,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
{ {
if(!imagesRectified && decimatedData.cameraModels().size()) if(!imagesRectified && decimatedData.cameraModels().size())
{ {
UASSERT_MSG((int)keypoints.size() == descriptors.rows, uFormat("%d vs %d", (int)keypoints.size(), descriptors.rows).c_str());
std::vector<cv::KeyPoint> keypointsValid; std::vector<cv::KeyPoint> keypointsValid;
keypointsValid.reserve(keypoints.size()); keypointsValid.reserve(keypoints.size());
cv::Mat descriptorsValid; cv::Mat descriptorsValid;
@@ -4859,6 +4906,144 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
UASSERT_MSG(imagesRectified, "Cannot extract descriptors on not rectified image from keypoints which assumed to be undistorted"); UASSERT_MSG(imagesRectified, "Cannot extract descriptors on not rectified image from keypoints which assumed to be undistorted");
descriptors = _feature2D->generateDescriptors(imageMono, keypoints); descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
} }
else if(!imagesRectified && !data.cameraModels().empty())
{
std::vector<cv::KeyPoint> keypointsValid;
keypointsValid.reserve(keypoints.size());
cv::Mat descriptorsValid;
descriptorsValid.reserve(descriptors.rows);
std::vector<cv::Point3f> keypoints3DValid;
keypoints3DValid.reserve(keypoints3D.size());
//undistort keypoints before projection (RGB-D)
if(data.cameraModels().size() == 1)
{
std::vector<cv::Point2f> pointsIn, pointsOut;
cv::KeyPoint::convert(keypoints,pointsIn);
if(data.cameraModels()[0].D_raw().cols == 6)
{
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = data.cameraModels()[0].D_raw().at<double>(0,0);
D.at<double>(0,1) = data.cameraModels()[0].D_raw().at<double>(0,1);
D.at<double>(0,2) = data.cameraModels()[0].D_raw().at<double>(0,4);
D.at<double>(0,3) = data.cameraModels()[0].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[0].K_raw(),
D,
data.cameraModels()[0].R(),
data.cameraModels()[0].P());
}
else
#else
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
}
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[0].K_raw(),
data.cameraModels()[0].D_raw(),
data.cameraModels()[0].R(),
data.cameraModels()[0].P());
}
UASSERT(pointsOut.size() == keypoints.size());
for(unsigned int i=0; i<pointsOut.size(); ++i)
{
if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<data.cameraModels()[0].imageWidth() &&
pointsOut.at(i).y>=0 && pointsOut.at(i).y<data.cameraModels()[0].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut.at(i).x;
keypointsValid.back().pt.y = pointsOut.at(i).y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{
keypoints3DValid.push_back(keypoints3D.at(i));
}
}
}
}
else
{
float subImageWidth;
if(!data.imageRaw().empty())
{
UASSERT(int((data.imageRaw().cols/data.cameraModels().size())*data.cameraModels().size()) == data.imageRaw().cols);
subImageWidth = data.imageRaw().cols/data.cameraModels().size();
}
else
{
UASSERT(data.cameraModels()[0].imageWidth()>0);
subImageWidth = data.cameraModels()[0].imageWidth();
}
for(unsigned int i=0; i<keypoints.size(); ++i)
{
int cameraIndex = int(keypoints.at(i).pt.x / subImageWidth);
UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (int)data.cameraModels().size(),
uFormat("cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
cameraIndex, (int)data.cameraModels().size(), keypoints[i].pt.x, subImageWidth, data.cameraModels()[0].imageWidth()).c_str());
std::vector<cv::Point2f> pointsIn, pointsOut;
pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y));
if(data.cameraModels()[cameraIndex].D_raw().cols == 6)
{
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,0);
D.at<double>(0,1) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,1);
D.at<double>(0,2) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,4);
D.at<double>(0,3) = data.cameraModels()[cameraIndex].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(),
D,
data.cameraModels()[cameraIndex].R(),
data.cameraModels()[cameraIndex].P());
}
else
#else
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
}
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
data.cameraModels()[cameraIndex].K_raw(),
data.cameraModels()[cameraIndex].D_raw(),
data.cameraModels()[cameraIndex].R(),
data.cameraModels()[cameraIndex].P());
}
if(pointsOut[0].x>=0 && pointsOut[0].x<data.cameraModels()[cameraIndex].imageWidth() &&
pointsOut[0].y>=0 && pointsOut[0].y<data.cameraModels()[cameraIndex].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex;
keypointsValid.back().pt.y = pointsOut[0].y;
descriptorsValid.push_back(descriptors.row(i));
if(!keypoints3D.empty())
{
keypoints3DValid.push_back(keypoints3D.at(i));
}
}
}
}
keypoints = keypointsValid;
descriptors = descriptorsValid;
keypoints3D = keypoints3DValid;
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f);
UDEBUG("time rectification = %fs", t);
}
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t); UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
@@ -5297,7 +5482,8 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
0, 0,
_laserScanVoxelSize, _laserScanVoxelSize,
_laserScanNormalK, _laserScanNormalK,
_laserScanNormalRadius); _laserScanNormalRadius,
_laserScanGroundNormalsUp);
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemScan_filtering(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemScan_filtering(), t*1000.0f);
UDEBUG("time normals scan = %fs", t); UDEBUG("time normals scan = %fs", t);
@@ -5648,7 +5834,24 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
} }
} }
Link landmark(s->id(), landmarkId, Link::kLandmark, iter->second.pose(), iter->second.covariance().inv(), landmarkSize);
Transform landmarkPose = iter->second.pose();
if(_registrationPipeline->force3DoF())
{
// For 2D slam, make sure the landmark z axis is up
rtabmap::Transform tx = landmarkPose.rotation() * rtabmap::Transform(1,0,0,0,0,0);
rtabmap::Transform ty = landmarkPose.rotation() * rtabmap::Transform(0,1,0,0,0,0);
if(fabs(tx.z()) > 0.9)
{
landmarkPose*=rtabmap::Transform(0,0,0,0,(tx.z()>0?1:-1)*M_PI/2,0);
}
else if(fabs(ty.z()) > 0.9)
{
landmarkPose*=rtabmap::Transform(0,0,0,(ty.z()>0?-1:1)*M_PI/2,0,0);
}
}
Link landmark(s->id(), landmarkId, Link::kLandmark, landmarkPose, iter->second.covariance().inv(), landmarkSize);
s->addLandmark(landmark); s->addLandmark(landmark);
// Update landmark index // Update landmark index
+11 -6
View File
@@ -56,6 +56,7 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
projMapFrame_(Parameters::defaultGridMapFrameProjection()), projMapFrame_(Parameters::defaultGridMapFrameProjection()),
maxObstacleHeight_(Parameters::defaultGridMaxObstacleHeight()), maxObstacleHeight_(Parameters::defaultGridMaxObstacleHeight()),
normalKSearch_(Parameters::defaultGridNormalK()), normalKSearch_(Parameters::defaultGridNormalK()),
groundNormalsUp_(Parameters::defaultIcpPointToPlaneGroundNormalsUp()),
maxGroundAngle_(Parameters::defaultGridMaxGroundAngle()*M_PI/180.0f), maxGroundAngle_(Parameters::defaultGridMaxGroundAngle()*M_PI/180.0f),
clusterRadius_(Parameters::defaultGridClusterRadius()), clusterRadius_(Parameters::defaultGridClusterRadius()),
minClusterSize_(Parameters::defaultGridMinClusterSize()), minClusterSize_(Parameters::defaultGridMinClusterSize()),
@@ -115,6 +116,7 @@ void OccupancyGrid::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kGridMinGroundHeight(), minGroundHeight_); Parameters::parse(parameters, Parameters::kGridMinGroundHeight(), minGroundHeight_);
Parameters::parse(parameters, Parameters::kGridMaxGroundHeight(), maxGroundHeight_); Parameters::parse(parameters, Parameters::kGridMaxGroundHeight(), maxGroundHeight_);
Parameters::parse(parameters, Parameters::kGridNormalK(), normalKSearch_); Parameters::parse(parameters, Parameters::kGridNormalK(), normalKSearch_);
Parameters::parse(parameters, Parameters::kIcpPointToPlaneGroundNormalsUp(), groundNormalsUp_);
if(Parameters::parse(parameters, Parameters::kGridMaxGroundAngle(), maxGroundAngle_)) if(Parameters::parse(parameters, Parameters::kGridMaxGroundAngle(), maxGroundAngle_))
{ {
maxGroundAngle_ *= M_PI/180.0f; maxGroundAngle_ *= M_PI/180.0f;
@@ -336,10 +338,11 @@ void OccupancyGrid::createLocalMap(
const Transform & t = node.sensorData().laserScanRaw().localTransform(); const Transform & t = node.sensorData().laserScanRaw().localTransform();
LaserScan scan = util3d::downsample(node.sensorData().laserScanRaw(), scanDecimation_); LaserScan scan = util3d::downsample(node.sensorData().laserScanRaw(), scanDecimation_);
#ifdef RTABMAP_OCTOMAP #ifdef RTABMAP_OCTOMAP
// clipping will be done in OctoMap // If ray tracing enabled, clipping will be done in OctoMap or in occupancy2DFromLaserScan()
float maxRange = grid3D_&&rayTracing_?0.0f:cloudMaxDepth_; float maxRange = rayTracing_?0.0f:cloudMaxDepth_;
#else #else
float maxRange = cloudMaxDepth_; // If ray tracing enabled, clipping will be done in occupancy2DFromLaserScan()
float maxRange = !grid3D_ && rayTracing_?0.0f:cloudMaxDepth_;
#endif #endif
if(cloudMinDepth_ > 0.0f || maxRange > 0.0f) if(cloudMinDepth_ > 0.0f || maxRange > 0.0f)
{ {
@@ -390,10 +393,11 @@ void OccupancyGrid::createLocalMap(
node.sensorData(), node.sensorData(),
cloudDecimation_, cloudDecimation_,
#ifdef RTABMAP_OCTOMAP #ifdef RTABMAP_OCTOMAP
// clipping will be done in OctoMap // If ray tracing enabled, clipping will be done in OctoMap or in occupancy2DFromLaserScan()
grid3D_&&rayTracing_?0.0f:cloudMaxDepth_, rayTracing_?0.0f:cloudMaxDepth_,
#else #else
cloudMaxDepth_, // If ray tracing enabled, clipping will be done in occupancy2DFromLaserScan()
!grid3D_&&rayTracing_?0.0f:cloudMaxDepth_,
#endif #endif
cloudMinDepth_, cloudMinDepth_,
indices.get(), indices.get(),
@@ -401,6 +405,7 @@ void OccupancyGrid::createLocalMap(
roiRatios_); roiRatios_);
// update viewpoint // update viewpoint
viewPoint = cv::Point3f(0,0,0);
if(node.sensorData().cameraModels().size()) if(node.sensorData().cameraModels().size())
{ {
// average of all local transforms // average of all local transforms
+31 -6
View File
@@ -106,6 +106,23 @@ bool RtabmapColorOcTreeNode::createChild(unsigned int i) {
#endif #endif
} }
void RtabmapColorOcTreeNode::updateOccupancyTypeChildren()
{
if (children != NULL){
int type = kTypeUnknown;
for (int i=0; i<8 && type != kTypeObstacle; i++) {
RtabmapColorOcTreeNode* child = static_cast<RtabmapColorOcTreeNode*>(children[i]);
if (child != NULL && child->getOccupancyType() >= kTypeEmpty) {
if(type == kTypeUnknown) {
type = child->getOccupancyType();
}
}
}
type_ = type;
}
}
RtabmapColorOcTree::RtabmapColorOcTree(double resolution) RtabmapColorOcTree::RtabmapColorOcTree(double resolution)
: OccupancyOcTreeBase<RtabmapColorOcTreeNode>(resolution) { : OccupancyOcTreeBase<RtabmapColorOcTreeNode>(resolution) {
RtabmapColorOcTreeMemberInit.ensureLinking(); RtabmapColorOcTreeMemberInit.ensureLinking();
@@ -231,6 +248,7 @@ void RtabmapColorOcTree::updateInnerOccupancyRecurs(RtabmapColorOcTreeNode* node
} }
node->updateOccupancyChildren(); node->updateOccupancyChildren();
node->updateColorChildren(); node->updateColorChildren();
node->updateOccupancyTypeChildren();
} }
#else #else
// only recurse and update for inner nodes: // only recurse and update for inner nodes:
@@ -245,6 +263,7 @@ void RtabmapColorOcTree::updateInnerOccupancyRecurs(RtabmapColorOcTreeNode* node
} }
node->updateOccupancyChildren(); node->updateOccupancyChildren();
node->updateColorChildren(); node->updateColorChildren();
node->updateOccupancyTypeChildren();
} }
#endif #endif
} }
@@ -872,7 +891,7 @@ bool OctoMap::update(const std::map<int, Transform> & poses)
} }
} }
RtabmapColorOcTreeNode * n = octree_->updateNode(*it, false, orderedPoses.size() == 1); RtabmapColorOcTreeNode * n = octree_->updateNode(*it, false, true);
if(n && n->getOccupancyType() == RtabmapColorOcTreeNode::kTypeUnknown) if(n && n->getOccupancyType() == RtabmapColorOcTreeNode::kTypeUnknown)
{ {
n->setOccupancyType(RtabmapColorOcTreeNode::kTypeEmpty); n->setOccupancyType(RtabmapColorOcTreeNode::kTypeEmpty);
@@ -938,6 +957,10 @@ bool OctoMap::update(const std::map<int, Transform> & poses)
} }
} }
} }
}
if((occupancyIter != cache_.end() && occupancyIter->second.second.cols) || !free_cells.empty())
{
octree_->updateInnerOccupancy(); octree_->updateInnerOccupancy();
} }
@@ -1209,21 +1232,23 @@ cv::Mat OctoMap::createProjectionMap(float & xMin, float & yMin, float & gridCel
int oi=0; int oi=0;
cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0); cv::Vec2f * oPtr = obstaclesMat.ptr<cv::Vec2f>(0,0);
cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0); cv::Vec2f * gPtr = groundMat.ptr<cv::Vec2f>(0,0);
float halfCellSize = octree_->getNodeSize(treeDepth)/2.0f;
for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it) for (RtabmapColorOcTree::iterator it = octree_->begin(treeDepth); it != octree_->end(); ++it)
{ {
octomap::point3d pt = octree_->keyToCoord(it.getKey()); octomap::point3d pt = octree_->keyToCoord(it.getKey());
if(octree_->isNodeOccupied(*it) && it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeObstacle) if(octree_->isNodeOccupied(*it) &&
it->getOccupancyType() == RtabmapColorOcTreeNode::kTypeObstacle)
{ {
// projected on ground // projected on ground
oPtr[oi][0] = pt.x(); oPtr[oi][0] = pt.x()-halfCellSize;
oPtr[oi][1] = pt.y(); oPtr[oi][1] = pt.y()-halfCellSize;
++oi; ++oi;
} }
else else
{ {
// projected on ground // projected on ground
gPtr[gi][0] = pt.x(); gPtr[gi][0] = pt.x()-halfCellSize;
gPtr[gi][1] = pt.y(); gPtr[gi][1] = pt.y()-halfCellSize;
++gi; ++gi;
} }
} }
+4
View File
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/odometry/OdometryMSCKF.h" #include "rtabmap/core/odometry/OdometryMSCKF.h"
#include "rtabmap/core/odometry/OdometryVINS.h" #include "rtabmap/core/odometry/OdometryVINS.h"
#include "rtabmap/core/odometry/OdometryOpenVINS.h" #include "rtabmap/core/odometry/OdometryOpenVINS.h"
#include "rtabmap/core/odometry/OdometryOpen3D.h"
#include "rtabmap/core/OdometryInfo.h" #include "rtabmap/core/OdometryInfo.h"
#include "rtabmap/core/util3d.h" #include "rtabmap/core/util3d.h"
#include "rtabmap/core/util3d_mapping.h" #include "rtabmap/core/util3d_mapping.h"
@@ -103,6 +104,9 @@ Odometry * Odometry::create(Odometry::Type & type, const ParametersMap & paramet
case Odometry::kTypeOpenVINS: case Odometry::kTypeOpenVINS:
odometry = new OdometryOpenVINS(parameters); odometry = new OdometryOpenVINS(parameters);
break; break;
case Odometry::kTypeOpen3D:
odometry = new OdometryOpen3D(parameters);
break;
default: default:
UERROR("Unknown odometry type %d, using F2M instead...", (int)type); UERROR("Unknown odometry type %d, using F2M instead...", (int)type);
odometry = new OdometryF2M(parameters); odometry = new OdometryF2M(parameters);
+23 -15
View File
@@ -190,7 +190,8 @@ void Optimizer::getConnectedGraph(
const std::map<int, Transform> & posesIn, const std::map<int, Transform> & posesIn,
const std::multimap<int, Link> & linksIn, const std::multimap<int, Link> & linksIn,
std::map<int, Transform> & posesOut, std::map<int, Transform> & posesOut,
std::multimap<int, Link> & linksOut) const std::multimap<int, Link> & linksOut,
bool adjustPosesWithConstraints) const
{ {
UDEBUG("IN: fromId=%d poses=%d links=%d priorsIgnored=%d landmarksIgnored=%d", fromId, (int)posesIn.size(), (int)linksIn.size(), priorsIgnored()?1:0, landmarksIgnored()?1:0); UDEBUG("IN: fromId=%d poses=%d links=%d priorsIgnored=%d landmarksIgnored=%d", fromId, (int)posesIn.size(), (int)linksIn.size(), priorsIgnored()?1:0, landmarksIgnored()?1:0);
UASSERT(fromId>0); UASSERT(fromId>0);
@@ -216,15 +217,15 @@ void Optimizer::getConnectedGraph(
while(nextPoses.size()) while(nextPoses.size())
{ {
int fromId = *nextPoses.rbegin(); // fill up all nodes before landmarks int currentId = *nextPoses.rbegin(); // fill up all nodes before landmarks
nextPoses.erase(*nextPoses.rbegin()); nextPoses.erase(*nextPoses.rbegin());
if(posesOut.empty()) if(posesOut.empty())
{ {
posesOut.insert(std::make_pair(fromId, posesIn.find(fromId)->second)); posesOut.insert(std::make_pair(currentId, posesIn.find(currentId)->second));
// add prior links // add prior links
for(std::multimap<int, Link>::const_iterator pter=linksIn.find(fromId); pter!=linksIn.end() && pter->first==fromId; ++pter) for(std::multimap<int, Link>::const_iterator pter=linksIn.find(currentId); pter!=linksIn.end() && pter->first==currentId; ++pter)
{ {
if(pter->second.from() == pter->second.to() && (!priorsIgnored() || pter->second.type() != Link::kPosePrior)) if(pter->second.from() == pter->second.to() && (!priorsIgnored() || pter->second.type() != Link::kPosePrior))
{ {
@@ -233,33 +234,40 @@ void Optimizer::getConnectedGraph(
} }
} }
for(std::multimap<int, int>::const_iterator iter=biLinks.find(fromId); iter!=biLinks.end() && iter->first==fromId; ++iter) for(std::multimap<int, int>::const_iterator iter=biLinks.find(currentId); iter!=biLinks.end() && iter->first==currentId; ++iter)
{ {
int toId = iter->second; int toId = iter->second;
if(posesIn.find(toId) != posesIn.end() && (!landmarksIgnored() || toId>0)) if(posesIn.find(toId) != posesIn.end() && (!landmarksIgnored() || toId>0))
{ {
std::multimap<int, Link>::const_iterator kter = graph::findLink(linksIn, fromId, toId); std::multimap<int, Link>::const_iterator kter = graph::findLink(linksIn, currentId, toId);
if(nextPoses.find(toId) == nextPoses.end()) if(nextPoses.find(toId) == nextPoses.end())
{ {
if(!uContains(posesOut, toId)) if(!uContains(posesOut, toId))
{ {
if(isSlam2d() && kter->second.type() == Link::kLandmark && toId>0) if(adjustPosesWithConstraints)
{ {
Transform t; if(isSlam2d() && kter->second.type() == Link::kLandmark && toId>0)
if(kter->second.from()==fromId)
{ {
t = kter->second.transform(); Transform t;
if(kter->second.from()==currentId)
{
t = kter->second.transform();
}
else
{
t = kter->second.transform().inverse();
}
posesOut.insert(std::make_pair(toId, (posesOut.at(currentId) * t).to3DoF()));
} }
else else
{ {
t = kter->second.transform().inverse(); Transform t = posesOut.at(currentId) * (kter->second.from()==currentId?kter->second.transform():kter->second.transform().inverse());
posesOut.insert(std::make_pair(toId, t));
} }
posesOut.insert(std::make_pair(toId, (posesOut.at(fromId) * t).to3DoF()));
} }
else else
{ {
Transform t = posesOut.at(fromId) * (kter->second.from()==fromId?kter->second.transform():kter->second.transform().inverse()); posesOut.insert(*posesIn.find(toId));
posesOut.insert(std::make_pair(toId, t));
} }
// add prior links // add prior links
for(std::multimap<int, Link>::const_iterator pter=linksIn.find(toId); pter!=linksIn.end() && pter->first==toId; ++pter) for(std::multimap<int, Link>::const_iterator pter=linksIn.find(toId); pter!=linksIn.end() && pter->first==toId; ++pter)
@@ -274,7 +282,7 @@ void Optimizer::getConnectedGraph(
} }
// only add unique links // only add unique links
if(graph::findLink(linksOut, fromId, toId) == linksOut.end()) if(graph::findLink(linksOut, currentId, toId) == linksOut.end())
{ {
if(kter->second.to() < 0) if(kter->second.to() < 0)
{ {
+7 -2
View File
@@ -136,7 +136,7 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
ParametersMap::const_iterator iter; ParametersMap::const_iterator iter;
if((iter=parameters.find(Parameters::kRtabmapWorkingDirectory())) != parameters.end()) if((iter=parameters.find(Parameters::kRtabmapWorkingDirectory())) != parameters.end())
{ {
_workingDir = iter->second; _workingDir = uReplaceChar(iter->second, '~', UDirectory::homeDir());
} }
bool pointToPlane = _pointToPlane; bool pointToPlane = _pointToPlane;
@@ -277,8 +277,12 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
#ifndef RTABMAP_CCCORELIB #ifndef RTABMAP_CCCORELIB
if(_strategy==2) if(_strategy==2)
{ {
UWARN("Parameter %s is set to true but RTAB-Map has not been built with CCCoreLib support. Setting to 0.", Parameters::kIcpStrategy().c_str()); #ifdef RTABMAP_POINTMATCHER
_strategy = 1;
#else
_strategy = 0; _strategy = 0;
#endif
UWARN("Parameter %s is set to 2 but RTAB-Map has not been built with CCCoreLib support. Setting to %d.", Parameters::kIcpStrategy().c_str(), _strategy);
} }
#else #else
if(_strategy==2 && _pointToPlane) if(_strategy==2 && _pointToPlane)
@@ -329,6 +333,7 @@ Transform RegistrationIcp::computeTransformationImpl(
UDEBUG("Max translation=%f", _maxTranslation); UDEBUG("Max translation=%f", _maxTranslation);
UDEBUG("Max rotation=%f", _maxRotation); UDEBUG("Max rotation=%f", _maxRotation);
UDEBUG("Downsampling step=%d", _downsamplingStep); UDEBUG("Downsampling step=%d", _downsamplingStep);
UDEBUG("Force 3DoF=%s", this->force3DoF()?"true":"false");
UDEBUG("Force 4DoF=%s", _force4DoF?"true":"false"); UDEBUG("Force 4DoF=%s", _force4DoF?"true":"false");
UDEBUG("Min Complexity=%f", _pointToPlaneMinComplexity); UDEBUG("Min Complexity=%f", _pointToPlaneMinComplexity);
UDEBUG("libpointmatcher (knn=%d, outlier ratio=%f)", _libpointmatcherKnn, _outlierRatio); UDEBUG("libpointmatcher (knn=%d, outlier ratio=%f)", _libpointmatcherKnn, _outlierRatio);
+745 -340
View File
File diff suppressed because it is too large Load Diff
+9 -2
View File
@@ -292,9 +292,16 @@ void RtabmapThread::mainLoop()
_rtabmap->clearPath(0); _rtabmap->clearPath(0);
break; break;
case kStateLabelling: case kStateLabelling:
if(!_rtabmap->labelLocation(atoi(parameters.at("id").c_str()), parameters.at("label").c_str())) if(!_rtabmap->labelLocation(atoi(parameters.at("id").c_str()), parameters.at("label")))
{ {
this->post(new RtabmapLabelErrorEvent(atoi(parameters.at("id").c_str()), parameters.at("label").c_str())); this->post(new RtabmapLabelErrorEvent(atoi(parameters.at("id").c_str()), parameters.at("label")));
}
break;
case kStateRemovingLabel:
id = _rtabmap->getMemory()->getSignatureIdByLabel(parameters.at("label"), true);
if(!_rtabmap->labelLocation(id, ""))
{
this->post(new RtabmapLabelErrorEvent(id, parameters.at("label")));
} }
break; break;
default: default:
+1 -1
View File
@@ -118,7 +118,7 @@ void Signature::addLinks(const std::map<int, Link> & links)
} }
void Signature::addLink(const Link & link) void Signature::addLink(const Link & link)
{ {
UDEBUG("Add link %d to %d (type=%d var=%f,%f)", link.to(), this->id(), (int)link.type(), link.transVariance(), link.rotVariance()); UDEBUG("Add link %d to %d (type=%d/%s var=%f,%f)", link.to(), this->id(), (int)link.type(), link.typeName().c_str(), link.transVariance(), link.rotVariance());
UASSERT_MSG(link.from() == this->id(), uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str()); UASSERT_MSG(link.from() == this->id(), uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str());
UASSERT_MSG((link.to() != this->id()) || link.type()==Link::kPosePrior || link.type()==Link::kGravity, uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str()); UASSERT_MSG((link.to() != this->id()) || link.type()==Link::kPosePrior || link.type()==Link::kGravity, uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str());
UASSERT_MSG(link.to() == this->id() || _links.find(link.to()) == _links.end(), uFormat("Link %d (type=%d) already added to signature %d!", link.to(), link.type(), this->id()).c_str()); UASSERT_MSG(link.to() == this->id() || _links.find(link.to()) == _links.end(), uFormat("Link %d (type=%d) already added to signature %d!", link.to(), link.type(), this->id()).c_str());
+14
View File
@@ -221,6 +221,20 @@ Transform Transform::to4DoF() const
return Transform(x,y,z, 0,0,yaw); return Transform(x,y,z, 0,0,yaw);
} }
bool Transform::is3DoF() const
{
return is4DoF() && z() == 0.0;
}
bool Transform::is4DoF() const
{
return r13() == 0.0 &&
r23() == 0.0 &&
r31() == 0.0 &&
r32() == 0.0 &&
r33() == 0.0;
}
cv::Mat Transform::rotationMatrix() const cv::Mat Transform::rotationMatrix() const
{ {
return data_.colRange(0, 3).clone(); return data_.colRange(0, 3).clone();
+11 -4
View File
@@ -178,8 +178,6 @@ void CameraOpenNI2::setOpenNI2StampsAndIDsUsed(bool used)
void CameraOpenNI2::setIRDepthShift(int horizontal, int vertical) void CameraOpenNI2::setIRDepthShift(int horizontal, int vertical)
{ {
#ifdef RTABMAP_OPENNI2 #ifdef RTABMAP_OPENNI2
UASSERT(horizontal >= 0);
UASSERT(vertical >= 0);
_depthHShift = horizontal; _depthHShift = horizontal;
_depthVShift = vertical; _depthVShift = vertical;
#endif #endif
@@ -538,10 +536,19 @@ SensorData CameraOpenNI2::captureImage(CameraInfo * info)
if(_type==kTypeColorDepth) if(_type==kTypeColorDepth)
{ {
if (_depthHShift > 0 || _depthVShift > 0) if (_depthHShift != 0 || _depthVShift != 0)
{ {
cv::Mat out = cv::Mat::zeros(depth.size(), depth.type()); cv::Mat out = cv::Mat::zeros(depth.size(), depth.type());
depth(cv::Rect(_depthHShift, _depthVShift, depth.cols - _depthHShift, depth.rows - _depthVShift)).copyTo(out(cv::Rect(0, 0, depth.cols - _depthHShift, depth.rows - _depthVShift))); depth(cv::Rect(
_depthHShift>0?_depthHShift:0,
_depthVShift>0?_depthVShift:0,
depth.cols - abs(_depthHShift),
depth.rows - abs(_depthVShift))).copyTo(
out(cv::Rect(
_depthHShift<0?-_depthHShift:0,
_depthVShift<0?-_depthVShift:0,
depth.cols - abs(_depthHShift),
depth.rows - abs(_depthVShift))));
depth = out; depth = out;
} }
+2 -3
View File
@@ -137,15 +137,14 @@ rtabmap::Transform icpCC(
icpTransformation.setNull(); icpTransformation.setNull();
return icpTransformation; return icpTransformation;
} }
else if(finalPointCount < 50) else if(!transform.R.isValid())
{ {
std::string msg = uFormat("CCCoreLib has failed: Rejecting transform as finalPointCount %d < 50 ", finalPointCount); std::string msg = uFormat("CCCoreLib has failed: Rotation matrix is invalid");
UDEBUG(msg.c_str()); UDEBUG(msg.c_str());
if(errorMsg) if(errorMsg)
{ {
*errorMsg = msg; *errorMsg = msg;
} }
icpTransformation.setNull(); icpTransformation.setNull();
return icpTransformation; return icpTransformation;
} }
+8 -1
View File
@@ -205,7 +205,14 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
{ {
cv::Mat newFrame; cv::Mat newFrame;
cv::cvtColor(data.imageRaw(), newFrame, cv::COLOR_BGR2GRAY); cv::cvtColor(data.imageRaw(), newFrame, cv::COLOR_BGR2GRAY);
data.setImageRaw(newFrame); if(data.stereoCameraModel().isValidForProjection())
{
data.setStereoImage(newFrame, data.rightRaw(), data.stereoCameraModel());
}
else
{
data.setRGBDImage(newFrame, data.depthRaw(), data.cameraModels());
}
} }
if(!localMap_.empty()) if(!localMap_.empty())
+306
View File
@@ -0,0 +1,306 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rtabmap/core/odometry/OdometryOpen3D.h"
#include "rtabmap/core/OdometryInfo.h"
#include "rtabmap/core/util2d.h"
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/utilite/UTimer.h"
#ifdef RTABMAP_OPEN3D
#include <open3d/pipelines/odometry/Odometry.h>
#include <open3d/geometry/RGBDImage.h>
#include <open3d/t/pipelines/odometry/RGBDOdometry.h>
#endif
namespace rtabmap {
/**
* https://github.com/laboshinl/loam_velodyne/pull/66
*/
OdometryOpen3D::OdometryOpen3D(const ParametersMap & parameters) :
Odometry(parameters)
#ifdef RTABMAP_OPEN3D
,method_(Parameters::defaultOdomOpen3DMethod()),
maxDepth_(Parameters::defaultOdomOpen3DMaxDepth()),
keyFrameThr_(Parameters::defaultOdomKeyFrameThr())
#endif
{
#ifdef RTABMAP_OPEN3D
Parameters::parse(parameters, Parameters::kOdomOpen3DMethod(), method_);
UASSERT(method_>=0 && method_<=2);
Parameters::parse(parameters, Parameters::kOdomOpen3DMaxDepth(), maxDepth_);
Parameters::parse(parameters, Parameters::kOdomKeyFrameThr(), keyFrameThr_);
#endif
}
OdometryOpen3D::~OdometryOpen3D()
{
}
void OdometryOpen3D::reset(const Transform & initialPose)
{
Odometry::reset(initialPose);
#ifdef RTABMAP_OPEN3D
keyFrame_ = SensorData();
lastKeyFramePose_.setNull();
#endif
}
#ifdef RTABMAP_OPEN3D
open3d::geometry::Image toOpen3D(const cv::Mat & image)
{
if(image.type() == CV_16UC1)
{
// convert to float
return toOpen3D(util2d::cvtDepthToFloat(image));
}
open3d::geometry::Image output;
output.width_ = image.cols;
output.height_ = image.rows;
output.num_of_channels_ = image.channels();
output.bytes_per_channel_ = image.elemSize()/image.channels();
output.data_.resize(image.total()*image.elemSize());
memcpy(output.data_.data(), image.data, output.data_.size());
return output;
}
open3d::geometry::RGBDImage toOpen3D(const SensorData & data)
{
return open3d::geometry::RGBDImage(
toOpen3D(data.imageRaw()),
toOpen3D(data.depthRaw()));
}
open3d::camera::PinholeCameraIntrinsic toOpen3D(const CameraModel & model)
{
return open3d::camera::PinholeCameraIntrinsic(
model.imageWidth(),
model.imageHeight(),
model.fx(),
model.fy(),
model.cx(),
model.cy());
}
//Tensor versions
open3d::t::geometry::Image toOpen3Dt(const cv::Mat & image)
{
if(image.type() == CV_16UC1)
{
// convert to float
return toOpen3Dt(util2d::cvtDepthToFloat(image));
}
if(image.type()==CV_32FC1)
{
return open3d::core::Tensor(
(const float_t*)image.data,
{image.rows, image.cols, image.channels()},
open3d::core::Float32);
}
else
{
return open3d::core::Tensor(
static_cast<const uint8_t*>(image.data),
{image.rows, image.cols, image.channels()},
open3d::core::UInt8);
}
}
open3d::t::geometry::RGBDImage toOpen3Dt(const SensorData & data)
{
return open3d::t::geometry::RGBDImage(
toOpen3Dt(data.imageRaw()),
toOpen3Dt(data.depthRaw()));
}
open3d::core::Tensor toOpen3Dt(const CameraModel & model)
{
return open3d::core::Tensor::Init<double>(
{{model.fx(), 0, model.cx()},
{0, model.fy(), model.cy()},
{0, 0, 1}});
}
open3d::core::Tensor toOpen3Dt(const Transform & t)
{
return open3d::core::Tensor::Init<double>(
{{t.r11(), t.r12(), t.r13(), t.x()},
{t.r21(), t.r22(), t.r23(), t.y()},
{t.r31(), t.r32(), t.r33(), t.z()},
{0,0,0,1}});
}
#endif
// return not null transform if odometry is correctly computed
Transform OdometryOpen3D::computeTransform(
SensorData & data,
const Transform & guess,
OdometryInfo * info)
{
Transform t;
#ifdef RTABMAP_OPEN3D
UTimer timer;
if(data.imageRaw().empty() || data.depthRaw().empty() || data.cameraModels().size()!=1)
{
UERROR("Open3D works only with single RGB-D data. Aborting odometry update...");
return t;
}
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1)*9999;
bool updateKeyFrame = false;
if(lastKeyFramePose_.isNull())
{
lastKeyFramePose_ = this->getPose(); // reset to current pose
}
Transform motionSinceLastKeyFrame = lastKeyFramePose_.inverse()*this->getPose();
if(keyFrame_.isValid())
{
/*bool tensor = true;
if(!tensor)
{
// Approach in open3d/pipelines/odometry
open3d::geometry::RGBDImage source = toOpen3D(data);
open3d::geometry::RGBDImage target = toOpen3D(keyFrame_);
open3d::camera::PinholeCameraIntrinsic intrinsics = toOpen3D(data.cameraModels()[0]);
UDEBUG("Data conversion to Open3D format: %fs", timer.ticks());
open3d::pipelines::odometry::OdometryOption option;
std::tuple<bool, Eigen::Matrix4d, Eigen::Matrix6d> ret = open3d::pipelines::odometry::ComputeRGBDOdometry(
source,
target,
intrinsics,
Eigen::Matrix4d::Identity(),
open3d::pipelines::odometry::RGBDOdometryJacobianFromHybridTerm(),
option);
UDEBUG("Compute Open3D odometry: %fs", timer.ticks());
if(std::get<0>(ret))
{
t = Transform::fromEigen4d(std::get<1>(ret));
// from camera frame to base frame
t = data.cameraModels()[0].localTransform() * t * data.cameraModels()[0].localTransform().inverse();
covariance = cv::Mat::eye(6,6,CV_64FC1)/100;
}
else
{
UWARN("Open3D odometry update failed!");
}
}
else*/
{
// Approach in open3d/t/pipelines/odometry
open3d::t::geometry::RGBDImage source = toOpen3Dt(data);
open3d::t::geometry::RGBDImage target = toOpen3Dt(keyFrame_);
open3d::core::Tensor intrinsics = toOpen3Dt(data.cameraModels()[0]);
Transform baseToCamera = data.cameraModels()[0].localTransform();
open3d::core::Tensor odomInit;
if(guess.isNull())
{
odomInit = open3d::core::Tensor::Eye(4, open3d::core::Float64, open3d::core::Device("CPU:0"));
}
else
{
odomInit = toOpen3Dt(baseToCamera.inverse() * (motionSinceLastKeyFrame*guess) * baseToCamera);
}
UDEBUG("Data conversion to Open3D format: %fs", timer.ticks());
open3d::t::pipelines::odometry::OdometryResult ret = open3d::t::pipelines::odometry::RGBDOdometryMultiScale(
source,
target,
intrinsics,
odomInit,
1.0f,
maxDepth_,
{10, 5, 3},
(open3d::t::pipelines::odometry::Method)method_,
open3d::t::pipelines::odometry::OdometryLossParams());
UDEBUG("Compute Open3D odometry: %fs", timer.ticks());
if(ret.fitness_!=0)
{
const double * ptr = (const double *)ret.transformation_.GetDataPtr();
t = Transform(
ptr[0], ptr[1], ptr[2], ptr[3],
ptr[4], ptr[5], ptr[6], ptr[7],
ptr[8], ptr[9], ptr[10],ptr[11]);
// from camera frame to base frame
t = baseToCamera * t * baseToCamera.inverse();
t = motionSinceLastKeyFrame.inverse() * t;
//based on values set in viso2_ros
covariance = cv::Mat::eye(6,6, CV_64FC1);
covariance.at<double>(0,0) = 0.002;
covariance.at<double>(1,1) = 0.002;
covariance.at<double>(2,2) = 0.05;
covariance.at<double>(3,3) = 0.09;
covariance.at<double>(4,4) = 0.09;
covariance.at<double>(5,5) = 0.09;
if(info)
{
info->reg.icpRMS = ret.inlier_rmse_;
info->reg.icpInliersRatio = ret.fitness_;
}
if(ret.fitness_ < keyFrameThr_)
{
updateKeyFrame = true;
}
}
else
{
UWARN("Open3D odometry update failed!");
}
}
}
else
{
t.setIdentity();
updateKeyFrame = true;
}
if(updateKeyFrame)
{
keyFrame_ = data;
lastKeyFramePose_.setNull();
}
if(info)
{
info->reg.covariance = covariance;
info->keyFrameAdded = updateKeyFrame;
}
#else
UERROR("RTAB-Map is not built with Open3D support! Select another odometry approach.");
#endif
return t;
}
} // namespace rtabmap
+98 -8
View File
@@ -137,6 +137,28 @@ bool OptimizerG2O::isCholmodAvailable()
#endif #endif
} }
OptimizerG2O::OptimizerG2O(const ParametersMap & parameters) :
Optimizer(parameters),
solver_(Parameters::defaultg2oSolver()),
optimizer_(Parameters::defaultg2oOptimizer()),
pixelVariance_(Parameters::defaultg2oPixelVariance()),
robustKernelDelta_(Parameters::defaultg2oRobustKernelDelta()),
baseline_(Parameters::defaultg2oBaseline())
{
#ifdef RTABMAP_G2O
// Issue on android, have to explicitly register this type when using fixed root prior below
if(!g2o::Factory::instance()->knowsTag("CACHE_SE3_OFFSET"))
{
#if defined(RTABMAP_G2O_CPP11) and RTABMAP_G2O_CPP11 == 1
g2o::Factory::instance()->registerType("CACHE_SE3_OFFSET", g2o::make_unique<g2o::HyperGraphElementCreator<g2o::CacheSE3Offset> >());
#else
g2o::Factory::instance()->registerType("CACHE_SE3_OFFSET", new g2o::HyperGraphElementCreator<g2o::CacheSE3Offset>);
#endif
}
#endif
parseParameters(parameters);
}
void OptimizerG2O::parseParameters(const ParametersMap & parameters) void OptimizerG2O::parseParameters(const ParametersMap & parameters)
{ {
Optimizer::parseParameters(parameters); Optimizer::parseParameters(parameters);
@@ -310,14 +332,28 @@ std::map<int, Transform> OptimizerG2O::optimize(
} }
#endif #endif
// detect if there is a global pose prior set, if so remove rootId // detect if there is a global pose prior set, if so remove rootId
if(!priorsIgnored()) bool hasGravityConstraints = false;
if(!priorsIgnored() || (!isSlam2d() && gravitySigma() > 0))
{ {
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter) for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
if(iter->second.from() == iter->second.to() && iter->second.type() == Link::kPosePrior) if(iter->second.from() == iter->second.to())
{ {
rootId = 0; if(!priorsIgnored() && iter->second.type() == Link::kPosePrior)
break; {
rootId = 0;
break;
}
else if(!isSlam2d() &&
gravitySigma() > 0 &&
iter->second.type() == Link::kGravity)
{
hasGravityConstraints = true;
if(priorsIgnored())
{
break;
}
}
} }
} }
} }
@@ -325,7 +361,7 @@ std::map<int, Transform> OptimizerG2O::optimize(
int landmarkVertexOffset = poses.rbegin()->first+1; int landmarkVertexOffset = poses.rbegin()->first+1;
std::map<int, bool> isLandmarkWithRotation; std::map<int, bool> isLandmarkWithRotation;
UDEBUG("fill poses to g2o..."); UDEBUG("fill poses to g2o... (rootId=%d hasGravityConstraints=%d isSlam2d=%d)", rootId, hasGravityConstraints?1:0, isSlam2d()?1:0);
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{ {
UASSERT(!iter->second.isNull()); UASSERT(!iter->second.isNull());
@@ -339,6 +375,7 @@ std::map<int, Transform> OptimizerG2O::optimize(
v2->setEstimate(g2o::SE2(iter->second.x(), iter->second.y(), iter->second.theta())); v2->setEstimate(g2o::SE2(iter->second.x(), iter->second.y(), iter->second.theta()));
if(id == rootId) if(id == rootId)
{ {
UDEBUG("Set %d fixed", id);
v2->setFixed(true); v2->setFixed(true);
} }
vertex = v2; vertex = v2;
@@ -361,6 +398,11 @@ std::map<int, Transform> OptimizerG2O::optimize(
{ {
g2o::VertexSE2 * v2 = new g2o::VertexSE2(); g2o::VertexSE2 * v2 = new g2o::VertexSE2();
v2->setEstimate(g2o::SE2(iter->second.x(), iter->second.y(), iter->second.theta())); v2->setEstimate(g2o::SE2(iter->second.x(), iter->second.y(), iter->second.theta()));
if(id == rootId)
{
UDEBUG("Set %d fixed", id);
v2->setFixed(true);
}
vertex = v2; vertex = v2;
isLandmarkWithRotation.insert(std::make_pair(id, true)); isLandmarkWithRotation.insert(std::make_pair(id, true));
id = landmarkVertexOffset - id; id = landmarkVertexOffset - id;
@@ -382,8 +424,9 @@ std::map<int, Transform> OptimizerG2O::optimize(
pose = a.linear(); pose = a.linear();
pose.translation() = a.translation(); pose.translation() = a.translation();
v3->setEstimate(pose); v3->setEstimate(pose);
if(id == rootId) if(id == rootId && !hasGravityConstraints)
{ {
UDEBUG("Set %d fixed", id);
v3->setFixed(true); v3->setFixed(true);
} }
vertex = v3; vertex = v3;
@@ -412,6 +455,11 @@ std::map<int, Transform> OptimizerG2O::optimize(
pose = a.linear(); pose = a.linear();
pose.translation() = a.translation(); pose.translation() = a.translation();
v3->setEstimate(pose); v3->setEstimate(pose);
if(id == rootId && !hasGravityConstraints)
{
UDEBUG("Set %d fixed", id);
v3->setFixed(true);
}
vertex = v3; vertex = v3;
isLandmarkWithRotation.insert(std::make_pair(id, true)); isLandmarkWithRotation.insert(std::make_pair(id, true));
id = landmarkVertexOffset - id; id = landmarkVertexOffset - id;
@@ -422,8 +470,50 @@ std::map<int, Transform> OptimizerG2O::optimize(
continue; continue;
} }
} }
vertex->setId(id); if(vertex == 0)
UASSERT_MSG(optimizer.addVertex(vertex), uFormat("cannot insert vertex %d!?", iter->first).c_str()); {
UERROR("Could not create vertex for node %d", id);
}
else
{
vertex->setId(id);
UASSERT_MSG(optimizer.addVertex(vertex), uFormat("cannot insert vertex %d!?", iter->first).c_str());
}
}
// Setup root prior (fixed x,y,z,yaw)
if(!isSlam2d() && rootId !=0 && hasGravityConstraints)
{
g2o::VertexSE3* v1 = dynamic_cast<g2o::VertexSE3*>(optimizer.vertex(rootId));
if(v1)
{
g2o::EdgeSE3Prior * e = new g2o::EdgeSE3Prior();
e->setVertex(0, v1);
Eigen::Affine3d a = poses.at(rootId).toEigen3d();
Eigen::Isometry3d pose;
pose = a.linear();
pose.translation() = a.translation();
e->setMeasurement(pose);
e->setParameterId(0, PARAM_OFFSET);
Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity()*10e6;
// pitch and roll not fixed
information(3,3) = information(4,4) = 1;
e->setInformation(information);
if (!optimizer.addEdge(e))
{
delete e;
UERROR("Map: Failed adding fixed constraint of rootid %d, set as fixed instead", rootId);
v1->setFixed(true);
}
else
{
UDEBUG("Set %d fixed with prior (have gravity constraints)", rootId);
}
}
else
{
UERROR("Map: Failed adding fixed constraint of rootid %d (not found in added vertices)", rootId);
}
} }
UDEBUG("fill edges to g2o..."); UDEBUG("fill edges to g2o...");
+30 -22
View File
@@ -106,28 +106,35 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::NonlinearFactorGraph graph; gtsam::NonlinearFactorGraph graph;
// detect if there is a global pose prior set, if so remove rootId // detect if there is a global pose prior set, if so remove rootId
bool gpsPriorOnly = false; bool hasGPSPrior = false;
bool hasPriorPoses = false; bool hasGravityConstraints = false;
if(!priorsIgnored()) if(!priorsIgnored() || (!isSlam2d() && gravitySigma() > 0))
{ {
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter) for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
if(iter->second.from() == iter->second.to() && iter->second.type() == Link::kPosePrior) if(iter->second.from() == iter->second.to())
{ {
hasPriorPoses = true; if(!priorsIgnored() && iter->second.type() == Link::kPosePrior)
if ((isSlam2d() && 1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999) ||
(1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) < 9999.0 &&
1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) < 9999.0 &&
1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999.0))
{ {
// orientation is set, don't set root prior hasGPSPrior = true;
gpsPriorOnly = false; if ((isSlam2d() && 1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999) ||
rootId = 0; (1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) < 9999.0 &&
break; 1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) < 9999.0 &&
1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999.0))
{
// orientation is set, don't set root prior (it is no GPS)
rootId = 0;
hasGPSPrior = false;
break;
}
} }
else if(gravitySigma()<=0) if(iter->second.type() == Link::kGravity)
{ {
gpsPriorOnly = true; hasGravityConstraints = true;
if(priorsIgnored())
{
break;
}
} }
} }
} }
@@ -138,25 +145,25 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
{ {
UASSERT(uContains(poses, rootId)); UASSERT(uContains(poses, rootId));
const Transform & initialPose = poses.at(rootId); const Transform & initialPose = poses.at(rootId);
UDEBUG("hasPriorPoses=%s, gpsPriorOnly=%s", hasPriorPoses?"true":"false", gpsPriorOnly?"true":"false"); UDEBUG("hasGPSPrior=%s", hasGPSPrior?"true":"false");
if(isSlam2d()) if(isSlam2d())
{ {
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasPriorPoses?1e-2:std::numeric_limits<double>::min())); gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasGPSPrior?1e-2:std::numeric_limits<double>::min()));
graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.x(), initialPose.y(), initialPose.theta()), priorNoise)); graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.x(), initialPose.y(), initialPose.theta()), priorNoise));
} }
else else
{ {
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances( gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(
(gtsam::Vector(6) << (gtsam::Vector(6) <<
1e-2, 1e-2, hasPriorPoses?1e-2:std::numeric_limits<double>::min(), // roll, pitch, fixed yaw if there are no priors (hasGravityConstraints?2:1e-2), (hasGravityConstraints?2:1e-2), hasGPSPrior?1e-2:std::numeric_limits<double>::min(), // roll, pitch, fixed yaw if there are no priors
(gpsPriorOnly?2:1e-2), gpsPriorOnly?2:1e-2, gpsPriorOnly?2:1e-2 // xyz (hasGPSPrior?2:1e-2), hasGPSPrior?2:1e-2, hasGPSPrior?2:1e-2 // xyz
).finished()); ).finished());
graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise)); graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise));
} }
} }
UDEBUG("fill poses to gtsam... rootId=%d (priorsIgnored=%d gpsPriorOnly=%d landmarksIgnored=%d)", UDEBUG("fill poses to gtsam... rootId=%d (priorsIgnored=%d landmarksIgnored=%d)",
rootId, priorsIgnored()?1:0, gpsPriorOnly?1:0, landmarksIgnored()?1:0); rootId, priorsIgnored()?1:0, landmarksIgnored()?1:0);
gtsam::Values initialEstimate; gtsam::Values initialEstimate;
std::map<int, bool> isLandmarkWithRotation; std::map<int, bool> isLandmarkWithRotation;
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
@@ -618,8 +625,9 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
{ {
if(key > 0) if(key > 0)
{ {
poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>(); gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
optimizedPoses.insert(std::make_pair(key, Transform(p.x(), p.y(), p.theta()))); optimizedPoses.insert(std::make_pair(key, Transform(p.x(), p.y(), z, roll, pitch, p.theta())));
} }
else if(!landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end()) else if(!landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end())
{ {
+3 -1
View File
@@ -78,7 +78,9 @@ struct big_any_policy : typed_base_any_policy<T>
{ {
virtual void static_delete(void** x) virtual void static_delete(void** x)
{ {
if (* x) delete (* reinterpret_cast<T**>(x)); *x = NULL; if (* x)
delete (* reinterpret_cast<T**>(x));
*x = NULL;
} }
virtual void copy_from_value(void const* src, void** dest) virtual void copy_from_value(void const* src, void** dest)
{ {
+104 -55
View File
@@ -2823,7 +2823,13 @@ void fillProjectedCloudHoles(cv::Mat & registeredDepth, bool verticalDirection,
} }
} }
struct ProjectionInfo { class ProjectionInfo {
public:
ProjectionInfo():
nodeID(-1),
cameraIndex(-1),
distance(-1)
{}
int nodeID; int nodeID;
int cameraIndex; int cameraIndex;
pcl::PointXY uv; pcl::PointXY uv;
@@ -2842,9 +2848,18 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
float maxDistance, float maxDistance,
float maxAngle, float maxAngle,
const std::vector<float> & roiRatios, const std::vector<float> & roiRatios,
const cv::Mat & projMask,
bool distanceToCamPolicy, bool distanceToCamPolicy,
const ProgressState * state) const ProgressState * state)
{ {
UINFO("cloud=%d points", (int)cloud.size());
UINFO("cameraPoses=%d", (int)cameraPoses.size());
UINFO("cameraModels=%d", (int)cameraModels.size());
UINFO("maxDistance=%f", maxDistance);
UINFO("maxAngle=%f", maxAngle);
UINFO("distanceToCamPolicy=%s", distanceToCamPolicy?"true":"false");
UINFO("roiRatios=%s", roiRatios.size() == 4?uFormat("%f %f %f %f", roiRatios[0], roiRatios[1], roiRatios[2], roiRatios[3]):"");
UINFO("projMask=%dx%d", projMask.cols, projMask.rows);
std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > pointToPixel; std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > pointToPixel;
if (cloud.empty() || cameraPoses.empty() || cameraModels.empty()) if (cloud.empty() || cameraPoses.empty() || cameraModels.empty())
@@ -2859,20 +2874,48 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
return pointToPixel; return pointToPixel;
} }
std::vector<std::vector<ProjectionInfo> > invertedIndex(cloud.size()); // For each point: list of cameras std::vector<ProjectionInfo> invertedIndex(cloud.size()); // For each point: list of cameras
int cameraProcessed = 0; int cameraProcessed = 0;
bool wrongMaskFormatWarned = false;
for(std::map<int, Transform>::const_iterator pter = cameraPoses.lower_bound(0); pter!=cameraPoses.end(); ++pter) for(std::map<int, Transform>::const_iterator pter = cameraPoses.lower_bound(0); pter!=cameraPoses.end(); ++pter)
{ {
std::map<int, std::vector<CameraModel> >::const_iterator iter=cameraModels.find(pter->first); std::map<int, std::vector<CameraModel> >::const_iterator iter=cameraModels.find(pter->first);
if(iter!=cameraModels.end() && !iter->second.empty()) if(iter!=cameraModels.end() && !iter->second.empty())
{ {
for(size_t i=0; i<iter->second.size(); ++i) cv::Mat validProjMask;
if(!projMask.empty())
{ {
Transform cameraTransform = (pter->second * iter->second[i].localTransform()); if(projMask.type() != CV_8UC1)
{
if(!wrongMaskFormatWarned)
UERROR("Wrong camera projection mask type %d, should be CV_8UC1", projMask.type());
wrongMaskFormatWarned = true;
}
else if(projMask.cols == iter->second[0].imageWidth() * (int)iter->second.size() &&
projMask.rows == iter->second[0].imageHeight())
{
validProjMask = projMask;
}
else
{
UWARN("Camera projection mask (%dx%d) is not valid for current "
"camera model(s) (count=%ld, image size=%dx%d). It will be "
"ignored for node %d",
projMask.cols, projMask.rows,
iter->second.size(),
iter->second[0].imageWidth(),
iter->second[0].imageHeight(),
pter->first);
}
}
for(size_t camIndex=0; camIndex<iter->second.size(); ++camIndex)
{
Transform cameraTransform = (pter->second * iter->second[camIndex].localTransform());
UASSERT(!cameraTransform.isNull()); UASSERT(!cameraTransform.isNull());
cv::Mat cameraMatrixK = iter->second[i].K(); cv::Mat cameraMatrixK = iter->second[camIndex].K();
UASSERT(cameraMatrixK.type() == CV_64FC1 && cameraMatrixK.cols == 3 && cameraMatrixK.cols == 3); UASSERT(cameraMatrixK.type() == CV_64FC1 && cameraMatrixK.cols == 3 && cameraMatrixK.cols == 3);
const cv::Size & imageSize = iter->second[i].imageSize(); const cv::Size & imageSize = iter->second[camIndex].imageSize();
float fx = cameraMatrixK.at<double>(0,0); float fx = cameraMatrixK.at<double>(0,0);
float fy = cameraMatrixK.at<double>(1,1); float fy = cameraMatrixK.at<double>(1,1);
@@ -2899,7 +2942,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
// re-project in camera frame // re-project in camera frame
float z = ptScan.z; float z = ptScan.z;
bool set = false; bool set = false;
if(z > 0.0f) if(z > 0.0f && (maxDistance<=0 || z<maxDistance))
{ {
float invZ = 1.0f/z; float invZ = 1.0f/z;
float dx = (fx*ptScan.x)*invZ + cx; float dx = (fx*ptScan.x)*invZ + cx;
@@ -2909,7 +2952,8 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
int dx_high = dx + 0.5f; int dx_high = dx + 0.5f;
int dy_high = dy + 0.5f; int dy_high = dy + 0.5f;
int zMM = z * 1000; int zMM = z * 1000;
if(uIsInBounds(dx_low, roi.x, roi.x+roi.width) && uIsInBounds(dy_low, roi.y, roi.y+roi.height)) if(uIsInBounds(dx_low, roi.x, roi.x+roi.width) && uIsInBounds(dy_low, roi.y, roi.y+roi.height) &&
(validProjMask.empty() || validProjMask.at<unsigned char>(dy_low, imageSize.width*camIndex+dx_low) > 0))
{ {
set = true; set = true;
cv::Vec2i &zReg = registered.at<cv::Vec2i>(dy_low, dx_low); cv::Vec2i &zReg = registered.at<cv::Vec2i>(dy_low, dx_low);
@@ -2920,7 +2964,8 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
} }
} }
if((dx_low != dx_high || dy_low != dy_high) && if((dx_low != dx_high || dy_low != dy_high) &&
uIsInBounds(dx_high, roi.x, roi.x+roi.width) && uIsInBounds(dy_high, roi.y, roi.y+roi.height)) uIsInBounds(dx_high, roi.x, roi.x+roi.width) && uIsInBounds(dy_high, roi.y, roi.y+roi.height) &&
(validProjMask.empty() || validProjMask.at<unsigned char>(dy_high, imageSize.width*camIndex+dx_high) > 0))
{ {
set = true; set = true;
cv::Vec2i &zReg = registered.at<cv::Vec2i>(dy_high, dx_high); cv::Vec2i &zReg = registered.at<cv::Vec2i>(dy_high, dx_high);
@@ -2939,11 +2984,11 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
if(count == 0) if(count == 0)
{ {
registered = cv::Mat(); registered = cv::Mat();
UINFO("No points projected in camera %d/%d", pter->first, i); UINFO("No points projected in camera %d/%d", pter->first, camIndex);
} }
else else
{ {
UDEBUG("%d points projected in camera %d/%d", count, pter->first, i); UDEBUG("%d points projected in camera %d/%d", count, pter->first, camIndex);
} }
for(int u=0; u<registered.cols; ++u) for(int u=0; u<registered.cols; ++u)
{ {
@@ -2954,11 +2999,42 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
{ {
ProjectionInfo info; ProjectionInfo info;
info.nodeID = pter->first; info.nodeID = pter->first;
info.cameraIndex = i; info.cameraIndex = camIndex;
info.uv.x = float(u)/float(imageSize.width); info.uv.x = float(u)/float(imageSize.width);
info.uv.y = float(v)/float(imageSize.height); info.uv.y = float(v)/float(imageSize.height);
info.distance = zReg[0]/1000.0f; const Transform & cam = cameraPoses.at(info.nodeID);
invertedIndex[zReg[1]].push_back(info); const PointT & pt = cloud.at(zReg[1]);
Eigen::Vector4f camDir(cam.x()-pt.x, cam.y()-pt.y, cam.z()-pt.z, 0);
Eigen::Vector4f normal(pt.normal_x, pt.normal_y, pt.normal_z, 0);
float angleToCam = maxAngle<=0?0:pcl::getAngle3D(normal, camDir);
float distanceToCam = zReg[0]/1000.0f;
if( (maxAngle<=0 || (camDir.dot(normal) > 0 && angleToCam < maxAngle)) && // is facing camera? is point normal perpendicular to camera?
(maxDistance<=0 || distanceToCam<maxDistance)) // is point not too far from camera?
{
float vx = info.uv.x-0.5f;
float vy = info.uv.y-0.5f;
float distanceToCenter = vx*vx+vy*vy;
float distance = distanceToCenter;
if(distanceToCamPolicy)
{
distance = distanceToCam;
}
info.distance = distance;
if(invertedIndex[zReg[1]].distance != -1.0f)
{
if(distance <= invertedIndex[zReg[1]].distance)
{
invertedIndex[zReg[1]] = info;
}
}
else
{
invertedIndex[zReg[1]] = info;
}
}
} }
} }
} }
@@ -2991,50 +3067,14 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
// For each point // For each point
for(size_t i=0; i<invertedIndex.size(); ++i) for(size_t i=0; i<invertedIndex.size(); ++i)
{ {
if((i+1)%10000 == 0)
{
UDEBUG("Point %d/%d", i+1, (int)cloud.size());
if(state && !state->callback(uFormat("%d/%d points projected to cameras (out of %d points)", colorized, i+1, (int)cloud.size())))
{
//cancelled!
UWARN("Projecting to camera cancelled!");
pointToPixel.clear();
return pointToPixel;
}
}
const PointT & pt = cloud.at(i);
int nodeID = -1; int nodeID = -1;
int cameraIndex = -1; int cameraIndex = -1;
float smallestWeight = std::numeric_limits<float>::max();
pcl::PointXY uv_coords; pcl::PointXY uv_coords;
for (size_t j = 0; j<invertedIndex[i].size(); ++j) if(invertedIndex[i].distance > -1.0f)
{ {
const Transform & cam = cameraPoses.at(invertedIndex[i][j].nodeID); nodeID = invertedIndex[i].nodeID;
Eigen::Vector4f camDir(cam.x()-pt.x, cam.y()-pt.y, cam.z()-pt.z, 0); cameraIndex = invertedIndex[i].cameraIndex;
Eigen::Vector4f normal(pt.normal_x, pt.normal_y, pt.normal_z, 0); uv_coords = invertedIndex[i].uv;
float angleToCam = maxAngle<=0?0:pcl::getAngle3D(normal, camDir);
float distanceToCam = invertedIndex[i][j].distance;
if( (maxAngle<=0 || (camDir.dot(normal) > 0 && angleToCam < maxAngle)) && // is facing camera? is point normal perpendicular to camera?
(maxDistance<=0 || distanceToCam<maxDistance)) // is point not too far from camera?
{
float vx = invertedIndex[i][j].uv.x-0.5f;
float vy = invertedIndex[i][j].uv.y-0.5f;
float distanceToCenter = vx*vx+vy*vy;
float distance = distanceToCenter;
if(distanceToCamPolicy)
{
distance = distanceToCam;
}
if(distance <= smallestWeight)
{
nodeID = invertedIndex[i][j].nodeID;
cameraIndex = invertedIndex[i][j].cameraIndex;
smallestWeight = distance;
uv_coords = invertedIndex[i][j].uv;
}
}
} }
if(nodeID>-1 && cameraIndex> -1) if(nodeID>-1 && cameraIndex> -1)
@@ -3046,7 +3086,12 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
} }
} }
UINFO("Process %d points...done! (%d [%d%%] projected in cameras)", (int)cloud.size(), colorized, colorized*100/cloud.size()); msg = uFormat("Process %d points...done! (%d [%d%%] projected in cameras)", (int)cloud.size(), colorized, colorized*100/cloud.size());
UINFO(msg.c_str());
if(state)
{
state->callback(msg);
}
return pointToPixel; return pointToPixel;
} }
@@ -3058,6 +3103,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
float maxDistance, float maxDistance,
float maxAngle, float maxAngle,
const std::vector<float> & roiRatios, const std::vector<float> & roiRatios,
const cv::Mat & projMask,
bool distanceToCamPolicy, bool distanceToCamPolicy,
const ProgressState * state) const ProgressState * state)
{ {
@@ -3067,6 +3113,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
maxDistance, maxDistance,
maxAngle, maxAngle,
roiRatios, roiRatios,
projMask,
distanceToCamPolicy, distanceToCamPolicy,
state); state);
} }
@@ -3078,6 +3125,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
float maxDistance, float maxDistance,
float maxAngle, float maxAngle,
const std::vector<float> & roiRatios, const std::vector<float> & roiRatios,
const cv::Mat & projMask,
bool distanceToCamPolicy, bool distanceToCamPolicy,
const ProgressState * state) const ProgressState * state)
{ {
@@ -3087,6 +3135,7 @@ std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > projectCloudToCamera
maxDistance, maxDistance,
maxAngle, maxAngle,
roiRatios, roiRatios,
projMask,
distanceToCamPolicy, distanceToCamPolicy,
state); state);
} }
+302 -26
View File
@@ -664,6 +664,7 @@ typename pcl::PointCloud<PointT>::Ptr randomSamplingImpl(
typename pcl::PointCloud<PointT>::Ptr output(new pcl::PointCloud<PointT>); typename pcl::PointCloud<PointT>::Ptr output(new pcl::PointCloud<PointT>);
pcl::RandomSample<PointT> filter; pcl::RandomSample<PointT> filter;
filter.setSample(samples); filter.setSample(samples);
filter.setSeed (std::rand ());
filter.setInputCloud(cloud); filter.setInputCloud(cloud);
filter.filter(*output); filter.filter(*output);
return output; return output;
@@ -672,10 +673,26 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr randomSampling(const pcl::PointCloud<pcl::Po
{ {
return randomSamplingImpl<pcl::PointXYZ>(cloud, samples); return randomSamplingImpl<pcl::PointXYZ>(cloud, samples);
} }
pcl::PointCloud<pcl::PointNormal>::Ptr randomSampling(const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud, int samples)
{
return randomSamplingImpl<pcl::PointNormal>(cloud, samples);
}
pcl::PointCloud<pcl::PointXYZRGB>::Ptr randomSampling(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, int samples) pcl::PointCloud<pcl::PointXYZRGB>::Ptr randomSampling(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, int samples)
{ {
return randomSamplingImpl<pcl::PointXYZRGB>(cloud, samples); return randomSamplingImpl<pcl::PointXYZRGB>(cloud, samples);
} }
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr randomSampling(const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud, int samples)
{
return randomSamplingImpl<pcl::PointXYZRGBNormal>(cloud, samples);
}
pcl::PointCloud<pcl::PointXYZI>::Ptr randomSampling(const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud, int samples)
{
return randomSamplingImpl<pcl::PointXYZI>(cloud, samples);
}
pcl::PointCloud<pcl::PointXYZINormal>::Ptr randomSampling(const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud, int samples)
{
return randomSamplingImpl<pcl::PointXYZINormal>(cloud, samples);
}
template<typename PointT> template<typename PointT>
pcl::IndicesPtr passThroughImpl( pcl::IndicesPtr passThroughImpl(
@@ -1106,7 +1123,7 @@ pcl::IndicesPtr radiusFilteringImpl(
{ {
std::vector<int> kIndices; std::vector<int> kIndices;
std::vector<float> kDistances; std::vector<float> kDistances;
int k = tree->radiusSearch(cloud->at(indices->at(i)), radiusSearch, kIndices, kDistances); int k = tree->radiusSearch(cloud->at(indices->at(i)), radiusSearch, kIndices, kDistances, minNeighborsInRadius+1);
if(k > minNeighborsInRadius) if(k > minNeighborsInRadius)
{ {
output->at(oi++) = indices->at(i); output->at(oi++) = indices->at(i);
@@ -1124,7 +1141,7 @@ pcl::IndicesPtr radiusFilteringImpl(
{ {
std::vector<int> kIndices; std::vector<int> kIndices;
std::vector<float> kDistances; std::vector<float> kDistances;
int k = tree->radiusSearch(cloud->at(i), radiusSearch, kIndices, kDistances); int k = tree->radiusSearch(cloud->at(i), radiusSearch, kIndices, kDistances, minNeighborsInRadius+1);
if(k > minNeighborsInRadius) if(k > minNeighborsInRadius)
{ {
output->at(oi++) = i; output->at(oi++) = i;
@@ -1160,6 +1177,239 @@ pcl::IndicesPtr radiusFiltering(const pcl::PointCloud<pcl::PointXYZINormal>::Ptr
return radiusFilteringImpl<pcl::PointXYZINormal>(cloud, indices, radiusSearch, minNeighborsInRadius); return radiusFilteringImpl<pcl::PointXYZINormal>(cloud, indices, radiusSearch, minNeighborsInRadius);
} }
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
pcl::IndicesPtr indices(new std::vector<int>);
return proportionalRadiusFiltering(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
template<typename PointT>
pcl::IndicesPtr proportionalRadiusFilteringImpl(
const typename pcl::PointCloud<PointT>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
typename pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT>(false));
UASSERT(cloud->size() == viewpointIndices.size());
UASSERT(factor>0.0f);
UASSERT(neighborScale>=1.0f);
if(!indices->empty())
{
std::vector<bool> kept(indices->size());
tree->setInputCloud(cloud, indices);
for(size_t i=0; i<indices->size(); ++i)
{
int index = indices->at(i);
std::vector<int> kIndices;
std::vector<float> kDistances;
std::map<int, Transform>::const_iterator viewpointIter = viewpoints.find(viewpointIndices[index]);
UASSERT(viewpointIter != viewpoints.end());
cv::Point3f viewpoint(viewpointIter->second.x(), viewpointIter->second.y(), viewpointIter->second.z());
cv::Point3f point = cv::Point3f(cloud->at(index).x,cloud->at(index).y, cloud->at(index).z);
float radiusSearch = factor * cv::norm(viewpoint-point);
int k = tree->radiusSearch(cloud->at(index), radiusSearch, kIndices, kDistances);
bool keep = k>0;
for(int j=0; j<k && keep; ++j)
{
if(kIndices[j] != index)
{
cv::Point3f pointTmp(cloud->at(kIndices[j]).x,cloud->at(kIndices[j]).y, cloud->at(kIndices[j]).z);
cv::Point3f tmp = pointTmp - point;
float distPtSqr = tmp.dot(tmp); // L2sqr
viewpointIter = viewpoints.find(viewpointIndices[kIndices[j]]);
UASSERT(viewpointIter != viewpoints.end());
viewpoint = cv::Point3f(viewpointIter->second.x(), viewpointIter->second.y(), viewpointIter->second.z());
float radiusSearchTmp = factor * cv::norm(viewpoint-pointTmp) * neighborScale;
if(distPtSqr > radiusSearchTmp*radiusSearchTmp)
{
keep = false;
}
}
}
kept[i] = keep;
}
pcl::IndicesPtr output(new std::vector<int>(indices->size()));
int oi = 0;
for(size_t i=0; i<indices->size(); ++i)
{
if(kept[i])
{
output->at(oi++) = indices->at(i);
}
}
output->resize(oi);
return output;
}
else
{
std::vector<bool> kept(cloud->size());
tree->setInputCloud(cloud);
#pragma omp parallel for
for(int i=0; i<(int)cloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
std::map<int, Transform>::const_iterator viewpointIter = viewpoints.find(viewpointIndices[i]);
UASSERT(viewpointIter != viewpoints.end());
cv::Point3f viewpoint(viewpointIter->second.x(), viewpointIter->second.y(), viewpointIter->second.z());
cv::Point3f point = cv::Point3f(cloud->at(i).x,cloud->at(i).y, cloud->at(i).z);
float radiusSearch = factor * cv::norm(viewpoint-point);
int k = tree->radiusSearch(cloud->at(i), radiusSearch, kIndices, kDistances);
bool keep = k>0;
for(int j=0; j<k && keep; ++j)
{
if(kIndices[j] != (int)i)
{
cv::Point3f pointTmp(cloud->at(kIndices[j]).x,cloud->at(kIndices[j]).y, cloud->at(kIndices[j]).z);
cv::Point3f tmp = pointTmp - point;
float distPtSqr = tmp.dot(tmp); // L2sqr
viewpointIter = viewpoints.find(viewpointIndices[kIndices[j]]);
UASSERT(viewpointIter != viewpoints.end());
viewpoint = cv::Point3f(viewpointIter->second.x(), viewpointIter->second.y(), viewpointIter->second.z());
float radiusSearchTmp = factor * cv::norm(viewpoint-pointTmp) * neighborScale;
if(distPtSqr > radiusSearchTmp*radiusSearchTmp)
{
keep = false;
}
}
}
kept[i] = keep;
}
pcl::IndicesPtr output(new std::vector<int>(cloud->size()));
int oi = 0;
for(size_t i=0; i<cloud->size(); ++i)
{
if(kept[i])
{
output->at(oi++) = i;
}
}
output->resize(oi);
return output;
}
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointXYZ>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointNormal>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointXYZRGB>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointXYZRGBNormal>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointXYZI>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::IndicesPtr proportionalRadiusFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const pcl::IndicesPtr & indices,
const std::vector<int> & viewpointIndices,
const std::map<int, Transform> & viewpoints,
float factor,
float neighborScale)
{
return proportionalRadiusFilteringImpl<pcl::PointXYZINormal>(cloud, indices, viewpointIndices, viewpoints, factor, neighborScale);
}
pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractFiltering( pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & substractCloud,
@@ -1680,20 +1930,22 @@ pcl::IndicesPtr normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
pcl::IndicesPtr indices(new std::vector<int>); pcl::IndicesPtr indices(new std::vector<int>);
return normalFiltering(cloud, indices, angleMax, normal, normalKSearch, viewpoint); return normalFiltering(cloud, indices, angleMax, normal, normalKSearch, viewpoint, groundNormalsUp);
} }
pcl::IndicesPtr normalFiltering( pcl::IndicesPtr normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
pcl::IndicesPtr indices(new std::vector<int>); pcl::IndicesPtr indices(new std::vector<int>);
return normalFiltering(cloud, indices, angleMax, normal, normalKSearch, viewpoint); return normalFiltering(cloud, indices, angleMax, normal, normalKSearch, viewpoint, groundNormalsUp);
} }
@@ -1704,7 +1956,8 @@ pcl::IndicesPtr normalFilteringImpl(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
pcl::IndicesPtr output(new std::vector<int>()); pcl::IndicesPtr output(new std::vector<int>());
@@ -1744,6 +1997,12 @@ pcl::IndicesPtr normalFilteringImpl(
for(unsigned int i=0; i<cloud_normals->size(); ++i) for(unsigned int i=0; i<cloud_normals->size(); ++i)
{ {
Eigen::Vector4f v(cloud_normals->at(i).normal_x, cloud_normals->at(i).normal_y, cloud_normals->at(i).normal_z, 0.0f); Eigen::Vector4f v(cloud_normals->at(i).normal_x, cloud_normals->at(i).normal_y, cloud_normals->at(i).normal_z, 0.0f);
if(groundNormalsUp>0.0f && v[2] < -groundNormalsUp && cloud->at(indices->size()!=0?indices->at(i):i).z < viewpoint[3]) // some far velodyne rays on road can have normals toward ground
{
//reverse normal
v *= -1.0f;
}
float angle = pcl::getAngle3D(normal, v); float angle = pcl::getAngle3D(normal, v);
if(angle < angleMax) if(angle < angleMax)
{ {
@@ -1761,10 +2020,10 @@ pcl::IndicesPtr normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointXYZ>(cloud, indices, angleMax, normal, normalKSearch, viewpoint); return normalFilteringImpl<pcl::PointXYZ>(cloud, indices, angleMax, normal, normalKSearch, viewpoint, groundNormalsUp);
} }
pcl::IndicesPtr normalFiltering( pcl::IndicesPtr normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
@@ -1772,9 +2031,10 @@ pcl::IndicesPtr normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointXYZRGB>(cloud, indices, angleMax, normal, normalKSearch, viewpoint); return normalFilteringImpl<pcl::PointXYZRGB>(cloud, indices, angleMax, normal, normalKSearch, viewpoint, groundNormalsUp);
} }
pcl::IndicesPtr normalFiltering( pcl::IndicesPtr normalFiltering(
const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
@@ -1782,17 +2042,20 @@ pcl::IndicesPtr normalFiltering(
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int normalKSearch,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointXYZI>(cloud, indices, angleMax, normal, normalKSearch, viewpoint); return normalFilteringImpl<pcl::PointXYZI>(cloud, indices, angleMax, normal, normalKSearch, viewpoint, groundNormalsUp);
} }
template<typename PointT> template<typename PointNormalT>
pcl::IndicesPtr normalFilteringImpl( pcl::IndicesPtr normalFilteringImpl(
const typename pcl::PointCloud<PointT>::Ptr & cloud, const typename pcl::PointCloud<PointNormalT>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal) const Eigen::Vector4f & normal,
const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
pcl::IndicesPtr output(new std::vector<int>()); pcl::IndicesPtr output(new std::vector<int>());
@@ -1805,6 +2068,11 @@ pcl::IndicesPtr normalFilteringImpl(
for(unsigned int i=0; i<indices->size(); ++i) for(unsigned int i=0; i<indices->size(); ++i)
{ {
Eigen::Vector4f v(cloud->at(indices->at(i)).normal_x, cloud->at(indices->at(i)).normal_y, cloud->at(indices->at(i)).normal_z, 0.0f); Eigen::Vector4f v(cloud->at(indices->at(i)).normal_x, cloud->at(indices->at(i)).normal_y, cloud->at(indices->at(i)).normal_z, 0.0f);
if(groundNormalsUp>0.0f && v[2] < -groundNormalsUp && cloud->at(indices->at(i)).z < viewpoint[3]) // some far velodyne rays on road can have normals toward ground
{
//reverse normal
v *= -1.0f;
}
float angle = pcl::getAngle3D(normal, v); float angle = pcl::getAngle3D(normal, v);
if(angle < angleMax) if(angle < angleMax)
{ {
@@ -1818,6 +2086,11 @@ pcl::IndicesPtr normalFilteringImpl(
for(unsigned int i=0; i<cloud->size(); ++i) for(unsigned int i=0; i<cloud->size(); ++i)
{ {
Eigen::Vector4f v(cloud->at(i).normal_x, cloud->at(i).normal_y, cloud->at(i).normal_z, 0.0f); Eigen::Vector4f v(cloud->at(i).normal_x, cloud->at(i).normal_y, cloud->at(i).normal_z, 0.0f);
if(groundNormalsUp>0.0f && v[2] < -groundNormalsUp && cloud->at(i).z < viewpoint[3]) // some far velodyne rays on road can have normals toward ground
{
//reverse normal
v *= -1.0f;
}
float angle = pcl::getAngle3D(normal, v); float angle = pcl::getAngle3D(normal, v);
if(angle < angleMax) if(angle < angleMax)
{ {
@@ -1836,30 +2109,33 @@ pcl::IndicesPtr normalFiltering(
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointNormal>(cloud, indices, angleMax, normal); return normalFilteringImpl<pcl::PointNormal>(cloud, indices, angleMax, normal, viewpoint, groundNormalsUp);
} }
pcl::IndicesPtr normalFiltering( pcl::IndicesPtr normalFiltering(
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointXYZRGBNormal>(cloud, indices, angleMax, normal); return normalFilteringImpl<pcl::PointXYZRGBNormal>(cloud, indices, angleMax, normal, viewpoint, groundNormalsUp);
} }
pcl::IndicesPtr normalFiltering( pcl::IndicesPtr normalFiltering(
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
const pcl::IndicesPtr & indices, const pcl::IndicesPtr & indices,
float angleMax, float angleMax,
const Eigen::Vector4f & normal, const Eigen::Vector4f & normal,
int normalKSearch, int,
const Eigen::Vector4f & viewpoint) const Eigen::Vector4f & viewpoint,
float groundNormalsUp)
{ {
return normalFilteringImpl<pcl::PointXYZINormal>(cloud, indices, angleMax, normal); return normalFilteringImpl<pcl::PointXYZINormal>(cloud, indices, angleMax, normal, viewpoint, groundNormalsUp);
} }
std::vector<pcl::IndicesPtr> extractClusters( std::vector<pcl::IndicesPtr> extractClusters(
+3 -3
View File
@@ -122,7 +122,7 @@ void occupancy2DFromLaserScan(
} }
else else
{ {
scanNoHit = scanHit; scanNoHit = scanNoHitIn;
} }
std::map<int, Transform> poses; std::map<int, Transform> poses;
@@ -330,8 +330,8 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
{ {
//Get map size //Get map size
float margin = cellSize*10.0f; float margin = cellSize*10.0f;
xMin = minX-margin; xMin = minX-margin-cellSize/2.0f;
yMin = minY-margin; yMin = minY-margin-cellSize/2.0f;
float xMax = maxX+margin; float xMax = maxX+margin;
float yMax = maxY+margin; float yMax = maxY+margin;
if(fabs((yMax - yMin) / cellSize) > 30000 || // Max 1.5Km/1.5Km at 5 cm/cell -> 900MB if(fabs((yMax - yMin) / cellSize) > 30000 || // Max 1.5Km/1.5Km at 5 cm/cell -> 900MB
+38 -47
View File
@@ -3493,7 +3493,8 @@ void adjustNormalsToViewPointImpl(
const Eigen::Vector3f & viewpoint, const Eigen::Vector3f & viewpoint,
float groundNormalsUp) float groundNormalsUp)
{ {
for(unsigned int i=0; i<cloud->size(); ++i) #pragma omp parallel for
for(int i=0; i<(int)cloud->size(); ++i)
{ {
pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z); pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
if(pcl::isFinite(normal)) if(pcl::isFinite(normal))
@@ -3559,18 +3560,22 @@ void adjustNormalsToViewPoint(
adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp); adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp);
} }
void adjustNormalsToViewPoints(
template<typename PointT>
void adjustNormalsToViewPointsImpl(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices, const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud) typename pcl::PointCloud<PointT>::Ptr & cloud,
float groundNormalsUp)
{ {
if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size()) if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
{ {
pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (new pcl::search::KdTree<pcl::PointXYZ>); pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (new pcl::search::KdTree<pcl::PointXYZ>);
rawTree->setInputCloud (rawCloud); rawTree->setInputCloud (rawCloud);
for(unsigned int i=0; i<cloud->size(); ++i) #pragma omp parallel for
for(int i=0; i<(int)cloud->size(); ++i)
{ {
pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z); pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
if(pcl::isFinite(normal)) if(pcl::isFinite(normal))
@@ -3581,14 +3586,15 @@ void adjustNormalsToViewPoints(
UASSERT(indices.size() == 1); UASSERT(indices.size() == 1);
if(indices.size() && indices[0]>=0) if(indices.size() && indices[0]>=0)
{ {
Transform p = poses.at(rawCameraIndices[indices[0]]); const Transform & p = poses.at(rawCameraIndices[indices[0]]);
pcl::PointXYZ viewpoint(p.x(), p.y(), p.z()); pcl::PointXYZ viewpoint(p.x(), p.y(), p.z());
Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap(); Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap();
Eigen::Vector3f n(normal.x, normal.y, normal.z); Eigen::Vector3f n(normal.x, normal.y, normal.z);
float result = v.dot(n); float result = v.dot(n);
if(result < 0) if(result < 0 ||
(groundNormalsUp>0.0f && normal.z < -groundNormalsUp && cloud->points[i].z < viewpoint.z)) // some far velodyne rays on road can have normals toward ground)
{ {
//reverse normal //reverse normal
cloud->points[i].normal_x *= -1.0f; cloud->points[i].normal_x *= -1.0f;
@@ -3609,55 +3615,38 @@ void adjustNormalsToViewPoints(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices, const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud) pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
float groundNormalsUp)
{ {
UASSERT(rawCloud.get() && cloud.get()); adjustNormalsToViewPointsImpl<pcl::PointNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
UDEBUG("poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (int)poses.size(), (int)rawCloud->size(), (int)rawCameraIndices.size(), (int)cloud->size()); }
if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
{
pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (new pcl::search::KdTree<pcl::PointXYZ>);
rawTree->setInputCloud (rawCloud);
for(unsigned int i=0; i<cloud->size(); ++i)
{
pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
if(pcl::isFinite(normal))
{
std::vector<int> indices;
std::vector<float> dist;
rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z), 1, indices, dist);
if(indices.size() && indices[0]>=0)
{
UASSERT_MSG(indices[0]<(int)rawCameraIndices.size(), uFormat("indices[0]=%d rawCameraIndices.size()=%d", indices[0], (int)rawCameraIndices.size()).c_str());
UASSERT(uContains(poses, rawCameraIndices[indices[0]]));
Transform p = poses.at(rawCameraIndices[indices[0]]);
pcl::PointXYZ viewpoint(p.x(), p.y(), p.z());
Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap();
Eigen::Vector3f n(normal.x, normal.y, normal.z); void adjustNormalsToViewPoints(
const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
const std::vector<int> & rawCameraIndices,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
float groundNormalsUp)
{
adjustNormalsToViewPointsImpl<pcl::PointXYZRGBNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
}
float result = v.dot(n); void adjustNormalsToViewPoints(
if(result < 0) const std::map<int, Transform> & poses,
{ const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
//reverse normal const std::vector<int> & rawCameraIndices,
cloud->points[i].normal_x *= -1.0f; pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
cloud->points[i].normal_y *= -1.0f; float groundNormalsUp)
cloud->points[i].normal_z *= -1.0f; {
} adjustNormalsToViewPointsImpl<pcl::PointXYZINormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
}
else
{
UWARN("Not found camera viewpoint for point %d!?", i);
}
}
}
}
} }
void adjustNormalsToViewPoints( void adjustNormalsToViewPoints(
const std::map<int, Transform> & viewpoints, const std::map<int, Transform> & viewpoints,
const LaserScan & rawScan, const LaserScan & rawScan,
const std::vector<int> & viewpointIds, const std::vector<int> & viewpointIds,
LaserScan & scan) LaserScan & scan,
float groundNormalsUp)
{ {
UDEBUG("poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (int)viewpoints.size(), (int)rawScan.size(), (int)viewpointIds.size(), (int)scan.size()); UDEBUG("poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (int)viewpoints.size(), (int)rawScan.size(), (int)viewpointIds.size(), (int)scan.size());
if(viewpoints.size() && rawScan.size() && rawScan.size() == (int)viewpointIds.size() && scan.size() && scan.hasNormals()) if(viewpoints.size() && rawScan.size() && rawScan.size() == (int)viewpointIds.size() && scan.size() && scan.hasNormals())
@@ -3665,6 +3654,7 @@ void adjustNormalsToViewPoints(
pcl::PointCloud<pcl::PointXYZ>::Ptr rawCloud = util3d::laserScanToPointCloud(rawScan); pcl::PointCloud<pcl::PointXYZ>::Ptr rawCloud = util3d::laserScanToPointCloud(rawScan);
pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (new pcl::search::KdTree<pcl::PointXYZ>); pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (new pcl::search::KdTree<pcl::PointXYZ>);
rawTree->setInputCloud (rawCloud); rawTree->setInputCloud (rawCloud);
#pragma omp parallel for
for(int i=0; i<scan.size(); ++i) for(int i=0; i<scan.size(); ++i)
{ {
pcl::PointNormal point = util3d::laserScanToPointNormal(scan, i); pcl::PointNormal point = util3d::laserScanToPointNormal(scan, i);
@@ -3685,7 +3675,8 @@ void adjustNormalsToViewPoints(
Eigen::Vector3f n(normal.x, normal.y, normal.z); Eigen::Vector3f n(normal.x, normal.y, normal.z);
float result = v.dot(n); float result = v.dot(n);
if(result < 0) if(result < 0 ||
(groundNormalsUp>0.0f && normal.z < -groundNormalsUp && point.z < viewpoint.z)) // some far velodyne rays on road can have normals toward ground))
{ {
//reverse normal //reverse normal
scan.field(i, scan.getNormalsOffset()) *= -1.0f; scan.field(i, scan.getNormalsOffset()) *= -1.0f;

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Some files were not shown because too many files have changed in this diff Show More