DBViewer: updated refine constraints menu action with more options, DBDriver: added updateCalibration for convenience

This commit is contained in:
matlabbe
2023-12-20 14:39:49 -08:00
parent ee09e92496
commit d135ef02e2
11 changed files with 703 additions and 30 deletions

View File

@@ -36,6 +36,7 @@ SET(headers_ui
../include/${PROJECT_PREFIX}/gui/EditMapArea.h
../include/${PROJECT_PREFIX}/gui/MultiSessionLocWidget.h
../include/${PROJECT_PREFIX}/gui/MultiSessionLocSubView.h
../include/${PROJECT_PREFIX}/gui/LinkRefiningDialog.h
)
SET(qrc
@@ -81,6 +82,7 @@ SET(SRC_FILES
./CreateSimpleCalibrationDialog.cpp
./ParametersToolBox.cpp
./DepthCalibrationDialog.cpp
./LinkRefiningDialog.cpp
./3rdParty/QMultiComboBox.cpp
./opencv/vtkImageMatSource.cpp
${qrc}

View File

@@ -83,6 +83,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/VisualWord.h"
#include "rtabmap/gui/ExportDialog.h"
#include "rtabmap/gui/EditConstraintDialog.h"
#include "rtabmap/gui/LinkRefiningDialog.h"
#include "rtabmap/gui/ProgressDialog.h"
#include "rtabmap/gui/ParametersToolBox.h"
#include "rtabmap/gui/RecoveryState.h"
@@ -112,6 +113,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
exportDialog_(new ExportCloudsDialog(this)),
editDepthDialog_(new QDialog(this)),
editMapDialog_(new QDialog(this)),
linkRefiningDialog_(new LinkRefiningDialog(this)),
savedMaximized_(false),
firstCall_(true),
iniFilePath_(ini),
@@ -308,8 +310,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->actionUpdate_all_neighbor_covariances, SIGNAL(triggered()), this, SLOT(updateAllNeighborCovariances()));
connect(ui_->actionUpdate_all_loop_closure_covariances, SIGNAL(triggered()), this, SLOT(updateAllLoopClosureCovariances()));
connect(ui_->actionUpdate_all_landmark_covariances, SIGNAL(triggered()), this, SLOT(updateAllLandmarkCovariances()));
connect(ui_->actionRefine_all_neighbor_links, SIGNAL(triggered()), this, SLOT(refineAllNeighborLinks()));
connect(ui_->actionRefine_all_loop_closure_links, SIGNAL(triggered()), this, SLOT(refineAllLoopClosureLinks()));
connect(ui_->actionRefine_links, SIGNAL(triggered()), this, SLOT(refineLinks()));
connect(ui_->actionRegenerate_local_grid_maps, SIGNAL(triggered()), this, SLOT(regenerateLocalMaps()));
connect(ui_->actionRegenerate_local_grid_maps_selected, SIGNAL(triggered()), this, SLOT(regenerateCurrentLocalMaps()));
connect(ui_->actionReset_all_changes, SIGNAL(triggered()), this, SLOT(resetAllChanges()));
@@ -1163,6 +1164,10 @@ bool DatabaseViewer::closeDatabase()
stereoViewer_->refreshView();
ui_->toolBox_statistics->clear();
// This will re-init the dialog
delete linkRefiningDialog_;
linkRefiningDialog_ = new LinkRefiningDialog(this);
}
ui_->actionClose_database->setEnabled(dbDriver_ != 0);
@@ -4282,7 +4287,7 @@ void DatabaseViewer::detectMoreLoopClosures()
void DatabaseViewer::updateAllNeighborCovariances()
{
updateAllCovariances(neighborLinks_);
updateCovariances(neighborLinks_);
}
void DatabaseViewer::updateAllLoopClosureCovariances()
{
@@ -4294,7 +4299,7 @@ void DatabaseViewer::updateAllLoopClosureCovariances()
links.push_back(loopLinks_.at(i));
}
}
updateAllCovariances(links);
updateCovariances(links);
}
void DatabaseViewer::updateAllLandmarkCovariances()
{
@@ -4306,10 +4311,10 @@ void DatabaseViewer::updateAllLandmarkCovariances()
links.push_back(loopLinks_.at(i));
}
}
updateAllCovariances(links);
updateCovariances(links);
}
void DatabaseViewer::updateAllCovariances(const QList<Link> & links)
void DatabaseViewer::updateCovariances(const QList<Link> & links)
{
if(links.size())
{
@@ -4397,15 +4402,79 @@ void DatabaseViewer::updateAllCovariances(const QList<Link> & links)
}
}
void DatabaseViewer::refineAllNeighborLinks()
void DatabaseViewer::refineLinks()
{
refineAllLinks(neighborLinks_);
int minNodeId = 0;
int maxNodeId = 0;
int minMapId = 0;
int maxMapId = 0;
std::multimap<int, Link> allLinks = updateLinksWithModifications(links_);
for(std::multimap<int, Link>::iterator iter=allLinks.begin(); iter!=allLinks.end(); ++iter)
{
int minId = iter->second.from()>iter->second.to()?iter->second.to():iter->second.from();
int maxId = iter->second.from()<iter->second.to()?iter->second.to():iter->second.from();
if(minNodeId == 0 || minNodeId > minId)
{
minNodeId = minId;
}
if(maxNodeId == 0 || maxNodeId < maxId)
{
maxNodeId = maxId;
}
}
if(minNodeId > 0)
{
minMapId = uValue(mapIds_, minNodeId, 0);
maxMapId = uValue(mapIds_, maxNodeId, minMapId);
linkRefiningDialog_->setMinMax(
minNodeId,
maxNodeId,
minMapId,
maxMapId);
if(linkRefiningDialog_->exec() == QDialog::Accepted)
{
QList<Link> links;
Link::Type type = linkRefiningDialog_->getLinkType();
linkRefiningDialog_->getRangeNodeId(minNodeId, maxNodeId);
linkRefiningDialog_->getRangeNodeId(minMapId, maxMapId);
bool intra, inter;
linkRefiningDialog_->getIntraInterSessions(intra, inter);
for(std::multimap<int, Link>::iterator iter=allLinks.begin(); iter!=allLinks.end(); ++iter)
{
if(type==Link::kEnd || type == iter->second.type())
{
int from = iter->second.from();
int to = iter->second.to();
int mapFrom = uValue(mapIds_, from, 0);
int mapTo = uValue(mapIds_, to, 0);
if(((linkRefiningDialog_->isRangeByNodeId() &&
((from >= minNodeId && from <= maxNodeId) ||
(to >= minNodeId && to <= maxNodeId))) ||
(linkRefiningDialog_->isRangeByMapId() &&
((mapFrom >= minMapId && mapFrom <= maxMapId) ||
(mapTo >= minMapId && mapTo <= maxMapId)))) &&
((intra && mapTo == mapFrom) ||
(inter && mapTo != mapFrom)))
{
links.push_back(iter->second);
}
}
}
if(links.isEmpty())
{
QMessageBox::warning(this, tr("Refine links"), tr("No links found matching the requested parameters."));
return;
}
else
{
refineLinks(links);
}
}
}
}
void DatabaseViewer::refineAllLoopClosureLinks()
{
refineAllLinks(loopLinks_);
}
void DatabaseViewer::refineAllLinks(const QList<Link> & links)
void DatabaseViewer::refineLinks(const QList<Link> & links)
{
if(links.size())
{

View File

@@ -0,0 +1,156 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rtabmap/gui/LinkRefiningDialog.h"
#include "ui_linkRefiningDialog.h"
#include <QPushButton>
namespace rtabmap {
LinkRefiningDialog::LinkRefiningDialog(QWidget * parent) :
QDialog(parent),
defaultNodeIdMin_(0),
defaultNodeIdMax_(0),
defaultMapIdMin_(0),
defaultMapIdMax_(0)
{
ui_ = new Ui_linkRefiningDialog();
ui_->setupUi(this);
ui_->comboBox_link_type->addItem("All");
for(int i =0; i<Link::kPosePrior; ++i)
{
ui_->comboBox_link_type->addItem(Link::typeName((Link::Type)i).c_str());
if(((Link::Type)i) == Link::kVirtualClosure)
{
ui_->comboBox_link_type->setItemData(i+1, 0, Qt::UserRole - 1);
}
}
restoreDefaults();
connect(ui_->buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), this, SLOT(restoreDefaults()));
connect(ui_->comboBox_link_type, SIGNAL(currentIndexChanged(int)), this, SLOT(updateIntraInterState()));
connect(ui_->spinBox_node_from, SIGNAL(valueChanged(int)), this, SLOT(setRangeToNodeId()));
connect(ui_->spinBox_node_to, SIGNAL(valueChanged(int)), this, SLOT(setRangeToNodeId()));
connect(ui_->spinBox_map_from, SIGNAL(valueChanged(int)), this, SLOT(setRangeToMapId()));
connect(ui_->spinBox_map_to, SIGNAL(valueChanged(int)), this, SLOT(setRangeToMapId()));
}
LinkRefiningDialog::~LinkRefiningDialog()
{
delete ui_;
}
void LinkRefiningDialog::setMinMax(
int nodeIdMin,
int nodeIdMax,
int mapIdMin,
int mapIdMax)
{
bool reset = defaultNodeIdMin_ == 0;
defaultNodeIdMin_ = nodeIdMin;
defaultNodeIdMax_ = nodeIdMax;
defaultMapIdMin_ = mapIdMin;
defaultMapIdMax_ = mapIdMax;
ui_->spinBox_node_from->setMinimum(defaultNodeIdMin_);
ui_->spinBox_node_to->setMaximum(defaultNodeIdMax_);
ui_->spinBox_map_from->setMinimum(defaultMapIdMin_);
ui_->spinBox_map_to->setMaximum(defaultMapIdMax_);
if(reset)
{
restoreDefaults();
}
}
Link::Type LinkRefiningDialog::getLinkType() const
{
if(ui_->comboBox_link_type->currentIndex() == 0)
{
return Link::kEnd;
}
return (Link::Type)(ui_->comboBox_link_type->currentIndex()-1);
}
void LinkRefiningDialog::getIntraInterSessions(bool & intra, bool & inter) const
{
intra = ui_->comboBox_link_inter_intra->currentIndex() == 0 || ui_->comboBox_link_inter_intra->currentIndex() == 1 || getLinkType() == Link::kNeighbor;
inter = ui_->comboBox_link_inter_intra->currentIndex() == 0 || ui_->comboBox_link_inter_intra->currentIndex() == 2;
}
bool LinkRefiningDialog::isRangeByNodeId() const
{
return ui_->radioButton_nodes->isChecked();
}
bool LinkRefiningDialog::isRangeByMapId() const
{
return ui_->radioButton_maps->isChecked();
}
void LinkRefiningDialog::getRangeNodeId(int & from, int & to) const
{
from = ui_->spinBox_node_from->value();
to = ui_->spinBox_node_to->value();
}
void LinkRefiningDialog::getRangeMapId(int & from, int & to) const
{
from = ui_->spinBox_map_from->value();
to = ui_->spinBox_map_to->value();
}
void LinkRefiningDialog::restoreDefaults()
{
ui_->comboBox_link_type->setCurrentIndex(0);
ui_->comboBox_link_inter_intra->setCurrentIndex(0);
ui_->spinBox_node_from->setValue(defaultNodeIdMin_);
ui_->spinBox_node_to->setValue(defaultNodeIdMax_);
ui_->spinBox_map_from->setValue(defaultMapIdMin_);
ui_->spinBox_map_to->setValue(defaultMapIdMax_);
ui_->radioButton_nodes->setChecked(true);
}
void LinkRefiningDialog::updateIntraInterState()
{
ui_->comboBox_link_inter_intra->setEnabled(getLinkType() != Link::kNeighbor);
}
void LinkRefiningDialog::setRangeToNodeId()
{
ui_->radioButton_nodes->setChecked(true);
}
void LinkRefiningDialog::setRangeToMapId()
{
ui_->radioButton_maps->setChecked(true);
}
}

View File

@@ -843,8 +843,7 @@
<addaction name="actionGenerate_local_graph_dot"/>
<addaction name="separator"/>
<addaction name="actionDetect_more_loop_closures"/>
<addaction name="actionRefine_all_neighbor_links"/>
<addaction name="actionRefine_all_loop_closure_links"/>
<addaction name="actionRefine_links"/>
<addaction name="actionUpdate_all_neighbor_covariances"/>
<addaction name="actionUpdate_all_loop_closure_covariances"/>
<addaction name="actionUpdate_all_landmark_covariances"/>
@@ -3130,20 +3129,12 @@
<string>View 3D map...</string>
</property>
</action>
<action name="actionRefine_all_neighbor_links">
<action name="actionRefine_links">
<property name="text">
<string>Refine all neighbor links...</string>
<string>Refine links...</string>
</property>
<property name="toolTip">
<string>Refine all neighbor links with the registration strategy set in &quot;Core Parameters&quot;-&gt;&quot;Reg&quot;</string>
</property>
</action>
<action name="actionRefine_all_loop_closure_links">
<property name="text">
<string>Refine all loop closure links...</string>
</property>
<property name="toolTip">
<string>Refine all loop closure links with the registration strategy set in &quot;Core Parameters&quot;-&gt;&quot;Reg&quot;</string>
<string>Refine selected links with the registration strategy set in &quot;Core Parameters&quot;-&gt;&quot;Reg&quot;, &quot;Vis&quot; and/or &quot;Icp&quot;</string>
</property>
</action>
<action name="actionDetect_more_loop_closures">

View File

@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>linkRefiningDialog</class>
<widget class="QDialog" name="linkRefiningDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<height>286</height>
</rect>
</property>
<property name="windowTitle">
<string>Link Refining</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Link Type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="comboBox_link_type"/>
</item>
<item>
<widget class="QComboBox" name="comboBox_link_inter_intra">
<item>
<property name="text">
<string>Inter and Intra Sessions</string>
</property>
</item>
<item>
<property name="text">
<string>Intra-only</string>
</property>
</item>
<item>
<property name="text">
<string>Inter-only</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Range</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" 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">
<property name="text">
<string>To</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">
<widget class="QSpinBox" name="spinBox_node_from">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="spinBox_node_to">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="radioButton_maps">
<property name="text">
<string>Maps:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_map_from">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="spinBox_map_to">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<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>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>linkRefiningDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>linkRefiningDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>