Version 0.11.0: Refactored Visual/ICP transformation estimation approaches, Added Registration classes for convenience, Added Parameters migration approach, 3D laser scans can be used

This commit is contained in:
matlabbe
2015-11-22 18:08:32 -05:00
parent 1e5bcfded8
commit ae9f21acd7
46 changed files with 4934 additions and 4547 deletions

View File

@@ -518,6 +518,23 @@ bool CloudViewer::addCloud(
return false;
}
bool CloudViewer::addCloud(
const std::string & id,
const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const Transform & pose,
const QColor & color)
{
if(!_addedClouds.contains(id))
{
UDEBUG("Adding %s with %d points", id.c_str(), (int)cloud->size());
pcl::PCLPointCloud2Ptr binaryCloud(new pcl::PCLPointCloud2);
pcl::toPCLPointCloud2(*cloud, *binaryCloud);
return addCloud(id, binaryCloud, pose, false, true, color);
}
return false;
}
bool CloudViewer::addCloud(
const std::string & id,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,

View File

@@ -102,6 +102,7 @@ void CreateSimpleCalibrationDialog::saveCalibration()
QString dir = QFileInfo(filePath).absoluteDir().absolutePath();
if(!name.isEmpty())
{
cameraName_ = name;
std::string base = (dir+QDir::separator()+name).toStdString();
std::string leftPath = base+"_left.yaml";
std::string rightPath = base+"_right.yaml";

View File

@@ -60,12 +60,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Features2d.h"
#include "rtabmap/core/Compression.h"
#include "rtabmap/core/Graph.h"
#include "rtabmap/core/RegistrationVis.h"
#include "rtabmap/core/RegistrationIcp.h"
#include "rtabmap/gui/DataRecorder.h"
#include "rtabmap/core/SensorData.h"
#include "ExportDialog.h"
#include "rtabmap/gui/ProgressDialog.h"
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/common/transforms.h>
#include <pcl/common/common.h>
@@ -90,6 +93,10 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
ui_->buttonBox->setVisible(false);
connect(ui_->buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
ui_->comboBox_logger_level->setVisible(parent==0);
ui_->label_logger_level->setVisible(parent==0);
connect(ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(int)), this, SLOT(updateLoggerLevel()));
QString title("RTAB-Map Database Viewer[*]");
this->setWindowTitle(title);
@@ -164,7 +171,9 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
connect(ui_->actionGenerate_g2o_graph_g2o, SIGNAL(triggered()), this, SLOT(generateG2OGraph()));
ui_->actionGenerate_g2o_graph_g2o->setEnabled(graph::G2OOptimizer::available());
connect(ui_->actionView_3D_map, SIGNAL(triggered()), this, SLOT(view3DMap()));
connect(ui_->actionView_3D_laser_scans, SIGNAL(triggered()), this, SLOT(view3DLaserScans()));
connect(ui_->actionGenerate_3D_map_pcd, SIGNAL(triggered()), this, SLOT(generate3DMap()));
connect(ui_->actionExport_3D_laser_scans_ply_pcd, SIGNAL(triggered()), this, SLOT(generate3DLaserScans()));
connect(ui_->actionDetect_more_loop_closures, SIGNAL(triggered()), this, SLOT(detectMoreLoopClosures()));
connect(ui_->actionRefine_all_neighbor_links, SIGNAL(triggered()), this, SLOT(refineAllNeighborLinks()));
connect(ui_->actionRefine_all_loop_closure_links, SIGNAL(triggered()), this, SLOT(refineAllLoopClosureLinks()));
@@ -221,6 +230,7 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
connect(ui_->checkBox_robust, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreCovariance, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(int)), this, SLOT(updateConstraintView()));
connect(ui_->checkBox_ignoreGlobalLoop, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreLocalLoopSpace, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
@@ -260,6 +270,7 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
connect(ui_->graphViewer, SIGNAL(configChanged()), this, SLOT(configModified()));
//connect(ui_->graphicsView_A, SIGNAL(configChanged()), this, SLOT(configModified()));
//connect(ui_->graphicsView_B, SIGNAL(configChanged()), this, SLOT(configModified()));
connect(ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(int)), this, SLOT(configModified()));
// Graph view
connect(ui_->spinBox_iterations, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
@@ -288,11 +299,13 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
connect(ui_->spinBox_icp_decimation, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_icp_maxDepth, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_icp_voxel, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_icp_downsamplingStepSize, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_icp_maxCorrespDistance, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_icp_iteration, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_icp_p2plane, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->spinBox_icp_normalKSearch, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_icp_2d, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_icp_laserScan, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_icp_minCorrespondenceRatio, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
// Visual parameters
connect(ui_->groupBox_visual_recomputeFeatures, SIGNAL(clicked(bool)), this, SLOT(configModified()));
@@ -382,6 +395,8 @@ void DatabaseViewer::readSettings()
}
savedMaximized_ = settings.value("maximized", false).toBool();
ui_->comboBox_logger_level->setCurrentIndex(settings.value("loggerLevel", ui_->comboBox_logger_level->currentIndex()).toInt());
// GraphViewer settings
ui_->graphViewer->loadSettings(settings, "GraphView");
@@ -423,11 +438,13 @@ void DatabaseViewer::readSettings()
ui_->spinBox_icp_decimation->setValue(settings.value("decimation", ui_->spinBox_icp_decimation->value()).toInt());
ui_->doubleSpinBox_icp_maxDepth->setValue(settings.value("maxDepth", ui_->doubleSpinBox_icp_maxDepth->value()).toDouble());
ui_->doubleSpinBox_icp_voxel->setValue(settings.value("voxel", ui_->doubleSpinBox_icp_voxel->value()).toDouble());
ui_->spinBox_icp_downsamplingStepSize->setValue(settings.value("samplingStep", ui_->spinBox_icp_downsamplingStepSize->value()).toInt());
ui_->doubleSpinBox_icp_maxCorrespDistance->setValue(settings.value("maxCorrDist", ui_->doubleSpinBox_icp_maxCorrespDistance->value()).toDouble());
ui_->spinBox_icp_iteration->setValue(settings.value("iterations", ui_->spinBox_icp_iteration->value()).toInt());
ui_->checkBox_icp_p2plane->setChecked(settings.value("point2place", ui_->checkBox_icp_p2plane->isChecked()).toBool());
ui_->spinBox_icp_normalKSearch->setValue(settings.value("normalKSearch", ui_->spinBox_icp_normalKSearch->value()).toInt());
ui_->checkBox_icp_2d->setChecked(settings.value("icp2d", ui_->checkBox_icp_2d->isChecked()).toBool());
ui_->checkBox_icp_laserScan->setChecked(settings.value("icpLaserScan", ui_->checkBox_icp_laserScan->isChecked()).toBool());
ui_->doubleSpinBox_icp_minCorrespondenceRatio->setValue(settings.value("icpMinRatio", ui_->doubleSpinBox_icp_minCorrespondenceRatio->value()).toDouble());
settings.endGroup();
@@ -481,6 +498,8 @@ void DatabaseViewer::writeSettings()
settings.setValue("maximized", this->isMaximized());
savedMaximized_ = this->isMaximized();
settings.setValue("loggerLevel", ui_->comboBox_logger_level->currentIndex());
// save GraphViewer settings
ui_->graphViewer->saveSettings(settings, "GraphView");
@@ -524,11 +543,13 @@ void DatabaseViewer::writeSettings()
settings.setValue("decimation", ui_->spinBox_icp_decimation->value());
settings.setValue("maxDepth", ui_->doubleSpinBox_icp_maxDepth->value());
settings.setValue("voxel", ui_->doubleSpinBox_icp_voxel->value());
settings.setValue("samplingStep", ui_->spinBox_icp_downsamplingStepSize->value());
settings.setValue("maxCorrDist", ui_->doubleSpinBox_icp_maxCorrespDistance->value());
settings.setValue("iterations", ui_->spinBox_icp_iteration->value());
settings.setValue("point2place", ui_->checkBox_icp_p2plane->isChecked());
settings.setValue("normalKSearch", ui_->spinBox_icp_normalKSearch->value());
settings.setValue("icp2d", ui_->checkBox_icp_2d->isChecked());
settings.setValue("icpLaserScan", ui_->checkBox_icp_laserScan->isChecked());
settings.setValue("icpMinRatio", ui_->doubleSpinBox_icp_minCorrespondenceRatio->value());
settings.endGroup();
@@ -1541,6 +1562,112 @@ void DatabaseViewer::view3DMap()
}
}
void DatabaseViewer::view3DLaserScans()
{
if(!ids_.size() || !dbDriver_)
{
QMessageBox::warning(this, tr("Cannot view 3D laser scans"), tr("The database is empty..."));
return;
}
if(graphes_.empty())
{
this->updateGraphView();
if(graphes_.empty() || ui_->horizontalSlider_iterations->maximum() != (int)graphes_.size()-1)
{
QMessageBox::warning(this, tr("Cannot generate a graph"), tr("No graph in database?!"));
return;
}
}
bool ok = false;
int downsamplingStepSize = QInputDialog::getInt(this, tr("Downsampling?"), tr("Downsample step size (1 = no filtering)"), 1, 1, 99999, 1, &ok);
if(ok)
{
std::map<int, Transform> optimizedPoses = uValueAt(graphes_, ui_->horizontalSlider_iterations->value());
if(ui_->groupBox_posefiltering->isChecked())
{
optimizedPoses = graph::radiusPosesFiltering(optimizedPoses,
ui_->doubleSpinBox_posefilteringRadius->value(),
ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
}
if(optimizedPoses.size() > 0)
{
rtabmap::ProgressDialog progressDialog(this);
progressDialog.setMaximumSteps((int)optimizedPoses.size());
progressDialog.show();
// create a window
QDialog * window = new QDialog(this, Qt::Window);
window->setModal(this->isModal());
window->setWindowTitle(tr("3D Laser Scans"));
window->setMinimumWidth(800);
window->setMinimumHeight(600);
rtabmap::CloudViewer * viewer = new rtabmap::CloudViewer(window);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(viewer);
viewer->setCameraLockZ(false);
window->setLayout(layout);
connect(window, SIGNAL(finished(int)), viewer, SLOT(clear()));
window->show();
for(std::map<int, Transform>::const_iterator iter = optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
{
rtabmap::Transform pose = iter->second;
if(!pose.isNull())
{
SensorData data;
dbDriver_->getNodeData(iter->first, data);
cv::Mat scan;
data.uncompressDataConst(0, 0, &scan);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
UASSERT(scan.empty() || scan.type()==CV_32FC2 || scan.type() == CV_32FC3);
if(downsamplingStepSize>1)
{
scan = util3d::downsample(scan, downsamplingStepSize);
}
cloud = util3d::laserScanToPointCloud(scan);
if(cloud->size())
{
QColor color = Qt::red;
int mapId, weight;
Transform odomPose;
std::string label;
double stamp;
if(dbDriver_->getNodeInfo(iter->first, odomPose, mapId, weight, label, stamp))
{
color = (Qt::GlobalColor)(mapId % 12 + 7 );
}
pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals = util3d::computeNormals(cloud, ui_->spinBox_icp_normalKSearch->value());
viewer->addCloud(uFormat("cloud%d", iter->first), cloudNormals, pose, color);
UINFO("Generated %d (%d points)", iter->first, cloud->size());
progressDialog.appendText(QString("Generated %1 (%2 points)").arg(iter->first).arg(cloud->size()));
}
else
{
UINFO("Empty cloud %d", iter->first);
progressDialog.appendText(QString("Empty cloud %1").arg(iter->first));
}
progressDialog.incrementStep();
QApplication::processEvents();
}
}
progressDialog.setValue(progressDialog.maximumSteps());
}
else
{
QMessageBox::critical(this, tr("Error"), tr("No neighbors found for node %1.").arg(ui_->spinBox_optimizationsFrom->value()));
}
}
}
void DatabaseViewer::generate3DMap()
{
if(!ids_.size() || !dbDriver_)
@@ -1559,10 +1686,28 @@ void DatabaseViewer::generate3DMap()
if(ok)
{
int decimation = item.toInt();
double maxDepth = QInputDialog::getDouble(this, tr("Camera depth?"), tr("Maximum depth (m, 0=no max):"), 4.0, 0, 100, 2, &ok);
double maxDepth = QInputDialog::getDouble(this, tr("Camera depth?"), tr("Maximum depth (m, 0=no max):"), 4.0, 0, 100, 2, &ok);
if(ok)
{
QString path = QFileDialog::getExistingDirectory(this, tr("Save directory"), pathDatabase_);
QMessageBox::StandardButton b = QMessageBox::question(
this,
tr("Assembling?"),
tr("Do you want to assemble all the point clouds (creating only one file with a density of 1pt/cm)?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::Yes);
bool assemble = b == QMessageBox::Yes;
QString path;
if(assemble)
{
path = QFileDialog::getSaveFileName(this, tr("Save point cloud"),
pathDatabase_+QDir::separator()+"cloud.ply",
tr("Point Cloud (*.ply *.pcd)"));
}
else
{
path = QFileDialog::getExistingDirectory(this, tr("Save directory"), pathDatabase_);
}
if(!path.isEmpty())
{
std::map<int, Transform> optimizedPoses = uValueAt(graphes_, ui_->horizontalSlider_iterations->value());
@@ -1578,6 +1723,7 @@ void DatabaseViewer::generate3DMap()
progressDialog.setMaximumSteps((int)optimizedPoses.size());
progressDialog.show();
pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
for(std::map<int, Transform>::const_iterator iter = optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
{
const rtabmap::Transform & pose = iter->second;
@@ -1589,27 +1735,66 @@ void DatabaseViewer::generate3DMap()
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
UASSERT(data.imageRaw().empty() || data.imageRaw().type()==CV_8UC3 || data.imageRaw().type() == CV_8UC1);
UASSERT(data.depthOrRightRaw().empty() || data.depthOrRightRaw().type()==CV_8UC1 || data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1);
cloud = util3d::cloudRGBFromSensorData(data, decimation, maxDepth);
std::string name = uFormat("%s/node%d.pcd", path.toStdString().c_str(), iter->first);
if(cloud->size())
cloud = util3d::cloudRGBFromSensorData(data, decimation, maxDepth, assemble?0.01:0);
if(assemble)
{
cloud = rtabmap::util3d::transformPointCloud(cloud, pose);
pcl::io::savePCDFile(name, *cloud);
UINFO("Saved %s (%d points)", name.c_str(), cloud->size());
progressDialog.appendText(QString("Saved %1 (%2 points)").arg(name.c_str()).arg(cloud->size()));
if(cloud->size())
{
cloud = rtabmap::util3d::transformPointCloud(cloud, pose);
if(assembledCloud->size() == 0)
{
*assembledCloud = *cloud;
}
else
{
*assembledCloud += *cloud;
}
}
UINFO("Created cloud %d (%d points)", iter->first, (int)cloud->size());
progressDialog.appendText(QString("Created cloud %1 (%2 points)").arg(iter->first).arg(cloud->size()));
}
else
{
UINFO("Ignored empty cloud %s", name.c_str());
progressDialog.appendText(QString("Ignored empty cloud %1").arg(name.c_str()));
std::string name = uFormat("%s/node%d.pcd", path.toStdString().c_str(), iter->first);
if(cloud->size())
{
cloud = rtabmap::util3d::transformPointCloud(cloud, pose);
pcl::io::savePCDFile(name, *cloud);
UINFO("Saved %s (%d points)", name.c_str(), cloud->size());
progressDialog.appendText(QString("Saved %1 (%2 points)").arg(name.c_str()).arg(cloud->size()));
}
else
{
UINFO("Ignored empty cloud %s", name.c_str());
progressDialog.appendText(QString("Ignored empty cloud %1").arg(name.c_str()));
}
}
progressDialog.incrementStep();
QApplication::processEvents();
}
}
progressDialog.setValue(progressDialog.maximumSteps());
if(assemble && assembledCloud->size())
{
//voxelize by default to 1 cm
progressDialog.appendText(QString("Voxelize assembled cloud (%1 points)").arg(assembledCloud->size()));
QApplication::processEvents();
assembledCloud = util3d::voxelize(assembledCloud, 0.01);
if(QFileInfo(path).suffix() == "ply")
{
pcl::io::savePLYFile(path.toStdString(), *assembledCloud);
}
else
{
pcl::io::savePCDFile(path.toStdString(), *assembledCloud);
}
progressDialog.appendText(QString("Saved %1 (%2 points)").arg(path).arg(assembledCloud->size()));
QApplication::processEvents();
}
QMessageBox::information(this, tr("Finished"), tr("%1 clouds generated to %2.").arg(optimizedPoses.size()).arg(path));
progressDialog.setValue(progressDialog.maximumSteps());
}
else
{
@@ -1620,6 +1805,103 @@ void DatabaseViewer::generate3DMap()
}
}
void DatabaseViewer::generate3DLaserScans()
{
if(!ids_.size() || !dbDriver_)
{
QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty..."));
return;
}
bool ok = false;
int downsamplingStepSize = QInputDialog::getInt(this, tr("Downsampling?"), tr("Downsample step size (1 = no filtering)"), 1, 1, 99999, 1, &ok);
if(ok)
{
QString path = QFileDialog::getSaveFileName(this, tr("Save point cloud"),
pathDatabase_+QDir::separator()+"cloud.ply",
tr("Point Cloud (*.ply *.pcd)"));
if(!path.isEmpty())
{
std::map<int, Transform> optimizedPoses = uValueAt(graphes_, ui_->horizontalSlider_iterations->value());
if(ui_->groupBox_posefiltering->isChecked())
{
optimizedPoses = graph::radiusPosesFiltering(optimizedPoses,
ui_->doubleSpinBox_posefilteringRadius->value(),
ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
}
if(optimizedPoses.size() > 0)
{
rtabmap::ProgressDialog progressDialog;
progressDialog.setMaximumSteps((int)optimizedPoses.size());
progressDialog.show();
pcl::PointCloud<pcl::PointXYZ>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
for(std::map<int, Transform>::const_iterator iter = optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
{
const rtabmap::Transform & pose = iter->second;
if(!pose.isNull())
{
SensorData data;
dbDriver_->getNodeData(iter->first, data);
cv::Mat scan;
data.uncompressDataConst(0, 0, &scan);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
UASSERT(scan.empty() || scan.type()==CV_32FC2 || scan.type() == CV_32FC3);
if(downsamplingStepSize > 1)
{
scan = util3d::downsample(scan, downsamplingStepSize);
}
cloud = util3d::laserScanToPointCloud(scan);
if(cloud->size())
{
cloud = rtabmap::util3d::transformPointCloud(cloud, pose);
if(assembledCloud->size() == 0)
{
*assembledCloud = *cloud;
}
else
{
*assembledCloud += *cloud;
}
}
UINFO("Created cloud %d (%d points)", iter->first, (int)cloud->size());
progressDialog.appendText(QString("Created cloud %1 (%2 points)").arg(iter->first).arg(cloud->size()));
progressDialog.incrementStep();
QApplication::processEvents();
}
}
if(assembledCloud->size())
{
//voxelize by default to 1 cm
progressDialog.appendText(QString("Voxelize assembled cloud (%1 points)").arg(assembledCloud->size()));
QApplication::processEvents();
assembledCloud = util3d::voxelize(assembledCloud, 0.01);
if(QFileInfo(path).suffix() == "ply")
{
pcl::io::savePLYFile(path.toStdString(), *assembledCloud);
}
else
{
pcl::io::savePCDFile(path.toStdString(), *assembledCloud);
}
progressDialog.appendText(QString("Saved %1 (%2 points)").arg(path).arg(assembledCloud->size()));
QApplication::processEvents();
}
QMessageBox::information(this, tr("Finished"), tr("%1 clouds generated to %2.").arg(optimizedPoses.size()).arg(path));
progressDialog.setValue(progressDialog.maximumSteps());
}
else
{
QMessageBox::critical(this, tr("Error"), tr("No neighbors found for node %1.").arg(ui_->spinBox_optimizationsFrom->value()));
}
}
}
}
void DatabaseViewer::detectMoreLoopClosures()
{
const std::map<int, Transform> & optimizedPoses = graphes_.back();
@@ -2079,6 +2361,14 @@ void DatabaseViewer::update(int value,
view->setSceneRect(rect);
}
}
void DatabaseViewer::updateLoggerLevel()
{
if(this->parent() == 0)
{
ULogger::setLevel((ULogger::Level)ui_->comboBox_logger_level->currentIndex());
}
}
void DatabaseViewer::updateStereo()
{
@@ -2417,6 +2707,19 @@ void DatabaseViewer::updateConstraintView(
{
link = iterLink->second;
}
else if(ui_->checkBox_ignorePoseCorrection->isChecked())
{
if(link.type() == Link::kNeighbor ||
link.type() == Link::kNeighborMerged)
{
Transform poseFrom = uValue(poses_, link.from(), Transform());
Transform poseTo = uValue(poses_, link.to(), Transform());
if(!poseFrom.isNull() && !poseTo.isNull())
{
link.setTransform(poseFrom.inverse() * poseTo); // recompute raw odom transformation
}
}
}
rtabmap::Transform t = link.transform();
ui_->label_constraint->clear();
@@ -2426,7 +2729,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_type->setText(tr("%1 (%2)")
.arg(link.type())
.arg(link.type()==Link::kNeighbor?"Neigbor":
.arg(link.type()==Link::kNeighbor?"Neighbor":
link.type()==Link::kNeighbor?"Merged neighbor":
link.type()==Link::kGlobalClosure?"Loop closure":
link.type()==Link::kLocalSpaceClosure?"Space proximity link":
@@ -2964,15 +3267,18 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
cv::Mat laserScan;
data.uncompressDataConst(0, 0, &laserScan);
cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(
laserScan,
ground,
obstacles,
ui_->doubleSpinBox_gridCellSize->value(),
ui_->checkBox_gridFillUnkownSpace->isChecked(),
data.laserScanMaxRange());
if(laserScan.type() == CV_32FC2)
{
util3d::occupancy2DFromLaserScan(
laserScan,
ground,
obstacles,
ui_->doubleSpinBox_gridCellSize->value(),
ui_->checkBox_gridFillUnkownSpace->isChecked(),
data.laserScanMaxRange());
added = true;
}
localMaps_.insert(std::make_pair(ids.at(i), std::make_pair(ground, obstacles)));
added = true;
}
}
if(added)
@@ -3345,207 +3651,104 @@ void DatabaseViewer::refineConstraint(int from, int to, bool silent, bool update
}
}
}
else if(ui_->checkBox_ignorePoseCorrection->isChecked() &&
graph::findLink(linksRefined_, from, to) == linksRefined_.end())
{
if(currentLink.type() == Link::kNeighbor ||
currentLink.type() == Link::kNeighborMerged)
{
Transform poseFrom = uValue(poses_, currentLink.from(), Transform());
Transform poseTo = uValue(poses_, currentLink.to(), Transform());
if(!poseFrom.isNull() && !poseTo.isNull())
{
t = poseFrom.inverse() * poseTo; // recompute raw odom transformation
}
}
}
bool hasConverged = false;
double variance = -1.0;
int correspondences = 0;
float variance = -1.0f;
Transform transform;
SensorData dataFrom, dataTo;
dbDriver_->getNodeData(currentLink.from(), dataFrom);
dbDriver_->getNodeData(currentLink.to(), dataTo);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr scanAVoxelized(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr scanBVoxelized(new pcl::PointCloud<pcl::PointXYZ>);
float correspondenceRatio = 0.0f;
if(ui_->checkBox_icp_2d->isChecked())
UTimer timer;
if(!ui_->checkBox_icp_laserScan->isChecked())
{
//2D
cv::Mat oldLaserScan = rtabmap::uncompressData(dataFrom.laserScanCompressed());
cv::Mat newLaserScan = rtabmap::uncompressData(dataTo.laserScanCompressed());
if(!oldLaserScan.empty() && !newLaserScan.empty())
{
// 2D
pcl::PointCloud<pcl::PointXYZ>::Ptr scanA(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr scanB(new pcl::PointCloud<pcl::PointXYZ>);
scanA = util3d::cvMat2Cloud(oldLaserScan);
scanB = util3d::cvMat2Cloud(newLaserScan, t);
//voxelize
if(ui_->doubleSpinBox_icp_voxel->value() > 0.0f)
{
scanA = util3d::voxelize(scanA, ui_->doubleSpinBox_icp_voxel->value());
scanB = util3d::voxelize(scanB, ui_->doubleSpinBox_icp_voxel->value());
}
else
{
scanAVoxelized = scanA;
scanBVoxelized = scanB;
}
if(scanB->size() && scanA->size())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr scanBRegistered(new pcl::PointCloud<pcl::PointXYZ>);
transform = util3d::icp2D(
scanB,
scanA,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
ui_->spinBox_icp_iteration->value(),
hasConverged,
*scanBRegistered);
if(!transform.isNull())
{
if(dataTo.laserScanMaxPts())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr scanBTransformed = scanBRegistered;
if(ui_->doubleSpinBox_icp_voxel->value() > 0.0f)
{
scanBTransformed = util3d::transformPointCloud(scanB, transform);
}
util3d::computeVarianceAndCorrespondences(
scanBTransformed,
scanA,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
variance,
correspondences);
correspondenceRatio = float(correspondences)/float(dataTo.laserScanMaxPts());
}
else if(ui_->doubleSpinBox_icp_minCorrespondenceRatio->value())
{
UWARN("Laser scan max pts not set, but correspondence ratio is set!");
}
}
}
}
// generate laser scans from depth image
cv::Mat tmpA, tmpB, tmpC, tmpD;
dataFrom.uncompressData(&tmpA, &tmpB, 0);
dataTo.uncompressData(&tmpC, &tmpD, 0);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom = util3d::cloudFromSensorData(
dataFrom,
ui_->spinBox_icp_decimation->value(),
ui_->doubleSpinBox_icp_maxDepth->value());
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo = util3d::cloudFromSensorData(
dataTo,
ui_->spinBox_icp_decimation->value(),
ui_->doubleSpinBox_icp_maxDepth->value());
int maxLaserScans = cloudFrom->size();
dataFrom.setLaserScanRaw(util3d::laserScanFromPointCloud(*util3d::removeNaNFromPointCloud(cloudFrom), Transform()), maxLaserScans, 0);
dataTo.setLaserScanRaw(util3d::laserScanFromPointCloud(*util3d::removeNaNFromPointCloud(cloudTo), Transform()), maxLaserScans, 0);
}
else
{
//3D
cv::Mat im,de;
dataFrom.uncompressData(&im, &de, 0);
dataTo.uncompressData(&im, &de, 0);
cloudA = util3d::cloudFromSensorData(dataFrom,
ui_->spinBox_icp_decimation->value(),
ui_->doubleSpinBox_icp_maxDepth->value(),
ui_->doubleSpinBox_icp_voxel->value());
cloudB = util3d::cloudFromSensorData(dataTo,
ui_->spinBox_icp_decimation->value(),
ui_->doubleSpinBox_icp_maxDepth->value(),
ui_->doubleSpinBox_icp_voxel->value());
if(cloudA->size() && cloudB->size())
{
cloudB = util3d::transformPointCloud(cloudB, t);
if(ui_->checkBox_icp_p2plane->isChecked())
{
pcl::PointCloud<pcl::PointNormal>::Ptr cloudANormals = util3d::computeNormals(cloudA, ui_->spinBox_icp_normalKSearch->value());
pcl::PointCloud<pcl::PointNormal>::Ptr cloudBNormals = util3d::computeNormals(cloudB, ui_->spinBox_icp_normalKSearch->value());
cloudANormals = util3d::removeNaNNormalsFromPointCloud(cloudANormals);
if(cloudA->size() != cloudANormals->size())
{
UWARN("removed nan normals...");
}
cloudBNormals = util3d::removeNaNNormalsFromPointCloud(cloudBNormals);
if(cloudB->size() != cloudBNormals->size())
{
UWARN("removed nan normals...");
}
pcl::PointCloud<pcl::PointNormal>::Ptr cloudBRegistered(new pcl::PointCloud<pcl::PointNormal>);
transform = util3d::icpPointToPlane(
cloudBNormals,
cloudANormals,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
ui_->spinBox_icp_iteration->value(),
hasConverged,
*cloudBRegistered);
util3d::computeVarianceAndCorrespondences(
cloudBRegistered,
cloudANormals,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
variance,
correspondences);
}
else
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudBRegistered(new pcl::PointCloud<pcl::PointXYZ>);
transform = util3d::icp(cloudB,
cloudA,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
ui_->spinBox_icp_iteration->value(),
hasConverged,
*cloudBRegistered);
util3d::computeVarianceAndCorrespondences(
cloudBRegistered,
cloudA,
ui_->doubleSpinBox_icp_maxCorrespDistance->value(),
variance,
correspondences);
}
correspondenceRatio = float(correspondences)/float(cloudA->size()>cloudB->size()?cloudA->size():cloudB->size());
}
else
{
UWARN("No cloud generated!");
}
cv::Mat tmpA, tmpB;
dataFrom.uncompressData(0, 0, &tmpA);
dataTo.uncompressData(0, 0, &tmpB);
}
UINFO("Uncompress time: %f s", timer.ticks());
if(hasConverged && !transform.isNull())
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kIcpDownsamplingStep(), uNumber2Str(ui_->spinBox_icp_downsamplingStepSize->value())));
parameters.insert(ParametersPair(Parameters::kIcpVoxelSize(), uNumber2Str(ui_->doubleSpinBox_icp_voxel->value())));
parameters.insert(ParametersPair(Parameters::kIcp2D(), uBool2Str(ui_->checkBox_icp_2d->isChecked())));
parameters.insert(ParametersPair(Parameters::kIcpPointToPlane(), uBool2Str(ui_->checkBox_icp_p2plane->isChecked())));
parameters.insert(ParametersPair(Parameters::kIcpPointToPlaneNormalNeighbors(), uNumber2Str(ui_->spinBox_icp_normalKSearch->value())));
parameters.insert(ParametersPair(Parameters::kIcpMaxCorrespondenceDistance(), uNumber2Str(ui_->doubleSpinBox_icp_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kIcpIterations(), uNumber2Str(ui_->spinBox_icp_iteration->value())));
parameters.insert(ParametersPair(Parameters::kIcpCorrespondenceRatio(), uNumber2Str(ui_->doubleSpinBox_icp_minCorrespondenceRatio->value())));
RegistrationIcp registration(parameters);
transform = registration.computeTransformation(dataFrom, dataTo, t, 0, 0, &variance);
UINFO("Icp time: %f s", timer.ticks());
if(!transform.isNull())
{
if(correspondenceRatio < ui_->doubleSpinBox_icp_minCorrespondenceRatio->value())
Link newLink(currentLink.from(), currentLink.to(), currentLink.type(), transform, variance, variance);
bool updated = false;
std::multimap<int, Link>::iterator iter = linksRefined_.find(currentLink.from());
while(iter != linksRefined_.end() && iter->first == currentLink.from())
{
if(!silent)
if(iter->second.to() == currentLink.to() &&
iter->second.type() == currentLink.type())
{
QMessageBox::warning(this,
tr("Refine link"),
tr("Cannot find a transformation between nodes %1 and %2, correspondence ratio too low (%3).")
.arg(from).arg(to).arg(correspondenceRatio));
iter->second = newLink;
updated = true;
break;
}
++iter;
}
if(!updated)
{
linksRefined_.insert(std::make_pair(newLink.from(), newLink));
if(updateGraph)
{
this->updateGraphView();
}
}
else
if(ui_->dockWidget_constraints->isVisible())
{
Link newLink(currentLink.from(), currentLink.to(), currentLink.type(), transform*t, variance, variance);
bool updated = false;
std::multimap<int, Link>::iterator iter = linksRefined_.find(currentLink.from());
while(iter != linksRefined_.end() && iter->first == currentLink.from())
{
if(iter->second.to() == currentLink.to() &&
iter->second.type() == currentLink.type())
{
iter->second = newLink;
updated = true;
break;
}
++iter;
}
if(!updated)
{
linksRefined_.insert(std::make_pair(newLink.from(), newLink));
if(updateGraph)
{
this->updateGraphView();
}
}
if(ui_->dockWidget_constraints->isVisible())
{
cloudB = util3d::transformPointCloud(cloudB, transform);
scanBVoxelized = util3d::transformPointCloud(scanBVoxelized, transform);
this->updateConstraintView(newLink, true, cloudA, cloudB, scanAVoxelized, scanBVoxelized);
}
this->updateConstraintView(newLink, true);
}
}
else if(!silent)
{
QMessageBox::warning(this,
@@ -3576,30 +3779,31 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, boo
return;
}
// create a fake memory to compute transform
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kVisInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value())));
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value())));
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowForce2D(), uBool2Str(ui_->checkBox_visual_2d->isChecked())));
parameters.insert(ParametersPair(Parameters::kLccBowVarianceFromInliersCount(), uBool2Str(ui_->checkBox_visual_var_inliers->isChecked())));
parameters.insert(ParametersPair(Parameters::kVisIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kVisMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kVisEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kVisPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kVisForce2D(), uBool2Str(ui_->checkBox_visual_2d->isChecked())));
parameters.insert(ParametersPair(Parameters::kRegVarianceFromInliersCount(), uBool2Str(ui_->checkBox_visual_var_inliers->isChecked())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
Transform t;
std::string rejectedMsg;
double variance = -1.0;
float variance = -1.0f;
int inliers = -1;
if(ui_->groupBox_visual_recomputeFeatures->isChecked())
{
// create a fake memory to compute transform
Memory tmpMemory(parameters);
// Add sensor data to generate features
SensorData dataFrom;
dbDriver_->getNodeData(from, dataFrom);
@@ -3620,7 +3824,7 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, boo
}
t = tmpMemory.computeVisualTransform(to, from, &rejectedMsg, &inliers, &variance);
t = tmpMemory.computeVisualTransform(from, to, &rejectedMsg, &inliers, &variance);
}
else
{
@@ -3632,7 +3836,8 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, boo
if(signatures.size() == 2)
{
t = tmpMemory.computeVisualTransform(*signatures.front(), *signatures.back(), &rejectedMsg, &inliers, &variance);
RegistrationVis registration(parameters);
t = registration.computeTransformation(*signatures.back(), *signatures.front(), Transform(), &rejectedMsg, &inliers, &variance);
}
//cleanup
for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
@@ -3702,30 +3907,31 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
UASSERT(!containsLink(linksRemoved_, from, to));
UASSERT(!containsLink(linksRefined_, from, to));
// create a fake memory to compute the transform
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kVisInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value())));
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value())));
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowForce2D(), uBool2Str(ui_->checkBox_visual_2d->isChecked())));
parameters.insert(ParametersPair(Parameters::kLccBowVarianceFromInliersCount(), uBool2Str(ui_->checkBox_visual_var_inliers->isChecked())));
parameters.insert(ParametersPair(Parameters::kVisIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kVisMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kVisEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kVisPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kVisForce2D(), uBool2Str(ui_->checkBox_visual_2d->isChecked())));
parameters.insert(ParametersPair(Parameters::kRegVarianceFromInliersCount(), uBool2Str(ui_->checkBox_visual_var_inliers->isChecked())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
Transform t;
std::string rejectedMsg;
double variance = -1.0;
float variance = -1.0f;
int inliers = -1;
if(ui_->groupBox_visual_recomputeFeatures->isChecked())
{
// create a fake memory to compute the transform
Memory tmpMemory(parameters);
// Add sensor data to generate features
SensorData dataFrom;
dbDriver_->getNodeData(from, dataFrom);
@@ -3746,7 +3952,7 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
}
t = tmpMemory.computeVisualTransform(to, from, &rejectedMsg, &inliers, &variance);
t = tmpMemory.computeVisualTransform(from, to, &rejectedMsg, &inliers, &variance);
if(!silent)
{
@@ -3765,7 +3971,9 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
if(signatures.size() == 2)
{
t = tmpMemory.computeVisualTransform(*signatures.front(), *signatures.back(), &rejectedMsg, &inliers, &variance);
RegistrationVis registration(parameters);
t = registration.computeTransformation(*signatures.back(), *signatures.front(), Transform(), &rejectedMsg, &inliers, &variance);
}
//cleanup
for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)

View File

@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Signature.h"
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/RegistrationVis.h"
#include "rtabmap/gui/ImageView.h"
#include "rtabmap/gui/KeypointItem.h"
@@ -94,6 +95,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/util3d_surface.h"
#include "rtabmap/core/util3d_registration.h"
#include "rtabmap/core/Graph.h"
#include "rtabmap/core/RegistrationIcp.h"
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/transforms.h>
#include <pcl/common/common.h>
@@ -481,9 +483,8 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
// update loop closure viewer parameters
ParametersMap parameters = _preferencesDialog->getAllParameters();
_ui->widget_loopClosureViewer->setDecimation(atoi(parameters.at(Parameters::kLccIcp3Decimation()).c_str()));
_ui->widget_loopClosureViewer->setMaxDepth(uStr2Float(parameters.at(Parameters::kLccIcp3MaxDepth())));
_ui->widget_loopClosureViewer->setSamples(atoi(parameters.at(Parameters::kLccIcp3Samples()).c_str()));
_ui->widget_loopClosureViewer->setDecimation(_preferencesDialog->getCloudDecimation(0));
_ui->widget_loopClosureViewer->setMaxDepth(_preferencesDialog->getCloudMaxDepth(0));
//update ui
_ui->doubleSpinBox_stats_detectionRate->setValue(_preferencesDialog->getDetectionRate());
@@ -810,21 +811,22 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom)
_preferencesDialog->isScansShown(1))
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cloud = util3d::laserScanToPointCloud(odom.data().laserScanRaw());
cloud = util3d::transformPointCloud(cloud, pose);
cloud = util3d::laserScanToPointCloud(odom.data().laserScanRaw(), pose);
if(_preferencesDialog->getDownsamplingStepScan(1) > 0)
{
cloud = util3d::downsample(cloud, _preferencesDialog->getDownsamplingStepScan(1));
}
if(_preferencesDialog->getCloudVoxelSizeScan(1) > 0.0)
{
cloud = util3d::voxelize(cloud, _preferencesDialog->getCloudVoxelSizeScan(1));
}
if(!_ui->widget_cloudViewer->addOrUpdateCloud("scanOdom", cloud, _odometryCorrection))
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cloud = util3d::laserScanToPointCloud(odom.data().laserScanRaw());
cloud = util3d::transformPointCloud(cloud, pose);
if(!_ui->widget_cloudViewer->addOrUpdateCloud("scanOdom", cloud, _odometryCorrection))
{
UERROR("Adding scanOdom to viewer failed!");
}
_ui->widget_cloudViewer->setCloudVisibility("scanOdom", true);
_ui->widget_cloudViewer->setCloudOpacity("scanOdom", _preferencesDialog->getScanOpacity(1));
_ui->widget_cloudViewer->setCloudPointSize("scanOdom", _preferencesDialog->getScanPointSize(1));
UERROR("Adding scanOdom to viewer failed!");
}
_ui->widget_cloudViewer->setCloudVisibility("scanOdom", true);
_ui->widget_cloudViewer->setCloudOpacity("scanOdom", _preferencesDialog->getScanOpacity(1));
_ui->widget_cloudViewer->setCloudPointSize("scanOdom", _preferencesDialog->getScanPointSize(1));
}
}
}
@@ -1929,6 +1931,14 @@ void MainWindow::createAndAddScanToMap(int nodeId, const Transform & pose, int m
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cloud = util3d::laserScanToPointCloud(depth2D);
if(_preferencesDialog->getDownsamplingStepScan(0) > 0)
{
cloud = util3d::downsample(cloud, _preferencesDialog->getDownsamplingStepScan(0));
}
if(_preferencesDialog->getCloudVoxelSizeScan(0) > 0.0)
{
cloud = util3d::voxelize(cloud, _preferencesDialog->getCloudVoxelSizeScan(0));
}
QColor color = Qt::gray;
if(mapId >= 0)
{
@@ -1942,9 +1952,12 @@ void MainWindow::createAndAddScanToMap(int nodeId, const Transform & pose, int m
{
_createdScans.insert(std::make_pair(nodeId, cloud));
cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(depth2D, ground, obstacles, _preferencesDialog->getGridMapResolution());
_gridLocalMaps.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
if(depth2D.channels() == 2)
{
cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(depth2D, ground, obstacles, _preferencesDialog->getGridMapResolution());
_gridLocalMaps.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
}
}
_ui->widget_cloudViewer->setCloudOpacity(scanName, _preferencesDialog->getScanOpacity(0));
_ui->widget_cloudViewer->setCloudPointSize(scanName, _preferencesDialog->getScanPointSize(0));
@@ -2376,19 +2389,9 @@ void MainWindow::applyPrefSettings(const rtabmap::ParametersMap & parameters, bo
_ui->widget_cloudViewer->setWorkingDirectory(_preferencesDialog->getWorkingDirectory());
}
// update loop closure viewer parameters
if(uContains(parameters, Parameters::kLccIcp3Decimation()))
{
_ui->widget_loopClosureViewer->setDecimation(atoi(parameters.at(Parameters::kLccIcp3Decimation()).c_str()));
}
if(uContains(parameters, Parameters::kLccIcp3MaxDepth()))
{
_ui->widget_loopClosureViewer->setMaxDepth(uStr2Float(parameters.at(Parameters::kLccIcp3MaxDepth())));
}
if(uContains(parameters, Parameters::kLccIcp3Samples()))
{
_ui->widget_loopClosureViewer->setSamples(atoi(parameters.at(Parameters::kLccIcp3Samples()).c_str()));
}
// update loop closure viewer parameters (Use Map parameters)
_ui->widget_loopClosureViewer->setDecimation(_preferencesDialog->getCloudDecimation(0));
_ui->widget_loopClosureViewer->setMaxDepth(_preferencesDialog->getCloudMaxDepth(0));
// update graph view parameters
if(uContains(parameters, Parameters::kRGBDLocalRadius()))
@@ -3370,31 +3373,6 @@ void MainWindow::postProcessing()
{
odomPoses.insert(*iter); // fill raw poses
}
/*
if(jter->sensorData().cameraModels().size() == 0 && !jter->sensorData().stereoCameraModel().isValid())
{
UWARN("Calibration of %d is null.", iter->first);
allDataAvailable = false;
}
if(refineNeighborLinks || refineLoopClosureLinks || reextractFeatures)
{
// depth data required
if(jter->sensorData().depthOrRightCompressed().empty())
{
UWARN("Depth data of %d missing.", iter->first);
allDataAvailable = false;
}
if(reextractFeatures)
{
// rgb required
if(jter->sensorData().imageCompressed().empty())
{
UWARN("Rgb of %d missing.", iter->first);
allDataAvailable = false;
}
}
}*/
}
else
{
@@ -3442,22 +3420,6 @@ void MainWindow::postProcessing()
if(detectMoreLoopClosures)
{
UDEBUG("");
Memory memory(parameters);
if(reextractFeatures)
{
ParametersMap customParameters;
// override some parameters
customParameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0")); // desactivate rehearsal
customParameters.insert(ParametersPair(Parameters::kMemBinDataKept(), "false"));
customParameters.insert(ParametersPair(Parameters::kMemSTMSize(), "0"));
customParameters.insert(ParametersPair(Parameters::kKpNewWordsComparedTogether(), "false"));
customParameters.insert(ParametersPair(Parameters::kKpNNStrategy(), parameters.at(Parameters::kLccReextractNNType())));
customParameters.insert(ParametersPair(Parameters::kKpNndrRatio(), parameters.at(Parameters::kLccReextractNNDR())));
customParameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kLccReextractFeatureType())));
customParameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), parameters.at(Parameters::kLccReextractMaxWords())));
customParameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
memory.parseParameters(customParameters);
}
UASSERT(detectLoopClosureIterations>0);
for(int n=0; n<detectLoopClosureIterations; ++n)
@@ -3502,52 +3464,24 @@ void MainWindow::postProcessing()
_initProgressDialog->incrementStep();
QApplication::processEvents();
Signature & signatureFrom = _cachedSignatures[from];
Signature & signatureTo = _cachedSignatures[to];
Signature signatureFrom = _cachedSignatures[from];
Signature signatureTo = _cachedSignatures[to];
if(reextractFeatures)
{
signatureFrom.setWords(std::multimap<int, cv::KeyPoint>());
signatureFrom.setWords3(std::multimap<int, pcl::PointXYZ>());
signatureTo.setWords(std::multimap<int, cv::KeyPoint>());
signatureTo.setWords3(std::multimap<int, pcl::PointXYZ>());
}
Transform transform;
std::string rejectedMsg;
int inliers = -1;
double variance = -1.0;
if(reextractFeatures)
{
memory.init("", true); // clear previously added signatures
float variance = -1.0f;
RegistrationVis registration(parameters);
transform = registration.computeTransformation(signatureFrom, signatureTo, Transform(), &rejectedMsg, &inliers, &variance);
// Add signatures
SensorData dataFrom = signatureFrom.sensorData();
SensorData dataTo = signatureTo.sensorData();
cv::Mat image, depth;
dataFrom.uncompressData(&image, &depth, 0);
dataTo.uncompressData(&image, &depth, 0);
if(dataFrom.isValid() &&
dataTo.isValid() &&
dataFrom.id() != Memory::kIdInvalid &&
signatureFrom.id() != Memory::kIdInvalid)
{
if(from > to)
{
memory.update(dataTo);
memory.update(dataFrom);
}
else
{
memory.update(dataFrom);
memory.update(dataTo);
}
transform = memory.computeVisualTransform(dataTo.id(), dataFrom.id(), &rejectedMsg, &inliers, &variance);
}
else
{
UERROR("not supposed to be here!");
}
}
else
{
transform = memory.computeVisualTransform(signatureTo, signatureFrom, &rejectedMsg, &inliers, &variance);
}
if(!transform.isNull())
{
UINFO("Added new loop closure between %d and %d.", from, to);
@@ -3597,26 +3531,10 @@ void MainWindow::postProcessing()
{
_initProgressDialog->setMaximumSteps(_initProgressDialog->maximumSteps()+loopClosuresAdded);
}
// TODO: support ICP from laser scans?
_initProgressDialog->appendText(tr("Refining links..."));
int decimation=Parameters::defaultLccIcp3Decimation();
float maxDepth=Parameters::defaultLccIcp3MaxDepth();
float voxelSize=Parameters::defaultLccIcp3VoxelSize();
int samples = Parameters::defaultLccIcp3Samples();
float maxCorrespondenceDistance = Parameters::defaultLccIcp3MaxCorrespondenceDistance();
float correspondenceRatio = Parameters::defaultLccIcp3CorrespondenceRatio();
float icpIterations = Parameters::defaultLccIcp3Iterations();
Parameters::parse(parameters, Parameters::kLccIcp3Decimation(), decimation);
Parameters::parse(parameters, Parameters::kLccIcp3MaxDepth(), maxDepth);
Parameters::parse(parameters, Parameters::kLccIcp3VoxelSize(), voxelSize);
Parameters::parse(parameters, Parameters::kLccIcp3Samples(), samples);
Parameters::parse(parameters, Parameters::kLccIcp3CorrespondenceRatio(), correspondenceRatio);
Parameters::parse(parameters, Parameters::kLccIcp3MaxCorrespondenceDistance(), maxCorrespondenceDistance);
Parameters::parse(parameters, Parameters::kLccIcp3Iterations(), icpIterations);
bool pointToPlane = Parameters::defaultLccIcp3PointToPlane();
int pointToPlaneNormalNeighbors = Parameters::defaultLccIcp3PointToPlaneNormalNeighbors();
Parameters::parse(parameters, Parameters::kLccIcp3PointToPlane(), pointToPlane);
Parameters::parse(parameters, Parameters::kLccIcp3PointToPlaneNormalNeighbors(), pointToPlaneNormalNeighbors);
RegistrationIcp regIcp(parameters);
int i=0;
for(std::multimap<int, Link>::iterator iter = _currentLinksMap.begin(); iter!=_currentLinksMap.end(); ++iter, ++i)
@@ -3646,102 +3564,21 @@ void MainWindow::postProcessing()
Signature & signatureFrom = _cachedSignatures[from];
Signature & signatureTo = _cachedSignatures[to];
//3D
UDEBUG("");
cv::Mat depthA, depthB;
if(signatureFrom.sensorData().stereoCameraModel().isValid())
if(!signatureFrom.sensorData().laserScanRaw().empty() &&
!signatureTo.sensorData().laserScanRaw().empty())
{
cv::Mat leftA, leftB;
signatureFrom.sensorData().uncompressData(&leftA, &depthA, 0);
signatureTo.sensorData().uncompressData(&leftB, &depthB, 0);
}
else
{
signatureFrom.sensorData().uncompressData(0, &depthA, 0);
signatureTo.sensorData().uncompressData(0, &depthB, 0);
}
std::string rejectedMsg;
float variance = -1.0f;
Transform transform = regIcp.computeTransformation(signatureFrom, signatureTo, iter->second.transform(), &rejectedMsg, 0, &variance);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA = util3d::cloudFromSensorData(
signatureFrom.sensorData(),
decimation,
maxDepth,
voxelSize,
samples);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB = util3d::cloudFromSensorData(
signatureTo.sensorData(),
decimation,
maxDepth,
voxelSize,
samples);
if(cloudA->size() && cloudB->size())
{
cloudB = util3d::transformPointCloud(cloudB, iter->second.transform());
bool hasConverged = false;
double variance = -1;
int correspondences = 0;
Transform transform;
if(pointToPlane)
{
UDEBUG("");
pcl::PointCloud<pcl::PointNormal>::Ptr cloudANormals = util3d::computeNormals(cloudA, pointToPlaneNormalNeighbors);
pcl::PointCloud<pcl::PointNormal>::Ptr cloudBNormals = util3d::computeNormals(cloudB, pointToPlaneNormalNeighbors);
cloudANormals = util3d::removeNaNNormalsFromPointCloud(cloudANormals);
if(cloudA->size() != cloudANormals->size())
{
UWARN("removed nan normals...");
}
cloudBNormals = util3d::removeNaNNormalsFromPointCloud(cloudBNormals);
if(cloudB->size() != cloudBNormals->size())
{
UWARN("removed nan normals...");
}
pcl::PointCloud<pcl::PointNormal>::Ptr cloudBRegistered(new pcl::PointCloud<pcl::PointNormal>);
transform = util3d::icpPointToPlane(cloudBNormals,
cloudANormals,
maxCorrespondenceDistance,
icpIterations,
hasConverged,
*cloudBRegistered);
util3d::computeVarianceAndCorrespondences(
cloudBRegistered,
cloudANormals,
maxCorrespondenceDistance,
variance,
correspondences);
}
else
{
UDEBUG("");
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudBRegistered(new pcl::PointCloud<pcl::PointXYZ>);
transform = util3d::icp(cloudB,
cloudA,
maxCorrespondenceDistance,
icpIterations,
hasConverged,
*cloudBRegistered);
util3d::computeVarianceAndCorrespondences(
cloudBRegistered,
cloudA,
maxCorrespondenceDistance,
variance,
correspondences);
}
float correspondencesRatio = float(correspondences)/float(cloudB->size()>cloudA->size()?cloudB->size():cloudA->size());
if(!transform.isNull() && hasConverged &&
correspondencesRatio >= correspondenceRatio)
if(!transform.isNull())
{
Link newLink(from, to, iter->second.type(), transform*iter->second.transform(), variance, variance);
iter->second = newLink;
}
else
{
QString str = tr("Cannot refine link %1->%2 (converged=%3 variance=%4 correspondencesRatio=%5 (ref=%6))").arg(from).arg(to).arg(hasConverged?"true":"false").arg(variance).arg(correspondencesRatio).arg(correspondenceRatio);
QString str = tr("Cannot refine link %1->%2 (%3").arg(from).arg(to).arg(rejectedMsg.c_str());
_initProgressDialog->appendText(str, Qt::darkYellow);
UWARN("%s", str.toStdString().c_str());
warn = true;

View File

@@ -129,7 +129,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
// remove BruteForceGPU option
_ui->comboBox_dictionary_strategy->removeItem(4);
_ui->odom_bin_nn->removeItem(4);
_ui->reextract_nn->removeItem(4);
}
@@ -145,12 +144,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_detector_strategy->setItemData(1, 0, Qt::UserRole - 1);
_ui->reextract_type->setItemData(0, 0, Qt::UserRole - 1);
_ui->reextract_type->setItemData(1, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(0, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(1, 0, Qt::UserRole - 1);
_ui->comboBox_dictionary_strategy->setItemData(1, 0, Qt::UserRole - 1);
_ui->reextract_nn->setItemData(1, 0, Qt::UserRole - 1);
_ui->odom_bin_nn->setItemData(1, 0, Qt::UserRole - 1);
#if CV_MAJOR_VERSION == 3
_ui->comboBox_detector_strategy->setItemData(0, 0, Qt::UserRole - 1);
@@ -165,12 +161,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->reextract_type->setItemData(4, 0, Qt::UserRole - 1);
_ui->reextract_type->setItemData(5, 0, Qt::UserRole - 1);
_ui->reextract_type->setItemData(6, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(0, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(1, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(3, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(4, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(5, 0, Qt::UserRole - 1);
_ui->odom_type->setItemData(6, 0, Qt::UserRole - 1);
#endif
}
if(!graph::G2OOptimizer::available())
@@ -279,6 +269,14 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_3dRenderingShowScans[0] = _ui->checkBox_showScans;
_3dRenderingShowScans[1] = _ui->checkBox_showOdomScans;
_3dRenderingDownsamplingScan.resize(2);
_3dRenderingDownsamplingScan[0] = _ui->spinBox_downsamplingScan;
_3dRenderingDownsamplingScan[1] = _ui->spinBox_downsamplingScan_odom;
_3dRenderingVoxelSizeScan.resize(2);
_3dRenderingVoxelSizeScan[0] = _ui->doubleSpinBox_voxelSizeScan;
_3dRenderingVoxelSizeScan[1] = _ui->doubleSpinBox_voxelSizeScan_odom;
_3dRenderingOpacityScan.resize(2);
_3dRenderingOpacityScan[0] = _ui->doubleSpinBox_opacity_scan;
_3dRenderingOpacityScan[1] = _ui->doubleSpinBox_opacity_odom_scan;
@@ -295,6 +293,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_3dRenderingMaxDepth[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingShowScans[i], SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingDownsamplingScan[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingVoxelSizeScan[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingOpacity[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingPtSize[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_3dRenderingOpacityScan[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel()));
@@ -333,7 +333,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
//Source panel
connect(_ui->general_doubleSpinBox_imgRate, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->source_mirroring, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_calibrationName, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->toolButton_source_path_calibration, SIGNAL(clicked()), this, SLOT(selectCalibrationPath()));
connect(_ui->lineEdit_calibrationFile, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
_ui->stackedWidget_src->setCurrentIndex(_ui->comboBox_sourceType->currentIndex());
connect(_ui->comboBox_sourceType, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_src, SLOT(setCurrentIndex(int)));
connect(_ui->comboBox_sourceType, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
@@ -398,8 +399,12 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->lineEdit_cameraStereoImages_timestamps, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->toolButton_cameraStereoImages_path_left, SIGNAL(clicked()), this, SLOT(selectSourceStereoImagesPathLeft()));
connect(_ui->toolButton_cameraStereoImages_path_right, SIGNAL(clicked()), this, SLOT(selectSourceStereoImagesPathRight()));
connect(_ui->toolButton_cameraStereoImages_path_scans, SIGNAL(clicked()), this, SLOT(selectSourceStereoImagesPathScans()));
connect(_ui->lineEdit_cameraStereoImages_path_left, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_cameraStereoImages_path_right, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_cameraStereoImages_path_scans, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_cameraStereoImages_laser_transform, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_cameraStereoImages_max_scan_pts, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_stereoImages_timestamps, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_stereoImages_rectify, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
@@ -476,7 +481,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->checkBox_localSpaceLinksKeptInWM->setObjectName(Parameters::kMemLocalSpaceLinksKeptInWM().c_str());
_ui->checkBox_localSpaceScanMatchingIDsSaved->setObjectName(Parameters::kRGBDScanMatchingIdsSavedInLinks().c_str());
_ui->spinBox_imageDecimation->setObjectName(Parameters::kMemImageDecimation().c_str());
_ui->general_doubleSpinBox_laserScanVoxel->setObjectName(Parameters::kMemLaserScanVoxelSize().c_str());
_ui->general_spinBox_laserScanDownsample->setObjectName(Parameters::kMemLaserScanDownsampleStepSize().c_str());
// Database
@@ -503,6 +508,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str());
_ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str());
_ui->surf_doubleSpinBox_maxDepth->setObjectName(Parameters::kKpMaxDepth().c_str());
_ui->surf_doubleSpinBox_minDepth->setObjectName(Parameters::kKpMinDepth().c_str());
_ui->surf_spinBox_wordsPerImageTarget->setObjectName(Parameters::kKpWordsPerImage().c_str());
_ui->surf_doubleSpinBox_ratioBadSign->setObjectName(Parameters::kKpBadSignRatio().c_str());
_ui->checkBox_kp_tfIdfLikelihoodUsed->setObjectName(Parameters::kKpTfIdfLikelihoodUsed().c_str());
@@ -511,6 +517,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->lineEdit_dictionaryPath->setObjectName(Parameters::kKpDictionaryPath().c_str());
connect(_ui->toolButton_dictionaryPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath()));
_ui->checkBox_kp_newWordsComparedTogether->setObjectName(Parameters::kKpNewWordsComparedTogether().c_str());
_ui->subpix_winSize_kp->setObjectName(Parameters::kKpSubPixWinSize().c_str());
_ui->subpix_iterations_kp->setObjectName(Parameters::kKpSubPixIterations().c_str());
_ui->subpix_eps_kp->setObjectName(Parameters::kKpSubPixEps().c_str());
_ui->subpix_winSize->setObjectName(Parameters::kKpSubPixWinSize().c_str());
_ui->subpix_iterations->setObjectName(Parameters::kKpSubPixIterations().c_str());
@@ -581,7 +590,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->rgdb_angularUpdate->setObjectName(Parameters::kRGBDAngularUpdate().c_str());
_ui->rgdb_rehearsalWeightIgnoredWhileMoving->setObjectName(Parameters::kMemRehearsalWeightIgnoredWhileMoving().c_str());
_ui->rgdb_newMapOdomChange->setObjectName(Parameters::kRGBDNewMapOdomChangeDistance().c_str());
_ui->odomScanHistory->setObjectName(Parameters::kRGBDPoseScanMatching().c_str());
_ui->odomScanHistory->setObjectName(Parameters::kRGBDIcpOdomRefining().c_str());
_ui->spinBox_maxLocalLocationsRetrieved->setObjectName(Parameters::kRGBDMaxLocalRetrieved().c_str());
_ui->graphOptimization_type->setObjectName(Parameters::kRGBDOptimizeStrategy().c_str());
@@ -605,76 +614,57 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->localDetection_maxDiffID->setObjectName(Parameters::kRGBDLocalLoopDetectionMaxGraphDepth().c_str());
_ui->localDetection_pathFilteringRadius->setObjectName(Parameters::kRGBDLocalLoopDetectionPathFilteringRadius().c_str());
_ui->checkBox_localSpacePathOdomPosesUsed->setObjectName(Parameters::kRGBDLocalLoopDetectionPathOdomPosesUsed().c_str());
_ui->checkBox_localSpaceAssembleScans->setObjectName(Parameters::kRGBDLocalLoopDetectionPathScansMerged().c_str());
_ui->rgdb_localImmunizationRatio->setObjectName(Parameters::kRGBDLocalImmunizationRatio().c_str());
_ui->loopClosure_bowMinInliers->setObjectName(Parameters::kLccBowMinInliers().c_str());
_ui->loopClosure_bowInlierDistance->setObjectName(Parameters::kLccBowInlierDistance().c_str());
_ui->loopClosure_bowIterations->setObjectName(Parameters::kLccBowIterations().c_str());
_ui->loopClosure_bowRefineIterations->setObjectName(Parameters::kLccBowRefineIterations().c_str());
_ui->loopClosure_bowForce2D->setObjectName(Parameters::kLccBowForce2D().c_str());
_ui->loopClosure_estimationType->setObjectName(Parameters::kLccBowEstimationType().c_str());
_ui->loopClosure_bowMinInliers->setObjectName(Parameters::kVisMinInliers().c_str());
_ui->loopClosure_bowInlierDistance->setObjectName(Parameters::kVisInlierDistance().c_str());
_ui->loopClosure_bowIterations->setObjectName(Parameters::kVisIterations().c_str());
_ui->loopClosure_bowRefineIterations->setObjectName(Parameters::kVisRefineIterations().c_str());
_ui->loopClosure_bowForce2D->setObjectName(Parameters::kVisForce2D().c_str());
_ui->loopClosure_estimationType->setObjectName(Parameters::kVisEstimationType().c_str());
connect(_ui->loopClosure_estimationType, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_loopClosureEstimation, SLOT(setCurrentIndex(int)));
_ui->stackedWidget_loopClosureEstimation->setCurrentIndex(Parameters::defaultLccBowEstimationType());
_ui->loopClosure_bowEpipolarGeometryVar->setObjectName(Parameters::kLccBowEpipolarGeometryVar().c_str());
_ui->loopClosure_pnpReprojError->setObjectName(Parameters::kLccBowPnPReprojError().c_str());
_ui->loopClosure_pnpFlags->setObjectName(Parameters::kLccBowPnPFlags().c_str());
_ui->loopClosure_bowVarianceFromInliersCount->setObjectName(Parameters::kLccBowVarianceFromInliersCount().c_str());
_ui->stackedWidget_loopClosureEstimation->setCurrentIndex(Parameters::defaultVisEstimationType());
_ui->loopClosure_bowEpipolarGeometryVar->setObjectName(Parameters::kVisEpipolarGeometryVar().c_str());
_ui->loopClosure_pnpReprojError->setObjectName(Parameters::kVisPnPReprojError().c_str());
_ui->loopClosure_pnpFlags->setObjectName(Parameters::kVisPnPFlags().c_str());
_ui->loopClosure_bowVarianceFromInliersCount->setObjectName(Parameters::kRegVarianceFromInliersCount().c_str());
_ui->groupBox_reextract->setObjectName(Parameters::kLccReextractActivated().c_str());
_ui->reextract_nn->setObjectName(Parameters::kLccReextractNNType().c_str());
_ui->reextract_nndrRatio->setObjectName(Parameters::kLccReextractNNDR().c_str());
_ui->reextract_type->setObjectName(Parameters::kLccReextractFeatureType().c_str());
_ui->reextract_maxFeatures->setObjectName(Parameters::kLccReextractMaxWords().c_str());
_ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kLccReextractMaxDepth().c_str());
_ui->loopClosure_reextract->setObjectName(Parameters::kRGBDLoopClosureReextractFeatures().c_str());
_ui->reextract_nn->setObjectName(Parameters::kVisNNType().c_str());
_ui->reextract_nndrRatio->setObjectName(Parameters::kVisNNDR().c_str());
_ui->reextract_type->setObjectName(Parameters::kVisFeatureType().c_str());
_ui->reextract_maxFeatures->setObjectName(Parameters::kVisMaxFeatures().c_str());
_ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kVisMaxDepth().c_str());
_ui->loopClosure_bowMinDepth->setObjectName(Parameters::kVisMinDepth().c_str());
_ui->loopClosure_roi->setObjectName(Parameters::kVisRoiRatios().c_str());
_ui->subpix_winSize->setObjectName(Parameters::kVisSubPixWinSize().c_str());
_ui->subpix_iterations->setObjectName(Parameters::kVisSubPixIterations().c_str());
_ui->subpix_eps->setObjectName(Parameters::kVisSubPixEps().c_str());
_ui->globalDetection_icpType->setObjectName(Parameters::kLccIcpType().c_str());
_ui->globalDetection_icpMaxTranslation->setObjectName(Parameters::kLccIcpMaxTranslation().c_str());
_ui->globalDetection_icpMaxRotation->setObjectName(Parameters::kLccIcpMaxRotation().c_str());
_ui->loopClosure_icp->setObjectName(Parameters::kRGBDIcpLoopClosureRefining().c_str());
_ui->globalDetection_icpMaxTranslation->setObjectName(Parameters::kIcpMaxTranslation().c_str());
_ui->globalDetection_icpMaxRotation->setObjectName(Parameters::kIcpMaxRotation().c_str());
_ui->loopClosure_icp2D->setObjectName(Parameters::kIcp2D().c_str());
_ui->loopClosure_icpDecimation->setObjectName(Parameters::kLccIcp3Decimation().c_str());
_ui->loopClosure_icpMaxDepth->setObjectName(Parameters::kLccIcp3MaxDepth().c_str());
_ui->loopClosure_icpVoxelSize->setObjectName(Parameters::kLccIcp3VoxelSize().c_str());
_ui->loopClosure_icpSamples->setObjectName(Parameters::kLccIcp3Samples().c_str());
_ui->loopClosure_icpMaxCorrespondenceDistance->setObjectName(Parameters::kLccIcp3MaxCorrespondenceDistance().c_str());
_ui->loopClosure_icpIterations->setObjectName(Parameters::kLccIcp3Iterations().c_str());
_ui->loopClosure_icpRatio->setObjectName(Parameters::kLccIcp3CorrespondenceRatio().c_str());
_ui->loopClosure_icpPointToPlane->setObjectName(Parameters::kLccIcp3PointToPlane().c_str());
_ui->loopClosure_icpPointToPlaneNormals->setObjectName(Parameters::kLccIcp3PointToPlaneNormalNeighbors().c_str());
_ui->loopClosure_icp2MaxCorrespondenceDistance->setObjectName(Parameters::kLccIcp2MaxCorrespondenceDistance().c_str());
_ui->loopClosure_icp2Iterations->setObjectName(Parameters::kLccIcp2Iterations().c_str());
_ui->loopClosure_icp2Ratio->setObjectName(Parameters::kLccIcp2CorrespondenceRatio().c_str());
_ui->loopClosure_icp2Voxel->setObjectName(Parameters::kLccIcp2VoxelSize().c_str());
_ui->loopClosure_icpVoxelSize->setObjectName(Parameters::kIcpVoxelSize().c_str());
_ui->loopClosure_icpDownsamplingStep->setObjectName(Parameters::kIcpDownsamplingStep().c_str());
_ui->loopClosure_icpMaxCorrespondenceDistance->setObjectName(Parameters::kIcpMaxCorrespondenceDistance().c_str());
_ui->loopClosure_icpIterations->setObjectName(Parameters::kIcpIterations().c_str());
_ui->loopClosure_icpRatio->setObjectName(Parameters::kIcpCorrespondenceRatio().c_str());
_ui->loopClosure_icpPointToPlane->setObjectName(Parameters::kIcpPointToPlane().c_str());
_ui->loopClosure_icpPointToPlaneNormals->setObjectName(Parameters::kIcpPointToPlaneNormalNeighbors().c_str());
//Odometry
_ui->odom_strategy->setObjectName(Parameters::kOdomStrategy().c_str());
_ui->odom_type->setObjectName(Parameters::kOdomFeatureType().c_str());
_ui->odom_countdown->setObjectName(Parameters::kOdomResetCountdown().c_str());
_ui->odom_maxFeatures->setObjectName(Parameters::kOdomMaxFeatures().c_str());
_ui->odom_inlierDistance->setObjectName(Parameters::kOdomInlierDistance().c_str());
_ui->odom_iterations->setObjectName(Parameters::kOdomIterations().c_str());
_ui->odom_maxDepth->setObjectName(Parameters::kOdomMaxDepth().c_str());
_ui->odom_minInliers->setObjectName(Parameters::kOdomMinInliers().c_str());
_ui->odom_refine_iterations->setObjectName(Parameters::kOdomRefineIterations().c_str());
_ui->odom_force2D->setObjectName(Parameters::kOdomForce2D().c_str());
_ui->odom_holonomic->setObjectName(Parameters::kOdomHolonomic().c_str());
_ui->odom_fillInfoData->setObjectName(Parameters::kOdomFillInfoData().c_str());
_ui->odom_dataBufferSize->setObjectName(Parameters::kOdomImageBufferSize().c_str());
_ui->odom_varianceFromInliersCount->setObjectName(Parameters::kOdomVarianceFromInliersCount().c_str());
connect(_ui->odom_varianceFromInliersCount, SIGNAL(clicked(bool)), _ui->loopClosure_bowVarianceFromInliersCount, SLOT(setChecked(bool)));
connect(_ui->loopClosure_bowVarianceFromInliersCount, SIGNAL(clicked(bool)), _ui->odom_varianceFromInliersCount, SLOT(setChecked(bool)));
_ui->lineEdit_odom_roi->setObjectName(Parameters::kOdomRoiRatios().c_str());
_ui->odom_estimationType->setObjectName(Parameters::kOdomEstimationType().c_str());
connect(_ui->odom_estimationType, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_odomEstimation, SLOT(setCurrentIndex(int)));
_ui->stackedWidget_odomEstimation->setCurrentIndex(Parameters::defaultOdomEstimationType());
_ui->odom_pnpReprojError->setObjectName(Parameters::kOdomPnPReprojError().c_str());
_ui->odom_pnpFlags->setObjectName(Parameters::kOdomPnPFlags().c_str());
//Odometry BOW
_ui->odom_localHistory->setObjectName(Parameters::kOdomBowLocalHistorySize().c_str());
_ui->odom_bin_nn->setObjectName(Parameters::kOdomBowNNType().c_str());
_ui->odom_bin_nndrRatio->setObjectName(Parameters::kOdomBowNNDR().c_str());
_ui->odom_fixedLocalMapPath->setObjectName(Parameters::kOdomBowFixedLocalMapPath().c_str());
connect(_ui->toolButton_odomBowFixedLocalMap, SIGNAL(clicked()), this, SLOT(changeOdomBowFixedLocalMapPath()));
@@ -683,9 +673,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->odom_flow_maxLevel->setObjectName(Parameters::kOdomFlowMaxLevel().c_str());
_ui->odom_flow_iterations->setObjectName(Parameters::kOdomFlowIterations().c_str());
_ui->odom_flow_eps->setObjectName(Parameters::kOdomFlowEps().c_str());
_ui->odom_subpix_winSize->setObjectName(Parameters::kOdomSubPixWinSize().c_str());
_ui->odom_subpix_iterations->setObjectName(Parameters::kOdomSubPixIterations().c_str());
_ui->odom_subpix_eps->setObjectName(Parameters::kOdomSubPixEps().c_str());
//Odometry Mono
_ui->doubleSpinBox_minFlow->setObjectName(Parameters::kOdomMonoInitMinFlow().c_str());
@@ -737,6 +724,7 @@ PreferencesDialog::~PreferencesDialog() {
void PreferencesDialog::init()
{
UDEBUG("");
//First set all default values
const ParametersMap & defaults = Parameters::getDefaultParameters();
for(ParametersMap::const_iterator iter=defaults.begin(); iter!=defaults.end(); ++iter)
@@ -1048,6 +1036,8 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_3dRenderingMaxDepth[i]->setValue(0.0);
_3dRenderingShowScans[i]->setChecked(true);
_3dRenderingDownsamplingScan[i]->setValue(0);
_3dRenderingVoxelSizeScan[i]->setValue(0.0);
_3dRenderingOpacity[i]->setValue(i==0?1.0:0.5);
_3dRenderingPtSize[i]->setValue(2);
_3dRenderingOpacityScan[i]->setValue(i==0?1.0:0.5);
@@ -1088,10 +1078,10 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
{
_ui->general_doubleSpinBox_imgRate->setValue(0.0);
_ui->source_mirroring->setChecked(false);
_ui->lineEdit_calibrationName->clear();
_ui->lineEdit_calibrationFile->clear();
_ui->comboBox_sourceType->setCurrentIndex(kSrcRGBD);
_ui->lineEdit_sourceDevice->setText("");
_ui->lineEdit_sourceLocalTransform->setText("0 0 0 -PI_2 0 -PI_2");
_ui->lineEdit_sourceLocalTransform->setText("0 0 1 -1 0 0 0 -1 0");
_ui->source_comboBox_image_type->setCurrentIndex(kSrcUsbDevice-kSrcUsbDevice);
_ui->source_images_spinBox_startPos->setValue(1);
@@ -1160,6 +1150,9 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->lineEdit_cameraStereoImages_timestamps->setText("");
_ui->lineEdit_cameraStereoImages_path_left->setText("");
_ui->lineEdit_cameraStereoImages_path_right->setText("");
_ui->lineEdit_cameraStereoImages_path_scans->setText("");
_ui->lineEdit_cameraStereoImages_laser_transform->setText("0 0 0 0 0 0");
_ui->spinBox_cameraStereoImages_max_scan_pts->setValue(0);
_ui->checkBox_stereoImages_timestamps->setChecked(false);
_ui->checkBox_stereoImages_rectify->setChecked(false);
_ui->lineEdit_cameraStereoVideo_path->setText("");
@@ -1280,7 +1273,7 @@ void PreferencesDialog::loadConfigFrom()
void PreferencesDialog::readSettings(const QString & filePath)
{
ULOGGER_DEBUG("");
ULOGGER_DEBUG("%s", filePath.toStdString().c_str());
readGuiSettings(filePath);
readCameraSettings(filePath);
if(!readCoreSettings(filePath))
@@ -1348,6 +1341,8 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
_3dRenderingMaxDepth[i]->setValue(settings.value(QString("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value()).toDouble());
_3dRenderingShowScans[i]->setChecked(settings.value(QString("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked()).toBool());
_3dRenderingDownsamplingScan[i]->setValue(settings.value(QString("downsamplingScan%1").arg(i), _3dRenderingDownsamplingScan[i]->value()).toInt());
_3dRenderingVoxelSizeScan[i]->setValue(settings.value(QString("voxelSizeScan%1").arg(i), _3dRenderingVoxelSizeScan[i]->value()).toDouble());
_3dRenderingOpacity[i]->setValue(settings.value(QString("opacity%1").arg(i), _3dRenderingOpacity[i]->value()).toDouble());
_3dRenderingPtSize[i]->setValue(settings.value(QString("ptSize%1").arg(i), _3dRenderingPtSize[i]->value()).toInt());
_3dRenderingOpacityScan[i]->setValue(settings.value(QString("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value()).toDouble());
@@ -1392,7 +1387,7 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
settings.beginGroup("Camera");
_ui->general_doubleSpinBox_imgRate->setValue(settings.value("imgRate", _ui->general_doubleSpinBox_imgRate->value()).toDouble());
_ui->source_mirroring->setChecked(settings.value("mirroring", _ui->source_mirroring->isChecked()).toBool());
_ui->lineEdit_calibrationName->setText(settings.value("calibrationName", _ui->lineEdit_calibrationName->text()).toString());
_ui->lineEdit_calibrationFile->setText(settings.value("calibrationName", _ui->lineEdit_calibrationFile->text()).toString());
_ui->comboBox_sourceType->setCurrentIndex(settings.value("type", _ui->comboBox_sourceType->currentIndex()).toInt());
_ui->lineEdit_sourceDevice->setText(settings.value("device",_ui->lineEdit_sourceDevice->text()).toString());
_ui->lineEdit_sourceLocalTransform->setText(settings.value("localTransform",_ui->lineEdit_sourceLocalTransform->text()).toString());
@@ -1446,6 +1441,9 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->lineEdit_cameraStereoImages_timestamps->setText(settings.value("stamps", _ui->lineEdit_cameraStereoImages_timestamps->text()).toString());
_ui->lineEdit_cameraStereoImages_path_left->setText(settings.value("path_left", _ui->lineEdit_cameraStereoImages_path_left->text()).toString());
_ui->lineEdit_cameraStereoImages_path_right->setText(settings.value("path_right", _ui->lineEdit_cameraStereoImages_path_right->text()).toString());
_ui->lineEdit_cameraStereoImages_path_scans->setText(settings.value("path_scans", _ui->lineEdit_cameraStereoImages_path_scans->text()).toString());
_ui->lineEdit_cameraStereoImages_laser_transform->setText(settings.value("scan_transform", _ui->lineEdit_cameraStereoImages_laser_transform->text()).toString());
_ui->spinBox_cameraStereoImages_max_scan_pts->setValue(settings.value("scan_max_pts", _ui->spinBox_cameraStereoImages_max_scan_pts->value()).toInt());
_ui->checkBox_stereoImages_timestamps->setChecked(settings.value("filenames_as_stamps",_ui->checkBox_stereoImages_timestamps->isChecked()).toBool());
_ui->checkBox_stereoImages_rectify->setChecked(settings.value("rectify",_ui->checkBox_stereoImages_rectify->isChecked()).toBool());
settings.endGroup(); // StereoImages
@@ -1484,13 +1482,14 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
bool PreferencesDialog::readCoreSettings(const QString & filePath)
{
UDEBUG("");
QString path = getIniFilePath();
if(!filePath.isEmpty())
{
path = filePath;
}
UDEBUG("%s", path.toStdString().c_str());
if(!QFile::exists(path))
{
QMessageBox::information(this, tr("INI file doesn't exist..."), tr("The configuration file \"%1\" does not exist, it will be created with default parameters.").arg(path));
@@ -1533,8 +1532,23 @@ bool PreferencesDialog::readCoreSettings(const QString & filePath)
const rtabmap::ParametersMap & parameters = Parameters::getDefaultParameters();
for(rtabmap::ParametersMap::const_iterator iter = parameters.begin(); iter!=parameters.end(); ++iter)
{
QString key((*iter).first.c_str());
QString key(iter->first.c_str());
QString value = settings.value(key, "").toString();
if(value.isEmpty())
{
// look for old parameter name
rtabmap::ParametersMap::const_iterator oldIter = Parameters::getBackwardCompatibilityMap().find(iter->first);
if(oldIter!=Parameters::getBackwardCompatibilityMap().end())
{
value = settings.value(QString(oldIter->second.c_str()), "").toString();
if(!value.isEmpty())
{
UWARN("Parameter migration from \"%s\" to \"%s\" (value=%s).",
oldIter->second.c_str(), oldIter->first.c_str(), value.toStdString().c_str());
}
}
}
if(!value.isEmpty())
{
if(key.toStdString().compare(Parameters::kRtabmapWorkingDirectory()) == 0)
@@ -1563,6 +1577,7 @@ bool PreferencesDialog::readCoreSettings(const QString & filePath)
else
{
UDEBUG("key.toStdString()=%s", key.toStdString().c_str());
// Use the default value if the key doesn't exist yet
this->setParameter(key.toStdString(), (*iter).second);
@@ -1668,6 +1683,8 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
settings.setValue(QString("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value());
settings.setValue(QString("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked());
settings.setValue(QString("downsamplingScan%1").arg(i), _3dRenderingDownsamplingScan[i]->value());
settings.setValue(QString("voxelSizeScan%1").arg(i), _3dRenderingVoxelSizeScan[i]->value());
settings.setValue(QString("opacity%1").arg(i), _3dRenderingOpacity[i]->value());
settings.setValue(QString("ptSize%1").arg(i), _3dRenderingPtSize[i]->value());
settings.setValue(QString("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value());
@@ -1711,7 +1728,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.beginGroup("Camera");
settings.setValue("imgRate", _ui->general_doubleSpinBox_imgRate->value());
settings.setValue("mirroring", _ui->source_mirroring->isChecked());
settings.setValue("calibrationName", _ui->lineEdit_calibrationName->text());
settings.setValue("calibrationName", _ui->lineEdit_calibrationFile->text());
settings.setValue("type", _ui->comboBox_sourceType->currentIndex());
settings.setValue("device", _ui->lineEdit_sourceDevice->text());
settings.setValue("localTransform", _ui->lineEdit_sourceLocalTransform->text());
@@ -1765,6 +1782,9 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("stamps", _ui->lineEdit_cameraStereoImages_timestamps->text());
settings.setValue("path_left", _ui->lineEdit_cameraStereoImages_path_left->text());
settings.setValue("path_right", _ui->lineEdit_cameraStereoImages_path_right->text());
settings.setValue("path_scans", _ui->lineEdit_cameraStereoImages_path_scans->text());
settings.setValue("scan_transform", _ui->lineEdit_cameraStereoImages_laser_transform->text());
settings.setValue("scan_max_pts", _ui->spinBox_cameraStereoImages_max_scan_pts->value());
settings.setValue("filenames_as_stamps", _ui->checkBox_stereoImages_timestamps->isChecked());
settings.setValue("rectify", _ui->checkBox_stereoImages_rectify->isChecked());
settings.endGroup(); // StereoImages
@@ -1889,14 +1909,6 @@ bool PreferencesDialog::validateForm()
"of features on loop closure."));
_ui->reextract_type->setCurrentIndex(Feature2D::kFeatureFastBrief);
}
// odom type
if(_ui->odom_type->currentIndex() <= 1)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Selected feature type (SURF/SIFT) is not available. RTAB-Map is not built "
"with the nonfree module from OpenCV. GFTT/Brief is set instead for odometry."));
_ui->odom_type->setCurrentIndex(Feature2D::kFeatureGfttBrief);
}
}
// optimization strategy
@@ -1956,32 +1968,6 @@ bool PreferencesDialog::validateForm()
_ui->reextract_nn->setCurrentIndex(VWDictionary::kNNBruteForce);
}
// odom type
if(_ui->odom_bin_nn->currentIndex() == VWDictionary::kNNFlannLSH && _ui->odom_type->currentIndex() <= 1)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("With the selected feature type (SURF or SIFT), parameter \"Odometry->Nearest Neighbor\" "
"cannot be LSH (used for binary descriptor). KD-tree is set instead for odometry."));
_ui->odom_bin_nn->setCurrentIndex(VWDictionary::kNNFlannKdTree);
}
else if(_ui->odom_bin_nn->currentIndex() == VWDictionary::kNNFlannKdTree && _ui->odom_type->currentIndex() >1)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("With the selected feature type (ORB, FAST, FREAK or BRIEF), parameter \"Odometry->Nearest Neighbor\" "
"cannot be KD-Tree (used for float descriptor). BruteForce matching is set instead for odometry."));
_ui->odom_bin_nn->setCurrentIndex(VWDictionary::kNNBruteForce);
}
if(_ui->loopClosure_bowVarianceFromInliersCount->isChecked() != _ui->odom_varianceFromInliersCount->isChecked())
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Odometry %1 variance from inliers count but Loop Closure constraint %2. "
"Applying the same parameter to Loop Closure Constraint.")
.arg(_ui->odom_varianceFromInliersCount->isChecked()?tr("uses"):tr("does not use"))
.arg(_ui->odom_varianceFromInliersCount->isChecked()?tr("does not"):tr("does")));
_ui->loopClosure_bowVarianceFromInliersCount->setChecked(_ui->odom_varianceFromInliersCount->isChecked());
}
if(_ui->doubleSpinBox_freenect2MinDepth->value() >= _ui->doubleSpinBox_freenect2MaxDepth->value())
{
QMessageBox::warning(this, tr("Parameter warning"),
@@ -1992,6 +1978,28 @@ bool PreferencesDialog::validateForm()
_ui->doubleSpinBox_freenect2MaxDepth->setValue(_ui->doubleSpinBox_freenect2MaxDepth->value()+1);
}
if(_ui->surf_doubleSpinBox_maxDepth->value() > 0.0 &&
_ui->surf_doubleSpinBox_minDepth->value() >= _ui->surf_doubleSpinBox_maxDepth->value())
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Visual word minimum depth (%1 m) should be lower than maximum depth (%2 m). Setting maximum depth to %3 m.")
.arg(_ui->surf_doubleSpinBox_minDepth->value())
.arg(_ui->surf_doubleSpinBox_maxDepth->value())
.arg(_ui->surf_doubleSpinBox_maxDepth->value()+1));
_ui->doubleSpinBox_freenect2MinDepth->setValue(0);
}
if(_ui->loopClosure_bowMaxDepth->value() > 0.0 &&
_ui->loopClosure_bowMinDepth->value() >= _ui->loopClosure_bowMaxDepth->value())
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Visual registration word minimum depth (%1 m) should be lower than maximum depth (%2 m). Setting maximum depth to %3 m.")
.arg(_ui->loopClosure_bowMinDepth->value())
.arg(_ui->loopClosure_bowMaxDepth->value())
.arg(_ui->loopClosure_bowMaxDepth->value()+1));
_ui->loopClosure_bowMinDepth->setValue(0);
}
return true;
}
@@ -2014,7 +2022,7 @@ void PreferencesDialog::showEvent ( QShowEvent * event )
_ui->label_dictionaryPath->setEnabled(false);
_ui->groupBox_source0->setEnabled(false);
_ui->groupBox_odometry1->setEnabled(false);
_ui->groupBox_odometry2->setEnabled(false);
this->setWindowTitle(tr("Preferences [Monitoring mode]"));
}
@@ -2029,7 +2037,7 @@ void PreferencesDialog::showEvent ( QShowEvent * event )
_ui->label_dictionaryPath->setEnabled(true);
_ui->groupBox_source0->setEnabled(true);
_ui->groupBox_odometry1->setEnabled(true);
_ui->groupBox_odometry2->setEnabled(true);
this->setWindowTitle(tr("Preferences"));
}
@@ -2336,6 +2344,20 @@ void PreferencesDialog::openDatabaseViewer()
}
}
void PreferencesDialog::selectCalibrationPath()
{
QString dir = _ui->lineEdit_calibrationFile->text();
if(dir.isEmpty())
{
dir = getWorkingDirectory()+"/camera_info";
}
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Calibration file (*.yaml)"));
if(path.size())
{
_ui->lineEdit_calibrationFile->setText(path);
}
}
void PreferencesDialog::selectSourceRGBDImagesStamps()
{
QString dir = _ui->lineEdit_cameraRGBDImages_timestamps->text();
@@ -2420,6 +2442,20 @@ void PreferencesDialog::selectSourceStereoImagesPathRight()
}
}
void PreferencesDialog::selectSourceStereoImagesPathScans()
{
QString dir = _ui->lineEdit_cameraStereoImages_path_scans->text();
if(dir.isEmpty())
{
dir = getWorkingDirectory();
}
QString path = QFileDialog::getExistingDirectory(this, tr("Select scans directory"), dir);
if(path.size())
{
_ui->lineEdit_cameraStereoImages_path_scans->setText(path);
}
}
void PreferencesDialog::selectSourceImagesPath()
{
QString dir = _ui->source_images_lineEdit_path->text();
@@ -2534,8 +2570,7 @@ void PreferencesDialog::setParameter(const std::string & key, const std::string
{
if(valueInt <= 1 &&
(combo->objectName().toStdString().compare(Parameters::kKpDetectorStrategy()) == 0 ||
combo->objectName().toStdString().compare(Parameters::kLccReextractFeatureType()) == 0 ||
combo->objectName().toStdString().compare(Parameters::kOdomFeatureType()) == 0))
combo->objectName().toStdString().compare(Parameters::kVisFeatureType()) == 0))
{
UWARN("Trying to set \"%s\" to SIFT/SURF but RTAB-Map isn't built "
"with the nonfree module from OpenCV. Keeping default combo value: %s.",
@@ -2545,8 +2580,7 @@ void PreferencesDialog::setParameter(const std::string & key, const std::string
}
else if(valueInt==1 &&
(combo->objectName().toStdString().compare(Parameters::kKpNNStrategy()) == 0 ||
combo->objectName().toStdString().compare(Parameters::kLccReextractNNType()) == 0 ||
combo->objectName().toStdString().compare(Parameters::kOdomBowNNType()) == 0))
combo->objectName().toStdString().compare(Parameters::kVisNNType()) == 0))
{
UWARN("Trying to set \"%s\" to KdTree but RTAB-Map isn't built "
@@ -2691,7 +2725,6 @@ void PreferencesDialog::addParameter(const QObject * object, int value)
}
}
else if(comboBox == _ui->comboBox_detector_strategy ||
comboBox == _ui->odom_type ||
comboBox == _ui->reextract_type)
{
if(value == 0) // surf
@@ -2731,25 +2764,10 @@ void PreferencesDialog::addParameter(const QObject * object, int value)
this->addParameters(_ui->groupBox_detector_brisk2);
}
}
else if(comboBox == _ui->globalDetection_icpType)
{
if(value == 1) // 1 icp3
{
this->addParameters(_ui->groupBox_loopClosure_icp3);
}
else if(value == 2) // 2 icp2
{
this->addParameters(_ui->groupBox_loopClosure_icp2);
}
}
else if(comboBox == _ui->loopClosure_estimationType)
{
this->addParameters(_ui->stackedWidget_loopClosureEstimation, _ui->loopClosure_estimationType->currentIndex());
}
else if(comboBox == _ui->odom_estimationType)
{
this->addParameters(_ui->stackedWidget_odomEstimation, _ui->stackedWidget_odomEstimation->currentIndex());
}
else if(comboBox == _ui->graphOptimization_type)
{
this->addParameter(_ui->graphOptimization_iterations, _ui->graphOptimization_iterations->value());
@@ -2802,6 +2820,11 @@ void PreferencesDialog::addParameter(const QObject * object, bool value)
this->addParameters(_ui->groupBox_localDetection_time);
this->addParameters(_ui->groupBox_localDetection_space);
this->addParameters(_ui->groupBox_visualTransform2);
this->addParameters(_ui->groupBox_icp2);
}
else if(value && checkbox == _ui->loopClosure_icp)
{
this->addParameters(_ui->groupBox_icp2);
}
if(groupBox)
@@ -2813,7 +2836,7 @@ void PreferencesDialog::addParameter(const QObject * object, bool value)
}
if(value && groupBox == _ui->groupBox_localDetection_space)
{
this->addParameters(_ui->groupBox_loopClosure_icp2);
this->addParameters(_ui->groupBox_icp2);
}
this->addParameters(groupBox);
@@ -3345,6 +3368,16 @@ bool PreferencesDialog::isScansShown(int index) const
UASSERT(index >= 0 && index <= 1);
return _3dRenderingShowScans[index]->isChecked();
}
int PreferencesDialog::getDownsamplingStepScan(int index) const
{
UASSERT(index >= 0 && index <= 1);
return _3dRenderingDownsamplingScan[index]->value();
}
double PreferencesDialog::getCloudVoxelSizeScan(int index) const
{
UASSERT(index >= 0 && index <= 1);
return _3dRenderingVoxelSizeScan[index]->value();
}
double PreferencesDialog::getScanOpacity(int index) const
{
UASSERT(index >= 0 && index <= 1);
@@ -3426,10 +3459,6 @@ bool PreferencesDialog::isSourceMirroring() const
{
return _ui->source_mirroring->isChecked();
}
QString PreferencesDialog::getCalibrationName() const
{
return _ui->lineEdit_calibrationName->text();
}
PreferencesDialog::Src PreferencesDialog::getSourceType() const
{
int index = _ui->comboBox_sourceType->currentIndex();
@@ -3498,49 +3527,23 @@ QString PreferencesDialog::getSourceDevice() const
{
return _ui->lineEdit_sourceDevice->text();
}
Transform PreferencesDialog::getSourceLocalTransform() const
{
Transform t = Transform::getIdentity();
QString str = _ui->lineEdit_sourceLocalTransform->text();
str.replace("PI_2", QString::number(3.141592/2.0));
QStringList list = str.split(' ');
if(list.size() == 6 || list.size() == 9 || list.size() == 12)
Transform t = Transform::fromString(_ui->lineEdit_sourceLocalTransform->text().replace("PI_2", QString::number(3.141592/2.0)).toStdString());
if(t.isNull())
{
std::vector<float> numbers(list.size());
bool ok = false;
for(int i=0; i<list.size(); ++i)
{
numbers[i] = list.at(i).toDouble(&ok);
if(!ok)
{
UERROR("Parsing local transform failed! \"%s\" not recognized (%s)",
list.at(i).toStdString().c_str(), str.toStdString().c_str());
break;
}
}
if(ok)
{
if(numbers.size() == 6)
{
t = Transform(numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5]);
}
else if(numbers.size() == 9)
{
t = Transform(numbers[0], numbers[1], numbers[2], 0,
numbers[3], numbers[4], numbers[5], 0,
numbers[6], numbers[7], numbers[8], 0);
}
else if(numbers.size() == 12)
{
t = Transform(numbers[0], numbers[1], numbers[2], numbers[9],
numbers[3], numbers[4], numbers[5], numbers[10],
numbers[6], numbers[7], numbers[8], numbers[11]);
}
}
return Transform::getIdentity();
}
else
return t;
}
Transform PreferencesDialog::getStereoLaserLocalTransform() const
{
Transform t = Transform::fromString(_ui->lineEdit_cameraStereoImages_laser_transform->text().replace("PI_2", QString::number(3.141592/2.0)).toStdString());
if(t.isNull())
{
UERROR("Local transform is wrong! must have 6 or 9 items (%s)", str.toStdString().c_str());
return Transform::getIdentity();
}
return t;
}
@@ -3700,6 +3703,9 @@ Camera * PreferencesDialog::createCamera(bool useRawImages)
else if(driver == kSrcStereoImages)
{
camera = new CameraStereoImages(
_ui->lineEdit_cameraStereoImages_path_scans->text().append(QDir::separator()).toStdString(),
this->getStereoLaserLocalTransform(),
_ui->spinBox_cameraStereoImages_max_scan_pts->value(),
_ui->lineEdit_cameraStereoImages_path_left->text().append(QDir::separator()).toStdString(),
_ui->lineEdit_cameraStereoImages_path_right->text().append(QDir::separator()).toStdString(),
_ui->checkBox_stereoImages_timestamps->isChecked(),
@@ -3755,7 +3761,20 @@ Camera * PreferencesDialog::createCamera(bool useRawImages)
if(camera)
{
// don't set calibration folder if we want raw images
if(!camera->init(useRawImages?"":this->getCameraInfoDir().toStdString(), this->getCalibrationName().toStdString()))
QString dir = this->getCameraInfoDir();
QString name = QFileInfo(_ui->lineEdit_calibrationFile->text()
.remove("_left.yaml")
.remove("_right.yaml")
.remove("_pose.yaml")).baseName();
if(!_ui->lineEdit_calibrationFile->text().isEmpty())
{
QDir d = QFileInfo(_ui->lineEdit_calibrationFile->text()).dir();
if(!d.path().isEmpty())
{
dir = d.absolutePath();
}
}
if(!camera->init(useRawImages?"":dir.toStdString(), name.toStdString()))
{
UWARN("init camera failed... ");
QMessageBox::warning(this,
@@ -3809,7 +3828,7 @@ int PreferencesDialog::getOdomBufferSize() const
{
return _ui->odom_dataBufferSize->value();
}
bool PreferencesDialog::getLccBowVarianceFromInliersCount() const
bool PreferencesDialog::getRegVarianceFromInliersCount() const
{
return _ui->loopClosure_bowVarianceFromInliersCount->isChecked();
}
@@ -3906,11 +3925,6 @@ void PreferencesDialog::setSLAMMode(bool enabled)
}
void PreferencesDialog::testOdometry()
{
testOdometry(_ui->odom_type->currentIndex());
}
void PreferencesDialog::testOdometry(int type)
{
DBReader dbReader(_ui->source_database_lineEdit_path->text().toStdString(),
_ui->source_checkBox_useDbStamps->isChecked()?-1:this->getGeneralInputRate(),
@@ -4098,7 +4112,7 @@ void PreferencesDialog::calibrate()
void PreferencesDialog::calibrateSimple()
{
CreateSimpleCalibrationDialog dialog(this->getCameraInfoDir(), _ui->lineEdit_calibrationName->text(), this);
CreateSimpleCalibrationDialog dialog(this->getCameraInfoDir(), "", this);
dialog.exec();
}

View File

@@ -50,8 +50,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>166</width>
<height>173</height>
<width>181</width>
<height>184</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
@@ -236,8 +236,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>165</width>
<height>173</height>
<width>181</width>
<height>184</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
@@ -418,7 +418,7 @@
<x>0</x>
<y>0</y>
<width>1285</width>
<height>25</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -430,6 +430,7 @@
<addaction name="actionSave_config"/>
<addaction name="separator"/>
<addaction name="actionGenerate_3D_map_pcd"/>
<addaction name="actionExport_3D_laser_scans_ply_pcd"/>
<addaction name="actionExport"/>
<addaction name="actionExtract_images"/>
<addaction name="separator"/>
@@ -453,6 +454,7 @@
<addaction name="actionReset_all_changes"/>
<addaction name="separator"/>
<addaction name="actionView_3D_map"/>
<addaction name="actionView_3D_laser_scans"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
@@ -826,25 +828,103 @@
</attribute>
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QComboBox" name="comboBox_logger_level">
<property name="currentIndex">
<number>1</number>
</property>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Warning</string>
</property>
</item>
<item>
<property name="text">
<string>Error</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_logger_level">
<property name="text">
<string>Logger level</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>314</width>
<height>303</height>
<width>312</width>
<height>374</height>
</rect>
</property>
<attribute name="label">
<string>ICP</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
<item row="0" column="0">
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_icp_iteration">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Iteration</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Point to plane</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QSpinBox" name="spinBox_icp_normalKSearch">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_icp_decimation">
<property name="minimum">
<number>1</number>
@@ -857,14 +937,14 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Decimation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxDepth">
<property name="suffix">
<string> m</string>
@@ -880,14 +960,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Max depth</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_voxel">
<property name="suffix">
<string> m</string>
@@ -903,14 +976,14 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="4" column="1">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Voxel</string>
<string>Voxel size</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxCorrespDistance">
<property name="suffix">
<string> m</string>
@@ -929,14 +1002,31 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Max correspondence distance</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="11" column="0">
<widget class="QCheckBox" name="checkBox_icp_2d">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Max depth</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_minCorrespondenceRatio">
<property name="suffix">
<string/>
@@ -955,34 +1045,14 @@
</property>
</widget>
</item>
<item row="5" column="1">
<item row="7" column="1">
<widget class="QLabel" name="label_46">
<property name="text">
<string>Min correspondence ratio</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QSpinBox" name="spinBox_icp_iteration">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Iteration</string>
</property>
</widget>
</item>
<item row="7" column="0">
<item row="9" column="0">
<widget class="QCheckBox" name="checkBox_icp_p2plane">
<property name="text">
<string/>
@@ -992,51 +1062,21 @@
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Point to plane</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_icp_normalKSearch">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="10" column="1">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Normal K neighbors</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="checkBox_icp_2d">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="11" column="1">
<widget class="QLabel" name="label_27">
<property name="text">
<string>2D icp (laser scans required)</string>
<string>2D icp</string>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="12" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -1049,6 +1089,43 @@
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_68">
<property name="text">
<string>Use laser scans for ICP</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_icp_laserScan">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_69">
<property name="text">
<string>Downsample step size</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QSpinBox" name="spinBox_icp_downsamplingStepSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
<property name="singleStep">
<number>1000</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
@@ -1056,8 +1133,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>407</height>
<width>366</width>
<height>420</height>
</rect>
</property>
<attribute name="label">
@@ -1389,8 +1466,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<height>333</height>
<width>338</width>
<height>330</height>
</rect>
</property>
<attribute name="label">
@@ -1628,8 +1705,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>255</width>
<height>377</height>
<width>261</width>
<height>411</height>
</rect>
</property>
<attribute name="label">
@@ -1886,7 +1963,7 @@
<x>0</x>
<y>0</y>
<width>201</width>
<height>117</height>
<height>126</height>
</rect>
</property>
<attribute name="label">
@@ -1985,8 +2062,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>285</width>
<height>309</height>
<width>283</width>
<height>322</height>
</rect>
</property>
<attribute name="label">
@@ -2394,7 +2471,7 @@
</action>
<action name="actionGenerate_3D_map_pcd">
<property name="text">
<string>Export 3D map (*.pcd) ...</string>
<string>Export 3D map (*.ply *.pcd) ...</string>
</property>
</action>
<action name="actionExport">
@@ -2457,6 +2534,16 @@
<string>Generate g2o graph (*.g2o)...</string>
</property>
</action>
<action name="actionView_3D_laser_scans">
<property name="text">
<string>View 3D laser scans...</string>
</property>
</action>
<action name="actionExport_3D_laser_scans_ply_pcd">
<property name="text">
<string>Export 3D laser scans (*.ply *.pcd) ...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

File diff suppressed because it is too large Load Diff