mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-03 10:00:23 +08:00
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:
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user