Multi component view (#1729)

* Multi component view implemented except for rotations. Rotations can cause segfaults.

* Implemented: handling rotations and applied rotations on optimized poses. Addition of a notion of main component (for saves in db) abd a node selection tool.

* New feature: merge component using selected nodes

* Refactored with suggestions.

* Fixing QSet error on older Qt versions

---------

Co-authored-by: matlabbe <[email protected]>
This commit is contained in:
Pierre ELIS
2026-08-01 08:33:53 -07:00
committed by GitHub
co-authored by matlabbe
parent d9f3337f97
commit bef4eaf679
11 changed files with 1525 additions and 441 deletions
+40 -2
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QMainWindow>
#include <QtCore/QByteArray>
#include <QtCore/QMap>
#include <QtCore/QPointF>
#include <QtCore/QSet>
#include <QtGui/QImage>
#include <opencv2/core/core.hpp>
@@ -71,6 +72,24 @@ class EditMapArea;
class LinkRefiningDialog;
class Registration;
class RegistrationIcp;
class ExportDialog;
class GraphComponent
{
public:
GraphComponent() : id(0), rootId(0), firstNodeId(0), lastNodeId(0), rotationValue(0), viewScale(-1.0f), optimizationFlavor(0) {}
int id;
int rootId;
int firstNodeId;
int lastNodeId;
int rotationValue;
QPointF rootCoordinates;
float viewScale;
std::set<int> nodeIds;
std::set<int> selectedNodeIds;
int optimizationFlavor;
};
class RTABMAP_GUI_EXPORT DatabaseViewer : public QMainWindow
{
@@ -85,6 +104,10 @@ public:
protected:
virtual void showEvent(QShowEvent* anEvent);
private:
void backupCurrentComponent();
virtual void moveEvent(QMoveEvent* anEvent);
virtual void resizeEvent(QResizeEvent* anEvent);
virtual void keyPressEvent(QKeyEvent *event);
@@ -92,6 +115,7 @@ protected:
virtual bool eventFilter(QObject *obj, QEvent *event);
private Q_SLOTS:
void updateGraphInteractionMode();
void writeSettings();
void restoreDefaultSettings();
void configModified();
@@ -131,6 +155,7 @@ private Q_SLOTS:
void view3DMap();
void generate3DMap();
void detectMoreLoopClosures();
void mergeComponents();
void updateAllNeighborCovariances();
void updateAllLoopClosureCovariances();
void updateAllLandmarkCovariances();
@@ -138,6 +163,7 @@ private Q_SLOTS:
void resetAllChanges();
void graphNodeSelected(int);
void graphLinkSelected(int, int);
void zoomToNode();
void sliderAValueChanged(int);
void sliderBValueChanged(int);
void sliderAMoved(int);
@@ -146,6 +172,7 @@ private Q_SLOTS:
void sliderNeighborValueChanged(int);
void sliderLoopValueChanged(int);
void sliderIterationsValueChanged(int);
void updateGraphViewRootId();
void editConstraint();
void updateGrid();
void updateOctomapView();
@@ -161,6 +188,12 @@ private Q_SLOTS:
void notifyParametersChanged(const QStringList &);
void setupMainLayout(bool vertical);
void updateConstraintButtons();
void optimizationIgnoredStateChanged();
void fitInViewClicked();
void tabBarComponentsValueChanged(int);
void regenerateGraphComponents();
void updateComponentSelectedNodes();
void clearAllSelectedNodes();
private:
QString getIniFilePath() const;
@@ -175,7 +208,7 @@ private:
QLabel * label,
QLabel * stamp,
rtabmap::ImageView * view,
QLabel * labelId,
QToolButton * buttonNodeId,
QLabel * labelMapId,
QLabel * labelPose,
QLabel * labelOptPose,
@@ -205,7 +238,8 @@ private:
std::multimap<int, rtabmap::Link> updateLinksWithModifications(
const std::multimap<int, rtabmap::Link> & edgeConstraints);
void updateNeighborsSlider(int from = 0, int to = 0);
void updateLoopClosuresSlider(int from = 0, int to = 0);
void updateLoopClosuresSlider(int from, int to);
void updateLoopClosuresSlider();
void updateCovariances(const QList<Link> & links);
void refineLinks(const QList<Link> & links);
void refineConstraint(int from, int to, Registration * reg, RegistrationIcp * regIcp, bool silent);
@@ -234,6 +268,9 @@ private:
std::string databaseFileName_;
std::list<std::map<int, rtabmap::Transform> > graphes_;
std::multimap<int, rtabmap::Link> graphLinks_;
std::vector<GraphComponent> components_;
int activeComponentIndex_;
int lastValidNodeId_;
std::map<int, rtabmap::Transform> odomPoses_;
std::map<int, rtabmap::Transform> groundTruthPoses_;
std::map<int, rtabmap::Transform> gpsPoses_;
@@ -253,6 +290,7 @@ private:
QDialog * editMapDialog_;
EditMapArea * editMapArea_;
LinkRefiningDialog * linkRefiningDialog_;
ExportDialog * exportDataDialog_;
bool savedMaximized_;
bool firstCall_;
@@ -53,6 +53,8 @@ public:
int framesIgnored() const;
double targetFramerate() const;
int sessionExported() const;
bool currentComponentOnly() const;
bool selectedNodesOnly() const;
bool isRgbExported() const;
bool isDepthExported() const;
bool isDepth2dExported() const;
+9
View File
@@ -57,6 +57,7 @@ class RTABMAP_GUI_EXPORT GraphViewer : public QGraphicsView {
public:
enum ViewPlane {XY, XZ, YZ};
enum InteractionMode {HandMode, SelectionMode};
public:
GraphViewer(QWidget * parent = 0);
@@ -172,14 +173,21 @@ public:
void setOdomCacheOverlayVisible(bool visible);
void setOrientationENU(bool enabled);
void setViewPlane(ViewPlane plane);
void setInteractionMode(InteractionMode mode);
InteractionMode getInteractionMode() const {return _interactionMode;}
std::set<int> getSelectedNodeIds();
void selectNodesFromIds(const std::set<int> & ids);
void setEnsureFrameVisible(bool visible);
void setFastZoomMinNodes(int value);
QPointF getNodeScenePosition(int id) const;
void centerOnNode(int id);
Q_SIGNALS:
void configChanged();
void mapShownRequested();
void nodeSelected(int);
void linkSelected(int, int);
void nodesSelected(); // Nodes selected by rubber band, call getSelectedNodeIds() to get ids selected
public Q_SLOTS:
void restoreDefaults();
@@ -253,6 +261,7 @@ private:
bool _orientationENU;
bool _mouseTracking;
ViewPlane _viewPlane;
InteractionMode _interactionMode;
bool _ensureFrameVisible;
QPoint _previousMousePos;
QPoint _initialMousePos;
@@ -52,9 +52,13 @@ public:
int nodeIdMax,
int mapIdMin,
int mapIdMax);
void setRangesEnabled(bool selectedNodes, bool currentComponent);
Link::Type getLinkType() const;
void getIntraInterSessions(bool & intra, bool & inter) const;
bool isRangeByCurrentComponent() const;
bool isRangeBySelectedNodeIds() const;
bool isRangeByNodeId() const;
bool isRangeByMapId() const;
void getRangeNodeId(int & from, int & to) const;
File diff suppressed because it is too large Load Diff
+17
View File
@@ -47,6 +47,7 @@ ExportDialog::ExportDialog(QWidget * parent) :
connect(_ui->spinBox_ignored, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_framerate, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->spinBox_session, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_selected_nodes, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_rgb, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_depth, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_depth2d, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
@@ -70,6 +71,8 @@ void ExportDialog::saveSettings(QSettings & settings, const QString & group) con
settings.setValue("framesIgnored", this->framesIgnored());
settings.setValue("targetFramerate", this->targetFramerate());
settings.setValue("sessionExported", this->sessionExported());
settings.setValue("currentComponentOnly", this->currentComponentOnly());
settings.setValue("selectedNodesOnly", this->selectedNodesOnly());
settings.setValue("rgbExported", this->isRgbExported());
settings.setValue("depthExported", this->isDepthExported());
settings.setValue("depth2dExported", this->isDepth2dExported());
@@ -90,6 +93,8 @@ void ExportDialog::loadSettings(QSettings & settings, const QString & group)
_ui->spinBox_ignored->setValue(settings.value("framesIgnored", this->framesIgnored()).toInt());
_ui->doubleSpinBox_framerate->setValue(settings.value("targetFramerate", this->targetFramerate()).toDouble());
_ui->spinBox_session->setValue(settings.value("sessionExported", this->sessionExported()).toInt());
_ui->checkBox_current_component->setChecked(settings.value("currentComponentOnly", this->currentComponentOnly()).toBool());
_ui->checkBox_selected_nodes->setChecked(settings.value("selectedNodesOnly", this->selectedNodesOnly()).toBool());
_ui->checkBox_rgb->setChecked(settings.value("rgbExported", this->isRgbExported()).toBool());
_ui->checkBox_depth->setChecked(settings.value("depthExported", this->isDepthExported()).toBool());
_ui->checkBox_depth2d->setChecked(settings.value("depth2dExported", this->isDepth2dExported()).toBool());
@@ -106,6 +111,8 @@ void ExportDialog::restoreDefaults()
_ui->spinBox_ignored->setValue(0);
_ui->doubleSpinBox_framerate->setValue(0);
_ui->spinBox_session->setValue(-1);
_ui->checkBox_current_component->setChecked(false);
_ui->checkBox_selected_nodes->setChecked(false);
_ui->checkBox_rgb->setChecked(true);
_ui->checkBox_depth->setChecked(true);
_ui->checkBox_depth2d->setChecked(true);
@@ -142,6 +149,16 @@ int ExportDialog::sessionExported() const
return _ui->spinBox_session->value();
}
bool ExportDialog::currentComponentOnly() const
{
return _ui->checkBox_current_component->isChecked();
}
bool ExportDialog::selectedNodesOnly() const
{
return _ui->checkBox_selected_nodes->isChecked();
}
bool ExportDialog::isRgbExported() const
{
return _ui->checkBox_rgb->isChecked();
+71 -1
View File
@@ -342,6 +342,7 @@ GraphViewer::GraphViewer(QWidget * parent) :
_orientationENU(false),
_mouseTracking(false),
_viewPlane(XY),
_interactionMode(HandMode),
_ensureFrameVisible(true),
_previousMousePos(-1,-1),
_initialMousePos(-1,-1),
@@ -388,6 +389,7 @@ void GraphViewer::setupGraphicsScene()
_zoomOverlayItem->setVisible(false);
_zoomOverlayItem->setAcceptedMouseButtons(Qt::NoButton);
_zoomOverlayItem->setAcceptHoverEvents(false);
connect(this->scene(), &QGraphicsScene::selectionChanged, this, &GraphViewer::nodesSelected);
_world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
_root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
@@ -664,6 +666,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
item->setZValue(iter->first<0?21:20);
item->setColor(color);
item->setParentItem(_graphRoot);
item->setFlag(QGraphicsItem::ItemIsSelectable, iter->first>0 && _interactionMode == SelectionMode);
item->show();
_nodeItems.insert(iter->first, item);
++iter;
@@ -674,6 +677,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
// NodeItem exists for the pose, copy data and increase both iterators
UASSERT(iter->first == nter.key());
nter.value()->setColor(color); // reset color
nter.value()->setFlag(QGraphicsItem::ItemIsSelectable, iter->first > 0 && _interactionMode == SelectionMode);
nter.value()->setToolTipInfo(QString());
nter.value()->setZValue(iter->first<0?21:20);
nter.value()->setPose(iter->second, _viewPlane);
@@ -937,6 +941,7 @@ void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
item->setZValue(20);
item->setColor(_gtPathColor);
item->setParentItem(_gtGraphRoot);
item->setFlag(QGraphicsItem::ItemIsSelectable, false);
item->setVisible(_nodeVisible);
_gtNodeItems.insert(iter->first, item);
}
@@ -1071,6 +1076,7 @@ void GraphViewer::updateGPSGraph(
item->setZValue(20);
item->setColor(_gpsPathColor);
item->setParentItem(_gpsGraphRoot);
item->setFlag(QGraphicsItem::ItemIsSelectable, false);
item->setVisible(_nodeVisible);
_gpsNodeItems.insert(iter->first, item);
}
@@ -1453,6 +1459,48 @@ void GraphViewer::highlightNode(int nodeId, int highlightIndex)
}
}
std::set<int> GraphViewer::getSelectedNodeIds()
{
std::set<int> ids;
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter != _nodeItems.end(); iter++)
{
if(iter.value() && iter.value()->isSelected())
ids.insert(iter.key());
}
return ids;
}
void GraphViewer::selectNodesFromIds(const std::set<int> & ids)
{
this->scene()->blockSignals(true);
for (QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter != _nodeItems.end(); ++iter)
{
if(iter.value() && iter.key()>0)
iter.value()->setSelected(ids.find(iter.key()) != ids.end());
}
this->scene()->blockSignals(false);
}
void GraphViewer::setInteractionMode(InteractionMode mode)
{
if(_interactionMode == mode)
{
return;
}
_interactionMode = mode;
this->setDragMode(mode == HandMode ? QGraphicsView::ScrollHandDrag : QGraphicsView::RubberBandDrag);
this->setRubberBandSelectionMode(Qt::IntersectsItemShape);
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter != _nodeItems.end(); iter++)
{
if(iter.key()>0 && iter.value())
{
iter.value()->setFlag(QGraphicsItem::ItemIsSelectable, mode == SelectionMode);
}
}
}
void GraphViewer::clearGraph()
{
qDeleteAll(_nodeItems);
@@ -1566,6 +1614,7 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
settings.setValue("odom_cache_overlay", this->isOdomCacheOverlayVisible());
settings.setValue("orientation_ENU", this->isOrientationENU());
settings.setValue("view_plane", (int)this->getViewPlane());
settings.setValue("interaction_mode", (int)this->getInteractionMode());
settings.setValue("ensure_frame_visible", (int)this->isEnsureFrameVisible());
settings.setValue("fast_zoom_min_nodes", this->getFastZoomMinNodes());
if(!group.isEmpty())
@@ -1618,6 +1667,7 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
this->setOdomCacheOverlayVisible(settings.value("odom_cache_overlay", this->isOdomCacheOverlayVisible()).toBool());
this->setOrientationENU(settings.value("orientation_ENU", this->isOrientationENU()).toBool());
this->setViewPlane((ViewPlane)settings.value("view_plane", (int)this->getViewPlane()).toInt());
this->setInteractionMode((InteractionMode)settings.value("interaction_mode", (int)this->getInteractionMode()).toInt());
this->setEnsureFrameVisible(settings.value("ensure_frame_visible", this->isEnsureFrameVisible()).toBool());
this->setFastZoomMinNodes(settings.value("fast_zoom_min_nodes", this->getFastZoomMinNodes()).toInt());
if(!group.isEmpty())
@@ -2087,6 +2137,7 @@ void GraphViewer::restoreDefaults()
setLocalPathVisible(true);
setGtGraphVisible(true);
setFastZoomMinNodes(0);
setInteractionMode(HandMode);
}
void GraphViewer::wheelEvent(QWheelEvent * event)
@@ -2123,7 +2174,7 @@ void GraphViewer::mouseMoveEvent(QMouseEvent * event)
{
QToolTip::hideText();
}
if (event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier) && event->buttons() & Qt::LeftButton) {
if (_interactionMode == HandMode && event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier) && event->buttons() & Qt::LeftButton) {
// same modifiers than 3D view, change zoom
if(_previousMousePos.y()!=0) {
qreal factor = (event->pos().y() - _previousMousePos.y() > 0) ? 0.98 : 1.02;
@@ -2200,6 +2251,25 @@ QIcon createIcon(const QColor & color)
return QIcon(pixmap);
}
QPointF GraphViewer::getNodeScenePosition(int id) const
{
NodeItem * item = _nodeItems.value(id, 0);
if(item)
{
return item->sceneBoundingRect().center();
}
return QPointF();
}
void GraphViewer::centerOnNode(int id)
{
QPointF center = this->getNodeScenePosition(id);
if(!center.isNull())
{
this->centerOn(center);
}
}
void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
QMenu menu;
+24
View File
@@ -87,6 +87,20 @@ void LinkRefiningDialog::setMinMax(
restoreDefaults();
}
}
void LinkRefiningDialog::setRangesEnabled(bool selectedNodes, bool currentComponent)
{
ui_->radioButton_selected_nodes->setEnabled(selectedNodes);
if(!selectedNodes && ui_->radioButton_selected_nodes->isChecked())
{
ui_->radioButton_nodes->setChecked(true);
}
ui_->radioButton_current_component->setEnabled(currentComponent);
if(!currentComponent && ui_->radioButton_current_component->isChecked())
{
ui_->radioButton_nodes->setChecked(true);
}
}
Link::Type LinkRefiningDialog::getLinkType() const
{
@@ -103,6 +117,16 @@ void LinkRefiningDialog::getIntraInterSessions(bool & intra, bool & inter) const
inter = ui_->comboBox_link_inter_intra->currentIndex() == 0 || ui_->comboBox_link_inter_intra->currentIndex() == 2;
}
bool LinkRefiningDialog::isRangeByCurrentComponent() const
{
return ui_->radioButton_current_component->isChecked();
}
bool LinkRefiningDialog::isRangeBySelectedNodeIds() const
{
return ui_->radioButton_selected_nodes->isChecked();
}
bool LinkRefiningDialog::isRangeByNodeId() const
{
return ui_->radioButton_nodes->isChecked();
+336 -171
View File
@@ -61,7 +61,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>364</width>
<width>344</width>
<height>389</height>
</rect>
</property>
@@ -392,7 +392,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>364</width>
<width>343</width>
<height>389</height>
</rect>
</property>
@@ -752,10 +752,19 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_idA">
<widget class="QToolButton" name="button_nodeIdA">
<property name="toolTip">
<string>Click to locate in Graph View</string>
</property>
<property name="text">
<string>idA</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@@ -835,10 +844,19 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_idB">
<widget class="QToolButton" name="button_nodeIdB">
<property name="toolTip">
<string>Click to locate in Graph View</string>
</property>
<property name="text">
<string>idB</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@@ -914,10 +932,10 @@
<addaction name="actionRestore_default_GUI_settings"/>
<addaction name="separator"/>
<addaction name="actionGenerate_3D_map_pcd"/>
<addaction name="actionExport"/>
<addaction name="actionExtract_images"/>
<addaction name="menuExport_poses"/>
<addaction name="menuExport_GPS"/>
<addaction name="actionExport"/>
<addaction name="separator"/>
<addaction name="actionEdit_optimized_2D_map"/>
<addaction name="actionExport_saved_2D_map"/>
@@ -937,6 +955,7 @@
<addaction name="actionGenerate_graph_dot"/>
<addaction name="actionGenerate_local_graph_dot"/>
<addaction name="separator"/>
<addaction name="actionMerge_components_using_selected_nodes"/>
<addaction name="actionDetect_more_loop_closures"/>
<addaction name="actionRefine_links"/>
<addaction name="actionUpdate_all_neighbor_covariances"/>
@@ -948,6 +967,7 @@
<addaction name="separator"/>
<addaction name="actionEdit_depth_image"/>
<addaction name="separator"/>
<addaction name="actionClear_all_selected_nodes"/>
<addaction name="actionReset_all_changes"/>
<addaction name="separator"/>
<addaction name="actionView_3D_map"/>
@@ -1198,7 +1218,17 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QHBoxLayout" name="horizontalLayout_23">
<item>
<widget class="QCheckBox" name="checkBox_optimize_on_all_changes">
<property name="toolTip">
<string>Re-optimize the graph right away after using any of these actions</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_refine">
<property name="toolTip">
@@ -1217,20 +1247,44 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_add">
<property name="text">
<string>Add</string>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_enableForAll">
<property name="toolTip">
<string>Enable &quot;Add&quot; for all nodes (even not in graph)</string>
</property>
<property name="text">
<string/>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButton_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_enableForAll">
<property name="toolTip">
<string>Enable &quot;Add&quot; for all nodes (even not in graph)</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -1247,7 +1301,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<width>13</width>
<height>20</height>
</size>
</property>
@@ -1267,9 +1321,74 @@
</attribute>
<widget class="QWidget" name="dockWidget_graphContents">
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_21">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Interaction mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_graphHand">
<property name="text">
<string>Hand / Move</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_graphSelection">
<property name="text">
<string>Selection</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="rtabmap::GraphViewer" name="graphViewer"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_22" stretch="0,1">
<item>
<widget class="QLabel" name="graphComponentText">
<property name="text">
<string>Graph component</string>
</property>
</widget>
</item>
<item>
<widget class="QTabBar" name="tabBar_components" native="true">
<property name="documentMode" stdset="0">
<bool>true</bool>
</property>
<property name="usesScrollButtons" stdset="0">
<bool>true</bool>
</property>
<property name="expanding" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="widget_graphControl" native="true">
<layout class="QVBoxLayout" name="verticalLayout_61">
@@ -1292,6 +1411,9 @@
<layout class="QVBoxLayout" name="verticalLayout_91">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_rotation">
<property name="text">
@@ -1337,7 +1459,13 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<layout class="QHBoxLayout" name="horizontalLayout_20"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0,0,0">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_iterations">
<property name="text">
@@ -1380,10 +1508,23 @@
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_fit_in_view">
<property name="toolTip">
<string>After any graph changes, re-zoom to fit the whole map in the view</string>
</property>
<property name="text">
<string>Fit in view</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="1" column="1">
<widget class="QLabel" name="label_alignPosesWithGPS">
<property name="text">
@@ -1467,6 +1608,9 @@
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0,1">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_optimizeFrom">
<property name="text">
@@ -1722,7 +1866,7 @@
<item>
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="page_3">
<property name="geometry">
@@ -1737,8 +1881,25 @@
<string>Graph optimization</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7" columnstretch="0,0,0">
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_ignoreGlobalLoop">
<item row="1" column="2">
<widget class="QLabel" name="label_35">
<property name="text">
<string>Ignore pose correction</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLandmarks">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_ignoreUserLoop">
<property name="text">
<string/>
</property>
@@ -1754,16 +1915,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopSpace">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_48">
<property name="text">
@@ -1771,15 +1922,8 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_35">
<property name="text">
<string>Ignore pose correction</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_ignorePoseCorrection">
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_ignoreGlobalLoop">
<property name="text">
<string/>
</property>
@@ -1788,13 +1932,10 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopTime">
<item row="6" column="2">
<widget class="QLabel" name="label_58">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
<string>Ignore landmarks</string>
</property>
</widget>
</item>
@@ -1811,8 +1952,15 @@
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_ignoreUserLoop">
<item row="3" column="2">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Ignore local loop closures (space)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopSpace">
<property name="text">
<string/>
</property>
@@ -1828,20 +1976,6 @@
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Ignore local loop closures (space)</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_scale_title">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_optimizationScale">
<property name="decimals">
@@ -1861,15 +1995,25 @@
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="label_58">
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopTime">
<property name="text">
<string>Ignore landmarks</string>
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLandmarks">
<item row="0" column="2">
<widget class="QLabel" name="label_scale_title">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_ignorePoseCorrection">
<property name="text">
<string/>
</property>
@@ -2604,7 +2748,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-175</y>
<y>0</y>
<width>403</width>
<height>319</height>
</rect>
@@ -2613,54 +2757,13 @@
<string>Detect more loop closures</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_10" columnstretch="0,1">
<item row="2" column="1">
<widget class="QLabel" name="label_30">
<item row="3" column="1">
<widget class="QLabel" name="label_31">
<property name="text">
<string>Angle</string>
<string>Iterations</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Inter-session</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_detectMore_interSession">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Radius Max</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_32">
<property name="text">
<string>Intra-session</string>
</property>
</widget>
</item>
<item row="9" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_angle">
<property name="suffix">
@@ -2680,10 +2783,29 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Radius Min</string>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_fromToMapId">
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_minGraphDistance">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
@@ -2700,6 +2822,39 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_detectMore_interSession">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_radius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Inter-session</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_38">
<property name="text">
@@ -2707,20 +2862,23 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_31">
<property name="text">
<string>Iterations</string>
<item row="9" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBox_opt_graph_as_guess">
<item row="0" column="1">
<widget class="QLabel" name="label_29">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
<string>Radius Max</string>
</property>
</widget>
</item>
@@ -2750,6 +2908,16 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkBox_opt_graph_as_guess">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_37">
<property name="text">
@@ -2760,38 +2928,6 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_detectMore_radius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_fromToMapId">
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_40">
<property name="text">
@@ -2799,16 +2935,24 @@
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QSpinBox" name="spinBox_minGraphDistance">
<property name="minimum">
<number>1</number>
<item row="2" column="1">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Angle</string>
</property>
<property name="maximum">
<number>9999</number>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_32">
<property name="text">
<string>Intra-session</string>
</property>
<property name="value">
<number>10</number>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Radius Min</string>
</property>
</widget>
</item>
@@ -3021,7 +3165,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>0</width>
<height>20</height>
</size>
</property>
@@ -3391,7 +3535,7 @@
</action>
<action name="actionGenerate_3D_map_pcd">
<property name="text">
<string>Export 3D map (*.ply *.pcd) ...</string>
<string>Export 3D map (*.ply *.pcd)...</string>
</property>
</action>
<action name="actionExport">
@@ -3557,6 +3701,9 @@
<property name="text">
<string>Update optimized mesh...</string>
</property>
<property name="toolTip">
<string>Available only for the Main component</string>
</property>
</action>
<action name="actionUpdate_all_neighbor_covariances">
<property name="text">
@@ -3585,6 +3732,9 @@
<property name="text">
<string>Regenerate optimized 2D map...</string>
</property>
<property name="toolTip">
<string>Available only for the Main component</string>
</property>
</action>
<action name="actionRGBD_SLAM_ID_format_txt">
<property name="text">
@@ -3596,6 +3746,16 @@
<string>Update all landmark covariances...</string>
</property>
</action>
<action name="actionMerge_components_using_selected_nodes">
<property name="text">
<string>Merge components...</string>
</property>
</action>
<action name="actionClear_all_selected_nodes">
<property name="text">
<string>Clear all selected nodes</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
@@ -3620,6 +3780,11 @@
<header>../include/rtabmap/gui/ParametersToolBox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QTabBar</class>
<extends>QWidget</extends>
<header>qtabbar.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
+180 -159
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>331</height>
<width>333</width>
<height>520</height>
</rect>
</property>
<property name="windowTitle">
@@ -15,178 +15,199 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSpinBox" name="spinBox_ignored">
<property name="suffix">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Frames ignored</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_framerate">
<property name="suffix">
<string> Hz</string>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Target frame rate</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="spinBox_session">
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Mapping session (-1 = all)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBox_rgb">
<property name="text">
<string>RGB images</string>
</property>
<property name="checked">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Selection</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_session">
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Mapping session (-1 = all)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_selected_nodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Selected nodes</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Current component only</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_current_component">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_depth">
<property name="text">
<string>Depth images</string>
</property>
<property name="checked">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Filtering</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_ignored">
<property name="suffix">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>Nodes ignored</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_framerate">
<property name="suffix">
<string> Hz</string>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Target frame rate</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_depth2d">
<property name="text">
<string>Laser scans</string>
</property>
<property name="checked">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Data</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="checkBox_rgb">
<property name="text">
<string>RGB images</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_depth">
<property name="text">
<string>Depth images</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_depth2d">
<property name="text">
<string>Laser scans</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_odom">
<property name="text">
<string>Odometry</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_userData">
<property name="text">
<string>User data (planned goals)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_odom">
<property name="text">
<string>Odometry</string>
</property>
<property name="checked">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Output Path</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineEdit_path">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_path">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_userData">
<property name="text">
<string>User data (planned goals)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineEdit_path">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_path">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
+34 -20
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<height>286</height>
<width>369</width>
<height>344</height>
</rect>
</property>
<property name="windowTitle">
@@ -51,28 +51,21 @@
<string>Range</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<item row="1" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>From</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_2">
<item row="3" column="0">
<widget class="QRadioButton" name="radioButton_maps">
<property name="text">
<string>To</string>
<string>Maps:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButton_nodes">
<property name="text">
<string>Nodes:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_node_from">
<property name="minimum">
<number>1</number>
@@ -82,7 +75,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="2" column="2">
<widget class="QSpinBox" name="spinBox_node_to">
<property name="minimum">
<number>1</number>
@@ -92,14 +85,21 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="radioButton_maps">
<item row="4" column="0">
<widget class="QRadioButton" name="radioButton_selected_nodes">
<property name="text">
<string>Maps:</string>
<string>Nodes selected</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>To</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_map_from">
<property name="minimum">
<number>0</number>
@@ -112,7 +112,7 @@
</property>
</widget>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QSpinBox" name="spinBox_map_to">
<property name="minimum">
<number>0</number>
@@ -125,6 +125,20 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="radioButton_nodes">
<property name="text">
<string>Nodes:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QRadioButton" name="radioButton_current_component">
<property name="text">
<string>Current component</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>