Compare commits

..
31 changed files with 527 additions and 1038 deletions
-25
View File
@@ -1,25 +0,0 @@
FROM introlab3it/rtabmap:resolute-deps
# For devcontainer
# remove ubuntu user
RUN touch /var/mail/ubuntu && chown ubuntu /var/mail/ubuntu && userdel -r ubuntu
RUN apt-get update && apt-get install -y sudo && \
apt-get clean && rm -rf /var/lib/apt/lists/
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=1000
RUN set -ex && \
groupadd --gid ${USER_GID} ${USERNAME} && \
useradd --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME} && \
usermod -a -G sudo ${USERNAME} && \
echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USERNAME} && \
chmod 0440 /etc/sudoers.d/${USERNAME}
RUN mkdir -p /home/${USERNAME}/Documents/RTAB-Map && chown -R ${USERNAME} /home/${USERNAME}
RUN echo "source /usr/share/bash-completion/completions/git" >> /home/${USERNAME}/.bashrc
-30
View File
@@ -1,30 +0,0 @@
{
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools", "ms-vscode.cpptools-extension-pack"]
}
},
"workspaceMount": "source=${localWorkspaceFolder},target=/home/vscode/rtabmap,type=bind",
"workspaceFolder": "/home/vscode/rtabmap",
//"mounts": ["source=${localEnv:HOME}/Documents/RTAB-Map,target=/home/vscode/Documents/RTAB-Map,type=bind,consistency=cached"],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
},
"remoteUser": "vscode",
"hostRequirements": {
"gpu": "optional"
},
"runArgs": ["--privileged",
"--network=host",
"--gpus=all",
//"--runtime=nvidia", // uncommment this if rtabmap doesn't show up in nvidia-smi on the host computer
"--env=DISPLAY",
"--env=QT_X11_NO_MITSHM=1",
"--volume=/tmp/.X11-unix:/tmp/.X11-unix"],
"containerEnv": {
"NVIDIA_VISIBLE_DEVICES": "all"
}
}
+1 -5
View File
@@ -22,7 +22,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
build_name: [ubuntu-22.04, ubuntu-24.04, ubuntu-24.04-with-opengv, ubuntu-26.04] build_name: [ubuntu-22.04, ubuntu-24.04, ubuntu-24.04-with-opengv]
include: include:
- build_name: ubuntu-22.04 - build_name: ubuntu-22.04
os: ubuntu-22.04 os: ubuntu-22.04
@@ -36,10 +36,6 @@ jobs:
os: ubuntu-24.04 os: ubuntu-24.04
extra_deps: "libg2o-dev libceres-dev" extra_deps: "libg2o-dev libceres-dev"
extra_cmake_def: "-DWITH_CERES=ON -DWITH_PYTHON=ON -DBUILD_OPENGV=ON" extra_cmake_def: "-DWITH_CERES=ON -DWITH_PYTHON=ON -DBUILD_OPENGV=ON"
- build_name: ubuntu-26.04
os: ubuntu-26.04
extra_deps: "libg2o-dev libceres-dev"
extra_cmake_def: "-DWITH_CERES=ON -DWITH_PYTHON=ON -DBUILD_OPENGV=ON"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
+50 -13
View File
@@ -3,7 +3,7 @@ name: CMake-ROS
on: on:
push: push:
branches: branches:
- humble-devel - master
pull_request: pull_request:
branches: branches:
- '**' - '**'
@@ -22,25 +22,62 @@ jobs:
# well on Windows or Mac. You can convert this to a matrix build if you need # well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage. # cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
name: ${{ matrix.ros_distribution }} name: ${{ matrix.ros_distribution }}-${{ matrix.os }}
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ros_distribution: [ humble ] ros_distribution: [ humble, jazzy, kilted, rolling ]
include: include:
- ros_distribution: 'humble' - ros_distribution: 'humble'
skip_keys: "" os: ubuntu-22.04
container: - ros_distribution: 'jazzy'
image: osrf/ros:${{ matrix.ros_distribution }}-desktop-full os: ubuntu-24.04
- ros_distribution: 'kilted'
os: ubuntu-24.04
- ros_distribution: 'rolling'
os: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - name: Setup ROS2
# https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html
run: |
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
export ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F\" '{print $4}')
curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb"
sudo apt install /tmp/ros2-apt-source.deb
sudo apt update
- uses: ros-tooling/setup-ros@v0.7 - uses: ros-tooling/setup-ros@v0.7
with: with:
required-ros-distributions: ${{ matrix.ros_distribution }} required-ros-distributions: ${{ matrix.ros_distribution }}
- uses: ros-tooling/action-ros-ci@v0.4
with: - uses: actions/checkout@v4
package-name: rtabmap
target-ros2-distro: ${{ matrix.ros_distribution }} - name: Point rosdep to latest Rolling on Noble until github runners support ubuntu 26.04
rosdep-skip-keys: "${{ matrix.skip_keys }}" if: matrix.ros_distribution == 'rolling'
run: |
echo "ROSDISTRO_INDEX_URL=https://raw.githubusercontent.com/ros/rosdistro/6527fa694360d609c1491528ed50437bd853af5b/index-v4.yaml" >> $GITHUB_ENV
- name: Install dependencies
run: |
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
rosdep update
rosdep install --from-paths ${{github.workspace}} -y
- name: Configure CMake
run: |
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Info
working-directory: ${{github.workspace}}/build/bin
run: |
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
./rtabmap-console --version
+5 -35
View File
@@ -4,13 +4,6 @@ on:
push: push:
branches: branches:
- 'master' - 'master'
pull_request:
branches:
- '**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs: jobs:
docker_deps: docker_deps:
@@ -22,15 +15,14 @@ jobs:
# $ sudo apt-get upgrade qemu-user-static # $ sudo apt-get upgrade qemu-user-static
# $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -c yes # $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -c yes
# More info: https://github.com/introlab/rtabmap/issues/1454 # More info: https://github.com/introlab/rtabmap/issues/1454
# Skipped on pull requests; built and pushed only on push to master. # if: false
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
docker_tag: [focal-deps, jammy-deps, noble-deps, noble-kilted-deps, resolute-deps] docker_tag: [focal-deps, jammy-deps, noble-deps, noble-kilted-deps]
include: include:
- docker_tag: focal-deps - docker_tag: focal-deps
docker_tags: | docker_tags: |
@@ -60,13 +52,6 @@ jobs:
linux/amd64 linux/amd64
linux/arm64 linux/arm64
docker_path: 'noble-kilted/deps' docker_path: 'noble-kilted/deps'
- docker_tag: resolute-deps
docker_tags: |
introlab3it/rtabmap:resolute-deps
docker_platforms: |
linux/amd64
linux/arm64
docker_path: 'resolute/deps'
steps: steps:
- -
@@ -100,14 +85,12 @@ jobs:
docker: docker:
needs: docker_deps needs: docker_deps
# Run even when docker_deps is skipped (it is, on pull requests).
if: ${{ !cancelled() && !failure() }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
docker_tag: [bionic, focal, jammy, noble, noble-kilted, resolute, android23, android24, android26, android30] docker_tag: [bionic, focal, jammy, noble, noble-kilted, android23, android24, android26, android30]
include: include:
- docker_tag: bionic - docker_tag: bionic
docker_tags: | docker_tags: |
@@ -159,16 +142,6 @@ jobs:
linux/amd64 linux/amd64
linux/arm64 linux/arm64
docker_path: 'noble-kilted' docker_path: 'noble-kilted'
- docker_tag: resolute
docker_tags: |
introlab3it/rtabmap:resolute
introlab3it/rtabmap:26.04
docker_args: |
NOT_USED=0
docker_platforms: |
linux/amd64
linux/arm64
docker_path: 'resolute'
- docker_tag: android23 - docker_tag: android23
docker_tags: | docker_tags: |
introlab3it/rtabmap:android23 introlab3it/rtabmap:android23
@@ -217,9 +190,6 @@ jobs:
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- -
name: Login to DockerHub name: Login to DockerHub
# Only needed when pushing; skipped on pull requests (secrets are
# unavailable for fork PRs and we don't push there anyway).
if: github.event_name != 'pull_request'
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -229,8 +199,8 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
push: ${{ github.event_name != 'pull_request' }} push: true
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || matrix.docker_platforms }} platforms: ${{ matrix.docker_platforms }}
file: ./docker/${{ matrix.docker_path }}/Dockerfile file: ./docker/${{ matrix.docker_path }}/Dockerfile
build-args: | build-args: |
${{ matrix.docker_args }} ${{ matrix.docker_args }}
-114
View File
@@ -1,114 +0,0 @@
name: iOS
on:
push:
branches:
- master
paths: &ios_paths
- '.github/workflows/ios.yml'
- 'app/ios/**'
- 'app/android/jni/**'
- 'corelib/**'
- 'utilite/**'
- 'cmake_modules/**'
- 'CMakeLists.txt'
pull_request:
branches:
- '**'
paths: *ios_paths
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Pre-built iOS dependencies (content of app/ios/RTABMapApp/Libraries, generated by install_deps.sh).
# Bump this when the dependency set changes (must match the Xcode toolchain below).
DEPS_URL: https://github.com/introlab/rtabmap/releases/download/0.23.1/libraries-ios-xcode26.5.zip
XCODE_VERSION: '26.5'
jobs:
build:
name: build-ios
# macos-26 (Tahoe) ships Xcode 26.x, matching the toolchain used to build the prebuilt libraries.
runs-on: macos-26
steps:
- uses: actions/checkout@v4
- name: Select Xcode ${{ env.XCODE_VERSION }}
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.XCODE_VERSION }}
- name: Versions
run: |
xcodebuild -version
cmake --version || brew install cmake
- name: Cache prebuilt dependencies archive
id: deps-cache
uses: actions/cache@v4
with:
path: deps.zip
# Keyed on the archive URL (release tag + filename), so the cache is
# reused until DEPS_URL is bumped, regardless of other workflow edits.
key: ${{ runner.os }}-ios-deps-${{ env.DEPS_URL }}
- name: Download prebuilt dependencies
if: steps.deps-cache.outputs.cache-hit != 'true'
run: curl -L "$DEPS_URL" -o deps.zip
- name: Extract dependencies into Libraries
run: |
set -eux
mkdir -p app/ios/RTABMapApp/Libraries
rm -rf deps_extract && mkdir -p deps_extract
unzip -q deps.zip -d deps_extract
# The archive holds the *content* of the Libraries folder (include/ lib/ share/),
# but tolerate an extra top-level Libraries/ wrapper just in case.
if [ -d deps_extract/Libraries ]; then
SRC=deps_extract/Libraries
else
SRC=deps_extract
fi
cp -R "$SRC"/. app/ios/RTABMapApp/Libraries/
test -d app/ios/RTABMapApp/Libraries/include
test -d app/ios/RTABMapApp/Libraries/lib
- name: Build rtabmap core (third-party deps are skipped, already provided by the archive)
working-directory: app/ios/RTABMapApp
run: ./install_deps.sh
- name: Build RTABMapApp
run: |
xcodebuild \
-project app/ios/RTABMapApp.xcodeproj \
-scheme RTABMapApp \
-configuration Release \
-sdk iphoneos \
-destination 'generic/platform=iOS' \
-derivedDataPath build \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY="" \
DEVELOPMENT_TEAM="" \
build
- name: Package app (unsigned .ipa)
run: |
set -eux
APP_DIR="build/Build/Products/Release-iphoneos"
rm -rf Payload && mkdir Payload
cp -R "$APP_DIR/RTABMapApp.app" Payload/
# Unsigned .ipa: not installable as-is, but ready for later (re)signing.
zip -q -r RTABMapApp-unsigned.ipa Payload
- name: Upload app artifact
uses: actions/upload-artifact@v4
with:
name: RTABMapApp-ios-unsigned
path: RTABMapApp-unsigned.ipa
compression-level: 0
if-no-files-found: error
retention-days: ${{ github.event_name == 'pull_request' && 1 || 90 }}
+18 -6
View File
@@ -842,7 +842,22 @@ IF(WITH_VINS_FUSION)
ENDIF(WITH_VINS_FUSION) ENDIF(WITH_VINS_FUSION)
IF(WITH_OPENVINS) IF(WITH_OPENVINS)
FIND_PACKAGE(OpenVINS) FIND_PACKAGE(ov_msckf)
# On ROS2, the indirect includes and libraries
# are not forwarded by ov_msckf target, append them manually
FIND_PACKAGE(ov_core)
FIND_PACKAGE(ov_init)
IF(ov_msckf_FOUND AND ov_core_FOUND AND ov_init_FOUND)
SET(ov_msckf_INCLUDE_DIRS
${ov_msckf_INCLUDE_DIRS}
${ov_core_INCLUDE_DIRS}
${ov_init_INCLUDE_DIRS})
SET(ov_msckf_LIBRARIES
${ov_msckf_LIBRARIES}
${ov_core_LIBRARIES}
${ov_init_LIBRARIES})
MESSAGE(STATUS "Found OpenVINS: ${ov_msckf_INCLUDE_DIRS}")
ENDIF()
ENDIF(WITH_OPENVINS) ENDIF(WITH_OPENVINS)
IF(WITH_FASTCV) IF(WITH_FASTCV)
@@ -901,9 +916,6 @@ IF(WITH_OPENGV OR okvis_FOUND)
set(BUILD_TESTS OFF) set(BUILD_TESTS OFF)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# OpenGV's CMakeLists.txt declares cmake_minimum_required(VERSION 2.x),
# which CMake >= 4.0 (e.g. recent Ubuntu) rejects. Allow it to configure.
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
# Eigen should have been already added by PCL, just populate the compatible variables # Eigen should have been already added by PCL, just populate the compatible variables
IF(EIGEN_INCLUDE_DIRS) IF(EIGEN_INCLUDE_DIRS)
set(EIGEN_INCLUDE_DIRS "${EIGEN_INCLUDE_DIRS}" CACHE PATH "Eigen include dirs" FORCE) set(EIGEN_INCLUDE_DIRS "${EIGEN_INCLUDE_DIRS}" CACHE PATH "Eigen include dirs" FORCE)
@@ -1211,7 +1223,7 @@ ENDIF()
IF(NOT vins_FOUND) IF(NOT vins_FOUND)
SET(VINSFUSION "//") SET(VINSFUSION "//")
ENDIF() ENDIF()
IF(NOT OpenVINS_FOUND) IF(NOT ov_msckf_FOUND)
SET(OPENVINS "//") SET(OPENVINS "//")
ENDIF() ENDIF()
IF(NOT CUVSLAM_FOUND) IF(NOT CUVSLAM_FOUND)
@@ -1969,7 +1981,7 @@ ELSE()
MESSAGE(STATUS " With VINS-Fusion = NO (VINS-Fusion not found)") MESSAGE(STATUS " With VINS-Fusion = NO (VINS-Fusion not found)")
ENDIF() ENDIF()
IF(OpenVINS_FOUND) IF(ov_msckf_FOUND)
MESSAGE(STATUS " With OpenVINS = YES (License: GPLv3)") MESSAGE(STATUS " With OpenVINS = YES (License: GPLv3)")
ELSEIF(NOT WITH_OPENVINS) ELSEIF(NOT WITH_OPENVINS)
MESSAGE(STATUS " With OpenVINS = NO (WITH_OPENVINS=OFF)") MESSAGE(STATUS " With OpenVINS = NO (WITH_OPENVINS=OFF)")
+2 -2
View File
@@ -1065,7 +1065,7 @@
"$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib",
"$(PROJECT_DIR)/RTABMapApp/Libraries/lib/opencv4/3rdparty", "$(PROJECT_DIR)/RTABMapApp/Libraries/lib/opencv4/3rdparty",
); );
MARKETING_VERSION = 0.23.7; MARKETING_VERSION = 0.22.0;
OTHER_CFLAGS = ""; OTHER_CFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap; PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1125,7 +1125,7 @@
"$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib", "$(PROJECT_DIR)/RTABMapApp/Libraries/share/OpenCV/3rdparty/lib",
"$(PROJECT_DIR)/RTABMapApp/Libraries/lib/opencv4/3rdparty", "$(PROJECT_DIR)/RTABMapApp/Libraries/lib/opencv4/3rdparty",
); );
MARKETING_VERSION = 0.23.7; MARKETING_VERSION = 0.22.0;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = ""; OTHER_CFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap; PRODUCT_BUNDLE_IDENTIFIER = com.introlab.rtabmap;
-12
View File
@@ -175,18 +175,6 @@ cd $pwd
#rm -rf g2o #rm -rf g2o
fi fi
# g2o's installed CMake config hard-codes the absolute build-time prefix of its
# external dependencies (e.g. suitesparse) in INTERFACE_INCLUDE_DIRECTORIES. That
# path doesn't exist when the prebuilt Libraries archive is unpacked on another
# machine (CI), breaking find_package(g2o) with "includes non-existent path".
# Rewrite those absolute paths to be relocatable (relative to the config file).
# Run unconditionally (outside the build guard above) so it also fixes the prebuilt
# archive in CI, where the g2o build step is skipped.
find "$prefix/lib" -path '*/cmake/g2o/*.cmake' -print0 | while IFS= read -r -d '' f
do
sed -i '' -E 's#[^";]*/Libraries#${CMAKE_CURRENT_LIST_DIR}/../../..#g' "$f"
done
# VTK # VTK
if [ ! -e $prefix/lib/vtk.framework ] if [ ! -e $prefix/lib/vtk.framework ]
then then
-44
View File
@@ -1,44 +0,0 @@
# Find OpenVINS
#
# We search for a vins installation in ROS/ROS2 first, then fallback on
# ros-free library in common install paths
FIND_PACKAGE(ov_msckf QUIET)
IF(ov_msckf_FOUND)
# On ROS2, the indirect includes and libraries
# are not forwarded by ov_msckf target, append them manually
FIND_PACKAGE(ov_core)
FIND_PACKAGE(ov_init)
IF(ov_msckf_FOUND AND ov_core_FOUND AND ov_init_FOUND)
SET(OpenVINS_FOUND TRUE)
SET(OpenVINS_INCLUDE_DIRS
${ov_msckf_INCLUDE_DIRS}
${ov_core_INCLUDE_DIRS}
${ov_init_INCLUDE_DIRS})
SET(OpenVINS_LIBRARIES
${ov_msckf_LIBRARIES}
${ov_core_LIBRARIES}
${ov_init_LIBRARIES})
ENDIF()
ELSE()
find_path(OpenVINS_INCLUDE_DIR NAMES core/VioManager.h PATH_SUFFIXES open_vins)
find_library(OpenVINS_LIBRARY NAMES ov_msckf_lib)
IF (OpenVINS_INCLUDE_DIR AND OpenVINS_LIBRARY)
SET(OpenVINS_FOUND TRUE)
SET(OpenVINS_INCLUDE_DIRS ${OpenVINS_INCLUDE_DIR})
SET(OpenVINS_LIBRARIES ${OpenVINS_LIBRARY})
ENDIF()
ENDIF()
IF (OpenVINS_FOUND)
# show which OpenVINS was found only if not quiet
IF (NOT OpenVINS_FIND_QUIETLY)
MESSAGE(STATUS "Found OpenVINS: ${OpenVINS_LIBRARIES} ${OpenVINS_INCLUDE_DIRS}")
ENDIF (NOT OpenVINS_FIND_QUIETLY)
ELSE (OpenVINS_FOUND)
# fatal error if OpenVINS is required but not found
IF (OpenVINS_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find OpenVINS")
ENDIF (OpenVINS_FIND_REQUIRED)
ENDIF (OpenVINS_FOUND)
+56 -57
View File
@@ -620,67 +620,66 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM_STR(OdomVINSFusion, ConfigPath, "", "Path of VINS-Fusion config file."); RTABMAP_PARAM_STR(OdomVINSFusion, ConfigPath, "", "Path of VINS-Fusion config file.");
// Odometry OpenVINS // Odometry OpenVINS
RTABMAP_PARAM_STR(OdomOpenVINS, ConfigPath, "", "Path of OpenVINS config file (*.yaml). Same format used than OpenVINS library. Note that any parameter from that config file will overwrite the same parameter in OdomOpenVINS group."); RTABMAP_PARAM(OdomOpenVINS, UseStereo, bool, true, "If we have more than 1 camera, if we should try to track stereo constraints between pairs");
RTABMAP_PARAM(OdomOpenVINS, UseStereo, bool, true, "If we have more than 1 camera, if we should try to track stereo constraints between pairs."); RTABMAP_PARAM(OdomOpenVINS, UseKLT, bool, true, "If true we will use KLT, otherwise use a ORB descriptor + robust matching");
RTABMAP_PARAM(OdomOpenVINS, UseKLT, bool, true, "If true we will use KLT, otherwise use a ORB descriptor + robust matching."); RTABMAP_PARAM(OdomOpenVINS, NumPts, int, 200, "Number of points (per camera) we will extract and try to track");
RTABMAP_PARAM(OdomOpenVINS, NumPts, int, 200, "Number of points (per camera) we will extract and try to track."); RTABMAP_PARAM(OdomOpenVINS, MinPxDist, int, 15, "Eistance between features (features near each other provide less information)");
RTABMAP_PARAM(OdomOpenVINS, MinPxDist, int, 15, "Eistance between features (features near each other provide less information)."); RTABMAP_PARAM(OdomOpenVINS, FiTriangulate1d, bool, false, "If we should perform 1d triangulation instead of 3d");
RTABMAP_PARAM(OdomOpenVINS, FiTriangulate1d, bool, false, "If we should perform 1d triangulation instead of 3d."); RTABMAP_PARAM(OdomOpenVINS, FiRefineFeatures, bool, true, "If we should perform Levenberg-Marquardt refinement");
RTABMAP_PARAM(OdomOpenVINS, FiRefineFeatures, bool, true, "If we should perform Levenberg-Marquardt refinement."); RTABMAP_PARAM(OdomOpenVINS, FiMaxRuns, int, 5, "Max runs for Levenberg-Marquardt");
RTABMAP_PARAM(OdomOpenVINS, FiMaxRuns, int, 5, "Max runs for Levenberg-Marquardt."); RTABMAP_PARAM(OdomOpenVINS, FiMaxBaseline, double, 40, "Max baseline ratio to accept triangulated features");
RTABMAP_PARAM(OdomOpenVINS, FiMaxBaseline, double, 40, "Max baseline ratio to accept triangulated features."); RTABMAP_PARAM(OdomOpenVINS, FiMaxCondNumber, double, 10000, "Max condition number of linear triangulation matrix accept triangulated features");
RTABMAP_PARAM(OdomOpenVINS, FiMaxCondNumber, double, 10000, "Max condition number of linear triangulation matrix accept triangulated features.");
RTABMAP_PARAM(OdomOpenVINS, UseFEJ, bool, true, "If first-estimate Jacobians should be used (enable for good consistency)."); RTABMAP_PARAM(OdomOpenVINS, UseFEJ, bool, true, "If first-estimate Jacobians should be used (enable for good consistency)");
RTABMAP_PARAM(OdomOpenVINS, Integration, int, 1, "0=discrete, 1=rk4, 2=analytical (if rk4 or analytical used then analytical covariance propagation is used)."); RTABMAP_PARAM(OdomOpenVINS, Integration, int, 1, "0=discrete, 1=rk4, 2=analytical (if rk4 or analytical used then analytical covariance propagation is used)");
RTABMAP_PARAM(OdomOpenVINS, CalibCamExtrinsics, bool, false, "Bool to determine whether or not to calibrate imu-to-camera pose."); RTABMAP_PARAM(OdomOpenVINS, CalibCamExtrinsics, bool, false, "Bool to determine whether or not to calibrate imu-to-camera pose");
RTABMAP_PARAM(OdomOpenVINS, CalibCamIntrinsics, bool, false, "Bool to determine whether or not to calibrate camera intrinsics."); RTABMAP_PARAM(OdomOpenVINS, CalibCamIntrinsics, bool, false, "Bool to determine whether or not to calibrate camera intrinsics");
RTABMAP_PARAM(OdomOpenVINS, CalibCamTimeoffset, bool, false, "Bool to determine whether or not to calibrate camera to IMU time offset."); RTABMAP_PARAM(OdomOpenVINS, CalibCamTimeoffset, bool, false, "Bool to determine whether or not to calibrate camera to IMU time offset");
RTABMAP_PARAM(OdomOpenVINS, CalibIMUIntrinsics, bool, false, "Bool to determine whether or not to calibrate the IMU intrinsics."); RTABMAP_PARAM(OdomOpenVINS, CalibIMUIntrinsics, bool, false, "Bool to determine whether or not to calibrate the IMU intrinsics");
RTABMAP_PARAM(OdomOpenVINS, CalibIMUGSensitivity, bool, false, "Bool to determine whether or not to calibrate the Gravity sensitivity."); RTABMAP_PARAM(OdomOpenVINS, CalibIMUGSensitivity, bool, false, "Bool to determine whether or not to calibrate the Gravity sensitivity");
RTABMAP_PARAM(OdomOpenVINS, MaxClones, int, 11, "Max clone size of sliding window."); RTABMAP_PARAM(OdomOpenVINS, MaxClones, int, 11, "Max clone size of sliding window");
RTABMAP_PARAM(OdomOpenVINS, MaxSLAM, int, 50, "Max number of estimated SLAM features."); RTABMAP_PARAM(OdomOpenVINS, MaxSLAM, int, 50, "Max number of estimated SLAM features");
RTABMAP_PARAM(OdomOpenVINS, MaxSLAMInUpdate, int, 25, "Max number of SLAM features we allow to be included in a single EKF update.."); RTABMAP_PARAM(OdomOpenVINS, MaxSLAMInUpdate, int, 25, "Max number of SLAM features we allow to be included in a single EKF update.");
RTABMAP_PARAM(OdomOpenVINS, MaxMSCKFInUpdate, int, 50, "Max number of MSCKF features we will use at a given image timestep.."); RTABMAP_PARAM(OdomOpenVINS, MaxMSCKFInUpdate, int, 50, "Max number of MSCKF features we will use at a given image timestep.");
RTABMAP_PARAM(OdomOpenVINS, FeatRepMSCKF, int, 0, "What representation our features are in (msckf features)."); RTABMAP_PARAM(OdomOpenVINS, FeatRepMSCKF, int, 0, "What representation our features are in (msckf features)");
RTABMAP_PARAM(OdomOpenVINS, FeatRepSLAM, int, 4, "What representation our features are in (slam features)."); RTABMAP_PARAM(OdomOpenVINS, FeatRepSLAM, int, 4, "What representation our features are in (slam features)");
RTABMAP_PARAM(OdomOpenVINS, DtSLAMDelay, double, 0.0, "Delay, in seconds, that we should wait from init before we start estimating SLAM features."); RTABMAP_PARAM(OdomOpenVINS, DtSLAMDelay, double, 0.0, "Delay, in seconds, that we should wait from init before we start estimating SLAM features");
RTABMAP_PARAM(OdomOpenVINS, GravityMag, double, 9.81, "Gravity magnitude in the global frame (i.e. should be 9.81 typically)."); RTABMAP_PARAM(OdomOpenVINS, GravityMag, double, 9.81, "Gravity magnitude in the global frame (i.e. should be 9.81 typically)");
RTABMAP_PARAM_STR(OdomOpenVINS, LeftMaskPath, "", "Mask for left image."); RTABMAP_PARAM_STR(OdomOpenVINS, LeftMaskPath, "", "Mask for left image");
RTABMAP_PARAM_STR(OdomOpenVINS, RightMaskPath, "", "Mask for right image."); RTABMAP_PARAM_STR(OdomOpenVINS, RightMaskPath, "", "Mask for right image");
RTABMAP_PARAM(OdomOpenVINS, InitWindowTime, double, 2.0, "Amount of time we will initialize over (seconds)."); RTABMAP_PARAM(OdomOpenVINS, InitWindowTime, double, 2.0, "Amount of time we will initialize over (seconds)");
RTABMAP_PARAM(OdomOpenVINS, InitIMUThresh, double, 1.0, "Variance threshold on our acceleration to be classified as moving."); RTABMAP_PARAM(OdomOpenVINS, InitIMUThresh, double, 1.0, "Variance threshold on our acceleration to be classified as moving");
RTABMAP_PARAM(OdomOpenVINS, InitMaxDisparity, double, 10.0, "Max disparity to consider the platform stationary (dependent on resolution)."); RTABMAP_PARAM(OdomOpenVINS, InitMaxDisparity, double, 10.0, "Max disparity to consider the platform stationary (dependent on resolution)");
RTABMAP_PARAM(OdomOpenVINS, InitMaxFeatures, int, 50, "How many features to track during initialization (saves on computation)."); RTABMAP_PARAM(OdomOpenVINS, InitMaxFeatures, int, 50, "How many features to track during initialization (saves on computation)");
RTABMAP_PARAM(OdomOpenVINS, InitDynUse, bool, false, "If dynamic initialization should be used."); RTABMAP_PARAM(OdomOpenVINS, InitDynUse, bool, false, "If dynamic initialization should be used");
RTABMAP_PARAM(OdomOpenVINS, InitDynMLEOptCalib, bool, false, "If we should optimize calibration during intialization (not recommended)."); RTABMAP_PARAM(OdomOpenVINS, InitDynMLEOptCalib, bool, false, "If we should optimize calibration during intialization (not recommended)");
RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxIter, int, 50, "How many iterations the MLE refinement should use (zero to skip the MLE)."); RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxIter, int, 50, "How many iterations the MLE refinement should use (zero to skip the MLE)");
RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxTime, double, 0.05, "How many seconds the MLE should be completed in."); RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxTime, double, 0.05, "How many seconds the MLE should be completed in");
RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxThreads, int, 6, "How many threads the MLE should use."); RTABMAP_PARAM(OdomOpenVINS, InitDynMLEMaxThreads, int, 6, "How many threads the MLE should use");
RTABMAP_PARAM(OdomOpenVINS, InitDynNumPose, int, 6, "Number of poses to use within our window time (evenly spaced)."); RTABMAP_PARAM(OdomOpenVINS, InitDynNumPose, int, 6, "Number of poses to use within our window time (evenly spaced)");
RTABMAP_PARAM(OdomOpenVINS, InitDynMinDeg, double, 10.0, "Orientation change needed to try to init."); RTABMAP_PARAM(OdomOpenVINS, InitDynMinDeg, double, 10.0, "Orientation change needed to try to init");
RTABMAP_PARAM(OdomOpenVINS, InitDynInflationOri, double, 10.0, "What to inflate the recovered q_GtoI covariance by."); RTABMAP_PARAM(OdomOpenVINS, InitDynInflationOri, double, 10.0, "What to inflate the recovered q_GtoI covariance by");
RTABMAP_PARAM(OdomOpenVINS, InitDynInflationVel, double, 100.0, "What to inflate the recovered v_IinG covariance by."); RTABMAP_PARAM(OdomOpenVINS, InitDynInflationVel, double, 100.0, "What to inflate the recovered v_IinG covariance by");
RTABMAP_PARAM(OdomOpenVINS, InitDynInflationBg, double, 10.0, "What to inflate the recovered bias_g covariance by."); RTABMAP_PARAM(OdomOpenVINS, InitDynInflationBg, double, 10.0, "What to inflate the recovered bias_g covariance by");
RTABMAP_PARAM(OdomOpenVINS, InitDynInflationBa, double, 100.0, "What to inflate the recovered bias_a covariance by."); RTABMAP_PARAM(OdomOpenVINS, InitDynInflationBa, double, 100.0, "What to inflate the recovered bias_a covariance by");
RTABMAP_PARAM(OdomOpenVINS, InitDynMinRecCond, double, 1e-15, "Reciprocal condition number thresh for info inversion."); RTABMAP_PARAM(OdomOpenVINS, InitDynMinRecCond, double, 1e-15, "Reciprocal condition number thresh for info inversion");
RTABMAP_PARAM(OdomOpenVINS, TryZUPT, bool, true, "If we should try to use zero velocity update."); RTABMAP_PARAM(OdomOpenVINS, TryZUPT, bool, true, "If we should try to use zero velocity update");
RTABMAP_PARAM(OdomOpenVINS, ZUPTChi2Multiplier, double, 0.0, "Chi2 multiplier for zero velocity."); RTABMAP_PARAM(OdomOpenVINS, ZUPTChi2Multiplier, double, 0.0, "Chi2 multiplier for zero velocity");
RTABMAP_PARAM(OdomOpenVINS, ZUPTMaxVelodicy, double, 0.1, "Max velocity we will consider to try to do a zupt (i.e. if above this, don't do zupt)."); RTABMAP_PARAM(OdomOpenVINS, ZUPTMaxVelodicy, double, 0.1, "Max velocity we will consider to try to do a zupt (i.e. if above this, don't do zupt)");
RTABMAP_PARAM(OdomOpenVINS, ZUPTNoiseMultiplier, double, 10.0, "Multiplier of our zupt measurement IMU noise matrix (default should be 1.0)."); RTABMAP_PARAM(OdomOpenVINS, ZUPTNoiseMultiplier, double, 10.0, "Multiplier of our zupt measurement IMU noise matrix (default should be 1.0)");
RTABMAP_PARAM(OdomOpenVINS, ZUPTMaxDisparity, double, 0.5, "Max disparity we will consider to try to do a zupt (i.e. if above this, don't do zupt)."); RTABMAP_PARAM(OdomOpenVINS, ZUPTMaxDisparity, double, 0.5, "Max disparity we will consider to try to do a zupt (i.e. if above this, don't do zupt)");
RTABMAP_PARAM(OdomOpenVINS, ZUPTOnlyAtBeginning, bool, false, "If we should only use the zupt at the very beginning static initialization phase."); RTABMAP_PARAM(OdomOpenVINS, ZUPTOnlyAtBeginning, bool, false, "If we should only use the zupt at the very beginning static initialization phase");
RTABMAP_PARAM(OdomOpenVINS, AccelerometerNoiseDensity, double, 0.01, "[m/s^2/sqrt(Hz)] (accel \"white noise\")."); RTABMAP_PARAM(OdomOpenVINS, AccelerometerNoiseDensity, double, 0.01, "[m/s^2/sqrt(Hz)] (accel \"white noise\")");
RTABMAP_PARAM(OdomOpenVINS, AccelerometerRandomWalk, double, 0.001, "[m/s^3/sqrt(Hz)] (accel bias diffusion)."); RTABMAP_PARAM(OdomOpenVINS, AccelerometerRandomWalk, double, 0.001, "[m/s^3/sqrt(Hz)] (accel bias diffusion)");
RTABMAP_PARAM(OdomOpenVINS, GyroscopeNoiseDensity, double, 0.001, "[rad/s/sqrt(Hz)] (gyro \"white noise\")."); RTABMAP_PARAM(OdomOpenVINS, GyroscopeNoiseDensity, double, 0.001, "[rad/s/sqrt(Hz)] (gyro \"white noise\")");
RTABMAP_PARAM(OdomOpenVINS, GyroscopeRandomWalk, double, 0.0001, "[rad/s^2/sqrt(Hz)] (gyro bias diffusion)."); RTABMAP_PARAM(OdomOpenVINS, GyroscopeRandomWalk, double, 0.0001, "[rad/s^2/sqrt(Hz)] (gyro bias diffusion)");
RTABMAP_PARAM(OdomOpenVINS, UpMSCKFSigmaPx, double, 1.0, "Pixel noise for MSCKF features."); RTABMAP_PARAM(OdomOpenVINS, UpMSCKFSigmaPx, double, 1.0, "Pixel noise for MSCKF features");
RTABMAP_PARAM(OdomOpenVINS, UpMSCKFChi2Multiplier, double, 1.0, "Chi2 multiplier for MSCKF features."); RTABMAP_PARAM(OdomOpenVINS, UpMSCKFChi2Multiplier, double, 1.0, "Chi2 multiplier for MSCKF features");
RTABMAP_PARAM(OdomOpenVINS, UpSLAMSigmaPx, double, 1.0, "Pixel noise for SLAM features."); RTABMAP_PARAM(OdomOpenVINS, UpSLAMSigmaPx, double, 1.0, "Pixel noise for SLAM features");
RTABMAP_PARAM(OdomOpenVINS, UpSLAMChi2Multiplier, double, 1.0, "Chi2 multiplier for SLAM features."); RTABMAP_PARAM(OdomOpenVINS, UpSLAMChi2Multiplier, double, 1.0, "Chi2 multiplier for SLAM features");
// Odometry Open3D // Odometry Open3D
RTABMAP_PARAM(OdomOpen3D, MaxDepth, float, 3.0, "Maximum depth."); RTABMAP_PARAM(OdomOpen3D, MaxDepth, float, 3.0, "Maximum depth.");
@@ -83,6 +83,7 @@ class RTABMAP_CORE_EXPORT Statistics
RTABMAP_STATS(Loop, Optimization_max_error_removed_from_id, ); RTABMAP_STATS(Loop, Optimization_max_error_removed_from_id, );
RTABMAP_STATS(Loop, Optimization_max_error_removed_to_id, ); RTABMAP_STATS(Loop, Optimization_max_error_removed_to_id, );
RTABMAP_STATS(Loop, Optimization_max_error_removed_count, ); RTABMAP_STATS(Loop, Optimization_max_error_removed_count, );
RTABMAP_STATS(Loop, Optimization_factors, );
RTABMAP_STATS(Loop, Linear_variance,); RTABMAP_STATS(Loop, Linear_variance,);
RTABMAP_STATS(Loop, Angular_variance,); RTABMAP_STATS(Loop, Angular_variance,);
RTABMAP_STATS(Loop, Landmark_detected,); RTABMAP_STATS(Loop, Landmark_detected,);
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define OPTIMIZERGTSAM_H_ #define OPTIMIZERGTSAM_H_
#include <rtabmap/core/Optimizer.h> #include <rtabmap/core/Optimizer.h>
#include <tuple>
namespace gtsam { namespace gtsam {
class ISAM2; class ISAM2;
@@ -58,26 +59,25 @@ public:
double * finalError = 0, double * finalError = 0,
int * iterationsDone = 0); int * iterationsDone = 0);
// True when iSAM2 (incremental) backend is active.
bool isIncremental() const {return isam2_ != 0;}
// Number of factors we believe are live in iSAM2.
std::size_t getTrackedFactorsCount() const {
return trackedFactors_.size() + (lastRootFactorIndex_.first != 0 ? 1 : 0);
}
// Live factor count reported by iSAM2 itself (should match getTrackedFactorsCount()).
std::size_t getISAM2LiveFactorsCount() const;
private: private:
int internalOptimizerType_; int internalOptimizerType_;
gtsam::ISAM2 * isam2_; gtsam::ISAM2 * isam2_;
struct ConstraintToFactor {
ConstraintToFactor(int _from, int _to, std::uint64_t _factorIndice)
{
from = _from;
to = _to;
factorIndice = _factorIndice;
}
int from;
int to;
std::uint64_t factorIndice;
};
std::vector<ConstraintToFactor> lastAddedConstraints_;
int lastSwitchId_; int lastSwitchId_;
std::set<int> addedPoses_; std::set<int> addedPoses_;
std::map<int, bool> isLandmarkWithRotation_; // persists across iSAM2 incremental calls std::map<int, bool> isLandmarkWithRotation_; // persists across iSAM2 incremental calls
std::map<std::tuple<int, int, int>, std::uint64_t> trackedFactors_; // iSAM2 tracked constraints
std::pair<int, std::uint64_t> lastRootFactorIndex_; std::pair<int, std::uint64_t> lastRootFactorIndex_;
}; };
+4 -4
View File
@@ -781,16 +781,16 @@ IF(vins_FOUND)
) )
ENDIF(vins_FOUND) ENDIF(vins_FOUND)
IF(OpenVINS_FOUND) IF(ov_msckf_FOUND)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
${OpenVINS_INCLUDE_DIRS} ${ov_msckf_INCLUDE_DIRS}
${INCLUDE_DIRS} ${INCLUDE_DIRS}
) )
SET(LIBRARIES SET(LIBRARIES
${OpenVINS_LIBRARIES} ${ov_msckf_LIBRARIES}
${LIBRARIES} ${LIBRARIES}
) )
ENDIF(OpenVINS_FOUND) ENDIF(ov_msckf_FOUND)
IF(ORB_SLAM_FOUND) IF(ORB_SLAM_FOUND)
SET(INCLUDE_DIRS SET(INCLUDE_DIRS
+4 -61
View File
@@ -887,17 +887,8 @@ cv::Mat Feature2D::generateDescriptors(
UASSERT(!image.empty()); UASSERT(!image.empty());
UASSERT(image.type() == CV_8UC1); UASSERT(image.type() == CV_8UC1);
descriptors = generateDescriptorsImpl(image, keypoints); descriptors = generateDescriptorsImpl(image, keypoints);
if(descriptors.rows != (int)keypoints.size()) UASSERT_MSG(descriptors.rows == (int)keypoints.size(), uFormat("descriptors=%d, keypoints=%d", descriptors.rows, (int)keypoints.size()).c_str());
{ UDEBUG("Descriptors extracted = %d, remaining kpts=%d", descriptors.rows, (int)keypoints.size());
UWARN("Descriptor extraction returned %d rows for %d keypoints — "
"clearing keypoints to keep them in sync.",
descriptors.rows, (int)keypoints.size());
keypoints.clear();
descriptors = cv::Mat();
}
else {
UDEBUG("Descriptors extracted = %d, remaining kpts=%d", descriptors.rows, (int)keypoints.size());
}
} }
return descriptors; return descriptors;
} }
@@ -2639,31 +2630,7 @@ cv::Mat SuperPointTorch::generateDescriptorsImpl(const cv::Mat & image, std::vec
{ {
#ifdef RTABMAP_TORCH #ifdef RTABMAP_TORCH
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
cv::Mat descriptors; return superPoint_->compute(keypoints);
if(!keypoints.empty())
{
descriptors = superPoint_->compute(keypoints);
if(descriptors.empty())
{
// superpoint may have been reset between keypoint detection and now,
// re-detect features to re-inialize the descriptors matrix, then
// re-extract descriptors with original keypoints.
UWARN("Re-initializing superpoint on that image to extract descriptors");
if(!superPoint_->detect(image).empty())
{
descriptors = superPoint_->compute(keypoints);
if(descriptors.rows == (int)keypoints.size())
{
UWARN("Sucessfully re-initialized superpoint, returning %d descriptors.", descriptors.rows);
}
}
else
{
UWARN("Failed to re-initialize superpoint on that image, returning empty descriptors.");
}
}
}
return descriptors;
#else #else
UWARN("RTAB-Map is not built with Torch support so SuperPoint Torch feature cannot be used!"); UWARN("RTAB-Map is not built with Torch support so SuperPoint Torch feature cannot be used!");
return cv::Mat(); return cv::Mat();
@@ -2765,31 +2732,7 @@ cv::Mat SuperPointRpautrat::generateDescriptorsImpl(const cv::Mat & image, std::
{ {
#if defined(RTABMAP_TORCH) && defined(RTABMAP_PYTHON) #if defined(RTABMAP_TORCH) && defined(RTABMAP_PYTHON)
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U); UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
cv::Mat descriptors; return superPoint_->compute(keypoints);
if(!keypoints.empty())
{
descriptors = superPoint_->compute(keypoints);
if(descriptors.empty())
{
// superpoint may have been reset between keypoint detection and now,
// re-detect features to re-inialize the descriptors matrix, then
// re-extract descriptors with original keypoints.
UWARN("Re-initializing superpoint on that image to extract descriptors");
if(!superPoint_->detect(image).empty())
{
descriptors = superPoint_->compute(keypoints);
if(descriptors.rows == (int)keypoints.size())
{
UWARN("Sucessfully re-initialized superpoint, returning %d descriptors.", descriptors.rows);
}
}
else
{
UWARN("Failed to re-initialize superpoint on that image, returning empty descriptors.");
}
}
}
return descriptors;
#else #else
UWARN("RTAB-Map is not built with Torch support so SuperPoint Rpautrat feature cannot be used!"); UWARN("RTAB-Map is not built with Torch support so SuperPoint Rpautrat feature cannot be used!");
return cv::Mat(); return cv::Mat();
+2 -2
View File
@@ -551,7 +551,7 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
} }
if(idsAdded.find(det->id)!=idsAdded.end()) if(idsAdded.find(det->id)!=idsAdded.end())
{ {
UDEBUG("Marker %d already added by another camera, ignoring detection from camera %d", det->id, cameraIndex); UWARN("Marker %d already added by another camera, ignoring detection from camera %d", det->id, cameraIndex);
continue; continue;
} }
@@ -668,7 +668,7 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
} }
if(idsAdded.find(id) != idsAdded.end()) if(idsAdded.find(id) != idsAdded.end())
{ {
UDEBUG("Marker %d already added by another camera, ignoring detection from camera %d", id, cameraIndex); UWARN("Marker %d already added by another camera, ignoring detection from camera %d", id, cameraIndex);
continue; continue;
} }
+132 -125
View File
@@ -5205,7 +5205,6 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
// is using less features than feature2D->getMaxFeatures() // is using less features than feature2D->getMaxFeatures()
meanWordsPerLocation = 0; meanWordsPerLocation = 0;
} }
UDEBUG("ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation);
if(_parallelized && !isIntermediateNode) if(_parallelized && !isIntermediateNode)
{ {
@@ -5475,90 +5474,41 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t); UDEBUG("time descriptors (%d) = %fs", descriptors.rows, t);
if(!imagesRectified && decimatedData.cameraModels().size()) UDEBUG("ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation);
if(descriptors.rows && descriptors.rows < _badSignRatio * float(meanWordsPerLocation))
{ {
UASSERT_MSG((int)keypoints.size() == descriptors.rows, uFormat("%d vs %d", (int)keypoints.size(), descriptors.rows).c_str()); descriptors = cv::Mat();
std::vector<cv::KeyPoint> keypointsValid; }
keypointsValid.reserve(keypoints.size()); else
cv::Mat descriptorsValid; {
descriptorsValid.reserve(descriptors.rows); if(!imagesRectified && decimatedData.cameraModels().size())
//undistort keypoints before projection (RGB-D)
if(decimatedData.cameraModels().size() == 1)
{ {
std::vector<cv::Point2f> pointsIn, pointsOut; UASSERT_MSG((int)keypoints.size() == descriptors.rows, uFormat("%d vs %d", (int)keypoints.size(), descriptors.rows).c_str());
cv::KeyPoint::convert(keypoints,pointsIn); std::vector<cv::KeyPoint> keypointsValid;
if(decimatedData.cameraModels()[0].D_raw().cols == 6) keypointsValid.reserve(keypoints.size());
{ cv::Mat descriptorsValid;
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) descriptorsValid.reserve(descriptors.rows);
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = decimatedData.cameraModels()[0].D_raw().at<double>(0,0);
D.at<double>(0,1) = decimatedData.cameraModels()[0].D_raw().at<double>(0,1);
D.at<double>(0,2) = decimatedData.cameraModels()[0].D_raw().at<double>(0,4);
D.at<double>(0,3) = decimatedData.cameraModels()[0].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[0].K_raw(),
D,
decimatedData.cameraModels()[0].R(),
decimatedData.cameraModels()[0].P());
}
else
#else
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
}
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[0].K_raw(),
decimatedData.cameraModels()[0].D_raw(),
decimatedData.cameraModels()[0].R(),
decimatedData.cameraModels()[0].P());
}
UASSERT(pointsOut.size() == keypoints.size());
for(unsigned int i=0; i<pointsOut.size(); ++i)
{
if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<decimatedData.cameraModels()[0].imageWidth() &&
pointsOut.at(i).y>=0 && pointsOut.at(i).y<decimatedData.cameraModels()[0].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut.at(i).x;
keypointsValid.back().pt.y = pointsOut.at(i).y;
descriptorsValid.push_back(descriptors.row(i));
}
}
}
else
{
UASSERT(int((decimatedData.imageRaw().cols/decimatedData.cameraModels().size())*decimatedData.cameraModels().size()) == decimatedData.imageRaw().cols);
float subImageWidth = decimatedData.imageRaw().cols/decimatedData.cameraModels().size();
for(unsigned int i=0; i<keypoints.size(); ++i)
{
int cameraIndex = int(keypoints.at(i).pt.x / subImageWidth);
UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (int)decimatedData.cameraModels().size(),
uFormat("cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
cameraIndex, (int)decimatedData.cameraModels().size(), keypoints[i].pt.x, subImageWidth, decimatedData.cameraModels()[0].imageWidth()).c_str());
//undistort keypoints before projection (RGB-D)
if(decimatedData.cameraModels().size() == 1)
{
std::vector<cv::Point2f> pointsIn, pointsOut; std::vector<cv::Point2f> pointsIn, pointsOut;
pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y)); cv::KeyPoint::convert(keypoints,pointsIn);
if(decimatedData.cameraModels()[cameraIndex].D_raw().cols == 6) if(decimatedData.cameraModels()[0].D_raw().cols == 6)
{ {
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye // Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4) // get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1); cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,0); D.at<double>(0,0) = decimatedData.cameraModels()[0].D_raw().at<double>(0,0);
D.at<double>(0,1) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,1); D.at<double>(0,1) = decimatedData.cameraModels()[0].D_raw().at<double>(0,1);
D.at<double>(0,2) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,4); D.at<double>(0,2) = decimatedData.cameraModels()[0].D_raw().at<double>(0,4);
D.at<double>(0,3) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,5); D.at<double>(0,3) = decimatedData.cameraModels()[0].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut, cv::fisheye::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[cameraIndex].K_raw(), decimatedData.cameraModels()[0].K_raw(),
D, D,
decimatedData.cameraModels()[cameraIndex].R(), decimatedData.cameraModels()[0].R(),
decimatedData.cameraModels()[cameraIndex].P()); decimatedData.cameraModels()[0].P());
} }
else else
#else #else
@@ -5569,57 +5519,114 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
{ {
//RadialTangential //RadialTangential
cv::undistortPoints(pointsIn, pointsOut, cv::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[cameraIndex].K_raw(), decimatedData.cameraModels()[0].K_raw(),
decimatedData.cameraModels()[cameraIndex].D_raw(), decimatedData.cameraModels()[0].D_raw(),
decimatedData.cameraModels()[cameraIndex].R(), decimatedData.cameraModels()[0].R(),
decimatedData.cameraModels()[cameraIndex].P()); decimatedData.cameraModels()[0].P());
} }
UASSERT(pointsOut.size() == keypoints.size());
if(pointsOut[0].x>=0 && pointsOut[0].x<decimatedData.cameraModels()[cameraIndex].imageWidth() && for(unsigned int i=0; i<pointsOut.size(); ++i)
pointsOut[0].y>=0 && pointsOut[0].y<decimatedData.cameraModels()[cameraIndex].imageHeight())
{ {
keypointsValid.push_back(keypoints.at(i)); if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<decimatedData.cameraModels()[0].imageWidth() &&
keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex; pointsOut.at(i).y>=0 && pointsOut.at(i).y<decimatedData.cameraModels()[0].imageHeight())
keypointsValid.back().pt.y = pointsOut[0].y; {
descriptorsValid.push_back(descriptors.row(i)); keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut.at(i).x;
keypointsValid.back().pt.y = pointsOut.at(i).y;
descriptorsValid.push_back(descriptors.row(i));
}
} }
} }
else
{
UASSERT(int((decimatedData.imageRaw().cols/decimatedData.cameraModels().size())*decimatedData.cameraModels().size()) == decimatedData.imageRaw().cols);
float subImageWidth = decimatedData.imageRaw().cols/decimatedData.cameraModels().size();
for(unsigned int i=0; i<keypoints.size(); ++i)
{
int cameraIndex = int(keypoints.at(i).pt.x / subImageWidth);
UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (int)decimatedData.cameraModels().size(),
uFormat("cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
cameraIndex, (int)decimatedData.cameraModels().size(), keypoints[i].pt.x, subImageWidth, decimatedData.cameraModels()[0].imageWidth()).c_str());
std::vector<cv::Point2f> pointsIn, pointsOut;
pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y));
if(decimatedData.cameraModels()[cameraIndex].D_raw().cols == 6)
{
#if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
// Equidistant / FishEye
// get only k parameters (k1,k2,p1,p2,k3,k4)
cv::Mat D(1, 4, CV_64FC1);
D.at<double>(0,0) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,0);
D.at<double>(0,1) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,1);
D.at<double>(0,2) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,4);
D.at<double>(0,3) = decimatedData.cameraModels()[cameraIndex].D_raw().at<double>(0,5);
cv::fisheye::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[cameraIndex].K_raw(),
D,
decimatedData.cameraModels()[cameraIndex].R(),
decimatedData.cameraModels()[cameraIndex].P());
}
else
#else
UWARN("Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
}
#endif
{
//RadialTangential
cv::undistortPoints(pointsIn, pointsOut,
decimatedData.cameraModels()[cameraIndex].K_raw(),
decimatedData.cameraModels()[cameraIndex].D_raw(),
decimatedData.cameraModels()[cameraIndex].R(),
decimatedData.cameraModels()[cameraIndex].P());
}
if(pointsOut[0].x>=0 && pointsOut[0].x<decimatedData.cameraModels()[cameraIndex].imageWidth() &&
pointsOut[0].y>=0 && pointsOut[0].y<decimatedData.cameraModels()[cameraIndex].imageHeight())
{
keypointsValid.push_back(keypoints.at(i));
keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex;
keypointsValid.back().pt.y = pointsOut[0].y;
descriptorsValid.push_back(descriptors.row(i));
}
}
}
keypoints = keypointsValid;
descriptors = descriptorsValid;
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f);
UDEBUG("time rectification = %fs", t);
} }
keypoints = keypointsValid; if(useProvided3dPoints && keypoints.size() != data.keypoints3D().size())
descriptors = descriptorsValid;
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f);
UDEBUG("time rectification = %fs", t);
}
if(useProvided3dPoints && keypoints.size() != data.keypoints3D().size())
{
UDEBUG("Using provided 3d points (%d->%d)", (int)data.keypoints3D().size(), (int)keypoints.size());
keypoints3D.resize(keypoints.size());
for(size_t i=0; i<keypoints.size(); ++i)
{ {
UASSERT(keypoints[i].class_id < (int)data.keypoints3D().size()); UDEBUG("Using provided 3d points (%d->%d)", (int)data.keypoints3D().size(), (int)keypoints.size());
keypoints3D[i] = data.keypoints3D()[keypoints[i].class_id]; keypoints3D.resize(keypoints.size());
for(size_t i=0; i<keypoints.size(); ++i)
{
UASSERT(keypoints[i].class_id < (int)data.keypoints3D().size());
keypoints3D[i] = data.keypoints3D()[keypoints[i].class_id];
}
}
else if(useProvided3dPoints && keypoints.size() == data.keypoints3D().size())
{
UDEBUG("Using provided 3d points (%d)", (int)data.keypoints3D().size());
keypoints3D = data.keypoints3D();
}
else if((!decimatedData.depthRaw().empty() && decimatedData.cameraModels().size() && decimatedData.cameraModels()[0].isValidForProjection()) ||
(!decimatedData.rightRaw().empty() && decimatedData.stereoCameraModels().size() && decimatedData.stereoCameraModels()[0].isValidForProjection()))
{
keypoints3D = _feature2D->generateKeypoints3D(decimatedData, keypoints);
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t);
}
if(depthMask.empty() && (_feature2D->getMinDepth() > 0.0f || _feature2D->getMaxDepth() > 0.0f))
{
_feature2D->filterKeypointsByDepth(keypoints, descriptors, keypoints3D, _feature2D->getMinDepth(), _feature2D->getMaxDepth());
} }
}
else if(useProvided3dPoints && keypoints.size() == data.keypoints3D().size())
{
UDEBUG("Using provided 3d points (%d)", (int)data.keypoints3D().size());
keypoints3D = data.keypoints3D();
}
else if((!decimatedData.depthRaw().empty() && decimatedData.cameraModels().size() && decimatedData.cameraModels()[0].isValidForProjection()) ||
(!decimatedData.rightRaw().empty() && decimatedData.stereoCameraModels().size() && decimatedData.stereoCameraModels()[0].isValidForProjection()))
{
keypoints3D = _feature2D->generateKeypoints3D(decimatedData, keypoints);
t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t);
}
if(depthMask.empty() && (_feature2D->getMinDepth() > 0.0f || _feature2D->getMaxDepth() > 0.0f))
{
_feature2D->filterKeypointsByDepth(keypoints, descriptors, keypoints3D, _feature2D->getMinDepth(), _feature2D->getMaxDepth());
} }
} }
else if(data.imageRaw().empty()) else if(data.imageRaw().empty())
@@ -5846,6 +5853,12 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t); UDEBUG("time keypoints 3D (%d) = %fs", (int)keypoints3D.size(), t);
UDEBUG("ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation);
if(descriptors.rows && descriptors.rows < _badSignRatio * float(meanWordsPerLocation))
{
descriptors = cv::Mat();
}
} }
} }
@@ -5871,9 +5884,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
bool addedToDictionary = false; bool addedToDictionary = false;
if(!keypoints.empty()) if(!keypoints.empty())
{ {
if(descriptors.rows && if(descriptors.rows && !isIntermediateNode)
!isIntermediateNode && // don't add intermediate nodes to dictionary
descriptors.rows >= int(_badSignRatio * float(meanWordsPerLocation))) // don't add bad signatures to dictionary
{ {
// In case the number of features we want to do quantization is lower // In case the number of features we want to do quantization is lower
// than extracted ones (that would be used for transform estimation) // than extracted ones (that would be used for transform estimation)
@@ -5980,11 +5991,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
else else
{ {
// Set all words as not used in dictionary // Set all words as not used in dictionary
int negIndex = -1; wordIds.resize(keypoints.size(),-1);
for(size_t i=0; i<keypoints.size(); ++i)
{
wordIds.push_back(negIndex--);
}
} }
t = timer.ticks(); t = timer.ticks();
+7
View File
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Version.h" #include "rtabmap/core/Version.h"
#include "rtabmap/core/Features2d.h" #include "rtabmap/core/Features2d.h"
#include "rtabmap/core/Optimizer.h" #include "rtabmap/core/Optimizer.h"
#include "rtabmap/core/optimizer/OptimizerGTSAM.h"
#include "rtabmap/core/Graph.h" #include "rtabmap/core/Graph.h"
#include "rtabmap/core/Signature.h" #include "rtabmap/core/Signature.h"
@@ -4231,6 +4232,12 @@ bool Rtabmap::process(
statistics_.addStatistic(Statistics::kLoopLandmark_detected_node_ref(), landmarksDetected.empty() || landmarksDetected.begin()->second.empty()?0:*landmarksDetected.begin()->second.begin()); statistics_.addStatistic(Statistics::kLoopLandmark_detected_node_ref(), landmarksDetected.empty() || landmarksDetected.begin()->second.empty()?0:*landmarksDetected.begin()->second.begin());
statistics_.addStatistic(Statistics::kLoopVisual_inliers_mean_dist(), loopClosureVisualInliersMeanDist); statistics_.addStatistic(Statistics::kLoopVisual_inliers_mean_dist(), loopClosureVisualInliersMeanDist);
statistics_.addStatistic(Statistics::kLoopVisual_inliers_distribution(), loopClosureVisualInliersDistribution); statistics_.addStatistic(Statistics::kLoopVisual_inliers_distribution(), loopClosureVisualInliersDistribution);
OptimizerGTSAM * gtsamOpt = dynamic_cast<OptimizerGTSAM*>(_graphOptimizer);
if(gtsamOpt != 0 && gtsamOpt->isIncremental())
{
statistics_.addStatistic(Statistics::kLoopOptimization_factors(), (float)gtsamOpt->getTrackedFactorsCount());
statistics_.addStatistic("Loop/Optimization_internal_factors", (float)gtsamOpt->getISAM2LiveFactorsCount());
}
statistics_.addStatistic(Statistics::kProximityTime_detections(), proximityDetectionsInTimeFound); statistics_.addStatistic(Statistics::kProximityTime_detections(), proximityDetectionsInTimeFound);
statistics_.addStatistic(Statistics::kProximitySpace_detections_added_visually(), proximityDetectionsAddedVisually); statistics_.addStatistic(Statistics::kProximitySpace_detections_added_visually(), proximityDetectionsAddedVisually);
-79
View File
@@ -152,85 +152,6 @@ OdometryOpenVINS::OdometryOpenVINS(const ParametersMap & parameters) :
params_->init_options.sigma_wb = params_->imu_noises.sigma_wb; params_->init_options.sigma_wb = params_->imu_noises.sigma_wb;
params_->init_options.sigma_pix = params_->slam_options.sigma_pix; params_->init_options.sigma_pix = params_->slam_options.sigma_pix;
params_->init_options.gravity_mag = params_->gravity_mag; params_->init_options.gravity_mag = params_->gravity_mag;
if(parameters.find(Parameters::kOdomOpenVINSConfigPath()) != parameters.end())
{
// Load the config: will override all parameters above!
std::string configPath = parameters.at(Parameters::kOdomOpenVINSConfigPath());
if(!configPath.empty())
{
if(UFile::exists(configPath))
{
UWARN("OpenVINS config file is provided (%s=\"%s\"), reading it. The parameters from the config file will overwrite OdomOpenVINS/*** parameters.",
Parameters::kOdomOpenVINSConfigPath().c_str(), configPath.c_str());
auto parser = std::make_shared<ov_core::YamlParser>(configPath);
// The sequence of loading is based on VioManagerOptions::print_and_load()
// We removed all parts about intrinsics/extrinsics, which will be loaded later
// when we receive the data (which should already include intrinsics and extrinsics).
params_->state_options.print(parser);
params_->init_options.print_and_load_initializer(parser);
params_->init_options.print_and_load_noise(parser);
parser->parse_config("gravity_mag", params_->init_options.gravity_mag);
parser->parse_config("max_cameras", params_->init_options.num_cameras);
parser->parse_config("use_stereo", params_->init_options.use_stereo);
parser->parse_config("downsample_cameras", params_->init_options.downsample_cameras);
parser->parse_config("dt_slam_delay", params_->dt_slam_delay);
parser->parse_config("try_zupt", params_->try_zupt);
parser->parse_config("zupt_max_velocity",params_-> zupt_max_velocity);
parser->parse_config("zupt_noise_multiplier", params_->zupt_noise_multiplier);
parser->parse_config("zupt_max_disparity", params_->zupt_max_disparity);
parser->parse_config("zupt_only_at_beginning", params_->zupt_only_at_beginning);
parser->parse_config("record_timing_information", params_->record_timing_information);
parser->parse_config("record_timing_filepath", params_->record_timing_filepath);
params_->print_and_load_trackers(parser);
params_->print_and_load_noise(parser);
if(params_->state_options.num_cameras > 2)
{
UFATAL("OpenVINS integration in RTAB-Map doesn't support more than 2 cameras (num_cameras=%d).", params_->state_options.num_cameras);
}
parser->parse_config("gravity_mag", params_->gravity_mag);
parser->parse_config("use_mask", params_->use_mask);
params_->masks.clear();
if (params_->use_mask) {
for (int i = 0; i < params_->state_options.num_cameras; i++) {
std::string mask_path;
std::string mask_node = "mask" + std::to_string(i);
parser->parse_config(mask_node, mask_path);
std::string total_mask_path = parser->get_config_folder() + mask_path;
if (!boost::filesystem::exists(total_mask_path)) {
PRINT_ERROR(RED "VioManager(): invalid mask path:\n" RESET);
PRINT_ERROR(RED "\t- mask%d - %s\n" RESET, i, total_mask_path.c_str());
std::exit(EXIT_FAILURE);
}
params_->masks.emplace(i, cv::imread(total_mask_path, cv::IMREAD_GRAYSCALE));
}
}
if (!parser->successful()) {
UWARN("Not all expected OpenVINS parameters were read successfully "
"from \"%s\". Values from RTAB-Map's OpenOpenVINS/* parameters "
"will be used instead for the missing ones.",
configPath.c_str());
}
else {
UINFO("OpenVINS config file(%s=\"%s\") read.",
Parameters::kOdomOpenVINSConfigPath().c_str(), configPath.c_str());
}
}
else
{
UERROR("OpenVINS config file is provided (%s=\"%s\") but it doesn't exist!",
Parameters::kOdomOpenVINSConfigPath().c_str(), configPath.c_str());
}
}
}
#endif #endif
} }
+145 -38
View File
@@ -90,6 +90,27 @@ bool OptimizerGTSAM::available()
#endif #endif
} }
std::size_t OptimizerGTSAM::getISAM2LiveFactorsCount() const
{
#ifdef RTABMAP_GTSAM
if(isam2_ == 0)
{
return 0;
}
// iSAM2 keeps removed factors as null entries to preserve factor indices,
// so we have to skip nulls to get the actual live count.
const gtsam::NonlinearFactorGraph & factors = isam2_->getFactorsUnsafe();
std::size_t live = 0;
for(const gtsam::NonlinearFactorGraph::sharedFactor & f : factors)
{
if(f) ++live;
}
return live;
#else
return 0;
#endif
}
void OptimizerGTSAM::parseParameters(const ParametersMap & parameters) void OptimizerGTSAM::parseParameters(const ParametersMap & parameters)
{ {
Optimizer::parseParameters(parameters); Optimizer::parseParameters(parameters);
@@ -124,7 +145,7 @@ void OptimizerGTSAM::parseParameters(const ParametersMap & parameters)
isam2_ = new gtsam::ISAM2(params); isam2_ = new gtsam::ISAM2(params);
addedPoses_.clear(); addedPoses_.clear();
lastAddedConstraints_.clear(); trackedFactors_.clear();
lastRootFactorIndex_.first = 0; lastRootFactorIndex_.first = 0;
lastSwitchId_ = 1000000000; lastSwitchId_ = 1000000000;
} }
@@ -197,7 +218,21 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
} }
} }
std::vector<ConstraintToFactor> addedPrior; // Ordered list of (from, to, type) entries added to the gtsam graph
// during this optimize() call. The order matches the order of factors
// pushed into iSAM2, so result.newFactorsIndices[j] gives the factor
// index for addedConstraints[j]. Used post-update to populate
// trackedFactors_. type holds Link::Type as int; type == -1 marks
// the synthetic root prior, which is managed separately via
// lastRootFactorIndex_ and stays out of trackedFactors_.
struct ConstraintToFactor {
ConstraintToFactor(int _from, int _to, int _type = -1) :
from(_from), to(_to), type(_type) {}
int from;
int to;
int type;
};
std::vector<ConstraintToFactor> addedConstraints;
gtsam::FactorIndices removeFactorIndices; gtsam::FactorIndices removeFactorIndices;
//prior first pose //prior first pose
@@ -211,7 +246,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
{ {
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasGPSPrior?1e-2:1e-9)); gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasGPSPrior?1e-2:1e-9));
graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.x(), initialPose.y(), initialPose.theta()), priorNoise)); graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.x(), initialPose.y(), initialPose.theta()), priorNoise));
addedPrior.push_back(ConstraintToFactor(rootId, rootId, -1)); addedConstraints.push_back(ConstraintToFactor(rootId, rootId));
} }
else else
{ {
@@ -221,7 +256,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
(hasGPSPrior?2:1e-2), hasGPSPrior?2:1e-2, hasGPSPrior?2:1e-2 // xyz (hasGPSPrior?2:1e-2), hasGPSPrior?2:1e-2, hasGPSPrior?2:1e-2 // xyz
).finished()); ).finished());
graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise)); graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise));
addedPrior.push_back(ConstraintToFactor(rootId, rootId, -1)); addedConstraints.push_back(ConstraintToFactor(rootId, rootId));
} }
if(isam2_ && lastRootFactorIndex_.first!=0) if(isam2_ && lastRootFactorIndex_.first!=0)
{ {
@@ -238,7 +273,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
delete isam2_; delete isam2_;
isam2_ = new gtsam::ISAM2(params); isam2_ = new gtsam::ISAM2(params);
addedPoses_.clear(); addedPoses_.clear();
lastAddedConstraints_.clear(); trackedFactors_.clear();
isLandmarkWithRotation_.clear(); isLandmarkWithRotation_.clear();
lastRootFactorIndex_.first = 0; lastRootFactorIndex_.first = 0;
lastSwitchId_ = 1000000000; lastSwitchId_ = 1000000000;
@@ -250,6 +285,16 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
std::map<int, Transform> newPoses; std::map<int, Transform> newPoses;
std::multimap<int, Link> newEdgeConstraints; std::multimap<int, Link> newEdgeConstraints;
// trackedFactors_ keys are (min(from,to), max(from,to), type) so that:
// - (A,B) and (B,A) with the same type map to the same entry
// (matches graph::findLink(checkBothWays=true) and the
// "Input links should be unique!" invariant in Graph.cpp);
// - the same pair with a *different* Link::Type counts as a
// distinct constraint and gets its own factor index.
auto linkKey = [](int from, int to, int type) {
return std::make_tuple(std::min(from, to), std::max(from, to), type);
};
if(isam2_) if(isam2_)
{ {
UDEBUG("Add new poses..."); UDEBUG("Add new poses...");
@@ -264,31 +309,78 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
} }
UDEBUG("Add new links..."); UDEBUG("Add new links...");
// new links? // new links?
// - self-referring (priors, gravity): add once per new pose, by
// checking addedPoses_ (these are never removed/re-added).
// - regular edges: add if (from,to,type) is not already a live
// factor in iSAM2 (trackedFactors_) AND not already queued
// earlier in this same call (queuedLinks). The latter dedupes
// bidirectional duplicates of the same logical edge supplied
// within a single optimize() call — only one factor goes into
// iSAM2.
// Self-ref constraints (priors, gravity) are tracked uniformly
// with edges: when a node is transferred to LTM its prior is
// dropped from the input, and we need to remove its factor from
// iSAM2. Likewise a prior re-supplied after being dropped must
// be re-added.
std::set<std::tuple<int, int, int> > queuedLinks;
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter) for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
if(addedPoses_.find(iter->second.from()) == addedPoses_.end() || const int from = iter->second.from();
addedPoses_.find(iter->second.to()) == addedPoses_.end()) const int to = iter->second.to();
const std::tuple<int, int, int> key = linkKey(from, to, (int)iter->second.type());
bool isNew;
if(trackedFactors_.find(key) != trackedFactors_.end())
{
isNew = false;
}
else if(!queuedLinks.insert(key).second)
{
// Already queued earlier in this call (bidirectional
// duplicate supplied as both A->B and B->A with the
// same type). Skip the second copy.
UDEBUG("Ignoring duplicate constraint %d (%d->%d type=%d)", iter->first, from, to, (int)iter->second.type());
isNew = false;
}
else
{
isNew = true;
}
if(isNew)
{ {
newEdgeConstraints.insert(*iter); newEdgeConstraints.insert(*iter);
UDEBUG("Adding constraint %d (%d->%d) to factor graph", iter->first, iter->second.from(), iter->second.to()); UDEBUG("Adding constraint %d (%d->%d type=%d) to factor graph", iter->first, from, to, (int)iter->second.type());
} }
} }
if(!this->isRobust()) if(!this->isRobust())
{ {
UDEBUG("Remove links..."); UDEBUG("Remove links...");
// Remove constraints not there anymore in case the last loop closures were rejected. // Remove every tracked non-self-ref factor whose (from,to,type)
// As we don't track "switch" constraints, we don't support this if vertigo is used. // is no longer present in the input. Covers loop closures
for(size_t i=0; i<lastAddedConstraints_.size(); ++i) // rejected since the last call, links deleted by graph repair,
// or any external deleteLink() applied to old edges. We don't
// track "switch" constraints, so this is skipped when vertigo
// is used.
std::set<std::tuple<int, int, int> > inputLinks;
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
if(lastAddedConstraints_[i].from != lastAddedConstraints_[i].to && inputLinks.insert(linkKey(iter->second.from(), iter->second.to(), (int)iter->second.type()));
graph::findLink(edgeConstraints, lastAddedConstraints_[i].from, lastAddedConstraints_[i].to) == edgeConstraints.end()) }
for(std::map<std::tuple<int, int, int>, std::uint64_t>::iterator iter=trackedFactors_.begin(); iter!=trackedFactors_.end(); )
{
if(inputLinks.find(iter->first) == inputLinks.end())
{ {
removeFactorIndices.push_back(lastAddedConstraints_[i].factorIndice); removeFactorIndices.push_back(iter->second);
UDEBUG("Removing constraint %d->%d (factor indice=%ld)", UDEBUG("Removing constraint %d->%d type=%d (factor indice=%ld)",
lastAddedConstraints_[i].from, std::get<0>(iter->first),
lastAddedConstraints_[i].to, std::get<1>(iter->first),
lastAddedConstraints_[i].factorIndice); std::get<2>(iter->first),
iter->second);
iter = trackedFactors_.erase(iter);
}
else
{
++iter;
} }
} }
} }
@@ -298,7 +390,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
return optimizedPoses; return optimizedPoses;
} }
lastAddedConstraints_ = addedPrior;
} }
else else
{ {
@@ -403,7 +495,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
1/iter->second.infMatrix().at<double>(0,0), 1/iter->second.infMatrix().at<double>(0,0),
1/iter->second.infMatrix().at<double>(1,1))); 1/iter->second.infMatrix().at<double>(1,1)));
graph.add(XYFactor<gtsam::Point2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model)); graph.add(XYFactor<gtsam::Point2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
else if (1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0) else if (1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0)
{ {
@@ -411,7 +503,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
1/iter->second.infMatrix().at<double>(0,0), 1/iter->second.infMatrix().at<double>(0,0),
1/iter->second.infMatrix().at<double>(1,1))); 1/iter->second.infMatrix().at<double>(1,1)));
graph.add(XYFactor<gtsam::Pose2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model)); graph.add(XYFactor<gtsam::Pose2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
else else
{ {
@@ -431,7 +523,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information); gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model)); graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
} }
else else
@@ -443,7 +535,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
iter->second.infMatrix().at<double>(1,1), iter->second.infMatrix().at<double>(1,1),
iter->second.infMatrix().at<double>(2,2))); iter->second.infMatrix().at<double>(2,2)));
graph.add(XYZFactor<gtsam::Point3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model)); graph.add(XYZFactor<gtsam::Point3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
else if (1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) >= 9999.0 || 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>(4,4)) >= 9999.0 ||
@@ -454,7 +546,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
iter->second.infMatrix().at<double>(1,1), iter->second.infMatrix().at<double>(1,1),
iter->second.infMatrix().at<double>(2,2))); iter->second.infMatrix().at<double>(2,2)));
graph.add(XYZFactor<gtsam::Pose3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model)); graph.add(XYZFactor<gtsam::Pose3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
else else
{ {
@@ -472,7 +564,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam); gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam);
graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model)); graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id1, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id1, (int)iter->second.type()));
} }
} }
} }
@@ -489,7 +581,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
#else #else
graph.add(gtsam::AttitudeFactor<gtsam::Pose3>(iter->first, nZ, model, bGMeas)); graph.add(gtsam::AttitudeFactor<gtsam::Pose3>(iter->first, nZ, model, bGMeas));
#endif #endif
lastAddedConstraints_.push_back(ConstraintToFactor(iter->first, iter->first, -1)); addedConstraints.push_back(ConstraintToFactor(iter->first, iter->first, (int)iter->second.type()));
} }
} }
else if(id1<0 || id2 < 0) else if(id1<0 || id2 < 0)
@@ -563,7 +655,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
#endif #endif
{ {
graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(t.x(), t.y(), t.theta()), model)); graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(t.x(), t.y(), t.theta()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
else if(1 / static_cast<double>(iter->second.infMatrix().at<double>(1,1)) < 9999) else if(1 / static_cast<double>(iter->second.infMatrix().at<double>(1,1)) < 9999)
@@ -579,7 +671,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::Point2 landmark(t.x(), t.y()); gtsam::Point2 landmark(t.x(), t.y());
gtsam::Pose2 p; gtsam::Pose2 p;
graph.add(gtsam::BearingRangeFactor<gtsam::Pose2, gtsam::Point2>(id1, id2, p.bearing(landmark), p.range(landmark), model)); graph.add(gtsam::BearingRangeFactor<gtsam::Pose2, gtsam::Point2>(id1, id2, p.bearing(landmark), p.range(landmark), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
else else
{ {
@@ -594,7 +686,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::Point2 landmark(t.x(), t.y()); gtsam::Point2 landmark(t.x(), t.y());
gtsam::Pose2 p; gtsam::Pose2 p;
graph.add(gtsam::BearingFactor<gtsam::Pose2, gtsam::Point2>(id1, id2, p.bearing(landmark), model)); graph.add(gtsam::BearingFactor<gtsam::Pose2, gtsam::Point2>(id1, id2, p.bearing(landmark), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
else else
@@ -626,7 +718,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
#endif #endif
{ {
graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(t.toEigen4d()), model)); graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(t.toEigen4d()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
else if(1 / static_cast<double>(iter->second.infMatrix().at<double>(2,2)) < 9999) else if(1 / static_cast<double>(iter->second.infMatrix().at<double>(2,2)) < 9999)
@@ -643,7 +735,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::Point3 landmark(t.x(), t.y(), t.z()); gtsam::Point3 landmark(t.x(), t.y(), t.z());
gtsam::Pose3 p; gtsam::Pose3 p;
graph.add(gtsam::BearingRangeFactor<gtsam::Pose3, gtsam::Point3>(id1, id2, p.bearing(landmark), p.range(landmark), model)); graph.add(gtsam::BearingRangeFactor<gtsam::Pose3, gtsam::Point3>(id1, id2, p.bearing(landmark), p.range(landmark), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
else else
{ {
@@ -659,7 +751,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
gtsam::Point3 landmark(t.x(), t.y(), t.z()); gtsam::Point3 landmark(t.x(), t.y(), t.z());
gtsam::Pose3 p; gtsam::Pose3 p;
graph.add(gtsam::BearingFactor<gtsam::Pose3, gtsam::Point3>(id1, id2, p.bearing(landmark), model)); graph.add(gtsam::BearingFactor<gtsam::Pose3, gtsam::Point3>(id1, id2, p.bearing(landmark), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
} }
@@ -717,7 +809,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
#endif #endif
{ {
graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model)); graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
else else
@@ -747,7 +839,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
#endif #endif
{ {
graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(iter->second.transform().toEigen4d()), model)); graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
lastAddedConstraints_.push_back(ConstraintToFactor(id1, id2, -1)); addedConstraints.push_back(ConstraintToFactor(id1, id2, (int)iter->second.type()));
} }
} }
} }
@@ -870,6 +962,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
{ {
UDEBUG("Update iSAM with the new factors"); UDEBUG("Update iSAM with the new factors");
result = isam2_->update(graph, initialEstimate, removeFactorIndices); result = isam2_->update(graph, initialEstimate, removeFactorIndices);
#if BOOST_VERSION >= 106800 #if BOOST_VERSION >= 106800
UASSERT(result.errorBefore.has_value()); UASSERT(result.errorBefore.has_value());
UASSERT(result.errorAfter.has_value()); UASSERT(result.errorAfter.has_value());
@@ -882,12 +975,26 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
error = result.errorAfter.value(); error = result.errorAfter.value();
if(!this->isRobust()) if(!this->isRobust())
{ {
UASSERT_MSG(lastAddedConstraints_.size() == result.newFactorsIndices.size(), UASSERT_MSG(addedConstraints.size() == result.newFactorsIndices.size(),
uFormat("%ld versus %ld", lastAddedConstraints_.size(), result.newFactorsIndices.size()).c_str()); uFormat("%ld versus %ld", addedConstraints.size(), result.newFactorsIndices.size()).c_str());
for(size_t j=0; j<result.newFactorsIndices.size(); ++j) for(size_t j=0; j<result.newFactorsIndices.size(); ++j)
{ {
UDEBUG("New factor indice: %ld", result.newFactorsIndices[j]); UDEBUG("New factor indice: %ld", result.newFactorsIndices[j]);
lastAddedConstraints_[j].factorIndice = result.newFactorsIndices[j]; // Persist all input-derived factors (including
// self-ref priors / gravity) so later calls can
// remove them when dropped from input or skip
// re-adding when still present. type == -1 marks
// the synthetic root prior, which is managed
// separately via lastRootFactorIndex_ and must
// stay out of trackedFactors_.
if(addedConstraints[j].type != -1)
{
trackedFactors_[linkKey(
addedConstraints[j].from,
addedConstraints[j].to,
addedConstraints[j].type)] =
result.newFactorsIndices[j];
}
} }
} }
if(rootId != 0 && lastRootFactorIndex_.first == 0) if(rootId != 0 && lastRootFactorIndex_.first == 0)
@@ -928,7 +1035,7 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
delete isam2_; delete isam2_;
isam2_ = new gtsam::ISAM2(params); isam2_ = new gtsam::ISAM2(params);
addedPoses_.clear(); addedPoses_.clear();
lastAddedConstraints_.clear(); trackedFactors_.clear();
lastRootFactorIndex_.first = 0; lastRootFactorIndex_.first = 0;
lastSwitchId_ = 1000000000; lastSwitchId_ = 1000000000;
} }
+15 -77
View File
@@ -380,7 +380,7 @@ bool OptimizerTORO::saveGraph(
if(file) if(file)
{ {
for (std::map<int, Transform>::const_iterator iter = poses.lower_bound(0); iter != poses.end(); ++iter) for (std::map<int, Transform>::const_iterator iter = poses.begin(); iter != poses.end(); ++iter)
{ {
if (isSlam2d()) if (isSlam2d())
{ {
@@ -409,7 +409,7 @@ bool OptimizerTORO::saveGraph(
for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter) for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
if (iter->second.from() != iter->second.to() && iter->second.type() != Link::kLandmark) if (iter->second.type() != Link::kPosePrior && iter->second.type() != Link::kGravity)
{ {
if (isSlam2d()) if (isSlam2d())
{ {
@@ -494,31 +494,9 @@ bool OptimizerTORO::loadGraph(
while ( fgets (line , 400 , file) != NULL ) while ( fgets (line , 400 , file) != NULL )
{ {
std::vector<std::string> strList = uListToVector(uSplit(uReplaceChar(line, '\n', ' '), ' ')); std::vector<std::string> strList = uListToVector(uSplit(uReplaceChar(line, '\n', ' '), ' '));
if(strList.empty()) if(strList.size() == 8)
{ {
continue; //VERTEX3
}
const std::string & tag = strList[0];
if(tag.compare("VERTEX2") == 0 && strList.size() == 5)
{
//VERTEX2 id x y theta
int id = atoi(strList[1].c_str());
float x = uStr2Float(strList[2]);
float y = uStr2Float(strList[3]);
float theta = uStr2Float(strList[4]);
Transform pose(x, y, theta);
if(poses.find(id) == poses.end())
{
poses.insert(std::make_pair(id, pose));
}
else
{
UFATAL("Pose %d already added", id);
}
}
else if(tag.compare("VERTEX3") == 0 && strList.size() == 8)
{
//VERTEX3 id x y z roll pitch yaw
int id = atoi(strList[1].c_str()); int id = atoi(strList[1].c_str());
float x = uStr2Float(strList[2]); float x = uStr2Float(strList[2]);
float y = uStr2Float(strList[3]); float y = uStr2Float(strList[3]);
@@ -536,44 +514,9 @@ bool OptimizerTORO::loadGraph(
UFATAL("Pose %d already added", id); UFATAL("Pose %d already added", id);
} }
} }
else if(tag.compare("EDGE2") == 0 && strList.size() == 12) else if(strList.size() == 30)
{ {
//EDGE2 observed_vertex_id observing_vertex_id x y theta inf_11 inf_12 inf_13 inf_22 inf_23 inf_33 //EDGE3
int idFrom = atoi(strList[1].c_str());
int idTo = atoi(strList[2].c_str());
float x = uStr2Float(strList[3]);
float y = uStr2Float(strList[4]);
float theta = uStr2Float(strList[5]);
cv::Mat informationMatrix = cv::Mat::eye(6,6,CV_64FC1);
informationMatrix.at<double>(0,0) = uStr2Float(strList[6]); // x-x
informationMatrix.at<double>(0,1) = uStr2Float(strList[7]); // x-y
informationMatrix.at<double>(0,5) = uStr2Float(strList[8]); // x-theta
informationMatrix.at<double>(1,1) = uStr2Float(strList[9]); // y-y
informationMatrix.at<double>(1,5) = uStr2Float(strList[10]); // y-theta
informationMatrix.at<double>(5,5) = uStr2Float(strList[11]); // theta-theta
// symmetric counterparts
informationMatrix.at<double>(1,0) = informationMatrix.at<double>(0,1);
informationMatrix.at<double>(5,0) = informationMatrix.at<double>(0,5);
informationMatrix.at<double>(5,1) = informationMatrix.at<double>(1,5);
informationMatrix.at<double>(2,2) = 0.00010001; // 9999 cov
informationMatrix.at<double>(3,3) = 0.00010001; // 9999 cov
informationMatrix.at<double>(4,4) = 0.00010001; // 9999 cov
UASSERT_MSG(informationMatrix.at<double>(0,0) > 0.0 && informationMatrix.at<double>(1,1) > 0.0 && informationMatrix.at<double>(5,5) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
Transform transform(x, y, theta);
if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
{
//Link type is unknown
Link link(idFrom, idTo, Link::kUndef, transform, informationMatrix);
edgeConstraints.insert(std::pair<int, Link>(idFrom, link));
}
else
{
UERROR("Referred poses from the link (%d->%d) don't exist! Link ignored!", idFrom, idTo);
}
}
else if(tag.compare("EDGE3") == 0 && strList.size() == 30)
{
//EDGE3 observed_vertex_id observing_vertex_id x y z roll pitch yaw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
int idFrom = atoi(strList[1].c_str()); int idFrom = atoi(strList[1].c_str());
int idTo = atoi(strList[2].c_str()); int idTo = atoi(strList[2].c_str());
float x = uStr2Float(strList[3]); float x = uStr2Float(strList[3]);
@@ -582,20 +525,15 @@ bool OptimizerTORO::loadGraph(
float roll = uStr2Float(strList[6]); float roll = uStr2Float(strList[6]);
float pitch = uStr2Float(strList[7]); float pitch = uStr2Float(strList[7]);
float yaw = uStr2Float(strList[8]); float yaw = uStr2Float(strList[8]);
// upper triangle is stored row by row (same order as saveGraph)
cv::Mat informationMatrix(6,6,CV_64FC1); cv::Mat informationMatrix(6,6,CV_64FC1);
int index = 9; informationMatrix.at<double>(3,3) = uStr2Float(strList[9]);
for(int i=0; i<6; ++i) informationMatrix.at<double>(4,4) = uStr2Float(strList[15]);
{ informationMatrix.at<double>(5,5) = uStr2Float(strList[20]);
for(int j=i; j<6; ++j) UASSERT_MSG(informationMatrix.at<double>(3,3) > 0.0 && informationMatrix.at<double>(4,4) > 0.0 && informationMatrix.at<double>(5,5) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
{ informationMatrix.at<double>(0,0) = uStr2Float(strList[24]);
double value = uStr2Float(strList[index++]); informationMatrix.at<double>(1,1) = uStr2Float(strList[27]);
informationMatrix.at<double>(i,j) = value; informationMatrix.at<double>(2,2) = uStr2Float(strList[29]);
informationMatrix.at<double>(j,i) = value; UASSERT_MSG(informationMatrix.at<double>(0,0) > 0.0 && informationMatrix.at<double>(1,1) > 0.0 && informationMatrix.at<double>(2,2) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
}
}
UASSERT_MSG(informationMatrix.at<double>(0,0) > 0.0 && informationMatrix.at<double>(1,1) > 0.0 && informationMatrix.at<double>(2,2) > 0.0 &&
informationMatrix.at<double>(3,3) > 0.0 && informationMatrix.at<double>(4,4) > 0.0 && informationMatrix.at<double>(5,5) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
Transform transform(x, y, z, roll, pitch, yaw); Transform transform(x, y, z, roll, pitch, yaw);
if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end()) if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
{ {
@@ -608,7 +546,7 @@ bool OptimizerTORO::loadGraph(
UERROR("Referred poses from the link (%d->%d) don't exist! Link ignored!", idFrom, idTo); UERROR("Referred poses from the link (%d->%d) don't exist! Link ignored!", idFrom, idTo);
} }
} }
else else if(strList.size())
{ {
UFATAL("Error parsing graph file %s on line \"%s\" (strList.size()=%d)", fileName.c_str(), line, (int)strList.size()); UFATAL("Error parsing graph file %s on line \"%s\" (strList.size()=%d)", fileName.c_str(), line, (int)strList.size());
} }
+8 -28
View File
@@ -202,30 +202,18 @@ std::vector<cv::KeyPoint> PyDetector::generateKeypointsImpl(const cv::Mat & imag
arrayPtr = reinterpret_cast<PyArrayObject*>(descPtr); arrayPtr = reinterpret_cast<PyArrayObject*>(descPtr);
int nDesc = PyArray_SHAPE(arrayPtr)[0]; int nDesc = PyArray_SHAPE(arrayPtr)[0];
UASSERT(nDesc = nKpts);
int dim = PyArray_SHAPE(arrayPtr)[1]; int dim = PyArray_SHAPE(arrayPtr)[1];
type = PyArray_TYPE(arrayPtr); type = PyArray_TYPE(arrayPtr);
UDEBUG("Desc array %dx%d (type=%d)", nDesc, dim, type); UDEBUG("Desc array %dx%d (type=%d)", nDesc, dim, type);
UASSERT_MSG(type == NPY_FLOAT, uFormat("Returned matches should type FLOAT=11, received type=%d", type).c_str());
if(nDesc != nKpts || dim <= 0) c_out = reinterpret_cast<float*>(PyArray_DATA(arrayPtr));
for (int i = 0, kpt_idx = 0; i < nDesc*dim; i+=dim, kpt_idx++)
{ {
UWARN("Python detector returned mismatched arrays: " if(keep_kpt[kpt_idx]) {
"%d keypoints vs %d descriptors (dim=%d). " cv::Mat descriptor = cv::Mat(1, dim, CV_32FC1, &c_out[i]).clone();
"Returning empty features.", descriptors_.push_back(descriptor);
nKpts, nDesc, dim);
keypoints.clear();
descriptors_ = cv::Mat();
}
else
{
UASSERT_MSG(type == NPY_FLOAT, uFormat("Returned matches should type FLOAT=11, received type=%d", type).c_str());
c_out = reinterpret_cast<float*>(PyArray_DATA(arrayPtr));
for (int i = 0, kpt_idx = 0; i < nDesc*dim; i+=dim, kpt_idx++)
{
if(keep_kpt[kpt_idx]) {
cv::Mat descriptor = cv::Mat(1, dim, CV_32FC1, &c_out[i]).clone();
descriptors_.push_back(descriptor);
}
} }
} }
} }
@@ -247,15 +235,7 @@ std::vector<cv::KeyPoint> PyDetector::generateKeypointsImpl(const cv::Mat & imag
cv::Mat PyDetector::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const cv::Mat PyDetector::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{ {
if(!keypoints.empty() && (int)keypoints.size() != descriptors_.rows) UASSERT((int)keypoints.size() == descriptors_.rows);
{
UERROR("The number of keypoints (%ld) doesn't match the number of buffered "
"descriptors (%d). PyDetector's descriptors extraction should "
"be called right after keypoints detection, with same keypoints "
"returned by the detection. Returning empty descriptors.",
keypoints.size(), descriptors_.rows);
return cv::Mat();
}
return descriptors_; return descriptors_;
} }
@@ -130,7 +130,7 @@ cv::Mat SPDetectorRpautrat::compute(const std::vector<cv::KeyPoint> &keypoints)
{ {
if(!detected_) if(!detected_)
{ {
UERROR("SPDetectorRpautrat has been reset before extracting the descriptors! detect() should be called before compute()."); UERROR("SPDetector has been reset before extracting the descriptors! detect() should be called before compute().");
return cv::Mat(); return cv::Mat();
} }
if(keypoints.empty()) if(keypoints.empty())
+3 -8
View File
@@ -144,12 +144,7 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
UASSERT(img.type() == CV_8UC1); UASSERT(img.type() == CV_8UC1);
UASSERT(mask.empty() || (mask.type() == CV_8UC1 && img.cols == mask.cols && img.rows == mask.rows)); UASSERT(mask.empty() || (mask.type() == CV_8UC1 && img.cols == mask.cols && img.rows == mask.rows));
detected_ = false; detected_ = false;
if(!model_) if(model_)
{
UERROR("No model is loaded!");
return std::vector<cv::KeyPoint>();
}
try
{ {
torch::NoGradGuard no_grad_guard; torch::NoGradGuard no_grad_guard;
auto x = torch::from_blob(img.data, {1, 1, img.rows, img.cols}, torch::kByte); auto x = torch::from_blob(img.data, {1, 1, img.rows, img.cols}, torch::kByte);
@@ -204,9 +199,9 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
detected_ = true; detected_ = true;
return keypoints; return keypoints;
} }
catch(const std::exception & e) else
{ {
UERROR("SPDetector::detect() threw: %s", e.what()); UERROR("No model is loaded!");
return std::vector<cv::KeyPoint>(); return std::vector<cv::KeyPoint>();
} }
} }
-20
View File
@@ -1,20 +0,0 @@
# Image: introlab3it/rtabmap:resolute
FROM introlab3it/rtabmap:resolute-deps
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map && chmod 777 /root/Documents/RTAB-Map
# Copy current source code
COPY . /root/rtabmap
# Build RTAB-Map project
RUN source /ros_entrypoint.sh && \
cd rtabmap/build && \
cmake -DWITH_OPENGV=ON .. && \
make -j4 && \
make install && \
cd ../.. && \
rm -rf rtabmap && \
ldconfig
-121
View File
@@ -1,121 +0,0 @@
# Image: introlab3it/rtabmap:resolute-deps
FROM ubuntu:26.04
ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
RUN echo "I am building for $TARGETPLATFORM"
ENV DEBIAN_FRONTEND=noninteractive
# Install ROS2
RUN apt update && \
apt install software-properties-common -y && \
add-apt-repository universe && \
apt update && \
apt install curl -y && \
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null && \
apt-get clean && rm -rf /var/lib/apt/lists/
# Install build dependencies
RUN apt-get update && \
apt upgrade -y && \
apt-get install -y \
git \
wget \
libtbb-dev \
libproj-dev \
libpcl-dev \
liboctomap-dev \
libfreenect-dev \
libceres-dev \
ros-lyrical-ros-base \
ros-dev-tools \
ros-lyrical-cv-bridge \
ros-lyrical-image-geometry \
ros-lyrical-laser-geometry \
ros-lyrical-pcl-conversions \
ros-lyrical-rviz-common \
ros-lyrical-rviz-rendering \
ros-lyrical-rviz-default-plugins \
ros-lyrical-pcl-ros \
ros-lyrical-imu-filter-madgwick \
ros-lyrical-image-transport \
ros-lyrical-octomap-msgs \
ros-lyrical-libg2o \
ros-lyrical-gtsam \
ros-lyrical-qt-gui-cpp \
ros-lyrical-diagnostic-updater && \
apt-get clean && rm -rf /var/lib/apt/lists/
WORKDIR /root/
# 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 && \
apt-get clean && rm -rf /var/lib/apt/lists/ && \
git clone https://github.com/OpenKinect/libfreenect2 && \
cd libfreenect2 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. && \
make -j4 && \
make install && \
cd && \
rm -r libfreenect2; fi
# zed open capture
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing zed-open-capture..." && \
apt-get update && apt install -y libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev wget && \
apt-get clean && rm -rf /var/lib/apt/lists/ && \
git clone https://github.com/stereolabs/zed-open-capture.git && \
cd zed-open-capture && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. && \
make -j4 && \
make install && \
cd && \
rm -r zed-open-capture; fi
# OpenCV with all modules (same version than distro version to avoid conflicts with cv_bridge ros package)
RUN git clone --branch 4.10.0 https://github.com/opencv/opencv.git && \
git clone --branch 4.10.0 https://github.com/opencv/opencv_contrib.git && \
cd opencv && \
# FFmpeg 7/8 compatibility (Ubuntu 26.04): avcodec_close / av_stream_get_side_data removed
git -c user.email=docker@build -c user.name=docker cherry-pick -x 90c444abd387ffa70b2e72a34922903a2f0f4f5a 443d0ae63fad6dfd8c485d609203db16c8bd0ec3 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TBB=ON -DWITH_ADE=OFF -DWITH_OPENMP=ON -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
make -j4 && \
make install && \
cd ../.. && \
rm -rf opencv opencv_contrib
RUN git clone https://github.com/laurentkneip/opengv.git && \
cd opengv && \
git checkout 91f4b19c73450833a40e463ad3648aae80b3a7f3 && \
wget https://gist.githubusercontent.com/matlabbe/a412cf7c4627253874f81a00745a7fbb/raw/accc3acf465d1ffd0304a46b17741f62d4d354ef/opengv_disable_march_native.patch && \
git apply opengv_disable_march_native.patch && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. && \
make -j4 && \
make install && \
cd && \
rm -r opengv
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
RUN echo -e '#!/bin/bash\nset -e\n\n# setup ros2 environment\nsource "/opt/ros/lyrical/setup.bash" --\nexec "$@"' > /ros_entrypoint.sh
RUN chmod +x /ros_entrypoint.sh
ENTRYPOINT [ "/ros_entrypoint.sh" ]
# ros2 seems not sourcing by default its multi-arch folders
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/ros/lyrical/lib/x86_64-linux-gnu:/opt/ros/lyrical/lib/aarch64-linux-gnu
# for jetson (https://github.com/introlab/rtabmap/issues/776)
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/aarch64-linux-gnu/tegra
@@ -372,7 +372,6 @@ private Q_SLOTS:
void changeOdometryORBSLAMVocabulary(); void changeOdometryORBSLAMVocabulary();
void changeOdometryOKVISConfigPath(); void changeOdometryOKVISConfigPath();
void changeOdometryVINSFusionConfigPath(); void changeOdometryVINSFusionConfigPath();
void changeOdometryOpenVINSConfigPath();
void changeOdometryLIOSAMConfigPath(); void changeOdometryLIOSAMConfigPath();
void changeOdometryOpenVINSLeftMask(); void changeOdometryOpenVINSLeftMask();
void changeOdometryOpenVINSRightMask(); void changeOdometryOpenVINSRightMask();
-19
View File
@@ -1617,8 +1617,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->toolButton_OdomVinsFusionPath, SIGNAL(clicked()), this, SLOT(changeOdometryVINSFusionConfigPath())); connect(_ui->toolButton_OdomVinsFusionPath, SIGNAL(clicked()), this, SLOT(changeOdometryVINSFusionConfigPath()));
// Odometry OpenVINS // Odometry OpenVINS
_ui->lineEdit_openvinsConfigPath->setObjectName(Parameters::kOdomOpenVINSConfigPath().c_str());
connect(_ui->toolButton_openvinsConfigPath, SIGNAL(clicked()), this, SLOT(changeOdometryOpenVINSConfigPath()));
_ui->checkBox_OdomOpenVINSUseStereo->setObjectName(Parameters::kOdomOpenVINSUseStereo().c_str()); _ui->checkBox_OdomOpenVINSUseStereo->setObjectName(Parameters::kOdomOpenVINSUseStereo().c_str());
_ui->checkBox_OdomOpenVINSUseKLT->setObjectName(Parameters::kOdomOpenVINSUseKLT().c_str()); _ui->checkBox_OdomOpenVINSUseKLT->setObjectName(Parameters::kOdomOpenVINSUseKLT().c_str());
_ui->spinBox_OdomOpenVINSNumPts->setObjectName(Parameters::kOdomOpenVINSNumPts().c_str()); _ui->spinBox_OdomOpenVINSNumPts->setObjectName(Parameters::kOdomOpenVINSNumPts().c_str());
@@ -5794,23 +5792,6 @@ void PreferencesDialog::changeOdometryVINSFusionConfigPath()
} }
} }
void PreferencesDialog::changeOdometryOpenVINSConfigPath()
{
QString path;
if(_ui->lineEdit_openvinsConfigPath->text().isEmpty())
{
path = QFileDialog::getOpenFileName(this, tr("OpenVINS Config"), this->getWorkingDirectory(), tr("OpenVINS config (*.yaml)"));
}
else
{
path = QFileDialog::getOpenFileName(this, tr("OpenVINS Config"), _ui->lineEdit_openvinsConfigPath->text(), tr("OpenVINS config (*.yaml)"));
}
if(!path.isEmpty())
{
_ui->lineEdit_openvinsConfigPath->setText(path);
}
}
void PreferencesDialog::changeOdometryLIOSAMConfigPath() void PreferencesDialog::changeOdometryLIOSAMConfigPath()
{ {
QString path; QString path;
+59 -86
View File
@@ -63,7 +63,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-648</y> <y>0</y>
<width>684</width> <width>684</width>
<height>5218</height> <height>5218</height>
</rect> </rect>
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>19</number> <number>18</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0">
@@ -16763,7 +16763,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item> <item>
<widget class="QStackedWidget" name="stackedWidget_odometryType"> <widget class="QStackedWidget" name="stackedWidget_odometryType">
<property name="currentIndex"> <property name="currentIndex">
<number>10</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="page_52"> <widget class="QWidget" name="page_52">
<layout class="QVBoxLayout" name="verticalLayout_77"> <layout class="QVBoxLayout" name="verticalLayout_77">
@@ -20388,7 +20388,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<property name="title"> <property name="title">
<string>OpenVINS</string> <string>OpenVINS</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_161"> <layout class="QVBoxLayout" name="verticalLayout_161" stretch="0,0,0,0,0,0">
<item> <item>
<widget class="QLabel" name="label_632"> <widget class="QLabel" name="label_632">
<property name="text"> <property name="text">
@@ -20405,33 +20405,6 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_19" stretch="0,0,1">
<item>
<widget class="QToolButton" name="toolButton_openvinsConfigPath">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_openvinsConfigPath"/>
</item>
<item>
<widget class="QLabel" name="label_796">
<property name="text">
<string>Configuration file (*.yaml). Same format used than OpenVINS library. Note that any parameter from that config file will overwrite the same parameter below.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_36"> <widget class="QGroupBox" name="groupBox_36">
<property name="title"> <property name="title">
@@ -20448,7 +20421,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_682"> <widget class="QLabel" name="label_682">
<property name="text"> <property name="text">
<string>Stereo mode. If we should process two cameras are being stereo or binocular. If binocular, we do monocular feature tracking on each image. Ignored if provided input data is not stereo.</string> <string>If we should process two cameras are being stereo or binocular. If binocular, we do monocular feature tracking on each image.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20468,7 +20441,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_683"> <widget class="QLabel" name="label_683">
<property name="text"> <property name="text">
<string>KLT tracking. Uncheck to use descriptor matcher.</string> <string>If we should use KLT tracking, or descriptor matcher</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20494,7 +20467,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_684"> <widget class="QLabel" name="label_684">
<property name="text"> <property name="text">
<string>Number of points (per camera) we will extract and try to track.</string> <string>Number of points (per camera) we will extract and try to track</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20517,7 +20490,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_688"> <widget class="QLabel" name="label_688">
<property name="text"> <property name="text">
<string>Minimum pixel distance. Will check after doing KLT track and remove any features closer than this.</string> <string>Will check after doing KLT track and remove any features closer than this</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20537,7 +20510,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_689"> <widget class="QLabel" name="label_689">
<property name="text"> <property name="text">
<string>If we should perform 1d triangulation instead of 3d.</string> <string>If we should perform 1d triangulation instead of 3d</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20557,7 +20530,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_732"> <widget class="QLabel" name="label_732">
<property name="text"> <property name="text">
<string>If we should perform Levenberg-Marquardt refinement.</string> <string>If we should perform Levenberg-Marquardt refinement</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20580,7 +20553,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_733"> <widget class="QLabel" name="label_733">
<property name="text"> <property name="text">
<string>Max runs for Levenberg-Marquardt.</string> <string>Max runs for Levenberg-Marquardt</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20606,7 +20579,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_734"> <widget class="QLabel" name="label_734">
<property name="text"> <property name="text">
<string>Max baseline ratio to accept triangulated features.</string> <string>Max baseline ratio to accept triangulated features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20632,7 +20605,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="8" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_735"> <widget class="QLabel" name="label_735">
<property name="text"> <property name="text">
<string>Max condition number of linear triangulation matrix accept triangulated features.</string> <string>Max condition number of linear triangulation matrix accept triangulated features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20661,7 +20634,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_690"> <widget class="QLabel" name="label_690">
<property name="text"> <property name="text">
<string>If first-estimate Jacobians should be used (enable for good consistency).</string> <string>If first-estimate Jacobians should be used (enable for good consistency)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20699,7 +20672,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_691"> <widget class="QLabel" name="label_691">
<property name="text"> <property name="text">
<string>Numerical integration methods.</string> <string>Numerical integration methods</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20719,7 +20692,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_685"> <widget class="QLabel" name="label_685">
<property name="text"> <property name="text">
<string>If the transform between camera and IMU should be optimized (R_ItoC, p_CinI).</string> <string>If the transform between camera and IMU should be optimized (R_ItoC, p_CinI)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20739,7 +20712,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_686"> <widget class="QLabel" name="label_686">
<property name="text"> <property name="text">
<string>If camera intrinsics should be optimized (focal, center, distortion).</string> <string>If camera intrinsics should be optimized (focal, center, distortion)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20759,7 +20732,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_687"> <widget class="QLabel" name="label_687">
<property name="text"> <property name="text">
<string>If timeoffset between camera and IMU should be optimized.</string> <string>If timeoffset between camera and IMU should be optimized</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20779,7 +20752,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_718"> <widget class="QLabel" name="label_718">
<property name="text"> <property name="text">
<string>If imu intrinsics should be calibrated (rotation and skew-scale matrix).</string> <string>If imu intrinsics should be calibrated (rotation and skew-scale matrix)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20799,7 +20772,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_719"> <widget class="QLabel" name="label_719">
<property name="text"> <property name="text">
<string>If gyroscope gravity sensitivity (Tg) should be calibrated.</string> <string>If gyroscope gravity sensitivity (Tg) should be calibrated</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20822,7 +20795,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_692"> <widget class="QLabel" name="label_692">
<property name="text"> <property name="text">
<string>Max clone size of sliding window.</string> <string>Max clone size of sliding window</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20848,7 +20821,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="8" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_693"> <widget class="QLabel" name="label_693">
<property name="text"> <property name="text">
<string>Max number of estimated SLAM features.</string> <string>Max number of estimated SLAM features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20953,7 +20926,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="11" column="1"> <item row="11" column="1">
<widget class="QLabel" name="label_696"> <widget class="QLabel" name="label_696">
<property name="text"> <property name="text">
<string>What representation our features are in (msckf features).</string> <string>What representation our features are in (msckf features)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -20969,7 +20942,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<number>4</number> <number>4</number>
</property> </property>
<property name="sizeAdjustPolicy"> <property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum> <enum>QComboBox::AdjustToContents</enum>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
@@ -21006,7 +20979,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="12" column="1"> <item row="12" column="1">
<widget class="QLabel" name="label_697"> <widget class="QLabel" name="label_697">
<property name="text"> <property name="text">
<string>What representation our features are in (slam features).</string> <string>What representation our features are in (slam features)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21035,7 +21008,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="13" column="1"> <item row="13" column="1">
<widget class="QLabel" name="label_698"> <widget class="QLabel" name="label_698">
<property name="text"> <property name="text">
<string>Delay before initializing (helps with stability from bad initialization...).</string> <string>Delay before initializing (helps with stability from bad initialization...)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21061,7 +21034,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="14" column="1"> <item row="14" column="1">
<widget class="QLabel" name="label_699"> <widget class="QLabel" name="label_699">
<property name="text"> <property name="text">
<string>Magnitude of gravity in this location.</string> <string>Magnitude of gravity in this location</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21088,7 +21061,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="15" column="1"> <item row="15" column="1">
<widget class="QLabel" name="label_736"> <widget class="QLabel" name="label_736">
<property name="text"> <property name="text">
<string>Mask for left image (stereo mode) or mono image (RGB-D mode). For RGB-D mode, to use depth as mask, enable that option under Visual Registration panel.</string> <string>Mask for left image</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21115,7 +21088,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="16" column="1"> <item row="16" column="1">
<widget class="QLabel" name="label_737"> <widget class="QLabel" name="label_737">
<property name="text"> <property name="text">
<string>Mask for right image.</string> <string>Mask for right image</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21153,7 +21126,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_700"> <widget class="QLabel" name="label_700">
<property name="text"> <property name="text">
<string>Amount of time we will initialize over.</string> <string>Amount of time we will initialize over</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21182,7 +21155,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_701"> <widget class="QLabel" name="label_701">
<property name="text"> <property name="text">
<string>Variance threshold on our acceleration to be classified as moving.</string> <string>Variance threshold on our acceleration to be classified as moving</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21208,7 +21181,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_702"> <widget class="QLabel" name="label_702">
<property name="text"> <property name="text">
<string>Max disparity to consider the platform stationary (dependent on resolution).</string> <string>Max disparity to consider the platform stationary (dependent on resolution)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21234,7 +21207,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_703"> <widget class="QLabel" name="label_703">
<property name="text"> <property name="text">
<string>How many features to track during initialization (saves on computation).</string> <string>How many features to track during initialization (saves on computation)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21254,7 +21227,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_720"> <widget class="QLabel" name="label_720">
<property name="text"> <property name="text">
<string>If we should perform dynamic initialization.</string> <string>If we should perform dynamic initialization</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21274,7 +21247,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_721"> <widget class="QLabel" name="label_721">
<property name="text"> <property name="text">
<string>If we should optimize and recover the calibration in our MLE.</string> <string>If we should optimize and recover the calibration in our MLE</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21297,7 +21270,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_722"> <widget class="QLabel" name="label_722">
<property name="text"> <property name="text">
<string>Max number of MLE iterations for dynamic initialization.</string> <string>Max number of MLE iterations for dynamic initialization</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21326,7 +21299,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_723"> <widget class="QLabel" name="label_723">
<property name="text"> <property name="text">
<string>Max time for MLE optimization.</string> <string>Max time for MLE optimization</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21349,7 +21322,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="8" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_724"> <widget class="QLabel" name="label_724">
<property name="text"> <property name="text">
<string>Max number of MLE threads for dynamic initialization.</string> <string>Max number of MLE threads for dynamic initialization</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21372,7 +21345,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="9" column="1"> <item row="9" column="1">
<widget class="QLabel" name="label_725"> <widget class="QLabel" name="label_725">
<property name="text"> <property name="text">
<string>Number of poses to use during initialization (max should be cam freq * window).</string> <string>Number of poses to use during initialization (max should be cam freq * window)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21401,7 +21374,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="10" column="1"> <item row="10" column="1">
<widget class="QLabel" name="label_726"> <widget class="QLabel" name="label_726">
<property name="text"> <property name="text">
<string>Minimum degrees we need to rotate before we try to init (sum of norm).</string> <string>Minimum degrees we need to rotate before we try to init (sum of norm)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21427,7 +21400,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="11" column="1"> <item row="11" column="1">
<widget class="QLabel" name="label_727"> <widget class="QLabel" name="label_727">
<property name="text"> <property name="text">
<string>Magnitude we will inflate initial covariance of orientation.</string> <string>Magnitude we will inflate initial covariance of orientation</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21453,7 +21426,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="12" column="1"> <item row="12" column="1">
<widget class="QLabel" name="label_728"> <widget class="QLabel" name="label_728">
<property name="text"> <property name="text">
<string>Magnitude we will inflate initial covariance of velocity.</string> <string>Magnitude we will inflate initial covariance of velocity</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21479,7 +21452,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="13" column="1"> <item row="13" column="1">
<widget class="QLabel" name="label_729"> <widget class="QLabel" name="label_729">
<property name="text"> <property name="text">
<string>Magnitude we will inflate initial covariance of gyroscope bias.</string> <string>Magnitude we will inflate initial covariance of gyroscope bias</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21505,7 +21478,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="14" column="1"> <item row="14" column="1">
<widget class="QLabel" name="label_730"> <widget class="QLabel" name="label_730">
<property name="text"> <property name="text">
<string>Magnitude we will inflate initial covariance of accelerometer bias.</string> <string>Magnitude we will inflate initial covariance of accelerometer bias</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21534,7 +21507,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="15" column="1"> <item row="15" column="1">
<widget class="QLabel" name="label_731"> <widget class="QLabel" name="label_731">
<property name="text"> <property name="text">
<string>Minimum reciprocal condition number acceptable for our covariance recovery.</string> <string>Minimum reciprocal condition number acceptable for our covariance recovery</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21563,7 +21536,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_704"> <widget class="QLabel" name="label_704">
<property name="text"> <property name="text">
<string>If we should try to use zero velocity update.</string> <string>If we should try to use zero velocity update</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21592,7 +21565,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_705"> <widget class="QLabel" name="label_705">
<property name="text"> <property name="text">
<string>Chi2 multiplier for zero velocity.</string> <string>Chi2 multiplier for zero velocity</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21621,7 +21594,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_706"> <widget class="QLabel" name="label_706">
<property name="text"> <property name="text">
<string>Max velocity we will consider to try to do a zupt (i.e. if above this, don't do zupt).</string> <string>Max velocity we will consider to try to do a zupt (i.e. if above this, don't do zupt)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21650,7 +21623,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_707"> <widget class="QLabel" name="label_707">
<property name="text"> <property name="text">
<string>Multiplier of our zupt measurement IMU noise matrix (default should be 1.0).</string> <string>Multiplier of our zupt measurement IMU noise matrix (default should be 1.0)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21679,7 +21652,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_708"> <widget class="QLabel" name="label_708">
<property name="text"> <property name="text">
<string>Max disparity we will consider to try to do a zupt (i.e. if above this, don't do zupt).</string> <string>Max disparity we will consider to try to do a zupt (i.e. if above this, don't do zupt)</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21699,7 +21672,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_709"> <widget class="QLabel" name="label_709">
<property name="text"> <property name="text">
<string>If we should only use the zupt at the very beginning static initialization phase.</string> <string>If we should only use the zupt at the very beginning static initialization phase</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21740,7 +21713,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_710"> <widget class="QLabel" name="label_710">
<property name="text"> <property name="text">
<string>Accel &quot;white noise&quot;.</string> <string>Accel &quot;white noise&quot;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21772,7 +21745,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_711"> <widget class="QLabel" name="label_711">
<property name="text"> <property name="text">
<string>Accel bias diffusion.</string> <string>Accel bias diffusion</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21804,7 +21777,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_712"> <widget class="QLabel" name="label_712">
<property name="text"> <property name="text">
<string>Gyro &quot;white noise&quot;.</string> <string>Gyro &quot;white noise&quot;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21836,7 +21809,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_713"> <widget class="QLabel" name="label_713">
<property name="text"> <property name="text">
<string>Gyro bias diffusion.</string> <string>Gyro bias diffusion</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21865,7 +21838,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_714"> <widget class="QLabel" name="label_714">
<property name="text"> <property name="text">
<string>Pixel noise for MSCKF features.</string> <string>Pixel noise for MSCKF features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21894,7 +21867,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_715"> <widget class="QLabel" name="label_715">
<property name="text"> <property name="text">
<string>Chi2 multiplier for MSCKF features.</string> <string>Chi2 multiplier for MSCKF features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21923,7 +21896,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_716"> <widget class="QLabel" name="label_716">
<property name="text"> <property name="text">
<string>Pixel noise for SLAM features.</string> <string>Pixel noise for SLAM features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -21952,7 +21925,7 @@ With &lt;0, the length is estimated once for each unique marker, then re-used fo
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_717"> <widget class="QLabel" name="label_717">
<property name="text"> <property name="text">
<string>Chi2 multiplier for SLAM features.</string> <string>Chi2 multiplier for SLAM features</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package format="2"> <package format="2">
<name>rtabmap</name> <name>rtabmap</name>
<version>0.23.7</version> <version>0.23.5</version>
<description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description> <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> <maintainer email="matlabbe@gmail.com">Mathieu Labbe</maintainer>
<author>Mathieu Labbe</author> <author>Mathieu Labbe</author>
-11
View File
@@ -82,7 +82,6 @@ void showUsage()
" -stop # Last node to process.\n" " -stop # Last node to process.\n"
" -start_s # Start from this map session ID.\n" " -start_s # Start from this map session ID.\n"
" -stop_s # Last map session to process.\n" " -stop_s # Last map session to process.\n"
" -stop_loop Stop after the first loop closure is detected.\n"
" -a Append mode: if Mem/IncrementalMemory is true, RTAB-Map is initialized with the first input database,\n" " -a Append mode: if Mem/IncrementalMemory is true, RTAB-Map is initialized with the first input database,\n"
" then next databases are reprocessed on top of the first one.\n" " then next databases are reprocessed on top of the first one.\n"
" -cam # Camera index to stream. Ignored if a database doesn't contain multi-camera data. Can also be multiple \n" " -cam # Camera index to stream. Ignored if a database doesn't contain multi-camera data. Can also be multiple \n"
@@ -272,7 +271,6 @@ int main(int argc, char * argv[])
int stopId = 0; int stopId = 0;
int startMapId = 0; int startMapId = 0;
int stopMapId = -1; int stopMapId = -1;
bool stopOnLoopClosure = false;
bool appendMode = false; bool appendMode = false;
std::vector<unsigned int> cameraIndices; std::vector<unsigned int> cameraIndices;
std::vector<Transform> cameraLocalTransformOverrides; std::vector<Transform> cameraLocalTransformOverrides;
@@ -421,10 +419,6 @@ int main(int argc, char * argv[])
showUsage(); showUsage();
} }
} }
else if(strcmp(argv[i], "-stop_loop") == 0 || strcmp(argv[i], "--stop_loop") == 0)
{
stopOnLoopClosure = true;
}
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--a") == 0) else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--a") == 0)
{ {
appendMode = true; appendMode = true;
@@ -1294,11 +1288,6 @@ int main(int argc, char * argv[])
++loopIntra; ++loopIntra;
} }
printf("[%f] Processed %d/%d nodes [id=%d map=%d graph=%d hyp=%d]... %dms %s on %d [%d]\n", data.stamp(), ++processed, totalIds, refId, refMapId, int(stats.poses().size()), int(uValue(stats.data(), Statistics::kLoopHighest_hypothesis_value())*100.0f), int(iterationTime.ticks() * 1000), stats.loopClosureId() > 0?"Loop":"Prox", loopId, loopMapId); printf("[%f] Processed %d/%d nodes [id=%d map=%d graph=%d hyp=%d]... %dms %s on %d [%d]\n", data.stamp(), ++processed, totalIds, refId, refMapId, int(stats.poses().size()), int(uValue(stats.data(), Statistics::kLoopHighest_hypothesis_value())*100.0f), int(iterationTime.ticks() * 1000), stats.loopClosureId() > 0?"Loop":"Prox", loopId, loopMapId);
if(stopOnLoopClosure)
{
printf("First loop closure has been detected and --stop_loop option is enabled, stop processing...\n");
break;
}
} }
else if(landmarkId != 0) else if(landmarkId != 0)
{ {