DatabaseViewer: Saving/loading settings, added 3D view, added Grid from 3d projection parameter

This commit is contained in:
Mathieu Labbe
2015-03-04 17:27:44 -05:00
parent c93460aadb
commit 8fd0f3761a
20 changed files with 1101 additions and 411 deletions

View File

@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QMap>
#include <QtCore/QSet>
#include <QtCore/qnamespace.h>
#include <QtCore/QSettings>
#include <opencv2/opencv.hpp>
@@ -63,6 +64,9 @@ public:
CloudViewer(QWidget * parent = 0);
virtual ~CloudViewer();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
bool updateCloudPose(
const std::string & id,
const Transform & pose); //including mesh

View File

@@ -53,6 +53,7 @@ namespace rtabmap
class Memory;
class ImageView;
class Signature;
class CloudViewer;
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
{
@@ -62,13 +63,18 @@ public:
DatabaseViewer(QWidget * parent = 0);
virtual ~DatabaseViewer();
bool openDatabase(const QString & path);
bool isSavedMaximized() const {return savedMaximized_;}
protected:
virtual void showEvent(QShowEvent* anEvent);
virtual void moveEvent(QMoveEvent* anEvent);
virtual void resizeEvent(QResizeEvent* anEvent);
virtual void closeEvent(QCloseEvent* event);
virtual bool eventFilter(QObject *obj, QEvent *event);
private slots:
void writeSettings();
void configModified();
void openDatabase();
void generateGraph();
void exportDatabase();
@@ -89,6 +95,7 @@ private slots:
void sliderNeighborValueChanged(int);
void sliderLoopValueChanged(int);
void sliderIterationsValueChanged(int);
void updateGrid();
void updateGraphView();
void refineConstraint();
void refineConstraintVisually();
@@ -98,6 +105,9 @@ private slots:
void updateConstraintView();
private:
QString getIniFilePath() const;
void readSettings();
void updateIds();
void update(int value,
QLabel * labelIndex,
@@ -107,6 +117,7 @@ private:
QLabel * label,
QLabel * stamp,
rtabmap::ImageView * view,
rtabmap::CloudViewer * view3D,
QLabel * labelId,
bool updateConstraintView = true);
void updateStereo(const Signature * data);
@@ -145,7 +156,10 @@ private:
std::multimap<int, rtabmap::Link> linksRefined_;
std::multimap<int, rtabmap::Link> linksAdded_;
std::multimap<int, rtabmap::Link> linksRemoved_;
std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > scans_;
std::map<int, std::pair<cv::Mat, cv::Mat> > localMaps_; // <ground, obstacles>
bool savedMaximized_;
bool firstCall_;
};
}

View File

@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtGui/QGraphicsView>
#include <QtCore/QRectF>
#include <QtCore/QMultiMap>
#include <QtCore/QSettings>
#include <opencv2/features2d/features2d.hpp>
#include <map>
@@ -51,6 +52,9 @@ public:
ImageView(QWidget * parent = 0);
virtual ~ImageView();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
void resetZoom();
bool isImageShown() const;

View File

@@ -298,6 +298,8 @@ private:
QVector<int> _refIds;
QVector<int> _loopClosureIds;
bool _firstCall;
};
}

View File

@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtGui/QWheelEvent>
#include <QtGui/QKeyEvent>
#include <QtGui/QColorDialog>
#include <QtGui/QVector3D>
#include <set>
#include <vtkRenderWindow.h>
@@ -159,6 +160,92 @@ void CloudViewer::createMenu()
_menu->addAction(_aSetBackgroundColor);
}
void CloudViewer::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
this->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
QVector3D pose(poseX, poseY, poseZ);
QVector3D focal(focalX, focalY, focalZ);
if(!this->isCameraFree())
{
// make camera position relative to target
Transform T = this->getTargetPose();
if(this->isCameraTargetLocked())
{
T = Transform(T.x(), T.y(), T.z(), 0,0,0);
}
Transform F(focalX, focalY, focalZ, 0,0,0);
Transform P(poseX, poseY, poseZ, 0,0,0);
Transform newFocal = T.inverse() * F;
Transform newPose = newFocal * F.inverse() * P;
pose = QVector3D(newPose.x(), newPose.y(), newPose.z());
focal = QVector3D(newFocal.x(), newFocal.y(), newFocal.z());
}
settings.setValue("camera_pose", pose);
settings.setValue("camera_focal", focal);
settings.setValue("camera_up", QVector3D(upX, upY, upZ));
settings.setValue("grid", this->isGridShown());
settings.setValue("grid_cell_count", this->getGridCellCount());
settings.setValue("grid_cell_size", this->getGridCellSize());
settings.setValue("trajectory_shown", this->isTrajectoryShown());
settings.setValue("trajectory_size", this->getTrajectorySize());
settings.setValue("camera_target_locked", this->isCameraTargetLocked());
settings.setValue("camera_target_follow", this->isCameraTargetFollow());
settings.setValue("camera_free", this->isCameraFree());
settings.setValue("camera_lockZ", this->isCameraLockZ());
settings.setValue("bg_color", this->getBackgroundColor());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void CloudViewer::loadSettings(QSettings & settings, const QString & group)
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
this->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
QVector3D pose(poseX, poseY, poseZ), focal(focalX, focalY, focalZ), up(upX, upY, upZ);
pose = settings.value("camera_pose", pose).value<QVector3D>();
focal = settings.value("camera_focal", focal).value<QVector3D>();
up = settings.value("camera_up", up).value<QVector3D>();
this->setCameraPosition(pose.x(),pose.y(),pose.z(), focal.x(),focal.y(),focal.z(), up.x(),up.y(),up.z());
this->setGridShown(settings.value("grid", this->isGridShown()).toBool());
this->setGridCellCount(settings.value("grid_cell_count", this->getGridCellCount()).toUInt());
this->setGridCellSize(settings.value("grid_cell_size", this->getGridCellSize()).toFloat());
this->setTrajectoryShown(settings.value("trajectory_shown", this->isTrajectoryShown()).toBool());
this->setTrajectorySize(settings.value("trajectory_size", this->getTrajectorySize()).toUInt());
this->setCameraTargetLocked(settings.value("camera_target_locked", this->isCameraTargetLocked()).toBool());
this->setCameraTargetFollow(settings.value("camera_target_follow", this->isCameraTargetFollow()).toBool());
if(settings.value("camera_free", this->isCameraFree()).toBool())
{
this->setCameraFree();
}
this->setCameraLockZ(settings.value("camera_lockZ", this->isCameraLockZ()).toBool());
this->setBackgroundColor(settings.value("bg_color", this->getBackgroundColor()).value<QColor>());
if(!group.isEmpty())
{
settings.endGroup();
}
}
bool CloudViewer::updateCloudPose(
const std::string & id,
const Transform & pose)

View File

