Compare commits

..
Author SHA1 Message Date
matlabbe 0fcf562042 latest update 2023-06-07 17:14:48 -07:00
matlabbe d48e2093f5 added fast normal estimation on obstacle segmentation 2023-06-02 16:05:05 -07:00
matlabbe 1b67d6a86a Triggering focal-foxy docker 2023-06-01 19:38:15 -07:00
matlabbe bfc4e939d1 Docker: updated ros2 base image to support arm64 2023-05-29 23:24:47 -07:00
André LisonandFIRST_NAME LAST_NAME 67df99aa57 fixes for texture mesh export pcl > 1.13.0 (#1039)
Co-authored-by: FIRST_NAME LAST_NAME <MY_NAME@example.com>
2023-05-29 19:00:18 -07:00
matlabbe d88c816ca1 Merge branch 'borongyuan-master' 2023-05-29 18:12:25 -07:00
matlabbe 5b1c9e7233 IMU board fix for original OAK-D 2023-05-29 17:02:53 -07:00
Borong Yuan 8d6c809c3c Update data sync implementation for DepthAI 2023-05-27 21:28:43 +08:00
Borong Yuan 52e417c313 Set IMU extrinsics to left camera optical frame 2023-05-25 12:19:07 +08:00
Borong Yuan 5592a1ebfe Update IMU local transform 2023-05-25 00:01:55 +08:00
Borong Yuan 42fbdda567 Merge branch 'introlab:master' into master 2023-05-23 10:08:21 +08:00
matlabbe ae3fda37a9 Fixed not invertible error ofter wrong graph optimization (seen on localization mode, gtsam returning inf poses) 2023-05-22 17:56:59 -07:00
Borong Yuan ffd89ead86 Get baseline using sdk method 2023-05-22 22:06:45 +08:00
Borong Yuan 937e9fbb3b Advanced parameter tuning for depth quality optimization 2023-05-22 20:29:44 +08:00
Borong Yuan 9ecf71e5ed Update DepthAI camera model 2023-05-22 18:37:08 +08:00
Borong Yuan ff83b14b49 Add options to enable IR featues on OAK Pro models 2023-05-18 01:48:38 +08:00
matlabbe 263eb6fbde Update README.md 2023-05-15 11:10:28 -07:00
matlabbe e7d61b3856 Update README.md 2023-05-15 10:45:16 -07:00
matlabbe 682d54725a Fixed build with gtsam 4.3.0 (#1033) 2023-05-14 13:14:53 -07:00
matlabbe ba33c080bc Added RGBD/LocalizationSmoothing parameter and fixed related issues (#1032)
* removed code

* added landmark in graph optimization checks

* reverted smoothing, only if there is already a previous localization link

* Added RGBDLocalizationSmoothing parameter

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml

* Update .appveyor.yml
2023-05-14 13:03:52 -07:00
matlabbe 2da448f4ee Docker: updated latest_deps dockerfile 2023-05-14 12:20:00 -07:00
matlabbe 376c82325e docker/focal: re-enabling opencv for arm64 (CI time limit issue) 2023-05-09 09:05:49 -07:00
matlabbe 95f65e1599 docker/focal: temporary disable opencv on arm64 build 2023-05-08 23:40:36 -07:00
matlabbe 060af6f7bb docker: cleanup files with nvidia, see new instructions on the wiki (no need to make another image anymore). Added latest OpenCV with xfeatures2d+nonfree modules. 2023-05-07 18:41:44 -07:00
matlabbe 999c01d71d Fixed https://github.com/introlab/rtabmap_ros/issues/948 2023-05-06 12:45:36 -07:00
matlabbe a54f76238b cmake: WITH_OPENGV=On by default 2023-04-30 14:33:58 -07:00
matlabbe f8f6b7788a Fixed #1015 2023-04-16 18:59:18 -07:00
matlabbe e54195c47f ZED SDK 4 support (#1013) 2023-04-16 18:47:15 -07:00
matlabbe e300d4c5c1 Added IMU support for camera images source with odom approach not supporting async imu 2023-04-16 17:32:32 -07:00
matlabbe b91addb261 GUI: create simple calibration->fixed optical rotation 2023-04-15 18:24:14 -07:00
matlabbe 0f221ba3cd ParametersToolbox: fixed unsigned int parameter type not showing in toolbox 2023-04-14 17:50:34 -07:00
52 changed files with 1515 additions and 694 deletions
+4 -1
View File
@@ -17,6 +17,9 @@ init:
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64
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
# 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
@@ -73,7 +76,7 @@ install:
- ps: "ls \"C:/Program Files/PCL\""
- set PATH=%PATH%;C:\Program Files\PCL\bin
# zlib
- ps: wget 'https://docs.google.com/uc?authuser=0&id=0B46akLGdg-uaYm9MTTI4MUtUcmc&export=download' -outfile zlib-1.2.8-vc2010-x64.zip
- ps: gdown -q 0B46akLGdg-uaYm9MTTI4MUtUcmc
- ps: Expand-Archive zlib-1.2.8-vc2010-x64.zip -DestinationPath 'C:\Program Files'
- ECHO "Installed zlib:"
- ps: "ls \"C:/Program Files/zlib\""
+4 -4
View File
@@ -218,7 +218,7 @@ option(WITH_OPENVINS "Include OpenVINS support" OFF)
option(WITH_MADGWICK "Include Madgwick IMU filtering support" ON)
option(WITH_FASTCV "Include FastCV support" ON)
option(WITH_OPENMP "Include OpenMP support" ON)
option(WITH_OPENGV "Include OpenGV support" OFF)
option(WITH_OPENGV "Include OpenGV support" ON)
IF(MOBILE_BUILD)
option(PCL_OMP "With PCL OMP implementations" OFF)
ELSE()
@@ -228,7 +228,7 @@ ENDIF()
set(RTABMAP_QT_VERSION AUTO CACHE STRING "Force a specific Qt version.")
set_property(CACHE RTABMAP_QT_VERSION PROPERTY STRINGS AUTO 4 5 6)
FIND_PACKAGE(OpenCV REQUIRED QUIET COMPONENTS core calib3d imgproc highgui stitching photo video OPTIONAL_COMPONENTS aruco xfeatures2d nonfree gpu cudafeatures2d)
FIND_PACKAGE(OpenCV REQUIRED QUIET COMPONENTS core calib3d imgproc highgui stitching photo video videoio OPTIONAL_COMPONENTS aruco xfeatures2d nonfree gpu cudafeatures2d)
IF(WITH_QT)
FIND_PACKAGE(PCL 1.7 REQUIRED QUIET COMPONENTS common io kdtree search surface filters registration sample_consensus segmentation visualization)
@@ -977,10 +977,10 @@ IF(NOT mynteye_FOUND)
SET(MYNTEYE "//")
ENDIF(NOT mynteye_FOUND)
IF(NOT depthai_FOUND)
SET(CONF_DEPTH_AI OFF)
SET(CONF_WITH_DEPTH_AI 0)
SET(DEPTHAI "//")
ELSE()
SET(CONF_DEPTH_AI ON)
SET(CONF_WITH_DEPTH_AI 1)
ENDIF()
IF(NOT octomap_FOUND)
SET(OCTOMAP "//")
+12 -2
View File
@@ -4,11 +4,15 @@ rtabmap
[![RTAB-Map Logo](https://raw.githubusercontent.com/introlab/rtabmap/master/guilib/src/images/RTAB-Map100.png)](http://introlab.github.io/rtabmap)
[![Release][release-image]][releases]
[![Downloads][downloads-image]][downloads]
[![License][license-image]][license]
[release-image]: https://img.shields.io/badge/release-0.20.16-green.svg?style=flat
[release-image]: https://img.shields.io/badge/release-0.21.0-green.svg?style=flat
[releases]: https://github.com/introlab/rtabmap/releases
[downloads-image]: https://img.shields.io/github/downloads/introlab/rtabmap/total?label=downloads
[downloads]: https://github.com/introlab/rtabmap/releases
[license-image]: https://img.shields.io/badge/license-BSD-green.svg?style=flat
[license]: https://github.com/introlab/rtabmap/blob/master/LICENSE
@@ -71,6 +75,12 @@ This project is supported by [IntRoLab - Intelligent / Interactive / Integrated
<td>Rolling</td>
<td><a href="http://build.ros2.org/job/Rbin_uJ64__rtabmap__ubuntu_jammy_amd64__binary/"><img src="http://build.ros2.org/buildStatus/icon?job=Rbin_uJ64__rtabmap__ubuntu_jammy_amd64__binary" alt="Build Status"/></td>
</tr>
<tr>
<td>Docker</td>
<td>
<a href="https://hub.docker.com/r/introlab3it/rtabmap">rtabmap</a>
</td>
<td><img src="https://img.shields.io/docker/pulls/introlab3it/rtabmap.svg?label=pulls" alt="Docker Pulls"/></td>
</tr>
</tbody>
</table>
+4
View File
@@ -42,6 +42,10 @@ IF(@CONF_WITH_K4A@)
ENDIF()
ENDIF()
IF(@CONF_WITH_DEPTH_AI@)
find_dependency(depthai 2)
ENDIF()
IF(@CONF_WITH_OCTOMAP@)
find_dependency(octomap)
ENDIF()
+7
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include <rtabmap/core/Transform.h>
#include <rtabmap/core/Parameters.h>
#include <rtabmap/utilite/UThread.h>
#include <rtabmap/utilite/UEventsSender.h>
#include <rtabmap/utilite/UTimer.h>
@@ -39,6 +40,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace rtabmap
{
class IMUFilter;
/**
* Class IMUThread
*
@@ -53,6 +56,8 @@ public:
bool init(const std::string & path);
void setRate(int rate);
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap & parameters = ParametersMap(), bool baseFrameConversion = false);
void disableIMUFiltering();
private:
virtual void mainLoopBegin();
@@ -65,6 +70,8 @@ private:
UTimer frameRateTimer_;
double captureDelay_;
double previousStamp_;
IMUFilter * _imuFilter;
bool _imuBaseFrameConversion;
};
} // namespace rtabmap
@@ -132,6 +132,7 @@ private:
bool normalsSegmentation_;
bool grid3D_;
bool groundIsObstacle_;
bool labelUndergroundObstaclesAsGround_;
float noiseFilteringRadius_;
int noiseFilteringMinNeighbors_;
bool scan2dUnknownSpaceFilled_;
@@ -376,6 +376,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(RGBD, MarkerDetection, bool, false, "Detect static markers to be added as landmarks for graph optimization. If input data have already landmarks, this will be ignored. See \"Marker\" group for parameters.");
RTABMAP_PARAM(RGBD, LoopCovLimited, bool, false, "Limit covariance of non-neighbor links to minimum covariance of neighbor links. In other words, if covariance of a loop closure link is smaller than the minimum covariance of odometry links, its covariance is set to minimum covariance of odometry links.");
RTABMAP_PARAM(RGBD, MaxOdomCacheSize, int, 10, uFormat("Maximum odometry cache size. Used only in localization mode (when %s=false). This is used to get smoother localizations and to verify localization transforms (when %s!=0) to make sure we don't teleport to a location very similar to one we previously localized on. Set 0 to disable caching.", kMemIncrementalMemory().c_str(), kRGBDOptimizeMaxError().c_str()));
RTABMAP_PARAM(RGBD, LocalizationSmoothing, bool, true, uFormat("Adjust localization constraints based on optimized odometry cache poses (when %s>0).", kRGBDMaxOdomCacheSize().c_str()));
// Local/Proximity loop closure detection
RTABMAP_PARAM(RGBD, ProximityByTime, bool, false, "Detection over all locations in STM.");
@@ -759,6 +760,7 @@ class RTABMAP_CORE_EXPORT Parameters
RTABMAP_PARAM(Grid, 3D, bool, false, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is 0.", kGridSensor().c_str()));
#endif
RTABMAP_PARAM(Grid, GroundIsObstacle, bool, false, uFormat("[%s=true] Ground segmentation (%s) is ignored, all points are obstacles. Use this only if you want an OctoMap with ground identified as an obstacle (e.g., with an UAV).", kGrid3D().c_str(), kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, UndergroundIsGround, bool, false, uFormat("[%s=true] Label all underground points under largest flat surface detected as ground.", kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, NoiseFilteringRadius, float, 0.0, "Noise filtering radius (0=disabled). Done after segmentation.");
RTABMAP_PARAM(Grid, NoiseFilteringMinNeighbors, int, 5, "Noise filtering minimum neighbors.");
RTABMAP_PARAM(Grid, Scan2dUnknownSpaceFilled, bool, false, uFormat("Unknown space filled. Only used with 2D laser scans. Use %s to set maximum range if laser scan max range is to set.", kGridRangeMax().c_str()));
+1
View File
@@ -326,6 +326,7 @@ private:
bool _loopCovLimited;
bool _loopGPS;
int _maxOdomCacheSize;
bool _localizationSmoothing;
bool _createGlobalScanMap;
float _markerPriorsLinearVariance;
float _markerPriorsAngularVariance;
@@ -58,6 +58,9 @@ public:
void setOutputDepth(bool enabled, int confidence = 200);
void setIMUFirmwareUpdate(bool enabled);
void setIMUPublished(bool published);
void publishInterIMU(bool enabled);
void setLaserDotBrightness(float dotProjectormA = 0.0f);
void setFloodLightBrightness(float floodLightmA = 200.0f);
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
virtual bool isCalibrated() const;
@@ -76,12 +79,15 @@ private:
int resolution_;
bool imuFirmwareUpdate_;
bool imuPublished_;
bool publishInterIMU_;
float dotProjectormA_;
float floodLightmA_;
std::shared_ptr<dai::Device> device_;
std::shared_ptr<dai::DataOutputQueue> leftQueue_;
std::shared_ptr<dai::DataOutputQueue> rightOrDepthQueue_;
std::shared_ptr<dai::DataOutputQueue> imuQueue_;
std::map<double, cv::Vec3f> accBuffer_;
std::map<double, cv::Vec3f> gyroBuffer_;
UMutex imuMutex_;
#endif
};
@@ -45,11 +45,11 @@ class RTABMAP_CORE_EXPORT CameraStereoZed :
{
public:
static bool available();
static int sdkVersion();
public:
CameraStereoZed(
int deviceId,
int resolution = 2, // 0=HD2K, 1=HD1080, 2=HD720, 3=VGA
int resolution = 6, // 0=HD2K, 1=HD1080, 2=HD1200, 3=HD720, 4=SVGA, 5=VGA, 6=AUTO
int quality = 1, // 0=NONE, 1=PERFORMANCE, 2=QUALITY
int sensingMode = 0,// 0=STANDARD, 1=FILL
int confidenceThr = 100,
@@ -61,7 +61,7 @@ public:
int texturenessConfidenceThr = 90); // introduced with ZED SDK 3
CameraStereoZed(
const std::string & svoFilePath,
int quality = 1, // 0=NONE, 1=PERFORMANCE, 2=QUALITY
int quality = 1, // 0=NONE, 1=PERFORMANCE, 2=QUALITY, 3=NEURAL
int sensingMode = 0,// 0=STANDARD, 1=FILL
int confidenceThr = 100,
bool computeOdometry = false,
@@ -44,6 +44,8 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
pcl::IndicesPtr & obstaclesIndices,
pcl::IndicesPtr * flatObstacles) const
{
UDEBUG("cloudIn=%dx%d indicesIn=%ld", cloudIn->width, cloudIn->height, indicesIn->size());
groundIndices.reset(new std::vector<int>);
obstaclesIndices.reset(new std::vector<int>);
if(flatObstacles)
@@ -54,6 +56,7 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
typename pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
pcl::IndicesPtr indices(new std::vector<int>);
UDEBUG("preVoxelFiltering=%d", preVoxelFiltering_?1:0);
if(preVoxelFiltering_)
{
// voxelize to grid cell size
@@ -127,6 +130,9 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0);
UDEBUG("maxGroundHeight=%f", maxGroundHeight_);
UDEBUG("groundNormalsUp=%f", groundNormalsUp_);
UDEBUG("labelUndergroundObstaclesAsGround=%d", labelUndergroundObstaclesAsGround_?1:0);
UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0));
UDEBUG("cloud=%dx%d indices=%ld", cloud->width, cloud->height, indices->size());
util3d::segmentObstaclesFromGround<PointT>(
cloud,
indices,
@@ -140,8 +146,8 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
maxGroundHeight_,
flatObstacles,
Eigen::Vector4f(viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0), 1),
groundNormalsUp_);
UDEBUG("viewPoint=%f,%f,%f", viewPoint.x, viewPoint.y, viewPoint.z+(projMapFrame_?pose.z():0));
groundNormalsUp_,
labelUndergroundObstaclesAsGround_);
//UWARN("Saving ground.pcd and obstacles.pcd");
//pcl::io::savePCDFile("ground.pcd", *cloud, *groundIndices);
//pcl::io::savePCDFile("obstacles.pcd", *cloud, *obstaclesIndices);
@@ -165,6 +171,42 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
UDEBUG("groundIndices=%d obstaclesIndices=%d", (int)groundIndices->size(), (int)obstaclesIndices->size());
if(!preVoxelFiltering_ && (!groundIndices->empty() || !obstaclesIndices->empty()))
{
// voxelize to grid cell size
typename pcl::PointCloud<PointT>::Ptr cloudWithTransform = cloud;
cloud.reset(new pcl::PointCloud<PointT>);
if(!groundIndices->empty())
{
*cloud += *util3d::voxelize(cloudWithTransform, groundIndices, cellSize_);
groundIndices->resize(cloud->size());
for(size_t i=0; i<groundIndices->size(); ++i)
{
groundIndices->at(i) = i;
}
}
if(!obstaclesIndices->empty())
{
int previousSize = cloud->size();
*cloud += *util3d::voxelize(cloudWithTransform, obstaclesIndices, cellSize_);
obstaclesIndices->resize(cloud->size()-previousSize);
for(size_t i=0; i<obstaclesIndices->size(); ++i)
{
obstaclesIndices->at(i) = previousSize+i;
}
}
if(flatObstacles && !(*flatObstacles)->empty())
{
int previousSize = cloud->size();
*cloud += *util3d::voxelize(cloudWithTransform, *flatObstacles, cellSize_);
(*flatObstacles)->resize(cloud->size()-previousSize);
for(size_t i=0; i<(*flatObstacles)->size(); ++i)
{
(*flatObstacles)->at(i) = previousSize+i;
}
}
}
// Do radius filtering after voxel filtering ( a lot faster)
if(noiseFilteringRadius_ > 0.0 && noiseFilteringMinNeighbors_ > 0)
{
@@ -50,6 +50,79 @@ typename pcl::PointCloud<PointT>::Ptr projectCloudOnXYPlane(
return output;
}
void clusterIndicesFloodfill(std::vector<int> & cluster,
float * visitedIndices,
int width,
int height,
float clusterRadius,
int currentIndex,
float previousHeight);
/**
* @brief Cluster indices of an organized cloud
*
* @tparam PointT
* @param cloud
* @param indices
* @param minClusterSize
* @param maxClusterSize
* @param biggestClusterIndex
* @return std::vector<pcl::IndicesPtr>
*/
template<typename PointT>
std::vector<pcl::IndicesPtr> clusterIndices(
const typename pcl::PointCloud<PointT>::Ptr & cloud,
const typename pcl::IndicesPtr & indices,
float clusterRadius,
int minClusterSize,
int maxClusterSize,
int * biggestClusterIndex)
{
std::vector<pcl::IndicesPtr> clusters;
if(cloud->empty())
{
return clusters;
}
UASSERT(cloud->isOrganized());
cv::Mat visitedIndices = cv::Mat::zeros(cloud->height, cloud->width, CV_32FC1);
float * ptr = visitedIndices.ptr<float>();
// init search image
for(size_t i = 0; i<indices->size(); ++i)
{
ptr[indices->at(i)] = cloud->at(indices->at(i)).z;
}
int largestCluster = -1;
int largestClusterSize = 0;
int sum = 0;
for(size_t i = 0; i<indices->size(); ++i)
{
if(ptr[indices->at(i)] != 0.0f)
{
pcl::IndicesPtr cluster(new pcl::Indices());
clusterIndicesFloodfill(*cluster, ptr, visitedIndices.cols, visitedIndices.rows, clusterRadius, indices->at(i), ptr[indices->at(i)]);
if(cluster->size()>0 && (int)cluster->size()>=minClusterSize && (int)cluster->size()<=maxClusterSize)
{
clusters.push_back(cluster);
if((int)cluster->size() > largestClusterSize)
{
sum+=cluster->size();
largestCluster = clusters.size()-1;
largestClusterSize = cluster->size();
}
}
}
}
if(biggestClusterIndex)
{
*biggestClusterIndex = largestCluster;
}
return clusters;
}
template<typename PointT>
void segmentObstaclesFromGround(
const typename pcl::PointCloud<PointT>::Ptr & cloud,
@@ -64,7 +137,8 @@ void segmentObstaclesFromGround(
float maxGroundHeight,
pcl::IndicesPtr * flatObstacles,
const Eigen::Vector4f & viewPoint,
float groundNormalsUp)
float groundNormalsUp,
bool labelUndergroundObstaclesAsGround)
{
ground.reset(new std::vector<int>);
obstacles.reset(new std::vector<int>);
@@ -75,6 +149,8 @@ void segmentObstaclesFromGround(
if(cloud->size())
{
UDEBUG("Normal filtering.... cloud=%ld indices=%ld organized=%d",
cloud->size(), indices->size(), cloud->isOrganized()?1:0);
// Find the ground
pcl::IndicesPtr flatSurfaces = normalFiltering(
cloud,
@@ -84,22 +160,40 @@ void segmentObstaclesFromGround(
normalKSearch,
viewPoint,
groundNormalsUp);
UDEBUG("%ld points on flat surfaces (input indices = %ld, total cloud=%ld)",
flatSurfaces->size(), indices->size(), cloud->size());
Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax(0,0,0,0);
if(segmentFlatObstacles && flatSurfaces->size())
{
int biggestFlatSurfaceIndex;
std::vector<pcl::IndicesPtr> clusteredFlatSurfaces = extractClusters(
std::vector<pcl::IndicesPtr> clusteredFlatSurfaces;
if(cloud->isOrganized())
{
clusteredFlatSurfaces = clusterIndices<PointT>(
cloud,
flatSurfaces,
clusterRadius,
minClusterSize,
std::numeric_limits<int>::max(),
&biggestFlatSurfaceIndex);
UDEBUG("clusteredFlatSurfaces=%ld", clusteredFlatSurfaces.size());
}
else
{
clusteredFlatSurfaces = extractClusters(
cloud,
flatSurfaces,
clusterRadius,
minClusterSize,
std::numeric_limits<int>::max(),
&biggestFlatSurfaceIndex);
}
// cluster all surfaces for which the centroid is in the Z-range of the bigger surface
if(clusteredFlatSurfaces.size())
{
Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax;
if(maxGroundHeight != 0.0f)
{
// Search for biggest surface under max ground height
@@ -125,9 +219,12 @@ void segmentObstaclesFromGround(
if(biggestFlatSurfaceIndex>=0)
{
ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
UDEBUG("Biggest flat surface size = %ld (%d%%) (z min=%f max=%f)",
ground->size(), 100*ground->size()/cloud->size(), biggestSurfaceMin[2], biggestSurfaceMax[2]);
}
if(!ground->empty() && (maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
if(!ground->empty() &&
(maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
{
for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
{
@@ -135,7 +232,7 @@ void segmentObstaclesFromGround(
{
Eigen::Vector4f centroid(0,0,0,1);
pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
if(maxGroundHeight==0.0f || centroid[2] <= maxGroundHeight || centroid[2] <= biggestSurfaceMax[2]) // epsilon
if(centroid[2] <= biggestSurfaceMax[2]) // relative to ground detected
{
ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
}
@@ -145,9 +242,46 @@ void segmentObstaclesFromGround(
}
}
}
int groundRatio = 100*ground->size()/cloud->size();
int minGroundRatio = 10;
if(minGroundRatio != 0 && groundRatio<minGroundRatio)
{
if(labelUndergroundObstaclesAsGround && maxGroundHeight!=0.0f)
{
// just do passthrough (e.g. reflective floor)
UWARN("Failed normal segmentation (ground ratio=%d%%, ground height=%f), fallback to passThrough (label underground as ground is true).",
groundRatio, !ground->empty()?biggestSurfaceMin[2]:0.0f);
// passthrough filter
ground = rtabmap::util3d::passThrough(cloud, indices, "z",
std::numeric_limits<int>::min(),
maxGroundHeight!=0.0f?maxGroundHeight:std::numeric_limits<int>::max());
pcl::IndicesPtr notObstacles = ground;
if(indices->size())
{
notObstacles = util3d::extractIndices(cloud, indices, true);
notObstacles = util3d::concatenate(notObstacles, ground);
}
obstacles = rtabmap::util3d::extractIndices(cloud, notObstacles, true);
return;
}
else
{
UWARN("Failed normal segmentation, ground surface is too small (ground ratio=%d%%, ground height=%f)!",
groundRatio, !ground->empty()?biggestSurfaceMin[2]:0.0f);
// reject ground!
ground.reset(new std::vector<int>);
if(flatObstacles)
{
*flatObstacles = flatSurfaces;
}
}
}
}
else
{
UWARN("Failed normal segmentation, could not detect the ground!");
// reject ground!
ground.reset(new std::vector<int>);
if(flatObstacles)
@@ -168,28 +302,49 @@ void segmentObstaclesFromGround(
pcl::IndicesPtr notObstacles = ground;
if(indices->size())
{
// This will ignore all points not in input indices for obstacles.
notObstacles = util3d::extractIndices(cloud, indices, true);
notObstacles = util3d::concatenate(notObstacles, ground);
}
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
// If ground height is set, remove obstacles under it
if(maxGroundHeight != 0.0f)
// If ground height is set and if we label obstacles under it as ground
if(labelUndergroundObstaclesAsGround)
{
otherStuffIndices = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", maxGroundHeight, std::numeric_limits<float>::max());
float max = biggestSurfaceMax[2];
if(maxGroundHeight > 0)
{
max += maxGroundHeight;
}
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
pcl::IndicesPtr underground = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", (float)std::numeric_limits<int>::min(), max);
if(!underground->empty())
{
ground = util3d::concatenate(ground, underground);
notObstacles = util3d::concatenate(underground, notObstacles);
}
}
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
//Cluster remaining stuff (obstacles)
if(otherStuffIndices->size())
{
std::vector<pcl::IndicesPtr> clusteredObstaclesSurfaces = util3d::extractClusters(
cloud,
otherStuffIndices,
clusterRadius,
minClusterSize);
if(minClusterSize>1)
{
std::vector<pcl::IndicesPtr> clusteredObstaclesSurfaces = util3d::extractClusters(
cloud,
otherStuffIndices,
clusterRadius,
minClusterSize);
// merge indices
obstacles = util3d::concatenate(clusteredObstaclesSurfaces);
// merge indices
obstacles = util3d::concatenate(clusteredObstaclesSurfaces);
}
else
{
obstacles = otherStuffIndices;
}
}
}
}
@@ -208,7 +363,8 @@ void segmentObstaclesFromGround(
float maxGroundHeight,
pcl::IndicesPtr * flatObstacles,
const Eigen::Vector4f & viewPoint,
float groundNormalsUp)
float groundNormalsUp,
bool labelUndergroundObstaclesAsGround)
{
pcl::IndicesPtr indices(new std::vector<int>);
segmentObstaclesFromGround<PointT>(
@@ -224,7 +380,8 @@ void segmentObstaclesFromGround(
maxGroundHeight,
flatObstacles,
viewPoint,
groundNormalsUp);
groundNormalsUp,
labelUndergroundObstaclesAsGround);
}
template<typename PointT>
@@ -157,7 +157,8 @@ void segmentObstaclesFromGround(
float maxGroundHeight = 0.0f,
pcl::IndicesPtr * flatObstacles = 0,
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
float groundNormalsUp = 0);
float groundNormalsUp = 0,
bool labelUndergroundObstaclesAsGround = false);
template<typename PointT>
void segmentObstaclesFromGround(
const typename pcl::PointCloud<PointT>::Ptr & cloud,
@@ -171,7 +172,8 @@ void segmentObstaclesFromGround(
float maxGroundHeight = 0.0f,
pcl::IndicesPtr * flatObstacles = 0,
const Eigen::Vector4f & viewPoint = Eigen::Vector4f(0,0,100,0),
float groundNormalsUp = 0);
float groundNormalsUp = 0,
bool labelUndergroundObstaclesAsGround = false);
template<typename PointT>
void occupancy2DFromGroundObstacles(
@@ -381,6 +381,17 @@ pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormal
float searchRadius = 0.0f,
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
float maxDepthChangeFactor = 0.02f,
float normalSmoothingSize = 10.0f,
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const pcl::IndicesPtr & indices,
float maxDepthChangeFactor = 0.02f,
float normalSmoothingSize = 10.0f,
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_CORE_EXPORT computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
float maxDepthChangeFactor = 0.02f,
+53 -21
View File
@@ -902,7 +902,7 @@ void computeMaxGraphErrors(
float & maxAngularError,
const Link ** maxLinearErrorLink,
const Link ** maxAngularErrorLink,
bool for3DoF)
bool force3DoF)
{
maxLinearErrorRatio = -1;
maxAngularErrorRatio = -1;
@@ -912,17 +912,44 @@ void computeMaxGraphErrors(
UDEBUG("poses=%d links=%d", (int)poses.size(), (int)links.size());
for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
{
// ignore links with high variance, priors and landmarks
if(iter->second.transVariance() <= 1.0 && iter->second.from() != iter->second.to() && iter->second.type() != Link::kLandmark)
// ignore priors
if(iter->second.from() != iter->second.to())
{
Transform t1 = uValue(poses, iter->second.from(), Transform());
Transform t2 = uValue(poses, iter->second.to(), Transform());
if( t1.isNull() ||
t2.isNull() ||
!t1.isInvertible() ||
!t2.isInvertible())
{
UWARN("Poses are null or not invertible, aborting optimized graph max error check! (Pose %d=%s Pose %d=%s)",
iter->second.from(),
t1.prettyPrint().c_str(),
iter->second.to(),
t2.prettyPrint().c_str());
if(maxLinearErrorLink)
{
*maxLinearErrorLink = 0;
}
if(maxAngularErrorLink)
{
*maxAngularErrorLink = 0;
}
maxLinearErrorRatio = -1;
maxAngularErrorRatio = -1;
maxLinearError = -1;
maxAngularError = -1;
return;
}
Transform t = t1.inverse()*t2;
float linearError = uMax3(
fabs(iter->second.transform().x() - t.x()),
fabs(iter->second.transform().y() - t.y()),
for3DoF?0:fabs(iter->second.transform().z() - t.z()));
force3DoF?0:fabs(iter->second.transform().z() - t.z()));
UASSERT(iter->second.transVariance(false)>0.0);
float stddevLinear = sqrt(iter->second.transVariance(false));
float linearErrorRatio = linearError/stddevLinear;
@@ -936,25 +963,30 @@ void computeMaxGraphErrors(
}
}
float opt_roll,opt_pitch,opt_yaw;
float link_roll,link_pitch,link_yaw;
t.getEulerAngles(opt_roll, opt_pitch, opt_yaw);
iter->second.transform().getEulerAngles(link_roll, link_pitch, link_yaw);
float angularError = uMax3(
for3DoF?0:fabs(opt_roll - link_roll),
for3DoF?0:fabs(opt_pitch - link_pitch),
fabs(opt_yaw - link_yaw));
angularError = angularError>M_PI?2*M_PI-angularError:angularError;
UASSERT(iter->second.rotVariance(false)>0.0);
float stddevAngular = sqrt(iter->second.rotVariance(false));
float angularErrorRatio = angularError/stddevAngular;
if(angularErrorRatio > maxAngularErrorRatio)
// For landmark links, don't compute angular error if it doesn't estimate orientation
if(iter->second.type() != Link::kLandmark ||
1.0 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999.0)
{
maxAngularError = angularError;
maxAngularErrorRatio = angularErrorRatio;
if(maxAngularErrorLink)
float opt_roll,opt_pitch,opt_yaw;
float link_roll,link_pitch,link_yaw;
t.getEulerAngles(opt_roll, opt_pitch, opt_yaw);
iter->second.transform().getEulerAngles(link_roll, link_pitch, link_yaw);
float angularError = uMax3(
force3DoF?0:fabs(opt_roll - link_roll),
force3DoF?0:fabs(opt_pitch - link_pitch),
fabs(opt_yaw - link_yaw));
angularError = angularError>M_PI?2*M_PI-angularError:angularError;
UASSERT(iter->second.rotVariance(false)>0.0);
float stddevAngular = sqrt(iter->second.rotVariance(false));
float angularErrorRatio = angularError/stddevAngular;
if(angularErrorRatio > maxAngularErrorRatio)
{
*maxAngularErrorLink = &iter->second;
maxAngularError = angularError;
maxAngularErrorRatio = angularErrorRatio;
if(maxAngularErrorLink)
{
*maxAngularErrorLink = &iter->second;
}
}
}
}
+72 -1
View File
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/IMUThread.h"
#include "rtabmap/core/IMU.h"
#include "rtabmap/core/IMUFilter.h"
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UConversion.h>
@@ -38,13 +39,16 @@ IMUThread::IMUThread(int rate, const Transform & localTransform) :
rate_(rate),
localTransform_(localTransform),
captureDelay_(0.0),
previousStamp_(0.0)
previousStamp_(0.0),
_imuFilter(0),
_imuBaseFrameConversion(false)
{
}
IMUThread::~IMUThread()
{
imuFile_.close();
delete _imuFilter;
}
bool IMUThread::init(const std::string & path)
@@ -81,6 +85,19 @@ void IMUThread::setRate(int rate)
rate_ = rate;
}
void IMUThread::enableIMUFiltering(int filteringStrategy, const ParametersMap & parameters, bool baseFrameConversion)
{
delete _imuFilter;
_imuFilter = IMUFilter::create((IMUFilter::Type)filteringStrategy, parameters);
_imuBaseFrameConversion = baseFrameConversion;
}
void IMUThread::disableIMUFiltering()
{
delete _imuFilter;
_imuFilter = 0;
}
void IMUThread::mainLoopBegin()
{
ULogger::registerCurrentThread("IMU");
@@ -141,6 +158,60 @@ void IMUThread::mainLoop()
previousStamp_ = stamp;
IMU imu(gyr, cv::Mat(), acc, cv::Mat(), localTransform_);
// IMU filtering
if(_imuFilter && !imu.empty())
{
if(imu.angularVelocity()[0] == 0 &&
imu.angularVelocity()[1] == 0 &&
imu.angularVelocity()[2] == 0 &&
imu.linearAcceleration()[0] == 0 &&
imu.linearAcceleration()[1] == 0 &&
imu.linearAcceleration()[2] == 0)
{
UWARN("IMU's acc and gyr values are null! Please disable IMU filtering.");
}
else
{
// Transform IMU data in base_link to correctly initialize yaw
if(_imuBaseFrameConversion)
{
UASSERT(!imu.localTransform().isNull());
imu.convertToBaseFrame();
}
_imuFilter->update(
imu.angularVelocity()[0],
imu.angularVelocity()[1],
imu.angularVelocity()[2],
imu.linearAcceleration()[0],
imu.linearAcceleration()[1],
imu.linearAcceleration()[2],
stamp);
double qx,qy,qz,qw;
_imuFilter->getOrientation(qx,qy,qz,qw);
imu = IMU(
cv::Vec4d(qx,qy,qz,qw), cv::Mat::eye(3,3,CV_64FC1),
imu.angularVelocity(), imu.angularVelocityCovariance(),
imu.linearAcceleration(), imu.linearAccelerationCovariance(),
imu.localTransform());
UDEBUG("%f %f %f %f (gyro=%f %f %f, acc=%f %f %f, %fs)",
imu.orientation()[0],
imu.orientation()[1],
imu.orientation()[2],
imu.orientation()[3],
imu.angularVelocity()[0],
imu.angularVelocity()[1],
imu.angularVelocity()[2],
imu.linearAcceleration()[0],
imu.linearAcceleration()[1],
imu.linearAcceleration()[2],
stamp);
}
}
this->post(new IMUEvent(imu, stamp));
}
else if(!this->isKilled())
+4
View File
@@ -283,6 +283,10 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
-landmarkId, inserted.first->second, landmarkSize.at<float>(0,0));
}
}
else
{
UDEBUG("Caching landmark size %f for %d", landmarkSize.at<float>(0,0), -landmarkId);
}
}
std::map<int, std::set<int> >::iterator nter = _landmarksIndex.find(landmarkId);
+2
View File
@@ -66,6 +66,7 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
normalsSegmentation_(Parameters::defaultGridNormalsSegmentation()),
grid3D_(Parameters::defaultGrid3D()),
groundIsObstacle_(Parameters::defaultGridGroundIsObstacle()),
labelUndergroundObstaclesAsGround_(Parameters::defaultGridUndergroundIsGround()),
noiseFilteringRadius_(Parameters::defaultGridNoiseFilteringRadius()),
noiseFilteringMinNeighbors_(Parameters::defaultGridNoiseFilteringMinNeighbors()),
scan2dUnknownSpaceFilled_(Parameters::defaultGridScan2dUnknownSpaceFilled()),
@@ -128,6 +129,7 @@ void OccupancyGrid::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kGridNormalsSegmentation(), normalsSegmentation_);
Parameters::parse(parameters, Parameters::kGrid3D(), grid3D_);
Parameters::parse(parameters, Parameters::kGridGroundIsObstacle(), groundIsObstacle_);
Parameters::parse(parameters, Parameters::kGridUndergroundIsGround(), labelUndergroundObstaclesAsGround_);
Parameters::parse(parameters, Parameters::kGridNoiseFilteringRadius(), noiseFilteringRadius_);
Parameters::parse(parameters, Parameters::kGridNoiseFilteringMinNeighbors(), noiseFilteringMinNeighbors_);
Parameters::parse(parameters, Parameters::kGridScan2dUnknownSpaceFilled(), scan2dUnknownSpaceFilled_);
+4
View File
@@ -324,6 +324,10 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
imus_.erase(imus_.begin());
}
}
else
{
UWARN("Received IMU doesn't have orientation set! It is ignored.");
}
}
+27 -15
View File
@@ -147,6 +147,7 @@ Rtabmap::Rtabmap() :
_loopCovLimited(Parameters::defaultRGBDLoopCovLimited()),
_loopGPS(Parameters::defaultRtabmapLoopGPS()),
_maxOdomCacheSize(Parameters::defaultRGBDMaxOdomCacheSize()),
_localizationSmoothing(Parameters::defaultRGBDLocalizationSmoothing()),
_createGlobalScanMap(Parameters::defaultRGBDProximityGlobalScanMap()),
_markerPriorsLinearVariance(Parameters::defaultMarkerPriorsVarianceLinear()),
_markerPriorsAngularVariance(Parameters::defaultMarkerPriorsVarianceAngular()),
@@ -618,6 +619,7 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), _loopCovLimited);
Parameters::parse(parameters, Parameters::kRtabmapLoopGPS(), _loopGPS);
Parameters::parse(parameters, Parameters::kRGBDMaxOdomCacheSize(), _maxOdomCacheSize);
Parameters::parse(parameters, Parameters::kRGBDLocalizationSmoothing(), _localizationSmoothing);
Parameters::parse(parameters, Parameters::kRGBDProximityGlobalScanMap(), _createGlobalScanMap);
Parameters::parse(parameters, Parameters::kMarkerPriorsVarianceLinear(), _markerPriorsLinearVariance);
@@ -3173,10 +3175,10 @@ bool Rtabmap::process(
&maxLinearLink,
&maxAngularLink,
_graphOptimizer->isSlam2d());
if(maxLinearLink == 0 && maxAngularLink==0 && _maxOdomCacheSize>0)
if(maxLinearLink == 0 && maxAngularLink==0)
{
UWARN("Could not compute graph errors! Wrong loop closures could be accepted!");
optPoses = posesOut;
UWARN("Could not compute graph errors! Rejecting localization!");
rejectLocalization = true;
}
if(maxLinearLink)
@@ -3287,10 +3289,10 @@ bool Rtabmap::process(
&maxLinearLink,
&maxAngularLink,
_graphOptimizer->isSlam2d());
if(maxLinearLink == 0 && maxAngularLink==0 && _maxOdomCacheSize>0)
if(maxLinearLink == 0 && maxAngularLink==0)
{
UWARN("Could not compute graph errors! Wrong loop closures could be accepted!");
optPoses = posesOut;
UWARN("Could not compute graph errors! Rejecting localization!");
rejectLocalization = true;
}
if(maxLinearLink)
@@ -3395,16 +3397,26 @@ bool Rtabmap::process(
Transform newOptPoseInv = optPoses.at(signature->id()).inverse();
for(std::multimap<int, Link>::iterator iter=localizationLinks.begin(); iter!=localizationLinks.end(); ++iter)
{
Transform newT = newOptPoseInv * optPoses.at(iter->first);
UDEBUG("Adjusted localization link %d->%d after optimization", iter->second.from(), iter->second.to());
UDEBUG("from %s", iter->second.transform().prettyPrint().c_str());
UDEBUG(" to %s", newT.prettyPrint().c_str());
iter->second.setTransform(newT);
// Update link in the referred signatures
if(iter->first > 0)
_memory->updateLink(iter->second, false);
if(!_localizationSmoothing)
{
// Add original link without optimization
UDEBUG("Adding new odom cache constraint %d->%d (%s)",
iter->second.from(), iter->second.to(), iter->second.transform().prettyPrint().c_str());
}
else
{
// Adjust with optimized poses, this will smooth the localization
Transform newT = newOptPoseInv * optPoses.at(iter->first);
UDEBUG("Adjusted localization link %d->%d after optimization", iter->second.from(), iter->second.to());
UDEBUG("from %s", iter->second.transform().prettyPrint().c_str());
UDEBUG(" to %s", newT.prettyPrint().c_str());
iter->second.setTransform(newT);
// Update link in the referred signatures
if(iter->first > 0)
_memory->updateLink(iter->second, false);
}
_odomCacheConstraints.insert(std::make_pair(signature->id(), iter->second));
}
+163 -190
View File
@@ -57,7 +57,10 @@ CameraDepthAI::CameraDepthAI(
depthConfidence_(200),
resolution_(resolution),
imuFirmwareUpdate_(false),
imuPublished_(true)
imuPublished_(true),
publishInterIMU_(false),
dotProjectormA_(0.0),
floodLightmA_(200.0)
#endif
{
#ifdef RTABMAP_DEPTHAI
@@ -106,6 +109,33 @@ void CameraDepthAI::setIMUPublished(bool published)
#endif
}
void CameraDepthAI::publishInterIMU(bool enabled)
{
#ifdef RTABMAP_DEPTHAI
publishInterIMU_ = enabled;
#else
UERROR("CameraDepthAI: RTAB-Map is not built with depthai-core support!");
#endif
}
void CameraDepthAI::setLaserDotBrightness(float dotProjectormA)
{
#ifdef RTABMAP_DEPTHAI
dotProjectormA_ = dotProjectormA;
#else
UERROR("CameraDepthAI: RTAB-Map is not built with depthai-core support!");
#endif
}
void CameraDepthAI::setFloodLightBrightness(float floodLightmA)
{
#ifdef RTABMAP_DEPTHAI
floodLightmA_ = floodLightmA;
#else
UERROR("CameraDepthAI: RTAB-Map is not built with depthai-core support!");
#endif
}
bool CameraDepthAI::init(const std::string & calibrationFolder, const std::string & cameraName)
{
UDEBUG("");
@@ -183,31 +213,29 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
}
// StereoDepth
stereo->initialConfig.setConfidenceThreshold(depthConfidence_);
stereo->initialConfig.setLeftRightCheckThreshold(5);
stereo->setRectifyEdgeFillColor(0); // black, to better see the cutout
stereo->setLeftRightCheck(true);
stereo->setSubpixel(false);
stereo->setDepthAlign(dai::StereoDepthProperties::DepthAlign::RECTIFIED_LEFT);
stereo->setSubpixel(true);
stereo->setSubpixelFractionalBits(4);
stereo->setExtendedDisparity(false);
stereo->setRectifyEdgeFillColor(0); // black, to better see the cutout
stereo->initialConfig.setConfidenceThreshold(depthConfidence_);
stereo->initialConfig.setLeftRightCheck(true);
stereo->initialConfig.setLeftRightCheckThreshold(5);
stereo->initialConfig.setMedianFilter(dai::MedianFilter::KERNEL_5x5);
auto config = stereo->initialConfig.get();
config.costMatching.disparityWidth = dai::StereoDepthConfig::CostMatching::DisparityWidth::DISPARITY_64;
config.costMatching.enableCompanding = true;
stereo->initialConfig.set(config);
// Link plugins CAM -> STEREO -> XLINK
monoLeft->out.link(stereo->left);
monoRight->out.link(stereo->right);
stereo->rectifiedLeft.link(xoutLeft->input);
if(outputDepth_)
{
// Depth is registered to right image by default, so subscribe to right image when depth is used
if(outputDepth_)
stereo->rectifiedRight.link(xoutLeft->input);
else
stereo->rectifiedLeft.link(xoutLeft->input);
stereo->depth.link(xoutDepthOrRight->input);
}
else
{
stereo->rectifiedLeft.link(xoutLeft->input);
stereo->rectifiedRight.link(xoutDepthOrRight->input);
}
if(imuPublished_)
{
@@ -235,8 +263,7 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
double fy = matrix[1][1];
double cx = matrix[0][2];
double cy = matrix[1][2];
matrix = calibHandler.getCameraExtrinsics(dai::CameraBoardSocket::RIGHT, dai::CameraBoardSocket::LEFT);
double baseline = matrix[0][3]/100.0;
double baseline = calibHandler.getBaselineDistance(dai::CameraBoardSocket::RIGHT, dai::CameraBoardSocket::LEFT, false)/100.0;
UINFO("left: fx=%f fy=%f cx=%f cy=%f baseline=%f", fx, fy, cx, cy, baseline);
stereoModel_ = StereoCameraModel(device_->getMxId(), fx, fy, cx, cy, baseline, this->getLocalTransform(), targetSize);
@@ -249,12 +276,27 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
// matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
// matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
// matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3]);
// Hard-coded: x->down, y->left, z->forward
imuLocalTransform_ = Transform(
0, 0, 1, 0,
0, 1, 0, 0,
-1 ,0, 0, 0);
UINFO("IMU local transform = %s", imuLocalTransform_.prettyPrint().c_str());
auto eeprom = calibHandler.getEepromData();
if(eeprom.boardName == "OAK-D" ||
eeprom.boardName == "BW1098OBC")
{
imuLocalTransform_ = Transform(
0, -1, 0, 0.0525,
1, 0, 0, 0.0137,
0, 0, 1, 0);
}
else if(eeprom.boardName == "DM9098")
{
imuLocalTransform_ = Transform(
0, 1, 0, 0.0754,
1, 0, 0, 0.0026,
0, 0, -1, -0.007);
}
else
{
UWARN("Unknown boardName (%s)! Disabling IMU!", eeprom.boardName.c_str());
imuPublished_ = false;
}
}
else
{
@@ -263,10 +305,47 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
if(imuPublished_)
{
imuQueue_ = device_->getOutputQueue("imu", 50, false);
imuLocalTransform_ = this->getLocalTransform() * imuLocalTransform_;
UINFO("IMU local transform = %s", imuLocalTransform_.prettyPrint().c_str());
device_->getOutputQueue("imu", 50, false)->addCallback([this](std::shared_ptr<dai::ADatatype> callback) {
if(dynamic_cast<dai::IMUData*>(callback.get()) != nullptr)
{
dai::IMUData* imuData = static_cast<dai::IMUData*>(callback.get());
auto imuPackets = imuData->packets;
for(auto& imuPacket : imuPackets)
{
auto& acceleroValues = imuPacket.acceleroMeter;
auto& gyroValues = imuPacket.gyroscope;
double accStamp = std::chrono::duration<double>(acceleroValues.getTimestampDevice().time_since_epoch()).count();
double gyroStamp = std::chrono::duration<double>(gyroValues.getTimestampDevice().time_since_epoch()).count();
if(publishInterIMU_)
{
IMU imu(cv::Vec3f(gyroValues.x, gyroValues.y, gyroValues.z), cv::Mat::eye(3,3,CV_64FC1),
cv::Vec3f(acceleroValues.x, acceleroValues.y, acceleroValues.z), cv::Mat::eye(3,3,CV_64FC1),
imuLocalTransform_);
UEventsManager::post(new IMUEvent(imu, (accStamp+gyroStamp)/2));
}
else
{
UScopeMutex lock(imuMutex_);
accBuffer_.emplace_hint(accBuffer_.end(), std::make_pair(accStamp, cv::Vec3f(acceleroValues.x, acceleroValues.y, acceleroValues.z)));
gyroBuffer_.emplace_hint(gyroBuffer_.end(), std::make_pair(gyroStamp, cv::Vec3f(gyroValues.x, gyroValues.y, gyroValues.z)));
}
}
}
});
}
leftQueue_ = device_->getOutputQueue("rectified_left", 8, false);
rightOrDepthQueue_ = device_->getOutputQueue(outputDepth_?"depth":"rectified_right", 8, false);
std::vector<std::tuple<std::string, int, int>> irDrivers = device_->getIrDrivers();
if(!irDrivers.empty())
{
device_->setIrLaserDotProjectorBrightness(dotProjectormA_);
device_->setIrFloodLightBrightness(floodLightmA_);
}
leftQueue_ = device_->getOutputQueue("rectified_left", 1, false);
rightOrDepthQueue_ = device_->getOutputQueue(outputDepth_?"depth":"rectified_right", 1, false);
uSleep(2000); // avoid bad frames on start
@@ -303,173 +382,67 @@ SensorData CameraDepthAI::captureImage(CameraInfo * info)
auto rectifL = leftQueue_->get<dai::ImgFrame>();
auto rectifRightOrDepth = rightOrDepthQueue_->get<dai::ImgFrame>();
if(rectifL.get() && rectifRightOrDepth.get())
{
auto stampLeft = rectifL->getTimestamp().time_since_epoch().count();
auto stampRight = rectifRightOrDepth->getTimestamp().time_since_epoch().count();
double stamp = double(stampLeft)/10e8;
left = rectifL->getCvFrame();
depthOrRight = rectifRightOrDepth->getCvFrame();
while(rectifL->getSequenceNum() < rectifRightOrDepth->getSequenceNum())
rectifL = leftQueue_->get<dai::ImgFrame>();
while(rectifL->getSequenceNum() > rectifRightOrDepth->getSequenceNum())
rectifRightOrDepth = rightOrDepthQueue_->get<dai::ImgFrame>();
if(!left.empty() && !depthOrRight.empty())
{
if(depthOrRight.type() == CV_8UC1)
{
if(stereoModel_.isValidForRectification())
{
left = stereoModel_.left().rectifyImage(left);
depthOrRight = stereoModel_.right().rectifyImage(depthOrRight);
}
data = SensorData(left, depthOrRight, stereoModel_, this->getNextSeqID(), stamp);
}
else
{
data = SensorData(left, depthOrRight, stereoModel_.left(), this->getNextSeqID(), stamp);
}
double stamp = std::chrono::duration<double>(rectifL->getTimestampDevice(dai::CameraExposureOffset::MIDDLE).time_since_epoch()).count();
left = rectifL->getCvFrame();
depthOrRight = rectifRightOrDepth->getCvFrame();
if(fabs(double(stampLeft)/10e8 - double(stampRight)/10e8) >= 0.0001) //0.1 ms
{
UWARN("Frames are not synchronized! %f vs %f", double(stampLeft)/10e8, double(stampRight)/10e8);
}
//get imu
double stampStart = UTimer::now();
while(imuPublished_ && imuQueue_.get())
{
if(imuQueue_->has())
{
auto imuData = imuQueue_->get<dai::IMUData>();
auto imuPackets = imuData->packets;
double accStamp = 0.0;
double gyroStamp = 0.0;
for(auto& imuPacket : imuPackets) {
auto& acceleroValues = imuPacket.acceleroMeter;
auto& gyroValues = imuPacket.gyroscope;
accStamp = double(acceleroValues.timestamp.get().time_since_epoch().count())/10e8;
gyroStamp = double(gyroValues.timestamp.get().time_since_epoch().count())/10e8;
accBuffer_.insert(accBuffer_.end(), std::make_pair(accStamp, cv::Vec3f(acceleroValues.x, acceleroValues.y, acceleroValues.z)));
gyroBuffer_.insert(gyroBuffer_.end(), std::make_pair(gyroStamp, cv::Vec3f(gyroValues.x, gyroValues.y, gyroValues.z)));
if(accBuffer_.size() > 1000)
{
accBuffer_.erase(accBuffer_.begin());
}
if(gyroBuffer_.size() > 1000)
{
gyroBuffer_.erase(gyroBuffer_.begin());
}
}
if(accStamp >= stamp && gyroStamp >= stamp)
{
break;
}
}
if((UTimer::now() - stampStart) > 0.01)
{
UWARN("Could not received IMU after 10 ms! Disabling IMU!");
imuPublished_ = false;
}
}
cv::Vec3d acc, gyro;
bool valid = !accBuffer_.empty() && !gyroBuffer_.empty();
//acc
if(!accBuffer_.empty())
{
std::map<double, cv::Vec3f>::const_iterator iterB = accBuffer_.lower_bound(stamp);
std::map<double, cv::Vec3f>::const_iterator iterA = iterB;
if(iterA != accBuffer_.begin())
{
iterA = --iterA;
}
if(iterB == accBuffer_.end())
{
iterB = --iterB;
}
if(iterA == iterB && stamp == iterA->first)
{
acc[0] = iterA->second[0];
acc[1] = iterA->second[1];
acc[2] = iterA->second[2];
}
else if(stamp >= iterA->first && stamp <= iterB->first)
{
float t = (stamp-iterA->first) / (iterB->first-iterA->first);
acc[0] = iterA->second[0] + t*(iterB->second[0] - iterA->second[0]);
acc[1] = iterA->second[1] + t*(iterB->second[1] - iterA->second[1]);
acc[2] = iterA->second[2] + t*(iterB->second[2] - iterA->second[2]);
}
else
{
valid = false;
if(stamp < iterA->first)
{
UWARN("Could not find acc data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
}
else if(stamp > iterB->first)
{
UWARN("Could not find acc data to interpolate at image time %f (latest is %f). Are sensors synchronized?", stamp, iterB->first);
}
else
{
UWARN("Could not find acc data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
}
}
}
//gyro
if(!gyroBuffer_.empty())
{
std::map<double, cv::Vec3f>::const_iterator iterB = gyroBuffer_.lower_bound(stamp);
std::map<double, cv::Vec3f>::const_iterator iterA = iterB;
if(iterA != gyroBuffer_.begin())
{
iterA = --iterA;
}
if(iterB == gyroBuffer_.end())
{
iterB = --iterB;
}
if(iterA == iterB && stamp == iterA->first)
{
gyro[0] = iterA->second[0];
gyro[1] = iterA->second[1];
gyro[2] = iterA->second[2];
}
else if(stamp >= iterA->first && stamp <= iterB->first)
{
float t = (stamp-iterA->first) / (iterB->first-iterA->first);
gyro[0] = iterA->second[0] + t*(iterB->second[0] - iterA->second[0]);
gyro[1] = iterA->second[1] + t*(iterB->second[1] - iterA->second[1]);
gyro[2] = iterA->second[2] + t*(iterB->second[2] - iterA->second[2]);
}
else
{
valid = false;
if(stamp < iterA->first)
{
UWARN("Could not find gyro data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
}
else if(stamp > iterB->first)
{
UWARN("Could not find gyro data to interpolate at image time %f (latest is %f). Are sensors synchronized?", stamp, iterB->first);
}
else
{
UWARN("Could not find gyro data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
}
}
}
if(valid)
{
data.setIMU(IMU(gyro, cv::Mat::eye(3, 3, CV_64FC1), acc, cv::Mat::eye(3, 3, CV_64FC1), imuLocalTransform_));
}
}
}
if(depthOrRight.type() == CV_8UC1)
data = SensorData(left, depthOrRight, stereoModel_, this->getNextSeqID(), stamp);
else
data = SensorData(left, depthOrRight, stereoModel_.left(), this->getNextSeqID(), stamp);
if(imuPublished_ && !publishInterIMU_)
{
UWARN("Null images received!?");
cv::Vec3d acc, gyro;
std::map<double, cv::Vec3f>::const_iterator iterA, iterB;
imuMutex_.lock();
while(accBuffer_.empty() || gyroBuffer_.empty() || accBuffer_.rbegin()->first < stamp || gyroBuffer_.rbegin()->first < stamp)
{
imuMutex_.unlock();
uSleep(1);
imuMutex_.lock();
}
//acc
iterB = accBuffer_.lower_bound(stamp);
iterA = iterB;
if(iterA != accBuffer_.begin())
iterA = --iterA;
if(iterA == iterB || stamp == iterB->first)
{
acc = iterB->second;
}
else if(stamp > iterA->first && stamp < iterB->first)
{
float t = (stamp-iterA->first) / (iterB->first-iterA->first);
acc = iterA->second + t*(iterB->second - iterA->second);
}
accBuffer_.erase(accBuffer_.begin(), iterB);
//gyro
iterB = gyroBuffer_.lower_bound(stamp);
iterA = iterB;
if(iterA != gyroBuffer_.begin())
iterA = --iterA;
if(iterA == iterB || stamp == iterB->first)
{
gyro = iterB->second;
}
else if(stamp > iterA->first && stamp < iterB->first)
{
float t = (stamp-iterA->first) / (iterB->first-iterA->first);
gyro = iterA->second + t*(iterB->second - iterA->second);
}
gyroBuffer_.erase(gyroBuffer_.begin(), iterB);
imuMutex_.unlock();
data.setIMU(IMU(gyro, cv::Mat::eye(3, 3, CV_64FC1), acc, cv::Mat::eye(3, 3, CV_64FC1), imuLocalTransform_));
}
#else
+56 -6
View File
@@ -240,6 +240,17 @@ bool CameraStereoZed::available()
#endif
}
int CameraStereoZed::sdkVersion()
{
#ifdef RTABMAP_ZED
return ZED_SDK_MAJOR_VERSION;
#else
return -1;
#endif
}
CameraStereoZed::CameraStereoZed(
int deviceId,
int resolution,
@@ -274,6 +285,16 @@ CameraStereoZed::CameraStereoZed(
{
UDEBUG("");
#ifdef RTABMAP_ZED
#if ZED_SDK_MAJOR_VERSION < 4
if(resolution_ == 3)
{
resolution_ = 2;
}
else if(resolution_ == 5)
{
resolution_ = 3;
}
#endif
#if ZED_SDK_MAJOR_VERSION < 3
UASSERT(resolution_ >= sl::RESOLUTION_HD2K && resolution_ <sl::RESOLUTION_LAST);
UASSERT(quality_ >= sl::DEPTH_MODE_NONE && quality_ <sl::DEPTH_MODE_LAST);
@@ -282,11 +303,15 @@ CameraStereoZed::CameraStereoZed(
#else
sl::RESOLUTION res = static_cast<sl::RESOLUTION>(resolution_);
sl::DEPTH_MODE qual = static_cast<sl::DEPTH_MODE>(quality_);
sl::SENSING_MODE sens = static_cast<sl::SENSING_MODE>(sensingMode_);
UASSERT(res >= sl::RESOLUTION::HD2K && res < sl::RESOLUTION::LAST);
UASSERT(qual >= sl::DEPTH_MODE::NONE && qual < sl::DEPTH_MODE::LAST);
#if ZED_SDK_MAJOR_VERSION < 4
sl::SENSING_MODE sens = static_cast<sl::SENSING_MODE>(sensingMode_);
UASSERT(sens >= sl::SENSING_MODE::STANDARD && sens < sl::SENSING_MODE::LAST);
#else
UASSERT(sensingMode_ >= 0 && sensingMode_ < 2);
#endif
UASSERT(confidenceThr_ >= 0 && confidenceThr_ <=100);
UASSERT(texturenessConfidenceThr_ >= 0 && texturenessConfidenceThr_ <=100);
#endif
@@ -334,11 +359,15 @@ CameraStereoZed::CameraStereoZed(
#else
sl::RESOLUTION res = static_cast<sl::RESOLUTION>(resolution_);
sl::DEPTH_MODE qual = static_cast<sl::DEPTH_MODE>(quality_);
sl::SENSING_MODE sens = static_cast<sl::SENSING_MODE>(sensingMode_);
UASSERT(res >= sl::RESOLUTION::HD2K && res < sl::RESOLUTION::LAST);
UASSERT(qual >= sl::DEPTH_MODE::NONE && qual < sl::DEPTH_MODE::LAST);
#if ZED_SDK_MAJOR_VERSION < 4
sl::SENSING_MODE sens = static_cast<sl::SENSING_MODE>(sensingMode_);
UASSERT(sens >= sl::SENSING_MODE::STANDARD && sens < sl::SENSING_MODE::LAST);
#else
UASSERT(sensingMode_ >= 0 && sensingMode_ < 2);
#endif
UASSERT(confidenceThr_ >= 0 && confidenceThr_ <=100);
UASSERT(texturenessConfidenceThr_ >= 0 && texturenessConfidenceThr_ <=100);
#endif
@@ -465,7 +494,11 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
}
sl::CameraInformation infos = zed_->getCameraInformation();
#if ZED_SDK_MAJOR_VERSION < 4
sl::CalibrationParameters *stereoParams = &(infos.calibration_parameters );
#else
sl::CalibrationParameters *stereoParams = &(infos.camera_configuration.calibration_parameters );
#endif
sl::Resolution res = stereoParams->left_cam.image_size;
stereoModel_ = StereoCameraModel(
@@ -473,7 +506,11 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
#if ZED_SDK_MAJOR_VERSION < 4
stereoParams->T[0],//baseline
#else
stereoParams->getCameraBaseline(),
#endif
this->getLocalTransform(),
cv::Size(res.width, res.height));
@@ -482,7 +519,11 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
stereoParams->left_cam.fy,
stereoParams->left_cam.cx,
stereoParams->left_cam.cy,
#if ZED_SDK_MAJOR_VERSION < 4
stereoParams->T[0],//baseline
#else
stereoParams->getCameraBaseline(),
#endif
(int)res.width,
(int)res.height,
this->getLocalTransform().prettyPrint().c_str());
@@ -493,11 +534,18 @@ bool CameraStereoZed::init(const std::string & calibrationFolder, const std::str
if(infos.camera_model != sl::MODEL::ZED)
#endif
{
#if ZED_SDK_MAJOR_VERSION < 4
imuLocalTransform_ = this->getLocalTransform() * zedPoseToTransform(infos.camera_imu_transform).inverse();
#else
imuLocalTransform_ = this->getLocalTransform() * zedPoseToTransform(infos.sensors_configuration.camera_imu_transform).inverse();
#endif
UINFO("IMU local transform: %s (imu2cam=%s))",
imuLocalTransform_.prettyPrint().c_str(),
zedPoseToTransform(infos.camera_imu_transform).prettyPrint().c_str());
imuLocalTransform_.prettyPrint().c_str(),
#if ZED_SDK_MAJOR_VERSION < 4
zedPoseToTransform(infos.camera_imu_transform).prettyPrint().c_str());
#else
zedPoseToTransform(infos.sensors_configuration.camera_imu_transform).prettyPrint().c_str());
#endif
if(publishInterIMU_)
{
imuPublishingThread_ = new ZedIMUThread(200, zed_, imuLocalTransform_, true);
@@ -623,8 +671,10 @@ SensorData CameraStereoZed::captureImage(CameraInfo * info)
#ifdef RTABMAP_ZED
#if ZED_SDK_MAJOR_VERSION < 3
sl::RuntimeParameters rparam((sl::SENSING_MODE)sensingMode_, quality_ > 0, quality_ > 0, sl::REFERENCE_FRAME_CAMERA);
#else
#elif ZED_SDK_MAJOR_VERSION < 4
sl::RuntimeParameters rparam((sl::SENSING_MODE)sensingMode_, quality_ > 0, confidenceThr_, texturenessConfidenceThr_, sl::REFERENCE_FRAME::CAMERA);
#else
sl::RuntimeParameters rparam(quality_ > 0, sensingMode_ == 1, confidenceThr_, texturenessConfidenceThr_, sl::REFERENCE_FRAME::CAMERA);
#endif
if(zed_)
+5
View File
@@ -214,6 +214,11 @@ Transform OdometryF2M::computeTransform(
if(sba_ && sba_->gravitySigma() > 0.0f && !imus().empty())
{
imuT = Transform::getTransform(imus(), data.stamp());
if(data.imu().empty())
{
Eigen::Quaternionf q = imuT.getQuaternionf();
data.setIMU(IMU(cv::Vec4d(q.x(), q.y(), q.z(), q.w()), cv::Mat(), cv::Vec3d(), cv::Mat(), cv::Vec3d(), cv::Mat()));
}
}
RegistrationInfo regInfo;
+8
View File
@@ -527,7 +527,11 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
{
float x,y,z,roll,pitch,yaw;
std::map<int, Transform> tmpPoses;
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
for(gtsam::Values::deref_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
#else
for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
#endif
{
if(iter->value.dim() > 1)
{
@@ -630,7 +634,11 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
optimizer->iterations(), optimizer->error(), graph.error(initialEstimate), graph.error(optimizer->values()), timer.ticks());
float x,y,z,roll,pitch,yaw;
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
for(gtsam::Values::deref_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
#else
for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
#endif
{
if(iter->value.dim() > 1)
{
+36 -6
View File
@@ -63,15 +63,21 @@ public:
/** vector of errors */
Vector attitudeError(const Rot3& p,
OptionalJacobian<2,3> H = boost::none) const;
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalJacobian<2,3> H = {}) const;
#else
OptionalJacobian<2,3> H = boost::none) const;
#endif
/** Serialization function */
#if defined(GTSAM_ENABLE_BOOST_SERIALIZATION) || GTSAM_VERSION_MAJOR < 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR < 3)
friend class boost::serialization::access;
template<class ARCHIVE>
void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
ar & boost::serialization::make_nvp("nZ_", const_cast<Unit3&>(nZ_));
ar & boost::serialization::make_nvp("bRef_", const_cast<Unit3&>(bRef_));
}
#endif
};
/**
@@ -85,7 +91,11 @@ class Rot3GravityFactor: public NoiseModelFactor1<Rot3>, public GravityFactor {
public:
/// shorthand for a smart pointer to a factor
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
typedef std::shared_ptr<Rot3GravityFactor> shared_ptr;
#else
typedef boost::shared_ptr<Rot3GravityFactor> shared_ptr;
#endif
/// Typedef to this class
typedef Rot3GravityFactor This;
@@ -111,7 +121,11 @@ public:
/// @return a deep copy of this factor
virtual gtsam::NonlinearFactor::shared_ptr clone() const {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
return std::static_pointer_cast<gtsam::NonlinearFactor>(
#else
return boost::static_pointer_cast<gtsam::NonlinearFactor>(
#endif
gtsam::NonlinearFactor::shared_ptr(new This(*this)));
}
@@ -124,7 +138,11 @@ public:
/** vector of errors */
virtual Vector evaluateError(const Rot3& nRb, //
boost::optional<Matrix&> H = boost::none) const {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H = OptionalNone) const {
#else
boost::optional<Matrix&> H = boost::none) const {
#endif
return attitudeError(nRb, H);
}
Unit3 nZ() const {
@@ -135,7 +153,7 @@ public:
}
private:
#if defined(GTSAM_ENABLE_BOOST_SERIALIZATION) || GTSAM_VERSION_MAJOR < 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR < 3)
/** Serialization function */
friend class boost::serialization::access;
template<class ARCHIVE>
@@ -145,6 +163,7 @@ private:
ar & boost::serialization::make_nvp("GravityFactor",
boost::serialization::base_object<GravityFactor>(*this));
}
#endif
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
@@ -163,8 +182,11 @@ class Pose3GravityFactor: public NoiseModelFactor1<Pose3>,
public:
/// shorthand for a smart pointer to a factor
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
typedef std::shared_ptr<Pose3GravityFactor> shared_ptr;
#else
typedef boost::shared_ptr<Pose3GravityFactor> shared_ptr;
#endif
/// Typedef to this class
typedef Pose3GravityFactor This;
@@ -189,7 +211,11 @@ public:
/// @return a deep copy of this factor
virtual gtsam::NonlinearFactor::shared_ptr clone() const {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
return std::static_pointer_cast<gtsam::NonlinearFactor>(
#else
return boost::static_pointer_cast<gtsam::NonlinearFactor>(
#endif
gtsam::NonlinearFactor::shared_ptr(new This(*this)));
}
@@ -202,7 +228,11 @@ public:
/** vector of errors */
virtual Vector evaluateError(const Pose3& nTb, //
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H = OptionalNone) const {
#else
boost::optional<Matrix&> H = boost::none) const {
#endif
Vector e = attitudeError(nTb.rotation(), H);
if (H) {
Matrix H23 = *H;
@@ -219,7 +249,7 @@ public:
}
private:
#if defined(GTSAM_ENABLE_BOOST_SERIALIZATION) || GTSAM_VERSION_MAJOR < 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR < 3)
/** Serialization function */
friend class boost::serialization::access;
template<class ARCHIVE>
@@ -229,7 +259,7 @@ private:
ar & boost::serialization::make_nvp("GravityFactor",
boost::serialization::base_object<GravityFactor>(*this));
}
#endif
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
+6 -1
View File
@@ -41,7 +41,12 @@ public:
// error function
// @param p the pose in Pose2
// @param H the optional Jacobian matrix, which use boost optional and has default null pointer
gtsam::Vector evaluateError(const VALUE& p, boost::optional<gtsam::Matrix&> H = boost::none) const {
gtsam::Vector evaluateError(const VALUE& p,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H = OptionalNone) const {
#else
boost::optional<gtsam::Matrix&> H = boost::none) const {
#endif
// note that use boost optional like a pointer
// only calculate jacobian matrix when non-null pointer exists
+12 -2
View File
@@ -41,14 +41,24 @@ public:
// error function
// @param p the pose in Pose
// @param H the optional Jacobian matrix, which use boost optional and has default null pointer
gtsam::Vector evaluateError(const gtsam::Pose3& p, boost::optional<gtsam::Matrix&> H = boost::none) const {
gtsam::Vector evaluateError(const gtsam::Pose3& p,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H = OptionalNone) const {
#else
boost::optional<gtsam::Matrix&> H = boost::none) const {
#endif
if(H)
{
p.translation(H);
}
return (gtsam::Vector3() << p.x() - mx_, p.y() - my_, p.z() - mz_).finished();
}
gtsam::Vector evaluateError(const gtsam::Point3& p, boost::optional<gtsam::Matrix&> H = boost::none) const {
gtsam::Vector evaluateError(const gtsam::Point3& p,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H = OptionalNone) const {
#else
boost::optional<gtsam::Matrix&> H = boost::none) const {
#endif
return (gtsam::Vector3() << p.x() - mx_, p.y() - my_, p.z() - mz_).finished();
}
};
@@ -72,9 +72,15 @@ public:
/**
* Clone this value (normal clone on the heap, delete with 'delete' operator)
*/
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
virtual std::shared_ptr<gtsam::Value> clone() const {
return std::make_shared<DERIVED>(static_cast<const DERIVED&>(*this));
}
#else
virtual boost::shared_ptr<gtsam::Value> clone() const {
return boost::make_shared<DERIVED>(static_cast<const DERIVED&>(*this));
}
#endif
/// equals implementing generic Value interface
virtual bool equals_(const gtsam::Value& p, double tol = 1e-9) const {
@@ -30,9 +30,15 @@ namespace vertigo {
betweenFactor(key1, key2, measured, model) {};
gtsam::Vector evaluateError(const VALUE& p1, const VALUE& p2, const SwitchVariableLinear& s,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H1 = OptionalNone,
OptionalMatrixType H2 = OptionalNone,
OptionalMatrixType H3 = OptionalNone) const
#else
boost::optional<gtsam::Matrix&> H1 = boost::none,
boost::optional<gtsam::Matrix&> H2 = boost::none,
boost::optional<gtsam::Matrix&> H3 = boost::none) const
boost::optional<gtsam::Matrix&> H2 = boost::none,
boost::optional<gtsam::Matrix&> H3 = boost::none) const
#endif
{
// calculate error
@@ -64,9 +70,15 @@ namespace vertigo {
betweenFactor(key1, key2, measured, model) {};
gtsam::Vector evaluateError(const VALUE& p1, const VALUE& p2, const SwitchVariableSigmoid& s,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H1 = OptionalNone,
OptionalMatrixType H2 = OptionalNone,
OptionalMatrixType H3 = OptionalNone) const
#else
boost::optional<gtsam::Matrix&> H1 = boost::none,
boost::optional<gtsam::Matrix&> H2 = boost::none,
boost::optional<gtsam::Matrix&> H3 = boost::none) const
boost::optional<gtsam::Matrix&> H2 = boost::none,
boost::optional<gtsam::Matrix&> H3 = boost::none) const
#endif
{
// calculate error
@@ -76,8 +76,13 @@ namespace vertigo {
/** between operation */
inline SwitchVariableLinear between(const SwitchVariableLinear& l2,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H1=OptionalNone,
OptionalMatrixType H2=OptionalNone) const {
#else
boost::optional<gtsam::Matrix&> H1=boost::none,
boost::optional<gtsam::Matrix&> H2=boost::none) const {
#endif
if(H1) *H1 = -gtsam::Matrix::Identity(1, 1);
if(H2) *H2 = gtsam::Matrix::Identity(1, 1);
return SwitchVariableLinear(l2.value() - value());
@@ -116,11 +121,19 @@ template<> struct traits<vertigo::SwitchVariableLinear> {
typedef OptionalJacobian<3, 3> ChartJacobian;
typedef gtsam::Vector TangentVector;
static TangentVector Local(const vertigo::SwitchVariableLinear& origin, const vertigo::SwitchVariableLinear& other,
ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
ChartJacobian Horigin = {}, ChartJacobian Hother = {}) {
#else
ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
#endif
return origin.localCoordinates(other);
}
static vertigo::SwitchVariableLinear Retract(const vertigo::SwitchVariableLinear& g, const TangentVector& v,
ChartJacobian H1 = boost::none, ChartJacobian H2 = boost::none) {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
#else
ChartJacobian H1 = boost::none, ChartJacobian H2 = boost::none) {
#endif
return g.retract(v);
}
};
@@ -76,8 +76,13 @@ namespace vertigo {
/** between operation */
inline SwitchVariableSigmoid between(const SwitchVariableSigmoid& l2,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
OptionalMatrixType H1=OptionalNone,
OptionalMatrixType H2=OptionalNone) const {
#else
boost::optional<gtsam::Matrix&> H1=boost::none,
boost::optional<gtsam::Matrix&> H2=boost::none) const {
#endif
if(H1) *H1 = -gtsam::Matrix::Identity(1, 1);
if(H2) *H2 = gtsam::Matrix::Identity(1, 1);
return SwitchVariableSigmoid(l2.value() - value());
@@ -117,11 +122,19 @@ template<> struct traits<vertigo::SwitchVariableSigmoid> {
typedef OptionalJacobian<3, 3> ChartJacobian;
typedef gtsam::Vector TangentVector;
static TangentVector Local(const vertigo::SwitchVariableSigmoid& origin, const vertigo::SwitchVariableSigmoid& other,
ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
ChartJacobian Horigin = {}, ChartJacobian Hother = {}) {
#else
ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
#endif
return origin.localCoordinates(other);
}
static vertigo::SwitchVariableSigmoid Retract(const vertigo::SwitchVariableSigmoid& g, const TangentVector& v,
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR == 4 && GTSAM_VERSION_MINOR >= 3)
ChartJacobian H1 = {}, ChartJacobian H2 = {}) {
#else
ChartJacobian H1 = boost::none, ChartJacobian H2 = boost::none) {
#endif
return g.retract(v);
}
};
+105 -12
View File
@@ -372,34 +372,127 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth(
float depthCx = model.cx() * rgbToDepthFactorX;
float depthCy = model.cy() * rgbToDepthFactorY;
UDEBUG("depth=%dx%d fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
bool isMM = imageDepth.type() == CV_16UC1;
UDEBUG("depth=%dx%d (isMM=%d) fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
imageDepth.cols, imageDepth.rows,
isMM?1:0,
model.fx(), model.fy(), model.cx(), model.cy(),
rgbToDepthFactorX,
rgbToDepthFactorY,
decimation);
int decimationMode = 1;
int oi = 0;
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
if(isMM)
{
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
{
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
pcl::PointXYZ ptXYZ = projectDepthTo3D(imageDepth, w, h, depthCx, depthCy, depthFx, depthFy, false);
if(pcl::isFinite(ptXYZ) && ptXYZ.z>=minDepth && (maxDepth<=0.0f || ptXYZ.z <= maxDepth))
const unsigned short * rowPtr = imageDepth.ptr<unsigned short>(h);
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
{
pt.x = ptXYZ.x;
pt.y = ptXYZ.y;
pt.z = ptXYZ.z;
if(validIndices)
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
if(decimationMode == 1 && decimation>1)
{
// project closest point
cv::Point2i closestPixel(w,h);
unsigned short closestDepthMM = 0;
for(int v = h; v < h + decimation; ++v)
{
const unsigned short * roiRowPtr = imageDepth.ptr<unsigned short>(v);
for(int u = w; u < w + decimation; ++u)
{
const unsigned short & depthMM = roiRowPtr[u];
if(depthMM > 0 && (depthMM < closestDepthMM || closestDepthMM == 0))
{
closestDepthMM = depthMM;
closestPixel.x = u;
closestPixel.y = v;
}
}
}
if(closestDepthMM > 0)
{
float depth = ((float)closestDepthMM)/1000.0f;
if(depth>=minDepth && (maxDepth<=0.0f || depth <= maxDepth))
{
// Fill in XYZ
pt.z = depth;
pt.x = ((float)closestPixel.x - depthCx) * pt.z / depthFx;
pt.y = ((float)closestPixel.y - depthCy) * pt.z / depthFy;
}
}
}
else if(rowPtr[w]>0)
{
float depth = ((float)rowPtr[w])/1000.0f;
if(depth>=minDepth && (maxDepth<=0.0f || depth <= maxDepth))
{
// Fill in XYZ
pt.z = depth;
pt.x = ((float)w - depthCx) * pt.z / depthFx;
pt.y = ((float)h - depthCy) * pt.z / depthFy;
}
}
if(pcl::isFinite(pt) && validIndices)
{
validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
}
}
else
}
}
else
{
for(int h = 0; h < imageDepth.rows && h/decimation < (int)cloud->height; h+=decimation)
{
const float * rowPtr = imageDepth.ptr<float>(h);
for(int w = 0; w < imageDepth.cols && w/decimation < (int)cloud->width; w+=decimation)
{
pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
if(decimationMode == 1 && decimation>1)
{
// project closest point
cv::Point2i closestPixel(w,h);
float closestDepth = 0.0f;
for(int v = h; v < h + decimation; ++v)
{
const float * roiRowPtr = imageDepth.ptr<float>(v);
for(int u = w; u < w + decimation; ++u)
{
const float & depth = roiRowPtr[u];
if(depth > 0.0f && (depth < closestDepth || closestDepth == 0.0f))
{
closestDepth = depth;
closestPixel.x = u;
closestPixel.y = v;
}
}
}
if(closestDepth > 0.0f && closestDepth>=minDepth && (maxDepth<=0.0f || closestDepth <= maxDepth))
{
// Fill in XYZ
pt.z = closestDepth;
pt.x = ((float)closestPixel.x - depthCx) * pt.z / depthFx;
pt.y = ((float)closestPixel.y - depthCy) * pt.z / depthFy;
}
}
else if(rowPtr[w] > 0 && rowPtr[w]>=minDepth && (maxDepth<=0.0f || rowPtr[w] <= maxDepth))
{
// Fill in XYZ
pt.z = rowPtr[w];
pt.x = ((float)w - depthCx) * pt.z / depthFx;
pt.y = ((float)h - depthCy) * pt.z / depthFy;
}
if(pcl::isFinite(pt) && validIndices)
{
validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
}
}
}
}
+30
View File
@@ -1026,6 +1026,36 @@ cv::Mat erodeMap(const cv::Mat & map)
return erodedMap;
}
void clusterIndicesFloodfill(std::vector<int> & cluster,
float * visitedIndices,
int width,
int height,
float clusterRadius,
int currentIndex,
float previousHeight)
{
if(visitedIndices[currentIndex] == 0.0f ||
(clusterRadius>0.0f && fabs(visitedIndices[currentIndex]-previousHeight)>clusterRadius))
{
return;
}
int y = currentIndex / width;
int x = currentIndex - y*width;
if(x>=0 && x<width && y>=0 && y<height)
{
cluster.push_back(currentIndex);
float currentHeight = visitedIndices[currentIndex];
visitedIndices[currentIndex] = 0;
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, (y+1)*width + x, currentHeight);
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, (y-1)*width + x, currentHeight);
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, y*width + x+1, currentHeight);
clusterIndicesFloodfill(cluster, visitedIndices, width, height, clusterRadius, y*width + x-1, currentHeight);
}
}
}
}
+60 -30
View File
@@ -3033,6 +3033,65 @@ pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals2D(
return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
}
template<typename PointT>
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormalsImpl(
const typename pcl::PointCloud<PointT>::Ptr & cloud,
const pcl::IndicesPtr & indices,
float maxDepthChangeFactor,
float normalSmoothingSize,
const Eigen::Vector3f & viewPoint)
{
UASSERT(cloud->isOrganized());
// Normal estimation
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
pcl::IntegralImageNormalEstimation<PointT, pcl::Normal> ne;
#if PCL_VERSION_COMPARE(<, 1, 7, 0)
ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
#else
ne.setNormalEstimationMethod (ne.SIMPLE_3D_GRADIENT);
ne.setBorderPolicy(ne.BORDER_POLICY_IGNORE);
#endif
ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
ne.setNormalSmoothingSize(normalSmoothingSize);
ne.setInputCloud(cloud);
// Commented: Keep the output normals size the same as the input cloud
//if(indices->size())
//{
// ne.setIndices(indices);
//}
// create kdtree search tree (not used by IntegralImageNormalEstimation) to avoid
// "[pcl::OrganizedNeighbor::radiusSearch] Input dataset is not from a projective device!"
// on clouds smaller than regular organized clouds from camera (640x480)
typename pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT>);
ne.setSearchMethod(tree);
ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
ne.compute(*normals);
return normals;
}
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
float maxDepthChangeFactor,
float normalSmoothingSize,
const Eigen::Vector3f & viewPoint)
{
pcl::IndicesPtr indices(new std::vector<int>);
return computeFastOrganizedNormals(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
}
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
const pcl::IndicesPtr & indices,
float maxDepthChangeFactor,
float normalSmoothingSize,
const Eigen::Vector3f & viewPoint)
{
return computeFastOrganizedNormalsImpl<pcl::PointXYZ>(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
}
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
float maxDepthChangeFactor,
@@ -3049,36 +3108,7 @@ pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
float normalSmoothingSize,
const Eigen::Vector3f & viewPoint)
{
UASSERT(cloud->isOrganized());
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
if(indices->size())
{
tree->setInputCloud(cloud, indices);
}
else
{
tree->setInputCloud (cloud);
}
// Normal estimation
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
ne.setNormalSmoothingSize(normalSmoothingSize);
ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
ne.setInputCloud(cloud);
// Commented: Keep the output normals size the same as the input cloud
//if(indices->size())
//{
// ne.setIndices(indices);
//}
ne.setSearchMethod(tree);
ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
ne.compute(*normals);
return normals;
return computeFastOrganizedNormalsImpl<pcl::PointXYZRGB>(cloud, indices, maxDepthChangeFactor, normalSmoothingSize, viewPoint);
}
float computeNormalsComplexity(
+4 -1
View File
@@ -5,7 +5,7 @@ FROM ros:melodic-perception
# Install build dependencies
RUN apt-get update && \
apt-get install -y git software-properties-common ros-melodic-rtabmap-ros && \
apt-get remove -y ros-melodic-rtabmap && \
apt-get remove -y ros-melodic-rtabmap* && \
apt-get clean && rm -rf /var/lib/apt/lists/
WORKDIR /root/
@@ -49,6 +49,9 @@ RUN git clone https://github.com/laurentkneip/opengv.git && \
cd && \
rm -r opengv
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Copy current source code
-13
View File
@@ -1,13 +0,0 @@
FROM introlab3it/rtabmap:bionic
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
# On Nvidia Jetpack, uncomment the following (https://github.com/introlab/rtabmap/issues/776):
# ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/aarch64-linux-gnu/tegra
+33 -6
View File
@@ -1,10 +1,22 @@
# Image: introlab3it/rtabmap:focal-foxy
FROM osrf/ros:foxy-desktop
FROM ubuntu:20.04
RUN apt update && \
apt install software-properties-common -y && \
add-apt-repository universe && \
apt update && \
apt install curl -y && \
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null && \
apt-get clean && rm -rf /var/lib/apt/lists/
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && \
apt-get install -y git software-properties-common ros-foxy-rtabmap-ros && \
apt upgrade -y && \
apt-get install -y git ros-foxy-ros-base python3-argcomplete ros-dev-tools ros-foxy-rtabmap-ros && \
apt-get remove -y ros-foxy-rtabmap && \
apt-get clean && rm -rf /var/lib/apt/lists/
@@ -32,8 +44,6 @@ ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
RUN echo "I am building for $TARGETPLATFORM"
ENV DEBIAN_FRONTEND=noninteractive
# Azure Kinect DK
# Taken from https://github.com/microsoft/Azure-Kinect-Sensor-SDK/issues/1190#issuecomment-822772494
# K4A binaries on 20.04 not released yet, we should take those from 18.04
@@ -77,7 +87,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing libfreenect2
# zed open capture
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing zed-open-capture..." && \
apt-get update && apt install libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev wget && \
apt-get update && apt install -y libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev wget && \
apt-get clean && rm -rf /var/lib/apt/lists/ && \
git clone https://github.com/stereolabs/zed-open-capture.git && \
cd zed-open-capture && \
@@ -145,7 +155,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then git clone https://github.com/
rm -r AliceVision; fi
#commit Aug 6 2020
RUN apt-get update && apt install wget && \
RUN apt-get update && apt install -y wget && \
apt-get clean && rm -rf /var/lib/apt/lists/
RUN git clone https://github.com/laurentkneip/opengv.git && \
cd opengv && \
@@ -160,11 +170,28 @@ RUN git clone https://github.com/laurentkneip/opengv.git && \
cd && \
rm -r opengv
#RUN git clone --branch 4.2.0 https://github.com/opencv/opencv.git && \
# git clone --branch 4.2.0 https://github.com/opencv/opencv_contrib.git && \
# cd opencv && \
# mkdir build && \
# cd build && \
# cmake -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
# make -j$(nproc) && \
# make install && \
# cd ../.. && \
# rm -rf opencv opencv_contrib
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map && chmod 777 /root/Documents/RTAB-Map
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Copy current source code
COPY . /root/rtabmap
RUN cp /root/rtabmap/docker/focal-foxy/ros_entrypoint.sh /ros_entrypoint.sh
ENTRYPOINT [ "/ros_entrypoint.sh" ]
# Build RTAB-Map project
RUN source /ros_entrypoint.sh && \
cd rtabmap/build && \
-13
View File
@@ -1,13 +0,0 @@
FROM introlab3it/rtabmap:focal-foxy
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
# On Nvidia Jetpack, uncomment the following (https://github.com/introlab/rtabmap/issues/776):
# ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/aarch64-linux-gnu/tegra
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
# setup ros2 environment
source "/opt/ros/foxy/setup.bash" --
exec "$@"
+15 -1
View File
@@ -5,7 +5,7 @@ FROM ros:noetic-perception
# Install build dependencies
RUN apt-get update && \
apt-get install -y git software-properties-common ros-noetic-rtabmap-ros && \
apt-get remove -y ros-noetic-rtabmap && \
apt-get remove -y ros-noetic-rtabmap* && \
apt-get clean && rm -rf /var/lib/apt/lists/
WORKDIR /root/
@@ -159,6 +159,20 @@ RUN git clone https://github.com/laurentkneip/opengv.git && \
cd && \
rm -r opengv
RUN git clone --branch 4.2.0 https://github.com/opencv/opencv.git && \
git clone --branch 4.2.0 https://github.com/opencv/opencv_contrib.git && \
cd opencv && \
mkdir build && \
cd build && \
cmake -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
make -j$(nproc) && \
make install && \
cd ../.. && \
rm -rf opencv opencv_contrib
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Copy current source code
-13
View File
@@ -1,13 +0,0 @@
FROM introlab3it/rtabmap:focal
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
# On Nvidia Jetpack, uncomment the following (https://github.com/introlab/rtabmap/issues/776):
# ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/aarch64-linux-gnu/tegra
+36 -8
View File
@@ -1,15 +1,28 @@
# Image: introlab3it/rtabmap:jammy
FROM osrf/ros:humble-desktop
FROM ubuntu:22.04
# Install ROS2
RUN apt update && \
apt install software-properties-common -y && \
add-apt-repository universe && \
apt update && \
apt install curl -y && \
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null && \
apt-get clean && rm -rf /var/lib/apt/lists/
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && \
apt-get install -y git software-properties-common ros-humble-rtabmap-ros && \
apt-get remove -y ros-humble-rtabmap && \
apt upgrade -y && \
apt-get install -y git ros-humble-ros-base ros-dev-tools ros-humble-rtabmap-ros && \
apt-get remove -y ros-humble-rtabmap* && \
apt-get clean && rm -rf /var/lib/apt/lists/
WORKDIR /root/
# PDAL
RUN apt-get update && apt-get install -y libpdal-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/
@@ -22,8 +35,6 @@ ARG TARGETPLATFORM
ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
RUN echo "I am building for $TARGETPLATFORM"
ENV DEBIAN_FRONTEND=noninteractive
# libfreenect2
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing libfreenect2..." && \
apt-get update && apt-get install -y mesa-utils xserver-xorg-video-all libusb-1.0-0-dev libturbojpeg0-dev libglfw3-dev && \
@@ -40,7 +51,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing libfreenect2
# zed open capture
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing zed-open-capture..." && \
apt-get update && apt install libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev wget && \
apt-get update && apt install -y libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev wget && \
apt-get clean && rm -rf /var/lib/apt/lists/ && \
git clone https://github.com/stereolabs/zed-open-capture.git && \
cd zed-open-capture && \
@@ -53,7 +64,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then echo "Installing zed-open-cap
rm -r zed-open-capture; fi
#commit Aug 6 2020
RUN apt-get update && apt install wget && \
RUN apt-get update && apt install -y wget && \
apt-get clean && rm -rf /var/lib/apt/lists/
RUN git clone https://github.com/laurentkneip/opengv.git && \
cd opengv && \
@@ -68,11 +79,28 @@ RUN git clone https://github.com/laurentkneip/opengv.git && \
cd && \
rm -r opengv
RUN git clone --branch 4.5.4 https://github.com/opencv/opencv.git && \
git clone --branch 4.5.4 https://github.com/opencv/opencv_contrib.git && \
cd opencv && \
mkdir build && \
cd build && \
cmake -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
make -j$(nproc) && \
make install && \
cd ../.. && \
rm -rf opencv opencv_contrib
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map && chmod 777 /root/Documents/RTAB-Map
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Copy current source code
COPY . /root/rtabmap
RUN cp /root/rtabmap/docker/jammy/ros_entrypoint.sh /ros_entrypoint.sh
ENTRYPOINT [ "/ros_entrypoint.sh" ]
# ros2 seems not sourcing by default its multi-arch folders
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/ros/humble/lib/x86_64-linux-gnu:/opt/ros/humble/lib/aarch64-linux-gnu
-13
View File
@@ -1,13 +0,0 @@
FROM introlab3it/rtabmap:jammy
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics
# Will be used to read/store databases on host
RUN mkdir -p /root/Documents/RTAB-Map
# On Nvidia Jetpack, uncomment the following (https://github.com/introlab/rtabmap/issues/776):
# ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/aarch64-linux-gnu/tegra
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
# setup ros2 environment
source "/opt/ros/humble/setup.bash" --
exec "$@"
+24 -7
View File
@@ -4,7 +4,7 @@ FROM osrf/ros:humble-desktop
# Install build dependencies
RUN apt-get update && \
apt-get install -y git software-properties-common ros-humble-rtabmap-ros libqt6* qt6* && \
apt-get remove -y ros-humble-rtabmap libpcl* libqt5* qt5* libvtk* libopencv* && \
apt-get remove -y ros-humble-rtabmap* ros-humble-libg2o libpcl* libqt5* qt5* libvtk* libopencv* && \
apt-get clean && rm -rf /var/lib/apt/lists/
WORKDIR /root/
@@ -42,12 +42,34 @@ RUN git clone https://github.com/opencv/opencv.git && \
cd opencv && \
mkdir build && \
cd build && \
cmake -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
cmake -DBUILD_opencv_python3=OFF -DBUILD_opencv_python_bindings_generator=OFF -DBUILD_opencv_python_tests=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules .. && \
make -j$(nproc) && \
make install && \
cd ../.. && \
rm -rf opencv
# Build latest gtsam
RUN git clone https://github.com/borglab/gtsam.git && \
cd gtsam && \
mkdir build && \
cd build && \
cmake -DGTSAM_BUILD_EXAMPLES_ALWAYS=OFF -DGTSAM_BUILD_TESTS=OFF -DGTSAM_BUILD_STATIC_LIBRARY=OFF -DGTSAM_BUILD_UNSTABLE=OFF -DGTSAM_INSTALL_CPPUNILITE=OFF -DGTSAM_USE_SYSTEM_EIGEN=ON .. && \
cmake --build . --config Release --target install && \
cd ../.. && \
rm -rf gtsam
# Build latest g2o
RUN git clone https://github.com/RainerKuemmerle/g2o.git && \
cd g2o && \
mkdir build && \
cd build && \
cmake -DBUILD_WITH_MARCH_NATIVE=OFF -DG2O_BUILD_APPS=OFF -DG2O_BUILD_EXAMPLES=OFF -DG2O_USE_OPENGL=OFF .. && \
cmake --build . --config Release --target install && \
cd ../.. && \
rm -rf g2o
RUN mkdir -p /root/Documents/RTAB-Map
# Copy current source code
COPY . /root/rtabmap
@@ -61,9 +83,4 @@ RUN source /ros_entrypoint.sh && \
rm -rf rtabmap && \
ldconfig
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics
@@ -153,6 +153,10 @@ private:
GainCompensator * _compensator;
const DBDriver * _dbDriver;
bool _scansHaveRGB;
bool saveOBJFile(const QString &path, pcl::TextureMesh::Ptr &mesh) const;
bool saveOBJFile(const QString &path, pcl::PolygonMesh &mesh) const;
};
}
+1 -1
View File
@@ -175,7 +175,7 @@ void CreateSimpleCalibrationDialog::saveCalibration()
ui_->doubleSpinBox_fy->value(),
ui_->doubleSpinBox_cx->value(),
ui_->doubleSpinBox_cy->value(),
Transform::getIdentity(),
CameraModel::opticalRotation(),
0,
cv::Size(width, height));
UASSERT(modelLeft.isValidForProjection());
+30 -7
View File
@@ -2844,7 +2844,7 @@ bool ExportCloudsDialog::getExportedClouds(
}
if(!image.empty())
{
if(_ui->spinBox_camProjDecimation->value()>1)
{
image = util2d::decimate(image, _ui->spinBox_camProjDecimation->value());
@@ -4369,11 +4369,11 @@ void ExportCloudsDialog::saveMeshes(
}
else if(QFileInfo(path).suffix() == "obj")
{
success = pcl::io::saveOBJFile(path.toStdString(), *meshes.begin()->second) == 0;
success = saveOBJFile(path, *meshes.begin()->second);
}
else
{
UERROR("Extension not recognized! (%s) Should be (*.ply).", QFileInfo(path).suffix().toStdString().c_str());
UERROR("Extension not recognized! (%s) Should be (*.ply) or (*.obj).", QFileInfo(path).suffix().toStdString().c_str());
}
if(success)
{
@@ -4455,7 +4455,7 @@ void ExportCloudsDialog::saveMeshes(
}
else if(suffix == "obj")
{
success = pcl::io::saveOBJFile(pathFile.toStdString(), mesh) == 0;
success = saveOBJFile(pathFile, mesh);
}
else
{
@@ -4779,8 +4779,7 @@ void ExportCloudsDialog::saveTextureMeshes(
}
}
success = pcl::io::saveOBJFile(path.toStdString(), *mesh) == 0;
if(success)
if(saveOBJFile(path, mesh))
{
_progressDialog->incrementStep();
_progressDialog->appendText(tr("Saving the mesh (with %1 textures)... done.").arg(mesh->tex_materials.size()));
@@ -4976,7 +4975,7 @@ void ExportCloudsDialog::saveTextureMeshes(
bool success =false;
if(suffix == "obj")
{
success = pcl::io::saveOBJFile(pathFile.toStdString(), *mesh) == 0;
success = saveOBJFile(pathFile, mesh);
}
else
{
@@ -5010,4 +5009,28 @@ void ExportCloudsDialog::saveTextureMeshes(
}
}
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::TextureMesh::Ptr &mesh) const {
#if PCL_VERSION_COMPARE(>=, 1, 13, 0)
mesh->tex_coord_indices = std::vector<std::vector<pcl::Vertices>>();
auto nr_meshes = static_cast<unsigned>(mesh->tex_polygons.size());
unsigned f_idx = 0;
for (unsigned m = 0; m < nr_meshes; m++) {
std::vector<pcl::Vertices> ci = mesh->tex_polygons[m];
for(std::size_t i = 0; i < ci.size(); i++) {
for (std::size_t j = 0; j < ci[i].vertices.size(); j++) {
ci[i].vertices[j] = ci[i].vertices.size() * (i + f_idx) + j;
}
}
mesh->tex_coord_indices.push_back(ci);
f_idx += static_cast<unsigned>(mesh->tex_polygons[m].size());
}
#endif
return pcl::io::saveOBJFile(path.toStdString(), *mesh) == 0;
}
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::PolygonMesh &mesh) const {
return pcl::io::saveOBJFile(path.toStdString(), mesh) == 0;
}
}
+12 -19
View File
@@ -5843,27 +5843,20 @@ void MainWindow::startDetection()
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcImages) &&
!_preferencesDialog->getIMUPath().isEmpty())
{
if( odomStrategy != Odometry::kTypeOkvis &&
odomStrategy != Odometry::kTypeMSCKF &&
odomStrategy != Odometry::kTypeVINS &&
odomStrategy != Odometry::kTypeOpenVINS)
_imuThread = new IMUThread(_preferencesDialog->getIMURate(), _preferencesDialog->getIMULocalTransform());
if(_preferencesDialog->getIMUFilteringStrategy()>0)
{
_imuThread->enableIMUFiltering(_preferencesDialog->getIMUFilteringStrategy()-1, parameters, _preferencesDialog->getIMUFilteringBaseFrameConversion());
}
if(!_imuThread->init(_preferencesDialog->getIMUPath().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("IMU path is set but odometry chosen doesn't support asynchronous IMU, ignoring IMU..."), QMessageBox::Ok);
}
else
{
_imuThread = new IMUThread(_preferencesDialog->getIMURate(), _preferencesDialog->getIMULocalTransform());
if(!_imuThread->init(_preferencesDialog->getIMUPath().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("Initialization of IMU data has failed! Path=%1.").arg(_preferencesDialog->getIMUPath()), QMessageBox::Ok);
delete _camera;
_camera = 0;
delete _imuThread;
_imuThread = 0;
return;
}
tr("Initialization of IMU data has failed! Path=%1.").arg(_preferencesDialog->getIMUPath()), QMessageBox::Ok);
delete _camera;
_camera = 0;
delete _imuThread;
_imuThread = 0;
return;
}
}
Odometry * odom = Odometry::create(odomParameters);
+9 -10
View File
@@ -296,19 +296,14 @@ void ParametersToolBox::addParameter(
{
addParameter(layout, key.c_str(), QString::fromStdString(value));
}
else if(type.compare("int") == 0)
else if(type.compare("int") == 0 ||
type.compare("uint") == 0 ||
type.compare("unsigned int") == 0)
{
addParameter(layout, key.c_str(), uStr2Int(value));
}
else if(type.compare("uint") == 0)
{
addParameter(layout, key.c_str(), uStr2Int(value));
}
else if(type.compare("double") == 0)
{
addParameter(layout, key.c_str(), uStr2Double(value));
}
else if(type.compare("float") == 0)
else if(type.compare("double") == 0 ||
type.compare("float") == 0)
{
addParameter(layout, key.c_str(), uStr2Double(value));
}
@@ -316,6 +311,10 @@ void ParametersToolBox::addParameter(
{
addParameter(layout, key.c_str(), uStr2Bool(value));
}
else
{
UWARN("Not implemented type \"%s\" for parameter \"%s\". Parameter is not added to toolbox.", type.c_str(), key.c_str());
}
}
void ParametersToolBox::addParameter(QVBoxLayout * layout,
+48 -36
View File
@@ -380,6 +380,13 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_cameraStereo->setItemData(kSrcStereoZed - kSrcStereo, 0, Qt::UserRole - 1);
_ui->comboBox_odom_sensor->setItemData(2, 0, Qt::UserRole - 1);
}
else if(CameraStereoZed::sdkVersion() < 4)
{
_ui->comboBox_stereoZed_resolution->setItemData(2, 0, Qt::UserRole - 1);
_ui->comboBox_stereoZed_resolution->setItemData(4, 0, Qt::UserRole - 1);
_ui->comboBox_stereoZed_resolution->setItemData(6, 0, Qt::UserRole - 1);
_ui->comboBox_stereoZed_quality->setItemData(3, 0, Qt::UserRole - 1);
}
if (!CameraStereoTara::available())
{
_ui->comboBox_cameraStereo->setItemData(kSrcStereoTara - kSrcStereo, 0, Qt::UserRole - 1);
@@ -800,6 +807,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->spinBox_depthai_confidence, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_depthai_imu_published, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_depthai_imu_firmware_update, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_depthai_laser_dot_brightness, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_depthai_floodlight_brightness, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_rgbd_colorOnly, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_source_imageDecimation, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
@@ -809,10 +818,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->pushButton_calibrate_simple, SIGNAL(clicked()), this, SLOT(calibrateSimple()));
connect(_ui->toolButton_openniOniPath, SIGNAL(clicked()), this, SLOT(selectSourceOniPath()));
connect(_ui->toolButton_openni2OniPath, SIGNAL(clicked()), this, SLOT(selectSourceOni2Path()));
connect(_ui->comboBox_k4a_rgb_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_framerate, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_rgb_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_framerate, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_k4a_depth_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_k4a_irDepth, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkbox_k4a_irDepth, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->toolButton_k4a_mkv, SIGNAL(clicked()), this, SLOT(selectSourceMKVPath()));
connect(_ui->toolButton_source_distortionModel, SIGNAL(clicked()), this, SLOT(selectSourceDistortionModel()));
connect(_ui->toolButton_distortionModel, SIGNAL(clicked()), this, SLOT(visualizeDistortionModel()));
@@ -1139,6 +1148,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->checkbox_rgbd_createOccupancyGrid->setObjectName(Parameters::kRGBDCreateOccupancyGrid().c_str());
_ui->RGBDMarkerDetection->setObjectName(Parameters::kRGBDMarkerDetection().c_str());
_ui->spinBox_maxOdomCacheSize->setObjectName(Parameters::kRGBDMaxOdomCacheSize().c_str());
_ui->checkbox_localizationSmoothing->setObjectName(Parameters::kRGBDLocalizationSmoothing().c_str());
// Registration
_ui->reg_repeatOnce->setObjectName(Parameters::kRegRepeatOnce().c_str());
@@ -2006,9 +2016,9 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->lineEdit_rs2_jsonFile->clear();
_ui->lineEdit_openniOniPath->clear();
_ui->lineEdit_openni2OniPath->clear();
_ui->comboBox_k4a_rgb_resolution->setCurrentIndex(0);
_ui->comboBox_k4a_framerate->setCurrentIndex(2);
_ui->comboBox_k4a_depth_resolution->setCurrentIndex(2);
_ui->comboBox_k4a_rgb_resolution->setCurrentIndex(0);
_ui->comboBox_k4a_framerate->setCurrentIndex(2);
_ui->comboBox_k4a_depth_resolution->setCurrentIndex(2);
_ui->checkbox_k4a_irDepth->setChecked(false);
_ui->lineEdit_k4a_mkv->clear();
_ui->source_checkBox_useMKVStamps->setChecked(true);
@@ -2033,7 +2043,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->spinBox_stereo_right_device->setValue(-1);
_ui->spinBox_stereousbcam_streamWidth->setValue(0);
_ui->spinBox_stereousbcam_streamHeight->setValue(0);
_ui->comboBox_stereoZed_resolution->setCurrentIndex(2);
_ui->comboBox_stereoZed_resolution->setCurrentIndex(CameraStereoZed::sdkVersion()<4?3:6);
_ui->comboBox_stereoZed_quality->setCurrentIndex(1);
_ui->checkbox_stereoZed_selfCalibration->setChecked(true);
_ui->comboBox_stereoZed_sensingMode->setCurrentIndex(0);
@@ -2053,6 +2063,8 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->spinBox_depthai_confidence->setValue(200);
_ui->checkBox_depthai_imu_published->setChecked(true);
_ui->checkBox_depthai_imu_firmware_update->setChecked(false);
_ui->doubleSpinBox_depthai_laser_dot_brightness->setValue(0.0);
_ui->doubleSpinBox_depthai_floodlight_brightness->setValue(200.0);
_ui->checkBox_cameraImages_configForEachFrame->setChecked(false);
_ui->checkBox_cameraImages_timestamps->setChecked(false);
@@ -2457,9 +2469,9 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
settings.endGroup(); // K4W2
settings.beginGroup("K4A");
_ui->comboBox_k4a_rgb_resolution->setCurrentIndex(settings.value("rgb_resolution", _ui->comboBox_k4a_rgb_resolution->currentIndex()).toInt());
_ui->comboBox_k4a_framerate->setCurrentIndex(settings.value("framerate", _ui->comboBox_k4a_framerate->currentIndex()).toInt());
_ui->comboBox_k4a_depth_resolution->setCurrentIndex(settings.value("depth_resolution", _ui->comboBox_k4a_depth_resolution->currentIndex()).toInt());
_ui->comboBox_k4a_rgb_resolution->setCurrentIndex(settings.value("rgb_resolution", _ui->comboBox_k4a_rgb_resolution->currentIndex()).toInt());
_ui->comboBox_k4a_framerate->setCurrentIndex(settings.value("framerate", _ui->comboBox_k4a_framerate->currentIndex()).toInt());
_ui->comboBox_k4a_depth_resolution->setCurrentIndex(settings.value("depth_resolution", _ui->comboBox_k4a_depth_resolution->currentIndex()).toInt());
_ui->checkbox_k4a_irDepth->setChecked(settings.value("ir", _ui->checkbox_k4a_irDepth->isChecked()).toBool());
_ui->lineEdit_k4a_mkv->setText(settings.value("mkvPath", _ui->lineEdit_k4a_mkv->text()).toString());
_ui->source_checkBox_useMKVStamps->setChecked(settings.value("useMkvStamps", _ui->source_checkBox_useMKVStamps->isChecked()).toBool());
@@ -2537,6 +2549,8 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->spinBox_depthai_confidence->setValue(settings.value("confidence", _ui->spinBox_depthai_confidence->value()).toInt());
_ui->checkBox_depthai_imu_published->setChecked(settings.value("imu_published", _ui->checkBox_depthai_imu_published->isChecked()).toBool());
_ui->checkBox_depthai_imu_firmware_update->setChecked(settings.value("imu_firmware_update", _ui->checkBox_depthai_imu_firmware_update->isChecked()).toBool());
_ui->doubleSpinBox_depthai_laser_dot_brightness->setValue(settings.value("laser_dot_brightness", _ui->doubleSpinBox_depthai_laser_dot_brightness->value()).toDouble());
_ui->doubleSpinBox_depthai_floodlight_brightness->setValue(settings.value("floodlight_brightness", _ui->doubleSpinBox_depthai_floodlight_brightness->value()).toDouble());
settings.endGroup(); // DepthAI
settings.beginGroup("Images");
@@ -2984,9 +2998,9 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.endGroup(); // K4W2
settings.beginGroup("K4A");
settings.setValue("rgb_resolution", _ui->comboBox_k4a_rgb_resolution->currentIndex());
settings.setValue("framerate", _ui->comboBox_k4a_framerate->currentIndex());
settings.setValue("depth_resolution", _ui->comboBox_k4a_depth_resolution->currentIndex());
settings.setValue("rgb_resolution", _ui->comboBox_k4a_rgb_resolution->currentIndex());
settings.setValue("framerate", _ui->comboBox_k4a_framerate->currentIndex());
settings.setValue("depth_resolution", _ui->comboBox_k4a_depth_resolution->currentIndex());
settings.setValue("ir", _ui->checkbox_k4a_irDepth->isChecked());
settings.setValue("mkvPath", _ui->lineEdit_k4a_mkv->text());
settings.setValue("useMkvStamps", _ui->source_checkBox_useMKVStamps->isChecked());
@@ -3063,7 +3077,9 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("depth", _ui->checkBox_depthai_depth->isChecked());
settings.setValue("confidence", _ui->spinBox_depthai_confidence->value());
settings.setValue("imu_published", _ui->checkBox_depthai_imu_published->isChecked());
settings.setValue("imu_firmware_update", _ui->checkBox_depthai_imu_firmware_update->isChecked());
settings.setValue("imu_firmware_update", _ui->checkBox_depthai_imu_firmware_update->isChecked());
settings.setValue("laser_dot_brightness", _ui->doubleSpinBox_depthai_laser_dot_brightness->value());
settings.setValue("floodlight_brightness", _ui->doubleSpinBox_depthai_floodlight_brightness->value());
settings.endGroup(); // DepthAI
settings.beginGroup("Images");
@@ -6039,9 +6055,9 @@ Camera * PreferencesDialog::createCamera(
}
((CameraK4A*)camera)->setIRDepthFormat(_ui->checkbox_k4a_irDepth->isChecked());
((CameraK4A*)camera)->setPreferences(_ui->comboBox_k4a_rgb_resolution->currentIndex(),
_ui->comboBox_k4a_framerate->currentIndex(),
_ui->comboBox_k4a_depth_resolution->currentIndex());
((CameraK4A*)camera)->setPreferences(_ui->comboBox_k4a_rgb_resolution->currentIndex(),
_ui->comboBox_k4a_framerate->currentIndex(),
_ui->comboBox_k4a_depth_resolution->currentIndex());
}
else if (driver == kSrcRealSense)
{
@@ -6311,6 +6327,9 @@ Camera * PreferencesDialog::createCamera(
((CameraDepthAI*)camera)->setOutputDepth(_ui->checkBox_depthai_depth->isChecked(), _ui->spinBox_depthai_confidence->value());
((CameraDepthAI*)camera)->setIMUFirmwareUpdate(_ui->checkBox_depthai_imu_firmware_update->isChecked());
((CameraDepthAI*)camera)->setIMUPublished(_ui->checkBox_depthai_imu_published->isChecked());
((CameraDepthAI*)camera)->publishInterIMU(_ui->checkbox_publishInterIMU->isChecked());
((CameraDepthAI*)camera)->setLaserDotBrightness(_ui->doubleSpinBox_depthai_laser_dot_brightness->value());
((CameraDepthAI*)camera)->setFloodLightBrightness(_ui->doubleSpinBox_depthai_floodlight_brightness->value());
}
else if(driver == kSrcUsbDevice)
{
@@ -6609,35 +6628,28 @@ void PreferencesDialog::testOdometry()
return;
}
ParametersMap parameters = this->getAllParameters();
IMUThread * imuThread = 0;
if((this->getSourceDriver() == kSrcStereoImages ||
this->getSourceDriver() == kSrcRGBDImages ||
this->getSourceDriver() == kSrcImages) &&
!_ui->lineEdit_cameraImages_path_imu->text().isEmpty())
{
if(this->getOdomStrategy() != Odometry::kTypeOkvis &&
this->getOdomStrategy() != Odometry::kTypeMSCKF &&
this->getOdomStrategy() != Odometry::kTypeVINS &&
this->getOdomStrategy() != Odometry::kTypeOpenVINS)
imuThread = new IMUThread(_ui->spinBox_cameraImages_max_imu_rate->value(), this->getIMULocalTransform());
if(getIMUFilteringStrategy()>0)
{
imuThread->enableIMUFiltering(getIMUFilteringStrategy()-1, parameters, getIMUFilteringBaseFrameConversion());
}
if(!imuThread->init(_ui->lineEdit_cameraImages_path_imu->text().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("IMU path is set but odometry chosen doesn't support asynchronous IMU, ignoring IMU..."), QMessageBox::Ok);
}
else
{
imuThread = new IMUThread(_ui->spinBox_cameraImages_max_imu_rate->value(), this->getIMULocalTransform());
if(!imuThread->init(_ui->lineEdit_cameraImages_path_imu->text().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("Initialization of IMU data has failed! Path=%1.").arg(_ui->lineEdit_cameraImages_path_imu->text()), QMessageBox::Ok);
delete camera;
delete imuThread;
return;
}
tr("Initialization of IMU data has failed! Path=%1.").arg(_ui->lineEdit_cameraImages_path_imu->text()), QMessageBox::Ok);
delete camera;
delete imuThread;
return;
}
}
ParametersMap parameters = this->getAllParameters();
if(getOdomRegistrationApproach() < 3)
{
uInsert(parameters, ParametersPair(Parameters::kRegStrategy(), uNumber2Str(getOdomRegistrationApproach())));
@@ -7059,7 +7071,7 @@ void PreferencesDialog::calibrateOdomSensorExtrinsics()
return;
}
// 3 steps calibration: RGB -> IR -> Extrinsic
QMessageBox::StandardButton button = QMessageBox::question(this, tr("Calibration"),
tr("We will calibrate the extrinsics. Important: Make sure "
+314 -222
View File
@@ -63,7 +63,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<y>-611</y>
<width>756</width>
<height>3657</height>
</rect>
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>22</number>
<number>12</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,0">
@@ -3188,7 +3188,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<item>
<widget class="QStackedWidget" name="stackedWidget_src">
<property name="currentIndex">
<number>3</number>
<number>1</number>
</property>
<widget class="QWidget" name="page_41">
<layout class="QVBoxLayout" name="verticalLayout_64">
@@ -4971,7 +4971,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<item>
<widget class="QStackedWidget" name="stackedWidget_stereo">
<property name="currentIndex">
<number>10</number>
<number>4</number>
</property>
<widget class="QWidget" name="page_49">
<layout class="QVBoxLayout" name="verticalLayout_91"/>
@@ -5240,6 +5240,11 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<string>ULTRA</string>
</property>
</item>
<item>
<property name="text">
<string>NEURAL</string>
</property>
</item>
</widget>
</item>
<item row="5" column="1">
@@ -5398,16 +5403,31 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<string>HD1080</string>
</property>
</item>
<item>
<property name="text">
<string>HD1200</string>
</property>
</item>
<item>
<property name="text">
<string>HD720</string>
</property>
</item>
<item>
<property name="text">
<string>SVGA</string>
</property>
</item>
<item>
<property name="text">
<string>VGA</string>
</property>
</item>
<item>
<property name="text">
<string>AUTO</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -5923,6 +5943,58 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_depthai_laser_dot_brightness">
<property name="suffix">
<string> mA</string>
</property>
<property name="maximum">
<double>1200.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_676">
<property name="text">
<string>Laser dot brightness.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_depthai_floodlight_brightness">
<property name="suffix">
<string> mA</string>
</property>
<property name="maximum">
<double>1500.000000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_677">
<property name="text">
<string>Floodlight brightness.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -11081,33 +11153,49 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<string>Map Update</string>
</property>
<layout class="QGridLayout" name="gridLayout_47" columnstretch="0,1">
<item row="8" column="1">
<widget class="QLabel" name="label_scanMatching_14">
<property name="text">
<string>Use Identity matrix as guess when computing loop closure transform, otherwise no guess is used (assuming that registration strategy can deal with transformation estimation without guess).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QDoubleSpinBox" name="maxLocalizationDistance">
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="rgdb_newMapOdomChange">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_152">
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="rgdb_linearSpeedUpdate">
<property name="suffix">
<string> m/s</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="loopClosure_identityGuess">
<property name="text">
<string>Angular update: Minimum angular displacement to update the map. Note that Weight Update is done prior to this, so weights are still updated.</string>
<string/>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_scanMatching_7">
<property name="text">
<string>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 &quot;Optimizer/GravitySigma&quot; is not zero.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11117,6 +11205,58 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_153">
<property name="text">
<string>Linear update: Minimum linear displacement to update the map. Note that Weight Update is done prior to this, so weights are still updated.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_163">
<property name="text">
<string>Odometry change detected that triggers a new map (0 means whatever the odometry change, the detector will still link the new pose in the current map). Also by default, when an odometry with Identity transformation is detected, a new map is automatically created. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="rgdb_angularSpeedUpdate">
<property name="suffix">
<string> rad/s</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>3.140000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="odomScanHistory">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_maxLocalLocationsRetrieved"/>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="rgdb_angularUpdate">
<property name="suffix">
@@ -11133,10 +11273,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="memCovOffDiagIgnored">
<item row="11" column="1">
<widget class="QLabel" name="label_scanMatching_16">
<property name="text">
<string/>
<string>Inverted registration. On loop closure, do registration from the target to reference instead of reference to target.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
@@ -11172,104 +11318,26 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="rgdb_newMapOdomChange">
<property name="suffix">
<string> m</string>
<item row="18" column="1">
<widget class="QLabel" name="label_space2_5">
<property name="text">
<string>Maximum odometry cache size. Used only in localization mode. This is used to get smoother localizations and to verify localization transforms (when maximum graph error is not null) to make sure we don't teleport to a location very similar to one we previously localized on. Set 0 to disable caching.</string>
</property>
<property name="decimals">
<number>1</number>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="loopClosure_bunlde">
<item row="7" column="0">
<widget class="QCheckBox" name="odomGravity">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_153">
<property name="text">
<string>Linear update: Minimum linear displacement to update the map. Note that Weight Update is done prior to this, so weights are still updated.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_432">
<property name="text">
<string>Maximum linear speed to update the map (0 means not limit).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="rgbd_savedLocalizationIgnored">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="rgdb_linearSpeedUpdate">
<property name="suffix">
<string> m/s</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="rgdb_linearUpdate">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_163">
<property name="text">
<string>Odometry change detected that triggers a new map (0 means whatever the odometry change, the detector will still link the new pose in the current map). Also by default, when an odometry with Identity transformation is detected, a new map is automatically created. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QSpinBox" name="spinBox_maxOdomCacheSize">
<property name="maximum">
@@ -11287,10 +11355,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_scanMatching_11">
<item row="14" column="1">
<widget class="QLabel" name="label_scanMatching_3">
<property name="text">
<string>Ignore off diagonal values of the odometry covariance matrix.</string>
<string>Maximum local locations retrieved (0=disabled) near the current pose in the local map or on the current planned path (those on the planned path have priority).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11300,6 +11368,33 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_scanMatching_14">
<property name="text">
<string>Use Identity matrix as guess when computing loop closure transform, otherwise no guess is used (assuming that registration strategy can deal with transformation estimation without guess).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="loopClosure_bunlde">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="loopClosure_invertedReg">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_scanMatching_12">
<property name="text">
@@ -11313,59 +11408,23 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_scanMatching_7">
<property name="text">
<string>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 &quot;Optimizer/GravitySigma&quot; is not zero.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_scanMatching_9">
<property name="text">
<string>Re-extract visual features when computing loop closure transformations. Raw features are not saved in database.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="rgdb_angularSpeedUpdate">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="rgdb_linearUpdate">
<property name="suffix">
<string> rad/s</string>
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>3.140000000000000</double>
<number>3</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="rgbd_loopCovLimited">
<item row="2" column="1">
<widget class="QLabel" name="label_432">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_433">
<property name="text">
<string>Maximum angular speed to update the map (0 means not limit).</string>
<string>Maximum linear speed to update the map (0 means not limit).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11375,13 +11434,24 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_maxLocalLocationsRetrieved"/>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_scanMatching_10">
<item row="9" column="0">
<widget class="QCheckBox" name="loopClosure_reextract">
<property name="text">
<string>Do local bundle adjustment with neighborhood of the loop closure.</string>
<string/>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="memCovOffDiagIgnored">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_scanMatching">
<property name="text">
<string>Neighbor link refining. When a new node is added to the graph, the transformation of its neighbor link (odometry) with the previous node is refined using ICP registration approach (laser scans required).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11404,20 +11474,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="odomScanHistory">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="odomGravity">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_space2_12">
<property name="text">
@@ -11431,39 +11487,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_scanMatching_3">
<property name="text">
<string>Maximum local locations retrieved (0=disabled) near the current pose in the local map or on the current planned path (those on the planned path have priority).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="loopClosure_reextract">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="label_space2_5">
<property name="text">
<string>Maximum odometry cache size. Used only in localization mode. This is used to get smoother localizations and to verify localization transforms (when maximum graph error is not null) to make sure we don't teleport to a location very similar to one we previously localized on. Set 0 to disable caching.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_scanMatching_5">
<property name="text">
@@ -11477,17 +11500,40 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="loopClosure_identityGuess">
<item row="1" column="1">
<widget class="QLabel" name="label_152">
<property name="text">
<string>Angular update: Minimum angular displacement to update the map. Note that Weight Update is done prior to this, so weights are still updated.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="rgbd_savedLocalizationIgnored">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_scanMatching">
<item row="17" column="0">
<widget class="QDoubleSpinBox" name="maxLocalizationDistance">
<property name="suffix">
<string> m</string>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_scanMatching_11">
<property name="text">
<string>Neighbor link refining. When a new node is added to the graph, the transformation of its neighbor link (odometry) with the previous node is refined using ICP registration approach (laser scans required).</string>
<string>Ignore off diagonal values of the odometry covariance matrix.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11497,10 +11543,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_scanMatching_16">
<item row="10" column="1">
<widget class="QLabel" name="label_scanMatching_10">
<property name="text">
<string>Inverted registration. On loop closure, do registration from the target to reference instead of reference to target.</string>
<string>Do local bundle adjustment with neighborhood of the loop closure.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -11510,8 +11556,54 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="loopClosure_invertedReg">
<item row="13" column="0">
<widget class="QCheckBox" name="rgbd_loopCovLimited">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_scanMatching_9">
<property name="text">
<string>Re-extract visual features when computing loop closure transformations. Raw features are not saved in database.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_433">
<property name="text">
<string>Maximum angular speed to update the map (0 means not limit).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="19" column="1">
<widget class="QLabel" name="label_space2_18">
<property name="text">
<string>Localization smoothing. Used only in localization mode. Adjust localization constraints based on optimized odometry cache poses.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="19" column="0">
<widget class="QCheckBox" name="checkbox_localizationSmoothing">
<property name="text">
<string/>
</property>