Compare commits

..

109 Commits

Author SHA1 Message Date
matlabbe
24ca56248f bump patch 2024-07-22 20:47:59 -07:00
matlabbe
0efd3c6b62 Merge branch 'clalancette-clalancette/switch-octomap-dependency' 2024-07-22 20:44:51 -07:00
matlabbe
49d67302d5 removed jazzy/rolling specific patches 2024-07-22 20:41:05 -07:00
matlabbe
41dcddc48e Merge branch 'clalancette/switch-octomap-dependency' of https://github.com/clalancette/rtabmap into clalancette-clalancette/switch-octomap-dependency 2024-07-22 20:39:56 -07:00
Chris Lalancette
ccca53be03 Switch the octomap dependency to the system version.
We are shortly going to be removing octomap the package
from ROS 2 Rolling; that's because it's ABI conflicts with
the system package.  Instead, switch rtabmap to use the system
package, which should work fine.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-07-22 19:25:27 +00:00
matlabbe
08a44ec44f DBViewer: added option to ignore optimized graph guess when detecting more loop closures 2024-07-19 14:02:03 -07:00
matlabbe
41fe47efdf Fixed build with OpenCV 3.2 (ubuntu bionic). Added more devcontainers for different ubuntu versions for convenience. 2024-06-30 19:11:14 -07:00
matlabbe
7641f28250 Fixed build with OpenCV >= 4.7 (charucoboard errors) 2024-06-30 18:15:56 -07:00
matlabbe
f5a477f0f4 Charuco calibration + depthai calibration support (#1302)
* In progress: adding charuco option

* DepthAI: added raw image publishing mode (added support rtabmap's calibration file). Calibration: working charuco board calibration (on opencv 4.5).

* fixed build with Qt<5.14

* Updated calibration options

* Removed depthai flashing delays

* depthai: fixed camera not detected as calibrated in Mono-depth mode. Calibration: added option to scale sampling factor.
2024-06-30 17:11:37 -07:00
matlabbe
2fbe31f7cb Split dev containers for standalone and android 2024-06-28 08:08:40 -07:00
matlabbe
623d056436 fixed android build 2024-06-26 05:43:17 +00:00
matlabbe
1611aa14f6 fixed typo 2024-06-25 13:21:02 -07:00
matlabbe
7d970ef020 Fixed DBReader odometry ignored 2024-06-25 12:04:37 -07:00
matlabbe
1ab0133f14 Added uPad function for convenience 2024-06-19 15:58:24 -07:00
matlabbe
4c1822683a Added new parameter: RGBD/AggressiveLoopThr 2024-06-19 10:28:17 -07:00
matlabbe
7c601bb6e8 Fixed #1300 (proximity sort by distance) 2024-06-16 11:11:39 -07:00
matlabbe
0d221a806f Update behavior of Odom/AlignWithGround when odmetry is already aligned with gravity (just update z value). 2024-06-15 17:24:00 -07:00
matlabbe
28fd696c18 Fixed WITH_QT=OFF (to not build with Qt even if any dependency included it) 2024-06-15 14:21:51 -07:00
Adam Serafin
c58fffe56d Add flags for OpenNI (#1299)
* update openni defines

* minor fix

* fixed build + minor changes

---------

Co-authored-by: matlabbe <matlabbe@gmail.com>
2024-06-15 14:12:07 -07:00
matlabbe
2a840fe340 Fixed https://github.com/introlab/rtabmap_ros/issues/1173 (edited optimized map regenerated in localization mode) 2024-06-09 20:46:51 -07:00
matlabbe
0f03db9d7f Disabling temporary cmake-ros workflow on ubuntu 24.04/jazzy because of setup-ros failing on that base image 2024-06-09 11:36:49 -07:00
matlabbe
4349f304d2 Merge branch 'borongyuan-xvisio' 2024-06-09 11:13:51 -07:00
matlabbe
80a4ce02c9 Fixed build without xvisio sdk, Added xvisio camera option in main menu. 2024-06-09 11:13:29 -07:00
matlabbe
b37f7d6351 docker: Fixed typo 2024-06-09 10:20:18 -07:00
matlabbe
35d4bd768c ci/noble: moved opengv to top image to be built on ci 2024-06-09 10:20:18 -07:00
matlabbe
e6691658bd Fixed compilation warnings on 22.04 (Qt 5.15.3) 2024-06-09 10:20:18 -07:00
matlabbe
3cfcccdb1d Added CI for Ubuntu Noble/24.04 + docker 2024-06-09 10:20:18 -07:00
matlabbe
8310925c81 Calibration tool: added support for rational model (8 coeff) 2024-06-09 10:20:18 -07:00
matlabbe
99cb02fdff ORB_SLAM3: fixed error if left image is color. SensorCaptureThread: stop thread if data cannot be captured (e.g., end of dataset) instead of skipping indefinitly with error log. 2024-06-09 10:20:18 -07:00
matlabbe
8b372b52ac arcore_java: fixed high speed filtering jumping (#1281) 2024-06-09 10:20:18 -07:00
matlabbe
c25add868a arcore_java: disabled max speed localization filtering by default #1281 2024-06-09 10:20:18 -07:00
matlabbe
91cbbc8238 arcore: fixed pose not updated correctly 2024-06-09 10:20:18 -07:00
matlabbe
ccdddfc83f Refactored android docker to easily re-use rtabmap.bash in a dev container to install Tango/ARCore/AREngine dependencies. 2024-06-09 10:19:22 -07:00
matlabbe
9b255d1f27 docker: Fixed typo 2024-06-03 20:12:17 -07:00
matlabbe
3ab8ae7eaf ci/noble: moved opengv to top image to be built on ci 2024-06-03 07:33:26 -07:00
Borong Yuan
a327c9530c add XVSDK VIO 2024-06-03 10:28:45 +08:00
matlabbe
5b810da73b Fixed compilation warnings on 22.04 (Qt 5.15.3) 2024-06-02 15:04:36 -07:00
matlabbe
098301e52c Added CI for Ubuntu Noble/24.04 + docker 2024-06-02 14:38:50 -07:00
matlabbe
2f21d42555 Calibration tool: added support for rational model (8 coeff) 2024-05-31 10:28:14 -07:00
Borong Yuan
fc9dcd6b3d rectify xvDepthColor 2024-05-30 19:41:48 +08:00
Borong Yuan
0ad1d0ad69 add CameraSeerSense to guilib 2024-05-30 16:55:37 +08:00
Borong Yuan
ce0c806d75 add CameraSeerSense methods 2024-05-29 19:41:14 +08:00
Borong Yuan
fb37b3adba add xvDepthColor 2024-05-28 17:08:49 +08:00
matlabbe
0f961783c1 merged master->rolling 2024-05-27 11:42:12 -07:00
matlabbe
32e03aaf68 ORB_SLAM3: fixed error if left image is color. SensorCaptureThread: stop thread if data cannot be captured (e.g., end of dataset) instead of skipping indefinitly with error log. 2024-05-26 18:04:07 -07:00
matlabbe
03afb94d92 arcore_java: fixed high speed filtering jumping (#1281) 2024-05-25 15:54:57 -07:00
matlabbe
c5c190a2a0 arcore_java: disabled max speed localization filtering by default #1281 2024-05-25 14:42:54 -07:00
matlabbe
bc66060fab arcore: fixed pose not updated correctly 2024-05-25 13:50:01 -07:00
Borong Yuan
3d5f1ad5c2 add xvImu 2024-05-24 23:12:16 +08:00
Borong Yuan
41a7eff8fa init CameraSeerSense 2024-05-23 20:51:13 +08:00
Borong Yuan
6acec02dbe add xvsdk cmake configs 2024-05-23 17:02:38 +08:00
Borong Yuan
fbeabf0751 Add ANMS (SSC method) (#1276) 2024-05-19 18:21:00 -07:00
matlabbe
0d4e4730c7 Merge branch 'borongyuan-likelihood_experiment' 2024-05-19 17:46:47 -07:00
matlabbe
995f65b2ec Added parameter Rtabmap/VirtualPlaceLikelihoodRatio to select how likelihood is normalized/adjusted (0=default old approach used in paper). 2024-05-19 17:46:00 -07:00
matlabbe
c034a9631c Merge branch 'likelihood_experiment' of https://github.com/borongyuan/rtabmap into borongyuan-likelihood_experiment 2024-05-19 14:57:58 -07:00
matlabbe
256dcbded4 Added script to reproduce results from loop closure detection paper. Added option to show Recall at 100% precision directly from rtabmap-console. Fixed retrieval not working on loop closure detection mode-only. Fixed showLogs.m error with Octave. 2024-05-19 14:54:37 -07:00
matlabbe
812caeeb9a docker: added libtbb-dev 2024-05-12 22:15:20 -07:00
matlabbe
a66564f98f docker/jammy/jammy-iron: added WITH_TBB option for opencv 2024-05-12 20:36:27 -07:00
matlabbe
375597af00 docker/focal: added WITH_TBB option for opencv 2024-05-12 19:58:12 -07:00
matlabbe
72d7418011 Fixed build with pcl<1.8 2024-05-12 19:13:05 -07:00
matlabbe
9505a21a7e DBViewer/Matcher tool: Fixed crash when python feature/matcher is used 2024-04-28 17:40:37 -07:00
matlabbe
36304b2cd1 frontiers docker: added missing pybind-dev dep 2024-04-28 11:46:37 -07:00
Borong Yuan
f3cfa7831d adjust likelihood using z-score 2024-04-28 12:22:26 +08:00
matlabbe
99c4612c64 Fixed #1268. Fixed ui warnings of labels with same name. 2024-04-27 14:58:33 -07:00
matlabbe
27dea71398 Apply fix from #979 2024-04-15 20:51:50 -07:00
matlabbe
726bceb816 fixing bionic build 2024-04-14 19:46:34 -07:00
matlabbe
700704bec9 LiDAR capture support in standalone library (#1264)
* Working rtabmap_lidar-mapping example (live and pcap)

* finalizing merge, added some deprecated

* fixed build

* Working deskewing for Lidar + Camera/IMU (no camera pose correction yet) and Lidar + Odom Sensor in main UI.

* backward compatibility

* fixed some not used variable warnings, fixed qt build for lidar mapping example

* Refactored CameraMobile, added AREngine background support, fixed LidarVPL16 build error with PCL 1.8

* ARCoreJava: buffer last depth image in case its stamp i higher than pose stamp. CameraMobile: added pose buffer. SensorCaptureThread: to get pose, odomSensor should be explicitly set, but can be same as lidar or camera  inputs.

* Working external lidar on iOS

* util3d::commonFiltering()/adjustNormalsToViewPoint() added organized cloud support. MainWindow: updated odomSensor setup

* fixed winsock include order

* reverted camera tool

* disable imu filtering when odom sensor is used

* Updated package version

* fixed windows build

* fixing more windows build erros
2024-04-14 19:06:04 -07:00
matlabbe
6a6913c939 Fixed #1262 2024-04-13 16:42:58 -07:00
Borong Yuan
a55b4203cd copy global descriptor (#1263) 2024-04-13 14:56:28 -07:00
matlabbe
a3267c9da6 UI: Added option to change map resolution on UI side, save/restore thresholds in figures, fixed basic panel's slam/rgbd mode checkboxes not changing the state of corresponding parameters. 2024-04-12 17:12:23 -07:00
matlabbe
fbbab1c077 Update README.md 2024-04-11 17:12:11 -07:00
mathieu86
4e7110930c DbViewer: switch between left and right views when double-clicking on single nodes 2024-04-11 13:01:00 -07:00
matlabbe
9266926a4a docker: enabled focal linux/arm/v7 2024-04-10 09:13:24 -07:00
Dominic Létourneau
5a159cef04 Create scheduled-stats.yml (#1260)
GitHub Stats for IntRoLab.
2024-04-09 09:09:21 -07:00
matlabbe
5ed1bf0ca8 GlobalDescriptor (PyDescriptor / netvlad) (#1163)
* First commit for pydescriptor

* Fixed Python refactoring errors

* GUI: added PyDescriptor parameters

* reordered python3 includes

* updated rtabmap_netvlad.py test main

* fixed build from last merge

* integrated https://github.com/introlab/rtabmap/pull/1255

* rescaled dot product result

Closing https://github.com/introlab/rtabmap/issues/1105
2024-04-07 15:48:16 -07:00
matlabbe
c33e995e83 Landmark constraints can now be rejected (in case we see same landmark at two different spots or constraint is poorly estimated). Optimizer/Robust can now be used with landmark constraints with orientation. 2024-04-06 13:41:03 -07:00
matlabbe
92edae35fc Fixed map empty on start if there is no global loop closure yet in localization mode when RGBD/OptimizeFromGraphEnd is true 2024-04-06 11:46:26 -07:00
matlabbe
d794669ef9 DBViewer: added buttons to edit/add priors 2024-04-02 17:37:52 -07:00
matlabbe
9cb0046734 fixing build with gtsam 4.0 2024-04-02 15:32:04 -07:00
matlabbe
76f63ab79a Fixing build with gtsam 4.2 2024-04-02 13:29:51 -07:00
matlabbe
063ca9c8ee fixed gtsam 4.3 build error (https://github.com/introlab/rtabmap/pull/1033#issuecomment-2031002034) 2024-04-01 23:05:16 -07:00
matlabbe
11adbdcc9f Fixed #1253 2024-03-31 14:53:00 -07:00
matlabbe
8612ebba93 fixed https://github.com/introlab/rtabmap_ros/issues/1134 2024-03-31 13:06:52 -07:00
matlabbe
a0476af896 UI: Exposed more depthai options, setting default rectification alpha to -1 to avoid OAK-D Pro crash 2024-03-30 18:08:32 -07:00
matlabbe
3b735907c8 DbViewer tool: added database's parameter overriding from arguments 2024-03-29 13:30:12 -07:00
matlabbe
0ba79be461 depthai >=2.24 requirement 2024-03-28 14:27:17 -07:00
matlabbe
cc17ebe92b iSAM2 integration (#1249)
* isam2 integration

* fonctional iSAM2, added related parameters

* updated default params after testing large-scale enviroment

* proximity search optimization

* boost<1.68 fix

* boost version

* Fixed map not showing in graphview

* iSAM2: supporting MM/localization/multi-session modes
2024-03-27 17:18:02 -07:00
Borong Yuan
bfeb487dba OAK Internal Sync & DepthAI HF-Net Support (#1193)
* Using Sync Node

* Using normalized IR intensity

* Set IMU output frequency to 200 Hz

* set sync threshold properly

* add depthai hfnet local head

* fix DB error

* add depthai hfnet global head

* fix data delay if image rate is set manually
2024-03-27 12:29:06 -07:00
matlabbe
bc6d390fb6 bionic docker: fixing cmake version for arm 2024-03-24 18:49:11 -07:00
matlabbe
f8a63ecf10 Fixing bionic docker (with cmake>=3.14) 2024-03-23 14:41:10 -07:00
matlabbe
7183b43c2a missed part from last commit 2024-03-23 14:34:54 -07:00
matlabbe
fa3ece5183 Increased minimal cmake version to 3.14 to use cmake's official FindSQLite3.cmake (#1250) 2024-03-23 14:32:18 -07:00
matlabbe
2f132b3a40 GUI: adjusted max limit of Optimizer/Epsilon 2024-03-19 16:34:11 -07:00
matlabbe
79dc180bf4 Fixed Odom/ResetCountdown not resetting anymore if next frame is also bad. 2024-03-17 17:19:08 -07:00
matlabbe
264c560a2c reverted 87faea7a85 for #783 (just don't include OptimizerCeres if -DWITH_CERES=OFF even if floam or okvis did include it) 2024-03-16 17:10:34 -07:00
matlabbe
4ce36ef245 Updated appveyor gdown version 2024-03-13 23:27:47 -07:00
matlabbe
d0227694c5 small fix for qt6 2024-03-13 22:52:44 -07:00
matlabbe
a6d9425bce DBViewer: support doubleclick on node or link in graphview to update correpsonding image view and constraints view, also added "Show pixel depth" menu option in ImageView to show pixel depth and pixel coordinate in map frame. 2024-03-13 22:42:47 -07:00
matlabbe
e299505a64 Fixed ORB_SLAM3 config for stereo mode 2024-03-12 23:13:06 -07:00
matlabbe
57b4954cb3 Update README.md 2024-03-10 15:24:48 -07:00
matlabbe
2577c47e77 Fixed #1232 2024-03-09 15:14:01 -08:00
matlabbe
52e1b01597 Fixed assert when exporting textured mesh with both multiband and blending enabled with grayscale images 2024-03-04 17:05:17 -08:00
matlabbe
8019a2dc49 Fixed #1227 2024-03-02 16:17:10 -08:00
matlabbe
33b875ecbf GraphView: fixed mouse cursor tracking inverted x-y values 2024-03-01 10:13:53 -08:00
matlabbe
c24f95a8d9 ExportCloudsDialog: added option to filter off-axis points 2024-02-29 16:19:57 -08:00
matlabbe
6f7e5cc97b Removed RGB option from main menu (#640) 2024-02-26 19:06:39 -08:00
matlabbe
fccf33dd96 GraphViewer: added "Show mouse cursor position (m)" context menu option. 2024-02-26 17:13:50 -08:00
Long Vuong
752ca76cf5 not limitKps inside Feature2D::generateKeypoints when using pyDetector (#1223)
* not limitKps when using pyDetector

* update with upstream

---------

Co-authored-by: Long Vuong <vuong@wheel.me>
2024-02-26 15:21:15 -08:00
Chris Lalancette
f8c4b62591 Remove dependency on qt_gui_cpp. (#1072)
There is no dependency in this package on qt_gui_cpp.
Instead, just use a dependency on qtbase5-dev

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-27 13:07:47 -07:00
224 changed files with 18685 additions and 10635 deletions

View File

@@ -19,7 +19,7 @@ init:
install:
# To download from google drive
- set PATH=C:\Python38-x64;C:\Python38-x64\Scripts;%PATH%
- ps: py -m pip --disable-pip-version-check install gdown==4.6.0
- ps: py -m pip --disable-pip-version-check install gdown>=5.1.0
# Qt
- set QTDIR=C:\Qt\5.10.1\msvc2015_64
# make sure Qt bin path is before cmake bin path to avoid copying qt5 dlls from cmake before qt installation

View File

@@ -0,0 +1,8 @@
{
"image": "introlab3it/rtabmap:android-deps",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools", "vscjava.vscode-java-pack"]
}
}
}

View File

@@ -0,0 +1,8 @@
{
"image": "introlab3it/rtabmap:18.04",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools"]
}
}
}

View File

@@ -2,7 +2,7 @@
"image": "introlab3it/rtabmap:20.04",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools", "vscjava.vscode-java-pack"]
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools"]
}
}
}

View File

@@ -0,0 +1,8 @@
{
"image": "introlab3it/rtabmap:22.04",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools"]
}
}
}

View File

@@ -0,0 +1,8 @@
{
"image": "introlab3it/rtabmap:24.04",
"customizations": {
"vscode": {
"extensions": ["ms-vscode.cpptools-themes", "ms-vscode.cmake-tools"]
}
}
}

View File

@@ -31,6 +31,9 @@ jobs:
os: ubuntu-22.04
- ros_distribution: 'iron'
os: ubuntu-22.04
# Currently CI has some errors on setup-ros with this OS, disabling for now
#- ros_distribution: 'jazzy'
# os: ubuntu-24.04
steps:
- uses: ros-tooling/setup-ros@v0.6

View File

@@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
steps:
- name: Install dependencies

View File

@@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
docker_tag: [focal-deps, jammy-deps, jammy-iron-deps]
docker_tag: [focal-deps, jammy-deps, jammy-iron-deps, noble-deps]
include:
- docker_tag: focal-deps
docker_tags: |
@@ -20,6 +20,7 @@ jobs:
docker_platforms: |
linux/amd64
linux/arm64
linux/arm/v7
docker_path: 'focal/deps'
- docker_tag: jammy-deps
docker_tags: |
@@ -34,6 +35,13 @@ jobs:
docker_platforms: |
linux/amd64
docker_path: 'jammy-iron/deps'
- docker_tag: noble-deps
docker_tags: |
introlab3it/rtabmap:noble-deps
docker_platforms: |
linux/amd64
linux/arm64
docker_path: 'noble/deps'
steps:
-
@@ -72,7 +80,7 @@ jobs:
strategy:
fail-fast: false
matrix:
docker_tag: [bionic, focal, jammy, jammy-iron, android23, android24, android26, android30]
docker_tag: [bionic, focal, jammy, jammy-iron, noble, android23, android24, android26, android30]
include:
- docker_tag: bionic
docker_tags: |
@@ -94,6 +102,7 @@ jobs:
docker_platforms: |
linux/amd64
linux/arm64
linux/arm/v7
docker_path: 'focal'
- docker_tag: jammy
docker_tags: |
@@ -113,6 +122,16 @@ jobs:
docker_platforms: |
linux/amd64
docker_path: 'jammy-iron'
- docker_tag: noble
docker_tags: |
introlab3it/rtabmap:noble
introlab3it/rtabmap:24.04
docker_args: |
NOT_USED=0
docker_platforms: |
linux/amd64
linux/arm64
docker_path: 'noble'
- docker_tag: android23
docker_tags: |
introlab3it/rtabmap:android23

16
.github/workflows/scheduled-stats.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: RTAB-Map Scheduled Stats Extraction From GitHub
on:
workflow_dispatch:
schedule:
- cron: '0 5 * * *'
jobs:
get_stats:
runs-on: ubuntu-latest
steps:
- name: Update Stats
uses: introlab/github-stats-action@v1
with:
github-stats-token: ${{ secrets.STATS_TOKEN }}
google-application-credentials: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
spreadsheet-id: ${{ secrets.SPREADSHEET_ID }}

View File

@@ -1,5 +1,5 @@
# Top-Level CmakeLists.txt
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.14)
PROJECT( RTABMap )
SET(PROJECT_PREFIX rtabmap)
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
#######################
SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 21)
SET(RTABMAP_PATCH_VERSION 4)
SET(RTABMAP_PATCH_VERSION 6)
SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
@@ -181,6 +181,7 @@ option(WITH_FREENECT "Include Freenect support" ON)
option(WITH_FREENECT2 "Include Freenect2 support" ON)
option(WITH_K4W2 "Include Kinect for Windows v2 support" ON)
option(WITH_K4A "Include Kinect for Azure support" ON)
option(WITH_OPENNI "Include OpenNI support" ON)
option(WITH_OPENNI2 "Include OpenNI2 support" ON)
option(WITH_DC1394 "Include dc1394 support" ON)
option(WITH_G2O "Include g2o support" ON)
@@ -203,6 +204,7 @@ option(WITH_REALSENSE_SLAM "Include RealSenseSlam support" ON)
option(WITH_REALSENSE2 "Include RealSense support" ON)
option(WITH_MYNTEYE "Include mynteye-s support" ON)
option(WITH_DEPTHAI "Include depthai-core support" OFF)
option(WITH_XVSDK "Include XVisio SDK support" OFF)
option(WITH_OCTOMAP "Include OctoMap support" ON)
option(WITH_GRIDMAP "Include GridMap support" ON)
option(WITH_CPUTSDF "Include CPUTSDF support" OFF)
@@ -252,10 +254,10 @@ endif()
FIND_PACKAGE(ZLIB REQUIRED QUIET)
FIND_PACKAGE(Sqlite3 QUIET)
IF(Sqlite3_FOUND)
MESSAGE(STATUS "Found Sqlite3: ${Sqlite3_INCLUDE_DIRS} ${Sqlite3_LIBRARIES}")
ENDIF(Sqlite3_FOUND)
FIND_PACKAGE(SQLite3 QUIET)
IF(SQLite3_FOUND)
MESSAGE(STATUS "Found SQLite3: ${SQLite3_INCLUDE_DIRS} ${SQLite3_LIBRARIES}")
ENDIF(SQLite3_FOUND)
if(NOT "${PCL_LIBRARIES}" STREQUAL "")
# fix libproj.so not found on Xenial
@@ -539,6 +541,11 @@ IF(WITH_POINTMATCHER)
message(STATUS "libnabo found, version ${libnabo_VERSION} (Config mode)")
SET(libpointmatcher_LIBRARIES "${libpointmatcher_LIBRARIES};libnabo::nabo")
ENDIF(value EQUAL -1)
string(FIND "${libpointmatcher_LIBRARIES}" "yaml-cpp::yaml-cpp" value)
IF(NOT value EQUAL -1)
# Find yaml-cpp (Issue #1268):
find_package(yaml-cpp QUIET)
ENDIF(NOT value EQUAL -1)
ENDIF(libpointmatcher_FOUND)
ENDIF(WITH_POINTMATCHER)
@@ -651,12 +658,19 @@ IF(WITH_MYNTEYE)
ENDIF(WITH_MYNTEYE)
IF(WITH_DEPTHAI)
FIND_PACKAGE(depthai 2 QUIET)
FIND_PACKAGE(depthai 2.24 QUIET)
IF(depthai_FOUND)
MESSAGE(STATUS "Found depthai-core (targets)")
ENDIF(depthai_FOUND)
ENDIF(WITH_DEPTHAI)
IF(WITH_XVSDK)
FIND_PACKAGE(xvsdk QUIET)
IF(xvsdk_FOUND)
MESSAGE(STATUS "Found xvsdk (targets)")
ENDIF(xvsdk_FOUND)
ENDIF(WITH_XVSDK)
IF(WITH_OCTOMAP)
FIND_PACKAGE(octomap QUIET)
IF(octomap_FOUND)
@@ -892,9 +906,9 @@ ENDIF()
IF(NOT MRPT_FOUND)
SET(MRPT "//")
ENDIF(NOT MRPT_FOUND)
IF(NOT CERES_FOUND)
IF(NOT WITH_CERES OR NOT CERES_FOUND)
SET(CERES "//")
ENDIF(NOT CERES_FOUND)
ENDIF(NOT WITH_CERES OR NOT CERES_FOUND)
IF(NOT WITH_TORO)
SET(TORO "//")
ENDIF(NOT WITH_TORO)
@@ -951,6 +965,9 @@ ELSE()
)
ENDIF(WIN32)
ENDIF()
IF(NOT (OpenNI_FOUND AND WITH_OPENNI))
SET(OPENNI "//")
ENDIF()
IF(NOT OpenNI2_FOUND)
SET(OPENNI2 "//")
ENDIF()
@@ -995,6 +1012,12 @@ IF(NOT depthai_FOUND)
ELSE()
SET(CONF_WITH_DEPTH_AI 1)
ENDIF()
IF(NOT xvsdk_FOUND)
SET(XVSDK "//")
SET(CONF_WITH_XVSDK 0)
ELSE()
SET(CONF_WITH_XVSDK 1)
ENDIF()
IF(NOT octomap_FOUND)
SET(OCTOMAP "//")
SET(CONF_WITH_OCTOMAP 0)
@@ -1070,13 +1093,15 @@ IF(ANDROID)
IF(BUILD_APP)
ADD_SUBDIRECTORY( app )
ENDIF(BUILD_APP)
ELSEIF(Qt6_FOUND OR Qt5_FOUND OR (QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND))
ADD_SUBDIRECTORY( guilib )
IF(BUILD_APP)
ADD_SUBDIRECTORY( app )
ENDIF(BUILD_APP)
ELSEIF(WITH_QT)
MESSAGE(WARNING "Qt not found, the GUI lib and the stand-alone application will not be compiled...")
IF(Qt6_FOUND OR Qt5_FOUND OR (QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND))
ADD_SUBDIRECTORY( guilib )
IF(BUILD_APP)
ADD_SUBDIRECTORY( app )
ENDIF(BUILD_APP)
ELSE()
MESSAGE(WARNING "Qt not found, the GUI lib and the stand-alone application will not be compiled...")
ENDIF()
ENDIF()
IF(BUILD_TOOLS)
@@ -1104,7 +1129,7 @@ ENDIF()
####
add_library(rtabmap INTERFACE)
add_library(rtabmap::rtabmap ALIAS rtabmap)
IF(QT4_FOUND OR Qt5_FOUND OR Qt6_FOUND)
IF(WITH_QT AND (QT4_FOUND OR Qt5_FOUND OR Qt6_FOUND))
set(CONF_WITH_GUI ON)
IF(QT4_FOUND)
set(CONF_QT_VERSION 4)
@@ -1316,13 +1341,13 @@ IF(OpenCV_FOUND)
ENDIF()
ENDIF(OpenCV_FOUND)
IF(QT4_FOUND)
IF(WITH_QT AND QT4_FOUND)
MESSAGE(STATUS " With Qt4 = YES (License: Open Source or Commercial)")
MESSAGE(STATUS " With VTK ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION} = YES (License: BSD)")
ELSEIF(Qt5_FOUND)
ELSEIF(WITH_QT AND Qt5_FOUND)
MESSAGE(STATUS " With Qt ${Qt5_VERSION} = YES (License: Open Source or Commercial)")
MESSAGE(STATUS " With VTK ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION} = YES (License: BSD)")
ELSEIF(Qt6_FOUND)
ELSEIF(WITH_QT AND Qt6_FOUND)
MESSAGE(STATUS " With Qt ${Qt6_VERSION} = YES (License: Open Source or Commercial)")
MESSAGE(STATUS " With VTK ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION} = YES (License: BSD)")
@@ -1332,10 +1357,10 @@ ELSE()
MESSAGE(STATUS " With Qt = NO (Qt not found)")
ENDIF()
IF(Sqlite3_FOUND)
IF(SQLite3_FOUND)
MESSAGE(STATUS " With external SQLite3 = YES (License: Public Domain)")
ELSE()
MESSAGE(STATUS " With external SQLite3 = NO (sqlite3 not found, internal version is used for convenience)")
MESSAGE(STATUS " With external SQLite3 = NO (SQLite3 not found, internal version is used for convenience)")
ENDIF()
IF(WITH_ORB_OCTREE)
@@ -1406,12 +1431,8 @@ ELSE()
MESSAGE(STATUS " *With GTSAM = NO (GTSAM not found)")
ENDIF()
IF(CERES_FOUND)
IF(WITH_CERES)
IF(WITH_CERES AND CERES_FOUND)
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD)")
ELSE()
MESSAGE(STATUS " *With Ceres ${Ceres_VERSION} = YES (License: BSD, WITH_CERES=OFF but it is enabled by okvis or floam dependencies)")
ENDIF()
ELSEIF(NOT WITH_CERES)
MESSAGE(STATUS " *With Ceres = NO (WITH_CERES=OFF)")
ELSE()
@@ -1530,6 +1551,14 @@ ELSE()
MESSAGE(STATUS " With Freenect = NO (libfreenect not found)")
ENDIF()
IF(WITH_OPENNI AND OpenNI_FOUND)
MESSAGE(STATUS " With OpenNI = YES (License: Apache v2)")
ELSEIF(NOT WITH_OPENNI)
MESSAGE(STATUS " With OpenNI = NO (WITH_OPENNI=OFF)")
ELSE()
MESSAGE(STATUS " With OpenNI = NO (OpenNI not found)")
ENDIF()
IF(OpenNI2_FOUND)
MESSAGE(STATUS " With OpenNI2 = YES (License: Apache v2)")
ELSEIF(NOT WITH_OPENNI2)
@@ -1637,6 +1666,14 @@ ELSE()
MESSAGE(STATUS " With DepthAI = NO (depthai-core not found)")
ENDIF()
IF(xvsdk_FOUND)
MESSAGE(STATUS " With XVisio SDK ${xvsdk_VERSION} = YES")
ELSEIF(NOT WITH_XVSDK)
MESSAGE(STATUS " With XVisio SDK = NO (WITH_XVSDK=OFF)")
ELSE()
MESSAGE(STATUS " With XVisio SDK = NO (xvsdk not found)")
ENDIF()
MESSAGE(STATUS "")
MESSAGE(STATUS " Odometry Approaches:")
IF(loam_velodyne_FOUND)

View File

@@ -43,7 +43,11 @@ IF(@CONF_WITH_K4A@)
ENDIF()
IF(@CONF_WITH_DEPTH_AI@)
find_dependency(depthai 2)
find_dependency(depthai 2.24)
ENDIF()
IF(@CONF_WITH_XVSDK@)
find_dependency(xvsdk)
ENDIF()
IF(@CONF_WITH_OCTOMAP@)
@@ -93,8 +97,7 @@ endforeach()
include("${CMAKE_CURRENT_LIST_DIR}/RTABMapTargets.cmake")
foreach(_comp ${RTABMap_FIND_COMPONENTS})
if (NOT ";${_RTABMap_supported_components};" MATCHES ";${_comp};")
set(RTABMap_${_comp}_FOUND False)
if (NOT RTABMap_${_comp}_FOUND)
if(${RTABMap_FIND_REQUIRED_${_comp}})
set(RTABMap_FOUND False)
set(RTABMap_NOT_FOUND_MESSAGE "Unsupported or not found required component: ${_comp}")

View File

@@ -45,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@CERES@#define RTABMAP_CERES
@MRPT@#define RTABMAP_MRPT
@VERTIGO@#define RTABMAP_VERTIGO
@OPENNI@#define RTABMAP_OPENNI
@OPENNI2@#define RTABMAP_OPENNI2
@FREENECT@#define RTABMAP_FREENECT
@FREENECT2@#define RTABMAP_FREENECT2
@@ -68,6 +69,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@REALSENSE2@#define RTABMAP_REALSENSE2
@MYNTEYE@#define RTABMAP_MYNTEYE
@DEPTHAI@#define RTABMAP_DEPTHAI
@XVSDK@#define RTABMAP_XVSDK
@OCTOMAP@#define RTABMAP_OCTOMAP
@GRIDMAP@#define RTABMAP_GRIDMAP
@CPUTSDF@#define RTABMAP_CPUTSDF

View File

@@ -334,11 +334,12 @@ void CameraARCore::setScreenRotationAndSize(ScreenRotation colorCameraToDisplayR
}
}
SensorData CameraARCore::captureImage(CameraInfo * info)
SensorData CameraARCore::updateDataOnRender(Transform & pose)
{
UScopeMutex lock(arSessionMutex_);
//LOGI("Capturing image...");
pose.setNull();
SensorData data;
if(!arSession_)
{
@@ -370,7 +371,7 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
if (geometry_changed != 0 || !uvs_initialized_) {
ArFrame_transformCoordinates2d(
arSession_, arFrame_, AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES,
BackgroundRenderer::kNumVertices, BackgroundRenderer_kVertices, AR_COORDINATES_2D_TEXTURE_NORMALIZED,
BackgroundRenderer::kNumVertices, BackgroundRenderer_kVerticesDevice, AR_COORDINATES_2D_TEXTURE_NORMALIZED,
transformed_uvs_);
UASSERT(transformed_uvs_);
uvs_initialized_ = true;
@@ -393,7 +394,6 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
ArTrackingState camera_tracking_state;
ArCamera_getTrackingState(arSession_, ar_camera, &camera_tracking_state);
Transform pose;
CameraModel model;
if(camera_tracking_state == AR_TRACKING_STATE_TRACKING)
{
@@ -401,24 +401,13 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
float pose_raw[7];
ArCamera_getPose(arSession_, ar_camera, arPose_);
ArPose_getPoseRaw(arSession_, arPose_, pose_raw);
pose = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
Transform poseArCore = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
poseArCore = rtabmap::rtabmap_world_T_opengl_world * poseArCore * rtabmap::opengl_world_T_rtabmap_world;
Transform poseArCore = pose;
if(pose.isNull())
if(poseArCore.isNull())
{
LOGE("CameraARCore: Pose is null");
}
else
{
this->poseReceived(pose);
// adjust origin
if(!getOriginOffset().isNull())
{
pose = getOriginOffset() * pose;
}
info->odomPose = pose;
}
// Get calibration parameters
float fx,fy, cx, cy;
@@ -551,6 +540,17 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
data = SensorData(scan, rgb, depthFromMotion_?getOcclusionImage():cv::Mat(), model, 0, stamp);
data.setFeatures(kpts, kpts3, cv::Mat());
if(!poseArCore.isNull())
{
pose = poseArCore;
this->poseReceived(pose, stamp);
// adjust origin
if(!getOriginOffset().isNull())
{
pose = getOriginOffset() * pose;
}
}
}
}
else
@@ -571,134 +571,6 @@ SensorData CameraARCore::captureImage(CameraInfo * info)
ArCamera_release(ar_camera);
return data;
}
void CameraARCore::capturePoseOnly()
{
UScopeMutex lock(arSessionMutex_);
//LOGI("Capturing image...");
if(!arSession_)
{
return;
}
if(textureId_ != 0)
{
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId_);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ArSession_setCameraTextureName(arSession_, textureId_);
}
// Update session to get current frame and render camera background.
if (ArSession_update(arSession_, arFrame_) != AR_SUCCESS) {
LOGE("CameraARCore::capturePoseOnly() ArSession_update error");
return;
}
// If display rotation changed (also includes view size change), we need to
// re-query the uv coordinates for the on-screen portion of the camera image.
int32_t geometry_changed = 0;
ArFrame_getDisplayGeometryChanged(arSession_, arFrame_, &geometry_changed);
if (geometry_changed != 0 || !uvs_initialized_) {
ArFrame_transformCoordinates2d(
arSession_, arFrame_, AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES,
BackgroundRenderer::kNumVertices, BackgroundRenderer_kVertices, AR_COORDINATES_2D_TEXTURE_NORMALIZED,
transformed_uvs_);
UASSERT(transformed_uvs_);
uvs_initialized_ = true;
}
ArCamera* ar_camera;
ArFrame_acquireCamera(arSession_, arFrame_, &ar_camera);
ArCamera_getViewMatrix(arSession_, ar_camera, glm::value_ptr(viewMatrix_));
ArCamera_getProjectionMatrix(arSession_, ar_camera,
/*near=*/0.1f, /*far=*/100.f,
glm::value_ptr(projectionMatrix_));
// adjust origin
if(!getOriginOffset().isNull())
{
viewMatrix_ = glm::inverse(rtabmap::glmFromTransform(rtabmap::opengl_world_T_rtabmap_world * getOriginOffset() *rtabmap::rtabmap_world_T_opengl_world)*glm::inverse(viewMatrix_));
}
ArTrackingState camera_tracking_state;
ArCamera_getTrackingState(arSession_, ar_camera, &camera_tracking_state);
Transform pose;
CameraModel model;
if(camera_tracking_state == AR_TRACKING_STATE_TRACKING)
{
// pose in OpenGL coordinates
float pose_raw[7];
ArCamera_getPose(arSession_, ar_camera, arPose_);
ArPose_getPoseRaw(arSession_, arPose_, pose_raw);
pose = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
if(!pose.isNull())
{
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
this->poseReceived(pose);
if(!getOriginOffset().isNull())
{
pose = getOriginOffset() * pose;
}
}
int32_t is_depth_supported = 0;
ArSession_isDepthModeSupported(arSession_, AR_DEPTH_MODE_AUTOMATIC, &is_depth_supported);
if(is_depth_supported)
{
LOGD("Acquire depth image!");
ArImage * depthImage = nullptr;
ArFrame_acquireDepthImage(arSession_, arFrame_, &depthImage);
ArImageFormat format;
ArImage_getFormat(arSession_, depthImage, &format);
if(format == AR_IMAGE_FORMAT_DEPTH16)
{
LOGD("Depth format detected!");
int planeCount;
ArImage_getNumberOfPlanes(arSession_, depthImage, &planeCount);
LOGD("planeCount=%d", planeCount);
UASSERT_MSG(planeCount == 1, uFormat("Error: getNumberOfPlanes() planceCount = %d", planeCount).c_str());
const uint8_t *data = nullptr;
int len = 0;
int stride;
int width;
int height;
ArImage_getWidth(arSession_, depthImage, &width);
ArImage_getHeight(arSession_, depthImage, &height);
ArImage_getPlaneRowStride(arSession_, depthImage, 0, &stride);
ArImage_getPlaneData(arSession_, depthImage, 0, &data, &len);
LOGD("width=%d, height=%d, bytes=%d stride=%d", width, height, len, stride);
cv::Mat occlusionImage = cv::Mat(height, width, CV_16UC1, (void*)data).clone();
float fx,fy, cx, cy;
int32_t rgb_width, rgb_height;
ArCamera_getImageIntrinsics(arSession_, ar_camera, arCameraIntrinsics_);
ArCameraIntrinsics_getFocalLength(arSession_, arCameraIntrinsics_, &fx, &fy);
ArCameraIntrinsics_getPrincipalPoint(arSession_, arCameraIntrinsics_, &cx, &cy);
ArCameraIntrinsics_getImageDimensions(arSession_, arCameraIntrinsics_, &rgb_width, &rgb_height);
float scaleX = (float)width / (float)rgb_width;
float scaleY = (float)height / (float)rgb_height;
CameraModel occlusionModel(fx*scaleX, fy*scaleY, cx*scaleX, cy*scaleY, pose*deviceTColorCamera_, 0, cv::Size(width, height));
this->setOcclusionImage(occlusionImage, occlusionModel);
}
ArImage_release(depthImage);
}
}
ArCamera_release(ar_camera);
}
} /* namespace rtabmap */

View File

@@ -63,23 +63,14 @@ public:
CameraARCore(void* env, void* context, void* activity, bool depthFromMotion = false, bool smoothing = false);
virtual ~CameraARCore();
bool uvsInitialized() const {return uvs_initialized_;}
const float* uvsTransformed() const {return transformed_uvs_;}
void getVPMatrices(glm::mat4 & view, glm::mat4 & projection) const {view=viewMatrix_; projection=projectionMatrix_;}
virtual void setScreenRotationAndSize(ScreenRotation colorCameraToDisplayRotation, int width, int height);
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
void setupGL();
virtual void close(); // close Tango connection
virtual void close(); // close ARCore connection
virtual std::string getSerial() const;
GLuint getTextureId() const {return textureId_;}
void imageCallback(AImageReader *reader);
protected:
virtual SensorData captureImage(CameraInfo * info = 0); // should be called in opengl thread
virtual void capturePoseOnly();
virtual SensorData updateDataOnRender(Transform & pose); // should be called in opengl thread
private:
rtabmap::Transform getPoseAtTimestamp(double timestamp);

View File

@@ -117,9 +117,6 @@ bool CameraAREngine::init(const std::string & calibrationFolder, const std::stri
deviceTColorCamera_ = opticalRotation;
// Required as ArSession_update does some off-screen OpenGL stuff...
HwArSession_setCameraTextureName(arSession_, textureId_);
if (HwArSession_resume(arSession_) != HWAR_SUCCESS)
{
UERROR("Cannot resume camera!");
@@ -169,38 +166,87 @@ void CameraAREngine::close()
CameraMobile::close();
}
SensorData CameraAREngine::captureImage(CameraInfo * info)
void CameraAREngine::setScreenRotationAndSize(ScreenRotation colorCameraToDisplayRotation, int width, int height)
{
CameraMobile::setScreenRotationAndSize(colorCameraToDisplayRotation, width, height);
if(arSession_)
{
int ret = static_cast<int>(colorCameraToDisplayRotation) + 1; // remove 90deg camera rotation
if (ret > 3) {
ret -= 4;
}
HwArSession_setDisplayGeometry(arSession_, ret, width, height);
}
}
SensorData CameraAREngine::updateDataOnRender(Transform & pose)
{
UScopeMutex lock(arSessionMutex_);
//LOGI("Capturing image...");
pose.setNull();
SensorData data;
if(!arSession_)
{
return data;
}
if(textureId_ == 0)
{
glGenTextures(1, &textureId_);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId_);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
if(textureId_!=0)
HwArSession_setCameraTextureName(arSession_, textureId_);
// Update session to get current frame and render camera background.
if (HwArSession_update(arSession_, arFrame_) != HWAR_SUCCESS) {
LOGE("CameraAREngine::captureImage() ArSession_update error");
return data;
}
// If display rotation changed (also includes view size change), we need to
// re-query the uv coordinates for the on-screen portion of the camera image.
int32_t geometry_changed = 0;
HwArFrame_getDisplayGeometryChanged(arSession_, arFrame_, &geometry_changed);
if (geometry_changed != 0 || !uvs_initialized_) {
HwArFrame_transformDisplayUvCoords(
arSession_, arFrame_,
BackgroundRenderer::kNumVertices*2, BackgroundRenderer_kVerticesView,
transformed_uvs_);
UERROR("uv: (%f,%f) (%f,%f) (%f,%f) (%f,%f)",
transformed_uvs_[0], transformed_uvs_[1],
transformed_uvs_[2], transformed_uvs_[3],
transformed_uvs_[4], transformed_uvs_[5],
transformed_uvs_[6], transformed_uvs_[7]);
UASSERT(transformed_uvs_);
uvs_initialized_ = true;
}
HwArCamera* ar_camera;
HwArFrame_acquireCamera(arSession_, arFrame_, &ar_camera);
HwArCamera_getViewMatrix(arSession_, ar_camera, glm::value_ptr(viewMatrix_));
HwArCamera_getProjectionMatrix(arSession_, ar_camera,
/*near=*/0.1f, /*far=*/100.f,
glm::value_ptr(projectionMatrix_));
// adjust origin
if(!getOriginOffset().isNull())
{
viewMatrix_ = glm::inverse(rtabmap::glmFromTransform(rtabmap::opengl_world_T_rtabmap_world * getOriginOffset() *rtabmap::rtabmap_world_T_opengl_world)*glm::inverse(viewMatrix_));
}
HwArTrackingState camera_tracking_state;
HwArCamera_getTrackingState(arSession_, ar_camera, &camera_tracking_state);
Transform pose;
if(camera_tracking_state == HWAR_TRACKING_STATE_TRACKING)
{
// pose in OpenGL coordinates
float pose_raw[7];
HwArCamera_getPose(arSession_, ar_camera, arPose_);
HwArPose_getPoseRaw(arSession_, arPose_, pose_raw);
pose = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
// Get calibration parameters
// FIXME: Hard-coded as getting intrinsics with the api fails
float fx=492.689667,fy=492.606201, cx=323.594849, cy=234.659744;
@@ -274,6 +320,26 @@ SensorData CameraAREngine::captureImage(CameraInfo * info)
double stamp = double(timestamp_ns)/10e8;
CameraModel model = CameraModel(fx, fy, cx, cy, deviceTColorCamera_, 0, cv::Size(camWidth, camHeight));
data = SensorData(outputRGB, outputDepth, model, 0, stamp);
// pose in OpenGL coordinates
float pose_raw[7];
HwArCamera_getPose(arSession_, ar_camera, arPose_);
HwArPose_getPoseRaw(arSession_, arPose_, pose_raw);
pose = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
if(pose.isNull())
{
LOGE("CameraAREngine: Pose is null");
}
else
{
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
this->poseReceived(pose, stamp);
// adjust origin
if(!getOriginOffset().isNull())
{
pose = getOriginOffset() * pose;
}
}
}
}
else
@@ -291,66 +357,8 @@ SensorData CameraAREngine::captureImage(CameraInfo * info)
}
HwArCamera_release(ar_camera);
if(pose.isNull())
{
LOGE("CameraAREngine: Pose is null");
}
else
{
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
this->poseReceived(pose);
// adjust origin
if(!getOriginOffset().isNull())
{
pose = getOriginOffset() * pose;
}
info->odomPose = pose;
}
return data;
}
void CameraAREngine::capturePoseOnly()
{
UScopeMutex lock(arSessionMutex_);
//LOGI("Capturing image...");
SensorData data;
if(!arSession_)
{
return;
}
// Update session to get current frame and render camera background.
if (HwArSession_update(arSession_, arFrame_) != HWAR_SUCCESS) {
LOGE("CameraARCore::captureImage() ArSession_update error");
return;
}
HwArCamera* ar_camera;
HwArFrame_acquireCamera(arSession_, arFrame_, &ar_camera);
HwArTrackingState camera_tracking_state;
HwArCamera_getTrackingState(arSession_, ar_camera, &camera_tracking_state);
Transform pose;
CameraModel model;
if(camera_tracking_state == HWAR_TRACKING_STATE_TRACKING)
{
// pose in OpenGL coordinates
float pose_raw[7];
HwArCamera_getPose(arSession_, ar_camera, arPose_);
HwArPose_getPoseRaw(arSession_, arPose_, pose_raw);
pose = Transform(pose_raw[4], pose_raw[5], pose_raw[6], pose_raw[0], pose_raw[1], pose_raw[2], pose_raw[3]);
if(!pose.isNull())
{
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
this->poseReceived(pose);
}
}
HwArCamera_release(ar_camera);
}
} /* namespace rtabmap */