@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QBuffer>
#include <QtCore/QTextStream>
#include <QtCore/QDateTime>
#include <QtCore/QSettings>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UConversion.h>
@@ -65,7 +66,9 @@ namespace rtabmap {
DatabaseViewer::DatabaseViewer(QWidget * parent) :
QMainWindow(parent),
memory_(0)
memory_(0),
savedMaximized_(false),
firstCall_(true)
{
pathDatabase_ = QDir::homePath()+"/Documents/RTAB-Map"; //use home directory by default
@@ -77,24 +80,34 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
ui_ = new Ui_DatabaseViewer();
ui_->setupUi(this);
QString title("RTAB-Map Database Viewer[*]");
this->setWindowTitle(title);
ui_->dockWidget_constraints->setVisible(false);
ui_->dockWidget_graphView->setVisible(false);
ui_->dockWidget_icp->setVisible(false);
ui_->dockWidget_visual->setVisible(false);
ui_->dockWidget_stereoView->setVisible(false);
ui_->dockWidget_icp->setFloating(true);
ui_->dockWidget_visual->setFloating(true);
ui_->dockWidget_view3d->setVisible(false);
ui_->constraintsViewer->setCameraLockZ(false);
ui_->constraintsViewer->setCameraFree();
this->readSettings();
ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_stereoView->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_view3d->toggleViewAction());
connect(ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateGraphView()));
connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
connect(ui_->buttonBox, SIGNAL(rejected()), this, SLOT(close()));
// connect actions with custom slots
ui_->actionSave_config->setShortcut(QKeySequence::Save);
connect(ui_->actionSave_config, SIGNAL(triggered()), this, SLOT(writeSettings()));
connect(ui_->actionOpen_database, SIGNAL(triggered()), this, SLOT(openDatabase()));
connect(ui_->actionExport, SIGNAL(triggered()), this, SLOT(exportDatabase()));
connect(ui_->actionExtract_images, SIGNAL(triggered()), this, SLOT(extractImages()));
@@ -144,16 +157,65 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
ui_->checkBox_showOptimized->setEnabled(false);
ui_->horizontalSlider_iterations->setTracking(false);
ui_->dockWidget_graphView->setEnabled(false);
ui_->horizontalSlider_iterations->setEnabled(false);
ui_->spinBox_optimizationsFrom->setEnabled(false);
connect(ui_->horizontalSlider_iterations, SIGNAL(valueChanged(int)), this, SLOT(sliderIterationsValueChanged(int)));
connect(ui_->horizontalSlider_iterations, SIGNAL(sliderMoved(int)), this, SLOT(sliderIterationsValueChanged(int)));
connect(ui_->spinBox_iterations, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->spinBox_optimizationsFrom, SIGNAL(valueChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_initGuess, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreCovariance, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_gridFromProjection, SIGNAL(stateChanged(int)), this, SLOT(updateGrid()));
connect(ui_->doubleSpinBox_gridCellSize, SIGNAL(editingFinished()), this, SLOT(updateGrid()));
connect(ui_->spinBox_projDecimation, SIGNAL(editingFinished()), this, SLOT(updateGrid()));
connect(ui_->doubleSpinBox_projMaxDepth, SIGNAL(editingFinished()), this, SLOT(updateGrid()));
ui_->constraintsViewer->setCameraLockZ(false);
ui_->constraintsViewer->setCameraFree();
// connect configuration changed
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()));
// Graph view
connect(ui_->spinBox_iterations, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_initGuess, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreCovariance, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_gridFromProjection, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_gridCellSize, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_projDecimation, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_projMaxDepth, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
// ICP parameters
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_->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()));
// Visual parameters
connect(ui_->checkBox_visual_recomputeFeatures, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_visual_2d, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_visual_hessian, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_visual_nndr, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_visual_minCorrespondences, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_visual_maxCorrespDistance, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_visual_iteration, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_visual_maxDepth, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_detectMore_radius, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_detectMore_angle, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->spinBox_detectMore_iterations, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
// dockwidget
QList<QDockWidget*> dockWidgets = this->findChildren<QDockWidget*>();
for(int i=0; i<dockWidgets.size(); ++i)
{
connect(dockWidgets[i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(configModified()));
connect(dockWidgets[i]->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(configModified()));
}
ui_->dockWidget_constraints->installEventFilter(this);
ui_->dockWidget_graphView->installEventFilter(this);
ui_->dockWidget_icp->installEventFilter(this);
ui_->dockWidget_stereoView->installEventFilter(this);
ui_->dockWidget_visual->installEventFilter(this);
ui_->dockWidget_view3d->installEventFilter(this);
}
DatabaseViewer::~DatabaseViewer()
@@ -165,6 +227,150 @@ DatabaseViewer::~DatabaseViewer()
}
}
void DatabaseViewer::configModified()
{
this->setWindowModified(true);
}
QString DatabaseViewer::getIniFilePath() const
{
QString privatePath = QDir::homePath() + "/.rtabmap";
if(!QDir(privatePath).exists())
{
QDir::home().mkdir(".rtabmap");
}
return privatePath + "/dbviewer.ini";
}
void DatabaseViewer::readSettings()
{
QString path = getIniFilePath();
QSettings settings(path, QSettings::IniFormat);
settings.beginGroup("DatabaseViewer");
//load window state / geometry
QByteArray bytes;
bytes = settings.value("geometry", QByteArray()).toByteArray();
if(!bytes.isEmpty())
{
this->restoreGeometry(bytes);
}
bytes = settings.value("state", QByteArray()).toByteArray();
if(!bytes.isEmpty())
{
this->restoreState(bytes);
}
savedMaximized_ = settings.value("maximized", false).toBool();
// GraphViewer settings
settings.beginGroup("GraphView");
ui_->graphViewer->loadSettings(settings);
ui_->spinBox_iterations->setValue(settings.value("iterations", ui_->spinBox_iterations->value()).toInt());
ui_->checkBox_initGuess->setChecked(settings.value("initGuess", ui_->checkBox_initGuess->isChecked()).toBool());
ui_->checkBox_ignoreCovariance->setChecked(settings.value("ignoreCovariance", ui_->checkBox_ignoreCovariance->isChecked()).toBool());
ui_->checkBox_gridFromProjection->setChecked(settings.value("gridFromProj", ui_->checkBox_gridFromProjection->isChecked()).toBool());
ui_->doubleSpinBox_gridCellSize->setValue(settings.value("gridCellSize", ui_->doubleSpinBox_gridCellSize->value()).toDouble());
ui_->spinBox_projDecimation->setValue(settings.value("projDecimation", ui_->spinBox_projDecimation->value()).toInt());
ui_->doubleSpinBox_projMaxDepth->setValue(settings.value("projMaxDepth", ui_->doubleSpinBox_projMaxDepth->value()).toDouble());
settings.endGroup();
// ImageViews
//ui_->graphicsView_A->loadSettings(settings, "ImageViewA");
//ui_->graphicsView_B->loadSettings(settings, "ImageViewB");
// ICP parameters
settings.beginGroup("icp");
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_->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());
settings.endGroup();
// Visual parameters
settings.beginGroup("visual");
ui_->checkBox_visual_recomputeFeatures->setChecked(settings.value("reextract", ui_->checkBox_visual_recomputeFeatures->isChecked()).toBool());
ui_->checkBox_visual_2d->setChecked(settings.value("force2d", ui_->checkBox_visual_2d->isChecked()).toBool());
ui_->doubleSpinBox_visual_hessian->setValue(settings.value("hessian", ui_->doubleSpinBox_visual_hessian->value()).toDouble());
ui_->doubleSpinBox_visual_nndr->setValue(settings.value("nndr", ui_->doubleSpinBox_visual_nndr->value()).toDouble());
ui_->spinBox_visual_minCorrespondences->setValue(settings.value("minCorr", ui_->spinBox_visual_minCorrespondences->value()).toInt());
ui_->doubleSpinBox_visual_maxCorrespDistance->setValue(settings.value("maxCorrDist", ui_->doubleSpinBox_visual_maxCorrespDistance->value()).toDouble());
ui_->spinBox_visual_iteration->setValue(settings.value("iterations", ui_->spinBox_visual_iteration->value()).toDouble());
ui_->doubleSpinBox_visual_maxDepth->setValue(settings.value("maxDepth", ui_->doubleSpinBox_visual_maxDepth->value()).toDouble());
ui_->doubleSpinBox_detectMore_radius->setValue(settings.value("detectMoreRadius", ui_->doubleSpinBox_detectMore_radius->value()).toDouble());
ui_->doubleSpinBox_detectMore_angle->setValue(settings.value("detectMoreAngle", ui_->doubleSpinBox_detectMore_angle->value()).toDouble());
ui_->spinBox_detectMore_iterations->setValue(settings.value("detectMoreIterations", ui_->spinBox_detectMore_iterations->value()).toInt());
settings.endGroup();
settings.endGroup(); // DatabaseViewer
}
void DatabaseViewer::writeSettings()
{
QString path = getIniFilePath();
QSettings settings(path, QSettings::IniFormat);
settings.beginGroup("DatabaseViewer");
//save window state / geometry
if(!this->isMaximized())
{
settings.setValue("geometry", this->saveGeometry());
}
settings.setValue("state", this->saveState());
settings.setValue("maximized", this->isMaximized());
savedMaximized_ = this->isMaximized();
// save GraphViewer settings
settings.beginGroup("GraphView");
ui_->graphViewer->saveSettings(settings);
settings.setValue("iterations", ui_->spinBox_iterations->value());
settings.setValue("initGuess", ui_->checkBox_initGuess->isChecked());
settings.setValue("ignoreCovariance", ui_->checkBox_ignoreCovariance->isChecked());
settings.setValue("gridFromProj", ui_->checkBox_gridFromProjection->isChecked());
settings.setValue("gridCellSize", ui_->doubleSpinBox_gridCellSize->value());
settings.setValue("projDecimation", ui_->spinBox_projDecimation->value());
settings.setValue("projMaxDepth", ui_->doubleSpinBox_projMaxDepth->value());
settings.endGroup();
// ImageViews
//ui_->graphicsView_A->saveSettings(settings, "ImageViewA");
//ui_->graphicsView_B->saveSettings(settings, "ImageViewB");
// save ICP parameters
settings.beginGroup("icp");
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("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.endGroup();
// save Visual parameters
settings.beginGroup("visual");
settings.setValue("reextract", ui_->checkBox_visual_recomputeFeatures->isChecked());
settings.setValue("force2d", ui_->checkBox_visual_2d->isChecked());
settings.setValue("hessian", ui_->doubleSpinBox_visual_hessian->value());
settings.setValue("nndr", ui_->doubleSpinBox_visual_nndr->value());
settings.setValue("minCorr", ui_->spinBox_visual_minCorrespondences->value());
settings.setValue("maxCorrDist", ui_->doubleSpinBox_visual_maxCorrespDistance->value());
settings.setValue("iterations", ui_->spinBox_visual_iteration->value());
settings.setValue("maxDepth", ui_->doubleSpinBox_visual_maxDepth->value());
settings.setValue("detectMoreRadius", ui_->doubleSpinBox_detectMore_radius->value());
settings.setValue("detectMoreAngle", ui_->doubleSpinBox_detectMore_angle->value());
settings.setValue("detectMoreIterations", ui_->spinBox_detectMore_iterations->value());
settings.endGroup();
settings.endGroup(); // DatabaseViewer
this->setWindowModified(false);
}
void DatabaseViewer::openDatabase()
{
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), pathDatabase_, tr("Databases (*.db)"));
@@ -193,7 +399,7 @@ bool DatabaseViewer::openDatabase(const QString & path)
linksAdded_.clear();
linksRefined_.clear();
linksRemoved_.clear();
scans_.clear();
localMaps_.clear();
ui_->actionGenerate_TORO_graph_graph->setEnabled(false);
ui_->checkBox_showOptimized->setEnabled(false);
}
@@ -228,6 +434,30 @@ bool DatabaseViewer::openDatabase(const QString & path)
void DatabaseViewer::closeEvent(QCloseEvent* event)
{
//write settings before quit?
bool save = false;
if(this->isWindowModified())
{
QMessageBox::Button b=QMessageBox::question(this,
tr("Database Viewer"),
tr("There are unsaved changed settings. Save them?"),
QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
if(b == QMessageBox::Save)
{
save = true;
}
else if(b != QMessageBox::Discard)
{
event->ignore();
return;
}
}
if(save)
{
writeSettings();
}
if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size())
{
QMessageBox::StandardButton button = QMessageBox::question(this,
@@ -316,6 +546,21 @@ void DatabaseViewer::showEvent(QShowEvent* anEvent)
ui_->graphicsView_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio);
ui_->graphicsView_A->resetZoom();
ui_->graphicsView_B->resetZoom();
this->setWindowModified(false);
}
void DatabaseViewer::moveEvent(QMoveEvent* anEvent)
{
if(this->isVisible())
{
// HACK, there is a move event when the window is shown the first time.
if(!firstCall_)
{
this->configModified();
}
firstCall_ = false;
}
}
void DatabaseViewer::resizeEvent(QResizeEvent* anEvent)
@@ -324,6 +569,19 @@ void DatabaseViewer::resizeEvent(QResizeEvent* anEvent)
ui_->graphicsView_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio);
ui_->graphicsView_A->resetZoom();
ui_->graphicsView_B->resetZoom();
if(this->isVisible())
{
this->configModified();
}
}
bool DatabaseViewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Resize && qobject_cast<QDockWidget*>(obj))
{
this->setWindowModified(true);
}
return QWidget::eventFilter(obj, event);
}
@@ -422,6 +680,8 @@ void DatabaseViewer::updateIds()
linksRemoved_.clear();
if(memory_->getLastWorkingSignature())
{
//get constraints only for parent links
memory_->getMetricConstraints(std::vector<int>(ids.begin(), ids.end()), poses_, links_, true);
if(poses_.size())
@@ -818,7 +1078,7 @@ void DatabaseViewer::detectMoreLoopClosures()
{
const std::map<int, Transform> & optimizedPoses = graphes_.back();
int iterations = ui_->doubleSpinBox_detectMore_iterations->value();
int iterations = ui_->spinBox_detectMore_iterations->value();
UASSERT(iterations > 0);
int added = 0;
for(int n=0; n<iterations; ++n)
@@ -973,6 +1233,7 @@ void DatabaseViewer::sliderAValueChanged(int value)
ui_->label_labelA,
ui_->label_stampA,
ui_->graphicsView_A,
ui_->widget_cloudA,
ui_->label_idA);
}
@@ -986,6 +1247,7 @@ void DatabaseViewer::sliderBValueChanged(int value)
ui_->label_labelB,
ui_->label_stampB,
ui_->graphicsView_B,
ui_->widget_cloudB,
ui_->label_idB);
}
@@ -997,6 +1259,7 @@ void DatabaseViewer::update(int value,
QLabel * label,
QLabel * stamp,
rtabmap::ImageView * view,
rtabmap::CloudViewer * view3D,
QLabel * labelId,
bool updateConstraintView)
{
@@ -1051,6 +1314,32 @@ void DatabaseViewer::update(int value,
{
this->updateStereo(&data);
}
// 3d view
if(view3D->isVisible() && !data.getDepthRaw().empty())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
if(data.getDepthRaw().type() == CV_8UC1)
{
cloud = util3d::cloudFromStereoImages(
data.getImageRaw(),
data.getDepthRaw(),
data.getDepthCx(), data.getDepthCy(),
data.getDepthFx(), data.getDepthFy(),
1);
}
else
{
cloud = util3d::cloudFromDepthRGB(
data.getImageRaw(),
data.getDepthRaw(),
data.getDepthCx(), data.getDepthCy(),
data.getDepthFx(), data.getDepthFy(),
1);
}
view3D->addOrUpdateCloud("0", cloud, data.getLocalTransform());
view3D->update();
}
}
if(!imgDepth.isNull())
@@ -1522,6 +1811,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_labelA,
ui_->label_stampA,
ui_->graphicsView_A,
ui_->widget_cloudA,
ui_->label_idA,
false); // don't update constraints view!
}
@@ -1535,6 +1825,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_labelB,
ui_->label_stampB,
ui_->graphicsView_B,
ui_->widget_cloudB,
ui_->label_idB,
false); // don't update constraints view!
}
@@ -1773,31 +2064,99 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
{
if(memory_ && value >=0 && value < (int)graphes_.size())
{
if(ui_->dockWidget_graphView->isVisible() && scans_.size() == 0)
if(ui_->dockWidget_graphView->isVisible() && localMaps_.size() == 0)
{
//update scans
UINFO("Update scans list...");
UINFO("Update local maps list...");
for(int i=0; i<ids_.size(); ++i)
{
Signature data = memory_->getSignatureData(ids_.at(i), false);
if(!data.getLaserScanCompressed().empty())
UTimer time;
bool added = false;
if(ui_->checkBox_gridFromProjection->isChecked())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cv::Mat laserScan = rtabmap::uncompressData(data.getLaserScanCompressed());
cloud = rtabmap::util3d::laserScanToPointCloud(laserScan);
scans_.insert(std::make_pair(ids_.at(i), cloud));
Signature data = memory_->getSignatureData(ids_.at(i), true);
if(!data.getDepthRaw().empty())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
if(data.getDepthRaw().type() == CV_8UC1)
{
cloud = rtabmap::util3d::cloudFromDisparity(
util3d::disparityFromStereoImages(data.getImageRaw(), data.getDepthRaw()),
data.getDepthCx(),
data.getDepthCy(),
data.getDepthFx(),
data.getDepthFy(),
ui_->spinBox_projDecimation->value());
}
else
{
cloud = util3d::cloudFromDepth(
data.getDepthRaw(),
data.getDepthCx(),
data.getDepthCy(),
data.getDepthFx(),
data.getDepthFy(),
ui_->spinBox_projDecimation->value());
}
if(cloud->size())
{
cloud = util3d::passThrough<pcl::PointXYZ>(cloud, "z", 0, ui_->doubleSpinBox_projMaxDepth->value());
}
if(cloud->size())
{
cloud = util3d::voxelize<pcl::PointXYZ>(cloud, ui_->doubleSpinBox_gridCellSize->value());
cloud = util3d::transformPointCloud<pcl::PointXYZ>(cloud, data.getLocalTransform());
UTimer timer;
float cellSize = ui_->doubleSpinBox_gridCellSize->value();
float groundNormalMaxAngle = M_PI_4;
int minClusterSize = 20;
cv::Mat ground, obstacles;
util3d::occupancy2DFromCloud3D<pcl::PointXYZ>(
cloud,
ground, obstacles,
cellSize,
groundNormalMaxAngle,
minClusterSize);
if(!ground.empty() || !obstacles.empty())
{
localMaps_.insert(std::make_pair(ids_.at(i), std::make_pair(ground, obstacles)));
added = true;
}
}
}
}
else
{
Signature data = memory_->getSignatureData(ids_.at(i), false);
if(!data.getLaserScanCompressed().empty())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
cv::Mat laserScan;
data.uncompressDataConst(0, 0, &laserScan);
cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(laserScan, ground, obstacles, ui_->doubleSpinBox_gridCellSize->value());
localMaps_.insert(std::make_pair(ids_.at(i), std::make_pair(ground, obstacles)));
added = true;
}
}
if(added)
{
UINFO("Processed grid map %d/%d (%fs)", i+1, (int)ids_.size(), time.ticks());
}
}
UINFO("Update scans list... done");
UINFO("Update local maps list... done");
}
std::map<int, rtabmap::Transform> & graph = uValueAt(graphes_, value);
std::multimap<int, Link> links = updateLinksWithModifications(links_);
ui_->graphViewer->updateGraph(graph, links);
if(graph.size() && scans_.size())
if(graph.size() && localMaps_.size())
{
float xMin, yMin;
float cell = 0.05;
cv::Mat map = rtabmap::util3d::convertMap2Image8U(rtabmap::util3d::create2DMap(graph, scans_, cell, true, xMin, yMin));
float cell = ui_->doubleSpinBox_gridCellSize->value();
cv::Mat map = rtabmap::util3d::convertMap2Image8U(rtabmap::util3d::create2DMapFromOccupancyLocalMaps(graph, localMaps_, cell, xMin, yMin));
ui_->graphViewer->updateMap(map, cell, xMin, yMin);
}
ui_->label_iterations->setNum(value);
@@ -1858,12 +2217,25 @@ void DatabaseViewer::updateGraphView()
{
ui_->horizontalSlider_iterations->setMaximum(graphes_.size()-1);
ui_->horizontalSlider_iterations->setValue(graphes_.size()-1);
ui_->dockWidget_graphView->setEnabled(true);
ui_->horizontalSlider_iterations->setEnabled(true);
ui_->spinBox_optimizationsFrom->setEnabled(true);
sliderIterationsValueChanged(graphes_.size()-1);
}
else
{
ui_->dockWidget_graphView->setEnabled(false);
ui_->horizontalSlider_iterations->setEnabled(false);
ui_->spinBox_optimizationsFrom->setEnabled(false);
}
}
void DatabaseViewer::updateGrid()
{
if((sender() != ui_->spinBox_projDecimation && sender() != ui_->doubleSpinBox_projMaxDepth) ||
(sender() == ui_->spinBox_projDecimation && ui_->checkBox_gridFromProjection->isChecked()) ||
(sender() == ui_->doubleSpinBox_projMaxDepth && ui_->checkBox_gridFromProjection->isChecked()))
{
localMaps_.clear();
updateGraphView();
}
}

