Compare commits

..
Author SHA1 Message Date
matlabbe 85112c2cdf add pull request template 2024-03-16 21:45:05 -07:00
matlabbe 8657e18bda update config 2024-03-16 21:27:50 -07:00
matlabbe 578bf0ed8f Try with pre-commit default usage 2024-03-16 21:06:00 -07:00
matlabbe 9f230f5b28 Adding pre-commit checks 2024-03-16 20:26:56 -07:00
matlabbe 264c560a2c reverted 87faea7a85 for #783 (just don't include OptimizerCeres if -DWITH_CERES=OFF even if floam or okvis did include it) 2024-03-16 17:10:34 -07:00
matlabbe 4ce36ef245 Updated appveyor gdown version 2024-03-13 23:27:47 -07:00
matlabbe d0227694c5 small fix for qt6 2024-03-13 22:52:44 -07:00
matlabbe a6d9425bce DBViewer: support doubleclick on node or link in graphview to update correpsonding image view and constraints view, also added "Show pixel depth" menu option in ImageView to show pixel depth and pixel coordinate in map frame. 2024-03-13 22:42:47 -07:00
matlabbe e299505a64 Fixed ORB_SLAM3 config for stereo mode 2024-03-12 23:13:06 -07:00
matlabbe 57b4954cb3 Update README.md 2024-03-10 15:24:48 -07:00
matlabbe 2577c47e77 Fixed #1232 2024-03-09 15:14:01 -08:00
matlabbe 52e1b01597 Fixed assert when exporting textured mesh with both multiband and blending enabled with grayscale images 2024-03-04 17:05:17 -08:00
matlabbe 8019a2dc49 Fixed #1227 2024-03-02 16:17:10 -08:00
matlabbe 33b875ecbf GraphView: fixed mouse cursor tracking inverted x-y values 2024-03-01 10:13:53 -08:00
matlabbe c24f95a8d9 ExportCloudsDialog: added option to filter off-axis points 2024-02-29 16:19:57 -08:00
matlabbe 6f7e5cc97b Removed RGB option from main menu (#640) 2024-02-26 19:06:39 -08:00
matlabbe fccf33dd96 GraphViewer: added "Show mouse cursor position (m)" context menu option. 2024-02-26 17:13:50 -08:00
Long VuongandLong Vuong 752ca76cf5 not limitKps inside Feature2D::generateKeypoints when using pyDetector (#1223)
* not limitKps when using pyDetector

* update with upstream

---------

Co-authored-by: Long Vuong <vuong@wheel.me>
2024-02-26 15:21:15 -08:00
matlabbe 81e249b56c Update README.md 2024-02-18 19:02:40 -08:00
matlabbe ff7c8af56f Mac: fixed cloud viewer pushed back behind main window after dialog closes 2024-02-18 13:43:52 -08:00
matlabbe a11ea291d8 Fixed #1211 2024-02-10 18:27:02 -08:00
matlabbe cd615c6e52 docker focal deps: removed gtsam as already installed by ros now (fixing downstream gtsam version conflict errors) 2024-02-10 14:06:41 -08:00
Borong Yuan 1bd2d9fe81 superpoint torch using simple nms (#1213) 2024-02-10 13:54:20 -08:00
matlabbe 510aef19e4 Added Vis/PnPSplitLinearCovComponents parameter (default false -> same as before) 2024-02-07 14:43:16 -08:00
matlabbe 1dadd50cf2 cmake: added VTK_GLOBAL_WARNING_DISPLAY option (default off) for VTK>=9 (https://github.com/introlab/rtabmap_ros/issues/1111) 2024-02-03 17:04:48 -08:00
matlabbe b2a86d640a Fixed zed build errors (windows, #1207) 2024-01-31 07:17:04 -08:00
matlabbe c27507bc77 Added missing Open3D status in --version and About. 2024-01-27 15:20:10 -08:00
matlabbe b374c6cd8e docker: jammy humble dep fix 2024-01-21 15:49:59 -08:00
matlabbe 29dc6c67fa docker: fixing humble arm64 build 2024-01-21 13:26:43 -08:00
matlabbe 10de748531 DatabaseViewer: Fixed seg fault on Mac when opening db 2024-01-21 13:05:02 -08:00
Borong Yuan dcd5994456 support color histogram equalization (#1203) 2024-01-21 12:38:34 -08:00
matlabbe 13cd5e7a5e Export Poses: Added support of landmarks. Fixed g2o export with 6DoF landmark constaints. Adjusted g2o export landmark id. (#1199) 2024-01-20 12:04:26 -08:00
matlabbe 856e372dde fixed bundle windows qt plugins destination 2024-01-15 23:53:27 -08:00
matlabbe 423e67558b fixed windows ci 2024-01-15 23:39:41 -08:00
matlabbe ace653593b working qt6/mac deploy 2024-01-15 20:51:12 -08:00
matlabbe 7b31c737be Deploy fix 2024-01-15 20:45:58 -08:00
matlabbe 0b534c9427 Qt6 deploy fixes for Mac 2024-01-15 20:41:18 -08:00
matlabbe cdbdcfe676 Fixing appveyor regression with gdown tool 2024-01-13 18:47:45 -08:00
matlabbe b7239fdc84 Added parameter Mem/RotateImagesUpsideUp 2024-01-10 14:54:55 -08:00
matlabbe a0559b156b Fixed #1196 2024-01-06 16:11:25 -08:00
50 changed files with 3179 additions and 2054 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ init:
install:
# To download from google drive
- set PATH=C:\Python38-x64;C:\Python38-x64\Scripts;%PATH%
- ps: py -m pip --disable-pip-version-check install gdown
- ps: py -m pip --disable-pip-version-check install gdown>=5.1.0
# Qt
- set QTDIR=C:\Qt\5.10.1\msvc2015_64
# make sure Qt bin path is before cmake bin path to avoid copying qt5 dlls from cmake before qt installation
+7
View File
@@ -0,0 +1,7 @@
## Description
Please include a summary of the change and which issue is fixed (if any).
## Checklist:
- [ ] Did `pre-commit run --all-files` locally to fix any pre-commit failures on CI.
+16
View File
@@ -0,0 +1,16 @@
name: pre-commit
on:
pull_request:
branches:
- '**'
push:
branches: [master]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/action@v3.0.1
+31
View File
@@ -0,0 +1,31 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: '^build/|^data/|^app/|^archive/|^cmake_modules/|^\..*'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/cheshirekow/cmake-format-precommit
rev: v0.6.10
hooks:
- id: cmake-format
- id: cmake-lint
- repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
rev: v0.1.0
hooks:
- id: dockerfilelint
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.1
hooks:
- id: clang-format
args: ["-style=Google", "-i"]
+14 -12
View File
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
#######################
SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 21)
SET(RTABMAP_PATCH_VERSION 3)
SET(RTABMAP_PATCH_VERSION 4)
SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
@@ -294,14 +294,20 @@ SET(ADD_VTK_GUI_SUPPORT_QT_TO_CONF FALSE)
IF(WITH_QT)
FIND_PACKAGE(VTK)
IF(NOT VTK_FOUND)
MESSAGE(FATAL_ERROR "VTK is required when using Qt. Set -DWITH_QT=OFF if you don't want gui tools.")
MESSAGE(FATAL_ERROR "VTK is required when using Qt. Set -DWITH_QT=OFF if you don't want gui tools.")
ENDIF(NOT VTK_FOUND)
# If Qt is here, the GUI will be built
IF(NOT(${VTK_MAJOR_VERSION} LESS 9))
IF(NOT VTK_QT_VERSION)
MESSAGE(FATAL_ERROR "WITH_QT option is ON, but VTK ${VTK_MAJOR_VERSION} has not been built with Qt support, disabling Qt.")
ENDIF()
IF(NOT VTK_QT_VERSION)
MESSAGE(FATAL_ERROR "WITH_QT option is ON, but VTK ${VTK_MAJOR_VERSION} has not been built with Qt support, disabling Qt.")
ENDIF()
option(VTK_GLOBAL_WARNING_DISPLAY "Show VTK warning display on runtime" OFF)
IF(NOT VTK_GLOBAL_WARNING_DISPLAY)
ADD_DEFINITIONS(-DVTK_GLOBAL_WARNING_DISPLAY_OFF)
ENDIF()
MESSAGE(STATUS "VTK>=9 detected, will use VTK_QT_VERSION=${VTK_QT_VERSION} for Qt version.")
IF(${VTK_QT_VERSION} EQUAL 6)
FIND_PACKAGE(Qt6 COMPONENTS Widgets Core Gui OpenGL PrintSupport QUIET OPTIONAL_COMPONENTS Svg)
@@ -886,9 +892,9 @@ ENDIF()
IF(NOT MRPT_FOUND)
SET(MRPT "//")
ENDIF(NOT MRPT_FOUND)
IF(NOT CERES_FOUND)
IF(NOT WITH_CERES OR NOT CERES_FOUND)
SET(CERES "//")
ENDIF(NOT CERES_FOUND)
ENDIF(NOT WITH_CERES OR NOT CERES_FOUND)
IF(NOT WITH_TORO)
SET(TORO "//")
ENDIF(NOT WITH_TORO)
@@ -1400,12 +1406,8 @@ ELSE()
MESSAGE(STATUS " *With GTSAM = NO (GTSAM not found)")
ENDIF()
IF(CERES_FOUND)
IF(WITH_CERES)
IF(WITH_CERES AND CERES_FOUND)
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD)")
ELSE()
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD, WITH_CERES=OFF but it is enabled by okvis or floam dependencies)")
ENDIF()
ELSEIF(NOT WITH_CERES)
MESSAGE(STATUS " *With Ceres = NO (WITH_CERES=OFF)")
ELSE()
+1 -1
View File
@@ -7,7 +7,7 @@ rtabmap
[![Downloads][downloads-image]][downloads]
[![License][license-image]][license]
[release-image]: https://img.shields.io/badge/release-0.21.0-green.svg?style=flat
[release-image]: https://img.shields.io/badge/release-0.21.4-green.svg?style=flat
[releases]: https://github.com/introlab/rtabmap/releases
[downloads-image]: https://img.shields.io/github/downloads/introlab/rtabmap/total?label=downloads
+90 -74
View File
@@ -65,15 +65,18 @@ ENDIF(APPLE AND BUILD_AS_BUNDLE)
IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
SET(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
SET(plugin_dest_dir bin)
SET(plugin_dest_dir bin/plugins)
SET(qtconf_dest_dir bin)
SET(openni2_dest_dir bin)
SET(thirdparty_dest_dir bin)
IF(APPLE)
SET(plugin_dest_dir MacOS)
SET(plugin_dest_dir MacOS/plugins)
IF(Qt6_FOUND)
SET(plugin_dest_dir PlugIns)
ENDIF()
SET(qtconf_dest_dir Resources)
SET(openni2_dest_dir MacOS)
SET(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/${CMAKE_BUNDLE_NAME}")
SET(thirdparty_dest_dir MacOS)
SET(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/${CMAKE_BUNDLE_NAME}")
ENDIF(APPLE)
IF(OpenNI2_FOUND)
@@ -89,11 +92,11 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
ENDIF()
INSTALL(DIRECTORY "${OpenNI2_BIN_DIR}/OpenNI2"
DESTINATION ${openni2_dest_dir}
DESTINATION ${thirdparty_dest_dir}
COMPONENT runtime
REGEX ".*pdb" EXCLUDE)
INSTALL(FILES "${OpenNI2_BIN_DIR}/OpenNI.ini"
DESTINATION ${openni2_dest_dir}
DESTINATION ${thirdparty_dest_dir}
COMPONENT runtime)
ENDIF(OpenNI2_FOUND)
@@ -102,7 +105,7 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
IF(WIN32)
file(TO_CMAKE_PATH "$ENV{K4A_ROOT_DIR}" ENV_K4A_ROOT_DIR)
INSTALL(FILES "${ENV_K4A_ROOT_DIR}/tools/depthengine_2_0.dll"
DESTINATION ${plugin_dest_dir}
DESTINATION ${thirdparty_dest_dir}
COMPONENT runtime)
ENDIF(WIN32)
ENDIF(k4a_FOUND)
@@ -117,7 +120,7 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
MESSAGE(STATUS "Found ${CUDNN_OPS_DLL}")
MESSAGE(STATUS "Found ${CUDNN_CNN_DLL}")
INSTALL(FILES ${CUDNN_OPS_DLL} ${CUDNN_CNN_DLL}
DESTINATION ${plugin_dest_dir}
DESTINATION ${thirdparty_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.")
@@ -132,82 +135,94 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
file(GENERATE OUTPUT ${deploy_script} CONTENT "
# Including the file pointed to by QT_DEPLOY_SUPPORT ensures the generated
# deployment script has access to qt_deploy_runtime_dependencies()
include(\"${QT_DEPLOY_SUPPORT}\")
include(\"${QT_DEPLOY_SUPPORT}\")
qt_deploy_runtime_dependencies(
EXECUTABLE \"${APPS}\"
PLUGINS_DIR ${plugin_dest_dir}
GENERATE_QT_CONF
NO_TRANSLATIONS
VERBOSE
PLUGINS_DIR ${plugin_dest_dir}/plugins
)")
IF("${CMAKE_BUILD_TYPE}" STREQUAL "" OR "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appDebug.cmake"
CONFIGURATIONS Debug
COMPONENT runtime)
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appRelease.cmake"
CONFIGURATIONS Release
COMPONENT runtime)
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appRelWithDebInfo.cmake"
CONFIGURATIONS RelWithDebInfo
COMPONENT runtime)
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appMinSizeRel.cmake"
CONFIGURATIONS MinSizeRel
COMPONENT runtime)
CONFIGURATIONS Debug
COMPONENT runtime)
ENDIF()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "" OR "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appRelease.cmake"
CONFIGURATIONS Release
COMPONENT runtime)
ENDIF()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appRelWithDebInfo.cmake"
CONFIGURATIONS RelWithDebInfo
COMPONENT runtime)
ENDIF()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "" OR "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/deploy_appMinSizeRel.cmake"
CONFIGURATIONS MinSizeRel
COMPONENT runtime)
ENDIF()
ELSEIF(Qt5_FOUND)
#Qt5
foreach(plugin ${Qt5Gui_PLUGINS})
get_target_property(plugin_loc ${plugin} LOCATION)
get_filename_component(plugin_dir ${plugin_loc} DIRECTORY)
string(REPLACE "plugins" ";" loc_list ${plugin_dir})
list(GET loc_list 1 plugin_type)
IF(NOT plugin_root)
get_filename_component(plugin_root ${plugin_dir} DIRECTORY)
ENDIF(NOT plugin_root)
#MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}/plugins${plugin_type}\"")
INSTALL(FILES ${plugin_loc}
DESTINATION ${plugin_dest_dir}/plugins${plugin_type}
COMPONENT runtime)
endforeach()
IF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0)
IF(WIN32)
SET(plugin_loc "${plugin_root}/styles/qwindowsvistastyle.dll")
ELSEIF(APPLE)
SET(plugin_loc "${plugin_root}/styles/libqmacstyle.dylib")
ENDIF()
IF(EXISTS ${plugin_loc})
get_filename_component(plugin_dir ${plugin_loc} DIRECTORY)
string(REPLACE "plugins" ";" loc_list ${plugin_dir})
list(GET loc_list 1 plugin_type)
INSTALL(FILES ${plugin_loc}
DESTINATION ${plugin_dest_dir}/plugins${plugin_type}
COMPONENT runtime)
#MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}/plugins${plugin_type}\"")
ENDIF(EXISTS ${plugin_loc})
ENDIF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0)
#Qt5
foreach(plugin ${Qt5Gui_PLUGINS})
get_target_property(plugin_loc ${plugin} LOCATION)
get_filename_component(plugin_dir ${plugin_loc} DIRECTORY)
string(REPLACE "plugins" ";" loc_list ${plugin_dir})
list(GET loc_list 1 plugin_type)
IF(NOT plugin_root)
get_filename_component(plugin_root ${plugin_dir} DIRECTORY)
ENDIF(NOT plugin_root)
#MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}${plugin_type}\"")
INSTALL(FILES ${plugin_loc}
DESTINATION ${plugin_dest_dir}${plugin_type}
COMPONENT runtime)
endforeach()
IF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0)
IF(WIN32)
SET(plugin_loc "${plugin_root}/styles/qwindowsvistastyle.dll")
ELSEIF(APPLE)
SET(plugin_loc "${plugin_root}/styles/libqmacstyle.dylib")
ENDIF()
IF(EXISTS ${plugin_loc})
get_filename_component(plugin_dir ${plugin_loc} DIRECTORY)
string(REPLACE "plugins" ";" loc_list ${plugin_dir})
list(GET loc_list 1 plugin_type)
INSTALL(FILES ${plugin_loc}
DESTINATION ${plugin_dest_dir}/plugins${plugin_type}
COMPONENT runtime)
#MESSAGE(STATUS "Qt5 plugin \"${plugin_loc}\" installed in \"${plugin_dest_dir}${plugin_type}\"")
ENDIF(EXISTS ${plugin_loc})
ENDIF(NOT Qt5Widgets_VERSION VERSION_LESS 5.10.0)
ELSEIF(QT_PLUGINS_DIR) # Qt4
# Install needed Qt plugins by copying directories from the qt installation
# One can cull what gets copied by using 'REGEX "..." EXCLUDE'
# Exclude debug libraries
INSTALL(DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
DESTINATION ${plugin_dest_dir}/plugins
COMPONENT runtime
REGEX ".*d4.dll" EXCLUDE
REGEX ".*d4.a" EXCLUDE)
# One can cull what gets copied by using 'REGEX "..." EXCLUDE'
# Exclude debug libraries
INSTALL(DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
DESTINATION ${plugin_dest_dir}
COMPONENT runtime
REGEX ".*d4.dll" EXCLUDE
REGEX ".*d4.a" EXCLUDE)
ENDIF()
# install a qt.conf file
# this inserts some cmake code into the install script to write the file
SET(QT_CONF_FILE [Paths]\nPlugins=plugins)
IF(APPLE)
SET(QT_CONF_FILE [Paths]\nPlugins=MacOS/plugins)
ENDIF(APPLE)
INSTALL(CODE "
file(WRITE \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"${QT_CONF_FILE}\")
" COMPONENT runtime)
IF(Qt5_FOUND OR QT4_FOUND)
# install a qt.conf file
# this inserts some cmake code into the install script to write the file
SET(QT_CONF_FILE [Paths]\nPlugins=plugins)
IF(APPLE)
SET(QT_CONF_FILE [Paths]\nPlugins=MacOS/plugins)
ENDIF(APPLE)
INSTALL(CODE "
file(WRITE \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"${QT_CONF_FILE}\")
" COMPONENT runtime)
ENDIF()
# directories to look for dependencies
SET(DIRS ${QT_LIBRARY_DIRS} ${PROJECT_BINARY_DIR}/bin)
SET(DIRS "${QT_LIBRARY_DIRS}" "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib")
IF(APPLE)
SET(DIRS ${DIRS} /usr/local /usr/local/lib /opt/homebrew /opt/homebrew/lib /opt/homebrew/lib/gcc/current)
ENDIF(APPLE)
ENDIF(APPLE)
# Now the work of copying dependencies into the bundle/package
# The quotes are escaped and variables to use at install time have their $ escaped
# An alternative is the do a configure_file() on a script and use install(SCRIPT ...).
@@ -215,10 +230,11 @@ IF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
# over.
# To find dependencies, cmake use "otool" on Apple and "dumpbin" on Windows (make sure you have one of them).
install(CODE "
file(GLOB_RECURSE QTPLUGINS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/plugins/*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
file(GLOB_RECURSE QTPLUGINS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(\"BundleUtilities\")
fixup_bundle(\"${APPS}\" \"\${QTPLUGINS}\" \"${DIRS}\")
" COMPONENT runtime)
" COMPONENT runtime)
ENDIF(BUILD_AS_BUNDLE AND (APPLE OR WIN32))
-3
View File
@@ -55,9 +55,6 @@ int main(int argc, char* argv[])
CoInitialize(nullptr);
#endif
#if VTK_MAJOR_VERSION >= 8 && defined(BUILD_AS_BUNDLE)
vtkObject::GlobalWarningDisplayOff();
#endif
#if VTK_MAJOR_VERSION > 9 || (VTK_MAJOR_VERSION==9 && VTK_MINOR_VERSION >= 1)
// needed to ensure appropriate OpenGL context is created for VTK rendering.
QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat());
+2 -2
View File
@@ -25,13 +25,13 @@ The following image shows when we do the same localization experiment at differe
We provide two formats: the first one is more general and the second one is used to produce the results in this paper with RTAB-Map. Please open issue if the links are outdated.
* [Images](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EV8F4PZUxOxLhwAyEehlzKwBjF-9xNuxR32Q4mUjx5u-rA?e=eCJ3TW):
* [Images](https://drive.google.com/file/d/1fUm1m8oW6q8qlThx7BjrBH2vrVbNQ9bQ/view?usp=drive_link):
* `rgb`: folder containing *.jpg color camera images
* `depth`: folder containing *.png 16bits mm depth images
* `calib`: folder containing calibration for each color image. Each calibration contains also the transform between `device` and `camera` frames as `local_transform`.
* `device_poses.txt`: VIO poses of each image in `device` frame
* `camera_poses.txt`: VIO poses of each image in `camera` frame
* [RTAB-Map Databases](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EU5fb0jEKzlGhPK3OWjMGLUBnDo1BRAoZwtB2czyeVLE_A?e=Y0JyXY)
* [RTAB-Map Databases](https://drive.google.com/file/d/1TklUcTKFSrcg8b0t0U80G_IpFRMVRlY5/view?usp=drive_link)
+1
View File
@@ -330,6 +330,7 @@ private:
bool _rehearsalWeightIgnoredWhileMoving;
bool _useOdometryFeatures;
bool _useOdometryGravity;
bool _rotateImagesUpsideUp;
bool _createOccupancyGrid;
int _visMaxFeatures;
bool _imagesAlreadyRectified;
@@ -231,6 +231,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Mem, UseOdomFeatures, bool, true, "Use odometry features instead of regenerating them.");
RTABMAP_PARAM(Mem, UseOdomGravity, bool, false, uFormat("Use odometry instead of IMU orientation to add gravity links to new nodes created. We assume that odometry is already aligned with gravity (e.g., we are using a VIO approach). Gravity constraints are used by graph optimization only if \"%s\" is not zero.", kOptimizerGravitySigma().c_str()));
RTABMAP_PARAM(Mem, CovOffDiagIgnored, bool, true, "Ignore off diagonal values of the covariance matrix.");
RTABMAP_PARAM(Mem, RotateImagesUpsideUp, bool, false, "Rotate images so that upside is up if they are not already. This can be useful in case the robots don't have all same camera orientation but are using the same map, so that not rotation-invariant visual features can still be used across the fleet.");
// KeypointMemory (Keypoint-based)
RTABMAP_PARAM(Kp, NNStrategy, int, 1, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
@@ -670,6 +671,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Vis, PnPVarianceMedianRatio, int, 4, uFormat("[%s = 1] Ratio used to compute variance of the estimated transformation if 3D correspondences are provided (should be > 1). The higher it is, the smaller the covariance will be. With accurate depth estimation, this could be set to 2. For depth estimated by stereo, 4 or more maybe used to ignore large errors of very far points.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, PnPMaxVariance, float, 0.0, uFormat("[%s = 1] Max linear variance between 3D point correspondences after PnP. 0 means disabled.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, PnPSamplingPolicy, unsigned int, 1, uFormat("[%s = 1] Multi-camera random sampling policy: 0=AUTO, 1=ANY, 2=HOMOGENEOUS. With HOMOGENEOUS policy, RANSAC will be done uniformly against all cameras, so at least 2 matches per camera are required. With ANY policy, RANSAC is not constraint to sample on all cameras at the same time. AUTO policy will use HOMOGENEOUS if there are at least 2 matches per camera, otherwise it will fallback to ANY policy.", kVisEstimationType().c_str()).c_str());
RTABMAP_PARAM(Vis, PnPSplitLinearCovComponents, bool, false, uFormat("[%s = 1] Compute variance for each linear component instead of using the combined XYZ variance for all linear components.", kVisEstimationType().c_str()).c_str());
RTABMAP_PARAM(Vis, EpipolarGeometryVar, float, 0.1, uFormat("[%s = 2] Epipolar geometry maximum variance to accept the transformation.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, MinInliers, int, 20, "Minimum feature correspondences to compute/accept the transformation.");
@@ -84,6 +84,7 @@ private:
int _PnPRefineIterations;
int _PnPVarMedianRatio;
float _PnPMaxVar;
bool _PnPSplitLinearCovarianceComponents;
unsigned int _multiSamplingPolicy;
int _correspondencesApproach;
int _flowWinSize;
@@ -49,7 +49,7 @@ public:
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
bool init(const rtabmap::CameraModel & model, double stamp, bool stereo, double baseline);
bool init(const rtabmap::CameraModel & model1, const rtabmap::CameraModel & model2, double stamp, bool stereo, double baseline);
private:
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 3
ORB_SLAM3::System * orbslam_;
+20
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/core/core.hpp>
#include <rtabmap/core/Transform.h>
#include <rtabmap/core/Parameters.h>
#include <rtabmap/core/CameraModel.h>
#include <vector>
namespace rtabmap
@@ -163,6 +164,25 @@ void RTABMAP_CORE_EXPORT NMS(
cv::Mat & descriptorsOut,
int border, int dist_thresh, int img_width, int img_height);
/**
* @brief Rotate images and camera model so that the top of the image is up.
*
* The roll value of local transform of the camera model is used to estimate
* if the images have to be rotated. If there is a pitch value higher than
* 45 deg, the original images and camera model will be returned (no rotation will happen).
* The return local transform of the camera model is updated accordingly. The distortion
* model is ignored and won't be transfered to modified camera model, so this function
* expects already rectified images.
*
* @param model a valid camera model
* @param rgb a rgb/grayscale image (set cv::Mat() if not used)
* @param depth a depth image (set cv::Mat() if not used)
*/
void RTABMAP_CORE_EXPORT rotateImagesUpsideUpIfNecessary(
CameraModel & model,
cv::Mat & rgb,
cv::Mat & depth);
} // namespace util3d
} // namespace rtabmap
@@ -54,7 +54,8 @@ Transform RTABMAP_CORE_EXPORT estimateMotion3DTo2D(
const std::map<int, cv::Point3f> & words3B = std::map<int, cv::Point3f>(),
cv::Mat * covariance = 0, // mean reproj error if words3B is not set
std::vector<int> * matchesOut = 0,
std::vector<int> * inliersOut = 0);
std::vector<int> * inliersOut = 0,
bool splitLinearCovarianceComponents = false);
Transform RTABMAP_CORE_EXPORT estimateMotion3DTo2D(
const std::map<int, cv::Point3f> & words3A,
@@ -72,7 +73,8 @@ Transform RTABMAP_CORE_EXPORT estimateMotion3DTo2D(
const std::map<int, cv::Point3f> & words3B = std::map<int, cv::Point3f>(),
cv::Mat * covariance = 0, // mean reproj error if words3B is not set
std::vector<int> * matchesOut = 0,
std::vector<int> * inliersOut = 0);
std::vector<int> * inliersOut = 0,
bool splitLinearCovarianceComponents = false);
Transform RTABMAP_CORE_EXPORT estimateMotion3DTo3D(
const std::map<int, cv::Point3f> & words3A,
+69 -27
View File
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/IMUFilter.h"
#include "rtabmap/core/Features2d.h"
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
#include <opencv2/imgproc/types_c.h>
#include <opencv2/stitching/detail/exposure_compensate.hpp>
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/ULogger.h>
@@ -543,46 +544,87 @@ void CameraThread::postUpdate(SensorData * dataPtr, CameraInfo * info) const
if(_histogramMethod && !data.imageRaw().empty())
{
if(data.imageRaw().type() == CV_8UC1)
UDEBUG("");
UTimer timer;
cv::Mat image;
if(_histogramMethod == 1)
{
UDEBUG("");
UTimer timer;
cv::Mat image;
if(_histogramMethod == 1)
if(data.imageRaw().type() == CV_8UC1)
{
cv::equalizeHist(data.imageRaw(), image);
if(!data.depthRaw().empty())
{
data.setRGBDImage(image, data.depthRaw(), data.cameraModels());
}
else if(!data.rightRaw().empty())
{
cv::Mat right;
cv::equalizeHist(data.rightRaw(), right);
data.setStereoImage(image, right, data.stereoCameraModels()[0]);
}
}
else if(_histogramMethod == 2)
else if(data.imageRaw().type() == CV_8UC3)
{
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0);
clahe->apply(data.imageRaw(), image);
if(!data.depthRaw().empty())
cv::Mat channels[3];
cv::cvtColor(data.imageRaw(), image, CV_BGR2YCrCb);
cv::split(image, channels);
cv::equalizeHist(channels[0], channels[0]);
cv::merge(channels, 3, image);
cv::cvtColor(image, image, CV_YCrCb2BGR);
}
if(!data.depthRaw().empty())
{
data.setRGBDImage(image, data.depthRaw(), data.cameraModels());
}
else if(!data.rightRaw().empty())
{
cv::Mat right;
if(data.rightRaw().type() == CV_8UC1)
{
data.setRGBDImage(image, data.depthRaw(), data.cameraModels());
cv::equalizeHist(data.rightRaw(), right);
}
else if(!data.rightRaw().empty())
else if(data.rightRaw().type() == CV_8UC3)
{
cv::Mat right;
clahe->apply(data.rightRaw(), right);
data.setStereoImage(image, right, data.stereoCameraModels()[0]);
cv::Mat channels[3];
cv::cvtColor(data.rightRaw(), right, CV_BGR2YCrCb);
cv::split(right, channels);
cv::equalizeHist(channels[0], channels[0]);
cv::merge(channels, 3, right);
cv::cvtColor(right, right, CV_YCrCb2BGR);
}
data.setStereoImage(image, right, data.stereoCameraModels()[0]);
}
if(info) info->timeHistogramEqualization = timer.ticks();
}
else
else if(_histogramMethod == 2)
{
UWARN("Histogram equalization only supports grayscale images...");
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0);
if(data.imageRaw().type() == CV_8UC1)
{
clahe->apply(data.imageRaw(), image);
}
else if(data.imageRaw().type() == CV_8UC3)
{
cv::Mat channels[3];
cv::cvtColor(data.imageRaw(), image, CV_BGR2YCrCb);
cv::split(image, channels);
clahe->apply(channels[0], channels[0]);
cv::merge(channels, 3, image);
cv::cvtColor(image, image, CV_YCrCb2BGR);
}
if(!data.depthRaw().empty())
{
data.setRGBDImage(image, data.depthRaw(), data.cameraModels());
}
else if(!data.rightRaw().empty())
{
cv::Mat right;
if(data.rightRaw().type() == CV_8UC1)
{
clahe->apply(data.rightRaw(), right);
}
else if(data.rightRaw().type() == CV_8UC3)
{
cv::Mat channels[3];
cv::cvtColor(data.rightRaw(), right, CV_BGR2YCrCb);
cv::split(right, channels);
clahe->apply(channels[0], channels[0]);
cv::merge(channels, 3, right);
cv::cvtColor(right, right, CV_YCrCb2BGR);
}
data.setStereoImage(image, right, data.stereoCameraModels()[0]);
}
}
if(info) info->timeHistogramEqualization = timer.ticks();
}
if(_stereoExposureCompensation && !data.imageRaw().empty() && !data.rightRaw().empty())
+4 -1
View File
@@ -734,7 +734,10 @@ std::vector<cv::KeyPoint> Feature2D::generateKeypoints(const cv::Mat & image, co
cv::Rect roi(globalRoi.x + j*colSize, globalRoi.y + i*rowSize, colSize, rowSize);
std::vector<cv::KeyPoint> subKeypoints;
subKeypoints = this->generateKeypointsImpl(image, roi, mask);
limitKeypoints(subKeypoints, maxFeatures);
if (this->getType() != Feature2D::Type::kFeaturePyDetector)
{
limitKeypoints(subKeypoints, maxFeatures);
}
if(roi.x || roi.y)
{
// Adjust keypoint position to raw image
+93 -1
View File
@@ -107,6 +107,7 @@ Memory::Memory(const ParametersMap & parameters) :
_rehearsalWeightIgnoredWhileMoving(Parameters::defaultMemRehearsalWeightIgnoredWhileMoving()),
_useOdometryFeatures(Parameters::defaultMemUseOdomFeatures()),
_useOdometryGravity(Parameters::defaultMemUseOdomGravity()),
_rotateImagesUpsideUp(Parameters::defaultMemRotateImagesUpsideUp()),
_createOccupancyGrid(Parameters::defaultRGBDCreateOccupancyGrid()),
_visMaxFeatures(Parameters::defaultVisMaxFeatures()),
_imagesAlreadyRectified(Parameters::defaultRtabmapImagesAlreadyRectified()),
@@ -597,6 +598,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
Parameters::parse(params, Parameters::kMemRehearsalWeightIgnoredWhileMoving(), _rehearsalWeightIgnoredWhileMoving);
Parameters::parse(params, Parameters::kMemUseOdomFeatures(), _useOdometryFeatures);
Parameters::parse(params, Parameters::kMemUseOdomGravity(), _useOdometryGravity);
Parameters::parse(params, Parameters::kMemRotateImagesUpsideUp(), _rotateImagesUpsideUp);
Parameters::parse(params, Parameters::kRGBDCreateOccupancyGrid(), _createOccupancyGrid);
Parameters::parse(params, Parameters::kVisMaxFeatures(), _visMaxFeatures);
Parameters::parse(params, Parameters::kRtabmapImagesAlreadyRectified(), _imagesAlreadyRectified);
@@ -3370,7 +3372,7 @@ bool Memory::addLink(const Link & link, bool addInDatabase)
{
UASSERT(link.type() > Link::kNeighbor && link.type() != Link::kUndef);
ULOGGER_INFO("to=%d, from=%d transform: %s var=%f", link.to(), link.from(), link.transform().prettyPrint().c_str(), link.transVariance());
ULOGGER_INFO("to=%d, from=%d transform: %s var=%f", link.to(), link.from(), link.transform().prettyPrint().c_str(), link.transVariance(false));
Signature * toS = _getSignature(link.to());
Signature * fromS = _getSignature(link.from());
if(toS && fromS)
@@ -4667,6 +4669,96 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
preUpdateThread.start();
}
if(_rotateImagesUpsideUp && !data.imageRaw().empty() && !data.cameraModels().empty())
{
// Currently stereo is not supported
UASSERT(int((data.imageRaw().cols/data.cameraModels().size())*data.cameraModels().size()) == data.imageRaw().cols);
int subInputImageWidth = data.imageRaw().cols/data.cameraModels().size();
int subInputDepthWidth = data.depthRaw().cols/data.cameraModels().size();
int subOutputImageWidth = 0;
int subOutputDepthWidth = 0;
cv::Mat rotatedColorImages;
cv::Mat rotatedDepthImages;
std::vector<CameraModel> rotatedCameraModels;
bool allOutputSizesAreOkay = true;
for(size_t i=0; i<data.cameraModels().size(); ++i)
{
UDEBUG("Rotating camera %ld", i);
cv::Mat rgb = cv::Mat(data.imageRaw(), cv::Rect(subInputImageWidth*i, 0, subInputImageWidth, data.imageRaw().rows));
cv::Mat depth = !data.depthRaw().empty()?cv::Mat(data.depthRaw(), cv::Rect(subInputDepthWidth*i, 0, subInputDepthWidth, data.depthRaw().rows)):cv::Mat();
CameraModel model = data.cameraModels()[i];
util2d::rotateImagesUpsideUpIfNecessary(model, rgb, depth);
if(rotatedColorImages.empty())
{
rotatedColorImages = cv::Mat(cv::Size(rgb.cols * data.cameraModels().size(), rgb.rows), rgb.type());
subOutputImageWidth = rgb.cols;;
if(!depth.empty())
{
rotatedDepthImages = cv::Mat(cv::Size(depth.cols * data.cameraModels().size(), depth.rows), depth.type());
subOutputDepthWidth = depth.cols;
}
}
else if(rgb.cols != subOutputImageWidth || depth.cols != subOutputDepthWidth ||
rgb.rows != rotatedColorImages.rows || depth.rows != rotatedDepthImages.rows)
{
UWARN("Rotated image for camera index %d (rgb=%dx%d depth=%dx%d) doesn't tally "
"with the first camera (rgb=%dx%d, depth=%dx%d). Aborting upside up rotation, "
"will use original image orientation. Set parameter %s to false to avoid "
"this warning.",
i,
rgb.cols, rgb.rows,
depth.cols, depth.rows,
subOutputImageWidth, rotatedColorImages.rows,
subOutputDepthWidth, rotatedDepthImages.rows,
Parameters::kMemRotateImagesUpsideUp().c_str());
allOutputSizesAreOkay = false;
break;
}
rgb.copyTo(cv::Mat(rotatedColorImages, cv::Rect(subOutputImageWidth*i, 0, subOutputImageWidth, rgb.rows)));
if(!depth.empty())
{
depth.copyTo(cv::Mat(rotatedDepthImages, cv::Rect(subOutputDepthWidth*i, 0, subOutputDepthWidth, depth.rows)));
}
rotatedCameraModels.push_back(model);
}
if(allOutputSizesAreOkay)
{
data.setRGBDImage(rotatedColorImages, rotatedDepthImages, rotatedCameraModels);
// Clear any features to avoid confusion with the rotated cameras.
if(!data.keypoints().empty() || !data.keypoints3D().empty() || !data.descriptors().empty())
{
if(_useOdometryFeatures)
{
static bool warned = false;
if(!warned)
{
UWARN("Because parameter %s is enabled, parameter %s is inhibited as "
"features have to be regenerated. To avoid this warning, set "
"explicitly %s to false. This message is only "
"printed once.",
Parameters::kMemRotateImagesUpsideUp().c_str(),
Parameters::kMemUseOdomFeatures().c_str(),
Parameters::kMemUseOdomFeatures().c_str());
warned = true;
}
}
data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
}
}
}
else if(_rotateImagesUpsideUp)
{
static bool warned = false;
if(!warned)
{
UWARN("Parameter %s can only be used with RGB-only or RGB-D cameras. "
"Ignoring upside up rotation. This message is only printed once.",
Parameters::kMemRotateImagesUpsideUp().c_str());
warned = true;
}
}
unsigned int preDecimation = 1;
std::vector<cv::Point3f> keypoints3D;
SensorData decimatedData;
+10 -1
View File
@@ -86,7 +86,7 @@ Odometry * Odometry::create(Odometry::Type & type, const ParametersMap & paramet
break;
case Odometry::kTypeORBSLAM:
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 2
odometry = new OdometryORBSLAM(parameters);
odometry = new OdometryORBSLAM2(parameters);
#else
odometry = new OdometryORBSLAM3(parameters);
#endif
@@ -335,6 +335,15 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
}
}
if(!data.imageRaw().empty())
{
UDEBUG("Processing image data %dx%d: rgbd models=%ld, stereo models=%ld",
data.imageRaw().cols,
data.imageRaw().rows,
data.cameraModels().size(),
data.stereoCameraModels().size());
}
if(!_imagesAlreadyRectified && !this->canProcessRawImages() && !data.imageRaw().empty())
{
+6
View File
@@ -814,6 +814,12 @@ ParametersMap Parameters::parseArguments(int argc, char * argv[], bool onlyParam
std::cout << str << std::setw(spacing - str.size()) << "true" << std::endl;
#else
std::cout << str << std::setw(spacing - str.size()) << "false" << std::endl;
#endif
str = "With Open3D:";
#ifdef RTABMAP_OPEN3D
std::cout << str << std::setw(spacing - str.size()) << "true" << std::endl;
#else
std::cout << str << std::setw(spacing - str.size()) << "false" << std::endl;
#endif
str = "With OctoMap:";
#ifdef RTABMAP_OCTOMAP
+7 -2
View File
@@ -72,6 +72,7 @@ RegistrationVis::RegistrationVis(const ParametersMap & parameters, Registration
_PnPRefineIterations(Parameters::defaultVisPnPRefineIterations()),
_PnPVarMedianRatio(Parameters::defaultVisPnPVarianceMedianRatio()),
_PnPMaxVar(Parameters::defaultVisPnPMaxVariance()),
_PnPSplitLinearCovarianceComponents(Parameters::defaultVisPnPSplitLinearCovComponents()),
_multiSamplingPolicy(Parameters::defaultVisPnPSamplingPolicy()),
_correspondencesApproach(Parameters::defaultVisCorType()),
_flowWinSize(Parameters::defaultVisCorFlowWinSize()),
@@ -130,6 +131,7 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kVisPnPRefineIterations(), _PnPRefineIterations);
Parameters::parse(parameters, Parameters::kVisPnPVarianceMedianRatio(), _PnPVarMedianRatio);
Parameters::parse(parameters, Parameters::kVisPnPMaxVariance(), _PnPMaxVar);
Parameters::parse(parameters, Parameters::kVisPnPSplitLinearCovComponents(), _PnPSplitLinearCovarianceComponents);
Parameters::parse(parameters, Parameters::kVisPnPSamplingPolicy(), _multiSamplingPolicy);
Parameters::parse(parameters, Parameters::kVisCorType(), _correspondencesApproach);
Parameters::parse(parameters, Parameters::kVisCorFlowWinSize(), _flowWinSize);
@@ -295,6 +297,7 @@ Transform RegistrationVis::computeTransformationImpl(
UDEBUG("%s=%f", Parameters::kVisPnPReprojError().c_str(), _PnPReprojError);
UDEBUG("%s=%d", Parameters::kVisPnPFlags().c_str(), _PnPFlags);
UDEBUG("%s=%f", Parameters::kVisPnPMaxVariance().c_str(), _PnPMaxVar);
UDEBUG("%s=%f", Parameters::kVisPnPSplitLinearCovComponents().c_str(), _PnPSplitLinearCovarianceComponents);
UDEBUG("%s=%d", Parameters::kVisCorType().c_str(), _correspondencesApproach);
UDEBUG("%s=%d", Parameters::kVisCorFlowWinSize().c_str(), _flowWinSize);
UDEBUG("%s=%d", Parameters::kVisCorFlowIterations().c_str(), _flowIterations);
@@ -1637,7 +1640,8 @@ Transform RegistrationVis::computeTransformationImpl(
words3B,
&covariances[dir],
&matchesV,
&inliersV);
&inliersV,
_PnPSplitLinearCovarianceComponents);
inliers[dir] = inliersV;
matches[dir] = matchesV;
}
@@ -1660,7 +1664,8 @@ Transform RegistrationVis::computeTransformationImpl(
words3B,
&covariances[dir],
&matchesV,
&inliersV);
&inliersV,
_PnPSplitLinearCovarianceComponents);
inliers[dir] = inliersV;
matches[dir] = matchesV;
}
+50 -8
View File
@@ -1442,8 +1442,10 @@ bool Rtabmap::process(
float angleToClosestNodeInTheGraph = 0;
if(_rgbdSlamMode)
{
statistics_.addStatistic(Statistics::kMemoryOdometry_variance_lin(), odomCovariance.empty()?1.0f:(float)odomCovariance.at<double>(0,0));
statistics_.addStatistic(Statistics::kMemoryOdometry_variance_ang(), odomCovariance.empty()?1.0f:(float)odomCovariance.at<double>(5,5));
double linVar = odomCovariance.empty()?1.0f:uMax3(odomCovariance.at<double>(0,0), odomCovariance.at<double>(1,1)>=9999?0:odomCovariance.at<double>(1,1), odomCovariance.at<double>(2,2)>=9999?0:odomCovariance.at<double>(2,2));
double angVar = odomCovariance.empty()?1.0f:uMax3(odomCovariance.at<double>(3,3)>=9999?0:odomCovariance.at<double>(3,3), odomCovariance.at<double>(4,4)>=9999?0:odomCovariance.at<double>(4,4), odomCovariance.at<double>(5,5));
statistics_.addStatistic(Statistics::kMemoryOdometry_variance_lin(), (float)linVar);
statistics_.addStatistic(Statistics::kMemoryOdometry_variance_ang(), (float)angVar);
//Verify if there was a rehearsal
int rehearsedId = (int)uValue(statistics_.data(), Statistics::kMemoryRehearsal_merged(), 0.0f);
@@ -1866,9 +1868,46 @@ bool Rtabmap::process(
//============================================================
// Bayes filter update
//============================================================
int previousId = signature->getLinks().size() && signature->getLinks().begin()->first!=signature->id()?signature->getLinks().begin()->first:0;
bool localizationOnPreviousUpdate = false;
if(_memory->isIncremental())
{
localizationOnPreviousUpdate =
signature->getLinks().size() &&
signature->getLinks().begin()->first!=signature->id() &&
_memory->getLoopClosureLinks(signature->getLinks().begin()->first, false).size() != 0;
}
else
{
// localization mode
// Count how many localization links are in the constraints
int localizationLinks = 0;
int previousIdWithLocalizationLink = 0;
for(std::multimap<int, Link>::iterator iter=_odomCacheConstraints.begin();
iter!=_odomCacheConstraints.end(); ++iter)
{
if(previousIdWithLocalizationLink == iter->first)
{
// ignore links with node already counted
continue;
}
if(iter->second.type() == Link::kGlobalClosure ||
iter->second.type() == Link::kLocalSpaceClosure ||
iter->second.type() == Link::kLocalTimeClosure ||
iter->second.type() == Link::kUserClosure ||
iter->second.type() == Link::kNeighborMerged ||
iter->second.type() == Link::kLandmark)
{
++localizationLinks;
previousIdWithLocalizationLink = iter->first;
}
}
localizationOnPreviousUpdate = localizationLinks > 1; // need two links in case we have delayed localization
}
// Not a bad signature, not an intermediate node, not a small displacement unless the previous signature didn't have a loop closure, not too fast movement
if(!signature->isBadSignature() && signature->getWeight()>=0 && (!smallDisplacement || _memory->getLoopClosureLinks(previousId, false).size() == 0) && !tooFastMovement)
if(!signature->isBadSignature() && signature->getWeight()>=0 && (!smallDisplacement || !localizationOnPreviousUpdate) && !tooFastMovement)
{
// If the working memory is empty, don't do the detection. It happens when it
// is the first time the detector is started (there needs some images to
@@ -2548,7 +2587,7 @@ bool Rtabmap::process(
// don't do it if it is a small displacement unless the previous signature didn't have a loop closure
// don't do it if there is a too fast movement
if((!smallDisplacement || _memory->getLoopClosureLinks(previousId, false).size() == 0) && !tooFastMovement)
if((!smallDisplacement || !localizationOnPreviousUpdate) && !tooFastMovement)
{
//============================================================
@@ -2959,9 +2998,10 @@ bool Rtabmap::process(
{
// Make the new one the parent of the old one
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
loopClosureLinearVariance = uMax3(info.covariance.at<double>(0,0), info.covariance.at<double>(1,1)>=9999?0:info.covariance.at<double>(1,1), info.covariance.at<double>(2,2)>=9999?0:info.covariance.at<double>(2,2));
loopClosureAngularVariance = uMax3(info.covariance.at<double>(3,3)>=9999?0:info.covariance.at<double>(3,3), info.covariance.at<double>(4,4)>=9999?0:info.covariance.at<double>(4,4), info.covariance.at<double>(5,5));
cv::Mat information = getInformation(info.covariance);
loopClosureLinearVariance = 1.0/information.at<double>(0,0);
loopClosureAngularVariance = 1.0/information.at<double>(5,5);
rejectedGlobalLoopClosure = !_memory->addLink(Link(signature->id(), _loopClosureHypothesis.first, Link::kGlobalClosure, transform, information));
if(!rejectedGlobalLoopClosure)
{
@@ -2987,7 +3027,7 @@ bool Rtabmap::process(
// Landmark
//============================================================
std::map<int, std::set<int> > landmarksDetected; // <Landmark ID, list of nodes that saw this landmark>
if(!signature->getLandmarks().empty())
if(!signature->getLandmarks().empty() && !_graphOptimizer->landmarksIgnored())
{
bool hasGlobalLoopClosuresInOdomCache = !graph::filterLinks(_odomCacheConstraints, Link::kGlobalClosure, true).empty() || _loopClosureHypothesis.first != 0;
UDEBUG("hasGlobalLoopClosuresInOdomCache=%d", hasGlobalLoopClosuresInOdomCache?1:0);
@@ -3487,6 +3527,7 @@ bool Rtabmap::process(
}
// update localization links
UASSERT(uContains(optPoses, signature->id()));
Transform newOptPoseInv = optPoses.at(signature->id()).inverse();
for(std::multimap<int, Link>::iterator iter=localizationLinks.begin(); iter!=localizationLinks.end(); ++iter)
{
@@ -3499,6 +3540,7 @@ bool Rtabmap::process(
else
{
// Adjust with optimized poses, this will smooth the localization
UASSERT(uContains(optPoses, iter->first));
Transform newT = newOptPoseInv * optPoses.at(iter->first);
UDEBUG("Adjusted localization link %d->%d after optimization", iter->second.from(), iter->second.to());
UDEBUG("from %s", iter->second.transform().prettyPrint().c_str());
+30 -12
View File
@@ -501,32 +501,47 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
#endif
sl::Resolution res = stereoParams->left_cam.image_size;
#if ZED_SDK_MAJOR_VERSION < 4
stereoModel_ = StereoCameraModel(
stereoParams->left_cam.fx,
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
stereoParams->T[0],//baseline
this->getLocalTransform(),
cv::Size(res.width, res.height));
#else
stereoModel_ = StereoCameraModel(
stereoParams->left_cam.fx,
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
#if ZED_SDK_MAJOR_VERSION < 4
stereoParams->T[0],//baseline
#else
stereoParams->getCameraBaseline(),
#endif
this->getLocalTransform(),
cv::Size(res.width, res.height));
#endif
#if ZED_SDK_MAJOR_VERSION < 4
UINFO("Calibration: fx=%f, fy=%f, cx=%f, cy=%f, baseline=%f, width=%d, height=%d, transform=%s",
stereoParams->left_cam.fx,
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
stereoParams->T[0],//baseline
(int)res.width,
(int)res.height,
this->getLocalTransform().prettyPrint().c_str());
#else
UINFO("Calibration: fx=%f, fy=%f, cx=%f, cy=%f, baseline=%f, width=%d, height=%d, transform=%s",
stereoParams->left_cam.fx,
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
#if ZED_SDK_MAJOR_VERSION < 4
stereoParams->T[0],//baseline
#else
stereoParams->getCameraBaseline(),
#endif
(int)res.width,
(int)res.height,
this->getLocalTransform().prettyPrint().c_str());
#endif
#if ZED_SDK_MAJOR_VERSION < 3
if(infos.camera_model == sl::MODEL_ZED_M)
@@ -539,12 +554,15 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
#else
imuLocalTransform_ = this->getLocalTransform() * zedPoseToTransform(infos.sensors_configuration.camera_imu_transform).inverse();
#endif
UINFO("IMU local transform: %s (imu2cam=%s))",
imuLocalTransform_.prettyPrint().c_str(),
#if ZED_SDK_MAJOR_VERSION < 4
zedPoseToTransform(infos.camera_imu_transform).prettyPrint().c_str());
UINFO("IMU local transform: %s (imu2cam=%s))",
imuLocalTransform_.prettyPrint().c_str(),
zedPoseToTransform(infos.camera_imu_transform).prettyPrint().c_str());
#else
zedPoseToTransform(infos.sensors_configuration.camera_imu_transform).prettyPrint().c_str());
UINFO("IMU local transform: %s (imu2cam=%s))",
imuLocalTransform_.prettyPrint().c_str(),
zedPoseToTransform(infos.sensors_configuration.camera_imu_transform).prettyPrint().c_str());
#endif
if(publishInterIMU_)
{
+55 -37
View File
@@ -103,7 +103,7 @@ bool OdometryORBSLAM3::canProcessAsyncIMU() const
#endif
}
bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, bool stereo, double baseline)
bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model1, const rtabmap::CameraModel & model2, double stamp, bool stereo, double baseline)
{
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 3
std::string vocabularyPath;
@@ -138,40 +138,45 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
ofs << fixed << setprecision(13);
//# Camera calibration and distortion parameters (OpenCV)
ofs << "Camera1.fx: " << model.fx() << std::endl;
ofs << "Camera1.fy: " << model.fy() << std::endl;
ofs << "Camera1.cx: " << model.cx() << std::endl;
ofs << "Camera1.cy: " << model.cy() << std::endl;
ofs << std::endl;
for(int i=1; i<(stereo?3:2); ++i)
{
const CameraModel & model = i==1?model1:model2;
if(model.D().cols < 4)
{
ofs << "Camera1.k1: " << 0.0 << std::endl;
ofs << "Camera1.k2: " << 0.0 << std::endl;
ofs << "Camera1.p1: " << 0.0 << std::endl;
ofs << "Camera1.p2: " << 0.0 << std::endl;
if(!stereo)
//# Camera calibration and distortion parameters (OpenCV)
ofs << "Camera" << i << ".fx: " << model.fx() << std::endl;
ofs << "Camera" << i << ".fy: " << model.fy() << std::endl;
ofs << "Camera" << i << ".cx: " << model.cx() << std::endl;
ofs << "Camera" << i << ".cy: " << model.cy() << std::endl;
ofs << std::endl;
if(model.D().cols < 4)
{
ofs << "Camera1.k3: " << 0.0 << std::endl;
ofs << "Camera" << i << ".k1: " << 0.0 << std::endl;
ofs << "Camera" << i << ".k2: " << 0.0 << std::endl;
ofs << "Camera" << i << ".p1: " << 0.0 << std::endl;
ofs << "Camera" << i << ".p2: " << 0.0 << std::endl;
if(!stereo)
{
ofs << "Camera" << i << ".k3: " << 0.0 << std::endl;
}
}
if(model.D().cols >= 4)
{
ofs << "Camera" << i << ".k1: " << model.D().at<double>(0,0) << std::endl;
ofs << "Camera" << i << ".k2: " << model.D().at<double>(0,1) << std::endl;
ofs << "Camera" << i << ".p1: " << model.D().at<double>(0,2) << std::endl;
ofs << "Camera" << i << ".p2: " << model.D().at<double>(0,3) << std::endl;
}
if(model.D().cols >= 5)
{
ofs << "Camera" << i << ".k3: " << model.D().at<double>(0,4) << std::endl;
}
if(model.D().cols > 5)
{
UWARN("Unhandled camera distortion size %d, only 5 first coefficients used", model.D().cols);
}
ofs << std::endl;
}
if(model.D().cols >= 4)
{
ofs << "Camera1.k1: " << model.D().at<double>(0,0) << std::endl;
ofs << "Camera1.k2: " << model.D().at<double>(0,1) << std::endl;
ofs << "Camera1.p1: " << model.D().at<double>(0,2) << std::endl;
ofs << "Camera1.p2: " << model.D().at<double>(0,3) << std::endl;
}
if(model.D().cols >= 5)
{
ofs << "Camera1.k3: " << model.D().at<double>(0,4) << std::endl;
}
if(model.D().cols > 5)
{
UWARN("Unhandled camera distortion size %d, only 5 first coefficients used", model.D().cols);
}
ofs << std::endl;
//# IR projector baseline times fx (aprox.)
if(baseline <= 0.0)
@@ -179,15 +184,28 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
baseline = rtabmap::Parameters::defaultOdomORBSLAMBf();
rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAMBf(), baseline);
}
ofs << "Camera.bf: " << model.fx()*baseline << std::endl;
else
{
// # Transformation matrix from right camera to left camera
ofs << "Stereo.T_c1_c2: !!opencv-matrix" << std::endl;
ofs << " rows: 4" << std::endl;
ofs << " cols: 4" << std::endl;
ofs << " dt: f" << std::endl;
ofs << " data: [" << 1 << ", " << 0 << ", " << 0 << ", " << baseline << ", " << std::endl;
ofs << " " << 0 << ", " << 1 << ", " << 0 << ", " << 0 << ", " << std::endl;
ofs << " " << 0 << ", " << 0 << ", " << 1 << ", " << 0 << ", " << std::endl;
ofs << " 0.0, 0.0, 0.0, 1.0]" << std::endl;
ofs << std::endl;
}
ofs << "Camera.bf: " << model1.fx()*baseline << std::endl;
ofs << "Camera.width: " << model.imageWidth() << std::endl;
ofs << "Camera.height: " << model.imageHeight() << std::endl;
ofs << "Camera.width: " << model1.imageWidth() << std::endl;
ofs << "Camera.height: " << model1.imageHeight() << std::endl;
ofs << std::endl;
//# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
//Camera.RGB: 1
ofs << "Camera.RGB: 1" << std::endl;
ofs << "Camera.RGB: 0" << std::endl;
ofs << std::endl;
float fps = rtabmap::Parameters::defaultOdomORBSLAMFps();
@@ -222,7 +240,7 @@ bool OdometryORBSLAM3::init(const rtabmap::CameraModel & model, double stamp, b
//# IMU Parameters TODO: hard-coded, not used
//#--------------------------------------------------------------------------------------------
// Transformation from camera 0 to body-frame (imu)
rtabmap::Transform camImuT = model.localTransform()*imuLocalTransform_;
rtabmap::Transform camImuT = model1.localTransform()*imuLocalTransform_;
ofs << "IMU.T_b_c1: !!opencv-matrix" << std::endl;
ofs << " rows: 4" << std::endl;
ofs << " cols: 4" << std::endl;
@@ -418,7 +436,7 @@ Transform OdometryORBSLAM3::computeTransform(
}
CameraModel model = data.cameraModels().size()==1?data.cameraModels()[0]:data.stereoCameraModels()[0].left();
if(!init(model, data.stamp(), stereo, data.cameraModels().size()==1?0.0:data.stereoCameraModels()[0].baseline()))
if(!init(model, !stereo?model:data.stereoCameraModels()[0].right(), data.stamp(), stereo, data.cameraModels().size()==1?0.0:data.stereoCameraModels()[0].baseline()))
{
return t;
}
+159 -36
View File
@@ -2054,7 +2054,43 @@ bool OptimizerG2O::saveGraph(
q.w());
}
int landmarkOffset = poses.size()&&poses.rbegin()->first>0?poses.rbegin()->first+1:0;
// For landmarks, determinate which one has observation with orientation
std::map<int, bool> isLandmarkWithRotation;
for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{
int landmarkId = iter->second.from() < 0?iter->second.from():iter->second.to() < 0?iter->second.to():0;
if(landmarkId != 0 && isLandmarkWithRotation.find(landmarkId) == isLandmarkWithRotation.end())
{
if(isSlam2d())
{
if (1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0)
{
isLandmarkWithRotation.insert(std::make_pair(landmarkId, false));
UDEBUG("Tag %d has no orientation", landmarkId);
}
else
{
isLandmarkWithRotation.insert(std::make_pair(landmarkId, true));
UDEBUG("Tag %d has orientation", landmarkId);
}
}
else if (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)
{
isLandmarkWithRotation.insert(std::make_pair(landmarkId, false));
UDEBUG("Tag %d has no orientation", landmarkId);
}
else
{
isLandmarkWithRotation.insert(std::make_pair(landmarkId, true));
UDEBUG("Tag %d has orientation", landmarkId);
}
}
}
int landmarkOffset = poses.size()&&poses.rbegin()->first>0?poses.rbegin()->first:0;
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
if (isSlam2d())
@@ -2063,18 +2099,30 @@ bool OptimizerG2O::saveGraph(
{
// VERTEX_SE2 id x y theta
fprintf(file, "VERTEX_SE2 %d %f %f %f\n",
landmarkOffset-iter->first,
iter->first,
iter->second.x(),
iter->second.y(),
iter->second.theta());
}
else if(!landmarksIgnored())
{
// VERTEX_XY id x y
fprintf(file, "VERTEX_XY %d %f %f\n",
iter->first,
iter->second.x(),
iter->second.y());
if(uValue(isLandmarkWithRotation, iter->first, false))
{
// VERTEX_SE2 id x y theta
fprintf(file, "VERTEX_SE2 %d %f %f %f\n",
landmarkOffset-iter->first,
iter->second.x(),
iter->second.y(),
iter->second.theta());
}
else
{
// VERTEX_XY id x y
fprintf(file, "VERTEX_XY %d %f %f\n",
landmarkOffset-iter->first,
iter->second.x(),
iter->second.y());
}
}
}
else
@@ -2095,12 +2143,29 @@ bool OptimizerG2O::saveGraph(
}
else if(!landmarksIgnored())
{
// VERTEX_TRACKXYZ id x y z
fprintf(file, "VERTEX_TRACKXYZ %d %f %f %f\n",
landmarkOffset-iter->first,
iter->second.x(),
iter->second.y(),
iter->second.z());
if(uValue(isLandmarkWithRotation, iter->first, false))
{
// VERTEX_SE3 id x y z qw qx qy qz
Eigen::Quaternionf q = iter->second.getQuaternionf();
fprintf(file, "VERTEX_SE3:QUAT %d %f %f %f %f %f %f %f\n",
landmarkOffset-iter->first,
iter->second.x(),
iter->second.y(),
iter->second.z(),
q.x(),
q.y(),
q.z(),
q.w());
}
else
{
// VERTEX_TRACKXYZ id x y z
fprintf(file, "VERTEX_TRACKXYZ %d %f %f %f\n",
landmarkOffset-iter->first,
iter->second.x(),
iter->second.y(),
iter->second.z());
}
}
}
}
@@ -2116,32 +2181,90 @@ bool OptimizerG2O::saveGraph(
}
if(isSlam2d())
{
// EDGE_SE2_XY observed_vertex_id observing_vertex_id x y inf_11 inf_12 inf_22
fprintf(file, "EDGE_SE2_XY %d %d %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(1, 1));
if(uValue(isLandmarkWithRotation, iter->first, false))
{
// EDGE_SE2 observed_vertex_id observing_vertex_id x y qx qy qz qw inf_11 inf_12 inf_13 inf_22 inf_23 inf_33
fprintf(file, "EDGE_SE2 %d %d %f %f %f %f %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.transform().theta(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(0, 5),
iter->second.infMatrix().at<double>(1, 1),
iter->second.infMatrix().at<double>(1, 5),
iter->second.infMatrix().at<double>(5, 5));
}
else
{
// EDGE_SE2_XY observed_vertex_id observing_vertex_id x y inf_11 inf_12 inf_22
fprintf(file, "EDGE_SE2_XY %d %d %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(1, 1));
}
}
else
{
// EDGE_SE3_TRACKXYZ observed_vertex_id observing_vertex_id param_offset x y z inf_11 inf_12 inf_13 inf_22 inf_23 inf_33
fprintf(file, "EDGE_SE3_TRACKXYZ %d %d %d %f %f %f %f %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
PARAM_OFFSET,
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.transform().z(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(0, 2),
iter->second.infMatrix().at<double>(1, 1),
iter->second.infMatrix().at<double>(1, 2),
iter->second.infMatrix().at<double>(2, 2));
if(uValue(isLandmarkWithRotation, iter->first, false))
{
// EDGE_SE3 observed_vertex_id observing_vertex_id x y z qx qy qz qw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
Eigen::Quaternionf q = iter->second.transform().getQuaternionf();
fprintf(file, "EDGE_SE3 %d %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.transform().z(),
q.x(),
q.y(),
q.z(),
q.w(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(0, 2),
iter->second.infMatrix().at<double>(0, 3),
iter->second.infMatrix().at<double>(0, 4),
iter->second.infMatrix().at<double>(0, 5),
iter->second.infMatrix().at<double>(1, 1),
iter->second.infMatrix().at<double>(1, 2),
iter->second.infMatrix().at<double>(1, 3),
iter->second.infMatrix().at<double>(1, 4),
iter->second.infMatrix().at<double>(1, 5),
iter->second.infMatrix().at<double>(2, 2),
iter->second.infMatrix().at<double>(2, 3),
iter->second.infMatrix().at<double>(2, 4),
iter->second.infMatrix().at<double>(2, 5),
iter->second.infMatrix().at<double>(3, 3),
iter->second.infMatrix().at<double>(3, 4),
iter->second.infMatrix().at<double>(3, 5),
iter->second.infMatrix().at<double>(4, 4),
iter->second.infMatrix().at<double>(4, 5),
iter->second.infMatrix().at<double>(5, 5));
}
else
{
// EDGE_SE3_TRACKXYZ observed_vertex_id observing_vertex_id param_offset x y z inf_11 inf_12 inf_13 inf_22 inf_23 inf_33
fprintf(file, "EDGE_SE3_TRACKXYZ %d %d %d %f %f %f %f %f %f %f %f %f\n",
iter->second.from()<0?landmarkOffset-iter->second.from():iter->second.from(),
iter->second.to()<0?landmarkOffset-iter->second.to():iter->second.to(),
PARAM_OFFSET,
iter->second.transform().x(),
iter->second.transform().y(),
iter->second.transform().z(),
iter->second.infMatrix().at<double>(0, 0),
iter->second.infMatrix().at<double>(0, 1),
iter->second.infMatrix().at<double>(0, 2),
iter->second.infMatrix().at<double>(1, 1),
iter->second.infMatrix().at<double>(1, 2),
iter->second.infMatrix().at<double>(2, 2));
}
}
continue;
}
+28 -28
View File
@@ -3,7 +3,6 @@
*/
#include <superpoint_torch/SuperPoint.h>
#include <rtabmap/core/util2d.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UFile.h>
@@ -155,9 +154,31 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
x = x.set_requires_grad(false);
auto out = model_->forward(x.to(device));
prob_ = out[0].squeeze(0); // [H, W]
auto scores = out[0]; // [1, H, W]
desc_ = out[1]; // [1, 256, H/8, W/8]
if(nms_)
{
auto options = torch::nn::functional::MaxPool2dFuncOptions(minDistance_*2+1).stride(1).padding(minDistance_);
auto options_r1 = torch::nn::functional::MaxPool2dFuncOptions(3).stride(1).padding(1);
auto zeros = torch::zeros_like(scores);
auto max_mask = scores == torch::nn::functional::max_pool2d(scores, options);
auto max_mask_r1 = scores == torch::nn::functional::max_pool2d(scores, options_r1);
for(size_t i=0; i<2; i++)
{
auto supp_mask = torch::nn::functional::max_pool2d(max_mask.to(torch::kF32), options) > 0;
auto supp_scores = torch::where(supp_mask, zeros, scores);
auto new_max_mask = supp_scores == torch::nn::functional::max_pool2d(supp_scores, options);
max_mask = max_mask | (new_max_mask & (~supp_mask) & max_mask_r1);
}
prob_ = torch::where(max_mask, scores, zeros).squeeze(0);
}
else
{
prob_ = scores.squeeze(0);
}
auto kpts = (prob_ > threshold_);
kpts = torch::nonzero(kpts); // [n_keypoints, 2] (y, x)
@@ -165,39 +186,18 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
auto kpts_cpu = kpts.to(torch::kCPU);
auto prob_cpu = prob_.to(torch::kCPU);
std::vector<cv::KeyPoint> keypoints_no_nms;
for (int i = 0; i < kpts_cpu.size(0); i++) {
std::vector<cv::KeyPoint> keypoints;
for(int i=0; i<kpts_cpu.size(0); i++)
{
if(mask.empty() || mask.at<unsigned char>(kpts_cpu[i][0].item<int>(), kpts_cpu[i][1].item<int>()) != 0)
{
float response = prob_cpu[kpts_cpu[i][0]][kpts_cpu[i][1]].item<float>();
keypoints_no_nms.push_back(cv::KeyPoint(kpts_cpu[i][1].item<float>(), kpts_cpu[i][0].item<float>(), 8, -1, response));
keypoints.emplace_back(cv::KeyPoint(kpts_cpu[i][1].item<float>(), kpts_cpu[i][0].item<float>(), 8, -1, response));
}
}
detected_ = true;
if (nms_ && !keypoints_no_nms.empty()) {
int border = 0;
int dist_thresh = minDistance_;
int height = img.rows;
int width = img.cols;
std::vector<cv::KeyPoint> keypoints;
cv::Mat descEmpty;
util2d::NMS(keypoints_no_nms, descEmpty, keypoints, descEmpty, border, dist_thresh, width, height);
if(keypoints.size()>1)
{
return keypoints;
}
return std::vector<cv::KeyPoint>();
}
else if(keypoints_no_nms.size()>1)
{
return keypoints_no_nms;
}
else
{
return std::vector<cv::KeyPoint>();
}
return keypoints;
}
else
{
+92
View File
@@ -2202,6 +2202,98 @@ void NMS(
}
}
void rotateImagesUpsideUpIfNecessary(
CameraModel & model,
cv::Mat & rgb,
cv::Mat & depth)
{
float roll,pitch,yaw;
// remove optical rotation
Transform localTransform = model.localTransform()*CameraModel::opticalRotation().inverse();
localTransform.getEulerAngles(roll, pitch, yaw);
UDEBUG("roll=%f pitch=%f yaw=%f", roll, pitch, yaw);
if(fabs(pitch > M_PI/4))
{
// Return original because of ambiguity for what would be considered up...
UDEBUG("Ignoring image rotation as pitch(%f)>Pi/4", pitch);
return;
}
if(roll<0)
{
roll+=2*M_PI;
}
if(roll >= M_PI/4 && roll < 3*M_PI/4)
{
UDEBUG("ROTATION_90 (roll=%f)", roll);
if(!rgb.empty())
{
cv::flip(rgb,rgb,1);
cv::transpose(rgb,rgb);
}
if(!depth.empty())
{
cv::flip(depth,depth,1);
cv::transpose(depth,depth);
}
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(
model.fy(),
model.fx(),
model.cy(),
model.cx()>0?model.imageWidth()-model.cx():0,
model.localTransform()*rtabmap::Transform(0,-1,0,0, 1,0,0,0, 0,0,1,0));
model.setImageSize(sizet);
}
else if(roll >= 3*M_PI/4 && roll < 5*M_PI/4)
{
UDEBUG("ROTATION_180 (roll=%f)", roll);
if(!rgb.empty())
{
cv::flip(rgb,rgb,1);
cv::flip(rgb,rgb,0);
}
if(!depth.empty())
{
cv::flip(depth,depth,1);
cv::flip(depth,depth,0);
}
cv::Size sizet(model.imageWidth(), model.imageHeight());
model = CameraModel(
model.fx(),
model.fy(),
model.cx()>0?model.imageWidth()-model.cx():0,
model.cy()>0?model.imageHeight()-model.cy():0,
model.localTransform()*rtabmap::Transform(0,0,0,0,0,1,0));
model.setImageSize(sizet);
}
else if(roll >= 5*M_PI/4 && roll < 7*M_PI/4)
{
UDEBUG("ROTATION_270 (roll=%f)", roll);
if(!rgb.empty())
{
cv::transpose(rgb,rgb);
cv::flip(rgb,rgb,1);
}
if(!depth.empty())
{
cv::transpose(depth,depth);
cv::flip(depth,depth,1);
}
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(
model.fy(),
model.fx(),
model.cy()>0?model.imageHeight()-model.cy():0,
model.cx(),
model.localTransform()*rtabmap::Transform(0,1,0,0, -1,0,0,0, 0,0,1,0));
model.setImageSize(sizet);
}
else
{
UDEBUG("ROTATION_0 (roll=%f)", roll);
}
}
}
}
+113 -18
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/UStl.h"
#include "rtabmap/utilite/UMath.h"
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/utilite/UTimer.h"
#include "rtabmap/core/util3d_transforms.h"
#include "rtabmap/core/util3d_registration.h"
#include "rtabmap/core/util3d_correspondences.h"
@@ -70,7 +71,8 @@ Transform estimateMotion3DTo2D(
const std::map<int, cv::Point3f> & words3B,
cv::Mat * covariance,
std::vector<int> * matchesOut,
std::vector<int> * inliersOut)
std::vector<int> * inliersOut,
bool splitLinearCovarianceComponents)
{
UASSERT(cameraModel.isValidForProjection());
UASSERT(!guess.isNull());
@@ -155,25 +157,36 @@ Transform estimateMotion3DTo2D(
if(covariance && (!words3B.empty() || cameraModel.imageSize() != cv::Size()))
{
std::vector<float> errorSqrdDists(inliers.size());
std::vector<float> errorSqrdX;
std::vector<float> errorSqrdY;
std::vector<float> errorSqrdZ;
if(splitLinearCovarianceComponents)
{
errorSqrdX.resize(inliers.size());
errorSqrdY.resize(inliers.size());
errorSqrdZ.resize(inliers.size());
}
std::vector<float> errorSqrdAngles(inliers.size());
Transform localTransformInv = cameraModel.localTransform().inverse();
Transform transformCameraFrameInv = (transform * cameraModel.localTransform()).inverse();
Transform transformCameraFrame = transform * cameraModel.localTransform();
Transform transformCameraFrameInv = transformCameraFrame.inverse();
for(unsigned int i=0; i<inliers.size(); ++i)
{
cv::Point3f objPt = objectPoints[inliers[i]];
// Project obj point from base frame of cameraA in cameraB frame (z+ in front of the cameraB)
objPt = util3d::transformPoint(objPt, transformCameraFrameInv);
// Get 3D point from target in cameraB frame
// Get 3D point from cameraB base frame in cameraA base frame
std::map<int, cv::Point3f>::const_iterator iter = words3B.find(matches[inliers[i]]);
cv::Point3f newPt;
if(iter!=words3B.end() && util3d::isFinite(iter->second))
{
newPt = util3d::transformPoint(iter->second, localTransformInv);
newPt = util3d::transformPoint(iter->second, transform);
}
else
{
// Project obj point from base frame of cameraA in cameraB frame (z+ in front of the cameraB)
cv::Point3f objPtCamBFrame = util3d::transformPoint(objPt, transformCameraFrameInv);
//compute from projection
Eigen::Vector3f ray = projectDepthTo3DRay(
cameraModel.imageSize(),
@@ -184,7 +197,20 @@ Transform estimateMotion3DTo2D(
cameraModel.fx(),
cameraModel.fy());
// transform in camera B frame
newPt = cv::Point3f(ray.x(), ray.y(), ray.z()) * objPt.z*1.1; // Add 10 % error
newPt = cv::Point3f(ray.x(), ray.y(), ray.z()) * objPtCamBFrame.z*1.1; // Add 10 % error
//transform back into cameraA base frame
newPt = util3d::transformPoint(newPt, transformCameraFrame);
}
if(splitLinearCovarianceComponents)
{
double errorX = objPt.x-newPt.x;
double errorY = objPt.y-newPt.y;
double errorZ = objPt.z-newPt.z;
errorSqrdX[i] = errorX * errorX;
errorSqrdY[i] = errorY * errorY;
errorSqrdZ[i] = errorZ * errorZ;
}
errorSqrdDists[i] = uNormSquared(objPt.x-newPt.x, objPt.y-newPt.y, objPt.z-newPt.z);
@@ -204,6 +230,25 @@ Transform estimateMotion3DTo2D(
UASSERT(uIsFinite(median_error_sqr_ang));
(*covariance)(cv::Range(3,6), cv::Range(3,6)) *= median_error_sqr_ang;
if(splitLinearCovarianceComponents)
{
std::sort(errorSqrdX.begin(), errorSqrdX.end());
double median_error_sqr_x = 2.1981 * (double)errorSqrdX[errorSqrdX.size () / varianceMedianRatio];
std::sort(errorSqrdY.begin(), errorSqrdY.end());
double median_error_sqr_y = 2.1981 * (double)errorSqrdY[errorSqrdY.size () / varianceMedianRatio];
std::sort(errorSqrdZ.begin(), errorSqrdZ.end());
double median_error_sqr_z = 2.1981 * (double)errorSqrdZ[errorSqrdZ.size () / varianceMedianRatio];
UASSERT(uIsFinite(median_error_sqr_x));
UASSERT(uIsFinite(median_error_sqr_y));
UASSERT(uIsFinite(median_error_sqr_z));
covariance->at<double>(0,0) = median_error_sqr_x;
covariance->at<double>(1,1) = median_error_sqr_y;
covariance->at<double>(2,2) = median_error_sqr_z;
median_error_sqr_lin = uMax3(median_error_sqr_x, median_error_sqr_y, median_error_sqr_z);
}
if(maxVariance > 0 && median_error_sqr_lin > maxVariance)
{
UWARN("Rejected PnP transform, variance is too high! %f > %f!", median_error_sqr_lin, maxVariance);
@@ -259,7 +304,8 @@ Transform estimateMotion3DTo2D(
const std::map<int, cv::Point3f> & words3B,
cv::Mat * covariance,
std::vector<int> * matchesOut,
std::vector<int> * inliersOut)
std::vector<int> * inliersOut,
bool splitLinearCovarianceComponents)
{
Transform transform;
#ifndef RTABMAP_OPENGV
@@ -491,27 +537,44 @@ Transform estimateMotion3DTo2D(
// compute variance (like in PCL computeVariance() method of sac_model.h)
if(covariance)
{
std::vector<float> errorSqrdX;
std::vector<float> errorSqrdY;
std::vector<float> errorSqrdZ;
if(splitLinearCovarianceComponents)
{
errorSqrdX.resize(inliers.size());
errorSqrdY.resize(inliers.size());
errorSqrdZ.resize(inliers.size());
}
std::vector<float> errorSqrdDists(inliers.size());
std::vector<float> errorSqrdAngles(inliers.size());
std::vector<Transform> transformsCameraFrame(cameraModels.size());
std::vector<Transform> transformsCameraFrameInv(cameraModels.size());
for(size_t i=0; i<cameraModels.size(); ++i)
{
transformsCameraFrame[i] = transform * cameraModels[i].localTransform();
transformsCameraFrameInv[i] = transformsCameraFrame[i].inverse();
}
for(unsigned int i=0; i<inliers.size(); ++i)
{
cv::Point3f objPt = objectPoints[inliers[i]];
int cameraIndex = cameraIndexes[inliers[i]];
Transform transformCameraFrameInv = (transform * cameraModels[cameraIndex].localTransform()).inverse();
// Project obj point from base frame of cameraA in cameraB frame (z+ in front of the cameraB)
objPt = util3d::transformPoint(objPt, transformCameraFrameInv);
// Get 3D point from target in cameraB frame
// Get 3D point from cameraB base frame in cameraA base frame
std::map<int, cv::Point3f>::const_iterator iter = words3B.find(matches[inliers[i]]);
cv::Point3f newPt;
if(iter!=words3B.end() && util3d::isFinite(iter->second))
{
newPt = util3d::transformPoint(iter->second, cameraModels[cameraIndex].localTransform().inverse());
newPt = util3d::transformPoint(iter->second, transform);
}
else
{
int cameraIndex = cameraIndexes[inliers[i]];
// Project obj point from base frame of cameraA in cameraB frame (z+ in front of the cameraB)
cv::Point3f objPtCamBFrame = util3d::transformPoint(objPt, transformsCameraFrameInv[cameraIndex]);
//compute from projection
Eigen::Vector3f ray = projectDepthTo3DRay(
cameraModels[cameraIndex].imageSize(),
@@ -522,7 +585,20 @@ Transform estimateMotion3DTo2D(
cameraModels[cameraIndex].fx(),
cameraModels[cameraIndex].fy());
// transform in camera B frame
newPt = cv::Point3f(ray.x(), ray.y(), ray.z()) * objPt.z*1.1; // Add 10 % error
newPt = cv::Point3f(ray.x(), ray.y(), ray.z()) * objPtCamBFrame.z*1.1; // Add 10 % error
//transfor back into cameraA base frame
newPt = util3d::transformPoint(newPt, transformsCameraFrame[cameraIndex]);
}
if(splitLinearCovarianceComponents)
{
double errorX = objPt.x-newPt.x;
double errorY = objPt.y-newPt.y;
double errorZ = objPt.z-newPt.z;
errorSqrdX[i] = errorX * errorX;
errorSqrdY[i] = errorY * errorY;
errorSqrdZ[i] = errorZ * errorZ;
}
errorSqrdDists[i] = uNormSquared(objPt.x-newPt.x, objPt.y-newPt.y, objPt.z-newPt.z);
@@ -542,6 +618,25 @@ Transform estimateMotion3DTo2D(
UASSERT(uIsFinite(median_error_sqr_ang));
(*covariance)(cv::Range(3,6), cv::Range(3,6)) *= median_error_sqr_ang;
if(splitLinearCovarianceComponents)
{
std::sort(errorSqrdX.begin(), errorSqrdX.end());
double median_error_sqr_x = 2.1981 * (double)errorSqrdX[errorSqrdX.size () / varianceMedianRatio];
std::sort(errorSqrdY.begin(), errorSqrdY.end());
double median_error_sqr_y = 2.1981 * (double)errorSqrdY[errorSqrdY.size () / varianceMedianRatio];
std::sort(errorSqrdZ.begin(), errorSqrdZ.end());
double median_error_sqr_z = 2.1981 * (double)errorSqrdZ[errorSqrdZ.size () / varianceMedianRatio];
UASSERT(uIsFinite(median_error_sqr_x));
UASSERT(uIsFinite(median_error_sqr_y));
UASSERT(uIsFinite(median_error_sqr_z));
covariance->at<double>(0,0) = median_error_sqr_x;
covariance->at<double>(1,1) = median_error_sqr_y;
covariance->at<double>(2,2) = median_error_sqr_z;
median_error_sqr_lin = uMax3(median_error_sqr_x, median_error_sqr_y, median_error_sqr_z);
}
if(maxVariance > 0 && median_error_sqr_lin > maxVariance)
{
UWARN("Rejected PnP transform, variance is too high! %f > %f!", median_error_sqr_lin, maxVariance);
+29 -13
View File
@@ -2398,7 +2398,7 @@ bool multiBandTexturing(
std::string tmpImageDirectory = outputDirectory+"/rtabmap_tmp_textures";
UDirectory::removeDir(tmpImageDirectory);
UDirectory::makeDir(tmpImageDirectory);
UINFO("Temporary saving images in directory \"%s\"...", tmpImageDirectory.c_str());
UINFO("Temporary saving images from %ld nodes in directory \"%s\"...", cameraPoses.size(), tmpImageDirectory.c_str());
int viewId = 0;
for(std::map<int, Transform>::const_iterator iter = cameraPoses.lower_bound(1); iter!=cameraPoses.end(); ++iter)
{
@@ -2510,28 +2510,45 @@ bool multiBandTexturing(
imageSize.height = image.rows;
imageSize.width = image.cols;
}
UASSERT(image.cols % imageSize.width == 0);
cv::Mat imageRoi = image.colRange(i*imageSize.width, (i+1)*imageSize.width);
if(gains.find(camId) != gains.end() &&
gains.at(camId).find(i) != gains.at(camId).end())
{
const cv::Vec4d & g = gains.at(camId).at(i);
std::vector<cv::Mat> channels;
cv::split(imageRoi, channels);
if(imageRoi.channels() == 1)
{
cv::multiply(imageRoi, g.val[0], imageRoi);
}
else
{
std::vector<cv::Mat> channels;
cv::split(imageRoi, channels);
// assuming BGR
cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
// assuming BGR
cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
cv::Mat output;
cv::merge(channels, output);
imageRoi = output;
cv::Mat output;
cv::merge(channels, output);
imageRoi = output;
}
}
if(blendingGains.find(camId) != blendingGains.end() &&
blendingGains.at(camId).find(i) != blendingGains.at(camId).end())
{
// Should be color for blending options
if(imageRoi.channels() == 1)
{
cv::Mat imageRoiColor;
cv::cvtColor(imageRoi, imageRoiColor, CV_GRAY2BGR);
imageRoi = imageRoiColor;
}
cv::Mat g = blendingGains.at(camId).at(i);
cv::Mat dst;
cv::blur(g, dst, cv::Size(3,3));
@@ -2559,9 +2576,7 @@ bool multiBandTexturing(
sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
std::string imagePath = tmpImageDirectory+uFormat("/%d.jpg", viewId);
cv::imwrite(imagePath, imageRoi);
std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
imagePath,
(IndexT)viewId,
@@ -2572,8 +2587,9 @@ bool multiBandTexturing(
sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
++viewId;
}
UDEBUG("camId=%d", camId);
}
UINFO("Temporary saving images in directory \"%s\"... done (%d images). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.ticks());
UINFO("Temporary saving images in directory \"%s\"... done (%d images of %d nodes). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.ticks());
mvsUtils::MultiViewParams mp(sfmData);
-5
View File
@@ -10,11 +10,6 @@ RUN apt-get update && \
WORKDIR /root/
# GTSAM
RUN add-apt-repository ppa:borglab/gtsam-release-4.0 -y
RUN apt-get update && apt install libgtsam-dev libgtsam-unstable-dev -y && \
apt-get clean && rm -rf /var/lib/apt/lists/
# MRPT
RUN add-apt-repository ppa:joseluisblancoc/mrpt-stable -y
RUN apt-get update && apt install libmrpt-poses-dev -y && \
+18 -6
View File
@@ -2,6 +2,10 @@
FROM ubuntu:22.04
ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
RUN echo "I am building for $TARGETPLATFORM"
# Install ROS2
RUN apt update && \
apt install software-properties-common -y && \
@@ -17,10 +21,22 @@ ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && \
apt upgrade -y && \
apt-get install -y git ros-humble-ros-base ros-dev-tools ros-humble-rtabmap-ros && \
apt-get remove -y ros-humble-rtabmap* && \
apt-get install -y git ros-humble-ros-base ros-dev-tools && \
apt-get clean && rm -rf /var/lib/apt/lists/
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then apt-get update && \
apt upgrade -y && \
apt-get install -y ros-humble-rtabmap-ros && \
apt-get remove -y ros-humble-rtabmap* && \
apt-get clean && rm -rf /var/lib/apt/lists/; fi
# current issue that ros-humble-rtabmap-ros is not available on arm64
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then apt-get update && \
apt upgrade -y && \
apt-get install -y ros-humble-rtabmap-launch && \
apt-get remove -y ros-humble-rtabmap* && \
apt-get clean && rm -rf /var/lib/apt/lists/; fi
WORKDIR /root/
# PDAL
@@ -31,10 +47,6 @@ RUN apt-get update && apt-get install -y libpdal-dev && \
RUN apt-get update && apt-get install -y ros-humble-librealsense2 && \
apt-get clean && rm -rf /var/lib/apt/lists/
ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
RUN echo "I am building for $TARGETPLATFORM"
# libfreenect2
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing libfreenect2..." && \
apt-get update && apt-get install -y mesa-utils xserver-xorg-video-all libusb-1.0-0-dev libturbojpeg0-dev libglfw3-dev && \
@@ -128,6 +128,8 @@ private Q_SLOTS:
void updateAllLandmarkCovariances();
void refineLinks();
void resetAllChanges();
void graphNodeSelected(int);
void graphLinkSelected(int, int);
void sliderAValueChanged(int);
void sliderBValueChanged(int);
void sliderAMoved(int);
+5
View File
@@ -166,12 +166,16 @@ public:
Q_SIGNALS:
void configChanged();
void mapShownRequested();
void nodeSelected(int);
void linkSelected(int, int);
public Q_SLOTS:
void restoreDefaults();
protected:
virtual void wheelEvent ( QWheelEvent * event );
virtual void mouseMoveEvent(QMouseEvent * event);
virtual void mouseDoubleClickEvent(QMouseEvent * event);
virtual void contextMenuEvent(QContextMenuEvent * event);
private:
@@ -228,6 +232,7 @@ private:
float _loopClosureOutlierThr;
float _maxLinkLength;
bool _orientationENU;
bool _mouseTracking;
ViewPlane _viewPlane;
bool _ensureFrameVisible;
};
+6 -1
View File
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/features2d/features2d.hpp>
#include <map>
#include "rtabmap/utilite/UCv2Qt.h"
#include <rtabmap/core/CameraModel.h>
class QAction;
class QMenu;
@@ -96,7 +97,7 @@ public:
void setFeatures(const std::vector<cv::KeyPoint> & features, const cv::Mat & depth = cv::Mat(), const QColor & color = Qt::yellow);
void addFeature(int id, const cv::KeyPoint & kpt, float depth, QColor color);
void addLine(float x1, float y1, float x2, float y2, QColor color, const QString & text = QString());
void setImage(const QImage & image);
void setImage(const QImage & image, const std::vector<CameraModel> & models = std::vector<CameraModel>(), const Transform & pose = Transform());
void setImageDepth(const cv::Mat & imageDepth);
void setImageDepth(const QImage & image);
void setFeatureColor(int id, QColor color);
@@ -121,6 +122,7 @@ protected:
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent* event);
virtual void contextMenuEvent(QContextMenuEvent * e);
virtual void mouseMoveEvent(QMouseEvent * event);
private Q_SLOTS:
void sceneRectChanged(const QRectF &rect);
@@ -164,6 +166,7 @@ private:
QAction * _colorMapBlueToRed;
QAction * _colorMapMinRange;
QAction * _colorMapMaxRange;
QAction * _mouseTracking;
QMenu * _featureMenu;
QMenu * _scaleMenu;
@@ -175,6 +178,8 @@ private:
QPixmap _image;
QPixmap _imageDepth;
cv::Mat _imageDepthCv;
std::vector<CameraModel> _models;
Transform _pose;
};
}
-1
View File
@@ -170,7 +170,6 @@ protected Q_SLOTS:
void depthCalibration();
void openWorkingDirectory();
void updateEditMenu();
void selectStream();
void selectOpenni();
void selectFreenect();
void selectOpenniCv();
+8
View File
@@ -191,6 +191,14 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_cccorelib_license->setEnabled(false);
#endif
#ifdef RTABMAP_OPEN3D
_ui->label_open3d->setText("Yes");
_ui->label_open3d_license->setEnabled(true);
#else
_ui->label_open3d->setText("No");
_ui->label_open3d_license->setEnabled(false);
#endif
#ifdef RTABMAP_FOVIS
_ui->label_fovis->setText("Yes");
_ui->label_fovis_license->setEnabled(true);
+4
View File
@@ -204,6 +204,10 @@ CloudViewer::CloudViewer(QWidget *parent, CloudViewerInteractorStyle * style) :
}
_visualizer->getRenderWindow()->SetNumberOfLayers(4);
#ifdef VTK_GLOBAL_WARNING_DISPLAY_OFF
_visualizer->getRenderWindow()->GlobalWarningDisplayOff();
#endif
#if VTK_MAJOR_VERSION > 8
this->setRenderWindow(_visualizer->getRenderWindow());
#else
+58 -17
View File
@@ -268,6 +268,8 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->dockWidget_statistics->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateStatistics()));
connect(ui_->dockWidget_info->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateInfo()));
connect(ui_->graphViewer, SIGNAL(nodeSelected(int)), this , SLOT(graphNodeSelected(int)));
connect(ui_->graphViewer, SIGNAL(linkSelected(int,int)), this , SLOT(graphLinkSelected(int,int)));
connect(ui_->parameters_toolbox, SIGNAL(parametersChanged(const QStringList &)), this, SLOT(notifyParametersChanged(const QStringList &)));
@@ -2753,14 +2755,24 @@ void DatabaseViewer::exportPoses(int format)
}
}
if(format != 4 && !poses.empty() && poses.begin()->first<0) // not g2o, landmark not supported
if(format != 4 && format != 11 && !poses.empty() && poses.begin()->first<0) // not g2o, landmark not supported
{
UWARN("Only g2o format (4) can export landmarks, they are ignored with format %d", format);
std::map<int, Transform>::iterator iter=poses.begin();
while(iter!=poses.end() && iter->first < 0)
UWARN("Only g2o format (4) and RGBD format with ID format can export landmarks, they are ignored with format %d", format);
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end() && iter->first < 0;)
{
poses.erase(iter++);
}
for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end();)
{
if(iter->second.from() < 0 || iter->second.to() < 0)
{
links.erase(iter++);
}
else
{
++iter;
}
}
}
std::map<int, double> stamps;
@@ -2768,17 +2780,24 @@ void DatabaseViewer::exportPoses(int format)
{
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
Transform p, g;
int w;
std::string l;
double stamp=0.0;
int mapId;
std::vector<float> v;
GPS gps;
EnvSensors sensors;
if(dbDriver_->getNodeInfo(iter->first, p, mapId, w, l, stamp, g, v, gps, sensors))
if(iter->first<0 && format == 11) // in case of landmarks
{
stamps.insert(std::make_pair(iter->first, stamp));
stamps.insert(std::make_pair(iter->first, 0));
}
else
{
Transform p, g;
int w;
std::string l;
double stamp=0.0;
int mapId;
std::vector<float> v;
GPS gps;
EnvSensors sensors;
if(dbDriver_->getNodeInfo(iter->first, p, mapId, w, l, stamp, g, v, gps, sensors))
{
stamps.insert(std::make_pair(iter->first, stamp));
}
}
}
if(stamps.size()!=poses.size())
@@ -4530,6 +4549,20 @@ void DatabaseViewer::resetAllChanges()
}
}
void DatabaseViewer::graphNodeSelected(int id)
{
if(id>0 && idToIndex_.contains(id))
ui_->horizontalSlider_A->setValue(idToIndex_.value(id));
}
void DatabaseViewer::graphLinkSelected(int from, int to)
{
if(from>0 && idToIndex_.contains(from))
ui_->horizontalSlider_A->setValue(idToIndex_.value(from));
if(to>0 && idToIndex_.contains(to))
ui_->horizontalSlider_B->setValue(idToIndex_.value(to));
}
void DatabaseViewer::sliderAValueChanged(int value)
{
this->update(value,
@@ -4668,7 +4701,12 @@ void DatabaseViewer::update(int value,
QRectF rect;
if(!img.isNull())
{
view->setImage(img);
Transform pose;
if(!graphes_.empty() && graphes_.back().find(data.id())!=graphes_.back().end())
{
pose = graphes_.back().at(data.id());
}
view->setImage(img, data.cameraModels(), pose);
rect = img.rect();
}
else
@@ -6899,8 +6937,11 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
SensorData data;
dbDriver_->getNodeData(ids.at(i), data, false, false, false);
cv::Mat ground, obstacles, empty;
data.uncompressData(0, 0, 0, 0, &ground, &obstacles, &empty);
localMaps_.add(ids.at(i), ground, obstacles, empty, data.gridCellSize(), data.gridViewPoint());
if(data.gridCellSize()>0.0f)
{
data.uncompressData(0, 0, 0, 0, &ground, &obstacles, &empty);
}
localMaps_.add(ids.at(i), ground, obstacles, empty, data.gridCellSize()>0.0f?data.gridCellSize():Parameters::defaultGridCellSize(), data.gridViewPoint());
if(!ground.empty() || !obstacles.empty())
{
localMaps_.shareTo(ids.at(i), combinedLocalMaps);
+64 -1
View File
@@ -129,6 +129,14 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
connect(_ui->doubleSpinBox_minDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_ceilingHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_floorHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->groupBox_offAxisFiltering, SIGNAL(toggled(bool)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_offAxisFilteringAngle, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosX, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegX, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosY, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegY, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringPosZ, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_offAxisFilteringNegZ, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintWidth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintLength, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_footprintHeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
@@ -370,6 +378,14 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
settings.setValue("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value());
settings.setValue("regenerate_ceiling", _ui->doubleSpinBox_ceilingHeight->value());
settings.setValue("regenerate_floor", _ui->doubleSpinBox_floorHeight->value());
settings.setValue("regenerate_offaxis_filtering", _ui->groupBox_offAxisFiltering->isChecked());
settings.setValue("regenerate_offaxis_filtering_angle", _ui->doubleSpinBox_offAxisFilteringAngle->value());
settings.setValue("regenerate_offaxis_filtering_pos_x", _ui->checkBox_offAxisFilteringPosX->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_x", _ui->checkBox_offAxisFilteringNegX->isChecked());
settings.setValue("regenerate_offaxis_filtering_pos_y", _ui->checkBox_offAxisFilteringPosY->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_y", _ui->checkBox_offAxisFilteringNegY->isChecked());
settings.setValue("regenerate_offaxis_filtering_pos_z", _ui->checkBox_offAxisFilteringPosZ->isChecked());
settings.setValue("regenerate_offaxis_filtering_neg_z", _ui->checkBox_offAxisFilteringNegZ->isChecked());
settings.setValue("regenerate_footprint_height", _ui->doubleSpinBox_footprintHeight->value());
settings.setValue("regenerate_footprint_width", _ui->doubleSpinBox_footprintWidth->value());
settings.setValue("regenerate_footprint_length", _ui->doubleSpinBox_footprintLength->value());
@@ -543,6 +559,14 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->doubleSpinBox_minDepth->setValue(settings.value("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value()).toDouble());
_ui->doubleSpinBox_ceilingHeight->setValue(settings.value("regenerate_ceiling", _ui->doubleSpinBox_ceilingHeight->value()).toDouble());
_ui->doubleSpinBox_floorHeight->setValue(settings.value("regenerate_floor", _ui->doubleSpinBox_floorHeight->value()).toDouble());
_ui->groupBox_offAxisFiltering->setChecked(settings.value("regenerate_offaxis_filtering", _ui->groupBox_offAxisFiltering->isChecked()).toBool());
_ui->doubleSpinBox_offAxisFilteringAngle->setValue(settings.value("regenerate_offaxis_filtering_angle", _ui->doubleSpinBox_offAxisFilteringAngle->value()).toDouble());
_ui->checkBox_offAxisFilteringPosX->setChecked(settings.value("regenerate_offaxis_filtering_pos_x", _ui->checkBox_offAxisFilteringPosX->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegX->setChecked(settings.value("regenerate_offaxis_filtering_neg_x", _ui->checkBox_offAxisFilteringNegX->isChecked()).toBool());
_ui->checkBox_offAxisFilteringPosY->setChecked(settings.value("regenerate_offaxis_filtering_pos_y", _ui->checkBox_offAxisFilteringPosY->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegY->setChecked(settings.value("regenerate_offaxis_filtering_neg_y", _ui->checkBox_offAxisFilteringNegY->isChecked()).toBool());
_ui->checkBox_offAxisFilteringPosZ->setChecked(settings.value("regenerate_offaxis_filtering_pos_z", _ui->checkBox_offAxisFilteringPosZ->isChecked()).toBool());
_ui->checkBox_offAxisFilteringNegZ->setChecked(settings.value("regenerate_offaxis_filtering_neg_z", _ui->checkBox_offAxisFilteringNegZ->isChecked()).toBool());
_ui->doubleSpinBox_footprintHeight->setValue(settings.value("regenerate_footprint_height", _ui->doubleSpinBox_footprintHeight->value()).toDouble());
_ui->doubleSpinBox_footprintWidth->setValue(settings.value("regenerate_footprint_width", _ui->doubleSpinBox_footprintWidth->value()).toDouble());
_ui->doubleSpinBox_footprintLength->setValue(settings.value("regenerate_footprint_length", _ui->doubleSpinBox_footprintLength->value()).toDouble());
@@ -719,6 +743,14 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_minDepth->setValue(0);
_ui->doubleSpinBox_ceilingHeight->setValue(0);
_ui->doubleSpinBox_floorHeight->setValue(0);
_ui->groupBox_offAxisFiltering->setChecked(false);
_ui->doubleSpinBox_offAxisFilteringAngle->setValue(10);
_ui->checkBox_offAxisFilteringPosX->setChecked(true);
_ui->checkBox_offAxisFilteringNegX->setChecked(true);
_ui->checkBox_offAxisFilteringPosY->setChecked(true);
_ui->checkBox_offAxisFilteringNegY->setChecked(true);
_ui->checkBox_offAxisFilteringPosZ->setChecked(true);
_ui->checkBox_offAxisFilteringNegZ->setChecked(true);
_ui->doubleSpinBox_footprintHeight->setValue(0);
_ui->doubleSpinBox_footprintLength->setValue(0);
_ui->doubleSpinBox_footprintWidth->setValue(0);
@@ -1504,6 +1536,7 @@ void ExportCloudsDialog::viewClouds(
}
}
viewer->refreshView();
window->activateWindow();
}
else
{
@@ -3914,6 +3947,36 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
UWARN("Point cloud %d doesn't have anymore points (had %d points) after radius filtering.", iter->first, (int)cloud->size());
}
}
if( !indices->empty() && _ui->groupBox_offAxisFiltering->isChecked() &&
(_ui->checkBox_offAxisFilteringPosX->isChecked() ||
_ui->checkBox_offAxisFilteringNegX->isChecked() ||
_ui->checkBox_offAxisFilteringPosY->isChecked() ||
_ui->checkBox_offAxisFilteringNegY->isChecked() ||
_ui->checkBox_offAxisFilteringPosZ->isChecked() ||
_ui->checkBox_offAxisFilteringNegZ->isChecked()))
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudInMapFrame = util3d::transformPointCloud(cloud, iter->second);
std::vector<pcl::IndicesPtr> indicesVector;
double maxDeltaAngle = _ui->doubleSpinBox_offAxisFilteringAngle->value()*M_PI/180.0;
Eigen::Vector4f viewpoint(iter->second.x(), iter->second.y(), iter->second.z(), 0);
if(_ui->checkBox_offAxisFilteringPosX->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(1,0,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringPosY->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,1,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringPosZ->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,0,1,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegX->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(-1,0,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegY->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,-1,0,0), 20, viewpoint));
if(_ui->checkBox_offAxisFilteringNegZ->isChecked())
indicesVector.push_back(util3d::normalFiltering(cloudInMapFrame, indices, maxDeltaAngle, Eigen::Vector4f(0,0,-1,0), 20, viewpoint));
indices = util3d::concatenate(indicesVector);
if(indices->empty())
{
UWARN("Point cloud %d doesn't have anymore points (had %d points) after offaxis filtering.", iter->first, (int)cloud->size());
}
}
}
if(!indices->empty())
@@ -4613,7 +4676,7 @@ void ExportCloudsDialog::saveTextureMeshes(
path.toStdString(),
mesh->cloud,
mesh->tex_polygons[0],
poses,
filterNodes(poses),
textureVertexToPixels,
images,
calibrations,
+55
View File
@@ -45,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif
#include <QInputDialog>
#include <QMessageBox>
#include <QToolTip>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
@@ -316,6 +317,7 @@ GraphViewer::GraphViewer(QWidget * parent) :
_loopClosureOutlierThr(0),
_maxLinkLength(0.02f),
_orientationENU(false),
_mouseTracking(false),
_viewPlane(XY),
_ensureFrameVisible(true)
{
@@ -1789,6 +1791,50 @@ void GraphViewer::wheelEvent ( QWheelEvent * event )
}
}
void GraphViewer::mouseMoveEvent(QMouseEvent * event)
{
QPointF scenePoint = mapToScene(event->pos());
if(_mouseTracking && _viewPlane==XY && this->sceneRect().contains(scenePoint))
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QToolTip::showText(event->globalPosition().toPoint(), QString("%1m %2m").arg(-scenePoint.y()/100.0).arg(-scenePoint.x()/100.0));
#else
QToolTip::showText(event->globalPos(), QString("%1m %2m").arg(-scenePoint.y()/100.0).arg(-scenePoint.x()/100.0));
#endif
}
else
{
QToolTip::hideText();
}
QGraphicsView::mouseMoveEvent(event);
}
void GraphViewer::mouseDoubleClickEvent(QMouseEvent * event)
{
QGraphicsItem *item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
if(item)
{
NodeItem *nodeItem = qgraphicsitem_cast<NodeItem*>(item);
LinkItem *linkItem = qgraphicsitem_cast<LinkItem*>(item);
if(nodeItem && nodeItem->parentItem() == _graphRoot && nodeItem->id() != 0)
{
Q_EMIT nodeSelected(nodeItem->id());
}
else if(linkItem && linkItem->parentItem() == _graphRoot && linkItem->from() != 0 && linkItem->to() != 0)
{
Q_EMIT linkSelected(linkItem->from(), linkItem->to());
}
else
{
QGraphicsView::mouseDoubleClickEvent(event);
}
}
else
{
QGraphicsView::mouseDoubleClickEvent(event);
}
}
QIcon createIcon(const QColor & color)
{
QPixmap pixmap(50, 50);
@@ -1878,6 +1924,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
QAction * aShowHideGPSGraph;
QAction * aShowHideOdomCacheOverlay;
QAction * aOrientationENU;
QAction * aMouseTracking;
QAction * aViewPlaneXY;
QAction * aViewPlaneXZ;
QAction * aViewPlaneYZ;
@@ -1976,6 +2023,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
aOrientationENU = menu.addAction(tr("ENU Orientation"));
aOrientationENU->setCheckable(true);
aOrientationENU->setChecked(_orientationENU);
aMouseTracking = menu.addAction(tr("Show mouse cursor position (m)"));
aMouseTracking->setCheckable(true);
aMouseTracking->setChecked(_mouseTracking);
aMouseTracking->setEnabled(_viewPlane == XY);
aShowHideGraph->setEnabled(_nodeItems.size() && _viewPlane == XY);
aShowHideGraphNodes->setEnabled(_nodeItems.size() && _graphRoot->isVisible());
aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
@@ -2405,6 +2456,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
this->setOrientationENU(!this->isOrientationENU());
}
else if(r == aMouseTracking)
{
_mouseTracking = aMouseTracking->isChecked();
}
else if(r == aViewPlaneXY)
{
this->setViewPlane(XY);
+71 -1
View File
@@ -40,9 +40,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QColorDialog>
#include <QPrinter>
#include <QGraphicsRectItem>
#include <QToolTip>
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/gui/KeypointItem.h"
#include "rtabmap/core/util2d.h"
#include "rtabmap/core/util3d_transforms.h"
#include <QtGlobal>
#if QT_VERSION >= 0x050000
@@ -268,9 +270,14 @@ ImageView::ImageView(QWidget * parent) :
group->addAction(_colorMapRedToBlue);
group->addAction(_colorMapBlueToRed);
group->addAction(_colorMapMaxRange);
_mouseTracking = _menu->addAction(tr("Show pixel depth"));
_mouseTracking->setCheckable(true);
_mouseTracking->setChecked(false);
_saveImage = _menu->addAction(tr("Save picture..."));
_saveImage->setEnabled(false);
setMouseTracking(true);
connect(_graphicsView->scene(), SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(sceneRectChanged(const QRectF &)));
}
@@ -1047,6 +1054,65 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
}
}
void ImageView::mouseMoveEvent(QMouseEvent * event)
{
if(_mouseTracking->isChecked() &&
!_graphicsView->scene()->sceneRect().isNull() &&
!_image.isNull() &&
!_imageDepthCv.empty() &&
(_imageDepthCv.type() == CV_16UC1 || _imageDepthCv.type() == CV_32FC1))
{
float scale, offsetX, offsetY;
computeScaleOffsets(this->rect(), scale, offsetX, offsetY);
float u = (event->pos().x() - offsetX) / scale;
float v = (event->pos().y() - offsetY) / scale;
float depthScale = 1;
if(_image.width() > _imageDepth.width())
{
depthScale = _imageDepth.width() / _image.width();
}
int ud = int(u*depthScale);
int vd = int(v*depthScale);
if( ud>=0 && vd>=0 &&
ud < _imageDepthCv.cols &&
vd < _imageDepthCv.rows)
{
float depth = 0;
if(_imageDepthCv.type() == CV_32FC1)
{
depth = _imageDepthCv.at<float>(vd, ud);
}
else
{
depth = float(_imageDepthCv.at<unsigned short>(vd, ud)) / 1000.0f;
}
cv::Point3f pt(0,0,0);
if(depth>0 && !_models.empty() && !_pose.isNull())
{
int subImageWidth = _imageDepthCv.cols / _models.size();
int subImageIndex = ud / subImageWidth;
UASSERT(subImageIndex < (int)_models.size());
float x,y,z;
_models[subImageIndex].project(u, v, depth, x, y, z);
pt = cv::Point3f(x,y,z);
pt = util3d::transformPoint(pt, _pose*_models[subImageIndex].localTransform());
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QToolTip::showText(event->globalPosition().toPoint(), pt.x!=0?tr("Depth=%1m Map=(%2,%3,%4)").arg(depth).arg(pt.x).arg(pt.y).arg(pt.z):depth > 0?tr("Depth=%1m").arg(depth):tr("Depth=NA"));
#else
QToolTip::showText(event->globalPos(), pt.x!=0?tr("Depth=%1m Map=(%2,%3,%4)").arg(depth).arg(pt.x).arg(pt.y).arg(pt.z):depth > 0?tr("Depth=%1m").arg(depth):tr("Depth=NA"));
#endif
}
else
{
QToolTip::hideText();
}
}
QWidget::mouseMoveEvent(event);
}
void ImageView::updateOpacity()
{
if(_imageItem && _imageDepthItem)
@@ -1166,9 +1232,11 @@ void ImageView::addLine(float x1, float y1, float x2, float y2, QColor color, co
}
}
void ImageView::setImage(const QImage & image)
void ImageView::setImage(const QImage & image, const std::vector<CameraModel> & models, const Transform & pose)
{
_image = QPixmap::fromImage(image);
_models = models;
_pose = pose;
if(_graphicsView->isVisible())
{
if(_imageItem)
@@ -1394,6 +1462,8 @@ void ImageView::clear()
_imageItem = 0;
}
_image = QPixmap();
_models.clear();
_pose.setNull();
if(_imageDepthItem)
{
+28 -19
View File
@@ -435,7 +435,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
//Settings menu
connect(_ui->actionMore_options, SIGNAL(triggered()), this, SLOT(openPreferencesSource()));
connect(_ui->actionUsbCamera, SIGNAL(triggered()), this, SLOT(selectStream()));
connect(_ui->actionOpenNI_PCL, SIGNAL(triggered()), this, SLOT(selectOpenni()));
connect(_ui->actionOpenNI_PCL_ASUS, SIGNAL(triggered()), this, SLOT(selectOpenni()));
connect(_ui->actionFreenect, SIGNAL(triggered()), this, SLOT(selectFreenect()));
@@ -1775,6 +1774,8 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
//Process info
if(_preferencesDialog->isCacheSavedInFigures() || _ui->statsToolBox->isVisible())
{
double linVar = uMax3(odom.info().reg.covariance.at<double>(0,0), odom.info().reg.covariance.at<double>(1,1)>=9999?0:odom.info().reg.covariance.at<double>(1,1), odom.info().reg.covariance.at<double>(2,2)>=9999?0:odom.info().reg.covariance.at<double>(2,2));
double angVar = uMax3(odom.info().reg.covariance.at<double>(3,3)>=9999?0:odom.info().reg.covariance.at<double>(3,3), odom.info().reg.covariance.at<double>(4,4)>=9999?0:odom.info().reg.covariance.at<double>(4,4), odom.info().reg.covariance.at<double>(5,5));
_ui->statsToolBox->updateStat("Odometry/Inliers/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.inliers, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/InliersMeanDistance/m", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.inliersMeanDistance, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/InliersDistribution/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.inliersDistribution, _preferencesDialog->isCacheSavedInFigures());
@@ -1788,10 +1789,10 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
_ui->statsToolBox->updateStat("Odometry/ICPRMS/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.icpRMS, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/Matches/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.matches, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/MatchesRatio/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), odom.info().features<=0?0.0f:float(odom.info().reg.matches)/float(odom.info().features), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/StdDevLin/m", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), sqrt((float)odom.info().reg.covariance.at<double>(0,0)), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/VarianceLin/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.covariance.at<double>(0,0), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/StdDevAng/rad", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), sqrt((float)odom.info().reg.covariance.at<double>(5,5)), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/VarianceAng/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().reg.covariance.at<double>(5,5), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/StdDevLin/m", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), sqrt((float)linVar), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/VarianceLin/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)linVar, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/StdDevAng/rad", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), sqrt((float)angVar), _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/VarianceAng/", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)angVar, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Odometry/TimeEstimation/ms", _preferencesDialog->isTimeUsedInFigures()?data->stamp()-_firstStamp:(float)data->id(), (float)odom.info().timeEstimation*1000.0f, _preferencesDialog->isCacheSavedInFigures());
if(odom.info().timeParticleFiltering>0.0f)
{
@@ -5226,10 +5227,9 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event)
void MainWindow::updateSelectSourceMenu()
{
_ui->actionUsbCamera->setChecked(_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcUsbDevice);
_ui->actionMore_options->setChecked(
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcDatabase ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcUsbDevice ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcImages ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcVideo ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcStereoImages ||
@@ -6269,8 +6269,8 @@ void MainWindow::exportPoses(int format)
std::multimap<int, Link> links;
if(localTransforms.empty())
{
poses = std::map<int, Transform>(_currentPosesMap.lower_bound(1), _currentPosesMap.end());
links = std::multimap<int, Link>(_currentLinksMap.lower_bound(1), _currentLinksMap.end());
poses = std::map<int, Transform>(_currentPosesMap.begin(), _currentPosesMap.end());
links = std::multimap<int, Link>(_currentLinksMap.begin(), _currentLinksMap.end());
}
else
{
@@ -6291,14 +6291,24 @@ void MainWindow::exportPoses(int format)
}
}
if(format != 4 && !poses.empty() && poses.begin()->first<0) // not g2o, landmark not supported
if(format != 4 && format != 11 && !poses.empty() && poses.begin()->first<0) // not g2o, landmark not supported
{
UWARN("Only g2o format (4) can export landmarks, they are ignored with format %d", format);
std::map<int, Transform>::iterator iter=poses.begin();
while(iter!=poses.end() && iter->first < 0)
UWARN("Only g2o format (4) and RGBD format with ID format can export landmarks, they are ignored with format %d", format);
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end() && iter->first < 0;)
{
poses.erase(iter++);
}
for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end();)
{
if(iter->second.from() < 0 || iter->second.to() < 0)
{
links.erase(iter++);
}
else
{
++iter;
}
}
}
std::map<int, double> stamps;
@@ -6306,7 +6316,11 @@ void MainWindow::exportPoses(int format)
{
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(_cachedSignatures.contains(iter->first))
if(iter->first < 0 && format == 11) // in case of landmarks
{
stamps.insert(std::make_pair(iter->first, 0));
}
else if(_cachedSignatures.contains(iter->first))
{
stamps.insert(std::make_pair(iter->first, _cachedSignatures.value(iter->first).getStamp()));
}
@@ -7045,11 +7059,6 @@ void MainWindow::updateEditMenu()
}
}
void MainWindow::selectStream()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcUsbDevice);
}
void MainWindow::selectOpenni()
{
_preferencesDialog->selectSourceDriver(PreferencesDialog::kSrcOpenNI_PCL);
+2
View File
@@ -954,6 +954,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->general_doubleSpinBox_laserScanNormalRadius->setObjectName(Parameters::kMemLaserScanNormalRadius().c_str());
_ui->checkBox_useOdomFeatures->setObjectName(Parameters::kMemUseOdomFeatures().c_str());
_ui->memCovOffDiagIgnored->setObjectName(Parameters::kMemCovOffDiagIgnored().c_str());
_ui->general_checkBox_rotateImagesUpsideUp->setObjectName(Parameters::kMemRotateImagesUpsideUp().c_str());
// Database
_ui->checkBox_dbInMemory->setObjectName(Parameters::kDbSqlite3InMemory().c_str());
@@ -1189,6 +1190,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->loopClosure_pnpVarMedianRatio->setObjectName(Parameters::kVisPnPVarianceMedianRatio().c_str());
_ui->loopClosure_pnpMaxVariance->setObjectName(Parameters::kVisPnPMaxVariance().c_str());
_ui->loopClosure_pnpSamplingPolicy->setObjectName(Parameters::kVisPnPSamplingPolicy().c_str());
_ui->loopClosure_pnpSplitLinearCovComponents->setObjectName(Parameters::kVisPnPSplitLinearCovComponents().c_str());
_ui->reextract_nn->setObjectName(Parameters::kVisCorNNType().c_str());
connect(_ui->reextract_nn, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFeatureMatchingVisibility()));
_ui->reextract_nndrRatio->setObjectName(Parameters::kVisCorNNDR().c_str());
+13 -10
View File
@@ -528,15 +528,18 @@ void StatsToolBox::clear()
plots[0]->clearData();
}
else
{
UERROR("");
}
}
QList<StatItem*> items = _statBox->currentWidget()->findChildren<StatItem*>();
for (int i = 0; i<items.size(); ++i)
{
items[i]->clearCache();
}
{
UERROR("");
}
}
if(_statBox->currentWidget())
{
QList<StatItem*> items = _statBox->currentWidget()->findChildren<StatItem*>();
for (int i = 0; i<items.size(); ++i)
{
items[i]->clearCache();
}
}
}
void StatsToolBox::contextMenuEvent(QContextMenuEvent * event)
@@ -567,7 +570,7 @@ void StatsToolBox::contextMenuEvent(QContextMenuEvent * event)
}
}
if(!plotName.isEmpty())
if(!plotName.isEmpty() && _statBox->currentWidget())
{
QList<StatItem*> items = _statBox->currentWidget()->findChildren<StatItem*>();
for(int i=0; i<items.size(); ++i)
+1205 -1172
View File
File diff suppressed because it is too large Load Diff
+354 -212
View File
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1032</width>
<width>919</width>
<height>869</height>
</rect>
</property>
@@ -23,9 +23,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-2140</y>
<width>998</width>
<height>5850</height>
<y>-1328</y>
<width>885</width>
<height>6169</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
@@ -1086,220 +1086,362 @@
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_filteringRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_floorHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_filteringRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_filteringMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_144">
<property name="text">
<string>Footprint length.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintWidth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_145">
<property name="text">
<string>Footprint height. If negative, the footprint is filtered between [-height:height] around the base frame, otherwise it is [0:height]</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ceilingHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_141">
<property name="text">
<string>Floor filtering height. This is done in map frame.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_110">
<property name="text">
<string>Search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_143">
<property name="text">
<string>Footprint width.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_112">
<property name="text">
<string>Minimum neighbors in the search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_140">
<property name="text">
<string>Ceiling filtering height. This is done in map frame.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_110">
<property name="text">
<string>Search radius.</string>
<item>
<widget class="QGroupBox" name="groupBox_offAxisFiltering">
<property name="title">
<string>Off-Axis Filtering</string>
</property>
<property name="wordWrap">
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_filteringMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_112">
<property name="text">
<string>Minimum neighbors in the search radius.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ceilingHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_140">
<property name="text">
<string>Ceiling filtering height.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_floorHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_141">
<property name="text">
<string>Floor filtering height.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintWidth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_143">
<property name="text">
<string>Footprint width.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_144">
<property name="text">
<string>Footprint length.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_footprintHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1000.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_145">
<property name="text">
<string>Footprint height. If negative, the footprint is filtered between [-height:height] around the base frame, otherwise it is [0:height]</string>
</property>
<property name="wordWrap">
<property name="checked">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QLabel" name="label_148">
<property name="text">
<string>Keep only points with normals aligned with one/any of the map X-Y-Z axes.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_24">
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosX">
<property name="text">
<string>+X</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegY">
<property name="text">
<string>-Y</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegX">
<property name="text">
<string>-X</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosY">
<property name="text">
<string>+Y</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="checkBox_offAxisFilteringPosZ">
<property name="text">
<string>+Z</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QCheckBox" name="checkBox_offAxisFilteringNegZ">
<property name="text">
<string>-Z</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_23" columnstretch="0,1">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_offAxisFilteringAngle">
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>179.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_146">
<property name="text">
<string>Max angle error to keep the points. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
-23
View File
@@ -105,16 +105,6 @@
<property name="title">
<string>Select source</string>
</property>
<widget class="QMenu" name="menuImage">
<property name="title">
<string>RGB camera</string>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/webcam.png</normaloff>:/images/webcam.png</iconset>
</property>
<addaction name="actionUsbCamera"/>
</widget>
<widget class="QMenu" name="menuRGB_D_camera">
<property name="title">
<string>RGB-D camera</string>
@@ -342,7 +332,6 @@
</widget>
<addaction name="menuRGB_D_camera"/>
<addaction name="menuStereo_camera"/>
<addaction name="menuImage"/>
<addaction name="actionMore_options"/>
</widget>
<addaction name="menuSelect_source"/>
@@ -1244,18 +1233,6 @@
<string>240p</string>
</property>
</action>
<action name="actionUsbCamera">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../GuiLib.qrc">
<normaloff>:/images/webcam.png</normaloff>:/images/webcam.png</iconset>
</property>
<property name="text">
<string>Usb camera</string>
</property>
</action>
<action name="actionPrint_loop_closure_IDs_to_console">
<property name="text">
<string>Print loop closure IDs to console</string>
+349 -303
View File
@@ -63,9 +63,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<y>-1092</y>
<width>713</width>
<height>3893</height>
<height>3933</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>3</number>
<number>21</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0">
@@ -9258,17 +9258,63 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QGridLayout" name="gridLayout_42" columnstretch="0,1">
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
<property name="minimum">
<number>1</number>
<item row="15" column="1">
<widget class="QLabel" name="label_retrieved_13">
<property name="text">
<string>Image pre decimation. Decimation of the RGB image before visual feature detection. If depth size is larger than decimated RGB size, depth is decimated to be always at most equal to RGB size. If Vocabulary-&gt;Depth As Mask is true and if depth is smaller than decimated RGB, depth may be interpolated to match RGB size for feature detection.</string>
</property>
<property name="maximum">
<number>16</number>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="0">
<item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_transferSortingByWeightId">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="general_checkBox_createMapLabels">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QLabel" name="label_retrieved_6">
<property name="text">
<string>Image post decimation. Decimation of the RGB image before saving it to database. If depth size is larger than decimated RGB size, depth is decimated to be always at most equal to RGB size. Decimation is done from the original image. If set to same value than Pre Decimation, data already decimated is saved (no need to re-decimate the image).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="general_checkBox_compressionParallelized">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QSpinBox" name="spinBox_imagePostDecimation">
<property name="minimum">
<number>1</number>
@@ -9278,23 +9324,33 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="general_spinBox_maxStMemSize">
<property name="minimum">
<number>1</number>
<item row="11" column="0">
<widget class="QCheckBox" name="general_checkBox_keepDescriptors">
<property name="text">
<string/>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>15</number>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_retrieved_10">
<item row="11" column="1">
<widget class="QLabel" name="label_retrieved_12">
<property name="text">
<string>Reduce graph. Merge nodes when loop closures are added (ignoring those with user data set).</string>
<string>Raw descriptors kept in memory.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_retrieved_11">
<property name="text">
<string>Create map labels. The first node of a map will be labelled as &quot;map#&quot; where # is the map ID.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -9323,54 +9379,8 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_retrieved_4">
<property name="text">
<string>Initialize the Woking Memory with all nodes from Long-Term memory, instead of only nodes of the last session. This may be useful in localization mode, where less processing time is required than in SLAM mode, so more nodes can be kept in Working Memory.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="general_checkBox_initWMWithAllNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="general_spinBox_maxRetrieved">
<property name="maximum">
<number>999</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="general_checkBox_keepRawData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="general_checkBox_reduceGraph">
<item row="6" column="0">
<widget class="QCheckBox" name="general_checkBox_badSignaturesIgnored">
<property name="text">
<string/>
</property>
@@ -9392,8 +9402,8 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="general_checkBox_createMapLabels">
<item row="9" column="0">
<widget class="QCheckBox" name="general_checkBox_keepRawData">
<property name="text">
<string/>
</property>
@@ -9402,6 +9412,78 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_retrieved_10">
<property name="text">
<string>Reduce graph. Merge nodes when loop closures are added (ignoring those with user data set).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_retrieved_15">
<property name="text">
<string>Multi-threaded compression.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_ratioRecent">
<property name="text">
<string>T_recent : Ratio of locations after the last loop closure in WM that cannot be transferred.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="general_checkBox_generateIds">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_retrieved_16">
<property name="text">
<string>Save intermediate node data.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_retrieved_5">
<property name="text">
@@ -9415,21 +9497,8 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_retrieved_11">
<property name="text">
<string>Create map labels. The first node of a map will be labelled as &quot;map#&quot; where # is the map ID.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="general_checkBox_keepDescriptors">
<item row="7" column="0">
<widget class="QCheckBox" name="general_checkBox_reduceGraph">
<property name="text">
<string/>
</property>
@@ -9438,10 +9507,20 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_retrieved_12">
<item row="15" column="0">
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_retrieved_7">
<property name="text">
<string>Raw descriptors kept in memory.</string>
<string>On transfer, signatures are sorted by weight-&gt;ID (i.e. the oldest of the lowest weighted signatures are transferred first). If false, the signatures are sorted by weight-&gt;Age (i.e. the oldest inserted in WM of the lowest weighted signatures are transferred first). Note that retrieval updates the age, not the ID.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -9451,10 +9530,72 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_retrieved_13">
<item row="0" column="0">
<widget class="QSpinBox" name="general_spinBox_maxStMemSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>15</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Image pre decimation. Decimation of the RGB image before visual feature detection. If depth size is larger than decimated RGB size, depth is decimated to be always at most equal to RGB size. If Vocabulary-&gt;Depth As Mask is true and if depth is smaller than decimated RGB, depth may be interpolated to match RGB size for feature detection.</string>
<string>STM size : Short-term memory size.</string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="general_spinBox_maxRetrieved">
<property name="maximum">
<number>999</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="general_checkBox_initWMWithAllNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_retrieved_4">
<property name="text">
<string>Initialize the Woking Memory with all nodes from Long-Term memory, instead of only nodes of the last session. This may be useful in localization mode, where less processing time is required than in SLAM mode, so more nodes can be kept in Working Memory.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_retrieved_9">
<property name="text">
<string>Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -9490,62 +9631,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="general_checkBox_generateIds">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="general_checkBox_badSignaturesIgnored">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_transferSortingByWeightId">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_retrieved_9">
<property name="text">
<string>Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
<string>STM size : Short-term memory size.</string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="general_checkBox_saveDepth16bits">
<property name="text">
@@ -9556,10 +9641,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_ratioRecent">
<item row="14" column="1">
<widget class="QLabel" name="label_retrieved_19">
<property name="toolTip">
<string>This can be useful in case the robots don't have all same camera orientation but are using the same map, so that not rotation-invariant visual features can still be used across the fleet.</string>
</property>
<property name="text">
<string>T_recent : Ratio of locations after the last loop closure in WM that cannot be transferred.</string>
<string>Rotate images so that upside is up if they are not already.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -9569,34 +9657,8 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_retrieved_6">
<property name="text">
<string>Image post decimation. Decimation of the RGB image before saving it to database. If depth size is larger than decimated RGB size, depth is decimated to be always at most equal to RGB size. Decimation is done from the original image. If set to same value than Pre Decimation, data already decimated is saved (no need to re-decimate the image).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_retrieved_7">
<property name="text">
<string>On transfer, signatures are sorted by weight-&gt;ID (i.e. the oldest of the lowest weighted signatures are transferred first). If false, the signatures are sorted by weight-&gt;Age (i.e. the oldest inserted in WM of the lowest weighted signatures are transferred first). Note that retrieval updates the age, not the ID.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="general_checkBox_compressionParallelized">
<item row="14" column="0">
<widget class="QCheckBox" name="general_checkBox_rotateImagesUpsideUp">
<property name="text">
<string/>
</property>
@@ -9605,42 +9667,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_retrieved_15">
<property name="text">
<string>Multi-threaded compression.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_retrieved_16">
<property name="text">
<string>Save intermediate node data.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -21266,10 +21292,10 @@ Lower the ratio -&gt; higher the precision.</string>
<string>Motion Estimation: 3D to 2D (PnP)</string>
</property>
<layout class="QGridLayout" name="gridLayout_59" columnstretch="0,1">
<item row="1" column="1">
<widget class="QLabel" name="label_235">
<item row="0" column="1">
<widget class="QLabel" name="label_655">
<property name="text">
<string>Flags.</string>
<string>Reprojection error.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -21279,25 +21305,6 @@ Lower the ratio -&gt; higher the precision.</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QComboBox" name="loopClosure_pnpSamplingPolicy">
<item>
<property name="text">
<string>AUTO</string>
</property>
</item>
<item>
<property name="text">
<string>ANY</string>
</property>
</item>
<item>
<property name="text">
<string>HOMOGENEOUS</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="loopClosure_pnpFlags">
<item>
@@ -21317,45 +21324,67 @@ Lower the ratio -&gt; higher the precision.</string>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2">
<property name="text">
<string>Refine iterations.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
<item row="5" column="0">
<widget class="QComboBox" name="loopClosure_pnpSamplingPolicy">
<item>
<property name="text">
<string>AUTO</string>
</property>
</item>
<item>
<property name="text">
<string>ANY</string>
</property>
</item>
<item>
<property name="text">
<string>HOMOGENEOUS</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_655">
<property name="text">
<string>Reprojection error.</string>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="loopClosure_pnpReprojError">
<property name="suffix">
<string> pix</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<property name="decimals">
<number>1</number>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="loopClosure_pnpRefineIterations">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999</number>
<double>0.100000000000000</double>
</property>
<property name="singleStep">
<number>1</number>
<double>1.000000000000000</double>
</property>
<property name="value">
<number>1</number>
<double>8.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_235">
<property name="text">
<string>Flags.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2_4">
<property name="text">
<string>Ratio used to compute variance of the estimated transformation if 3D correspondences are provided (should be &gt; 1). The higher it is, the smaller the covariance will be. With accurate depth estimation, this could be set to 2. For depth estimated by stereo, 4 or more maybe used to ignore large errors of very far points.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
@@ -21381,25 +21410,6 @@ Lower the ratio -&gt; higher the precision.</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="loopClosure_pnpReprojError">
<property name="suffix">
<string> pix</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>8.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2_3">
<property name="text">
@@ -21413,19 +21423,6 @@ Lower the ratio -&gt; higher the precision.</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_656">
<property name="text">
<string>Reprojection error.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2_2">
<property name="text">
@@ -21439,10 +21436,10 @@ Lower the ratio -&gt; higher the precision.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2_4">
<item row="0" column="1">
<widget class="QLabel" name="label_656">
<property name="text">
<string>Ratio used to compute variance of the estimated transformation if 3D correspondences are provided (should be &gt; 1). The higher it is, the smaller the covariance will be. With accurate depth estimation, this could be set to 2. For depth estimated by stereo, 4 or more maybe used to ignore large errors of very far points.</string>
<string>Reprojection error.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -21465,6 +21462,55 @@ Lower the ratio -&gt; higher the precision.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2">
<property name="text">
<string>Refine iterations.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="loopClosure_pnpRefineIterations">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_loopClosure_pnpOpenCV2_5">
<property name="text">
<string>Compute variance for each linear component instead of using the combined XYZ variance for all linear components.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="loopClosure_pnpSplitLinearCovComponents">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<package format="2">
<name>rtabmap</name>
<version>0.21.3</version>
<version>0.21.4</version>
<description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description>
<maintainer email="matlabbe@gmail.com">Mathieu Labbe</maintainer>
<author>Mathieu Labbe</author>
-2
View File
@@ -186,11 +186,9 @@ template<class K, class V>
inline std::set<K> uKeysSet(const std::map<K, V> & m)
{
std::set<K> s;
int i=0;
for(typename std::map<K, V>::const_iterator iter = m.begin(); iter!=m.end(); ++iter)
{
s.insert(s.end(), iter->first);
++i;
}
return s;
}