View File

@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UEvent.h>
#include <rtabmap/utilite/UTimer.h>
#include <boost/thread/mutex.hpp>
#include <background_renderer.h>
#include <huawei_arengine_interface.h>
@@ -48,13 +49,14 @@ public:
CameraAREngine(void* env, void* context, void* activity, bool smoothing = false);
virtual ~CameraAREngine();
virtual void setScreenRotationAndSize(ScreenRotation colorCameraToDisplayRotation, int width, int height);
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
virtual void close(); // close Tango connection
virtual void close(); // close AREngine connection
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual void capturePoseOnly();
virtual SensorData updateDataOnRender(Transform & pose);
private:
rtabmap::Transform getPoseAtTimestamp(double timestamp);
@@ -69,7 +71,6 @@ private:
HwArCameraIntrinsics *arCameraIntrinsics_ = nullptr;
HwArPose * arPose_ = nullptr;
bool arInstallRequested_;
GLuint textureId_;
UMutex arSessionMutex_;
};

View File

@@ -55,10 +55,8 @@ const rtabmap::Transform CameraMobile::opticalRotationInv = Transform(
CameraMobile::CameraMobile(bool smoothing) :
Camera(10),
deviceTColorCamera_(Transform::getIdentity()),
spinOncePreviousStamp_(0.0),
textureId_(0),
uvs_initialized_(false),
previousStamp_(0.0),
stampEpochOffset_(0.0),
smoothing_(smoothing),
colorCameraToDisplayRotation_(ROTATION_0),
@@ -79,13 +77,12 @@ bool CameraMobile::init(const std::string &, const std::string &)
void CameraMobile::close()
{
previousPose_.setNull();
previousStamp_ = 0.0;
firstFrame_ = true;
lastKnownGPS_ = GPS();
lastEnvSensors_.clear();
originOffset_ = Transform();
originUpdate_ = false;
pose_ = Transform();
dataPose_ = Transform();
data_ = SensorData();
if(textureId_ != 0)
@@ -97,35 +94,107 @@ void CameraMobile::close()
void CameraMobile::resetOrigin()
{
previousPose_.setNull();
previousStamp_ = 0.0;
firstFrame_ = true;
lastKnownGPS_ = GPS();
lastEnvSensors_.clear();
pose_ = Transform();
dataPose_ = Transform();
data_ = SensorData();
originUpdate_ = true;
}
void CameraMobile::poseReceived(const Transform & pose)
bool CameraMobile::getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime)
{
pose.setNull();
int maxWaitTimeMs = maxWaitTime * 1000;
// Interpolate pose
if(!poseBuffer_.empty())
{
poseMutex_.lock();
int waitTry = 0;
while(maxWaitTimeMs>0 && poseBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
{
poseMutex_.unlock();
++waitTry;
uSleep(1);
poseMutex_.lock();
}
if(poseBuffer_.rbegin()->first < stamp)
{
if(maxWaitTimeMs > 0)
{
UWARN("Could not find poses to interpolate at time %f after waiting %d ms (latest is %f)...", stamp, maxWaitTimeMs, poseBuffer_.rbegin()->first);
}
else
{
UWARN("Could not find poses to interpolate at time %f (latest is %f)...", stamp, poseBuffer_.rbegin()->first);
}
}
else
{
std::map<double, Transform>::const_iterator iterB = poseBuffer_.lower_bound(stamp);
std::map<double, Transform>::const_iterator iterA = iterB;
if(iterA != poseBuffer_.begin())
{
iterA = --iterA;
}
if(iterB == poseBuffer_.end())
{
iterB = --iterB;
}
if(iterA == iterB && stamp == iterA->first)
{
pose = iterA->second;
}
else if(stamp >= iterA->first && stamp <= iterB->first)
{
pose = iterA->second.interpolate((stamp-iterA->first) / (iterB->first-iterA->first), iterB->second);
}
else // stamp < iterA->first
{
UWARN("Could not find pose data to interpolate at time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
}
}
poseMutex_.unlock();
}
return !pose.isNull();
}
void CameraMobile::poseReceived(const Transform & pose, double deviceStamp)
{
if(!pose.isNull())
{
// send pose of the camera (without optical rotation)
Transform p = pose*deviceTColorCamera_;
Transform p = pose;
if(originUpdate_)
{
originOffset_ = p.translation().inverse();
originUpdate_ = false;
}
if(stampEpochOffset_ == 0.0)
{
stampEpochOffset_ = UTimer::now() - deviceStamp;
}
double epochStamp = stampEpochOffset_ + deviceStamp;
if(!originOffset_.isNull())
{
this->post(new PoseEvent(originOffset_*p));
p = originOffset_*p;
}
else
{
this->post(new PoseEvent(p));
UScopeMutex lock(poseMutex_);
poseBuffer_.insert(poseBuffer_.end(), std::make_pair(epochStamp, p));
if(poseBuffer_.size() > 1000)
{
poseBuffer_.erase(poseBuffer_.begin());
}
}
// send pose of the camera (with optical rotation)
this->post(new PoseEvent(p * deviceTColorCamera_));
}
}
@@ -139,11 +208,20 @@ void CameraMobile::setGPS(const GPS & gps)
lastKnownGPS_ = gps;
}
void CameraMobile::setData(const SensorData & data, const Transform & pose, const glm::mat4 & viewMatrix, const glm::mat4 & projectionMatrix, const float * texCoord)
void CameraMobile::addEnvSensor(int type, float value)
{
LOGD("CameraMobile::setData pose=%s stamp=%f", pose.prettyPrint().c_str(), data.stamp());
lastEnvSensors_.insert(std::make_pair((EnvSensor::Type)type, EnvSensor((EnvSensor::Type)type, value)));
}
void CameraMobile::update(const SensorData & data, const Transform & pose, const glm::mat4 & viewMatrix, const glm::mat4 & projectionMatrix, const float * texCoord)
{
UScopeMutex lock(dataMutex_);
bool notify = !data_.isValid();
LOGD("CameraMobile::update pose=%s stamp=%f", pose.prettyPrint().c_str(), data.stamp());
data_ = data;
pose_ = pose;
dataPose_ = pose;
viewMatrix_ = viewMatrix;
projectionMatrix_ = projectionMatrix;
@@ -151,7 +229,7 @@ void CameraMobile::setData(const SensorData & data, const Transform & pose, cons
// adjust origin
if(!originOffset_.isNull())
{
pose_ = originOffset_ * pose_;
dataPose_ = originOffset_ * dataPose_;
viewMatrix_ = glm::inverse(rtabmap::glmFromTransform(rtabmap::opengl_world_T_rtabmap_world * originOffset_ *rtabmap::rtabmap_world_T_opengl_world)*glm::inverse(viewMatrix_));
}
@@ -166,7 +244,7 @@ void CameraMobile::setData(const SensorData & data, const Transform & pose, cons
uvs_initialized_ = true;
}
LOGD("CameraMobile::setData textureId_=%d", (int)textureId_);
LOGD("CameraMobile::update textureId_=%d", (int)textureId_);
if(textureId_ != 0 && texCoord != 0)
{
@@ -193,78 +271,63 @@ void CameraMobile::setData(const SensorData & data, const Transform & pose, cons
return;
}
}
}
void CameraMobile::addEnvSensor(int type, float value)
{
lastEnvSensors_.insert(std::make_pair((EnvSensor::Type)type, EnvSensor((EnvSensor::Type)type, value)));
}
void CameraMobile::spinOnce()
{
if(!this->isRunning())
postUpdate();
if(notify)
{
bool ignoreFrame = false;
//float rate = 10.0f; // maximum 10 FPS for image data
double now = UTimer::now();
/*if(rate>0.0f)
{
if((spinOncePreviousStamp_>=0.0 && now>spinOncePreviousStamp_ && now - spinOncePreviousStamp_ < 1.0f/rate) ||
((spinOncePreviousStamp_<=0.0 || now<=spinOncePreviousStamp_) && spinOnceFrameRateTimer_.getElapsedTime() < 1.0f/rate))
{
ignoreFrame = true;
}
}*/
dataReady_.release();
}
}
if(!ignoreFrame)
void CameraMobile::updateOnRender()
{
UScopeMutex lock(dataMutex_);
bool notify = !data_.isValid();
data_ = updateDataOnRender(dataPose_);
if(data_.isValid())
{
postUpdate();
if(notify)
{
spinOnceFrameRateTimer_.start();
spinOncePreviousStamp_ = now;
mainLoop();
}
else
{
// just send pose
capturePoseOnly();
dataReady_.release();
}
}
}
void CameraMobile::mainLoopBegin()
SensorData CameraMobile::updateDataOnRender(Transform & pose)
{
double t = cameraStartedTime_.elapsed();
if(t < 5.0)
{
uSleep((5.0-t)*1000); // just to make sure that the camera is started
}
LOGE("To use CameraMobile::updateOnRender(), CameraMobile::updateDataOnRender() "
"should be overridden by inherited classes. Returning empty data!\n");
return SensorData();
}
void CameraMobile::mainLoop()
void CameraMobile::postUpdate()
{
CameraInfo info;
SensorData data = this->captureImage(&info);
if(data.isValid() && !info.odomPose.isNull())
if(data_.isValid())
{
if(lastKnownGPS_.stamp() > 0.0 && data.stamp()-lastKnownGPS_.stamp()<1.0)
if(lastKnownGPS_.stamp() > 0.0 && data_.stamp()-lastKnownGPS_.stamp()<1.0)
{
data.setGPS(lastKnownGPS_);
data_.setGPS(lastKnownGPS_);
}
else if(lastKnownGPS_.stamp()>0.0)
{
LOGD("GPS too old (current time=%f, gps time = %f)", data.stamp(), lastKnownGPS_.stamp());
LOGD("GPS too old (current time=%f, gps time = %f)", data_.stamp(), lastKnownGPS_.stamp());
}
if(lastEnvSensors_.size())
{
data.setEnvSensors(lastEnvSensors_);
data_.setEnvSensors(lastEnvSensors_);
lastEnvSensors_.clear();
}
if(smoothing_ && !data.depthRaw().empty())
if(smoothing_ && !data_.depthRaw().empty())
{
//UTimer t;
data.setDepthOrRightRaw(rtabmap::util2d::fastBilateralFiltering(data.depthRaw(), bilateralFilteringSigmaS, bilateralFilteringSigmaR));
data_.setDepthOrRightRaw(rtabmap::util2d::fastBilateralFiltering(data_.depthRaw(), bilateralFilteringSigmaS, bilateralFilteringSigmaR));
//LOGD("Bilateral filtering, time=%fs", t.ticks());
}
@@ -273,15 +336,15 @@ void CameraMobile::mainLoop()
{
UDEBUG("ROTATION_90");
cv::Mat rgb, depth;
cv::Mat rgbt(data.imageRaw().cols, data.imageRaw().rows, data.imageRaw().type());
cv::flip(data.imageRaw(),rgb,1);
cv::Mat rgbt(data_.imageRaw().cols, data_.imageRaw().rows, data_.imageRaw().type());
cv::flip(data_.imageRaw(),rgb,1);
cv::transpose(rgb,rgbt);
rgb = rgbt;
cv::Mat deptht(data.depthRaw().cols, data.depthRaw().rows, data.depthRaw().type());
cv::flip(data.depthRaw(),depth,1);
cv::Mat deptht(data_.depthRaw().cols, data_.depthRaw().rows, data_.depthRaw().type());
cv::flip(data_.depthRaw(),depth,1);
cv::transpose(depth,deptht);
depth = deptht;
CameraModel model = data.cameraModels()[0];
CameraModel model = data_.cameraModels()[0];
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(
model.fy(),
@@ -290,25 +353,25 @@ void CameraMobile::mainLoop()
model.cx()>0?model.imageWidth()-model.cx():0,
model.localTransform()*rtabmap::Transform(0,-1,0,0, 1,0,0,0, 0,0,1,0));
model.setImageSize(sizet);
data.setRGBDImage(rgb, depth, model);
data_.setRGBDImage(rgb, depth, model);
std::vector<cv::KeyPoint> keypoints = data.keypoints();
std::vector<cv::KeyPoint> keypoints = data_.keypoints();
for(size_t i=0; i<keypoints.size(); ++i)
{
keypoints[i].pt.x = data.keypoints()[i].pt.y;
keypoints[i].pt.y = rgb.rows - data.keypoints()[i].pt.x;
keypoints[i].pt.x = data_.keypoints()[i].pt.y;
keypoints[i].pt.y = rgb.rows - data_.keypoints()[i].pt.x;
}
data.setFeatures(keypoints, data.keypoints3D(), cv::Mat());
data_.setFeatures(keypoints, data_.keypoints3D(), cv::Mat());
}
else if(colorCameraToDisplayRotation_ == ROTATION_180)
{
UDEBUG("ROTATION_180");
cv::Mat rgb, depth;
cv::flip(data.imageRaw(),rgb,1);
cv::flip(data_.imageRaw(),rgb,1);
cv::flip(rgb,rgb,0);
cv::flip(data.depthOrRightRaw(),depth,1);
cv::flip(data_.depthOrRightRaw(),depth,1);
cv::flip(depth,depth,0);
CameraModel model = data.cameraModels()[0];
CameraModel model = data_.cameraModels()[0];
cv::Size sizet(model.imageWidth(), model.imageHeight());
model = CameraModel(
model.fx(),
@@ -317,26 +380,26 @@ void CameraMobile::mainLoop()
model.cy()>0?model.imageHeight()-model.cy():0,
model.localTransform()*rtabmap::Transform(0,0,0,0,0,1,0));
model.setImageSize(sizet);
data.setRGBDImage(rgb, depth, model);
data_.setRGBDImage(rgb, depth, model);
std::vector<cv::KeyPoint> keypoints = data.keypoints();
std::vector<cv::KeyPoint> keypoints = data_.keypoints();
for(size_t i=0; i<keypoints.size(); ++i)
{
keypoints[i].pt.x = rgb.cols - data.keypoints()[i].pt.x;
keypoints[i].pt.y = rgb.rows - data.keypoints()[i].pt.y;
keypoints[i].pt.x = rgb.cols - data_.keypoints()[i].pt.x;
keypoints[i].pt.y = rgb.rows - data_.keypoints()[i].pt.y;
}
data.setFeatures(keypoints, data.keypoints3D(), cv::Mat());
data_.setFeatures(keypoints, data_.keypoints3D(), cv::Mat());
}
else if(colorCameraToDisplayRotation_ == ROTATION_270)
{
UDEBUG("ROTATION_270");
cv::Mat rgb(data.imageRaw().cols, data.imageRaw().rows, data.imageRaw().type());
cv::transpose(data.imageRaw(),rgb);
cv::Mat rgb(data_.imageRaw().cols, data_.imageRaw().rows, data_.imageRaw().type());
cv::transpose(data_.imageRaw(),rgb);
cv::flip(rgb,rgb,1);
cv::Mat depth(data.depthOrRightRaw().cols, data.depthOrRightRaw().rows, data.depthOrRightRaw().type());
cv::transpose(data.depthOrRightRaw(),depth);
cv::Mat depth(data_.depthOrRightRaw().cols, data_.depthOrRightRaw().rows, data_.depthOrRightRaw().type());
cv::transpose(data_.depthOrRightRaw(),depth);
cv::flip(depth,depth,1);
CameraModel model = data.cameraModels()[0];
CameraModel model = data_.cameraModels()[0];
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(
model.fy(),
@@ -345,61 +408,54 @@ void CameraMobile::mainLoop()
model.cx(),
model.localTransform()*rtabmap::Transform(0,1,0,0, -1,0,0,0, 0,0,1,0));
model.setImageSize(sizet);
data.setRGBDImage(rgb, depth, model);
data_.setRGBDImage(rgb, depth, model);
std::vector<cv::KeyPoint> keypoints = data.keypoints();
std::vector<cv::KeyPoint> keypoints = data_.keypoints();
for(size_t i=0; i<keypoints.size(); ++i)
{
keypoints[i].pt.x = rgb.cols - data.keypoints()[i].pt.y;
keypoints[i].pt.y = data.keypoints()[i].pt.x;
keypoints[i].pt.x = rgb.cols - data_.keypoints()[i].pt.y;
keypoints[i].pt.y = data_.keypoints()[i].pt.x;
}
data.setFeatures(keypoints, data.keypoints3D(), cv::Mat());
data_.setFeatures(keypoints, data_.keypoints3D(), cv::Mat());
}
rtabmap::Transform pose = info.odomPose;
data.setGroundTruth(Transform());
// convert stamp to epoch
bool firstFrame = previousPose_.isNull();
if(firstFrame)
{
stampEpochOffset_ = UTimer::now()-data.stamp();
}
data.setStamp(stampEpochOffset_ + data.stamp());
OdometryInfo info;
if(!firstFrame)
{
info.interval = data.stamp()-previousStamp_;
info.transform = previousPose_.inverse() * pose;
}
// linear cov = 0.0001
info.reg.covariance = cv::Mat::eye(6,6,CV_64FC1) * (firstFrame?9999.0:0.0001);
if(!firstFrame)
{
// angular cov = 0.000001
info.reg.covariance.at<double>(3,3) *= 0.01;
info.reg.covariance.at<double>(4,4) *= 0.01;
info.reg.covariance.at<double>(5,5) *= 0.01;
}
LOGI("Publish odometry message (variance=%f)", firstFrame?9999:0.0001);
this->post(new OdometryEvent(data, pose, info));
previousPose_ = pose;
previousStamp_ = data.stamp();
}
else if(!this->isKilled() && info.odomPose.isNull())
{
LOGW("Odometry lost");
this->post(new OdometryEvent());
}
}
SensorData CameraMobile::captureImage(CameraInfo * info)
SensorData CameraMobile::captureImage(SensorCaptureInfo * info)
{
if(info)
SensorData data;
if(dataReady_.acquire(1, 5000))
{
info->odomPose = pose_;
UScopeMutex lock(dataMutex_);
data = data_;
data_ = SensorData();
}
return data_;
if(data.isValid())
{
data.setGroundTruth(Transform());
data.setStamp(stampEpochOffset_ + data.stamp());
if(info)
{
// linear cov = 0.0001
info->odomCovariance = cv::Mat::eye(6,6,CV_64FC1) * (firstFrame_?9999.0:0.0001);
if(!firstFrame_)
{
// angular cov = 0.000001
info->odomCovariance.at<double>(3,3) *= 0.01;
info->odomCovariance.at<double>(4,4) *= 0.01;
info->odomCovariance.at<double>(5,5) *= 0.01;
}
info->odomPose = dataPose_;
}
firstFrame_ = false;
}
else
{
UWARN("CameraMobile::captureImage() invalid data!");
}
return data;
}
LaserScan CameraMobile::scanFromPointCloudData(

View File

@@ -68,7 +68,7 @@ private:
Transform pose_;
};
class CameraMobile : public Camera, public UThread, public UEventsSender {
class CameraMobile : public Camera, public UEventsSender {
public:
static const float bilateralFilteringSigmaS;
static const float bilateralFilteringSigmaR;
@@ -93,14 +93,20 @@ public:
// abstract functions
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
virtual void close(); // inherited classes should call its parent in their close().
virtual void close(); // inherited classes should call its parent at the end of their close().
virtual std::string getSerial() const {return "CameraMobile";}
void update(const SensorData & data, const Transform & pose, const glm::mat4 & viewMatrix, const glm::mat4 & projectionMatrix, const float * texCoord);
void updateOnRender();
const Transform & getOriginOffset() const {return originOffset_;} // in rtabmap frame
void resetOrigin();
virtual bool isCalibrated() const;
void poseReceived(const Transform & pose); // in rtabmap frame
virtual bool odomProvided() const { return true; }
virtual bool getPose(double epochStamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.06); // Return pose of device in rtabmap frame (with origin offset), stamp should be epoch time
void poseReceived(const Transform & pose, double deviceStamp); // original pose of device in rtabmap frame (without origin offset), stamp of the device (may be not epoch)
double getStampEpochOffset() const {return stampEpochOffset_;}
const CameraModel & getCameraModel() const {return model_;}
const Transform & getDeviceTColorCamera() const {return deviceTColorCamera_;}
@@ -108,10 +114,7 @@ public:
virtual void setScreenRotationAndSize(ScreenRotation colorCameraToDisplayRotation, int width, int height) {colorCameraToDisplayRotation_ = colorCameraToDisplayRotation;}
void setGPS(const GPS & gps);
void addEnvSensor(int type, float value);
void setData(const SensorData & data, const Transform & pose, const glm::mat4 & viewMatrix, const glm::mat4 & projectionMatrix, const float * texCoord);
void spinOnce(); // Should only be called if not thread is not running, otherwise it does nothing
GLuint getTextureId() {return textureId_;}
bool uvsInitialized() const {return uvs_initialized_;}
const float* uvsTransformed() const {return transformed_uvs_;}
@@ -122,17 +125,15 @@ public:
const cv::Mat & getOcclusionImage(CameraModel * model=0) const {if(model)*model=occlusionModel_; return occlusionImage_; }
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual void capturePoseOnly() {}
virtual SensorData updateDataOnRender(Transform & pose);
virtual void mainLoopBegin();
virtual void mainLoop();
private:
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
void postUpdate(); // Should be called while being protected by dataMutex_
protected:
CameraModel model_; // local transform is the device to camera optical rotation in rtabmap frame
Transform deviceTColorCamera_; // device to camera optical rotation in rtabmap frame
UTimer spinOnceFrameRateTimer_;
double spinOncePreviousStamp_;
GLuint textureId_;
glm::mat4 viewMatrix_;
@@ -141,9 +142,7 @@ protected:
bool uvs_initialized_ = false;
private:
Transform previousPose_;
double previousStamp_;
UTimer cameraStartedTime_;
bool firstFrame_;
double stampEpochOffset_;
bool smoothing_;
ScreenRotation colorCameraToDisplayRotation_;
@@ -152,8 +151,13 @@ private:
Transform originOffset_;
bool originUpdate_;
USemaphore dataReady_;
UMutex dataMutex_;
SensorData data_;
Transform pose_;
Transform dataPose_;
UMutex poseMutex_;
std::map<double, Transform> poseBuffer_; // <stamp, Pose>
cv::Mat occlusionImage_;
CameraModel occlusionModel_;

View File

@@ -101,7 +101,7 @@ void onPoseAvailableRouter(void* context, const TangoPoseData* pose)
if(pose->status_code == TANGO_POSE_VALID)
{
CameraTango* app = static_cast<CameraTango*>(context);
app->poseReceived(rtabmap_world_T_tango_world * app->tangoPoseToTransform(pose) * tango_device_T_rtabmap_world);
app->poseReceived(rtabmap_world_T_tango_world * app->tangoPoseToTransform(pose) * tango_device_T_rtabmap_world, pose->timestamp);
}
}
@@ -444,7 +444,7 @@ void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
//LOGD("Depth received! %fs (%d points)", timestamp, cloud.cols);
UASSERT(cloud.type() == CV_32FC4);
boost::mutex::scoped_lock lock(dataMutex_);
boost::mutex::scoped_lock lock(tangoDataMutex_);
// From post: http://stackoverflow.com/questions/29236110/timing-issues-with-tango-image-frames
// "In the current version of Project Tango Tablet RGB IR camera
@@ -463,7 +463,7 @@ void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
if(dt >= 0.0 && dt < 0.5)
{
bool notify = !data_.isValid();
bool notify = !tangoData_.isValid();
cv::Mat tangoImage = tangoColor_;
cv::Mat rgb;
@@ -495,7 +495,7 @@ void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
else
{
LOGE("Not supported color format : %d.", tangoColorType);
data_ = SensorData();
tangoData_ = SensorData();
return;
}
@@ -678,24 +678,24 @@ void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
if(rawScanPublished_)
{
data_ = SensorData(LaserScan::backwardCompatibility(scan, cloud.total()/scanDownsampling, 0, scanLocalTransform), rgb, depth, model, this->getNextSeqID(), rgbStamp);
tangoData_ = SensorData(LaserScan::backwardCompatibility(scan, cloud.total()/scanDownsampling, 0, scanLocalTransform), rgb, depth, model, this->getNextSeqID(), rgbStamp);
}
else
{
data_ = SensorData(rgb, depth, model, this->getNextSeqID(), rgbStamp);
tangoData_ = SensorData(rgb, depth, model, this->getNextSeqID(), rgbStamp);
}
data_.setGroundTruth(odom);
tangoData_.setGroundTruth(odom);
}
else
{
LOGE("Could not get depth and rgb images!?!");
data_ = SensorData();
tangoData_ = SensorData();
return;
}
if(notify)
{
dataReady_.release();
tangoDataReady_.release();
}
LOGD("process cloud received %fs", timer.ticks());
}
@@ -709,7 +709,7 @@ void CameraTango::rgbReceived(const cv::Mat & tangoImage, int type, double times
{
//LOGD("RGB received! %fs", timestamp);
boost::mutex::scoped_lock lock(dataMutex_);
boost::mutex::scoped_lock lock(tangoDataMutex_);
tangoColor_ = tangoImage.clone();
tangoColorStamp_ = timestamp;
@@ -775,10 +775,11 @@ rtabmap::Transform CameraTango::getPoseAtTimestamp(double timestamp)
return pose;
}
SensorData CameraTango::captureImage(CameraInfo * info)
SensorData CameraTango::updateDataOnRender(Transform & pose)
{
//LOGI("Capturing image...");
pose.setNull();
if(textureId_ == 0)
{
glGenTextures(1, &textureId_);
@@ -797,10 +798,7 @@ SensorData CameraTango::captureImage(CameraInfo * info)
if (status == TANGO_SUCCESS)
{
if(info)
{
info->odomPose = getPoseAtTimestamp(video_overlay_timestamp);
}
pose = getPoseAtTimestamp(video_overlay_timestamp);
int rotation = static_cast<int>(getScreenRotation()) + 1; // remove 90deg camera rotation
if (rotation > 3) {
@@ -876,16 +874,13 @@ SensorData CameraTango::captureImage(CameraInfo * info)
}
SensorData data;
if(dataReady_.acquireTry(1))
if(tangoDataReady_.acquireTry(1))
{
boost::mutex::scoped_lock lock(dataMutex_);
data = data_;
data_ = SensorData();
if(info)
{
info->odomPose = data.groundTruth();
data.setGroundTruth(Transform());
}
boost::mutex::scoped_lock lock(tangoDataMutex_);
data = tangoData_;
tangoData_ = SensorData();
pose = data.groundTruth();
data.setGroundTruth(Transform());
}
return data;

View File

@@ -52,7 +52,6 @@ public:
virtual void close(); // close Tango connection
virtual std::string getSerial() const;
rtabmap::Transform tangoPoseToTransform(const TangoPoseData * tangoPose) const;
void setColorCamera(bool enabled) {if(!this->isRunning()) colorCamera_ = enabled;}
void setDecimation(int value) {decimation_ = value;}
void setRawScanPublished(bool enabled) {rawScanPublished_ = enabled;}
@@ -61,7 +60,7 @@ public:
void tangoEventReceived(int type, const char * key, const char * value);
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData updateDataOnRender(Transform & pose);
private:
rtabmap::Transform getPoseAtTimestamp(double timestamp);
@@ -71,12 +70,12 @@ private:
bool colorCamera_;
int decimation_;
bool rawScanPublished_;
SensorData data_;
SensorData tangoData_;
cv::Mat tangoColor_;
int tangoColorType_;
double tangoColorStamp_;
boost::mutex dataMutex_;
USemaphore dataReady_;
boost::mutex tangoDataMutex_;
USemaphore tangoDataReady_;
cv::Mat fisheyeRectifyMapX_;
cv::Mat fisheyeRectifyMapY_;
};

View File

@@ -65,6 +65,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/GainCompensator.h>
#include <rtabmap/core/DBDriver.h>
#include <rtabmap/core/Recovery.h>
#include <rtabmap/core/lidar/LidarVLP16.h>
#include <pcl/common/common.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/io/ply_io.h>
@@ -134,6 +135,7 @@ rtabmap::ParametersMap RTABMapApp::getRtabmapParameters()
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kRtabmapPublishLikelihood(), std::string("false")));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kRtabmapPublishPdf(), std::string("false")));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kRtabmapStartNewMapOnLoopClosure(), uBool2Str(!localizationMode_ && appendMode_)));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kRGBDAggressiveLoopThr(), "0.0"));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kMemBinDataKept(), uBool2Str(!trajectoryMode_)));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kOptimizerIterations(), "10"));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kMemIncrementalMemory(), uBool2Str(!localizationMode_)));
@@ -202,6 +204,7 @@ RTABMapApp::RTABMapApp() :
#endif
cameraDriver_(0),
camera_(0),
sensorCaptureThread_(0),
rtabmapThread_(0),
rtabmap_(0),
logHandler_(0),
@@ -216,6 +219,7 @@ RTABMapApp::RTABMapApp() :
cameraColor_(true),
fullResolution_(false),
appendMode_(true),
useExternalLidar_(false),
maxCloudDepth_(2.5),
minCloudDepth_(0.0),
cloudDensityLevel_(1),
@@ -537,7 +541,7 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
// Voxelize and filter depending on the previous cloud?
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
pcl::IndicesPtr indices(new std::vector<int>);
if(!data.imageRaw().empty() && !data.depthRaw().empty())
if(!data.imageRaw().empty() && !data.depthRaw().empty() && (!useExternalLidar_ || data.laserScanRaw().isEmpty()))
{
int meshDecimation = updateMeshDecimation(data.depthRaw().cols, data.depthRaw().rows);
@@ -885,7 +889,7 @@ bool RTABMapApp::startCamera()
#endif
LOGW("startCamera() camera driver=%d", cameraDriver_);
boost::mutex::scoped_lock lock(cameraMutex_);
if(cameraDriver_ == 0) // Tango
{
#ifdef RTABMAP_TANGO
@@ -937,6 +941,19 @@ bool RTABMapApp::startCamera()
LOGI("Start camera thread");
cameraJustInitialized_ = true;
if(useExternalLidar_)
{
rtabmap::LidarVLP16 * lidar = new rtabmap::LidarVLP16(boost::asio::ip::address_v4::from_string("192.168.1.201"), 2368, true);
lidar->init();
camera_->setImageRate(0); // if lidar, to get close camera synchronization
sensorCaptureThread_ = new rtabmap::SensorCaptureThread(lidar, camera_, camera_, rtabmap::Transform::getIdentity());
sensorCaptureThread_->setScanParameters(false, 1, 0.0f, 0.0f, 0.0f, 0, 0.0f, 0.0f, true);
}
else
{
sensorCaptureThread_ = new rtabmap::SensorCaptureThread(camera_);
}
sensorCaptureThread_->start();
return true;
}
UERROR("Failed camera initialization!");
@@ -948,13 +965,12 @@ void RTABMapApp::stopCamera()
LOGI("stopCamera()");
{
boost::mutex::scoped_lock lock(cameraMutex_);
if(camera_!=0)
if(sensorCaptureThread_!=0)
{
camera_->join(true);
camera_->close();
delete camera_;
sensorCaptureThread_->join(true);
delete sensorCaptureThread_; // camera_ is closed and deleted inside
sensorCaptureThread_ = 0;
camera_ = 0;
poseBuffer_.clear();
}
}
{
@@ -1241,7 +1257,7 @@ int RTABMapApp::Render()
std::list<rtabmap::RtabmapEvent*> rtabmapEvents;
try
{
if(camera_ == 0)
if(sensorCaptureThread_ == 0)
{
// We are not doing continous drawing, just measure single draw
fpsTime_.restart();
@@ -1272,49 +1288,45 @@ int RTABMapApp::Render()
{
if(cameraDriver_ <= 2)
{
camera_->spinOnce();
camera_->updateOnRender();
}
#ifdef DEBUG_RENDERING_PERFORMANCE
LOGW("Camera spinOnce %fs", time.ticks());
LOGW("Camera updateOnRender %fs", time.ticks());
#endif
if(cameraDriver_ != 2)
if(main_scene_.background_renderer_ == 0 && camera_->getTextureId() != 0)
{
if(main_scene_.background_renderer_ == 0 && camera_->getTextureId() != 0)
main_scene_.background_renderer_ = new BackgroundRenderer();
main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraMobile*)camera_)->getTextureId(), cameraDriver_ <= 2);
}
if(camera_->uvsInitialized())
{
uvsTransformed = ((rtabmap::CameraMobile*)camera_)->uvsTransformed();
((rtabmap::CameraMobile*)camera_)->getVPMatrices(arViewMatrix, arProjectionMatrix);
if(graphOptimization_ && !mapToOdom_.isIdentity())
{
main_scene_.background_renderer_ = new BackgroundRenderer();
main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraMobile*)camera_)->getTextureId(), cameraDriver_ == 0 || cameraDriver_ == 1);
rtabmap::Transform mapCorrection = rtabmap::opengl_world_T_rtabmap_world * mapToOdom_ *rtabmap::rtabmap_world_T_opengl_world;
arViewMatrix = glm::inverse(rtabmap::glmFromTransform(mapCorrection)*glm::inverse(arViewMatrix));
}
if(camera_->uvsInitialized())
{
uvsTransformed = ((rtabmap::CameraMobile*)camera_)->uvsTransformed();
((rtabmap::CameraMobile*)camera_)->getVPMatrices(arViewMatrix, arProjectionMatrix);
if(graphOptimization_ && !mapToOdom_.isIdentity())
{
rtabmap::Transform mapCorrection = rtabmap::opengl_world_T_rtabmap_world * mapToOdom_ *rtabmap::rtabmap_world_T_opengl_world;
arViewMatrix = glm::inverse(rtabmap::glmFromTransform(mapCorrection)*glm::inverse(arViewMatrix));
}
}
if(!visualizingMesh_ && main_scene_.GetCameraType() == tango_gl::GestureCamera::kFirstPerson)
{
rtabmap::CameraModel occlusionModel;
cv::Mat occlusionImage = ((rtabmap::CameraMobile*)camera_)->getOcclusionImage(&occlusionModel);
}
if(!visualizingMesh_ && main_scene_.GetCameraType() == tango_gl::GestureCamera::kFirstPerson)
{
rtabmap::CameraModel occlusionModel;
cv::Mat occlusionImage = ((rtabmap::CameraMobile*)camera_)->getOcclusionImage(&occlusionModel);
if(occlusionModel.isValidForProjection())
{
pcl::IndicesPtr indices(new std::vector<int>);
int meshDecimation = updateMeshDecimation(occlusionImage.cols, occlusionImage.rows);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = rtabmap::util3d::cloudFromDepth(occlusionImage, occlusionModel, meshDecimation, 0, 0, indices.get());
cloud = rtabmap::util3d::transformPointCloud(cloud, rtabmap::opengl_world_T_rtabmap_world*mapToOdom_*occlusionModel.localTransform());
occlusionMesh.cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>());
pcl::copyPointCloud(*cloud, *occlusionMesh.cloud);
occlusionMesh.indices = indices;
occlusionMesh.polygons = rtabmap::util3d::organizedFastMesh(cloud, 1.0*M_PI/180.0, false, meshTrianglePix_);
}
else if(!occlusionImage.empty())
{
UERROR("invalid occlusionModel: %f %f %f %f %dx%d", occlusionModel.fx(), occlusionModel.fy(), occlusionModel.cx(), occlusionModel.cy(), occlusionModel.imageWidth(), occlusionModel.imageHeight());
}
if(occlusionModel.isValidForProjection())
{
pcl::IndicesPtr indices(new std::vector<int>);
int meshDecimation = updateMeshDecimation(occlusionImage.cols, occlusionImage.rows);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = rtabmap::util3d::cloudFromDepth(occlusionImage, occlusionModel, meshDecimation, 0, 0, indices.get());
cloud = rtabmap::util3d::transformPointCloud(cloud, rtabmap::opengl_world_T_rtabmap_world*mapToOdom_*occlusionModel.localTransform());
occlusionMesh.cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>());
pcl::copyPointCloud(*cloud, *occlusionMesh.cloud);
occlusionMesh.indices = indices;
occlusionMesh.polygons = rtabmap::util3d::organizedFastMesh(cloud, 1.0*M_PI/180.0, false, meshTrianglePix_);
}
else if(!occlusionImage.empty())
{
UERROR("invalid occlusionModel: %f %f %f %f %dx%d", occlusionModel.fx(), occlusionModel.fy(), occlusionModel.cx(), occlusionModel.cy(), occlusionModel.imageWidth(), occlusionModel.imageHeight());
}
}
#ifdef DEBUG_RENDERING_PERFORMANCE
@@ -1334,14 +1346,14 @@ int RTABMapApp::Render()
}
}
rtabmap::OdometryEvent odomEvent;
rtabmap::SensorEvent sensorEvent;
{
boost::mutex::scoped_lock lock(odomMutex_);
if(odomEvents_.size())
boost::mutex::scoped_lock lock(sensorMutex_);
if(sensorEvents_.size())
{
LOGI("Process odom events");
odomEvent = odomEvents_.back();
odomEvents_.clear();
LOGI("Process sensor events");
sensorEvent = sensorEvents_.back();
sensorEvents_.clear();
if(cameraJustInitialized_)
{
notifyCameraStarted = true;
@@ -1361,7 +1373,7 @@ int RTABMapApp::Render()
{
main_scene_.SetCameraPose(rtabmap::opengl_world_T_rtabmap_world*pose*rtabmap::optical_T_opengl);
}
if(camera_!=0 && cameraJustInitialized_)
if(sensorCaptureThread_!=0 && cameraJustInitialized_)
{
notifyCameraStarted = true;
cameraJustInitialized_ = false;
@@ -1562,9 +1574,9 @@ int RTABMapApp::Render()
if(clearSceneOnNextRender_)
{
LOGI("Clearing all rendering data...");
odomMutex_.lock();
odomEvents_.clear();
odomMutex_.unlock();
sensorMutex_.lock();
sensorEvents_.clear();
sensorMutex_.unlock();
poseMutex_.lock();
poseEvents_.clear();
@@ -1800,7 +1812,7 @@ int RTABMapApp::Render()
// Voxelize and filter depending on the previous cloud?
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
pcl::IndicesPtr indices(new std::vector<int>);
if(!data.imageRaw().empty() && !data.depthRaw().empty())
if(!data.imageRaw().empty() && !data.depthRaw().empty() && (!useExternalLidar_ || data.laserScanRaw().isEmpty()))
{
int meshDecimation = updateMeshDecimation(data.depthRaw().cols, data.depthRaw().rows);
cloud = rtabmap::util3d::cloudRGBFromSensorData(data, meshDecimation, maxCloudDepth_, minCloudDepth_, indices.get());
@@ -2004,26 +2016,26 @@ int RTABMapApp::Render()
}
else
{
main_scene_.setCloudVisible(-1, odomCloudShown_ && !trajectoryMode_ && camera_!=0);
main_scene_.setCloudVisible(-1, odomCloudShown_ && !trajectoryMode_ && sensorCaptureThread_!=0);
//just process the last one
if(!odomEvent.pose().isNull())
if(!sensorEvent.info().odomPose.isNull())
{
if(odomCloudShown_ && !trajectoryMode_)
{
if((!odomEvent.data().imageRaw().empty() && !odomEvent.data().depthRaw().empty()) || !odomEvent.data().laserScanRaw().isEmpty())
if((!sensorEvent.data().imageRaw().empty() && !sensorEvent.data().depthRaw().empty()) || !sensorEvent.data().laserScanRaw().isEmpty())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
pcl::IndicesPtr indices(new std::vector<int>);
if((!odomEvent.data().imageRaw().empty() && !odomEvent.data().depthRaw().empty()))
if(!sensorEvent.data().imageRaw().empty() && !sensorEvent.data().depthRaw().empty() && (!useExternalLidar_ || sensorEvent.data().laserScanRaw().isEmpty()))
{
int meshDecimation = updateMeshDecimation(odomEvent.data().depthRaw().cols, odomEvent.data().depthRaw().rows);
cloud = rtabmap::util3d::cloudRGBFromSensorData(odomEvent.data(), meshDecimation, maxCloudDepth_, minCloudDepth_, indices.get());
int meshDecimation = updateMeshDecimation(sensorEvent.data().depthRaw().cols, sensorEvent.data().depthRaw().rows);
cloud = rtabmap::util3d::cloudRGBFromSensorData(sensorEvent.data(), meshDecimation, maxCloudDepth_, minCloudDepth_, indices.get());
}
else
{
//scan
cloud = rtabmap::util3d::laserScanToPointCloudRGB(rtabmap::util3d::commonFiltering(odomEvent.data().laserScanRaw(), 1, minCloudDepth_, maxCloudDepth_), odomEvent.data().laserScanRaw().localTransform(), 255, 255, 255);
cloud = rtabmap::util3d::laserScanToPointCloudRGB(rtabmap::util3d::commonFiltering(sensorEvent.data().laserScanRaw(), 1, minCloudDepth_, maxCloudDepth_), sensorEvent.data().laserScanRaw().localTransform(), 255, 255, 255);
indices->resize(cloud->size());
for(unsigned int i=0; i<cloud->size(); ++i)
{
@@ -2034,10 +2046,10 @@ int RTABMapApp::Render()
if(cloud->size() && indices->size())
{
LOGI("Created odom cloud (rgb=%dx%d depth=%dx%d cloud=%dx%d)",
odomEvent.data().imageRaw().cols, odomEvent.data().imageRaw().rows,
odomEvent.data().depthRaw().cols, odomEvent.data().depthRaw().rows,
sensorEvent.data().imageRaw().cols, sensorEvent.data().imageRaw().rows,
sensorEvent.data().depthRaw().cols, sensorEvent.data().depthRaw().rows,
(int)cloud->width, (int)cloud->height);
main_scene_.addCloud(-1, cloud, indices, rtabmap::opengl_world_T_rtabmap_world*mapToOdom_*odomEvent.pose());
main_scene_.addCloud(-1, cloud, indices, rtabmap::opengl_world_T_rtabmap_world*mapToOdom_*sensorEvent.info().odomPose);
main_scene_.setCloudVisible(-1, true);
}
else
@@ -2127,7 +2139,7 @@ int RTABMapApp::Render()
lastPostRenderEventTime_ = UTimer::now();
if(camera_!=0 && lastPoseEventTime_>0.0 && UTimer::now()-lastPoseEventTime_ > 1.0)
if(sensorCaptureThread_!=0 && lastPoseEventTime_>0.0 && UTimer::now()-lastPoseEventTime_ > 1.0)
{
UERROR("TangoPoseEventNotReceived");
UEventsManager::post(new rtabmap::CameraInfoEvent(10, "TangoPoseEventNotReceived", uNumber2Str(UTimer::now()-lastPoseEventTime_, 6)));
@@ -2319,7 +2331,7 @@ void RTABMapApp::setTrajectoryMode(bool enabled)
void RTABMapApp::setGraphOptimization(bool enabled)
{
graphOptimization_ = enabled;
if((camera_ == 0) && rtabmap_ && rtabmap_->getMemory()->getLastWorkingSignature()!=0)
if((sensorCaptureThread_ == 0) && rtabmap_ && rtabmap_->getMemory()->getLastWorkingSignature()!=0)
{
std::map<int, rtabmap::Transform> poses;
std::multimap<int, rtabmap::Link> links;
@@ -3709,19 +3721,12 @@ void RTABMapApp::postCameraPoseEvent(
if(qx==0 && qy==0 && qz==0 && qw==0)
{
// Lost! clear buffer
poseBuffer_.clear();
camera_->resetOrigin(); // we are lost, create new session on next valid frame
return;
}
rtabmap::Transform pose(x,y,z,qx,qy,qz,qw);
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
camera_->poseReceived(pose);
poseBuffer_.insert(std::make_pair(stamp, pose));
if(poseBuffer_.size() > 1000)
{
poseBuffer_.erase(poseBuffer_.begin());
}
camera_->poseReceived(pose, stamp);
}
}
@@ -3833,66 +3838,41 @@ void RTABMapApp::postOdometryEvent(
{
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
rtabmap::Transform poseWithOriginOffset = pose;
if(!camera_->getOriginOffset().isNull())
{
poseWithOriginOffset = camera_->getOriginOffset() * pose;
}
// Registration depth to rgb
if(!outputDepth.empty() && !depthFrame.isNull() && depth_fx!=0 && (rgbFrame != depthFrame || depthStamp!=stamp))
{
UTimer time;
rtabmap::Transform motion = rtabmap::Transform::getIdentity();
if(depthStamp != stamp && !poseBuffer_.empty())
if(depthStamp != stamp)
{
// Interpolate pose
if(!poseBuffer_.empty())
rtabmap::Transform poseDepth;
cv::Mat cov;
if(!camera_->getPose(camera_->getStampEpochOffset()+depthStamp, poseDepth, cov, 0.0))
{
UERROR("Could not find pose at depth stamp %f (epoch=%f rgb=%f)!", depthStamp, camera_->getStampEpochOffset()+depthStamp, stamp);
}
else
{
if(poseBuffer_.rbegin()->first < depthStamp)
{
UWARN("Could not find poses to interpolate at time %f (last is %f)...", depthStamp, poseBuffer_.rbegin()->first);
}
else
{
std::map<double, rtabmap::Transform >::const_iterator iterB = poseBuffer_.lower_bound(depthStamp);
std::map<double, rtabmap::Transform >::const_iterator iterA = iterB;
rtabmap::Transform poseDepth;
if(iterA != poseBuffer_.begin())
{
iterA = --iterA;
}
if(iterB == poseBuffer_.end())
{
iterB = --iterB;
}
if(iterA == iterB && depthStamp == iterA->first)
{
poseDepth = iterA->second;
}
else if(depthStamp >= iterA->first && depthStamp <= iterB->first)
{
poseDepth = iterA->second.interpolate((depthStamp-iterA->first) / (iterB->first-iterA->first), iterB->second);
}
else if(depthStamp < iterA->first)
{
UERROR("Could not find poses to interpolate at image time %f (earliest is %f). Are sensors synchronized?", depthStamp, iterA->first);
}
else
{
UERROR("Could not find poses to interpolate at image time %f (between %f and %f), Are sensors synchronized?", depthStamp, iterA->first, iterB->first);
}
if(!poseDepth.isNull())
{
#ifndef DISABLE_LOG
UDEBUG("poseRGB =%s (stamp=%f)", pose.prettyPrint().c_str(), depthStamp);
UDEBUG("poseDepth=%s (stamp=%f)", poseDepth.prettyPrint().c_str(), depthStamp);
UDEBUG("poseRGB =%s (stamp=%f)", poseWithOriginOffset.prettyPrint().c_str(), stamp);
UDEBUG("poseDepth=%s (stamp=%f)", poseDepth.prettyPrint().c_str(), depthStamp);
#endif
motion = pose.inverse()*poseDepth;
// transform in camera frame
motion = poseWithOriginOffset.inverse()*poseDepth;
// transform in camera frame
#ifndef DISABLE_LOG
UDEBUG("motion=%s", motion.prettyPrint().c_str());
UDEBUG("motion=%s", motion.prettyPrint().c_str());
#endif
motion = rtabmap::CameraModel::opticalRotation().inverse() * motion * rtabmap::CameraModel::opticalRotation();
motion = rtabmap::CameraModel::opticalRotation().inverse() * motion * rtabmap::CameraModel::opticalRotation();
#ifndef DISABLE_LOG
UDEBUG("motion=%s", motion.prettyPrint().c_str());
UDEBUG("motion=%s", motion.prettyPrint().c_str());
#endif
}
}
}
}
rtabmap::Transform rgbToDepth = motion*rgbFrame.inverse()*depthFrame;
@@ -3941,11 +3921,6 @@ void RTABMapApp::postOdometryEvent(
if(!outputDepth.empty())
{
rtabmap::Transform poseWithOriginOffset = pose;
if(!camera_->getOriginOffset().isNull())
{
poseWithOriginOffset = camera_->getOriginOffset() * pose;
}
rtabmap::CameraModel depthModel = model.scaled(float(outputDepth.cols) / float(model.imageWidth()));
depthModel.setLocalTransform(poseWithOriginOffset*model.localTransform());
camera_->setOcclusionImage(outputDepth, depthModel);
@@ -3971,8 +3946,7 @@ void RTABMapApp::postOdometryEvent(
texCoords[5] = t5;
texCoords[6] = t6;
texCoords[7] = t7;
camera_->setData(data, pose, viewMatrixMat, projectionMatrix, main_scene_.GetCameraType() == tango_gl::GestureCamera::kFirstPerson?texCoords:0);
camera_->spinOnce();
camera_->update(data, pose, viewMatrixMat, projectionMatrix, main_scene_.GetCameraType() == tango_gl::GestureCamera::kFirstPerson?texCoords:0);
}
}
}
@@ -3989,17 +3963,17 @@ void RTABMapApp::postOdometryEvent(
bool RTABMapApp::handleEvent(UEvent * event)
{
if(camera_!=0)
if(sensorCaptureThread_!=0)
{
// called from events manager thread, so protect the data
if(event->getClassName().compare("OdometryEvent") == 0)
if(event->getClassName().compare("SensorEvent") == 0)
{
LOGI("Received OdometryEvent!");
if(odomMutex_.try_lock())
LOGI("Received SensorEvent!");
if(sensorMutex_.try_lock())
{
odomEvents_.clear();
odomEvents_.push_back(*((rtabmap::OdometryEvent*)(event)));
odomMutex_.unlock();
sensorEvents_.clear();
sensorEvents_.push_back(*((rtabmap::SensorEvent*)(event)));
sensorMutex_.unlock();
}
}
if(event->getClassName().compare("RtabmapEvent") == 0)

View File

@@ -40,7 +40,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "util.h"
#include "ProgressionStatus.h"
#include <rtabmap/core/SensorCaptureThread.h>
#include <rtabmap/core/RtabmapThread.h>
#include <rtabmap/core/SensorEvent.h>
#include <rtabmap/utilite/UEventsHandler.h>
#include <boost/thread/mutex.hpp>
#include <pcl/pcl_base.h>
@@ -209,6 +211,7 @@ class RTABMapApp : public UEventsHandler {
private:
int cameraDriver_;
rtabmap::CameraMobile * camera_;
rtabmap::SensorCaptureThread * sensorCaptureThread_;
rtabmap::RtabmapThread * rtabmapThread_;
rtabmap::Rtabmap * rtabmap_;
rtabmap::LogHandler * logHandler_;
@@ -224,6 +227,7 @@ class RTABMapApp : public UEventsHandler {
bool cameraColor_;
bool fullResolution_;
bool appendMode_;
bool useExternalLidar_;
float maxCloudDepth_;
float minCloudDepth_;
int cloudDensityLevel_;
@@ -270,16 +274,15 @@ class RTABMapApp : public UEventsHandler {
UTimer fpsTime_;
std::list<rtabmap::RtabmapEvent*> rtabmapEvents_;
std::list<rtabmap::OdometryEvent> odomEvents_;
std::list<rtabmap::SensorEvent> sensorEvents_;
std::list<rtabmap::Transform> poseEvents_;
std::map<double, rtabmap::Transform> poseBuffer_;
rtabmap::Transform mapToOdom_;
boost::mutex cameraMutex_;
boost::mutex rtabmapMutex_;
boost::mutex meshesMutex_;
boost::mutex odomMutex_;
boost::mutex sensorMutex_;
boost::mutex poseMutex_;
boost::mutex renderingMutex_;

View File

@@ -155,7 +155,7 @@ void BackgroundRenderer::InitializeGlContent(GLuint textureId, bool oes)
}
void BackgroundRenderer::Draw(const float * transformed_uvs, const GLuint & depthTexture, int screenWidth, int screenHeight, bool redUnknown) {
static_assert(std::extent<decltype(BackgroundRenderer_kVertices)>::value == kNumVertices * 2, "Incorrect kVertices length");
static_assert(std::extent<decltype(BackgroundRenderer_kVerticesDevice)>::value == kNumVertices * 2, "Incorrect kVertices length");
GLuint program = shaderPrograms_[depthTexture>0?1:0];
@@ -170,7 +170,7 @@ void BackgroundRenderer::Draw(const float * transformed_uvs, const GLuint & dept
else
#endif
glBindTexture(GL_TEXTURE_2D, texture_id_);
if(depthTexture>0)
{
// Texture activate unit 1
@@ -191,7 +191,7 @@ void BackgroundRenderer::Draw(const float * transformed_uvs, const GLuint & dept
GLuint attributeVertices = glGetAttribLocation(program, "a_Position");
GLuint attributeUvs = glGetAttribLocation(program, "a_TexCoord");
glVertexAttribPointer(attributeVertices, 2, GL_FLOAT, GL_FALSE, 0, BackgroundRenderer_kVertices);
glVertexAttribPointer(attributeVertices, 2, GL_FLOAT, GL_FALSE, 0, BackgroundRenderer_kVerticesDevice);
glVertexAttribPointer(attributeUvs, 2, GL_FLOAT, GL_FALSE, 0, transformed_uvs?transformed_uvs:BackgroundRenderer_kTexCoord);
glEnableVertexAttribArray(attributeVertices);

View File

@@ -28,9 +28,15 @@
#include "util.h"
static const GLfloat BackgroundRenderer_kVertices[] = {
static const GLfloat BackgroundRenderer_kVerticesDevice[] = {
-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f,
};
//static const GLfloat BackgroundRenderer_kVerticesView[] = {
// 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
//};
static const GLfloat BackgroundRenderer_kVerticesView[] = {
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};
static const GLfloat BackgroundRenderer_kTexCoord[] = {
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
};

View File

@@ -1 +1,4 @@
*.jar
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@@ -84,7 +84,7 @@
<string name="pref_key_depth_from_motion">pref_key_depth_from_motion</string>
<string name="pref_default_depth_from_motion">false</string>
<string name="pref_key_arcore_localization_filtering_speed">pref_key_arcore_localization_filtering_speed</string>
<string name="pref_default_arcore_localization_filtering_speed">1</string>
<string name="pref_default_arcore_localization_filtering_speed">0</string>
<string name="pref_key_update_rate">pref_key_update_rate</string>
<string name="pref_default_update_rate">1</string>
<string name="pref_key_max_speed">pref_key_max_speed</string>

View File

@@ -115,6 +115,9 @@ public class ARCoreSharedCamera {
// Image reader that continuously processes CPU images.
public TOF_ImageReader mTOFImageReader = new TOF_ImageReader();
private boolean mTOFAvailable = false;
ByteBuffer mPreviousDepth = null;
double mPreviousDepthStamp = 0.0;
public boolean isDepthSupported() {return mTOFAvailable;}
@@ -698,6 +701,7 @@ public class ARCoreSharedCamera {
mToast.setText(msg);
}
previousAnchorPose = null;
arCoreCorrection = Pose.IDENTITY;
}
}
});
@@ -718,7 +722,8 @@ public class ARCoreSharedCamera {
final double speed = Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])/((double)(frame.getTimestamp()-previousAnchorTimeStamp)/10e8);
if(speed>=mARCoreLocalizationFilteringSpeed)
{
arCoreCorrection = arCoreCorrection.compose(previousAnchorPose).compose(pose.inverse());
// Only correct the translation to not lose rotation aligned with gravity
arCoreCorrection = arCoreCorrection.compose(previousAnchorPose.compose(pose.inverse()).extractTranslation());
t = arCoreCorrection.getTranslation();
Log.e(TAG, String.format("POTENTIAL TELEPORTATION!!!!!!!!!!!!!! previous anchor moved (speed=%f), new arcorrection: %f %f %f", speed, t[0], t[1], t[2]));
@@ -744,7 +749,6 @@ public class ARCoreSharedCamera {
{
mToast.setText(msg);
}
previousAnchorPose = null;
}
}
});
@@ -755,9 +759,8 @@ public class ARCoreSharedCamera {
previousAnchorTimeStamp = frame.getTimestamp();
double stamp = (double)frame.getTimestamp()/10e8;
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("pose=%f %f %f q=%f %f %f %f stamp=%f", odomPose.tx(), odomPose.ty(), odomPose.tz(), odomPose.qx(), odomPose.qy(), odomPose.qz(), odomPose.qw(), stamp));
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("pose=%f %f %f arcore %f %f %f cor= %f %f %f stamp=%f", odomPose.tx(), odomPose.ty(), odomPose.tz(), pose.tx(), pose.ty(), pose.tz(), arCoreCorrection.tx(), arCoreCorrection.ty(), arCoreCorrection.tz(), stamp));
RTABMapLib.postCameraPoseEvent(RTABMapActivity.nativeApplication, odomPose.tx(), odomPose.ty(), odomPose.tz(), odomPose.qx(), odomPose.qy(), odomPose.qz(), odomPose.qw(), stamp);
CameraIntrinsics intrinsics = camera.getImageIntrinsics();
try{
Image image = frame.acquireCameraImage();
@@ -813,6 +816,12 @@ public class ARCoreSharedCamera {
depth = mTOFImageReader.depth16_raw;
depthStamp = (double)mTOFImageReader.timestamp/10e8;
}
if(mPreviousDepth == null)
{
mPreviousDepth = depth;
mPreviousDepthStamp = depthStamp;
}
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("Depth %dx%d len=%dbytes format=%d stamp=%f",
mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, depth.limit(), ImageFormat.DEPTH16, depthStamp));
@@ -825,13 +834,17 @@ public class ARCoreSharedCamera {
rgbExtrinsics.tx(), rgbExtrinsics.ty(), rgbExtrinsics.tz(), rgbExtrinsics.qx(), rgbExtrinsics.qy(), rgbExtrinsics.qz(), rgbExtrinsics.qw(),
depthExtrinsics.tx(), depthExtrinsics.ty(), depthExtrinsics.tz(), depthExtrinsics.qx(), depthExtrinsics.qy(), depthExtrinsics.qz(), depthExtrinsics.qw(),
stamp,
depthStamp,
depthStamp>stamp?mPreviousDepthStamp:depthStamp,
y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
depth, depth.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16,
depthStamp>stamp?mPreviousDepth:depth, depthStamp>stamp?mPreviousDepth.limit():depth.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16,
points, points.limit()/4,
viewMatrix[12], viewMatrix[13], viewMatrix[14], quat[1], quat[2], quat[3], quat[0],
p[0], p[5], p[8], p[9], p[10], p[11], p[14],
texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7]);
mPreviousDepthStamp = depthStamp;
mPreviousDepth = depth;
}
else
{

View File

@@ -284,11 +284,11 @@ void setCameraNative(const void *object, int type) {
}
void postCameraPoseEventNative(const void *object,
float x, float y, float z, float qx, float qy, float qz, float qw)
float x, float y, float z, float qx, float qy, float qz, float qw, double stamp)
{
if(object)
{
native(object)->postCameraPoseEvent(x,y,z,qx,qy,qz,qw,0.0);
native(object)->postCameraPoseEvent(x,y,z,qx,qy,qz,qw,stamp);
}
else
{

View File

@@ -67,7 +67,7 @@ bool startCameraNative(const void *object);
void stopCameraNative(const void *object);
void setCameraNative(const void *object, int type);
void postCameraPoseEventNative(const void *object,
float x, float y, float z, float qx, float qy, float qz, float qw);
float x, float y, float z, float qx, float qy, float qz, float qw, double stamp);
void postOdometryEventNative(const void *object,
float x, float y, float z, float qx, float qy, float qz, float qw,
float fx, float fy, float cx, float cy,

View File

@@ -216,18 +216,18 @@ class RTABMap {
setCameraNative(native_rtabmap, Int32(type))
}
func postCameraPoseEvent(pose: simd_float4x4) {
func postCameraPoseEvent(pose: simd_float4x4, stamp: TimeInterval) {
let rotation = GLKMatrix3(
m: (pose[0,0], pose[0,1], pose[0,2],
pose[1,0], pose[1,1], pose[1,2],
pose[2,0], pose[2,1], pose[2,2]))
let quat = GLKQuaternionMakeWithMatrix3(rotation)
postCameraPoseEventNative(native_rtabmap, pose[3,0], pose[3,1], pose[3,2], quat.x, quat.y, quat.z, quat.w)
postCameraPoseEventNative(native_rtabmap, pose[3,0], pose[3,1], pose[3,2], quat.x, quat.y, quat.z, quat.w, stamp)
}
func notifyLost() {
// a null transform will make rtabmap creating a new session
postCameraPoseEventNative(native_rtabmap, 0,0,0,0,0,0,0)
postCameraPoseEventNative(native_rtabmap, 0,0,0,0,0,0,0,0)
}
func postOdometryEvent(frame: ARFrame, orientation: UIInterfaceOrientation, viewport: CGSize) {
@@ -239,7 +239,7 @@ class RTABMap {
let quat = GLKQuaternionMakeWithMatrix3(rotation)
postCameraPoseEventNative(native_rtabmap, pose[3,0], pose[3,1], pose[3,2], quat.x, quat.y, quat.z, quat.w)
postCameraPoseEventNative(native_rtabmap, pose[3,0], pose[3,1], pose[3,2], quat.x, quat.y, quat.z, quat.w, frame.timestamp)
let confMap = frame.sceneDepth?.confidenceMap
let depthMap = frame.sceneDepth?.depthMap

View File

@@ -0,0 +1,25 @@
To reproduce results (based on parameters of this [paper](https://introlab.3it.usherbrooke.ca/mediawiki-introlab/images/b/bc/TRO2013.pdf)):
```
rtabmap-console \
--Rtabmap/StatisticLogged true\
--Rtabmap/StatisticLoggedHeaders false\
--Kp/DetectorStrategy 0\
--Rtabmap/MemoryThr 300\
--Rtabmap/LoopRatio 0.9\
--SURF/HessianThreshold 150\
--Mem/STMSize 30\
--Vis/MaxFeatures 400\
--Kp/TfIdfLikelihoodUsed false\
--Kp/MaxFeatures 400\
--Kp/BadSignRatio 0.25\
--Mem/BadSignaturesIgnored true\
--Mem/RehearsalSimilarity 0.20\
--Mem/RecentWmRatio 0.2\
-gt "~/Downloads/UdeS_1Hz.png"\
~/Downloads/UdeS_1Hz
```
Adding the ground truth file here is optional to show recall at 100% precision at the end of the process directly without using the octave/MATLAB script below. For NewCollege and CityCentre datasets, `rtabmap-imagesJoiner` can be used to assemble the left and right images together.
To analyze with Octave/MATLAB, drop `LogF.txt` and `LogI.txt` generated files from command above in ShowLogs directly, then execute `showLogs.m`.

View File

@@ -1,4 +0,0 @@
This directory contains some basic concepts on Bayes filtering.
Main scripts :
RecursivesBayes.m
RecursivesBayesAvpd.m

View File

@@ -32,8 +32,7 @@ if ~isempty(GroundTruth)
if size(GroundTruth, 1) ~= length(LogF(:,1)) || size(GroundTruth, 1) ~= length(LogI(:,1))
error(['The ground truth size doesn''t match the log files (LogI=' num2str(length(LogI(:,1))) ', LogF=' num2str(length(LogF(:,1))) ', GT=' num2str(size(GroundTruth, 1)) ')'])
end
%[highestHypot, CorrespondingID, GT, Accepted, Good, Index, UnderLoopRatio] descending order
if(sum(LogI(:,8) == 10) > 0)
%OLD
@@ -111,14 +110,14 @@ if ~isempty(GroundTruth)
index = find(PR(:,1) == 1);
if ~isempty(index)
maxRecall = PR(index(end),2) * 100;
display(['Recall max (Precision=100%) = ' num2str(maxRecall) '% (p=' num2str(lc(index(end),1)) '), accepted=' num2str(sum(lc(1:index(end),5) & ~lc(1:index(end),7) & lc(1:index(end),2)))])
display(['Recall max (Precision=100%) = ' num2str(maxRecall) '% (p=' num2str(lc(index(end),1)) '), accepted=' num2str(sum(lc(1:index(end),5) & ~lc(1:index(end),7) & lc(1:index(end),2))) '/' num2str(GT_total_positives)])
else
display('Recall max (Precision=100%) = 0')
end
indexAccepted = find(PR(:,3) == 1);
if ~isempty(indexAccepted)
maxRecall = PR(indexAccepted(end),2) * 100;
display(['Recall max accepted (Precision=100%) = ' num2str(maxRecall) '% (p=' num2str(lc(indexAccepted(end),1)) '), accepted=' num2str(sum(lc(1:indexAccepted(end),5) & ~lc(1:indexAccepted(end),7) & lc(1:indexAccepted(end),2)))])
display(['Recall max accepted (Precision=100%) = ' num2str(maxRecall) '% (p=' num2str(lc(indexAccepted(end),1)) '), accepted=' num2str(sum(lc(1:indexAccepted(end),5) & ~lc(1:indexAccepted(end),7) & lc(1:indexAccepted(end),2))) '/' num2str(GT_total_positives)])
else
display('Recall max accepted (Precision=100%) = 0')
end

View File

@@ -22,6 +22,8 @@ function [LogF LogI] = showlogs(PathPrefix, GT_file)
set(0,'defaultAxesFontName', 'Times')
set(0,'defaultTextFontName', 'Times')
close all
if nargin < 2, GT_file = ''; end
if nargin < 1, PathPrefix = '.'; end
@@ -325,7 +327,7 @@ y(LogI(:, 1) == 0) = [];
x(LogI(:, 1) == 0) = [];
plot(x,y, 'g.')
set(datacursormode,'UpdateFcn',@(Y,X){sprintf('X: %0.2f',X.Position(1)),sprintf('Y: %0.2f',X.Position(2))})
%set(datacursormode,'UpdateFcn',@(Y,X){sprintf('X: %0.2f',X.Position(1)),sprintf('Y: %0.2f',X.Position(2))})
% %matched sign words
% y = LogI(:,2);
% x = 1:length(y);

View File

@@ -0,0 +1,8 @@
#!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
$SCRIPT_DIR/run_bow.sh ~/loop_closure_detection_datasets/NewCollege ~/loop_closure_detection_datasets/NewCollege.png
$SCRIPT_DIR/run_bow.sh ~/loop_closure_detection_datasets/CityCentre ~/loop_closure_detection_datasets/CityCentre.png
$SCRIPT_DIR/run_bow.sh ~/loop_closure_detection_datasets/UdeS_1Hz ~/loop_closure_detection_datasets/UdeS_1Hz.png

View File

@@ -0,0 +1,32 @@
#!/bin/bash
DATASET_FOLDER=""
GT_FILE=""
if [ $# -eq 2 ]
then
DATASET_FOLDER=$1
GT_FILE=$2
else
echo "Usage: run_bow.sh \"dataset folder\" \"ground truth file\""
exit
fi
rtabmap-console \
-quiet \
--Rtabmap/StatisticLogged true\
--Rtabmap/StatisticLoggedHeaders false\
--Kp/DetectorStrategy 0\
--SURF/HessianThreshold 150\
--Rtabmap/MemoryThr 300\
--Rtabmap/LoopRatio 0.9\
--Mem/STMSize 30\
--Vis/MaxFeatures 400\
--Kp/TfIdfLikelihoodUsed false\
--Kp/MaxFeatures 400\
--Kp/BadSignRatio 0.25\
--Mem/BadSignaturesIgnored true\
--Mem/RehearsalSimilarity 0.20\
--Mem/RecentWmRatio 0.20\
-gt "$GT_FILE"\
"$DATASET_FOLDER"

View File

@@ -25,14 +25,14 @@ The following image shows when we do the same localization experiment at differe
We provide two formats: the first one is more general and the second one is used to produce the results in this paper with RTAB-Map. Please open issue if the links are outdated.
* [Images](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EV8F4PZUxOxLhwAyEehlzKwBjF-9xNuxR32Q4mUjx5u-rA?e=eCJ3TW):
* [Images](https://drive.google.com/file/d/1fUm1m8oW6q8qlThx7BjrBH2vrVbNQ9bQ/view?usp=drive_link):
* `rgb`: folder containing *.jpg color camera images
* `depth`: folder containing *.png 16bits mm depth images
* `calib`: folder containing calibration for each color image. Each calibration contains also the transform between `device` and `camera` frames as `local_transform`.
* `device_poses.txt`: VIO poses of each image in `device` frame
* `camera_poses.txt`: VIO poses of each image in `camera` frame
* [RTAB-Map Databases](https://usherbrooke-my.sharepoint.com/:u:/g/personal/labm2414_usherbrooke_ca/EU5fb0jEKzlGhPK3OWjMGLUBnDo1BRAoZwtB2czyeVLE_A?e=Y0JyXY)
* [RTAB-Map Databases](https://drive.google.com/file/d/1TklUcTKFSrcg8b0t0U80G_IpFRMVRlY5/view?usp=drive_link)
* Dataset now also available on [Federated Research Data Repository (FRDR)](https://doi.org/10.20383/103.0931) (if links above don't work)
## How reproduce results shown in the paper

View File

@@ -1,30 +0,0 @@
# - Find Sqlite3
# This module finds an installed Sqlite3 package.
#
# It sets the following variables:
# Sqlite3_FOUND - Set to false, or undefined, if Sqlite3 isn't found.
# Sqlite3_INCLUDE_DIR - The Sqlite3 include directory.
# Sqlite3_LIBRARY - The Sqlite3 library to link against.
FIND_PATH(Sqlite3_INCLUDE_DIR sqlite3.h PATHS $ENV{Sqlite3_ROOT_DIR}/include $ENV{Sqlite3_ROOT_DIR})
FIND_LIBRARY(Sqlite3_LIBRARY NAMES sqlite3 PATHS $ENV{Sqlite3_ROOT_DIR}/lib $ENV{Sqlite3_ROOT_DIR})
IF (Sqlite3_INCLUDE_DIR AND Sqlite3_LIBRARY)
SET(Sqlite3_FOUND TRUE)
SET(Sqlite3_INCLUDE_DIRS ${Sqlite3_INCLUDE_DIR})
SET(Sqlite3_LIBRARIES ${Sqlite3_LIBRARY})
ENDIF (Sqlite3_INCLUDE_DIR AND Sqlite3_LIBRARY)
IF (Sqlite3_FOUND)
# show which Sqlite3 was found only if not quiet
IF (NOT Sqlite3_FIND_QUIETLY)
MESSAGE(STATUS "Found Sqlite3: ${Sqlite3_INCLUDE_DIRS} ${Sqlite3_LIBRARIES}")
ENDIF (NOT Sqlite3_FIND_QUIETLY)
ELSE (Sqlite3_FOUND)
# fatal error if Sqlite3 is required but not found
IF (Sqlite3_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Sqlite3")
ENDIF (Sqlite3_FIND_REQUIRED)
ENDIF (Sqlite3_FOUND)

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
Copyright (c) 2010-2022, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,47 +28,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <opencv2/highgui/highgui.hpp>
#include "rtabmap/core/SensorData.h"
#include "rtabmap/core/CameraInfo.h"
#include <set>
#include <stack>
#include <list>
#include <vector>
class UDirectory;
class UTimer;
#include <rtabmap/core/SensorCapture.h>
#include <rtabmap/core/IMU.h>
namespace rtabmap
{
class IMUFilter;
/**
* Class Camera
*
*/
class RTABMAP_CORE_EXPORT Camera
class RTABMAP_CORE_EXPORT Camera : public SensorCapture
{
public:
virtual ~Camera();
SensorData takeImage(CameraInfo * info = 0);
SensorData takeImage(SensorCaptureInfo * info = 0) {return takeData(info);}
float getImageRate() const {return getFrameRate();}
void setImageRate(float imageRate) {setFrameRate(imageRate);}
void setInterIMUPublishing(bool enabled, IMUFilter * filter = 0); // Take ownership of filter
bool isInterIMUPublishing() const {return publishInterIMU_;}
bool initFromFile(const std::string & calibrationPath);
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "") = 0;
virtual bool isCalibrated() const = 0;
virtual std::string getSerial() const = 0;
virtual bool odomProvided() const { return false; }
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance) { return false; }
//getters
float getImageRate() const {return _imageRate;}
const Transform & getLocalTransform() const {return _localTransform;}
//setters
void setImageRate(float imageRate) {_imageRate = imageRate;}
void setLocalTransform(const Transform & localTransform) {_localTransform= localTransform;}
void resetTimer();
protected:
/**
* Constructor
@@ -78,19 +63,16 @@ protected:
*/
Camera(float imageRate = 0, const Transform & localTransform = Transform::getIdentity());
/**
* returned rgb and depth images should be already rectified if calibration was loaded
*/
virtual SensorData captureImage(CameraInfo * info = 0) = 0;
virtual SensorData captureImage(SensorCaptureInfo * info = 0) = 0;
int getNextSeqID() {return ++_seq;}
void postInterIMU(const IMU & imu, double stamp);
private:
float _imageRate;
Transform _localTransform;
cv::Size _targetImageSize;
UTimer * _frameRateTimer;
int _seq;
virtual SensorData captureData(SensorCaptureInfo * info = 0) {return captureImage(info);}
private:
IMUFilter * imuFilter_;
bool publishInterIMU_;
};

View File

@@ -27,65 +27,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <rtabmap/utilite/UEvent.h>
#include "rtabmap/core/SensorData.h"
#include "rtabmap/core/CameraInfo.h"
namespace rtabmap
{
class CameraEvent :
public UEvent
{
public:
enum Code {
kCodeData,
kCodeNoMoreImages
};
public:
CameraEvent(const cv::Mat & image, int seq=0, double stamp = 0.0, const std::string & cameraName = std::string()) :
UEvent(kCodeData),
data_(image, seq, stamp)
{
cameraInfo_.cameraName = cameraName;
}
CameraEvent() :
UEvent(kCodeNoMoreImages)
{
}
CameraEvent(const SensorData & data) :
UEvent(kCodeData),
data_(data)
{
}
CameraEvent(const SensorData & data, const std::string & cameraName) :
UEvent(kCodeData),
data_(data)
{
cameraInfo_.cameraName = cameraName;
}
CameraEvent(const SensorData & data, const CameraInfo & cameraInfo) :
UEvent(kCodeData),
data_(data),
cameraInfo_(cameraInfo)
{
}
// Image or descriptors
const SensorData & data() const {return data_;}
const std::string & cameraName() const {return cameraInfo_.cameraName;}
const CameraInfo & info() const {return cameraInfo_;}
virtual ~CameraEvent() {}
virtual std::string getClassName() const {return std::string("CameraEvent");}
private:
SensorData data_;
CameraInfo cameraInfo_;
};
} // namespace rtabmap
#include "rtabmap/core/SensorEvent.h"

View File

@@ -27,50 +27,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <string>
namespace rtabmap
{
class CameraInfo
{
public:
CameraInfo() :
cameraName(""),
id(0),
stamp(0.0),
timeCapture(0.0f),
timeDisparity(0.0f),
timeMirroring(0.0f),
timeStereoExposureCompensation(0.0f),
timeImageDecimation(0.0f),
timeHistogramEqualization(0.0f),
timeScanFromDepth(0.0f),
timeUndistortDepth(0.0f),
timeBilateralFiltering(0.0f),
timeTotal(0.0f),
odomCovariance(cv::Mat::eye(6,6,CV_64FC1))
{
}
virtual ~CameraInfo() {}
std::string cameraName;
int id;
double stamp;
float timeCapture;
float timeDisparity;
float timeMirroring;
float timeStereoExposureCompensation;
float timeImageDecimation;
float timeHistogramEqualization;
float timeScanFromDepth;
float timeUndistortDepth;
float timeBilateralFiltering;
float timeTotal;
Transform odomPose;
cv::Mat odomCovariance;
std::vector<float> odomVelocity;
};
} // namespace rtabmap
#include "rtabmap/core/SensorCaptureInfo.h"

View File

@@ -37,4 +37,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/camera/CameraRealSense2.h>
#include <rtabmap/core/camera/CameraRGBDImages.h>
#include <rtabmap/core/camera/CameraK4A.h>
#include <rtabmap/core/camera/CameraSeerSense.h>

View File

@@ -27,136 +27,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <rtabmap/core/Parameters.h>
#include <rtabmap/core/Transform.h>
#include <rtabmap/utilite/UThread.h>
#include <rtabmap/utilite/UEventsSender.h>
namespace clams
{
class DiscreteDepthDistortionModel;
}
namespace rtabmap
{
class Camera;
class CameraInfo;
class SensorData;
class StereoDense;
class IMUFilter;
class Feature2D;
/**
* Class CameraThread
*
*/
class RTABMAP_CORE_EXPORT CameraThread :
public UThread,
public UEventsSender
{
public:
// ownership transferred
CameraThread(Camera * camera, const ParametersMap & parameters = ParametersMap());
/**
* @param camera the camera to take images from
* @param odomSensor an odometry sensor to get a pose
* @param extrinsics the static transform between odometry sensor's left lens frame to camera's left lens frame
*/
CameraThread(Camera * camera,
Camera * odomSensor,
const Transform & extrinsics,
double poseTimeOffset = 0.0,
float poseScaleFactor = 1.0f,
bool odomAsGt = false,
const ParametersMap & parameters = ParametersMap());
CameraThread(Camera * camera,
bool odomAsGt,
const ParametersMap & parameters = ParametersMap());
virtual ~CameraThread();
void setMirroringEnabled(bool enabled) {_mirroring = enabled;}
void setStereoExposureCompensation(bool enabled) {_stereoExposureCompensation = enabled;}
void setColorOnly(bool colorOnly) {_colorOnly = colorOnly;}
void setImageDecimation(int decimation) {_imageDecimation = decimation;}
void setHistogramMethod(int histogramMethod) {_histogramMethod = histogramMethod;}
void setStereoToDepth(bool enabled) {_stereoToDepth = enabled;}
void setImageRate(float imageRate);
void setDistortionModel(const std::string & path);
void enableBilateralFiltering(float sigmaS, float sigmaR);
void disableBilateralFiltering() {_bilateralFiltering = false;}
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap & parameters = ParametersMap(), bool baseFrameConversion = false);
void disableIMUFiltering();
void enableFeatureDetection(const ParametersMap & parameters = ParametersMap());
void disableFeatureDetection();
// Use new version of this function with groundNormalsUp=0.8 for forceGroundNormalsUp=True and groundNormalsUp=0.0 for forceGroundNormalsUp=False.
RTABMAP_DEPRECATED void setScanParameters(
bool fromDepth,
int downsampleStep, // decimation of the depth image in case the scan is from depth image
float rangeMin,
float rangeMax,
float voxelSize,
int normalsK,
int normalsRadius,
bool forceGroundNormalsUp);
void setScanParameters(
bool fromDepth,
int downsampleStep=1, // decimation of the depth image in case the scan is from depth image
float rangeMin=0.0f,
float rangeMax=0.0f,
float voxelSize = 0.0f,
int normalsK = 0,
int normalsRadius = 0.0f,
float groundNormalsUp = 0.0f);
void postUpdate(SensorData * data, CameraInfo * info = 0) const;
//getters
bool isPaused() const {return !this->isRunning();}
bool isCapturing() const {return this->isRunning();}
bool odomProvided() const;
Camera * camera() {return _camera;} // return null if not set, valid until CameraThread is deleted
Camera * odomSensor() {return _odomSensor;} // return null if not set, valid until CameraThread is deleted
private:
virtual void mainLoopBegin();
virtual void mainLoop();
virtual void mainLoopKill();
private:
Camera * _camera;
Camera * _odomSensor;
Transform _extrinsicsOdomToCamera;
bool _odomAsGt;
double _poseTimeOffset;
float _poseScaleFactor;
bool _mirroring;
bool _stereoExposureCompensation;
bool _colorOnly;
int _imageDecimation;
int _histogramMethod;
bool _stereoToDepth;
bool _scanFromDepth;
int _scanDownsampleStep;
float _scanRangeMin;
float _scanRangeMax;
float _scanVoxelSize;
int _scanNormalsK;
float _scanNormalsRadius;
float _scanForceGroundNormalsUp;
StereoDense * _stereoDense;
clams::DiscreteDepthDistortionModel * _distortionModel;
bool _bilateralFiltering;
float _bilateralSigmaS;
float _bilateralSigmaR;
IMUFilter * _imuFilter;
bool _imuBaseFrameConversion;
Feature2D * _featureDetector;
bool _depthAsMask;
};
} // namespace rtabmap
#include "rtabmap/core/SensorCaptureThread.h"

View File

@@ -82,14 +82,15 @@ public:
virtual bool isCalibrated() const;
virtual std::string getSerial() const;
virtual bool odomProvided() const {return !_odometryIgnored;}
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.06);
const DBDriver * driver() const {return _dbDriver;}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
SensorData getNextData(CameraInfo * info = 0);
SensorData getNextData(SensorCaptureInfo * info = 0);
private:
std::list<std::string> _paths;

View File

@@ -192,16 +192,17 @@ public:
const cv::Mat & disparity,
float minDisparity);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, int maxKeypoints);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, cv::Mat & descriptors, int maxKeypoints);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & keypoints3D, cv::Mat & descriptors, int maxKeypoints);
static void limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints);
static void limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & keypoints3D, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false);
static void limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize = cv::Size(), bool ssc = false);
static void limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols, bool ssc = false);
static cv::Rect computeRoi(const cv::Mat & image, const std::string & roiRatios);
static cv::Rect computeRoi(const cv::Mat & image, const std::vector<float> & roiRatios);
int getMaxFeatures() const {return maxFeatures_;}
bool getSSC() const {return SSC_;}
float getMinDepth() const {return _minDepth;}
float getMaxDepth() const {return _maxDepth;}
int getGridRows() const {return gridRows_;}
@@ -234,6 +235,7 @@ private:
private:
ParametersMap parameters_;
int maxFeatures_;
bool SSC_;
float _maxDepth; // 0=inf
float _minDepth;
std::vector<float> _roiRatios; // size 4

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2010-2020, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
Copyright (c) 2010-2024, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -0,0 +1,73 @@
/*
Copyright (c) 2010-2024, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GLOBAL_DESCRIPTOR_EXTRACTOR_H_
#define GLOBAL_DESCRIPTOR_EXTRACTOR_H_
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/SensorData.h"
namespace rtabmap {
// Feature2D
class RTABMAP_CORE_EXPORT GlobalDescriptorExtractor {
public:
enum Type {
kUndef=0,
kPyDescriptor=1};
static std::string typeName(Type type)
{
switch(type){
case kPyDescriptor:
return "PyDescriptor";
default:
return "Unknown";
}
}
static GlobalDescriptorExtractor * create(const ParametersMap & parameters = ParametersMap());
static GlobalDescriptorExtractor * create(GlobalDescriptorExtractor::Type type, const ParametersMap & parameters = ParametersMap()); // for convenience
public:
virtual ~GlobalDescriptorExtractor();
virtual GlobalDescriptor extract(const SensorData & data) const = 0;
virtual void parseParameters(const ParametersMap & parameters) {}
virtual GlobalDescriptorExtractor::Type getType() const = 0;
protected:
GlobalDescriptorExtractor(const ParametersMap & parameters = ParametersMap());
};
}
#endif /* GLOBAL_DESCRIPTOR_EXTRACTOR_H_ */

View File

@@ -28,12 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CORELIB_INCLUDE_RTABMAP_CORE_IMUFILTER_H_
#define CORELIB_INCLUDE_RTABMAP_CORE_IMUFILTER_H_
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <rtabmap/core/Parameters.h>
#include <Eigen/Geometry>
namespace rtabmap {
class IMUFilter
class RTABMAP_CORE_EXPORT IMUFilter
{
public:
enum Type {

View File

@@ -47,7 +47,8 @@ public:
kXYZRGB=7,
kXYZNormal=8,
kXYZINormal=9,
kXYZRGBNormal=10};
kXYZRGBNormal=10,
kXYZIT=11};
static std::string formatName(const Format & format);
static int channels(const Format & format);
@@ -55,6 +56,7 @@ public:
static bool isScanHasNormals(const Format & format);
static bool isScanHasRGB(const Format & format);
static bool isScanHasIntensity(const Format & format);
static bool isScanHasTime(const Format & format);
static LaserScan backwardCompatibility(
const cv::Mat & oldScanFormat,
int maxPoints = 0,
@@ -121,22 +123,27 @@ public:
float angleMin() const {return angleMin_;}
float angleMax() const {return angleMax_;}
float angleIncrement() const {return angleIncrement_;}
void setLocalTransform(const Transform & t) {localTransform_ = t;}
Transform localTransform() const {return localTransform_;}
bool empty() const {return data_.empty();}
bool isEmpty() const {return data_.empty();}
int size() const {return data_.cols;}
int size() const {return data_.total();}
int dataType() const {return data_.type();}
bool is2d() const {return isScan2d(format_);}
bool hasNormals() const {return isScanHasNormals(format_);}
bool hasRGB() const {return isScanHasRGB(format_);}
bool hasIntensity() const {return isScanHasIntensity(format_);}
bool hasTime() const {return isScanHasTime(format_);}
bool isCompressed() const {return !data_.empty() && data_.type()==CV_8UC1;}
bool isOrganized() const {return data_.rows > 1;}
LaserScan clone() const;
LaserScan densify() const;
int getIntensityOffset() const {return hasIntensity()?(is2d()?2:3):-1;}
int getRGBOffset() const {return hasRGB()?(is2d()?2:3):-1;}
int getNormalsOffset() const {return hasNormals()?(2 + (is2d()?0:1) + ((hasRGB() || hasIntensity())?1:0)):-1;}
int getTimeOffset() const {return hasTime()?4:-1;}
float & field(unsigned int pointIndex, unsigned int channelOffset);

View File

@@ -0,0 +1,57 @@
/*
Copyright (c) 2010-2022, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <rtabmap/core/SensorCapture.h>
namespace rtabmap
{
/**
* Class Lidar
*
*/
class RTABMAP_CORE_EXPORT Lidar : public SensorCapture
{
public:
virtual ~Lidar() {}
protected:
/**
* Constructor
*
* @param lidarRate the frame rate (Hz), 0 for fast as the lidar can
* @param localTransform the transform from base frame to lidar frame
*/
Lidar(float lidarRate = 0, const Transform & localTransform = Transform::getIdentity()) :
SensorCapture(lidarRate, localTransform) {}
};
} // namespace rtabmap

View File

@@ -59,6 +59,7 @@ class RegistrationVis;
class Stereo;
class LocalGridMaker;
class MarkerDetector;
class GlobalDescriptorExtractor;
class RTABMAP_CORE_EXPORT Memory
{
@@ -333,6 +334,7 @@ private:
bool _rotateImagesUpsideUp;
bool _createOccupancyGrid;
int _visMaxFeatures;
bool _visSSC;
bool _imagesAlreadyRectified;
bool _rectifyOnlyFeatures;
bool _covOffDiagonalIgnored;
@@ -375,6 +377,8 @@ private:
LocalGridMaker * _localMapMaker;
MarkerDetector * _markerDetector;
GlobalDescriptorExtractor * _globalDescriptorExtractor;
};
} // namespace rtabmap

View File

@@ -111,6 +111,7 @@ private:
bool _alignWithGround;
bool _publishRAMUsage;
bool _imagesAlreadyRectified;
bool _deskewing;
Transform _pose;
int _resetCurrentCount;
double previousStamp_;

View File

@@ -50,6 +50,7 @@ public:
localBundleConstraints(0),
localBundleTime(0),
keyFrameAdded(false),
timeDeskewing(0.0f),
timeEstimation(0.0f),
timeParticleFiltering(0.0f),
stamp(0),
@@ -76,6 +77,7 @@ public:
output.localBundlePoses = localBundlePoses;
output.localBundleModels = localBundleModels;
output.keyFrameAdded = keyFrameAdded;
output.timeDeskewing = timeDeskewing;
output.timeEstimation = timeEstimation;
output.timeParticleFiltering = timeParticleFiltering;
output.stamp = stamp;
@@ -105,6 +107,7 @@ public:
std::map<int, Transform> localBundlePoses;
std::map<int, std::vector<CameraModel> > localBundleModels;
bool keyFrameAdded;
float timeDeskewing;
float timeEstimation;
float timeParticleFiltering;
double stamp;

View File

@@ -197,6 +197,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Rtabmap, LoopThr, float, 0.11, "Loop closing threshold.");
RTABMAP_PARAM(Rtabmap, LoopRatio, float, 0, "The loop closure hypothesis must be over LoopRatio x lastHypothesisValue.");
RTABMAP_PARAM(Rtabmap, LoopGPS, bool, true, uFormat("Use GPS to filter likelihood (if GPS is recorded). Only locations inside the local radius \"%s\" of the current GPS location are considered for loop closure detection.", kRGBDLocalRadius().c_str()));
RTABMAP_PARAM(Rtabmap, VirtualPlaceLikelihoodRatio, int, 0, "Likelihood ratio for virtual place (for no loop closure hypothesis): 0=Mean / StdDev, 1=StdDev / (Max-Mean)");
// Memory
RTABMAP_PARAM(Mem, RehearsalSimilarity, float, 0.6, "Rehearsal similarity.");
@@ -231,6 +232,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Mem, UseOdomFeatures, bool, true, "Use odometry features instead of regenerating them.");
RTABMAP_PARAM(Mem, UseOdomGravity, bool, false, uFormat("Use odometry instead of IMU orientation to add gravity links to new nodes created. We assume that odometry is already aligned with gravity (e.g., we are using a VIO approach). Gravity constraints are used by graph optimization only if \"%s\" is not zero.", kOptimizerGravitySigma().c_str()));
RTABMAP_PARAM(Mem, CovOffDiagIgnored, bool, true, "Ignore off diagonal values of the covariance matrix.");
RTABMAP_PARAM(Mem, GlobalDescriptorStrategy, int, 0, "Extract global descriptor from sensor data. 0=disabled, 1=PyDescriptor");
RTABMAP_PARAM(Mem, RotateImagesUpsideUp, bool, false, "Rotate images so that upside is up if they are not already. This can be useful in case the robots don't have all same camera orientation but are using the same map, so that not rotation-invariant visual features can still be used across the fleet.");
// KeypointMemory (Keypoint-based)
@@ -242,6 +244,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf).");
RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth.");
RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction).");
RTABMAP_PARAM(Kp, SSC, bool, false, "If true, SSC (Suppression via Square Covering) is applied to limit keypoints.");
RTABMAP_PARAM(Kp, BadSignRatio, float, 0.5, "Bad signature ratio (less than Ratio x AverageWordsPerImage = bad).");
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)");
#if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D)
@@ -354,10 +357,12 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(RGBD, AngularUpdate, float, 0.1, "Minimum angular displacement (rad) to update the map. Rehearsal is done prior to this, so weights are still updated.");
RTABMAP_PARAM(RGBD, LinearSpeedUpdate, float, 0.0, "Maximum linear speed (m/s) to update the map (0 means not limit).");
RTABMAP_PARAM(RGBD, AngularSpeedUpdate, float, 0.0, "Maximum angular speed (rad/s) to update the map (0 means not limit).");
RTABMAP_PARAM(RGBD, AggressiveLoopThr, float, 0.05, uFormat("Loop closure threshold used (overriding %s) when a new mapping session is not yet linked to a map of the highest loop closure hypothesis. In localization mode, this threshold is used when there are no loop closure constraints with any map in the cache (%s). In all cases, the goal is to aggressively loop on a previous map in the database. Only used when %s is enabled. Set 1 to disable.", kRtabmapLoopThr().c_str(), kRGBDMaxOdomCacheSize().c_str(), kRGBDEnabled().c_str()));
RTABMAP_PARAM(RGBD, NewMapOdomChangeDistance, float, 0, "A new map is created if a change of odometry translation greater than X m is detected (0 m = disabled).");
RTABMAP_PARAM(RGBD, OptimizeFromGraphEnd, bool, false, "Optimize graph from the newest node. If false, the graph is optimized from the oldest node of the current graph (this adds an overhead computation to detect to oldest node of the current graph, but it can be useful to preserve the map referential from the oldest node). Warning when set to false: when some nodes are transferred, the first referential of the local map may change, resulting in momentary changes in robot/map position (which are annoying in teleoperation).");
RTABMAP_PARAM(RGBD, OptimizeMaxError, float, 3.0, uFormat("Reject loop closures if optimization error ratio is greater than this value (0=disabled). Ratio is computed as absolute error over standard deviation of each link. This will help to detect when a wrong loop closure is added to the graph. Not compatible with \"%s\" if enabled.", kOptimizerRobust().c_str()));
RTABMAP_PARAM(RGBD, MaxLoopClosureDistance, float, 0.0, "Reject loop closures/localizations if the distance from the map is over this distance (0=disabled).");
RTABMAP_PARAM(RGBD, ForceOdom3DoF, bool, true, uFormat("Force odometry pose to be 3DoF if %s=true.", kRegForce3DoF().c_str()));
RTABMAP_PARAM(RGBD, StartAtOrigin, bool, false, uFormat("If true, rtabmap will assume the robot is starting from origin of the map. If false, rtabmap will assume the robot is restarting from the last saved localization pose from previous session (the place where it shut down previously). Used only in localization mode (%s=false).", kMemIncrementalMemory().c_str()));
RTABMAP_PARAM(RGBD, GoalReachedRadius, float, 0.5, "Goal reached radius (m).");
RTABMAP_PARAM(RGBD, PlanStuckIterations, int, 0, "Mark the current goal node on the path as unreachable if it is not updated after X iterations (0=disabled). If all upcoming nodes on the path are unreachabled, the plan fails.");
@@ -436,6 +441,9 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(g2o, Baseline, double, 0.075, "When doing bundle adjustment with RGB-D data, we can set a fake baseline (m) to do stereo bundle adjustment (if 0, mono bundle adjustment is done). For stereo data, the baseline in the calibration is used directly.");
RTABMAP_PARAM(GTSAM, Optimizer, int, 1, "0=Levenberg 1=GaussNewton 2=Dogleg");
RTABMAP_PARAM(GTSAM, Incremental, bool, false, uFormat("Do graph optimization incrementally (iSAM2) to increase optimization speed on loop closures. Note that only GaussNewton and Dogleg optimization algorithms are supported (%s) in this mode.", kGTSAMOptimizer().c_str()));
RTABMAP_PARAM(GTSAM, IncRelinearizeThreshold, double, 0.01, "Only relinearize variables whose linear delta magnitude is greater than this threshold. See GTSAM::ISAM2 doc for more info.");
RTABMAP_PARAM(GTSAM, IncRelinearizeSkip, int, 1, "Only relinearize any variables every X calls to ISAM2::update(). See GTSAM::ISAM2 doc for more info.");
// Odometry
RTABMAP_PARAM(Odom, Strategy, int, 0, "0=Frame-to-Map (F2M) 1=Frame-to-Frame (F2F) 2=Fovis 3=viso2 4=DVO-SLAM 5=ORB_SLAM2 6=OKVIS 7=LOAM 8=MSCKF_VIO 9=VINS-Fusion 10=OpenVINS 11=FLOAM 12=Open3D");
@@ -458,6 +466,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Odom, ScanKeyFrameThr, float, 0.9, "[Geometry] Create a new keyframe when the number of ICP inliers drops under this ratio of points in last frame's scan. Setting the value to 0 means that a keyframe is created for each processed frame.");
RTABMAP_PARAM(Odom, ImageDecimation, unsigned int, 1, uFormat("Decimation of the RGB image before registration. If depth size is larger than decimated RGB size, depth is decimated to be always at most equal to RGB size. If %s is true and if depth is smaller than decimated RGB, depth may be interpolated to match RGB size for feature detection.", kVisDepthAsMask().c_str()));
RTABMAP_PARAM(Odom, AlignWithGround, bool, false, "Align odometry with the ground on initialization.");
RTABMAP_PARAM(Odom, Deskewing, bool, true, "Lidar deskewing. If input lidar has time channel, it will be deskewed with a constant motion model (with IMU orientation and/or guess if provided).");
// Odometry Frame-to-Map
RTABMAP_PARAM(OdomF2M, MaxSize, int, 2000, "[Visual] Local map size: If > 0 (example 5000), the odometry will maintain a local map of X maximum words.");
@@ -686,6 +695,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY 15=PyDetector");
#endif
RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits.");
RTABMAP_PARAM(Vis, SSC, bool, false, "If true, SSC (Suppression via Square Covering) is applied to limit keypoints.");
RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit).");
RTABMAP_PARAM(Vis, MinDepth, float, 0, "Min depth of the features (0 means no limit).");
RTABMAP_PARAM(Vis, DepthAsMask, bool, true, "Use depth image as mask when extracting features.");
@@ -721,6 +731,10 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(GMS, WithScale, bool, false, "Take scale transformation into account.");
RTABMAP_PARAM(GMS, ThresholdFactor, double, 6.0, "The higher, the less matches.");
// Global descriptor approaches
RTABMAP_PARAM_STR(PyDescriptor, Path, "", "Path to python script file (see available ones in rtabmap/corelib/src/pydescriptor/*). See the header to see where the script should be used.");
RTABMAP_PARAM(PyDescriptor, Dim, int, 4096, "Descriptor dimension.");
// ICP registration parameters
#ifdef RTABMAP_POINTMATCHER
RTABMAP_PARAM(Icp, Strategy, int, 1, "ICP implementation: 0=Point Cloud Library, 1=libpointmatcher, 2=CCCoreLib (CloudCompare).");
@@ -743,6 +757,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Icp, Epsilon, float, 0, "Set the transformation epsilon (maximum allowable difference between two consecutive transformations) in order for an optimization to be considered as having converged to the final solution.");
RTABMAP_PARAM(Icp, CorrespondenceRatio, float, 0.1, "Ratio of matching correspondences to accept the transform.");
RTABMAP_PARAM(Icp, Force4DoF, bool, false, uFormat("Limit ICP to x, y, z and yaw DoF. Available if %s > 0.", kIcpStrategy().c_str()));
RTABMAP_PARAM(Icp, FiltersEnabled, int, 3, "Flag to enable filters: 1=\"from\" cloud only, 2=\"to\" cloud only, 3=both.");
#ifdef RTABMAP_POINTMATCHER
RTABMAP_PARAM(Icp, PointToPlane, bool, true, "Use point to plane ICP.");
#else
@@ -922,6 +937,7 @@ public:
static ParametersMap filterParameters(const ParametersMap & parameters, const std::string & group, bool remove = false);
static void readINI(const std::string & configFile, ParametersMap & parameters, bool modifiedOnly = false);
static void readINIStr(const std::string & configContent, ParametersMap & parameters, bool modifiedOnly = false);
static void writeINI(const std::string & configFile, const ParametersMap & parameters);
/**

View File

@@ -69,6 +69,7 @@ private:
float _epsilon;
float _correspondenceRatio;
bool _force4DoF;
int _filtersEnabled;
bool _pointToPlane;
int _pointToPlaneK;
float _pointToPlaneRadius;

View File

@@ -151,6 +151,8 @@ public:
float getTimeThreshold() const {return _maxTimeAllowed;} // in ms
void setTimeThreshold(float maxTimeAllowed); // in ms
int getMemoryThreshold() const {return _maxMemoryAllowed;} // in nodes
void setMemoryThreshold(int maxMemoryAllowed); // in nodes
void setInitialPose(const Transform & initialPose);
int triggerNewMap();
@@ -282,6 +284,8 @@ private:
unsigned int _maxMemoryAllowed; // signatures count in WM
float _loopThr;
float _loopRatio;
float _aggressiveLoopThr;
int _virtualPlaceLikelihoodRatio;
float _maxLoopClosureDistance;
bool _verifyLoopClosureHypothesis;
unsigned int _maxRetrieved;
@@ -322,6 +326,7 @@ private:
int _pathStuckIterations;
float _pathLinearVelocity;
float _pathAngularVelocity;
bool _forceOdom3doF;
bool _restartAtOrigin;
bool _loopCovLimited;
bool _loopGPS;

View File

@@ -0,0 +1,93 @@
/*
Copyright (c) 2010-2022, Mathieu Labbe
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <opencv2/highgui/highgui.hpp>
#include <rtabmap/core/SensorCaptureInfo.h>
#include "rtabmap/core/SensorData.h"
#include <set>
#include <stack>
#include <list>
#include <vector>
class UDirectory;
class UTimer;
namespace rtabmap
{
/**
* Class Camera
*
*/
class RTABMAP_CORE_EXPORT SensorCapture
{
public:
virtual ~SensorCapture();
SensorData takeData(SensorCaptureInfo * info = 0);
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "") = 0;
virtual std::string getSerial() const = 0;
virtual bool odomProvided() const { return false; }
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.06) { return false; }
//getters
float getFrameRate() const {return _frameRate;}
const Transform & getLocalTransform() const {return _localTransform;}
//setters
void setFrameRate(float frameRate) {_frameRate = frameRate;}
void setLocalTransform(const Transform & localTransform) {_localTransform= localTransform;}
void resetTimer();
protected:
/**
* Constructor
*
* @param frameRate the frame rate (Hz), 0 for fast as the sensor can
* @param localTransform the transform from base frame to sensor frame
*/
SensorCapture(float frameRate = 0, const Transform & localTransform = Transform::getIdentity());
/**
* returned rgb and depth images should be already rectified if calibration was loaded
*/
virtual SensorData captureData(SensorCaptureInfo * info = 0) = 0;
int getNextSeqID() {return ++_seq;}
private:
float _frameRate;
Transform _localTransform;
UTimer * _frameRateTimer;
int _seq;
};
} // namespace rtabmap

View File

@@ -0,0 +1,82 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "rtabmap/core/Transform.h"
#include <string>
namespace rtabmap
{
class SensorCaptureInfo
{
public:
SensorCaptureInfo() :
cameraName(""),
id(0),
stamp(0.0),
timeCapture(0.0f),
timeDeskewing(0.0f),
timeDisparity(0.0f),
timeMirroring(0.0f),
timeStereoExposureCompensation(0.0f),
timeImageDecimation(0.0f),
timeHistogramEqualization(0.0f),
timeScanFromDepth(0.0f),
timeUndistortDepth(0.0f),
timeBilateralFiltering(0.0f),
timeTotal(0.0f),
odomCovariance(cv::Mat::eye(6,6,CV_64FC1))
{
}
virtual ~SensorCaptureInfo() {}
std::string cameraName;
int id;
double stamp;
float timeCapture;
float timeDeskewing;
float timeDisparity;
float timeMirroring;
float timeStereoExposureCompensation;
float timeImageDecimation;
float timeHistogramEqualization;
float timeScanFromDepth;
float timeUndistortDepth;
float timeBilateralFiltering;
float timeTotal;
Transform odomPose;
cv::Mat odomCovariance;
std::vector<float> odomVelocity;
};
//backward compatibility
RTABMAP_DEPRECATED typedef SensorCaptureInfo CameraInfo;
} // namespace rtabmap

View File

@@ -0,0 +1,216 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <rtabmap/core/Parameters.h>
#include <rtabmap/core/Transform.h>
#include <rtabmap/utilite/UThread.h>
#include <rtabmap/utilite/UEventsSender.h>
namespace clams
{
class DiscreteDepthDistortionModel;
}
namespace rtabmap
{
class Camera;
class Lidar;
class SensorCapture;
class SensorCaptureInfo;
class SensorData;
class StereoDense;
class IMUFilter;
class Feature2D;
/**
* Class CameraThread
*
*/
class RTABMAP_CORE_EXPORT SensorCaptureThread :
public UThread,
public UEventsSender
{
public:
// ownership transferred
SensorCaptureThread(
Camera * camera,
const ParametersMap & parameters = ParametersMap());
/**
* @param camera the camera to take images from
* @param odomSensor an odometry sensor to get a pose (can be again the camera)
* @param odomAsGt set odometry sensor pose as ground truth instead of odometry
* @param extrinsics the static transform between odometry sensor's left lens frame to camera's left lens frame (without optical rotation)
*/
SensorCaptureThread(
Camera * camera,
SensorCapture * odomSensor,
const Transform & extrinsics,
double poseTimeOffset = 0.0,
float poseScaleFactor = 1.0f,
double poseWaitTime = 0.1,
const ParametersMap & parameters = ParametersMap());
/**
* @param lidar the lidar to take scans from
*/
SensorCaptureThread(
Lidar * lidar,
const ParametersMap & parameters = ParametersMap());
/**
* @param lidar the lidar to take scans from
* @param camera the camera to take images from. If the camera is providing a pose, it can be used for deskewing
*/
SensorCaptureThread(
Lidar * lidar,
Camera * camera,
const ParametersMap & parameters = ParametersMap());
/**
* @param lidar the lidar to take scans from
* @param odomSensor an odometry sensor to get a pose and used for deskewing (can be again the lidar)
*/
SensorCaptureThread(
Lidar * lidar,
SensorCapture * odomSensor,
double poseTimeOffset = 0.0,
float poseScaleFactor = 1.0f,
double poseWaitTime = 0.1,
const ParametersMap & parameters = ParametersMap());
/**
* @param lidar the lidar to take scans from
* @param camera the camera to take images from
* @param odomSensor an odometry sensor to get a pose and used for deskewing (can be again the camera or lidar)
* @param extrinsics the static transform between odometry frame to camera frame (without optical rotation)
*/
SensorCaptureThread(
Lidar * lidar,
Camera * camera,
SensorCapture * odomSensor,
const Transform & extrinsics,
double poseTimeOffset = 0.0,
float poseScaleFactor = 1.0f,
double poseWaitTime = 0.1,
const ParametersMap & parameters = ParametersMap());
virtual ~SensorCaptureThread();
void setMirroringEnabled(bool enabled) {_mirroring = enabled;}
void setStereoExposureCompensation(bool enabled) {_stereoExposureCompensation = enabled;}
void setColorOnly(bool colorOnly) {_colorOnly = colorOnly;}
void setImageDecimation(int decimation) {_imageDecimation = decimation;}
void setHistogramMethod(int histogramMethod) {_histogramMethod = histogramMethod;}
void setStereoToDepth(bool enabled) {_stereoToDepth = enabled;}
void setFrameRate(float frameRate);
RTABMAP_DEPRECATED void setImageRate(float frameRate) {setFrameRate(frameRate);}
void setDistortionModel(const std::string & path);
void setOdomAsGroundTruth(bool enabled) {_odomAsGt = enabled;}
void enableBilateralFiltering(float sigmaS, float sigmaR);
void disableBilateralFiltering() {_bilateralFiltering = false;}
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap & parameters = ParametersMap(), bool baseFrameConversion = false);
void disableIMUFiltering();
void enableFeatureDetection(const ParametersMap & parameters = ParametersMap());
void disableFeatureDetection();
// Use new version of this function with groundNormalsUp=0.8 for forceGroundNormalsUp=True and groundNormalsUp=0.0 for forceGroundNormalsUp=False.
RTABMAP_DEPRECATED void setScanParameters(
bool fromDepth,
int downsampleStep, // decimation of the depth image in case the scan is from depth image
float rangeMin,
float rangeMax,
float voxelSize,
int normalsK,
float normalsRadius,
bool forceGroundNormalsUp,
bool deskewing);
void setScanParameters(
bool fromDepth,
int downsampleStep=1, // decimation of the depth image in case the scan is from depth image
float rangeMin=0.0f,
float rangeMax=0.0f,
float voxelSize = 0.0f,
int normalsK = 0,
float normalsRadius = 0.0f,
float groundNormalsUp = 0.0f,
bool deskewing = false);
void postUpdate(SensorData * data, SensorCaptureInfo * info = 0) const;
//getters
bool isPaused() const {return !this->isRunning();}
bool isCapturing() const {return this->isRunning();}
bool odomProvided() const;
Camera * camera() {return _camera;} // return null if not set, valid until CameraThread is deleted
SensorCapture * odomSensor() {return _odomSensor;} // return null if not set, valid until CameraThread is deleted
Lidar * lidar() {return _lidar;} // return null if not set, valid until CameraThread is deleted
private:
virtual void mainLoopBegin();
virtual void mainLoop();
virtual void mainLoopKill();
private:
Camera * _camera;
SensorCapture * _odomSensor;
Lidar * _lidar;
Transform _extrinsicsOdomToCamera;
bool _odomAsGt;
double _poseTimeOffset;
float _poseScaleFactor;
double _poseWaitTime;
bool _mirroring;
bool _stereoExposureCompensation;
bool _colorOnly;
int _imageDecimation;
int _histogramMethod;
bool _stereoToDepth;
bool _scanDeskewing;
bool _scanFromDepth;
int _scanDownsampleStep;
float _scanRangeMin;
float _scanRangeMax;
float _scanVoxelSize;
int _scanNormalsK;
float _scanNormalsRadius;
float _scanForceGroundNormalsUp;
StereoDense * _stereoDense;
clams::DiscreteDepthDistortionModel * _distortionModel;
bool _bilateralFiltering;
float _bilateralSigmaS;
float _bilateralSigmaR;
IMUFilter * _imuFilter;
bool _imuBaseFrameConversion;
Feature2D * _featureDetector;
bool _depthAsMask;
};
//backward compatibility
RTABMAP_DEPRECATED typedef SensorCaptureThread CameraThread;
} // namespace rtabmap

View File

@@ -0,0 +1,94 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <rtabmap/core/SensorCaptureInfo.h>
#include <rtabmap/utilite/UEvent.h>
#include "rtabmap/core/SensorData.h"
namespace rtabmap
{
class SensorEvent :
public UEvent
{
public:
enum Code {
kCodeData,
kCodeNoMoreImages
};
public:
SensorEvent(const cv::Mat & image, int seq=0, double stamp = 0.0, const std::string & cameraName = std::string()) :
UEvent(kCodeData),
data_(image, seq, stamp)
{
sensorCaptureInfo_.cameraName = cameraName;
}
SensorEvent() :
UEvent(kCodeNoMoreImages)
{
}
SensorEvent(const SensorData & data) :
UEvent(kCodeData),
data_(data)
{
}
SensorEvent(const SensorData & data, const std::string & cameraName) :
UEvent(kCodeData),
data_(data)
{
sensorCaptureInfo_.cameraName = cameraName;
}
SensorEvent(const SensorData & data, const SensorCaptureInfo & sensorCaptureInfo) :
UEvent(kCodeData),
data_(data),
sensorCaptureInfo_(sensorCaptureInfo)
{
}
// Image or descriptors
const SensorData & data() const {return data_;}
const std::string & cameraName() const {return sensorCaptureInfo_.cameraName;}
const SensorCaptureInfo & info() const {return sensorCaptureInfo_;}
virtual ~SensorEvent() {}
virtual std::string getClassName() const {return std::string("SensorEvent");}
private:
SensorData data_;
SensorCaptureInfo sensorCaptureInfo_;
};
//backward compatibility
RTABMAP_DEPRECATED typedef SensorEvent CameraEvent;
} // namespace rtabmap

View File

@@ -90,9 +90,10 @@ public:
void removeLink(int idTo);
void removeVirtualLinks();
void addLandmark(const Link & landmark) {_landmarks.insert(std::make_pair(landmark.to(), landmark));}
void addLandmark(const Link & landmark);
const std::map<int, Link> & getLandmarks() const {return _landmarks;}
void removeLandmarks() {_landmarks.clear();}
void removeLandmarks();
void removeLandmark(int landmarkId);
void setSaved(bool saved) {_saved = saved;}
void setModified(bool modified) {_modified = modified; _linksModified = modified;}

View File

@@ -157,6 +157,7 @@ class RTABMAP_CORE_EXPORT Statistics
RTABMAP_STATS(Timing, Memory_update, ms);
RTABMAP_STATS(Timing, Neighbor_link_refining, ms);
RTABMAP_STATS(Timing, Proximity_by_time, ms);
RTABMAP_STATS(Timing, Proximity_by_space_search, ms);
RTABMAP_STATS(Timing, Proximity_by_space_visual, ms);
RTABMAP_STATS(Timing, Proximity_by_space, ms);
RTABMAP_STATS(Timing, Cleaning_neighbors, ms);

View File

@@ -57,9 +57,12 @@ public:
void setOutputMode(int outputMode = 0);
void setDepthProfile(int confThreshold = 200, int lrcThreshold = 5);
void setRectification(bool useSpecTranslation, float alphaScaling = 0.0f);
void setExtendedDisparity(bool extendedDisparity);
void setSubpixelMode(bool enabled, int fractionalBits = 3);
void setCompanding(bool enabled, int width=96);
void setRectification(bool useSpecTranslation, float alphaScaling = 0.0f, bool enabled=true);
void setIMU(bool imuPublished, bool publishInterIMU);
void setIrBrightness(float dotProjectormA = 0.0f, float floodLightmA = 200.0f);
void setIrIntensity(float dotIntensity = 0.0f, float floodIntensity = 0.0f);
void setDetectFeatures(int detectFeatures = 0);
void setBlobPath(const std::string & blobPath);
void setGFTTDetector(bool useHarrisDetector = false, float minDistance = 7.0f, int numTargetFeatures = 1000);
@@ -70,7 +73,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_DEPTHAI
@@ -82,12 +85,16 @@ private:
int confThreshold_;
int lrcThreshold_;
int resolution_;
bool extendedDisparity_;
int subpixelFractionalBits_;
int compandingWidth_;
bool useSpecTranslation_;
float alphaScaling_;
bool imagesRectified_;
bool imuPublished_;
bool publishInterIMU_;
float dotProjectormA_;
float floodLightmA_;
float dotIntensity_;
float floodIntensity_;
int detectFeatures_;
bool useHarrisDetector_;
float minDistance_;
@@ -97,9 +104,7 @@ private:
int nmsRadius_;
std::string blobPath_;
std::shared_ptr<dai::Device> device_;
std::shared_ptr<dai::DataOutputQueue> leftOrColorQueue_;
std::shared_ptr<dai::DataOutputQueue> rightOrDepthQueue_;
std::shared_ptr<dai::DataOutputQueue> featuresQueue_;
std::shared_ptr<dai::DataOutputQueue> cameraQueue_;
std::map<double, cv::Vec3f> accBuffer_;
std::map<double, cv::Vec3f> gyroBuffer_;
UMutex imuMutex_;

View File

@@ -61,7 +61,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_FREENECT

View File

@@ -77,7 +77,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_FREENECT2

View File

@@ -118,7 +118,7 @@ public:
}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
bool readPoses(

View File

@@ -63,7 +63,7 @@ public:
void setPreferences(int rgb_resolution, int framerate, int depth_resolution);
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
void close();

View File

@@ -72,7 +72,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
void close();

View File

@@ -67,7 +67,7 @@ protected:
/**
* returned rgb and depth images should be already rectified if calibration was loaded
*/
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_MYNTEYE

View File

@@ -69,7 +69,7 @@ public:
void setDepthDecimation(int decimation);
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_OPENNI2

View File

@@ -51,7 +51,7 @@ public:
virtual std::string getSerial() const {return "";} // unknown with OpenCV
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
bool _asus;

View File

@@ -34,15 +34,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <pcl/pcl_config.h>
#ifdef HAVE_OPENNI
#ifdef RTABMAP_OPENNI
#if __linux__ && __i386__ && __cplusplus >= 201103L
#warning "Openni driver is not available on i386 when building with c++11 support"
#else
#define RTABMAP_OPENNI
#endif
#include <pcl/io/openni_camera/openni_depth_image.h>
#include <pcl/io/openni_camera/openni_image.h>
#endif
#endif
#include <boost/signals2/connection.hpp>
@@ -74,7 +72,7 @@ public:
float constant);
#else
void image_cb (
const boost::shared_ptr<openni_wrapper::Image>& rgb,
const boost::shared_ptr<openni_wrapper::Image>& rgb,
const boost::shared_ptr<openni_wrapper::DepthImage>& depth,
float constant);
#endif
@@ -85,7 +83,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
pcl::Grabber* interface_;

View File

@@ -53,7 +53,7 @@ public:
virtual void setMaxFrames(int value) {CameraImages::setMaxFrames(value);cameraDepth_.setMaxFrames(value);}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
CameraImages cameraDepth_;

View File

@@ -72,7 +72,7 @@ public:
virtual bool odomProvided() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_REALSENSE

View File

@@ -68,7 +68,7 @@ public:
virtual bool isCalibrated() const;
virtual std::string getSerial() const;
virtual bool odomProvided() const;
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance);
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.06);
// parameters are set during initialization
// D400 series
@@ -77,7 +77,7 @@ public:
void setResolution(int width, int height, int fps = 30);
void setDepthResolution(int width, int height, int fps = 30);
void setGlobalTimeSync(bool enabled);
void publishInterIMU(bool enabled);
/**
* Dual mode (D400+T265 or L500+T265)
* @param enabled enable dual mode
@@ -105,7 +105,7 @@ private:
#endif
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_REALSENSE2
@@ -142,7 +142,6 @@ private:
int cameraDepthHeight_;
int cameraDepthFps_;
bool globalTimeSync_;
bool publishInterIMU_;
bool dualMode_;
Transform dualExtrinsics_;
std::string jsonConfig_;

View File

@@ -0,0 +1,52 @@
#pragma once
#include "rtabmap/core/Camera.h"
#include "rtabmap/core/Version.h"
#include "rtabmap/utilite/USemaphore.h"
#ifdef RTABMAP_XVSDK
#include <xv-sdk.h>
#endif
namespace rtabmap
{
class RTABMAP_CORE_EXPORT CameraSeerSense :
public Camera
{
public:
static bool available();
public:
CameraSeerSense(
bool computeOdometry = false,
float imageRate = 0.0f,
const Transform & localTransform = Transform::getIdentity()
);
virtual ~CameraSeerSense();
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
virtual bool isCalibrated() const;
virtual std::string getSerial() const;
virtual bool odomProvided() const;
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.0);
protected:
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_XVSDK
CameraModel cameraModel_;
bool computeOdometry_;
int imuId_;
int tofId_;
std::shared_ptr<xv::Device> device_;
std::map<double, std::pair<cv::Vec3d, cv::Vec3d>> imuBuffer_;
std::pair<double, std::pair<cv::Mat, cv::Mat>> lastData_;
UMutex imuMutex_;
UMutex dataMutex_;
USemaphore dataReady_;
#endif
};
} // namespace rtabmap

View File

@@ -51,7 +51,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_DC1394

View File

@@ -53,7 +53,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_FLYCAPTURE2

View File

@@ -64,7 +64,7 @@ public:
virtual void setMaxFrames(int value) {CameraImages::setMaxFrames(value);camera2_->setMaxFrames(value);}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
CameraImages * camera2_;

View File

@@ -60,7 +60,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
cv::VideoCapture capture_;

View File

@@ -71,7 +71,7 @@ public:
void setResolution(int width, int height) {_width=width, _height=height;}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
cv::VideoCapture capture_;

View File

@@ -76,12 +76,12 @@ public:
virtual bool isCalibrated() const;
virtual std::string getSerial() const;
virtual bool odomProvided() const;
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance);
virtual bool getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime = 0.0);
void publishInterIMU(bool enabled);
void postInterIMUPublic(const IMU & imu, double stamp);
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_ZED
@@ -100,7 +100,6 @@ private:
bool computeOdometry_;
bool lost_;
bool force3DoF_;
bool publishInterIMU_;
ZedIMUThread * imuPublishingThread_;
#endif
};

View File

@@ -63,7 +63,7 @@ public:
virtual std::string getSerial() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
#ifdef RTABMAP_ZEDOC

View File

@@ -64,7 +64,7 @@ public:
void setResolution(int width, int height) {_width=width, _height=height;}
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
virtual SensorData captureImage(SensorCaptureInfo * info = 0);
private:
// File type

View File

@@ -0,0 +1,94 @@
/*
Copyright (c) 2010-2022, Mathieu Labbe
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CORELIB_INCLUDE_RTABMAP_CORE_LIDAR_LIDARVLP16_H_
#define CORELIB_INCLUDE_RTABMAP_CORE_LIDAR_LIDARVLP16_H_
// Should be first on windows to avoid "WinSock.h has already been included" error
#include <pcl/io/vlp_grabber.h>
#include <rtabmap/core/Lidar.h>
#include <rtabmap/utilite/USemaphore.h>
namespace rtabmap {
struct PointXYZIT {
float x;
float y;
float z;
float i;
float t;
};
class RTABMAP_CORE_EXPORT LidarVLP16 :public Lidar, public pcl::VLPGrabber {
public:
LidarVLP16(
const std::string& pcapFile,
bool organized = false,
bool stampLast = true,
float frameRate = 0.0f,
Transform localTransform = Transform::getIdentity());
LidarVLP16(
const boost::asio::ip::address& ipAddress,
const std::uint16_t port = 2368,
bool organized = false,
bool useHostTime = true,
bool stampLast = true,
float frameRate = 0.0f,
Transform localTransform = Transform::getIdentity());
virtual ~LidarVLP16();
SensorData takeScan(SensorCaptureInfo * info = 0) {return takeData(info);}
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "") override;
virtual std::string getSerial() const override {return getName();}
void setOrganized(bool enable);
private:
void buildTimings(bool dualMode);
virtual void toPointClouds (HDLDataPacket *dataPacket) override;
protected:
virtual SensorData captureData(SensorCaptureInfo * info = 0) override;
private:
// timing offset lookup table
std::vector< std::vector<float> > timingOffsets_;
bool timingOffsetsDualMode_;
double startSweepTime_;
double startSweepTimeHost_;
bool organized_;
bool useHostTime_;
bool stampLast_;
SensorData lastScan_;
std::vector<std::vector<PointXYZIT> > accumulatedScans_;
USemaphore scanReady_;
UMutex lastScanMutex_;
};
} /* namespace rtabmap */
#endif /* CORELIB_INCLUDE_RTABMAP_CORE_LIDAR_LIDARVLP16_H_ */

View File

@@ -49,7 +49,7 @@ public:
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
bool init(const rtabmap::CameraModel & model, double stamp, bool stereo, double baseline);
bool init(const rtabmap::CameraModel & model1, const rtabmap::CameraModel & model2, double stamp, bool stereo, double baseline);
private:
#if defined(RTABMAP_ORB_SLAM) and RTABMAP_ORB_SLAM == 3
ORB_SLAM3::System * orbslam_;

View File

@@ -30,6 +30,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/Optimizer.h>
namespace gtsam {
class ISAM2;
}
namespace rtabmap {
class RTABMAP_CORE_EXPORT OptimizerGTSAM : public Optimizer
@@ -38,13 +42,8 @@ public:
static bool available();
public:
OptimizerGTSAM(const ParametersMap & parameters = ParametersMap()) :
Optimizer(parameters),
optimizer_(Parameters::defaultGTSAMOptimizer())
{
parseParameters(parameters);
}
virtual ~OptimizerGTSAM() {}
OptimizerGTSAM(const ParametersMap & parameters = ParametersMap());
virtual ~OptimizerGTSAM();
virtual Type type() const {return kTypeGTSAM;}
@@ -60,7 +59,25 @@ public:
int * iterationsDone = 0);
private:
int optimizer_;
int internalOptimizerType_;
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_;
std::set<int> addedPoses_;
std::pair<int, std::uint64_t> lastRootFactorIndex_;
};
} /* namespace rtabmap */

View File

@@ -164,6 +164,9 @@ void RTABMAP_CORE_EXPORT NMS(
cv::Mat & descriptorsOut,
int border, int dist_thresh, int img_width, int img_height);
std::vector<int> RTABMAP_CORE_EXPORT SSC(
const std::vector<cv::KeyPoint> & keypoints, int maxKeypoints, float tolerance, int cols, int rows);
/**
* @brief Rotate images and camera model so that the top of the image is up.
*

View File

@@ -455,6 +455,19 @@ RTABMAP_DEPRECATED pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_CORE_EXPORT loadC
int downsampleStep = 1,
float voxelSize = 0.0f);
/**
* @brief Lidar deskewing
* @param input lidar, format should have time channel
* @param input stamp of the lidar
* @param velocity in base frame
* @param velocity stamp at which it has been computed
* @return lidar deskewed
*/
LaserScan RTABMAP_CORE_EXPORT deskew(
const LaserScan & input,
double inputStamp,
const rtabmap::Transform & velocity);
} // namespace util3d
} // namespace rtabmap