View File

@@ -59,6 +59,54 @@ ExportCloudsDialog::~ExportCloudsDialog()
delete _ui;
}
void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
settings.setValue("assemble", this->getAssemble());
settings.setValue("assemble_voxel", this->getAssembleVoxel());
settings.setValue("regenerate", this->getGenerate());
settings.setValue("regenerate_decimation", this->getGenerateDecimation());
settings.setValue("regenerate_voxel", this->getGenerateVoxel());
settings.setValue("regenerate_max_depth", this->getGenerateMaxDepth());
settings.setValue("binary", this->getBinaryFile());
settings.setValue("mls", this->getMLS());
settings.setValue("mls_radius", this->getMLSRadius());
settings.setValue("mesh", this->getMesh());
settings.setValue("mesh_k", this->getMeshNormalKSearch());
settings.setValue("mesh_radius", this->getMeshGp3Radius());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & group)
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
this->setAssemble(settings.value("assemble", this->getAssemble()).toBool());
this->setAssembleVoxel(settings.value("assemble_voxel", this->getAssembleVoxel()).toDouble());
this->setGenerate(settings.value("regenerate", this->getGenerate()).toBool());
this->setGenerateDecimation(settings.value("regenerate_decimation", this->getGenerateDecimation()).toInt());
this->setGenerateVoxel(settings.value("regenerate_voxel", this->getGenerateVoxel()).toDouble());
this->setGenerateMaxDepth(settings.value("regenerate_max_depth", this->getGenerateMaxDepth()).toDouble());
this->setBinaryFile(settings.value("binary", this->getBinaryFile()).toBool());
this->setMLS(settings.value("mls", this->getMLS()).toBool());
this->setMLSRadius(settings.value("mls_radius", this->getMLSRadius()).toDouble());
this->setMesh(settings.value("mesh", this->getMesh()).toBool());
this->setMeshNormalKSearch(settings.value("mesh_k", this->getMeshNormalKSearch()).toInt());
this->setMeshGp3Radius(settings.value("mesh_radius", this->getMeshGp3Radius()).toDouble());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void ExportCloudsDialog::restoreDefaults()
{
setAssemble(true);

View File

@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define EXPORTCLOUDSDIALOG_H_
#include <QtGui/QDialog>
#include <QtCore/QSettings>
class Ui_ExportCloudsDialog;
class QAbstractButton;
@@ -44,6 +45,9 @@ public:
virtual ~ExportCloudsDialog();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
void setSaveButton();
void setOkButton();
void enableRegeneration(bool enabled);

View File

@@ -486,6 +486,54 @@ void GraphViewer::clearAll()
clearGraph();
}
void GraphViewer::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
settings.setValue("node_radius", this->getNodeRadius());
settings.setValue("link_width", this->getLinkWidth());
settings.setValue("node_color", this->getNodeColor());
settings.setValue("neighbor_color", this->getNeighborColor());
settings.setValue("global_color", this->getGlobalLoopClosureColor());
settings.setValue("local_color", this->getLocalLoopClosureColor());
settings.setValue("user_color", this->getUserLoopClosureColor());
settings.setValue("virtual_color", this->getVirtualLoopClosureColor());
settings.setValue("local_path_color", this->getLocalPathColor());
settings.setValue("grid_visible", this->isGridMapVisible());
settings.setValue("origin_visible", this->isOriginVisible());
settings.setValue("referential_visible", this->isReferentialVisible());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void GraphViewer::loadSettings(QSettings & settings, const QString & group)
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
this->setNodeRadius(settings.value("node_radius", this->getNodeRadius()).toDouble());
this->setLinkWidth(settings.value("link_width", this->getLinkWidth()).toDouble());
this->setNodeColor(settings.value("node_color", this->getNodeColor()).value<QColor>());
this->setNeighborColor(settings.value("neighbor_color", this->getNeighborColor()).value<QColor>());
this->setGlobalLoopClosureColor(settings.value("global_color", this->getGlobalLoopClosureColor()).value<QColor>());
this->setLocalLoopClosureColor(settings.value("local_color", this->getLocalLoopClosureColor()).value<QColor>());
this->setUserLoopClosureColor(settings.value("user_color", this->getUserLoopClosureColor()).value<QColor>());
this->setVirtualLoopClosureColor(settings.value("virtual_color", this->getVirtualLoopClosureColor()).value<QColor>());
this->setLocalPathColor(settings.value("local_path_color", this->getLocalPathColor()).value<QColor>());
this->setGridMapVisible(settings.value("grid_visible", this->isGridMapVisible()).toBool());
this->setOriginVisible(settings.value("origin_visible", this->isOriginVisible()).toBool());
this->setReferentialVisible(settings.value("referential_visible", this->isReferentialVisible()).toBool());
if(!group.isEmpty())
{
settings.endGroup();
}
}
bool GraphViewer::isGridMapVisible() const
{
return _gridMap->isVisible();

View File

@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtGui/QGraphicsView>
#include <QtCore/QMap>
#include <QtCore/QSettings>
#include <rtabmap/core/Link.h>
#include <opencv2/opencv.hpp>
#include <map>
@@ -62,6 +63,9 @@ public:
void clearPosterior();
void clearAll();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
//getters
const QString & getWorkingDirectory() const {return _workingDirectory;}
float getNodeRadius() const {return _nodeRadius;}

View File

@@ -74,6 +74,40 @@ ImageView::~ImageView() {
clear();
}
void ImageView::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
settings.setValue("image_shown", this->isImageShown());
settings.setValue("depth_shown", this->isImageDepthShown());
settings.setValue("features_shown", this->isFeaturesShown());
settings.setValue("lines_shown", this->isLinesShown());
settings.setValue("alpha", this->getAlpha());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void ImageView::loadSettings(QSettings & settings, const QString & group)
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
this->setImageShown(settings.value("image_shown", this->isImageShown()).toBool());
this->setImageDepthShown(settings.value("depth_shown", this->isImageDepthShown()).toBool());
this->setFeaturesShown(settings.value("features_shown", this->isFeaturesShown()).toBool());
this->setLinesShown(settings.value("lines_shown", this->isLinesShown()).toBool());
this->setAlpha(settings.value("alpha", this->getAlpha()).toInt());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void ImageView::resetZoom()
{
_zoom = _minZoom;

View File

@@ -131,7 +131,8 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
_posteriorCurve(0),
_likelihoodCurve(0),
_rawLikelihoodCurve(0),
_autoScreenCaptureOdomSync(false)
_autoScreenCaptureOdomSync(false),
_firstCall(true)
{
UDEBUG("");
@@ -173,19 +174,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
//_ui->dockWidget_odometry->setVisible(false);
//_ui->dockWidget_cloudViewer->setVisible(false);
//_ui->dockWidget_imageView->setVisible(false);
// catch resize events
_ui->dockWidget_posterior->installEventFilter(this);
_ui->dockWidget_likelihood->installEventFilter(this);
_ui->dockWidget_rawlikelihood->installEventFilter(this);
_ui->dockWidget_statsV2->installEventFilter(this);
_ui->dockWidget_console->installEventFilter(this);
_ui->dockWidget_loopClosureViewer->installEventFilter(this);
_ui->dockWidget_mapVisibility->installEventFilter(this);
_ui->dockWidget_graphViewer->installEventFilter(this);
_ui->dockWidget_odometry->installEventFilter(this);
_ui->dockWidget_cloudViewer->installEventFilter(this);
_ui->dockWidget_imageView->installEventFilter(this);
}
_ui->widget_mainWindow->setVisible(false);
@@ -399,6 +387,18 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
connect(dockWidgets[i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(configGUIModified()));
connect(dockWidgets[i]->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(configGUIModified()));
}
// catch resize events
_ui->dockWidget_posterior->installEventFilter(this);
_ui->dockWidget_likelihood->installEventFilter(this);
_ui->dockWidget_rawlikelihood->installEventFilter(this);
_ui->dockWidget_statsV2->installEventFilter(this);
_ui->dockWidget_console->installEventFilter(this);
_ui->dockWidget_loopClosureViewer->installEventFilter(this);
_ui->dockWidget_mapVisibility->installEventFilter(this);
_ui->dockWidget_graphViewer->installEventFilter(this);
_ui->dockWidget_odometry->installEventFilter(this);
_ui->dockWidget_cloudViewer->installEventFilter(this);
_ui->dockWidget_imageView->installEventFilter(this);
// more connects...
connect(_ui->doubleSpinBox_stats_imgRate, SIGNAL(editingFinished()), this, SLOT(changeImgRateSetting()));
@@ -2193,12 +2193,11 @@ void MainWindow::moveEvent(QMoveEvent* anEvent)
if(this->isVisible())
{
// HACK, there is a move event when the window is shown the first time.
static bool firstCall = true;
if(!firstCall)
if(!_firstCall)
{
this->configGUIModified();
}
firstCall = false;
_firstCall = false;
}
}
@@ -2471,7 +2470,14 @@ void MainWindow::editDatabase()
viewer->setWindowModality(Qt::WindowModal);
if(viewer->openDatabase(path))
{
viewer->show();
if(viewer->isSavedMaximized())
{
viewer->showMaximized();
}
else
{
viewer->show();
}
}
else
{

View File

@@ -57,6 +57,44 @@ PostProcessingDialog::~PostProcessingDialog()
delete _ui;
}
void PostProcessingDialog::saveSettings(QSettings & settings, const QString & group) const
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
settings.setValue("detect_more_lc", this->isDetectMoreLoopClosures());
settings.setValue("cluster_radius", this->clusterRadius());
settings.setValue("cluster_angle", this->clusterAngle());
settings.setValue("iterations", this->iterations());
settings.setValue("reextract_features", this->isReextractFeatures());
settings.setValue("refine_neigbors", this->isRefineNeighborLinks());
settings.setValue("refine_lc", this->isRefineLoopClosureLinks());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void PostProcessingDialog::loadSettings(QSettings & settings, const QString & group)
{
if(!group.isEmpty())
{
settings.beginGroup(group);
}
this->setDetectMoreLoopClosures(settings.value("detect_more_lc", this->isDetectMoreLoopClosures()).toBool());
this->setClusterRadius(settings.value("cluster_radius", this->clusterRadius()).toDouble());
this->setClusterAngle(settings.value("cluster_angle", this->clusterAngle()).toDouble());
this->setIterations(settings.value("iterations", this->iterations()).toInt());
this->setReextractFeatures(settings.value("reextract_features", this->isReextractFeatures()).toBool());
this->setRefineNeighborLinks(settings.value("refine_neigbors", this->isRefineNeighborLinks()).toBool());
this->setRefineLoopClosureLinks(settings.value("refine_lc", this->isRefineLoopClosureLinks()).toBool());
if(!group.isEmpty())
{
settings.endGroup();
}
}
void PostProcessingDialog::restoreDefaults()
{
setDetectMoreLoopClosures(true);

View File

@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define POSTPROCESSINGDIALOG_H_
#include <QtGui/QDialog>
#include <QtCore/QSettings>
class Ui_PostProcessingDialog;
class QAbstractButton;
@@ -44,6 +45,9 @@ public:
virtual ~PostProcessingDialog();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
//getters
bool isDetectMoreLoopClosures() const;
double clusterRadius() const;

View File

@@ -34,7 +34,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QDir>
#include <QtCore/QTimer>
#include <QtGui/QVector3D>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtGui/QStandardItemModel>
@@ -1750,90 +1749,23 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
if(cloudViewer)
{
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
cloudViewer->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
QVector3D pose(poseX, poseY, poseZ);
QVector3D focal(focalX, focalY, focalZ);
if(!cloudViewer->isCameraFree())
{
// make camera position relative to target
Transform T = cloudViewer->getTargetPose();
if(cloudViewer->isCameraTargetLocked())
{
T = Transform(T.x(), T.y(), T.z(), 0,0,0);
}
Transform F(focalX, focalY, focalZ, 0,0,0);
Transform P(poseX, poseY, poseZ, 0,0,0);
Transform newFocal = T.inverse() * F;
Transform newPose = newFocal * F.inverse() * P;
pose = QVector3D(newPose.x(), newPose.y(), newPose.z());
focal = QVector3D(newFocal.x(), newFocal.y(), newFocal.z());
}
settings.setValue("camera_pose", pose);
settings.setValue("camera_focal", focal);
settings.setValue("camera_up", QVector3D(upX, upY, upZ));
settings.setValue("grid", cloudViewer->isGridShown());
settings.setValue("grid_cell_count", cloudViewer->getGridCellCount());
settings.setValue("grid_cell_size", cloudViewer->getGridCellSize());
settings.setValue("trajectory_shown", cloudViewer->isTrajectoryShown());
settings.setValue("trajectory_size", cloudViewer->getTrajectorySize());
settings.setValue("camera_target_locked", cloudViewer->isCameraTargetLocked());
settings.setValue("camera_target_follow", cloudViewer->isCameraTargetFollow());
settings.setValue("camera_free", cloudViewer->isCameraFree());
settings.setValue("camera_lockZ", cloudViewer->isCameraLockZ());
settings.setValue("bg_color", cloudViewer->getBackgroundColor());
cloudViewer->saveSettings(settings);
}
else if(imageView)
{
settings.setValue("image_shown", imageView->isImageShown());
settings.setValue("depth_shown", imageView->isImageDepthShown());
settings.setValue("features_shown", imageView->isFeaturesShown());
settings.setValue("lines_shown", imageView->isLinesShown());
settings.setValue("alpha", imageView->getAlpha());
imageView->saveSettings(settings);
}
else if(exportCloudsDialog)
{
settings.setValue("assemble", exportCloudsDialog->getAssemble());
settings.setValue("assemble_voxel", exportCloudsDialog->getAssembleVoxel());
settings.setValue("regenerate", exportCloudsDialog->getGenerate());
settings.setValue("regenerate_decimation", exportCloudsDialog->getGenerateDecimation());
settings.setValue("regenerate_voxel", exportCloudsDialog->getGenerateVoxel());
settings.setValue("regenerate_max_depth", exportCloudsDialog->getGenerateMaxDepth());
settings.setValue("binary", exportCloudsDialog->getBinaryFile());
settings.setValue("mls", exportCloudsDialog->getMLS());
settings.setValue("mls_radius", exportCloudsDialog->getMLSRadius());
settings.setValue("mesh", exportCloudsDialog->getMesh());
settings.setValue("mesh_k", exportCloudsDialog->getMeshNormalKSearch());
settings.setValue("mesh_radius", exportCloudsDialog->getMeshGp3Radius());
exportCloudsDialog->saveSettings(settings);
}
else if(postProcessingDialog)
{
settings.setValue("detect_more_lc", postProcessingDialog->isDetectMoreLoopClosures());
settings.setValue("cluster_radius", postProcessingDialog->clusterRadius());
settings.setValue("cluster_angle", postProcessingDialog->clusterAngle());
settings.setValue("iterations", postProcessingDialog->iterations());
settings.setValue("reextract_features", postProcessingDialog->isReextractFeatures());
settings.setValue("refine_neigbors", postProcessingDialog->isRefineNeighborLinks());
settings.setValue("refine_lc", postProcessingDialog->isRefineLoopClosureLinks());
postProcessingDialog->saveSettings(settings);
}
else if(graphViewer)
{
settings.setValue("node_radius", graphViewer->getNodeRadius());
settings.setValue("link_width", graphViewer->getLinkWidth());
settings.setValue("node_color", graphViewer->getNodeColor());
settings.setValue("neighbor_color", graphViewer->getNeighborColor());
settings.setValue("global_color", graphViewer->getGlobalLoopClosureColor());
settings.setValue("local_color", graphViewer->getLocalLoopClosureColor());
settings.setValue("user_color", graphViewer->getUserLoopClosureColor());
settings.setValue("virtual_color", graphViewer->getVirtualLoopClosureColor());
settings.setValue("local_path_color", graphViewer->getLocalPathColor());
settings.setValue("grid_visible", graphViewer->isGridMapVisible());
settings.setValue("origin_visible", graphViewer->isOriginVisible());
settings.setValue("referential_visible", graphViewer->isReferentialVisible());
graphViewer->saveSettings(settings);
}
else
{
@@ -1862,78 +1794,23 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
if(cloudViewer)
{
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
cloudViewer->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
QVector3D pose(poseX, poseY, poseZ), focal(focalX, focalY, focalZ), up(upX, upY, upZ);
pose = settings.value("camera_pose", pose).value<QVector3D>();
focal = settings.value("camera_focal", focal).value<QVector3D>();
up = settings.value("camera_up", up).value<QVector3D>();
cloudViewer->setCameraPosition(pose.x(),pose.y(),pose.z(), focal.x(),focal.y(),focal.z(), up.x(),up.y(),up.z());
cloudViewer->setGridShown(settings.value("grid", cloudViewer->isGridShown()).toBool());
cloudViewer->setGridCellCount(settings.value("grid_cell_count", cloudViewer->getGridCellCount()).toUInt());
cloudViewer->setGridCellSize(settings.value("grid_cell_size", cloudViewer->getGridCellSize()).toFloat());
cloudViewer->setTrajectoryShown(settings.value("trajectory_shown", cloudViewer->isTrajectoryShown()).toBool());
cloudViewer->setTrajectorySize(settings.value("trajectory_size", cloudViewer->getTrajectorySize()).toUInt());
cloudViewer->setCameraTargetLocked(settings.value("camera_target_locked", cloudViewer->isCameraTargetLocked()).toBool());
cloudViewer->setCameraTargetFollow(settings.value("camera_target_follow", cloudViewer->isCameraTargetFollow()).toBool());
if(settings.value("camera_free", cloudViewer->isCameraFree()).toBool())
{
cloudViewer->setCameraFree();
}
cloudViewer->setCameraLockZ(settings.value("camera_lockZ", cloudViewer->isCameraLockZ()).toBool());
cloudViewer->setBackgroundColor(settings.value("bg_color", cloudViewer->getBackgroundColor()).value<QColor>());
cloudViewer->loadSettings(settings);
}
else if(imageView)
{
imageView->setImageShown(settings.value("image_shown", imageView->isImageShown()).toBool());
imageView->setImageDepthShown(settings.value("depth_shown", imageView->isImageDepthShown()).toBool());
imageView->setFeaturesShown(settings.value("features_shown", imageView->isFeaturesShown()).toBool());
imageView->setLinesShown(settings.value("lines_shown", imageView->isLinesShown()).toBool());
imageView->setAlpha(settings.value("alpha", imageView->getAlpha()).toInt());
imageView->loadSettings(settings);
}
else if(exportCloudsDialog)
{
exportCloudsDialog->setAssemble(settings.value("assemble", exportCloudsDialog->getAssemble()).toBool());
exportCloudsDialog->setAssembleVoxel(settings.value("assemble_voxel", exportCloudsDialog->getAssembleVoxel()).toDouble());
exportCloudsDialog->setGenerate(settings.value("regenerate", exportCloudsDialog->getGenerate()).toBool());
exportCloudsDialog->setGenerateDecimation(settings.value("regenerate_decimation", exportCloudsDialog->getGenerateDecimation()).toInt());
exportCloudsDialog->setGenerateVoxel(settings.value("regenerate_voxel", exportCloudsDialog->getGenerateVoxel()).toDouble());
exportCloudsDialog->setGenerateMaxDepth(settings.value("regenerate_max_depth", exportCloudsDialog->getGenerateMaxDepth()).toDouble());
exportCloudsDialog->setBinaryFile(settings.value("binary", exportCloudsDialog->getBinaryFile()).toBool());
exportCloudsDialog->setMLS(settings.value("mls", exportCloudsDialog->getMLS()).toBool());
exportCloudsDialog->setMLSRadius(settings.value("mls_radius", exportCloudsDialog->getMLSRadius()).toDouble());
exportCloudsDialog->setMesh(settings.value("mesh", exportCloudsDialog->getMesh()).toBool());
exportCloudsDialog->setMeshNormalKSearch(settings.value("mesh_k", exportCloudsDialog->getMeshNormalKSearch()).toInt());
exportCloudsDialog->setMeshGp3Radius(settings.value("mesh_radius", exportCloudsDialog->getMeshGp3Radius()).toDouble());
exportCloudsDialog->loadSettings(settings);
}
else if(postProcessingDialog)
{
postProcessingDialog->setDetectMoreLoopClosures(settings.value("detect_more_lc", postProcessingDialog->isDetectMoreLoopClosures()).toBool());
postProcessingDialog->setClusterRadius(settings.value("cluster_radius", postProcessingDialog->clusterRadius()).toDouble());
postProcessingDialog->setClusterAngle(settings.value("cluster_angle", postProcessingDialog->clusterAngle()).toDouble());
postProcessingDialog->setIterations(settings.value("iterations", postProcessingDialog->iterations()).toInt());
postProcessingDialog->setReextractFeatures(settings.value("reextract_features", postProcessingDialog->isReextractFeatures()).toBool());
postProcessingDialog->setRefineNeighborLinks(settings.value("refine_neigbors", postProcessingDialog->isRefineNeighborLinks()).toBool());
postProcessingDialog->setRefineLoopClosureLinks(settings.value("refine_lc", postProcessingDialog->isRefineLoopClosureLinks()).toBool());
postProcessingDialog->loadSettings(settings);
}
else if(graphViewer)
{
graphViewer->setNodeRadius(settings.value("node_radius", graphViewer->getNodeRadius()).toDouble());
graphViewer->setLinkWidth(settings.value("link_width", graphViewer->getLinkWidth()).toDouble());
graphViewer->setNodeColor(settings.value("node_color", graphViewer->getNodeColor()).value<QColor>());
graphViewer->setNeighborColor(settings.value("neighbor_color", graphViewer->getNeighborColor()).value<QColor>());
graphViewer->setGlobalLoopClosureColor(settings.value("global_color", graphViewer->getGlobalLoopClosureColor()).value<QColor>());
graphViewer->setLocalLoopClosureColor(settings.value("local_color", graphViewer->getLocalLoopClosureColor()).value<QColor>());
graphViewer->setUserLoopClosureColor(settings.value("user_color", graphViewer->getUserLoopClosureColor()).value<QColor>());
graphViewer->setVirtualLoopClosureColor(settings.value("virtual_color", graphViewer->getVirtualLoopClosureColor()).value<QColor>());
graphViewer->setLocalPathColor(settings.value("local_path_color", graphViewer->getLocalPathColor()).value<QColor>());
graphViewer->setGridMapVisible(settings.value("grid_visible", graphViewer->isGridMapVisible()).toBool());
graphViewer->setOriginVisible(settings.value("origin_visible", graphViewer->isOriginVisible()).toBool());
graphViewer->setReferentialVisible(settings.value("referential_visible", graphViewer->isReferentialVisible()).toBool());
graphViewer->loadSettings(settings);
}
else
{

View File

@@ -7,17 +7,14 @@
<x>0</x>
<y>0</y>
<width>1187</width>
<height>862</height>
<height>1018</height>
</rect>
</property>
<property name="windowTitle">
<string>Database viewer</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7" stretch="2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="rightMargin">
@@ -335,13 +332,6 @@
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
@@ -359,6 +349,8 @@
</property>
<addaction name="actionOpen_database"/>
<addaction name="separator"/>
<addaction name="actionSave_config"/>
<addaction name="separator"/>
<addaction name="actionExport"/>
<addaction name="actionExtract_images"/>
<addaction name="separator"/>
@@ -403,10 +395,7 @@
<widget class="rtabmap::CloudViewer" name="constraintsViewer" native="true"/>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<layout class="QGridLayout" name="gridLayout_6" columnstretch="0,1">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
@@ -441,6 +430,20 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_33">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_type">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
@@ -455,6 +458,20 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>σ (rot, trans)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_variance">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_showOptimized">
<property name="text">
@@ -483,34 +500,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>σ (rot, trans)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_variance">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_33">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_type">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -602,15 +591,79 @@
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<item row="1" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>TORO iterations:</string>
<string>TORO iterations</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Grid cell size</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_35">
<property name="text">
<string>Grid from 3D projection</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Initial tree guess</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Ignore covariance</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_gridCellSize">
<property name="suffix">
<string> m</string>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>5.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Total path length (m)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_initGuess">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="spinBox_iterations">
<property name="suffix">
<string/>
@@ -626,55 +679,17 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Optimize from:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_optimizationsFrom"/>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_initGuess">
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_gridFromProjection">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Initial tree guess:</string>
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Total path length (m):</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_pathLength">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Ignore covariance:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBox_ignoreCovariance">
<property name="text">
<string/>
@@ -684,12 +699,81 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_optimizationsFrom"/>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Optimize from</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_projDecimation">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>8</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_37">
<property name="text">
<string>Cloud decimation (3D projection)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Cloud max depth (3D projection)</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_projMaxDepth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.400000000000000</double>
</property>
<property name="maximum">
<double>15.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>4.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_pathLength">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_icp">
<property name="floating">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>ICP parameters</string>
</property>
@@ -699,22 +783,64 @@
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QGridLayout" name="gridLayout_4" columnminimumwidth="1,0">
<item row="4" column="0">
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
<item row="4" column="1">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Iteration</string>
</property>
</widget>
</item>
<item row="0" column="0">
<item row="0" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Decimation</string>
</property>
</widget>
</item>
<item row="0" column="1">
<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="1">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Voxel</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Max correspondence distance</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Point to plane</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Normal K neighbors</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_27">
<property name="text">
<string>2D icp</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_icp_decimation">
<property name="minimum">
<number>1</number>
@@ -728,13 +854,6 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Max depth</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxDepth">
<property name="suffix">
<string> m</string>
@@ -751,13 +870,6 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Voxel</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_voxel">
<property name="suffix">
<string> m</string>
@@ -774,13 +886,6 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Max correspondence distance</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxCorrespDistance">
<property name="suffix">
<string> m</string>
@@ -799,7 +904,7 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="4" column="0">
<widget class="QSpinBox" name="spinBox_icp_iteration">
<property name="minimum">
<number>1</number>
@@ -812,31 +917,7 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Point to plane</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="checkBox_icp_p2plane">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Normal K neighbors</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinBox_icp_normalKSearch">
<property name="minimum">
<number>1</number>
@@ -849,14 +930,17 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_27">
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_icp_p2plane">
<property name="text">
<string>2D icp</string>
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="7" column="0">
<widget class="QCheckBox" name="checkBox_icp_2d">
<property name="text">
<string/>
@@ -885,6 +969,9 @@
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_visual">
<property name="floating">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Visual parameters</string>
</property>
@@ -894,15 +981,85 @@
<widget class="QWidget" name="dockWidgetContents_4">
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QGridLayout" name="gridLayout_3" columnminimumwidth="1,0">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_3" columnstretch="0,1">
<item row="0" column="1">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Recompute features (SURF)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="2" column="1">
<widget class="QLabel" name="label_25">
<property name="text">
<string>SURF hessian threshold</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_26">
<property name="text">
<string>NNDR</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Min correspondences</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Max correspondence distance</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Iteration</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Max feature depth</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_28">
<property name="text">
<string>2D transform (x,y,yaw)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Detect more LCs: radius</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Detect more LCs: angle</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_31">
<property name="text">
<string>Detect more LCs: iterations</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox_visual_recomputeFeatures">
<property name="text">
<string/>
@@ -912,14 +1069,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_25">
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_visual_2d">
<property name="text">
<string>SURF hessian threshold</string>
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_visual_hessian">
<property name="suffix">
<string/>
@@ -939,13 +1096,6 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>NNDR</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_visual_nndr">
<property name="suffix">
<string> m</string>
@@ -968,13 +1118,6 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Min correspondences</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBox_visual_minCorrespondences">
<property name="minimum">
<number>3</number>
@@ -988,13 +1131,6 @@
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Max correspondence distance</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_visual_maxCorrespDistance">
<property name="suffix">
<string> m</string>
@@ -1014,13 +1150,6 @@
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Iteration</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinBox_visual_iteration">
<property name="minimum">
<number>1</number>
@@ -1034,13 +1163,6 @@
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Max feature depth</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_visual_maxDepth">
<property name="suffix">
<string> m</string>
@@ -1056,35 +1178,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>2D transform (x,y,yaw)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_visual_2d">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Detect more LCs: radius</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Detect more LCs: angle</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_radius">
<property name="suffix">
<string> m</string>
@@ -1103,7 +1197,7 @@
</property>
</widget>
</item>
<item row="9" column="1">
<item row="9" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_angle">
<property name="suffix">
<string> degrees</string>
@@ -1123,14 +1217,7 @@
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_31">
<property name="text">
<string>Detect more LCs: iterations</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="doubleSpinBox_detectMore_iterations">
<widget class="QSpinBox" name="spinBox_detectMore_iterations">
<property name="minimum">
<number>1</number>
</property>
@@ -1178,6 +1265,24 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_view3d">
<property name="windowTitle">
<string>3D view</string>
</property>
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_6">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="rtabmap::CloudViewer" name="widget_cloudA" native="true"/>
</item>
<item>
<widget class="rtabmap::CloudViewer" name="widget_cloudB" native="true"/>
</item>
</layout>
</widget>
</widget>
<action name="actionOpen_database">
<property name="text">
<string>Open database</string>
@@ -1268,6 +1373,11 @@
<string>Visual: Refine all loop closure links...</string>
</property>
</action>
<action name="actionSave_config">
<property name="text">
<string>Save config</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>