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

View File

@@ -282,6 +282,7 @@ private:
int _imagePostDecimation; int _imagePostDecimation;
bool _compressionParallelized; bool _compressionParallelized;
float _laserScanDownsampleStepSize; float _laserScanDownsampleStepSize;
float _laserScanVoxelSize;
int _laserScanNormalK; int _laserScanNormalK;
int _laserScanNormalRadius; int _laserScanNormalRadius;
bool _reextractLoopClosureFeatures; bool _reextractLoopClosureFeatures;

View File

@@ -64,6 +64,7 @@ private:
float scanKeyFrameThr_; float scanKeyFrameThr_;
int scanMaximumMapSize_; int scanMaximumMapSize_;
float scanSubtractRadius_; float scanSubtractRadius_;
float scanSubtractAngle_;
int bundleAdjustment_; int bundleAdjustment_;
int bundleMaxFrames_; int bundleMaxFrames_;

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, 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, 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, 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, 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."); RTABMAP_PARAM(Mem, UseOdomFeatures, bool, false, "Use odometry features.");
// KeypointMemory (Keypoint-based) // 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, 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, 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, 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, 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)."); RTABMAP_PARAM(OdomF2M, BundleAdjustmentMaxFrames, int, 0, "Maximum frames used for bundle adjustment (0=inf or all current frames in the local map).");

View File

@@ -134,6 +134,7 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(TimingMem, Compressing_data, ms); RTABMAP_STATS(TimingMem, Compressing_data, ms);
RTABMAP_STATS(TimingMem, Post_decimation, ms); RTABMAP_STATS(TimingMem, Post_decimation, ms);
RTABMAP_STATS(TimingMem, Scan_downsampling, ms); RTABMAP_STATS(TimingMem, Scan_downsampling, ms);
RTABMAP_STATS(TimingMem, Scan_voxel_filtering, ms);
RTABMAP_STATS(TimingMem, Scan_normals, ms); RTABMAP_STATS(TimingMem, Scan_normals, ms);
RTABMAP_STATS(TimingMem, Occupancy_grid, ms); RTABMAP_STATS(TimingMem, Occupancy_grid, ms);

View File

