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

@@ -128,21 +128,21 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP cloudFromDisparity(
const cv::Mat & imageDisparity, const cv::Mat & imageDisparity,
float cx, float cy, float cx, float cy,
float fx, float baseline, float fx, float baseline,
int decimation); int decimation = 1);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cloudFromDisparityRGB( pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cloudFromDisparityRGB(
const cv::Mat & imageRgb, const cv::Mat & imageRgb,
const cv::Mat & imageDisparity, const cv::Mat & imageDisparity,
float cx, float cy, float cx, float cy,
float fx, float baseline, float fx, float baseline,
int decimation); int decimation = 1);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cloudFromStereoImages( pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cloudFromStereoImages(
const cv::Mat & imageLeft, const cv::Mat & imageLeft,
const cv::Mat & imageRight, const cv::Mat & imageRight,
float cx, float cy, float cx, float cy,
float fx, float baseline, float fx, float baseline,
int decimation); int decimation = 1);
cv::Mat RTABMAP_EXP disparityFromStereoImages( cv::Mat RTABMAP_EXP disparityFromStereoImages(
const cv::Mat & leftImage, const cv::Mat & leftImage,

View File

@@ -139,7 +139,7 @@ void optimizeTOROGraph(
std::list<std::map<int, Transform> > * intermediateGraphes) std::list<std::map<int, Transform> > * intermediateGraphes)
{ {
optimizedPoses.clear(); optimizedPoses.clear();
if(depthGraph.size() && poses.size()>=2 && links.size()>=1) if(depthGraph.size() >= 2 && poses.size()>=2 && links.size()>=1)
{ {
// Modify IDs using the margin from the current signature (TORO root will be the last signature) // Modify IDs using the margin from the current signature (TORO root will be the last signature)
int m = 0; int m = 0;
@@ -184,7 +184,7 @@ void optimizeTOROGraph(
if(uContains(depthGraph, iter->second.from()) && uContains(depthGraph, iter->second.to())) if(uContains(depthGraph, iter->second.from()) && uContains(depthGraph, iter->second.to()))
{ {
UASSERT(uContains(rtabmapToToro, iter->first) && uContains(rtabmapToToro, iter->second.to())); UASSERT(uContains(rtabmapToToro, iter->first) && uContains(rtabmapToToro, iter->second.to()));
UASSERT(!iter->second.transform().isNull()); UASSERT_MSG(!iter->second.transform().isNull(), uFormat("Link from=%d to=%d", iter->first, iter->second.to()).c_str());
edgeConstraintsToro.insert(std::make_pair(rtabmapToToro.at(iter->first), Link(rtabmapToToro.at(iter->first), rtabmapToToro.at(iter->second.to()), iter->second.type(), iter->second.transform(), iter->second.rotVariance(), iter->second.transVariance()))); edgeConstraintsToro.insert(std::make_pair(rtabmapToToro.at(iter->first), Link(rtabmapToToro.at(iter->first), rtabmapToToro.at(iter->second.to()), iter->second.type(), iter->second.transform(), iter->second.rotVariance(), iter->second.transVariance())));
} }
} }
@@ -225,12 +225,30 @@ void optimizeTOROGraph(
} }
else else
{ {
UERROR("No TORO poses and constraints!?"); if(edgeConstraintsToro.size() == 0)
{
UERROR("No TORO constraints!? (input poses=%d, links=%d, depthGraph=%d)",
(int)poses.size(), (int)links.size(), (int)depthGraph.size());
}
if(posesToro.size() == 0)
{
UERROR("No TORO poses!? (input poses=%d, links=%d, depthGraph=%d)",
(int)poses.size(), (int)links.size(), (int)depthGraph.size());
}
} }
} }
else if(links.size() == 0 && poses.size() == 1) else if(depthGraph.size() == 1)
{ {
optimizedPoses = poses; std::map<int, Transform>::const_iterator iter = poses.find(depthGraph.begin()->first);
if(iter != poses.end())
{
UASSERT_MSG(!iter->second.isNull(), uFormat("Poses should not be null! Id=%d", iter->first).c_str());
optimizedPoses.insert(*iter);
}
else
{
UERROR("Pose %d from depthGraph not found in the poses map!", depthGraph.begin()->first);
}
} }
else else
{ {

View File

@@ -2614,7 +2614,8 @@ bool Memory::rehearsalMerge(int oldId, int newId)
UERROR("Didn't find neighbor %d of %d in RAM...", link.to(), oldS->id()); UERROR("Didn't find neighbor %d of %d in RAM...", link.to(), oldS->id());
} }
} }
newS->setLabel(oldS->getLabel());
oldS->setLabel("");
oldS->removeLinks(); // remove all links oldS->removeLinks(); // remove all links
oldS->addLink(Link(oldS->id(), newS->id(), Link::kGlobalClosure, Transform(), 1.0f, 1.0f)); // to keep track of the merged location oldS->addLink(Link(oldS->id(), newS->id(), Link::kGlobalClosure, Transform(), 1.0f, 1.0f)); // to keep track of the merged location
@@ -3840,7 +3841,10 @@ void Memory::getMetricConstraints(
{ {
Transform pose; Transform pose;
this->getPose(ids[i], pose, lookInDatabase); this->getPose(ids[i], pose, lookInDatabase);
poses.insert(std::make_pair(ids[i], pose)); if(!pose.isNull())
{
poses.insert(std::make_pair(ids[i], pose));
}
} }
for(unsigned int i=0; i<ids.size(); ++i) for(unsigned int i=0; i<ids.size(); ++i)
@@ -3850,7 +3854,7 @@ void Memory::getMetricConstraints(
std::map<int, Link> neighbors = this->getNeighborLinks(ids[i], lookInDatabase); // only direct neighbors std::map<int, Link> neighbors = this->getNeighborLinks(ids[i], lookInDatabase); // only direct neighbors
for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter) for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
{ {
if(uContains(poses, jter->first)) if(uContains(poses, jter->first) && jter->second.isValid())
{ {
bool edgeAlreadyAdded = false; bool edgeAlreadyAdded = false;
for(std::multimap<int, Link>::iterator iter = links.lower_bound(jter->first); for(std::multimap<int, Link>::iterator iter = links.lower_bound(jter->first);
@@ -3873,7 +3877,8 @@ void Memory::getMetricConstraints(
for(std::map<int, Link>::iterator jter=loops.begin(); jter!=loops.end(); ++jter) for(std::map<int, Link>::iterator jter=loops.begin(); jter!=loops.end(); ++jter)
{ {
if(jter->first < ids[i] && if(jter->first < ids[i] &&
uContains(poses, jter->first)) uContains(poses, jter->first) &&
jter->second.isValid()) // null transform means a child (rehearsed location)
{ {
links.insert(std::make_pair(ids[i],jter->second)); links.insert(std::make_pair(ids[i],jter->second));
} }

View File

@@ -835,12 +835,23 @@ cv::Mat disparityFromStereoImages(
const cv::Mat & rightImage) const cv::Mat & rightImage)
{ {
UASSERT(!leftImage.empty() && !rightImage.empty() && UASSERT(!leftImage.empty() && !rightImage.empty() &&
leftImage.type() == CV_8UC1 && rightImage.type() == CV_8UC1 && (leftImage.type() == CV_8UC1 || leftImage.type() == CV_8UC3) && rightImage.type() == CV_8UC1 &&
leftImage.cols == rightImage.cols && leftImage.cols == rightImage.cols &&
leftImage.rows == rightImage.rows); leftImage.rows == rightImage.rows);
cv::Mat leftMono;
if(leftImage.channels() == 3)
{
cv::cvtColor(leftImage, leftMono, CV_BGR2GRAY);
}
else
{
leftMono = leftImage;
}
cv::StereoBM stereo(cv::StereoBM::BASIC_PRESET, 0, 15); cv::StereoBM stereo(cv::StereoBM::BASIC_PRESET, 0, 15);
cv::Mat disparity; cv::Mat disparity;
stereo(leftImage, rightImage, disparity, CV_16SC1); stereo(leftMono, rightImage, disparity, CV_16SC1);
cv::filterSpeckles(disparity, 0, 1000, 16); cv::filterSpeckles(disparity, 0, 1000, 16);
return disparity; return disparity;
} }

View File

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

View File

@@ -53,6 +53,7 @@ namespace rtabmap
class Memory; class Memory;
class ImageView; class ImageView;
class Signature; class Signature;
class CloudViewer;
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
{ {
@@ -62,13 +63,18 @@ public:
DatabaseViewer(QWidget * parent = 0); DatabaseViewer(QWidget * parent = 0);
virtual ~DatabaseViewer(); virtual ~DatabaseViewer();
bool openDatabase(const QString & path); bool openDatabase(const QString & path);
bool isSavedMaximized() const {return savedMaximized_;}
protected: protected:
virtual void showEvent(QShowEvent* anEvent); virtual void showEvent(QShowEvent* anEvent);
virtual void moveEvent(QMoveEvent* anEvent);
virtual void resizeEvent(QResizeEvent* anEvent); virtual void resizeEvent(QResizeEvent* anEvent);
virtual void closeEvent(QCloseEvent* event); virtual void closeEvent(QCloseEvent* event);
virtual bool eventFilter(QObject *obj, QEvent *event);
private slots: private slots:
void writeSettings();
void configModified();
void openDatabase(); void openDatabase();
void generateGraph(); void generateGraph();
void exportDatabase(); void exportDatabase();
@@ -89,6 +95,7 @@ private slots:
void sliderNeighborValueChanged(int); void sliderNeighborValueChanged(int);
void sliderLoopValueChanged(int); void sliderLoopValueChanged(int);
void sliderIterationsValueChanged(int); void sliderIterationsValueChanged(int);
void updateGrid();
void updateGraphView(); void updateGraphView();
void refineConstraint(); void refineConstraint();
void refineConstraintVisually(); void refineConstraintVisually();
@@ -98,6 +105,9 @@ private slots:
void updateConstraintView(); void updateConstraintView();
private: private:
QString getIniFilePath() const;
void readSettings();
void updateIds(); void updateIds();
void update(int value, void update(int value,
QLabel * labelIndex, QLabel * labelIndex,
@@ -107,6 +117,7 @@ private:
QLabel * label, QLabel * label,
QLabel * stamp, QLabel * stamp,
rtabmap::ImageView * view, rtabmap::ImageView * view,
rtabmap::CloudViewer * view3D,
QLabel * labelId, QLabel * labelId,
bool updateConstraintView = true); bool updateConstraintView = true);
void updateStereo(const Signature * data); void updateStereo(const Signature * data);
@@ -145,7 +156,10 @@ private:
std::multimap<int, rtabmap::Link> linksRefined_; std::multimap<int, rtabmap::Link> linksRefined_;
std::multimap<int, rtabmap::Link> linksAdded_; std::multimap<int, rtabmap::Link> linksAdded_;
std::multimap<int, rtabmap::Link> linksRemoved_; 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 <QtGui/QGraphicsView>
#include <QtCore/QRectF> #include <QtCore/QRectF>
#include <QtCore/QMultiMap> #include <QtCore/QMultiMap>
#include <QtCore/QSettings>
#include <opencv2/features2d/features2d.hpp> #include <opencv2/features2d/features2d.hpp>
#include <map> #include <map>
@@ -51,6 +52,9 @@ public:
ImageView(QWidget * parent = 0); ImageView(QWidget * parent = 0);
virtual ~ImageView(); virtual ~ImageView();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
void resetZoom(); void resetZoom();
bool isImageShown() const; bool isImageShown() const;

View File

@@ -298,6 +298,8 @@ private:
QVector<int> _refIds; QVector<int> _refIds;
QVector<int> _loopClosureIds; 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/QWheelEvent>
#include <QtGui/QKeyEvent> #include <QtGui/QKeyEvent>
#include <QtGui/QColorDialog> #include <QtGui/QColorDialog>
#include <QtGui/QVector3D>
#include <set> #include <set>
#include <vtkRenderWindow.h> #include <vtkRenderWindow.h>
@@ -159,6 +160,92 @@ void CloudViewer::createMenu()
_menu->addAction(_aSetBackgroundColor); _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( bool CloudViewer::updateCloudPose(
const std::string & id, const std::string & id,
const Transform & pose) const Transform & pose)

View File

@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QBuffer> #include <QtCore/QBuffer>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtCore/QSettings>
#include <rtabmap/utilite/ULogger.h> #include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UDirectory.h> #include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UConversion.h> #include <rtabmap/utilite/UConversion.h>
@@ -65,7 +66,9 @@ namespace rtabmap {
DatabaseViewer::DatabaseViewer(QWidget * parent) : DatabaseViewer::DatabaseViewer(QWidget * parent) :
QMainWindow(parent), QMainWindow(parent),
memory_(0) memory_(0),
savedMaximized_(false),
firstCall_(true)
{ {
pathDatabase_ = QDir::homePath()+"/Documents/RTAB-Map"; //use home directory by default pathDatabase_ = QDir::homePath()+"/Documents/RTAB-Map"; //use home directory by default
@@ -77,24 +80,34 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
ui_ = new Ui_DatabaseViewer(); ui_ = new Ui_DatabaseViewer();
ui_->setupUi(this); ui_->setupUi(this);
QString title("RTAB-Map Database Viewer[*]");
this->setWindowTitle(title);
ui_->dockWidget_constraints->setVisible(false); ui_->dockWidget_constraints->setVisible(false);
ui_->dockWidget_graphView->setVisible(false); ui_->dockWidget_graphView->setVisible(false);
ui_->dockWidget_icp->setVisible(false); ui_->dockWidget_icp->setVisible(false);
ui_->dockWidget_visual->setVisible(false); ui_->dockWidget_visual->setVisible(false);
ui_->dockWidget_stereoView->setVisible(false); ui_->dockWidget_stereoView->setVisible(false);
ui_->dockWidget_icp->setFloating(true); ui_->dockWidget_view3d->setVisible(false);
ui_->dockWidget_visual->setFloating(true);
ui_->constraintsViewer->setCameraLockZ(false);
ui_->constraintsViewer->setCameraFree();
this->readSettings();
ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction()); ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction()); ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction()); ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction()); ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction());
ui_->menuView->addAction(ui_->dockWidget_stereoView->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_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateGraphView()));
connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close())); connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
connect(ui_->buttonBox, SIGNAL(rejected()), this, SLOT(close()));
// connect actions with custom slots // 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_->actionOpen_database, SIGNAL(triggered()), this, SLOT(openDatabase()));
connect(ui_->actionExport, SIGNAL(triggered()), this, SLOT(exportDatabase())); connect(ui_->actionExport, SIGNAL(triggered()), this, SLOT(exportDatabase()));
connect(ui_->actionExtract_images, SIGNAL(triggered()), this, SLOT(extractImages())); connect(ui_->actionExtract_images, SIGNAL(triggered()), this, SLOT(extractImages()));
@@ -144,16 +157,65 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
ui_->checkBox_showOptimized->setEnabled(false); ui_->checkBox_showOptimized->setEnabled(false);
ui_->horizontalSlider_iterations->setTracking(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(valueChanged(int)), this, SLOT(sliderIterationsValueChanged(int)));
connect(ui_->horizontalSlider_iterations, SIGNAL(sliderMoved(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_iterations, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->spinBox_optimizationsFrom, SIGNAL(valueChanged(int)), 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_initGuess, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreCovariance, 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); // connect configuration changed
ui_->constraintsViewer->setCameraFree(); 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() 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() void DatabaseViewer::openDatabase()
{ {
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), pathDatabase_, tr("Databases (*.db)")); QString path = QFileDialog::getOpenFileName(this, tr("Select file"), pathDatabase_, tr("Databases (*.db)"));
@@ -193,7 +399,7 @@ bool DatabaseViewer::openDatabase(const QString & path)
linksAdded_.clear(); linksAdded_.clear();
linksRefined_.clear(); linksRefined_.clear();
linksRemoved_.clear(); linksRemoved_.clear();
scans_.clear(); localMaps_.clear();
ui_->actionGenerate_TORO_graph_graph->setEnabled(false); ui_->actionGenerate_TORO_graph_graph->setEnabled(false);
ui_->checkBox_showOptimized->setEnabled(false); ui_->checkBox_showOptimized->setEnabled(false);
} }
@@ -228,6 +434,30 @@ bool DatabaseViewer::openDatabase(const QString & path)
void DatabaseViewer::closeEvent(QCloseEvent* event) 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()) if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size())
{ {
QMessageBox::StandardButton button = QMessageBox::question(this, 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_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio);
ui_->graphicsView_A->resetZoom(); ui_->graphicsView_A->resetZoom();
ui_->graphicsView_B->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) 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_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio);
ui_->graphicsView_A->resetZoom(); ui_->graphicsView_A->resetZoom();
ui_->graphicsView_B->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(); linksRemoved_.clear();
if(memory_->getLastWorkingSignature()) if(memory_->getLastWorkingSignature())
{ {
//get constraints only for parent links
memory_->getMetricConstraints(std::vector<int>(ids.begin(), ids.end()), poses_, links_, true); memory_->getMetricConstraints(std::vector<int>(ids.begin(), ids.end()), poses_, links_, true);
if(poses_.size()) if(poses_.size())
@@ -818,7 +1078,7 @@ void DatabaseViewer::detectMoreLoopClosures()
{ {
const std::map<int, Transform> & optimizedPoses = graphes_.back(); 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); UASSERT(iterations > 0);
int added = 0; int added = 0;
for(int n=0; n<iterations; ++n) for(int n=0; n<iterations; ++n)
@@ -973,6 +1233,7 @@ void DatabaseViewer::sliderAValueChanged(int value)
ui_->label_labelA, ui_->label_labelA,
ui_->label_stampA, ui_->label_stampA,
ui_->graphicsView_A, ui_->graphicsView_A,
ui_->widget_cloudA,
ui_->label_idA); ui_->label_idA);
} }
@@ -986,6 +1247,7 @@ void DatabaseViewer::sliderBValueChanged(int value)
ui_->label_labelB, ui_->label_labelB,
ui_->label_stampB, ui_->label_stampB,
ui_->graphicsView_B, ui_->graphicsView_B,
ui_->widget_cloudB,
ui_->label_idB); ui_->label_idB);
} }
@@ -997,6 +1259,7 @@ void DatabaseViewer::update(int value,
QLabel * label, QLabel * label,
QLabel * stamp, QLabel * stamp,
rtabmap::ImageView * view, rtabmap::ImageView * view,
rtabmap::CloudViewer * view3D,
QLabel * labelId, QLabel * labelId,
bool updateConstraintView) bool updateConstraintView)
{ {
@@ -1051,6 +1314,32 @@ void DatabaseViewer::update(int value,
{ {
this->updateStereo(&data); 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()) if(!imgDepth.isNull())
@@ -1522,6 +1811,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_labelA, ui_->label_labelA,
ui_->label_stampA, ui_->label_stampA,
ui_->graphicsView_A, ui_->graphicsView_A,
ui_->widget_cloudA,
ui_->label_idA, ui_->label_idA,
false); // don't update constraints view! false); // don't update constraints view!
} }
@@ -1535,6 +1825,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_labelB, ui_->label_labelB,
ui_->label_stampB, ui_->label_stampB,
ui_->graphicsView_B, ui_->graphicsView_B,
ui_->widget_cloudB,
ui_->label_idB, ui_->label_idB,
false); // don't update constraints view! false); // don't update constraints view!
} }
@@ -1773,31 +2064,99 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
{ {
if(memory_ && value >=0 && value < (int)graphes_.size()) 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 //update scans
UINFO("Update scans list..."); UINFO("Update local maps list...");
for(int i=0; i<ids_.size(); ++i) for(int i=0; i<ids_.size(); ++i)
{ {
Signature data = memory_->getSignatureData(ids_.at(i), false); UTimer time;
if(!data.getLaserScanCompressed().empty()) bool added = false;
if(ui_->checkBox_gridFromProjection->isChecked())
{ {
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; Signature data = memory_->getSignatureData(ids_.at(i), true);
cv::Mat laserScan = rtabmap::uncompressData(data.getLaserScanCompressed()); if(!data.getDepthRaw().empty())
cloud = rtabmap::util3d::laserScanToPointCloud(laserScan); {
scans_.insert(std::make_pair(ids_.at(i), cloud)); 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::map<int, rtabmap::Transform> & graph = uValueAt(graphes_, value);
std::multimap<int, Link> links = updateLinksWithModifications(links_); std::multimap<int, Link> links = updateLinksWithModifications(links_);
ui_->graphViewer->updateGraph(graph, links); ui_->graphViewer->updateGraph(graph, links);
if(graph.size() && scans_.size()) if(graph.size() && localMaps_.size())
{ {
float xMin, yMin; float xMin, yMin;
float cell = 0.05; float cell = ui_->doubleSpinBox_gridCellSize->value();
cv::Mat map = rtabmap::util3d::convertMap2Image8U(rtabmap::util3d::create2DMap(graph, scans_, cell, true, xMin, yMin)); cv::Mat map = rtabmap::util3d::convertMap2Image8U(rtabmap::util3d::create2DMapFromOccupancyLocalMaps(graph, localMaps_, cell, xMin, yMin));
ui_->graphViewer->updateMap(map, cell, xMin, yMin); ui_->graphViewer->updateMap(map, cell, xMin, yMin);
} }
ui_->label_iterations->setNum(value); ui_->label_iterations->setNum(value);
@@ -1858,12 +2217,25 @@ void DatabaseViewer::updateGraphView()
{ {
ui_->horizontalSlider_iterations->setMaximum(graphes_.size()-1); ui_->horizontalSlider_iterations->setMaximum(graphes_.size()-1);
ui_->horizontalSlider_iterations->setValue(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); sliderIterationsValueChanged(graphes_.size()-1);
} }
else 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; 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() void ExportCloudsDialog::restoreDefaults()
{ {
setAssemble(true); setAssemble(true);

View File

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

View File

@@ -486,6 +486,54 @@ void GraphViewer::clearAll()
clearGraph(); 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 bool GraphViewer::isGridMapVisible() const
{ {
return _gridMap->isVisible(); return _gridMap->isVisible();

View File

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

View File

@@ -74,6 +74,40 @@ ImageView::~ImageView() {
clear(); 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() void ImageView::resetZoom()
{ {
_zoom = _minZoom; _zoom = _minZoom;

View File

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

View File

@@ -57,6 +57,44 @@ PostProcessingDialog::~PostProcessingDialog()
delete _ui; 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() void PostProcessingDialog::restoreDefaults()
{ {
setDetectMoreLoopClosures(true); setDetectMoreLoopClosures(true);

View File

@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define POSTPROCESSINGDIALOG_H_ #define POSTPROCESSINGDIALOG_H_
#include <QtGui/QDialog> #include <QtGui/QDialog>
#include <QtCore/QSettings>
class Ui_PostProcessingDialog; class Ui_PostProcessingDialog;
class QAbstractButton; class QAbstractButton;
@@ -44,6 +45,9 @@ public:
virtual ~PostProcessingDialog(); virtual ~PostProcessingDialog();
void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = "");
//getters //getters
bool isDetectMoreLoopClosures() const; bool isDetectMoreLoopClosures() const;
double clusterRadius() 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/QDir>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QVector3D>
#include <QtGui/QFileDialog> #include <QtGui/QFileDialog>
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include <QtGui/QStandardItemModel> #include <QtGui/QStandardItemModel>
@@ -1750,90 +1749,23 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
if(cloudViewer) if(cloudViewer)
{ {
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ; cloudViewer->saveSettings(settings);
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());
} }
else if(imageView) else if(imageView)
{ {
settings.setValue("image_shown", imageView->isImageShown()); imageView->saveSettings(settings);
settings.setValue("depth_shown", imageView->isImageDepthShown());
settings.setValue("features_shown", imageView->isFeaturesShown());
settings.setValue("lines_shown", imageView->isLinesShown());
settings.setValue("alpha", imageView->getAlpha());
} }
else if(exportCloudsDialog) else if(exportCloudsDialog)
{ {
settings.setValue("assemble", exportCloudsDialog->getAssemble()); exportCloudsDialog->saveSettings(settings);
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());
} }
else if(postProcessingDialog) else if(postProcessingDialog)
{ {
settings.setValue("detect_more_lc", postProcessingDialog->isDetectMoreLoopClosures()); postProcessingDialog->saveSettings(settings);
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());
} }
else if(graphViewer) else if(graphViewer)
{ {
settings.setValue("node_radius", graphViewer->getNodeRadius()); graphViewer->saveSettings(settings);
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());
} }
else else
{ {
@@ -1862,78 +1794,23 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
if(cloudViewer) if(cloudViewer)
{ {
float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ; cloudViewer->loadSettings(settings);
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>());
} }
else if(imageView) else if(imageView)
{ {
imageView->setImageShown(settings.value("image_shown", imageView->isImageShown()).toBool()); imageView->loadSettings(settings);
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());
} }
else if(exportCloudsDialog) else if(exportCloudsDialog)
{ {
exportCloudsDialog->setAssemble(settings.value("assemble", exportCloudsDialog->getAssemble()).toBool()); exportCloudsDialog->loadSettings(settings);
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());
} }
else if(postProcessingDialog) else if(postProcessingDialog)
{ {
postProcessingDialog->setDetectMoreLoopClosures(settings.value("detect_more_lc", postProcessingDialog->isDetectMoreLoopClosures()).toBool()); postProcessingDialog->loadSettings(settings);
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());
} }
else if(graphViewer) else if(graphViewer)
{ {
graphViewer->setNodeRadius(settings.value("node_radius", graphViewer->getNodeRadius()).toDouble()); graphViewer->loadSettings(settings);
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());
} }
else else
{ {

View File

@@ -7,17 +7,14 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1187</width> <width>1187</width>
<height>862</height> <height>1018</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Database viewer</string> <string>Database viewer</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_7"> <layout class="QVBoxLayout" name="verticalLayout_7" stretch="2">
<property name="spacing">
<number>0</number>
</property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="rightMargin"> <property name="rightMargin">
@@ -335,13 +332,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QMenuBar" name="menubar"> <widget class="QMenuBar" name="menubar">
@@ -359,6 +349,8 @@
</property> </property>
<addaction name="actionOpen_database"/> <addaction name="actionOpen_database"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSave_config"/>
<addaction name="separator"/>
<addaction name="actionExport"/> <addaction name="actionExport"/>
<addaction name="actionExtract_images"/> <addaction name="actionExtract_images"/>
<addaction name="separator"/> <addaction name="separator"/>
@@ -403,10 +395,7 @@
<widget class="rtabmap::CloudViewer" name="constraintsViewer" native="true"/> <widget class="rtabmap::CloudViewer" name="constraintsViewer" native="true"/>
</item> </item>
<item> <item>
<layout class="QFormLayout" name="formLayout"> <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,1">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@@ -441,6 +430,20 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="3" column="0">
<widget class="QLabel" name="label_16"> <widget class="QLabel" name="label_16">
<property name="text"> <property name="text">
@@ -455,6 +458,20 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="5" column="0">
<widget class="QCheckBox" name="checkBox_showOptimized"> <widget class="QCheckBox" name="checkBox_showOptimized">
<property name="text"> <property name="text">
@@ -483,34 +500,6 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item> <item>
@@ -602,15 +591,79 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QFormLayout" name="formLayout_2"> <layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<item row="0" column="0"> <item row="1" column="1">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>TORO iterations:</string> <string>TORO iterations</string>
</property> </property>
</widget> </widget>
</item> </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"> <widget class="QSpinBox" name="spinBox_iterations">
<property name="suffix"> <property name="suffix">
<string/> <string/>
@@ -626,55 +679,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_8"> <widget class="QCheckBox" name="checkBox_gridFromProjection">
<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">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Initial tree guess:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <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"> <widget class="QCheckBox" name="checkBox_ignoreCovariance">
<property name="text"> <property name="text">
<string/> <string/>
@@ -684,12 +699,81 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_icp"> <widget class="QDockWidget" name="dockWidget_icp">
<property name="floating">
<bool>true</bool>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>ICP parameters</string> <string>ICP parameters</string>
</property> </property>
@@ -699,22 +783,64 @@
<widget class="QWidget" name="dockWidgetContents_3"> <widget class="QWidget" name="dockWidgetContents_3">
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_11">
<item> <item>
<layout class="QGridLayout" name="gridLayout_4" columnminimumwidth="1,0"> <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
<item row="4" column="0"> <item row="4" column="1">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
<string>Iteration</string> <string>Iteration</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="1">
<widget class="QLabel" name="label_14"> <widget class="QLabel" name="label_14">
<property name="text"> <property name="text">
<string>Decimation</string> <string>Decimation</string>
</property> </property>
</widget> </widget>
</item> </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"> <widget class="QSpinBox" name="spinBox_icp_decimation">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -728,13 +854,6 @@
</widget> </widget>
</item> </item>
<item row="1" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxDepth">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -751,13 +870,6 @@
</widget> </widget>
</item> </item>
<item row="2" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_icp_voxel">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -774,13 +886,6 @@
</widget> </widget>
</item> </item>
<item row="3" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_icp_maxCorrespDistance">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -799,7 +904,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="0">
<widget class="QSpinBox" name="spinBox_icp_iteration"> <widget class="QSpinBox" name="spinBox_icp_iteration">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -812,31 +917,7 @@
</property> </property>
</widget> </widget>
</item> </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"> <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"> <widget class="QSpinBox" name="spinBox_icp_normalKSearch">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -849,14 +930,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_27"> <widget class="QCheckBox" name="checkBox_icp_p2plane">
<property name="text"> <property name="text">
<string>2D icp</string> <string/>
</property>
<property name="checked">
<bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="7" column="0">
<widget class="QCheckBox" name="checkBox_icp_2d"> <widget class="QCheckBox" name="checkBox_icp_2d">
<property name="text"> <property name="text">
<string/> <string/>
@@ -885,6 +969,9 @@
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_visual"> <widget class="QDockWidget" name="dockWidget_visual">
<property name="floating">
<bool>true</bool>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Visual parameters</string> <string>Visual parameters</string>
</property> </property>
@@ -894,15 +981,85 @@
<widget class="QWidget" name="dockWidgetContents_4"> <widget class="QWidget" name="dockWidgetContents_4">
<layout class="QVBoxLayout" name="verticalLayout_10"> <layout class="QVBoxLayout" name="verticalLayout_10">
<item> <item>
<layout class="QGridLayout" name="gridLayout_3" columnminimumwidth="1,0"> <layout class="QGridLayout" name="gridLayout_3" columnstretch="0,1">
<item row="0" column="0"> <item row="0" column="1">
<widget class="QLabel" name="label_24"> <widget class="QLabel" name="label_24">
<property name="text"> <property name="text">
<string>Recompute features (SURF)</string> <string>Recompute features (SURF)</string>
</property> </property>
</widget> </widget>
</item> </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"> <widget class="QCheckBox" name="checkBox_visual_recomputeFeatures">
<property name="text"> <property name="text">
<string/> <string/>
@@ -912,14 +1069,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_25"> <widget class="QCheckBox" name="checkBox_visual_2d">
<property name="text"> <property name="text">
<string>SURF hessian threshold</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_visual_hessian"> <widget class="QDoubleSpinBox" name="doubleSpinBox_visual_hessian">
<property name="suffix"> <property name="suffix">
<string/> <string/>
@@ -939,13 +1096,6 @@
</widget> </widget>
</item> </item>
<item row="3" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_visual_nndr">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -968,13 +1118,6 @@
</widget> </widget>
</item> </item>
<item row="4" column="0"> <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"> <widget class="QSpinBox" name="spinBox_visual_minCorrespondences">
<property name="minimum"> <property name="minimum">
<number>3</number> <number>3</number>
@@ -988,13 +1131,6 @@
</widget> </widget>
</item> </item>
<item row="5" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_visual_maxCorrespDistance">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -1014,13 +1150,6 @@
</widget> </widget>
</item> </item>
<item row="6" column="0"> <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"> <widget class="QSpinBox" name="spinBox_visual_iteration">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@@ -1034,13 +1163,6 @@
</widget> </widget>
</item> </item>
<item row="7" column="0"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_visual_maxDepth">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -1056,35 +1178,7 @@
</property> </property>
</widget> </widget>
</item> </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"> <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"> <widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_radius">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -1103,7 +1197,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="9" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_angle"> <widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_angle">
<property name="suffix"> <property name="suffix">
<string> degrees</string> <string> degrees</string>
@@ -1123,14 +1217,7 @@
</widget> </widget>
</item> </item>
<item row="10" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_31"> <widget class="QSpinBox" name="spinBox_detectMore_iterations">
<property name="text">
<string>Detect more LCs: iterations</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="doubleSpinBox_detectMore_iterations">
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
</property> </property>
@@ -1178,6 +1265,24 @@
</layout> </layout>
</widget> </widget>
</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"> <action name="actionOpen_database">
<property name="text"> <property name="text">
<string>Open database</string> <string>Open database</string>
@@ -1268,6 +1373,11 @@
<string>Visual: Refine all loop closure links...</string> <string>Visual: Refine all loop closure links...</string>
</property> </property>
</action> </action>
<action name="actionSave_config">
<property name="text">
<string>Save config</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>