diff --git a/corelib/include/rtabmap/core/Memory.h b/corelib/include/rtabmap/core/Memory.h index 4f418879..e323e91f 100644 --- a/corelib/include/rtabmap/core/Memory.h +++ b/corelib/include/rtabmap/core/Memory.h @@ -282,6 +282,7 @@ private: int _imagePostDecimation; bool _compressionParallelized; float _laserScanDownsampleStepSize; + float _laserScanVoxelSize; int _laserScanNormalK; int _laserScanNormalRadius; bool _reextractLoopClosureFeatures; diff --git a/corelib/include/rtabmap/core/OdometryF2M.h b/corelib/include/rtabmap/core/OdometryF2M.h index 1b28e739..df739c54 100644 --- a/corelib/include/rtabmap/core/OdometryF2M.h +++ b/corelib/include/rtabmap/core/OdometryF2M.h @@ -64,6 +64,7 @@ private: float scanKeyFrameThr_; int scanMaximumMapSize_; float scanSubtractRadius_; + float scanSubtractAngle_; int bundleAdjustment_; int bundleMaxFrames_; diff --git a/corelib/include/rtabmap/core/Parameters.h b/corelib/include/rtabmap/core/Parameters.h index 5de16847..59a30a99 100644 --- a/corelib/include/rtabmap/core/Parameters.h +++ b/corelib/include/rtabmap/core/Parameters.h @@ -211,8 +211,9 @@ class RTABMAP_EXP Parameters RTABMAP_PARAM(Mem, ImagePostDecimation, int, 1, "Image decimation (>=1) of saved data in created signatures (after features extraction). Decimation is done from the original image. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value)."); RTABMAP_PARAM(Mem, CompressionParallelized, bool, true, "Compression of sensor data is multi-threaded."); RTABMAP_PARAM(Mem, LaserScanDownsampleStepSize, int, 1, "If > 1, downsample the laser scans when creating a signature."); + RTABMAP_PARAM(Mem, LaserScanVoxelSize, float, 0.0, uFormat("If > 0 m, voxel filtering is done on laser scans when creating a signature. If the laser scan had normals, they will be removed. To recompute the normals, make sure to use \"%s\" or \"%s\" parameters.", kMemLaserScanNormalK().c_str(), kMemLaserScanNormalRadius().c_str()).c_str()); RTABMAP_PARAM(Mem, LaserScanNormalK, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature."); - RTABMAP_PARAM(Mem, LaserScanNormalRadius, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with radius search neighbors when creating a signature."); + RTABMAP_PARAM(Mem, LaserScanNormalRadius, int, 0, "If > 0 m and laser scans don't have normals, normals will be computed with radius search neighbors when creating a signature."); RTABMAP_PARAM(Mem, UseOdomFeatures, bool, false, "Use odometry features."); // KeypointMemory (Keypoint-based) @@ -396,6 +397,7 @@ class RTABMAP_EXP Parameters RTABMAP_PARAM(OdomF2M, MaxNewFeatures, int, 0, "[Visual] Maximum features (sorted by keypoint response) added to local map from a new key-frame. 0 means no limit."); RTABMAP_PARAM(OdomF2M, ScanMaxSize, int, 2000, "[Geometry] Maximum local scan map size."); RTABMAP_PARAM(OdomF2M, ScanSubtractRadius, float, 0.05, "[Geometry] Radius used to filter points of a new added scan to local map. This could match the voxel size of the scans."); + RTABMAP_PARAM(OdomF2M, ScanSubtractAngle, float, 45, uFormat("[Geometry] Max angle (degrees) used to filter points of a new added scan to local map (when \"%s\">0). 0 means any angle.", kOdomF2MScanSubtractRadius().c_str()).c_str()); RTABMAP_PARAM(OdomF2M, BundleAdjustment, int, 0, "Local bundle adjustment: 0=disabled, 1=g2o, 2=cvsba."); RTABMAP_PARAM(OdomF2M, BundleAdjustmentMaxFrames, int, 0, "Maximum frames used for bundle adjustment (0=inf or all current frames in the local map)."); diff --git a/corelib/include/rtabmap/core/Statistics.h b/corelib/include/rtabmap/core/Statistics.h index cd6def47..c81eee43 100644 --- a/corelib/include/rtabmap/core/Statistics.h +++ b/corelib/include/rtabmap/core/Statistics.h @@ -134,6 +134,7 @@ class RTABMAP_EXP Statistics RTABMAP_STATS(TimingMem, Compressing_data, ms); RTABMAP_STATS(TimingMem, Post_decimation, ms); RTABMAP_STATS(TimingMem, Scan_downsampling, ms); + RTABMAP_STATS(TimingMem, Scan_voxel_filtering, ms); RTABMAP_STATS(TimingMem, Scan_normals, ms); RTABMAP_STATS(TimingMem, Occupancy_grid, ms); diff --git a/corelib/include/rtabmap/core/util3d_surface.h b/corelib/include/rtabmap/core/util3d_surface.h index 4f723896..c8253f8d 100644 --- a/corelib/include/rtabmap/core/util3d_surface.h +++ b/corelib/include/rtabmap/core/util3d_surface.h @@ -263,16 +263,24 @@ pcl::PointCloud::Ptr RTABMAP_EXP computeFastOrganizedNormals( const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0)); float RTABMAP_EXP computeNormalsComplexity( - const cv::Mat & scan); + const cv::Mat & scan, + cv::Mat * pcaEigenVectors = 0, + cv::Mat * pcaEigenValues = 0); float RTABMAP_EXP computeNormalsComplexity( const pcl::PointCloud & normals, - bool is2d = false); + bool is2d = false, + cv::Mat * pcaEigenVectors = 0, + cv::Mat * pcaEigenValues = 0); float RTABMAP_EXP computeNormalsComplexity( const pcl::PointCloud & cloud, - bool is2d = false); + bool is2d = false, + cv::Mat * pcaEigenVectors = 0, + cv::Mat * pcaEigenValues = 0); float RTABMAP_EXP computeNormalsComplexity( const pcl::PointCloud & cloud, - bool is2d = false); + bool is2d = false, + cv::Mat * pcaEigenVectors = 0, + cv::Mat * pcaEigenValues = 0); pcl::PointCloud::Ptr RTABMAP_EXP mls( const pcl::PointCloud::Ptr & cloud, diff --git a/corelib/src/Memory.cpp b/corelib/src/Memory.cpp index eed46118..eec614cb 100644 --- a/corelib/src/Memory.cpp +++ b/corelib/src/Memory.cpp @@ -88,6 +88,7 @@ Memory::Memory(const ParametersMap & parameters) : _imagePostDecimation(Parameters::defaultMemImagePostDecimation()), _compressionParallelized(Parameters::defaultMemCompressionParallelized()), _laserScanDownsampleStepSize(Parameters::defaultMemLaserScanDownsampleStepSize()), + _laserScanVoxelSize(Parameters::defaultMemLaserScanVoxelSize()), _laserScanNormalK(Parameters::defaultMemLaserScanNormalK()), _laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()), _reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()), @@ -440,6 +441,7 @@ void Memory::parseParameters(const ParametersMap & parameters) Parameters::parse(parameters, Parameters::kMemImagePostDecimation(), _imagePostDecimation); Parameters::parse(parameters, Parameters::kMemCompressionParallelized(), _compressionParallelized); Parameters::parse(parameters, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize); + Parameters::parse(parameters, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize); Parameters::parse(parameters, Parameters::kMemLaserScanNormalK(), _laserScanNormalK); Parameters::parse(parameters, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius); Parameters::parse(parameters, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures); @@ -3760,6 +3762,35 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p if(stats) stats->addStatistic(Statistics::kTimingMemScan_downsampling(), t*1000.0f); UDEBUG("time downsampling scan = %fs", t); } + if(!laserScan.empty() && _laserScanVoxelSize > 0.0f && !isIntermediateNode) + { + float pointsBeforeFiltering = laserScan.cols; + if(laserScan.channels() == 4 || laserScan.channels() == 7) + { + pcl::PointCloud::Ptr cloud = util3d::laserScanToPointCloudRGB(laserScan); + cloud = util3d::voxelize(cloud, _laserScanVoxelSize); + laserScan = util3d::laserScanFromPointCloud(*cloud); + } + else + { + pcl::PointCloud::Ptr cloud = util3d::laserScanToPointCloud(laserScan); + cloud = util3d::voxelize(cloud, _laserScanVoxelSize); + if(laserScan.channels() == 2 || laserScan.channels() == 5) + { + laserScan = util3d::laserScan2dFromPointCloud(*cloud); + } + else + { + laserScan = util3d::laserScanFromPointCloud(*cloud); + } + } + float ratio = float(laserScan.cols) / pointsBeforeFiltering; + maxLaserScanMaxPts = int(float(maxLaserScanMaxPts) * ratio); + + t = timer.ticks(); + if(stats) stats->addStatistic(Statistics::kTimingMemScan_voxel_filtering(), t*1000.0f); + UDEBUG("time voxel filtering scan = %fs", t); + } if(!laserScan.empty() && (_laserScanNormalK > 0 || _laserScanNormalRadius>0.0f) && laserScan.channels() > 1 && laserScan.channels() < 5 && diff --git a/corelib/src/OdometryF2M.cpp b/corelib/src/OdometryF2M.cpp index f5c571c6..552611e4 100644 --- a/corelib/src/OdometryF2M.cpp +++ b/corelib/src/OdometryF2M.cpp @@ -65,6 +65,7 @@ OdometryF2M::OdometryF2M(const ParametersMap & parameters) : scanKeyFrameThr_(Parameters::defaultOdomScanKeyFrameThr()), scanMaximumMapSize_(Parameters::defaultOdomF2MScanMaxSize()), scanSubtractRadius_(Parameters::defaultOdomF2MScanSubtractRadius()), + scanSubtractAngle_(Parameters::defaultOdomF2MScanSubtractAngle()), bundleAdjustment_(Parameters::defaultOdomF2MBundleAdjustment()), bundleMaxFrames_(Parameters::defaultOdomF2MBundleAdjustmentMaxFrames()), map_(new Signature(-1)), @@ -80,6 +81,10 @@ OdometryF2M::OdometryF2M(const ParametersMap & parameters) : Parameters::parse(parameters, Parameters::kOdomScanKeyFrameThr(), scanKeyFrameThr_); Parameters::parse(parameters, Parameters::kOdomF2MScanMaxSize(), scanMaximumMapSize_); Parameters::parse(parameters, Parameters::kOdomF2MScanSubtractRadius(), scanSubtractRadius_); + if(Parameters::parse(parameters, Parameters::kOdomF2MScanSubtractAngle(), scanSubtractAngle_)) + { + scanSubtractAngle_ *= M_PI/180.0f; + } Parameters::parse(parameters, Parameters::kOdomF2MBundleAdjustment(), bundleAdjustment_); Parameters::parse(parameters, Parameters::kOdomF2MBundleAdjustmentMaxFrames(), bundleMaxFrames_); UASSERT(bundleMaxFrames_ >= 0); @@ -605,7 +610,7 @@ Transform OdometryF2M::computeTransform( mapCloudNormals, pcl::IndicesPtr(new std::vector), scanSubtractRadius_, - 0.0f); + scanSubtractAngle_); newPoints = frameCloudNormalsIndices->size(); } else diff --git a/corelib/src/RegistrationIcp.cpp b/corelib/src/RegistrationIcp.cpp index af060db6..4bb2cf33 100644 --- a/corelib/src/RegistrationIcp.cpp +++ b/corelib/src/RegistrationIcp.cpp @@ -433,6 +433,7 @@ Transform RegistrationIcp::computeTransformationImpl( double variance = 1.0; bool transformComputed = false; bool tooLowComplexityForPlaneToPlane = false; + cv::Mat complexityVectors; if( _pointToPlane && _voxelSize == 0.0f && @@ -442,14 +443,16 @@ Transform RegistrationIcp::computeTransformationImpl( { //special case if we have already normals computed and there is no filtering - double fromComplexity = util3d::computeNormalsComplexity(fromScan); - double toComplexity = util3d::computeNormalsComplexity(toScan); + cv::Mat complexityVectorsFrom, complexityVectorsTo; + double fromComplexity = util3d::computeNormalsComplexity(fromScan, &complexityVectorsFrom); + double toComplexity = util3d::computeNormalsComplexity(toScan, &complexityVectorsTo); float complexity = fromComplexity 0.0f) + if(_voxelSize > 0.0f || !tooLowComplexityForPlaneToPlane) { // update output scans if(fromScan.channels() == 2 || fromScan.channels() == 5) @@ -743,7 +748,7 @@ Transform RegistrationIcp::computeTransformationImpl( } #ifdef RTABMAP_POINTMATCHER - if(_libpointmatcher && !_pointToPlane) // don't use libpointmatcher if it is configured for point to plane + if(_libpointmatcher) { // Load point clouds DP data = pclToDP(fromCloudFiltered, fromScan.channels() == 2 || fromScan.channels() == 5); @@ -756,7 +761,30 @@ Transform RegistrationIcp::computeTransformationImpl( UASSERT(_libpointmatcherICP != 0); PM::ICP & icp = *((PM::ICP*)_libpointmatcherICP); UDEBUG("libpointmatcher icp... (if there is a seg fault here, make sure all third party libraries are built with same Eigen version.)"); - T = icp(data, ref); + if(_pointToPlane) + { + // temporary set PointToPointErrorMinimizer + PM::ICP & icpTmp = icp; + icpTmp.errorMinimizer.reset(PM::get().ErrorMinimizerRegistrar.create("PointToPointErrorMinimizer")); + + for(PM::OutlierFilters::iterator iter=icpTmp.outlierFilters.begin(); iter!=icpTmp.outlierFilters.end();) + { + if((*iter)->className.compare("SurfaceNormalOutlierFilter") == 0) + { + iter = icpTmp.outlierFilters.erase(iter); + } + else + { + ++iter; + } + } + + T = icpTmp(data, ref); + } + else + { + T = icp(data, ref); + } UDEBUG("libpointmatcher icp...done!"); icpT = Transform::fromEigen3d(Eigen::Affine3d(Eigen::Matrix4d(eigenMatrixToDim(T.template cast(), 4)))); @@ -790,6 +818,39 @@ Transform RegistrationIcp::computeTransformationImpl( if(!icpT.isNull() && hasConverged) { + if(tooLowComplexityForPlaneToPlane) + { + Transform guessInv = guess.inverse(); + Transform t = guessInv * icpT.inverse() * guess; + Eigen::Vector3f v(t.x(), t.y(), t.z()); + if(complexityVectors.cols == 2) + { + // limit translation in direction of the first eigen vector + Eigen::Vector3f n(complexityVectors.at(0,0), complexityVectors.at(0,1), 0.0f); + float a = v.dot(n); + v = n*a; + } + else if(complexityVectors.rows == 3) + { + // limit translation in direction of the first and second eigen vectors + Eigen::Vector3f n1(complexityVectors.at(0,0), complexityVectors.at(0,1), complexityVectors.at(0,2)); + Eigen::Vector3f n2(complexityVectors.at(1,0), complexityVectors.at(1,1), complexityVectors.at(1,2)); + float a = v.dot(n1); + float b = v.dot(n2); + v = n1*a; + v += n2*b; + } + else + { + UWARN("not supposed to be here!"); + v = Eigen::Vector3f(0,0,0); + } + float roll, pitch, yaw; + t.getEulerAngles(roll, pitch, yaw); + t = Transform(v[0], v[1], v[2], roll, pitch, yaw); + icpT = guess * t.inverse() * guessInv; + } + util3d::computeVarianceAndCorrespondences( fromCloudRegistered, toCloudFiltered, diff --git a/corelib/src/util3d.cpp b/corelib/src/util3d.cpp index fe3ad546..63bf4d43 100644 --- a/corelib/src/util3d.cpp +++ b/corelib/src/util3d.cpp @@ -1531,6 +1531,7 @@ pcl::PointCloud::Ptr laserScanToPointCloud(const cv::Mat & laserS pcl::PointCloud::Ptr output(new pcl::PointCloud); output->resize(laserScan.cols); + output->is_dense = true; bool nullTransform = transform.isNull(); Eigen::Affine3f transform3f = transform.toEigen3f(); for(int i=0; i::Ptr laserScanToPointCloudNormal(const cv::Mat pcl::PointCloud::Ptr output(new pcl::PointCloud); output->resize(laserScan.cols); + output->is_dense = true; bool nullTransform = transform.isNull(); for(int i=0; i::Ptr laserScanToPointCloudRGB(const cv::Mat & pcl::PointCloud::Ptr output(new pcl::PointCloud); output->resize(laserScan.cols); + output->is_dense = true; bool nullTransform = transform.isNull() || transform.isIdentity(); Eigen::Affine3f transform3f = transform.toEigen3f(); for(int i=0; i::Ptr laserScanToPointCloudRGBNormal(cons pcl::PointCloud::Ptr output(new pcl::PointCloud); output->resize(laserScan.cols); + output->is_dense = true; bool nullTransform = transform.isNull() || transform.isIdentity(); for(int i=0; i::Ptr computeFastOrganizedNormals( return normals; } -float computeNormalsComplexity(const cv::Mat & scan) +float computeNormalsComplexity( + const cv::Mat & scan, + cv::Mat * pcaEigenVectors, + cv::Mat * pcaEigenValues) { if(!scan.empty() && (scan.channels() == 5 || scan.channels() == 6 || scan.channels() == 7)) { @@ -2384,6 +2387,15 @@ float computeNormalsComplexity(const cv::Mat & scan) { cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW); + if(pcaEigenVectors) + { + *pcaEigenVectors = pca_analysis.eigenvectors; + } + if(pcaEigenValues) + { + *pcaEigenValues = pca_analysis.eigenvalues; + } + // Get last eigen value, scale between 0 and 1: 0=low complexity, 1=high complexity return pca_analysis.eigenvalues.at(0, is2d?1:2)*(is2d?2.0f:3.0f); } @@ -2395,7 +2407,11 @@ float computeNormalsComplexity(const cv::Mat & scan) return 0.0f; } -float computeNormalsComplexity(const pcl::PointCloud & cloud, bool is2d) +float computeNormalsComplexity( + const pcl::PointCloud & cloud, + bool is2d, + cv::Mat * pcaEigenVectors, + cv::Mat * pcaEigenValues) { //Construct a buffer used by the pca analysis int sz = static_cast(cloud.size()*2); @@ -2419,13 +2435,26 @@ float computeNormalsComplexity(const pcl::PointCloud & cloud, { cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW); + if(pcaEigenVectors) + { + *pcaEigenVectors = pca_analysis.eigenvectors; + } + if(pcaEigenValues) + { + *pcaEigenValues = pca_analysis.eigenvalues; + } + // Get last eigen value, scale between 0 and 1: 0=low complexity, 1=high complexity return pca_analysis.eigenvalues.at(0, is2d?1:2)*(is2d?2.0f:3.0f); } return 0.0f; } -float computeNormalsComplexity(const pcl::PointCloud & normals, bool is2d) +float computeNormalsComplexity( + const pcl::PointCloud & normals, + bool is2d, + cv::Mat * pcaEigenVectors, + cv::Mat * pcaEigenValues) { //Construct a buffer used by the pca analysis int sz = static_cast(normals.size()*2); @@ -2449,13 +2478,26 @@ float computeNormalsComplexity(const pcl::PointCloud & normals, boo { cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW); + if(pcaEigenVectors) + { + *pcaEigenVectors = pca_analysis.eigenvectors; + } + if(pcaEigenValues) + { + *pcaEigenValues = pca_analysis.eigenvalues; + } + // Get last eigen value, scale between 0 and 1: 0=low complexity, 1=high complexity return pca_analysis.eigenvalues.at(0, is2d?1:2)*(is2d?2.0f:3.0f); } return 0.0f; } -float computeNormalsComplexity(const pcl::PointCloud & cloud, bool is2d) +float computeNormalsComplexity( + const pcl::PointCloud & cloud, + bool is2d, + cv::Mat * pcaEigenVectors, + cv::Mat * pcaEigenValues) { //Construct a buffer used by the pca analysis int sz = static_cast(cloud.size()*2); @@ -2479,6 +2521,15 @@ float computeNormalsComplexity(const pcl::PointCloud & c { cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW); + if(pcaEigenVectors) + { + *pcaEigenVectors = pca_analysis.eigenvectors; + } + if(pcaEigenValues) + { + *pcaEigenValues = pca_analysis.eigenvalues; + } + // Get last eigen value, scale between 0 and 1: 0=low complexity, 1=high complexity return pca_analysis.eigenvalues.at(0, is2d?1:2)*(is2d?2.0f:3.0f); } diff --git a/guilib/src/PreferencesDialog.cpp b/guilib/src/PreferencesDialog.cpp index 4d3c2fb1..a16c0a60 100644 --- a/guilib/src/PreferencesDialog.cpp +++ b/guilib/src/PreferencesDialog.cpp @@ -659,6 +659,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : _ui->spinBox_imagePreDecimation->setObjectName(Parameters::kMemImagePreDecimation().c_str()); _ui->spinBox_imagePostDecimation->setObjectName(Parameters::kMemImagePostDecimation().c_str()); _ui->general_spinBox_laserScanDownsample->setObjectName(Parameters::kMemLaserScanDownsampleStepSize().c_str()); + _ui->general_doubleSpinBox_laserScanVoxelSize->setObjectName(Parameters::kMemLaserScanVoxelSize().c_str()); _ui->general_spinBox_laserScanNormalK->setObjectName(Parameters::kMemLaserScanNormalK().c_str()); _ui->general_doubleSpinBox_laserScanNormalRadius->setObjectName(Parameters::kMemLaserScanNormalRadius().c_str()); _ui->checkBox_useOdomFeatures->setObjectName(Parameters::kMemUseOdomFeatures().c_str()); @@ -932,6 +933,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : _ui->spinBox_odom_f2m_maxNewFeatures->setObjectName(Parameters::kOdomF2MMaxNewFeatures().c_str()); _ui->spinBox_odom_f2m_scanMaxSize->setObjectName(Parameters::kOdomF2MScanMaxSize().c_str()); _ui->doubleSpinBox_odom_f2m_scanRadius->setObjectName(Parameters::kOdomF2MScanSubtractRadius().c_str()); + _ui->doubleSpinBox_odom_f2m_scanAngle->setObjectName(Parameters::kOdomF2MScanSubtractAngle().c_str()); _ui->odom_f2m_bundleStrategy->setObjectName(Parameters::kOdomF2MBundleAdjustment().c_str()); _ui->odom_f2m_bundleMaxFrames->setObjectName(Parameters::kOdomF2MBundleAdjustmentMaxFrames().c_str()); diff --git a/guilib/src/ui/preferencesDialog.ui b/guilib/src/ui/preferencesDialog.ui index 273fbfae..576f4aad 100644 --- a/guilib/src/ui/preferencesDialog.ui +++ b/guilib/src/ui/preferencesDialog.ui @@ -63,16 +63,25 @@ 0 - -215 + -629 678 - 2736 + 2739 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -86,7 +95,7 @@ QFrame::Raised - 21 + 18 @@ -4561,7 +4570,16 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki Directory of images (optional settings) - + + 0 + + + 0 + + + 0 + + 0 @@ -6040,6 +6058,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag + + + + -16 + + + 16 + + + @@ -6108,19 +6136,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - 999 - - - 1 - - - 2 - - - @@ -6131,16 +6146,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - Bad signatures are ignored. + + + + 999 - - true + + 1 - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + 2 @@ -6164,10 +6179,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - + + - Keep raw sensor data. Only useful to save loop closure computation time when features re-extraction is enabled. Disable to save RAM memory. + Bad signatures are ignored. true @@ -6187,6 +6202,19 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag + + + + Keep raw sensor data. Only useful to save loop closure computation time when features re-extraction is enabled. Disable to save RAM memory. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + @@ -6200,22 +6228,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - - 50 - 0 - - - - 1 - - - 9999 - - - @@ -6288,6 +6300,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag + + + + + + + false + + + @@ -6311,16 +6333,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - - - - false - - - @@ -6334,6 +6346,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag + + + + + + + false + + + @@ -6360,16 +6382,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - - - - false - - - @@ -6383,48 +6395,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - If > 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled. - - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - -16 - - - 16 - - - - - - - - 50 - 0 - - - - 0 - - - 99 - - - 0 - - - @@ -6435,16 +6405,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - + + - If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature. + - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + false @@ -6461,16 +6428,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - - - - false - - - @@ -6484,34 +6441,139 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - If > 0 and laser scans don't have normals, normals will be computed with radius search when creating a signature. - - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 50 - 0 - - - - 0.010000000000000 - - - + + + + Laser scan filtering + + + + + + + 50 + 0 + + + + 1 + + + 9999 + + + + + + + Downsampling step. If > 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 50 + 0 + + + + m + + + 0.010000000000000 + + + + + + + + 50 + 0 + + + + 0 + + + 99 + + + 0 + + + + + + + Normal K. If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Normal Radius. If > 0 and laser scans don't have normals, normals will be computed with radius search when creating a signature. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Voxel size. If > 0 m, voxel filtering is done on laser scans when creating a signature. If the laser scan had normals, they will be removed. To recompute the normals, make sure to use Normal K or Normal Radius parameters below. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 50 + 0 + + + + m + + + 3 + + + 0.010000000000000 + + + + + + @@ -10114,6 +10176,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag + + + + 999999999 + + + @@ -10140,14 +10209,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - - - 999999999 - - - - + [Visual] Local bundle adjustment. See Optimizer panel. This will not work if Optical Flow correspondences strategy is selected in Visual Registration panel. @@ -10160,7 +10222,14 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - + + + + 999999 + + + + [Visual] Maximum frames used for bundle adjustment (0=inf or all current frames in the local map). @@ -10173,7 +10242,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - + QComboBox::AdjustToContents @@ -10195,10 +10264,32 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - - + + + + [Geometry] Max angle (degrees) used to filter points of a new added scan to local map (when Radius above is >0). 0 means any angle. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + deg + + + 0 + - 999999 + 180.000000000000000 + + + 0.000000000000000 @@ -12562,7 +12653,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag - + + 0 + + + 0 + + + 0 + + 0 @@ -12702,7 +12802,16 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare - + + 0 + + + 0 + + + 0 + + 0 @@ -12860,7 +12969,16 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -12940,7 +13058,16 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -13052,7 +13179,16 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare 0 - + + 0 + + + 0 + + + 0 + + 0