@@ -263,16 +263,24 @@ pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeFastOrganizedNormals(
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0)); const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
float RTABMAP_EXP computeNormalsComplexity( float RTABMAP_EXP computeNormalsComplexity(
const cv::Mat & scan); const cv::Mat & scan,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
float RTABMAP_EXP computeNormalsComplexity( float RTABMAP_EXP computeNormalsComplexity(
const pcl::PointCloud<pcl::Normal> & normals, const pcl::PointCloud<pcl::Normal> & normals,
bool is2d = false); bool is2d = false,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
float RTABMAP_EXP computeNormalsComplexity( float RTABMAP_EXP computeNormalsComplexity(
const pcl::PointCloud<pcl::PointNormal> & cloud, const pcl::PointCloud<pcl::PointNormal> & cloud,
bool is2d = false); bool is2d = false,
cv::Mat * pcaEigenVectors = 0,
cv::Mat * pcaEigenValues = 0);
float RTABMAP_EXP computeNormalsComplexity( float RTABMAP_EXP computeNormalsComplexity(
const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud, 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( pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP mls(
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,

View File

@@ -88,6 +88,7 @@ Memory::Memory(const ParametersMap & parameters) :
_imagePostDecimation(Parameters::defaultMemImagePostDecimation()), _imagePostDecimation(Parameters::defaultMemImagePostDecimation()),
_compressionParallelized(Parameters::defaultMemCompressionParallelized()), _compressionParallelized(Parameters::defaultMemCompressionParallelized()),
_laserScanDownsampleStepSize(Parameters::defaultMemLaserScanDownsampleStepSize()), _laserScanDownsampleStepSize(Parameters::defaultMemLaserScanDownsampleStepSize()),
_laserScanVoxelSize(Parameters::defaultMemLaserScanVoxelSize()),
_laserScanNormalK(Parameters::defaultMemLaserScanNormalK()), _laserScanNormalK(Parameters::defaultMemLaserScanNormalK()),
_laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()), _laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()),
_reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()), _reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()),
@@ -440,6 +441,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kMemImagePostDecimation(), _imagePostDecimation); Parameters::parse(parameters, Parameters::kMemImagePostDecimation(), _imagePostDecimation);
Parameters::parse(parameters, Parameters::kMemCompressionParallelized(), _compressionParallelized); Parameters::parse(parameters, Parameters::kMemCompressionParallelized(), _compressionParallelized);
Parameters::parse(parameters, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize); Parameters::parse(parameters, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize);
Parameters::parse(parameters, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize);
Parameters::parse(parameters, Parameters::kMemLaserScanNormalK(), _laserScanNormalK); Parameters::parse(parameters, Parameters::kMemLaserScanNormalK(), _laserScanNormalK);
Parameters::parse(parameters, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius); Parameters::parse(parameters, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius);
Parameters::parse(parameters, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures); 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); if(stats) stats->addStatistic(Statistics::kTimingMemScan_downsampling(), t*1000.0f);
UDEBUG("time downsampling scan = %fs", t); 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() && if(!laserScan.empty() &&
(_laserScanNormalK > 0 || _laserScanNormalRadius>0.0f) && (_laserScanNormalK > 0 || _laserScanNormalRadius>0.0f) &&
laserScan.channels() > 1 && laserScan.channels() < 5 && laserScan.channels() > 1 && laserScan.channels() < 5 &&

View File

@@ -65,6 +65,7 @@ OdometryF2M::OdometryF2M(const ParametersMap & parameters) :
scanKeyFrameThr_(Parameters::defaultOdomScanKeyFrameThr()), scanKeyFrameThr_(Parameters::defaultOdomScanKeyFrameThr()),
scanMaximumMapSize_(Parameters::defaultOdomF2MScanMaxSize()), scanMaximumMapSize_(Parameters::defaultOdomF2MScanMaxSize()),
scanSubtractRadius_(Parameters::defaultOdomF2MScanSubtractRadius()), scanSubtractRadius_(Parameters::defaultOdomF2MScanSubtractRadius()),
scanSubtractAngle_(Parameters::defaultOdomF2MScanSubtractAngle()),
bundleAdjustment_(Parameters::defaultOdomF2MBundleAdjustment()), bundleAdjustment_(Parameters::defaultOdomF2MBundleAdjustment()),
bundleMaxFrames_(Parameters::defaultOdomF2MBundleAdjustmentMaxFrames()), bundleMaxFrames_(Parameters::defaultOdomF2MBundleAdjustmentMaxFrames()),
map_(new Signature(-1)), map_(new Signature(-1)),
@@ -80,6 +81,10 @@ OdometryF2M::OdometryF2M(const ParametersMap & parameters) :
Parameters::parse(parameters, Parameters::kOdomScanKeyFrameThr(), scanKeyFrameThr_); Parameters::parse(parameters, Parameters::kOdomScanKeyFrameThr(), scanKeyFrameThr_);
Parameters::parse(parameters, Parameters::kOdomF2MScanMaxSize(), scanMaximumMapSize_); Parameters::parse(parameters, Parameters::kOdomF2MScanMaxSize(), scanMaximumMapSize_);
Parameters::parse(parameters, Parameters::kOdomF2MScanSubtractRadius(), scanSubtractRadius_); 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::kOdomF2MBundleAdjustment(), bundleAdjustment_);
Parameters::parse(parameters, Parameters::kOdomF2MBundleAdjustmentMaxFrames(), bundleMaxFrames_); Parameters::parse(parameters, Parameters::kOdomF2MBundleAdjustmentMaxFrames(), bundleMaxFrames_);
UASSERT(bundleMaxFrames_ >= 0); UASSERT(bundleMaxFrames_ >= 0);
@@ -605,7 +610,7 @@ Transform OdometryF2M::computeTransform(
mapCloudNormals, mapCloudNormals,
pcl::IndicesPtr(new std::vector<int>), pcl::IndicesPtr(new std::vector<int>),
scanSubtractRadius_, scanSubtractRadius_,
0.0f); scanSubtractAngle_);
newPoints = frameCloudNormalsIndices->size(); newPoints = frameCloudNormalsIndices->size();
} }
else else

View File

