mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-11 05:50:21 +08:00
Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85112c2cdf | ||
|
|
8657e18bda | ||
|
|
578bf0ed8f | ||
|
|
9f230f5b28 | ||
|
|
264c560a2c | ||
|
|
4ce36ef245 | ||
|
|
d0227694c5 | ||
|
|
a6d9425bce | ||
|
|
e299505a64 | ||
|
|
57b4954cb3 | ||
|
|
2577c47e77 | ||
|
|
52e1b01597 | ||
|
|
8019a2dc49 | ||
|
|
33b875ecbf | ||
|
|
c24f95a8d9 | ||
|
|
6f7e5cc97b | ||
|
|
fccf33dd96 | ||
|
|
752ca76cf5 | ||
|
|
81e249b56c | ||
|
|
ff7c8af56f | ||
|
|
a11ea291d8 | ||
|
|
cd615c6e52 | ||
|
|
1bd2d9fe81 | ||
|
|
510aef19e4 | ||
|
|
1dadd50cf2 | ||
|
|
b2a86d640a | ||
|
|
c27507bc77 | ||
|
|
b374c6cd8e | ||
|
|
29dc6c67fa | ||
|
|
10de748531 | ||
|
|
dcd5994456 | ||
|
|
13cd5e7a5e | ||
|
|
856e372dde | ||
|
|
423e67558b | ||
|
|
ace653593b | ||
|
|
7b31c737be | ||
|
|
0b534c9427 | ||
|
|
cdbdcfe676 | ||
|
|
b7239fdc84 | ||
|
|
a0559b156b |
+1
-1
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
@@ -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_)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 && \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -170,7 +170,6 @@ protected Q_SLOTS:
|
||||
void depthCalibration();
|
||||
void openWorkingDirectory();
|
||||
void updateEditMenu();
|
||||
void selectStream();
|
||||
void selectOpenni();
|
||||
void selectFreenect();
|
||||
void selectOpenniCv();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+354
-212
@@ -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>
|
||||
|
||||
@@ -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
@@ -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->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 "map#" 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 "map#" 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->ID (i.e. the oldest of the lowest weighted signatures are transferred first). If false, the signatures are sorted by weight->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->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->ID (i.e. the oldest of the lowest weighted signatures are transferred first). If false, the signatures are sorted by weight->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 -> 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 -> 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 -> 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 > 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 -> 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 -> 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 -> 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 > 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 -> 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
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user