Added Mem/LaserScanVoxelSize and OdomF2M/ScanSubtractAngle parameters. util3d::computeNormalsComplexity() now returns PCA's eigen vectors and values optionally. RegistrationIcp: detecting complexity of environment when PointToPLane is used, if too low, PointToPoint is done and movements are limited to main direction of the normals.

This commit is contained in:
matlabbe
2017-09-19 14:15:17 -04:00
parent cf6478b633
commit fd18c0b2e9
12 changed files with 491 additions and 188 deletions
+1
View File
@@ -282,6 +282,7 @@ private:
int _imagePostDecimation;
bool _compressionParallelized;
float _laserScanDownsampleStepSize;
float _laserScanVoxelSize;
int _laserScanNormalK;
int _laserScanNormalRadius;
bool _reextractLoopClosureFeatures;
@@ -64,6 +64,7 @@ private:
float scanKeyFrameThr_;
int scanMaximumMapSize_;
float scanSubtractRadius_;
float scanSubtractAngle_;
int bundleAdjustment_;
int bundleMaxFrames_;
+3 -1
View File
@@ -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).");
@@ -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);
+12 -4
View File
@@ -263,16 +263,24 @@ pcl::PointCloud<pcl::Normal>::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<pcl::Normal> & normals,
bool is2d = false);
bool is2d = false,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
float RTABMAP_EXP computeNormalsComplexity(
const pcl::PointCloud<pcl::PointNormal> & cloud,
bool is2d = false);
bool is2d = false,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
float RTABMAP_EXP computeNormalsComplexity(
const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
bool is2d = false);
bool is2d = false,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP mls(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
+31
View File
@@ -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<pcl::PointXYZRGB>::Ptr cloud = util3d::laserScanToPointCloudRGB(laserScan);
cloud = util3d::voxelize(cloud, _laserScanVoxelSize);
laserScan = util3d::laserScanFromPointCloud(*cloud);
}
else
{
pcl::PointCloud<pcl::PointXYZ>::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 &&
+6 -1
View File
@@ -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<int>),
scanSubtractRadius_,
0.0f);
scanSubtractAngle_);
newPoints = frameCloudNormalsIndices->size();
}
else
+70 -9
View File
@@ -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<toComplexity?fromComplexity:toComplexity;
info.icpStructuralComplexity = complexity;
if(complexity < _pointToPlaneMinComplexity)
{
tooLowComplexityForPlaneToPlane = true;
UWARN("ICP PointToPlane ignored as structural complexity is too low: %f < %f (%s). PointToPoint is done instead.", complexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str());
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): %f < %f (%s). PointToPoint is done instead.", complexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str());
}
else
{
@@ -610,14 +613,16 @@ Transform RegistrationIcp::computeTransformationImpl(
normalsTo = util3d::computeNormals(toCloudFiltered, _pointToPlaneK, _pointToPlaneRadius, viewpointTo);
}
double fromComplexity = util3d::computeNormalsComplexity(*normalsFrom, fromScan.channels() == 2 || fromScan.channels() == 5);
double toComplexity = util3d::computeNormalsComplexity(*normalsTo, toScan.channels() == 2 || toScan.channels() == 5);
cv::Mat complexityVectorsFrom, complexityVectorsTo;
double fromComplexity = util3d::computeNormalsComplexity(*normalsFrom, fromScan.channels() == 2 || fromScan.channels() == 5, &complexityVectorsFrom);
double toComplexity = util3d::computeNormalsComplexity(*normalsTo, toScan.channels() == 2 || toScan.channels() == 5, &complexityVectorsTo);
float complexity = fromComplexity<toComplexity?fromComplexity:toComplexity;
info.icpStructuralComplexity = complexity;
if(complexity < _pointToPlaneMinComplexity)
{
tooLowComplexityForPlaneToPlane = true;
UWARN("ICP PointToPlane ignored as structural complexity is too low: %f < %f (%s). PointToPoint is done instead.", complexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str());
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): %f < %f (%s). PointToPoint is done instead.", complexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str());
}
else
{
@@ -721,7 +726,7 @@ Transform RegistrationIcp::computeTransformationImpl(
UWARN("ICP PointToPlane ignored for 2d scans with PCL registration (some crash issues). Use libpointmatcher (%s) or disable %s to avoid this warning.", Parameters::kIcpPM().c_str(), Parameters::kIcpPointToPlane().c_str());
}
if(_voxelSize > 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<double>(T.template cast<double>(), 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<float>(0,0), complexityVectors.at<float>(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<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2));
Eigen::Vector3f n2(complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(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,
+4
View File
@@ -1531,6 +1531,7 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr laserScanToPointCloud(const cv::Mat & laserS
pcl::PointCloud<pcl::PointXYZ>::Ptr output(new pcl::PointCloud<pcl::PointXYZ>);
output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull();
Eigen::Affine3f transform3f = transform.toEigen3f();
for(int i=0; i<laserScan.cols; ++i)
@@ -1550,6 +1551,7 @@ pcl::PointCloud<pcl::PointNormal>::Ptr laserScanToPointCloudNormal(const cv::Mat
pcl::PointCloud<pcl::PointNormal>::Ptr output(new pcl::PointCloud<pcl::PointNormal>);
output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull();
for(int i=0; i<laserScan.cols; ++i)
{
@@ -1568,6 +1570,7 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr laserScanToPointCloudRGB(const cv::Mat &
pcl::PointCloud<pcl::PointXYZRGB>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGB>);
output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull() || transform.isIdentity();
Eigen::Affine3f transform3f = transform.toEigen3f();
for(int i=0; i<laserScan.cols; ++i)
@@ -1587,6 +1590,7 @@ pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr laserScanToPointCloudRGBNormal(cons
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull() || transform.isIdentity();
for(int i=0; i<laserScan.cols; ++i)
{
+55 -4
View File
@@ -2338,7 +2338,10 @@ pcl::PointCloud<pcl::Normal>::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<float>(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<pcl::PointNormal> & cloud, bool is2d)
float computeNormalsComplexity(
const pcl::PointCloud<pcl::PointNormal> & cloud,
bool is2d,
cv::Mat * pcaEigenVectors,
cv::Mat * pcaEigenValues)
{
//Construct a buffer used by the pca analysis
int sz = static_cast<int>(cloud.size()*2);
@@ -2419,13 +2435,26 @@ float computeNormalsComplexity(const pcl::PointCloud<pcl::PointNormal> & 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<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
}
return 0.0f;
}
float computeNormalsComplexity(const pcl::PointCloud<pcl::Normal> & normals, bool is2d)
float computeNormalsComplexity(
const pcl::PointCloud<pcl::Normal> & normals,
bool is2d,
cv::Mat * pcaEigenVectors,
cv::Mat * pcaEigenValues)
{
//Construct a buffer used by the pca analysis
int sz = static_cast<int>(normals.size()*2);
@@ -2449,13 +2478,26 @@ float computeNormalsComplexity(const pcl::PointCloud<pcl::Normal> & 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<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
}
return 0.0f;
}
float computeNormalsComplexity(const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud, bool is2d)
float computeNormalsComplexity(
const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
bool is2d,
cv::Mat * pcaEigenVectors,
cv::Mat * pcaEigenValues)
{
//Construct a buffer used by the pca analysis
int sz = static_cast<int>(cloud.size()*2);
@@ -2479,6 +2521,15 @@ float computeNormalsComplexity(const pcl::PointCloud<pcl::PointXYZRGBNormal> & 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<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
}
+2
View File
@@ -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());
+305 -169
View File
@@ -63,16 +63,25 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-215</y>
<y>-629</y>
<width>678</width>
<height>2736</height>
<height>2739</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -86,7 +95,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>21</number>
<number>18</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -4561,7 +4570,16 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<string>Directory of images (optional settings)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_93">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -6040,6 +6058,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QGridLayout" name="gridLayout_42" columnstretch="0,1">
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
<property name="minimum">
<number>-16</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QSpinBox" name="spinBox_imagePostDecimation">
<property name="minimum">
@@ -6108,19 +6136,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="general_spinBox_maxRetrieved">
<property name="maximum">
<number>999</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="general_checkBox_initWMWithAllNodes">
<property name="text">
@@ -6131,16 +6146,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_retrieved_3">
<property name="text">
<string>Bad signatures are ignored.</string>
<item row="2" column="0">
<widget class="QSpinBox" name="general_spinBox_maxRetrieved">
<property name="maximum">
<number>999</number>
</property>
<property name="wordWrap">
<bool>true</bool>
<property name="singleStep">
<number>1</number>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
@@ -6164,10 +6179,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_retrieved_5">
<item row="6" column="1">
<widget class="QLabel" name="label_retrieved_3">
<property name="text">
<string>Keep raw sensor data. Only useful to save loop closure computation time when features re-extraction is enabled. Disable to save RAM memory.</string>
<string>Bad signatures are ignored.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -6187,6 +6202,19 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_retrieved_5">
<property name="text">
<string>Keep raw sensor data. Only useful to save loop closure computation time when features re-extraction is enabled. Disable to save RAM memory.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_retrieved_11">
<property name="text">
@@ -6200,22 +6228,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QSpinBox" name="general_spinBox_laserScanDownsample">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="general_checkBox_keepDescriptors">
<property name="text">
@@ -6288,6 +6300,16 @@ 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="general_checkBox_badSignaturesIgnored">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_transferSortingByWeightId">
<property name="text">
@@ -6311,16 +6333,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="general_checkBox_badSignaturesIgnored">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
@@ -6334,6 +6346,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="general_checkBox_saveDepth16bits">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_ratioRecent">
<property name="text">
@@ -6360,16 +6382,6 @@ 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="general_checkBox_saveDepth16bits">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_retrieved_7">
<property name="text">
@@ -6383,48 +6395,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QLabel" name="label_retrieved_8">
<property name="text">
<string>If &gt; 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
<property name="minimum">
<number>-16</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QSpinBox" name="general_spinBox_laserScanNormalK">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="general_checkBox_compressionParallelized">
<property name="text">
@@ -6435,16 +6405,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_retrieved_14">
<item row="10" column="0">
<widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
<property name="text">
<string>If &gt; 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature.</string>
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
@@ -6461,16 +6428,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_retrieved_16">
<property name="text">
@@ -6484,34 +6441,139 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="label_retrieved_17">
<property name="text">
<string>If &gt; 0 and laser scans don't have normals, normals will be computed with radius search when creating a signature.</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="QDoubleSpinBox" name="general_doubleSpinBox_laserScanNormalRadius">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_27">
<property name="title">
<string>Laser scan filtering</string>
</property>
<layout class="QGridLayout" name="gridLayout_10" columnstretch="0,1">
<item row="0" column="0">
<widget class="QSpinBox" name="general_spinBox_laserScanDownsample">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_retrieved_8">
<property name="text">
<string>Downsampling step. If &gt; 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled.</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="general_doubleSpinBox_laserScanNormalRadius">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="general_spinBox_laserScanNormalK">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_retrieved_14">
<property name="text">
<string>Normal K. If &gt; 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_retrieved_17">
<property name="text">
<string>Normal Radius. If &gt; 0 and laser scans don't have normals, normals will be computed with radius search when creating a signature.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_retrieved_18">
<property name="text">
<string>Voxel size. If &gt; 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.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="general_doubleSpinBox_laserScanVoxelSize">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_rehearsal2">
<property name="title">
@@ -10114,6 +10176,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="spinBox_odom_f2m_scanMaxSize">
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_194">
<property name="text">
@@ -10140,14 +10209,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="spinBox_odom_f2m_scanMaxSize">
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLabel" name="label_357">
<property name="text">
<string>[Visual] Local bundle adjustment. See Optimizer panel. This will not work if Optical Flow correspondences strategy is selected in Visual Registration panel.</string>
@@ -10160,7 +10222,14 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="0">
<widget class="QSpinBox" name="odom_f2m_bundleMaxFrames">
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_358">
<property name="text">
<string>[Visual] Maximum frames used for bundle adjustment (0=inf or all current frames in the local map).</string>
@@ -10173,7 +10242,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QComboBox" name="odom_f2m_bundleStrategy">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
@@ -10195,10 +10264,32 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QSpinBox" name="odom_f2m_bundleMaxFrames">
<item row="4" column="1">
<widget class="QLabel" name="label_430">
<property name="text">
<string>[Geometry] Max angle (degrees) used to filter points of a new added scan to local map (when Radius above is &gt;0). 0 means any angle.</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="QDoubleSpinBox" name="doubleSpinBox_odom_f2m_scanAngle">
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="maximum">
<number>999999</number>
<double>180.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
@@ -12562,7 +12653,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
<widget class="QWidget" name="page_54">
<layout class="QVBoxLayout" name="verticalLayout_85">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -12702,7 +12802,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
</widget>
<widget class="QWidget" name="page_55">
<layout class="QVBoxLayout" name="verticalLayout_86">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -12860,7 +12969,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -12940,7 +13058,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -13052,7 +13179,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>