@@ -433,6 +433,7 @@ Transform RegistrationIcp::computeTransformationImpl(
double variance = 1.0; double variance = 1.0;
bool transformComputed = false; bool transformComputed = false;
bool tooLowComplexityForPlaneToPlane = false; bool tooLowComplexityForPlaneToPlane = false;
cv::Mat complexityVectors;
if( _pointToPlane && if( _pointToPlane &&
_voxelSize == 0.0f && _voxelSize == 0.0f &&
@@ -442,14 +443,16 @@ Transform RegistrationIcp::computeTransformationImpl(
{ {
//special case if we have already normals computed and there is no filtering //special case if we have already normals computed and there is no filtering
double fromComplexity = util3d::computeNormalsComplexity(fromScan); cv::Mat complexityVectorsFrom, complexityVectorsTo;
double toComplexity = util3d::computeNormalsComplexity(toScan); double fromComplexity = util3d::computeNormalsComplexity(fromScan, &complexityVectorsFrom);
double toComplexity = util3d::computeNormalsComplexity(toScan, &complexityVectorsTo);
float complexity = fromComplexity<toComplexity?fromComplexity:toComplexity; float complexity = fromComplexity<toComplexity?fromComplexity:toComplexity;
info.icpStructuralComplexity = complexity; info.icpStructuralComplexity = complexity;
if(complexity < _pointToPlaneMinComplexity) if(complexity < _pointToPlaneMinComplexity)
{ {
tooLowComplexityForPlaneToPlane = true; 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 else
{ {
@@ -610,14 +613,16 @@ Transform RegistrationIcp::computeTransformationImpl(
normalsTo = util3d::computeNormals(toCloudFiltered, _pointToPlaneK, _pointToPlaneRadius, viewpointTo); normalsTo = util3d::computeNormals(toCloudFiltered, _pointToPlaneK, _pointToPlaneRadius, viewpointTo);
} }
double fromComplexity = util3d::computeNormalsComplexity(*normalsFrom, fromScan.channels() == 2 || fromScan.channels() == 5); cv::Mat complexityVectorsFrom, complexityVectorsTo;
double toComplexity = util3d::computeNormalsComplexity(*normalsTo, toScan.channels() == 2 || toScan.channels() == 5); 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; float complexity = fromComplexity<toComplexity?fromComplexity:toComplexity;
info.icpStructuralComplexity = complexity; info.icpStructuralComplexity = complexity;
if(complexity < _pointToPlaneMinComplexity) if(complexity < _pointToPlaneMinComplexity)
{ {
tooLowComplexityForPlaneToPlane = true; 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 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()); 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 // update output scans
if(fromScan.channels() == 2 || fromScan.channels() == 5) if(fromScan.channels() == 2 || fromScan.channels() == 5)
@@ -743,7 +748,7 @@ Transform RegistrationIcp::computeTransformationImpl(
} }
#ifdef RTABMAP_POINTMATCHER #ifdef RTABMAP_POINTMATCHER
if(_libpointmatcher && !_pointToPlane) // don't use libpointmatcher if it is configured for point to plane if(_libpointmatcher)
{ {
// Load point clouds // Load point clouds
DP data = pclToDP(fromCloudFiltered, fromScan.channels() == 2 || fromScan.channels() == 5); DP data = pclToDP(fromCloudFiltered, fromScan.channels() == 2 || fromScan.channels() == 5);
@@ -756,7 +761,30 @@ Transform RegistrationIcp::computeTransformationImpl(
UASSERT(_libpointmatcherICP != 0); UASSERT(_libpointmatcherICP != 0);
PM::ICP & icp = *((PM::ICP*)_libpointmatcherICP); 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.)"); 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!"); UDEBUG("libpointmatcher icp...done!");
icpT = Transform::fromEigen3d(Eigen::Affine3d(Eigen::Matrix4d(eigenMatrixToDim<double>(T.template cast<double>(), 4)))); 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(!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( util3d::computeVarianceAndCorrespondences(
fromCloudRegistered, fromCloudRegistered,
toCloudFiltered, toCloudFiltered,

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>); pcl::PointCloud<pcl::PointXYZ>::Ptr output(new pcl::PointCloud<pcl::PointXYZ>);
output->resize(laserScan.cols); output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull(); bool nullTransform = transform.isNull();
Eigen::Affine3f transform3f = transform.toEigen3f(); Eigen::Affine3f transform3f = transform.toEigen3f();
for(int i=0; i<laserScan.cols; ++i) 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>); pcl::PointCloud<pcl::PointNormal>::Ptr output(new pcl::PointCloud<pcl::PointNormal>);
output->resize(laserScan.cols); output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull(); bool nullTransform = transform.isNull();
for(int i=0; i<laserScan.cols; ++i) 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>); pcl::PointCloud<pcl::PointXYZRGB>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGB>);
output->resize(laserScan.cols); output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull() || transform.isIdentity(); bool nullTransform = transform.isNull() || transform.isIdentity();
Eigen::Affine3f transform3f = transform.toEigen3f(); Eigen::Affine3f transform3f = transform.toEigen3f();
for(int i=0; i<laserScan.cols; ++i) 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>); pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
output->resize(laserScan.cols); output->resize(laserScan.cols);
output->is_dense = true;
bool nullTransform = transform.isNull() || transform.isIdentity(); bool nullTransform = transform.isNull() || transform.isIdentity();
for(int i=0; i<laserScan.cols; ++i) for(int i=0; i<laserScan.cols; ++i)
{ {

View File

@@ -2338,7 +2338,10 @@ pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
return normals; 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)) 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); 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 // 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 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; 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 //Construct a buffer used by the pca analysis
int sz = static_cast<int>(cloud.size()*2); 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); 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 // 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 pca_analysis.eigenvalues.at<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
} }
return 0.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 //Construct a buffer used by the pca analysis
int sz = static_cast<int>(normals.size()*2); 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); 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 // 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 pca_analysis.eigenvalues.at<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
} }
return 0.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 //Construct a buffer used by the pca analysis
int sz = static_cast<int>(cloud.size()*2); 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); 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 // 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 pca_analysis.eigenvalues.at<float>(0, is2d?1:2)*(is2d?2.0f:3.0f);
} }