View File

@@ -13,8 +13,10 @@ SET(SRC_FILES
Recovery.cpp
SensorCapture.cpp
SensorCaptureThread.cpp
Camera.cpp
CameraThread.cpp
CameraModel.cpp
camera/CameraFreenect.cpp
@@ -38,6 +40,7 @@ SET(SRC_FILES
camera/CameraVideo.cpp
camera/CameraMyntEye.cpp
camera/CameraDepthAI.cpp
camera/CameraSeerSense.cpp
EpipolarGeometry.cpp
VisualWord.cpp
@@ -115,6 +118,8 @@ SET(SRC_FILES
MarkerDetector.cpp
GlobalDescriptorExtractor.cpp
GainCompensator.cpp
rtflann/ext/lz4.c
@@ -132,6 +137,13 @@ SET(SRC_FILES
opencv/five-point.cpp
)
IF(PCL_VERSION VERSION_GREATER_EQUAL "1.8")
SET(SRC_FILES
${SRC_FILES}
lidar/LidarVLP16.cpp
)
ENDIF(PCL_VERSION VERSION_GREATER_EQUAL "1.8")
IF(OpenCV_VERSION_MAJOR EQUAL 2)
SET(SRC_FILES
${SRC_FILES}
@@ -173,14 +185,14 @@ SET(PUBLIC_LIBRARIES
${PCL_LIBRARIES}
)
IF(Sqlite3_FOUND)
IF(SQLite3_FOUND)
SET(INCLUDE_DIRS
${INCLUDE_DIRS}
${Sqlite3_INCLUDE_DIRS}
${SQLite3_INCLUDE_DIRS}
)
SET(LIBRARIES
${LIBRARIES}
${Sqlite3_LIBRARIES}
${SQLite3_LIBRARIES}
)
ELSE()
SET(SRC_FILES
@@ -224,6 +236,7 @@ IF(WITH_PYTHON AND Python3_FOUND)
python/PythonInterface.cpp
python/PyMatcher.cpp
python/PyDetector.cpp
python/PyDescriptor.cpp
)
SET(INCLUDE_DIRS
${TORCH_INCLUDE_DIRS}
@@ -371,6 +384,13 @@ IF(depthai_FOUND)
)
ENDIF(depthai_FOUND)
IF(xvsdk_FOUND)
SET(PUBLIC_LIBRARIES
${PUBLIC_LIBRARIES}
${xvsdk_LIBRARIES}
)
ENDIF(xvsdk_FOUND)
IF(TARGET OpenMP::OpenMP_CXX)
SET(LIBRARIES
${LIBRARIES}

View File

@@ -26,42 +26,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rtabmap/core/Camera.h"
#include "rtabmap/core/IMUFilter.h"
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UTimer.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath>
#include <rtabmap/utilite/UEventsManager.h>
namespace rtabmap
{
Camera::Camera(float imageRate, const Transform & localTransform) :
_imageRate(imageRate),
_localTransform(localTransform*CameraModel::opticalRotation()),
_targetImageSize(0,0),
_frameRateTimer(new UTimer()),
_seq(0)
{
}
SensorCapture(imageRate, localTransform*CameraModel::opticalRotation()),
imuFilter_(0),
publishInterIMU_(false)
{}
Camera::~Camera()
{
UDEBUG("");
delete _frameRateTimer;
UDEBUG("");
}
void Camera::resetTimer()
{
_frameRateTimer->start();
delete imuFilter_;
}
bool Camera::initFromFile(const std::string & calibrationPath)
@@ -69,54 +52,32 @@ bool Camera::initFromFile(const std::string & calibrationPath)
return init(UDirectory::getDir(calibrationPath), uSplit(UFile::getName(calibrationPath), '.').front());
}
SensorData Camera::takeImage(CameraInfo * info)
void Camera::setInterIMUPublishing(bool enabled, IMUFilter * filter)
{
bool warnFrameRateTooHigh = false;
float actualFrameRate = 0;
float imageRate = _imageRate;
if(imageRate>0)
{
int sleepTime = (1000.0f/imageRate - 1000.0f*_frameRateTimer->getElapsedTime());
if(sleepTime > 2)
{
uSleep(sleepTime-2);
}
else if(sleepTime < 0)
{
warnFrameRateTooHigh = true;
actualFrameRate = 1.0/(_frameRateTimer->getElapsedTime());
}
publishInterIMU_ = enabled;
delete imuFilter_;
imuFilter_ = filter;
}
// Add precision at the cost of a small overhead
while(_frameRateTimer->getElapsedTime() < 1.0/double(imageRate)-0.000001)
{
//
}
double slept = _frameRateTimer->getElapsedTime();
_frameRateTimer->start();
UDEBUG("slept=%fs vs target=%fs", slept, 1.0/double(imageRate));
}
UTimer timer;
SensorData data = this->captureImage(info);
double captureTime = timer.ticks();
if(warnFrameRateTooHigh)
void Camera::postInterIMU(const IMU & imu, double stamp)
{
if(imuFilter_)
{
UWARN("Camera: Cannot reach target image rate %f Hz, current rate is %f Hz and capture time = %f s.",
imageRate, actualFrameRate, captureTime);
imuFilter_->update(
imu.angularVelocity()[0], imu.angularVelocity()[1], imu.angularVelocity()[2],
imu.linearAcceleration()[0], imu.linearAcceleration()[1], imu.linearAcceleration()[2],
stamp);
cv::Vec4d q;
imuFilter_->getOrientation(q[0],q[1],q[2],q[3]);
UEventsManager::post(new IMUEvent(IMU(
q, cv::Mat(),
imu.angularVelocity(), imu.angularVelocityCovariance(),
imu.linearAcceleration(), imu.linearAccelerationCovariance(),
imu.localTransform()),
stamp));
return;
}
else
{
UDEBUG("Time capturing image = %fs", captureTime);
}
if(info)
{
info->id = data.id();
info->stamp = data.stamp();
info->timeCapture = captureTime;
}
return data;
UEventsManager::post(new IMUEvent(imu, stamp));
}
} // namespace rtabmap

View File

@@ -60,7 +60,7 @@ CameraModel::CameraModel(
localTransform_(localTransform)
{
UASSERT(K_.empty() || (K_.rows == 3 && K_.cols == 3 && K_.type() == CV_64FC1));
UASSERT(D_.empty() || (D_.rows == 1 && (D_.cols == 4 || D_.cols == 5 || D_.cols == 6 || D_.cols == 8) && D_.type() == CV_64FC1));
UASSERT(D_.empty() || (D_.rows == 1 && (D_.cols == 4 || D_.cols == 5 || D_.cols == 6 || D_.cols == 8 || D_.cols == 12 || D_.cols == 14) && D_.type() == CV_64FC1));
UASSERT(R_.empty() || (R_.rows == 3 && R_.cols == 3 && R_.type() == CV_64FC1));
UASSERT(P_.empty() || (P_.rows == 3 && P_.cols == 4 && P_.type() == CV_64FC1));
}
@@ -156,7 +156,7 @@ CameraModel::CameraModel(
bool CameraModel::initRectificationMap()
{
UASSERT(imageSize_.height > 0 && imageSize_.width > 0);
UASSERT(D_.rows == 1 && (D_.cols == 4 || D_.cols == 5 || D_.cols == 6 || D_.cols == 8));
UASSERT(D_.rows == 1 && (D_.cols == 4 || D_.cols == 5 || D_.cols == 6 || D_.cols == 8 || D_.cols == 12 || D_.cols == 14));
UASSERT(R_.rows == 3 && R_.cols == 3);
UASSERT(P_.rows == 3 && P_.cols == 4);
// init rectification map
@@ -279,7 +279,7 @@ bool CameraModel::load(const std::string & filePath)
std::vector<double> data;
n["data"] >> data;
UASSERT(rows*cols == (int)data.size());
UASSERT(rows == 1 && (cols == 4 || cols == 5 || cols == 8));
UASSERT(rows == 1 && (cols == 4 || cols == 5 || cols == 8 || cols == 12 || cols == 14));
D_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
}
else

View File

@@ -6728,7 +6728,7 @@ void DBDriverSqlite3::stepGlobalDescriptor(sqlite3_stmt * ppStmt,
//data
std::vector<unsigned char> dataBytes = rtabmap::compressData(descriptor.data());
if(infoBytes.empty())
if(dataBytes.empty())
{
rc = sqlite3_bind_null(ppStmt, index++);
}

View File

@@ -25,6 +25,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <rtabmap/core/SensorEvent.h>
#include "rtabmap/core/DBReader.h"
#include "rtabmap/core/DBDriver.h"
@@ -34,7 +35,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UEventsManager.h>
#include "rtabmap/core/CameraEvent.h"
#include "rtabmap/core/RtabmapEvent.h"
#include "rtabmap/core/OdometryEvent.h"
#include "rtabmap/core/util3d.h"
@@ -268,7 +268,13 @@ std::string DBReader::getSerial() const
return "DBReader";
}
SensorData DBReader::captureImage(CameraInfo * info)
bool DBReader::getPose(double stamp, Transform & pose, cv::Mat & covariance, double maxWaitTime)
{
UERROR("DBReader only provides pose when capturing data, it cannot provide asynchronous pose.");
return false;
}
SensorData DBReader::captureImage(SensorCaptureInfo * info)
{
SensorData data = this->getNextData(info);
if(data.id()>0 && _stopId>0 && data.id() > _stopId)
@@ -370,7 +376,7 @@ SensorData DBReader::captureImage(CameraInfo * info)
return data;
}
SensorData DBReader::getNextData(CameraInfo * info)
SensorData DBReader::getNextData(SensorCaptureInfo * info)
{
SensorData data;
if(_dbDriver)

View File

@@ -268,70 +268,111 @@ void Feature2D::filterKeypointsByDisparity(
}
}
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, int maxKeypoints)
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, int maxKeypoints, const cv::Size & imageSize, bool ssc)
{
cv::Mat descriptors;
limitKeypoints(keypoints, descriptors, maxKeypoints);
limitKeypoints(keypoints, descriptors, maxKeypoints, imageSize, ssc);
}
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, cv::Mat & descriptors, int maxKeypoints)
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize, bool ssc)
{
std::vector<cv::Point3f> keypoints3D;
limitKeypoints(keypoints, keypoints3D, descriptors, maxKeypoints);
limitKeypoints(keypoints, keypoints3D, descriptors, maxKeypoints, imageSize, ssc);
}
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & keypoints3D, cv::Mat & descriptors, int maxKeypoints)
void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & keypoints3D, cv::Mat & descriptors, int maxKeypoints, const cv::Size & imageSize, bool ssc)
{
UASSERT_MSG((int)keypoints.size() == descriptors.rows || descriptors.rows == 0, uFormat("keypoints=%d descriptors=%d", (int)keypoints.size(), descriptors.rows).c_str());
UASSERT_MSG(keypoints.size() == keypoints3D.size() || keypoints3D.size() == 0, uFormat("keypoints=%d keypoints3D=%d", (int)keypoints.size(), (int)keypoints3D.size()).c_str());
if(maxKeypoints > 0 && (int)keypoints.size() > maxKeypoints)
{
UTimer timer;
ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
std::multimap<float, int> hessianMap; // <hessian,id>
for(unsigned int i = 0; i <keypoints.size(); ++i)
{
//Keep track of the data, to be easier to manage the data in the next step
hessianMap.insert(std::pair<float, int>(fabs(keypoints[i].response), i));
}
// Remove them from the signature
int removed = (int)hessianMap.size()-maxKeypoints;
std::multimap<float, int>::reverse_iterator iter = hessianMap.rbegin();
std::vector<cv::KeyPoint> kptsTmp(maxKeypoints);
int removed;
std::vector<cv::KeyPoint> kptsTmp;
std::vector<cv::Point3f> kpts3DTmp;
if(!keypoints3D.empty())
{
kpts3DTmp.resize(maxKeypoints);
}
cv::Mat descriptorsTmp;
if(descriptors.rows)
if(ssc)
{
descriptorsTmp = cv::Mat(maxKeypoints, descriptors.cols, descriptors.type());
}
for(unsigned int k=0; k < kptsTmp.size() && iter!=hessianMap.rend(); ++k, ++iter)
{
kptsTmp[k] = keypoints[iter->second];
if(keypoints3D.size())
ULOGGER_DEBUG("too much words (%d), removing words with SSC", keypoints.size());
static constexpr float tolerance = 0.1;
auto ResultVec = util2d::SSC(keypoints, maxKeypoints, tolerance, imageSize.width, imageSize.height);
removed = keypoints.size()-ResultVec.size();
// retrieve final keypoints
kptsTmp.resize(ResultVec.size());
if(!keypoints3D.empty())
{
kpts3DTmp[k] = keypoints3D[iter->second];
kpts3DTmp.resize(ResultVec.size());
}
if(descriptors.rows)
{
if(descriptors.type() == CV_32FC1)
descriptorsTmp = cv::Mat(ResultVec.size(), descriptors.cols, descriptors.type());
}
for(unsigned int k=0; k<ResultVec.size(); ++k)
{
kptsTmp[k] = keypoints[ResultVec[k]];
if(keypoints3D.size())
{
memcpy(descriptorsTmp.ptr<float>(k), descriptors.ptr<float>(iter->second), descriptors.cols*sizeof(float));
kpts3DTmp[k] = keypoints3D[ResultVec[k]];
}
else
if(descriptors.rows)
{
memcpy(descriptorsTmp.ptr<char>(k), descriptors.ptr<char>(iter->second), descriptors.cols*sizeof(char));
if(descriptors.type() == CV_32FC1)
{
memcpy(descriptorsTmp.ptr<float>(k), descriptors.ptr<float>(ResultVec[k]), descriptors.cols*sizeof(float));
}
else
{
memcpy(descriptorsTmp.ptr<char>(k), descriptors.ptr<char>(ResultVec[k]), descriptors.cols*sizeof(char));
}
}
}
}
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, (int)kptsTmp.size(), kptsTmp.size()?kptsTmp.back().response:0.0f);
else
{
ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
std::multimap<float, int> hessianMap; // <hessian,id>
for(unsigned int i = 0; i <keypoints.size(); ++i)
{
//Keep track of the data, to be easier to manage the data in the next step
hessianMap.insert(std::pair<float, int>(fabs(keypoints[i].response), i));
}
// Remove them from the signature
removed = (int)hessianMap.size()-maxKeypoints;
std::multimap<float, int>::reverse_iterator iter = hessianMap.rbegin();
kptsTmp.resize(maxKeypoints);
if(!keypoints3D.empty())
{
kpts3DTmp.resize(maxKeypoints);
}
if(descriptors.rows)
{
descriptorsTmp = cv::Mat(maxKeypoints, descriptors.cols, descriptors.type());
}
for(unsigned int k=0; k<kptsTmp.size() && iter!=hessianMap.rend(); ++k, ++iter)
{
kptsTmp[k] = keypoints[iter->second];
if(keypoints3D.size())
{
kpts3DTmp[k] = keypoints3D[iter->second];
}
if(descriptors.rows)
{
if(descriptors.type() == CV_32FC1)
{
memcpy(descriptorsTmp.ptr<float>(k), descriptors.ptr<float>(iter->second), descriptors.cols*sizeof(float));
}
else
{
memcpy(descriptorsTmp.ptr<char>(k), descriptors.ptr<char>(iter->second), descriptors.cols*sizeof(char));
}
}
}
}
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, (int)kptsTmp.size(), !ssc&&kptsTmp.size()?kptsTmp.back().response:0.0f);
ULOGGER_DEBUG("removing words time = %f s", timer.ticks());
keypoints = kptsTmp;
keypoints3D = kpts3DTmp;
@@ -342,31 +383,46 @@ void Feature2D::limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vecto
}
}
void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints)
void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize, bool ssc)
{
if(maxKeypoints > 0 && (int)keypoints.size() > maxKeypoints)
{
UTimer timer;
ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", (int)keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
std::multimap<float, int> hessianMap; // <hessian,id>
for(unsigned int i = 0; i <keypoints.size(); ++i)
{
//Keep track of the data, to be easier to manage the data in the next step
hessianMap.insert(std::pair<float, int>(fabs(keypoints[i].response), i));
}
// Keep keypoints with highest response
int removed = (int)hessianMap.size()-maxKeypoints;
std::multimap<float, int>::reverse_iterator iter = hessianMap.rbegin();
inliers.resize(keypoints.size(), false);
float minimumHessian = 0.0f;
for(int k=0; k < maxKeypoints && iter!=hessianMap.rend(); ++k, ++iter)
int removed;
inliers.resize(keypoints.size(), false);
if(ssc)
{
inliers[iter->second] = true;
minimumHessian = iter->first;
ULOGGER_DEBUG("too much words (%d), removing words with SSC", keypoints.size());
static constexpr float tolerance = 0.1;
auto ResultVec = util2d::SSC(keypoints, maxKeypoints, tolerance, imageSize.width, imageSize.height);
removed = keypoints.size()-ResultVec.size();
for(unsigned int k=0; k<ResultVec.size(); ++k)
{
inliers[ResultVec[k]] = true;
}
}
else
{
ULOGGER_DEBUG("too much words (%d), removing words with the hessian threshold", keypoints.size());
// Remove words under the new hessian threshold
// Sort words by hessian
std::multimap<float, int> hessianMap; // <hessian,id>
for(unsigned int i = 0; i<keypoints.size(); ++i)
{
//Keep track of the data, to be easier to manage the data in the next step
hessianMap.insert(std::pair<float, int>(fabs(keypoints[i].response), i));
}
// Keep keypoints with highest response
removed = (int)hessianMap.size()-maxKeypoints;
std::multimap<float, int>::reverse_iterator iter = hessianMap.rbegin();
for(int k=0; k<maxKeypoints && iter!=hessianMap.rend(); ++k, ++iter)
{
inliers[iter->second] = true;
minimumHessian = iter->first;
}
}
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, maxKeypoints, minimumHessian);
ULOGGER_DEBUG("filter keypoints time = %f s", timer.ticks());
@@ -378,7 +434,7 @@ void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std:
}
}
void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols)
void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints, const cv::Size & imageSize, int gridRows, int gridCols, bool ssc)
{
if(maxKeypoints <= 0 || (int)keypoints.size() <= maxKeypoints)
{
@@ -406,7 +462,7 @@ void Feature2D::limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std:
for(size_t i=0; i<keypointsPerCell.size(); ++i)
{
std::vector<bool> inliersCell;
limitKeypoints(keypointsPerCell[i], inliersCell, maxKeypointsPerCell);
limitKeypoints(keypointsPerCell[i], inliersCell, maxKeypointsPerCell, cv::Size(colSize, rowSize), ssc);
for(size_t j=0; j<inliersCell.size(); ++j)
{
if(inliersCell[j])
@@ -432,6 +488,7 @@ cv::Rect Feature2D::computeRoi(const cv::Mat & image, const std::vector<float> &
/////////////////////
Feature2D::Feature2D(const ParametersMap & parameters) :
maxFeatures_(Parameters::defaultKpMaxFeatures()),
SSC_(Parameters::defaultKpSSC()),
_maxDepth(Parameters::defaultKpMaxDepth()),
_minDepth(Parameters::defaultKpMinDepth()),
_roiRatios(std::vector<float>(4, 0.0f)),
@@ -453,6 +510,7 @@ void Feature2D::parseParameters(const ParametersMap & parameters)
uInsert(parameters_, parameters);
Parameters::parse(parameters, Parameters::kKpMaxFeatures(), maxFeatures_);
Parameters::parse(parameters, Parameters::kKpSSC(), SSC_);
Parameters::parse(parameters, Parameters::kKpMaxDepth(), _maxDepth);
Parameters::parse(parameters, Parameters::kKpMinDepth(), _minDepth);
Parameters::parse(parameters, Parameters::kKpSubPixWinSize(), _subPixWinSize);
@@ -734,7 +792,10 @@ std::vector<cv::KeyPoint> Feature2D::generateKeypoints(const cv::Mat & image, co
cv::Rect roi(globalRoi.x + j*colSize, globalRoi.y + i*rowSize, colSize, rowSize);
std::vector<cv::KeyPoint> subKeypoints;
subKeypoints = this->generateKeypointsImpl(image, roi, mask);
limitKeypoints(subKeypoints, maxFeatures);
if (this->getType() != Feature2D::Type::kFeaturePyDetector)
{
limitKeypoints(subKeypoints, maxFeatures, roi.size(), this->getSSC());
}
if(roi.x || roi.y)
{
// Adjust keypoint position to raw image
@@ -2139,7 +2200,7 @@ std::vector<cv::KeyPoint> ORBOctree::generateKeypointsImpl(const cv::Mat & image
if((int)keypoints.size() > this->getMaxFeatures())
{
limitKeypoints(keypoints, descriptors_, this->getMaxFeatures());
limitKeypoints(keypoints, descriptors_, this->getMaxFeatures(), roi.size(), this->getSSC());
}
#else
UWARN("RTAB-Map is not built with ORB OcTree option enabled so ORB OcTree feature cannot be used!");

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2010-2024, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rtabmap/core/GlobalDescriptorExtractor.h"
#ifdef RTABMAP_PYTHON
#include "python/PyDescriptor.h"
#endif
namespace rtabmap {
GlobalDescriptorExtractor::GlobalDescriptorExtractor(const ParametersMap & parameters)
{
}
GlobalDescriptorExtractor::~GlobalDescriptorExtractor()
{
}
GlobalDescriptorExtractor * GlobalDescriptorExtractor::create(const ParametersMap & parameters)
{
int type = Parameters::defaultMemGlobalDescriptorStrategy();
Parameters::parse(parameters, Parameters::kMemGlobalDescriptorStrategy(), type);
return create((GlobalDescriptorExtractor::Type)type, parameters);
}
GlobalDescriptorExtractor * GlobalDescriptorExtractor::create(GlobalDescriptorExtractor::Type type, const ParametersMap & parameters)
{
UDEBUG("Creating global descriptor of type %d", (int)type);
#ifndef RTABMAP_PYTHON
if(type == GlobalDescriptorExtractor::kPyDescriptor)
{
UWARN("PyDescriptor cannot be used as rtabmap is not built with Python3 support.");
type = GlobalDescriptorExtractor::kUndef;
}
#endif
GlobalDescriptorExtractor * GlobalDescriptorExtractor = 0;
switch(type)
{
#ifdef RTABMAP_PYTHON
case GlobalDescriptorExtractor::kPyDescriptor:
GlobalDescriptorExtractor = new PyDescriptor(parameters);
break;
#endif
default:
type = GlobalDescriptorExtractor::kUndef;
break;
}
return GlobalDescriptorExtractor;
}
}

View File

@@ -121,7 +121,7 @@ bool GlobalMap::update(const std::map<int, Transform> & poses)
}
else
{
UDEBUG("Updated pose for node %d is not found, some points may not be copied. Use negative ids to just update cell values without adding new ones.", jter->first);
UDEBUG("Updated pose for node %d is not found, some points may not be copied. Use negative ids to just update cell values without adding new ones.", iter->first);
}
}

View File

@@ -65,6 +65,9 @@ std::string LaserScan::formatName(const Format & format)
case kXYZRGBNormal:
name = "XYZRGBNormal";
break;
case kXYZIT:
name = "XYZIT";
break;
default:
name = "Unknown";
break;
@@ -88,6 +91,7 @@ int LaserScan::channels(const Format & format)
channels = 4;
break;
case kXYNormal:
case kXYZIT:
channels = 5;
break;
case kXYZNormal:
@@ -119,7 +123,11 @@ bool LaserScan::isScanHasRGB(const Format & format)
}
bool LaserScan::isScanHasIntensity(const Format & format)
{
return format==kXYZI || format==kXYZINormal || format == kXYI || format == kXYINormal;
return format==kXYZI || format==kXYZINormal || format == kXYI || format == kXYINormal || format==kXYZIT;
}
bool LaserScan::isScanHasTime(const Format & format)
{
return format==kXYZIT;
}
LaserScan LaserScan::backwardCompatibility(
@@ -213,7 +221,14 @@ LaserScan::LaserScan(
const LaserScan & scan,
int maxPoints,
float maxRange,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
UASSERT(scan.empty() || scan.format() != kUnknown);
init(scan.data(), scan.format(), 0, maxRange, 0, 0, 0, maxPoints, localTransform);
@@ -224,7 +239,14 @@ LaserScan::LaserScan(
int maxPoints,
float maxRange,
Format format,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
init(scan.data(), format, 0, maxRange, 0, 0, 0, maxPoints, localTransform);
}
@@ -234,7 +256,14 @@ LaserScan::LaserScan(
int maxPoints,
float maxRange,
Format format,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
init(data, format, 0, maxRange, 0, 0, 0, maxPoints, localTransform);
}
@@ -246,7 +275,14 @@ LaserScan::LaserScan(
float angleMin,
float angleMax,
float angleIncrement,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
UASSERT(scan.empty() || scan.format() != kUnknown);
init(scan.data(), scan.format(), minRange, maxRange, angleMin, angleMax, angleIncrement, 0, localTransform);
@@ -260,7 +296,14 @@ LaserScan::LaserScan(
float angleMin,
float angleMax,
float angleIncrement,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
init(scan.data(), format, minRange, maxRange, angleMin, angleMax, angleIncrement, 0, localTransform);
}
@@ -273,7 +316,14 @@ LaserScan::LaserScan(
float angleMin,
float angleMax,
float angleIncrement,
const Transform & localTransform)
const Transform & localTransform) :
format_(kUnknown),
maxPoints_(0),
rangeMin_(0),
rangeMax_(0),
angleMin_(0),
angleMax_(0),
angleIncrement_(0)
{
init(data, format, minRange, maxRange, angleMin, angleMax, angleIncrement, 0, localTransform);
}
@@ -289,8 +339,7 @@ void LaserScan::init(
int maxPoints,
const Transform & localTransform)
{
UASSERT(data.empty() || data.rows == 1);
UASSERT(data.empty() || data.type() == CV_8UC1 || data.type() == CV_32FC2 || data.type() == CV_32FC3 || data.type() == CV_32FC(4) || data.type() == CV_32FC(5) || data.type() == CV_32FC(6) || data.type() == CV_32FC(7));
UASSERT(data.empty() || (data.type() == CV_8UC1 && data.rows == 1) || data.type() == CV_32FC2 || data.type() == CV_32FC3 || data.type() == CV_32FC(4) || data.type() == CV_32FC(5) || data.type() == CV_32FC(6) || data.type() == CV_32FC(7));
UASSERT(!localTransform.isNull());
bool is2D = false;
@@ -307,6 +356,10 @@ void LaserScan::init(
// 3D scan
UASSERT(rangeMax>=rangeMin);
maxPoints_ = maxPoints;
if(maxPoints_ == 0 && data.rows>1)
{
maxPoints_ = data.rows * data.cols;
}
}
data_ = data;
@@ -320,18 +373,18 @@ void LaserScan::init(
if(!data.empty() && !isCompressed())
{
if(is2D && data_.cols > maxPoints_)
if(is2D && (int)data_.total() > maxPoints_)
{
UWARN("The number of points (%d) in the scan is over the maximum "
UWARN("The number of points (%ld) in the scan is over the maximum "
"points (%d) defined by angle settings (min=%f max=%f inc=%f). "
"The scan info may be wrong!",
data_.cols, maxPoints_, angleMin_, angleMax_, angleIncrement_);
data_.total(), maxPoints_, angleMin_, angleMax_, angleIncrement_);
}
else if(!is2D && maxPoints_>0 && data_.cols > maxPoints_)
else if(!is2D && maxPoints_>0 && (int)data_.total() > maxPoints_)
{
UDEBUG("The number of points (%d) in the scan is over the maximum "
UDEBUG("The number of points (%ld) in the scan is over the maximum "
"points (%d) defined by max points setting.",
data_.cols, maxPoints_);
data_.total(), maxPoints_);
}
if(format == kUnknown)
@@ -350,7 +403,7 @@ void LaserScan::init(
UASSERT_MSG(data.channels() != 2 || (data.channels() == 2 && format == kXY), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 3 || (data.channels() == 3 && (format == kXYZ || format == kXYI)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 4 || (data.channels() == 4 && (format == kXYZI || format == kXYZRGB)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 5 || (data.channels() == 5 && (format == kXYNormal)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 5 || (data.channels() == 5 && (format == kXYNormal || format == kXYZIT)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 6 || (data.channels() == 6 && (format == kXYINormal || format == kXYZNormal)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
UASSERT_MSG(data.channels() != 7 || (data.channels() == 7 && (format == kXYZRGBNormal || format == kXYZINormal)), uFormat("format=%s", LaserScan::formatName(format).c_str()).c_str());
}
@@ -366,11 +419,36 @@ LaserScan LaserScan::clone() const
return LaserScan(data_.clone(), maxPoints_, rangeMax_, format_, localTransform_.clone());
}
LaserScan LaserScan::densify() const
{
if(!isOrganized())
{
return *this;
}
cv::Mat output(1, data_.total(), data_.type());
int oi = 0;
for(int i=0; i<data_.rows; ++i)
{
for(int j=0; j<data_.cols; ++j)
{
const float * ptr = data_.ptr<float>(i, j);
float * outputPtr = output.ptr<float>(0, oi);
if(! (std::isnan(ptr[0]) || std::isnan(ptr[1]) || (!is2d() && std::isnan(ptr[2]))))
{
memcpy(outputPtr, ptr, data_.elemSize());
++oi;
}
}
}
return LaserScan(cv::Mat(output, cv::Range::all(), cv::Range(0,oi)), maxPoints_, rangeMax_, format_, localTransform_.clone());
}
float & LaserScan::field(unsigned int pointIndex, unsigned int channelOffset)
{
UASSERT(pointIndex < (unsigned int)data_.cols);
UASSERT(pointIndex < (unsigned int)data_.total());
UASSERT(channelOffset < (unsigned int)data_.channels());
return data_.ptr<float>(0, pointIndex)[channelOffset];
unsigned int row = pointIndex / data_.cols;
return data_.ptr<float>(row, pointIndex - row * data_.cols)[channelOffset];
}
LaserScan & LaserScan::operator+=(const LaserScan & scan)
@@ -381,7 +459,7 @@ LaserScan & LaserScan::operator+=(const LaserScan & scan)
LaserScan LaserScan::operator+(const LaserScan & scan)
{
UASSERT(this->empty() || scan.empty() || this->format() == scan.format());
UASSERT(this->empty() || scan.empty() || (this->format() == scan.format() && !this->isOrganized() && !scan.isOrganized()));
LaserScan dest;
if(!scan.empty())
{

View File

@@ -182,7 +182,7 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
{
if(i==0)
{
*imageWithDetections = image.clone();
*imageWithDetections = cv::Mat(image.size(), subImageWithDetections.type());
}
if(!subImageWithDetections.empty())
{
@@ -363,7 +363,14 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
if(imageWithDetections)
{
image.copyTo(*imageWithDetections);
if(image.channels()==1)
{
cv::cvtColor(image, *imageWithDetections, cv::COLOR_GRAY2BGR);
}
else
{
image.copyTo(*imageWithDetections);
}
if(!ids.empty())
{
cv::aruco::drawDetectedMarkers(*imageWithDetections, corners, ids);

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