View File

@@ -659,6 +659,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->spinBox_imagePreDecimation->setObjectName(Parameters::kMemImagePreDecimation().c_str()); _ui->spinBox_imagePreDecimation->setObjectName(Parameters::kMemImagePreDecimation().c_str());
_ui->spinBox_imagePostDecimation->setObjectName(Parameters::kMemImagePostDecimation().c_str()); _ui->spinBox_imagePostDecimation->setObjectName(Parameters::kMemImagePostDecimation().c_str());
_ui->general_spinBox_laserScanDownsample->setObjectName(Parameters::kMemLaserScanDownsampleStepSize().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_spinBox_laserScanNormalK->setObjectName(Parameters::kMemLaserScanNormalK().c_str());
_ui->general_doubleSpinBox_laserScanNormalRadius->setObjectName(Parameters::kMemLaserScanNormalRadius().c_str()); _ui->general_doubleSpinBox_laserScanNormalRadius->setObjectName(Parameters::kMemLaserScanNormalRadius().c_str());
_ui->checkBox_useOdomFeatures->setObjectName(Parameters::kMemUseOdomFeatures().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_maxNewFeatures->setObjectName(Parameters::kOdomF2MMaxNewFeatures().c_str());
_ui->spinBox_odom_f2m_scanMaxSize->setObjectName(Parameters::kOdomF2MScanMaxSize().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_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_bundleStrategy->setObjectName(Parameters::kOdomF2MBundleAdjustment().c_str());
_ui->odom_f2m_bundleMaxFrames->setObjectName(Parameters::kOdomF2MBundleAdjustmentMaxFrames().c_str()); _ui->odom_f2m_bundleMaxFrames->setObjectName(Parameters::kOdomF2MBundleAdjustmentMaxFrames().c_str());

View File

@@ -63,16 +63,25 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-215</y> <y>-629</y>
<width>678</width> <width>678</width>
<height>2736</height> <height>2739</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_16"> <layout class="QVBoxLayout" name="verticalLayout_16">
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> <number>0</number>
</property> </property>
<item> <item>
@@ -86,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>21</number> <number>18</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1"> <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> <string>Directory of images (optional settings)</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_93"> <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> <number>0</number>
</property> </property>
<item> <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"> <layout class="QVBoxLayout" name="verticalLayout_10">
<item> <item>
<layout class="QGridLayout" name="gridLayout_42" columnstretch="0,1"> <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"> <item row="15" column="0">
<widget class="QSpinBox" name="spinBox_imagePostDecimation"> <widget class="QSpinBox" name="spinBox_imagePostDecimation">
<property name="minimum"> <property name="minimum">
@@ -6108,19 +6136,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="8" column="0">
<widget class="QCheckBox" name="general_checkBox_initWMWithAllNodes"> <widget class="QCheckBox" name="general_checkBox_initWMWithAllNodes">
<property name="text"> <property name="text">
@@ -6131,16 +6146,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="2" column="0">
<widget class="QLabel" name="label_retrieved_3"> <widget class="QSpinBox" name="general_spinBox_maxRetrieved">
<property name="text"> <property name="maximum">
<string>Bad signatures are ignored.</string> <number>999</number>
</property> </property>
<property name="wordWrap"> <property name="singleStep">
<bool>true</bool> <number>1</number>
</property> </property>
<property name="textInteractionFlags"> <property name="value">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> <number>2</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -6164,10 +6179,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_retrieved_5"> <widget class="QLabel" name="label_retrieved_3">
<property name="text"> <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>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -6187,6 +6202,19 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="5" column="1">
<widget class="QLabel" name="label_retrieved_11"> <widget class="QLabel" name="label_retrieved_11">
<property name="text"> <property name="text">
@@ -6200,22 +6228,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="11" column="0">
<widget class="QCheckBox" name="general_checkBox_keepDescriptors"> <widget class="QCheckBox" name="general_checkBox_keepDescriptors">
<property name="text"> <property name="text">
@@ -6288,6 +6300,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_transferSortingByWeightId"> <widget class="QCheckBox" name="general_checkBox_transferSortingByWeightId">
<property name="text"> <property name="text">
@@ -6311,16 +6333,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="0" column="1">
<widget class="QLabel" name="label_29"> <widget class="QLabel" name="label_29">
<property name="text"> <property name="text">
@@ -6334,6 +6346,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="1">
<widget class="QLabel" name="label_ratioRecent"> <widget class="QLabel" name="label_ratioRecent">
<property name="text"> <property name="text">
@@ -6360,16 +6382,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="3" column="1">
<widget class="QLabel" name="label_retrieved_7"> <widget class="QLabel" name="label_retrieved_7">
<property name="text"> <property name="text">
@@ -6383,48 +6395,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="13" column="0">
<widget class="QCheckBox" name="general_checkBox_compressionParallelized"> <widget class="QCheckBox" name="general_checkBox_compressionParallelized">
<property name="text"> <property name="text">
@@ -6435,16 +6405,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="1"> <item row="10" column="0">
<widget class="QLabel" name="label_retrieved_14"> <widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
<property name="text"> <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>
<property name="wordWrap"> <property name="checked">
<bool>true</bool> <bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property> </property>
</widget> </widget>
</item> </item>
@@ -6461,16 +6428,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="10" column="1">
<widget class="QLabel" name="label_retrieved_16"> <widget class="QLabel" name="label_retrieved_16">
<property name="text"> <property name="text">
@@ -6484,34 +6441,139 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </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> <item>
<widget class="QGroupBox" name="groupBox_rehearsal2"> <widget class="QGroupBox" name="groupBox_rehearsal2">
<property name="title"> <property name="title">
@@ -10114,6 +10176,13 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="1">
<widget class="QLabel" name="label_194"> <widget class="QLabel" name="label_194">
<property name="text"> <property name="text">
@@ -10140,14 +10209,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="5" column="1">
<widget class="QSpinBox" name="spinBox_odom_f2m_scanMaxSize">
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_357"> <widget class="QLabel" name="label_357">
<property name="text"> <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> <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> </property>
</widget> </widget>
</item> </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"> <widget class="QLabel" name="label_358">
<property name="text"> <property name="text">
<string>[Visual] Maximum frames used for bundle adjustment (0=inf or all current frames in the local map).</string> <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> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="0">
<widget class="QComboBox" name="odom_f2m_bundleStrategy"> <widget class="QComboBox" name="odom_f2m_bundleStrategy">
<property name="sizeAdjustPolicy"> <property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum> <enum>QComboBox::AdjustToContents</enum>
@@ -10195,10 +10264,32 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</item> </item>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="4" column="1">
<widget class="QSpinBox" name="odom_f2m_bundleMaxFrames"> <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"> <property name="maximum">
<number>999999</number> <double>180.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
@@ -12562,7 +12653,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
<widget class="QWidget" name="page_54"> <widget class="QWidget" name="page_54">
<layout class="QVBoxLayout" name="verticalLayout_85"> <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> <number>0</number>
</property> </property>
<item> <item>
@@ -12702,7 +12802,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
</widget> </widget>
<widget class="QWidget" name="page_55"> <widget class="QWidget" name="page_55">
<layout class="QVBoxLayout" name="verticalLayout_86"> <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> <number>0</number>
</property> </property>
<item> <item>
@@ -12860,7 +12969,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> <number>0</number>
</property> </property>
<item> <item>
@@ -12940,7 +13058,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> <number>0</number>
</property> </property>
<item> <item>
@@ -13052,7 +13179,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> <number>0</number>
</property> </property>
<item> <item>