mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
DbViewer: added "Edit optimized map" and "Regenerate Optimized Map" actions
This commit is contained in:
@@ -60,6 +60,7 @@ class CloudViewer;
|
|||||||
class OctoMap;
|
class OctoMap;
|
||||||
class ExportCloudsDialog;
|
class ExportCloudsDialog;
|
||||||
class EditDepthArea;
|
class EditDepthArea;
|
||||||
|
class EditMapArea;
|
||||||
|
|
||||||
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
||||||
{
|
{
|
||||||
@@ -93,8 +94,10 @@ private Q_SLOTS:
|
|||||||
void selectEmptyColor();
|
void selectEmptyColor();
|
||||||
void editDepthImage();
|
void editDepthImage();
|
||||||
void generateGraph();
|
void generateGraph();
|
||||||
|
void editSaved2DMap();
|
||||||
void exportSaved2DMap();
|
void exportSaved2DMap();
|
||||||
void import2DMap();
|
void import2DMap();
|
||||||
|
void regenerateSavedMap();
|
||||||
void viewOptimizedMesh();
|
void viewOptimizedMesh();
|
||||||
void exportOptimizedMesh();
|
void exportOptimizedMesh();
|
||||||
void updateOptimizedMesh();
|
void updateOptimizedMesh();
|
||||||
@@ -225,6 +228,8 @@ private:
|
|||||||
ExportCloudsDialog * exportDialog_;
|
ExportCloudsDialog * exportDialog_;
|
||||||
QDialog * editDepthDialog_;
|
QDialog * editDepthDialog_;
|
||||||
EditDepthArea * editDepthArea_;
|
EditDepthArea * editDepthArea_;
|
||||||
|
QDialog * editMapDialog_;
|
||||||
|
EditMapArea * editMapArea_;
|
||||||
|
|
||||||
bool savedMaximized_;
|
bool savedMaximized_;
|
||||||
bool firstCall_;
|
bool firstCall_;
|
||||||
|
|||||||
92
guilib/include/rtabmap/gui/EditMapArea.h
Normal file
92
guilib/include/rtabmap/gui/EditMapArea.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTABMAP_EDITMAPAREA_H
|
||||||
|
#define RTABMAP_EDITMAPAREA_H
|
||||||
|
|
||||||
|
#include "rtabmap/gui/RtabmapGuiExp.h" // DLL export/import defines
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include "rtabmap/utilite/UCv2Qt.h"
|
||||||
|
|
||||||
|
class QMenu;
|
||||||
|
class QAction;
|
||||||
|
|
||||||
|
namespace rtabmap {
|
||||||
|
|
||||||
|
class RTABMAPGUI_EXP EditMapArea : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EditMapArea(QWidget *parent = 0);
|
||||||
|
|
||||||
|
void setMap(const cv::Mat & map);
|
||||||
|
cv::Mat getModifiedMap() const;
|
||||||
|
bool isModified() const {return modified_;}
|
||||||
|
|
||||||
|
void setPenWidth(int newWidth);
|
||||||
|
int penWidth() const { return myPenWidth_; }
|
||||||
|
void setColorMap(uCvQtDepthColorMap type);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void resetChanges();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void mousePressEvent(QMouseEvent *event);
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent *event);
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||||
|
virtual void paintEvent(QPaintEvent *event);
|
||||||
|
virtual void resizeEvent(QResizeEvent *event);
|
||||||
|
virtual void contextMenuEvent(QContextMenuEvent * e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawLineTo(const QPoint &endPoint);
|
||||||
|
void computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const;
|
||||||
|
|
||||||
|
bool modified_;
|
||||||
|
bool scribbling_;
|
||||||
|
int myPenWidth_;
|
||||||
|
QImage map_;
|
||||||
|
cv::Mat originalMap_;
|
||||||
|
QPoint lastPoint_;
|
||||||
|
|
||||||
|
QMenu * menu_;
|
||||||
|
QAction * resetChanges_;
|
||||||
|
QAction * setPenWidth_;
|
||||||
|
QAction * addObstacle_;
|
||||||
|
QAction * clearObstacle_;
|
||||||
|
QAction * setUnknown_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -32,6 +32,7 @@ SET(headers_ui
|
|||||||
../include/${PROJECT_PREFIX}/gui/TexturingState.h
|
../include/${PROJECT_PREFIX}/gui/TexturingState.h
|
||||||
../include/${PROJECT_PREFIX}/gui/RecoveryState.h
|
../include/${PROJECT_PREFIX}/gui/RecoveryState.h
|
||||||
../include/${PROJECT_PREFIX}/gui/EditDepthArea.h
|
../include/${PROJECT_PREFIX}/gui/EditDepthArea.h
|
||||||
|
../include/${PROJECT_PREFIX}/gui/EditMapArea.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(uis
|
SET(uis
|
||||||
@@ -98,6 +99,7 @@ SET(SRC_FILES
|
|||||||
./MapVisibilityWidget.cpp
|
./MapVisibilityWidget.cpp
|
||||||
./GraphViewer.cpp
|
./GraphViewer.cpp
|
||||||
./EditDepthArea.cpp
|
./EditDepthArea.cpp
|
||||||
|
./EditMapArea.cpp
|
||||||
./CreateSimpleCalibrationDialog.cpp
|
./CreateSimpleCalibrationDialog.cpp
|
||||||
./ParametersToolBox.cpp
|
./ParametersToolBox.cpp
|
||||||
./DepthCalibrationDialog.cpp
|
./DepthCalibrationDialog.cpp
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "rtabmap/gui/DataRecorder.h"
|
#include "rtabmap/gui/DataRecorder.h"
|
||||||
#include "rtabmap/gui/ExportCloudsDialog.h"
|
#include "rtabmap/gui/ExportCloudsDialog.h"
|
||||||
#include "rtabmap/gui/EditDepthArea.h"
|
#include "rtabmap/gui/EditDepthArea.h"
|
||||||
|
#include "rtabmap/gui/EditMapArea.h"
|
||||||
#include "rtabmap/core/SensorData.h"
|
#include "rtabmap/core/SensorData.h"
|
||||||
#include "rtabmap/core/GainCompensator.h"
|
#include "rtabmap/core/GainCompensator.h"
|
||||||
#include "rtabmap/gui/ExportDialog.h"
|
#include "rtabmap/gui/ExportDialog.h"
|
||||||
@@ -100,6 +101,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
|
|||||||
octomap_(0),
|
octomap_(0),
|
||||||
exportDialog_(new ExportCloudsDialog(this)),
|
exportDialog_(new ExportCloudsDialog(this)),
|
||||||
editDepthDialog_(new QDialog(this)),
|
editDepthDialog_(new QDialog(this)),
|
||||||
|
editMapDialog_(new QDialog(this)),
|
||||||
savedMaximized_(false),
|
savedMaximized_(false),
|
||||||
firstCall_(true),
|
firstCall_(true),
|
||||||
iniFilePath_(ini),
|
iniFilePath_(ini),
|
||||||
@@ -136,6 +138,20 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
|
|||||||
editDepthDialog_->setLayout(vLayout);
|
editDepthDialog_->setLayout(vLayout);
|
||||||
editDepthDialog_->setWindowTitle(tr("Edit Depth Image"));
|
editDepthDialog_->setWindowTitle(tr("Edit Depth Image"));
|
||||||
|
|
||||||
|
editMapDialog_->resize(640, 480);
|
||||||
|
vLayout = new QVBoxLayout(editMapDialog_);
|
||||||
|
editMapArea_ = new EditMapArea(editMapDialog_);
|
||||||
|
vLayout->setContentsMargins(0,0,0,0);
|
||||||
|
vLayout->setSpacing(0);
|
||||||
|
vLayout->addWidget(editMapArea_, 1);
|
||||||
|
buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal, editMapDialog_);
|
||||||
|
vLayout->addWidget(buttonBox);
|
||||||
|
connect(buttonBox, SIGNAL(accepted()), editMapDialog_, SLOT(accept()));
|
||||||
|
connect(buttonBox, SIGNAL(rejected()), editMapDialog_, SLOT(reject()));
|
||||||
|
connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), editMapArea_, SLOT(resetChanges()));
|
||||||
|
editMapDialog_->setLayout(vLayout);
|
||||||
|
editMapDialog_->setWindowTitle(tr("Edit Optimized Map"));
|
||||||
|
|
||||||
QString title("RTAB-Map Database Viewer[*]");
|
QString title("RTAB-Map Database Viewer[*]");
|
||||||
this->setWindowTitle(title);
|
this->setWindowTitle(title);
|
||||||
|
|
||||||
@@ -251,8 +267,10 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
|
|||||||
connect(ui_->actionPoses_KML, SIGNAL(triggered()), this , SLOT(exportPosesKML()));
|
connect(ui_->actionPoses_KML, SIGNAL(triggered()), this , SLOT(exportPosesKML()));
|
||||||
connect(ui_->actionGPS_TXT, SIGNAL(triggered()), this , SLOT(exportGPS_TXT()));
|
connect(ui_->actionGPS_TXT, SIGNAL(triggered()), this , SLOT(exportGPS_TXT()));
|
||||||
connect(ui_->actionGPS_KML, SIGNAL(triggered()), this , SLOT(exportGPS_KML()));
|
connect(ui_->actionGPS_KML, SIGNAL(triggered()), this , SLOT(exportGPS_KML()));
|
||||||
|
connect(ui_->actionEdit_optimized_2D_map, SIGNAL(triggered()), this , SLOT(editSaved2DMap()));
|
||||||
connect(ui_->actionExport_saved_2D_map, SIGNAL(triggered()), this , SLOT(exportSaved2DMap()));
|
connect(ui_->actionExport_saved_2D_map, SIGNAL(triggered()), this , SLOT(exportSaved2DMap()));
|
||||||
connect(ui_->actionImport_2D_map, SIGNAL(triggered()), this , SLOT(import2DMap()));
|
connect(ui_->actionImport_2D_map, SIGNAL(triggered()), this , SLOT(import2DMap()));
|
||||||
|
connect(ui_->actionRegenerate_optimized_2D_map, SIGNAL(triggered()), this , SLOT(regenerateSavedMap()));
|
||||||
connect(ui_->actionView_optimized_mesh, SIGNAL(triggered()), this , SLOT(viewOptimizedMesh()));
|
connect(ui_->actionView_optimized_mesh, SIGNAL(triggered()), this , SLOT(viewOptimizedMesh()));
|
||||||
connect(ui_->actionExport_optimized_mesh, SIGNAL(triggered()), this , SLOT(exportOptimizedMesh()));
|
connect(ui_->actionExport_optimized_mesh, SIGNAL(triggered()), this , SLOT(exportOptimizedMesh()));
|
||||||
connect(ui_->actionUpdate_optimized_mesh, SIGNAL(triggered()), this , SLOT(updateOptimizedMesh()));
|
connect(ui_->actionUpdate_optimized_mesh, SIGNAL(triggered()), this , SLOT(updateOptimizedMesh()));
|
||||||
@@ -285,7 +303,10 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
|
|||||||
ui_->menuExport_poses->setEnabled(false);
|
ui_->menuExport_poses->setEnabled(false);
|
||||||
ui_->menuExport_GPS->setEnabled(false);
|
ui_->menuExport_GPS->setEnabled(false);
|
||||||
ui_->actionPoses_KML->setEnabled(false);
|
ui_->actionPoses_KML->setEnabled(false);
|
||||||
|
ui_->actionEdit_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionExport_saved_2D_map->setEnabled(false);
|
ui_->actionExport_saved_2D_map->setEnabled(false);
|
||||||
|
ui_->actionImport_2D_map->setEnabled(false);
|
||||||
|
ui_->actionRegenerate_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionView_optimized_mesh->setEnabled(false);
|
ui_->actionView_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionExport_optimized_mesh->setEnabled(false);
|
ui_->actionExport_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionUpdate_optimized_mesh->setEnabled(false);
|
ui_->actionUpdate_optimized_mesh->setEnabled(false);
|
||||||
@@ -968,8 +989,10 @@ bool DatabaseViewer::closeDatabase()
|
|||||||
ui_->menuExport_poses->setEnabled(false);
|
ui_->menuExport_poses->setEnabled(false);
|
||||||
ui_->menuExport_GPS->setEnabled(false);
|
ui_->menuExport_GPS->setEnabled(false);
|
||||||
ui_->actionPoses_KML->setEnabled(false);
|
ui_->actionPoses_KML->setEnabled(false);
|
||||||
|
ui_->actionEdit_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionExport_saved_2D_map->setEnabled(false);
|
ui_->actionExport_saved_2D_map->setEnabled(false);
|
||||||
ui_->actionImport_2D_map->setEnabled(false);
|
ui_->actionImport_2D_map->setEnabled(false);
|
||||||
|
ui_->actionRegenerate_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionView_optimized_mesh->setEnabled(false);
|
ui_->actionView_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionExport_optimized_mesh->setEnabled(false);
|
ui_->actionExport_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionUpdate_optimized_mesh->setEnabled(false);
|
ui_->actionUpdate_optimized_mesh->setEnabled(false);
|
||||||
@@ -1526,8 +1549,10 @@ void DatabaseViewer::updateIds()
|
|||||||
ui_->menuExport_poses->setEnabled(false);
|
ui_->menuExport_poses->setEnabled(false);
|
||||||
ui_->menuExport_GPS->setEnabled(false);
|
ui_->menuExport_GPS->setEnabled(false);
|
||||||
ui_->actionPoses_KML->setEnabled(false);
|
ui_->actionPoses_KML->setEnabled(false);
|
||||||
|
ui_->actionEdit_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionExport_saved_2D_map->setEnabled(false);
|
ui_->actionExport_saved_2D_map->setEnabled(false);
|
||||||
ui_->actionImport_2D_map->setEnabled(false);
|
ui_->actionImport_2D_map->setEnabled(false);
|
||||||
|
ui_->actionRegenerate_optimized_2D_map->setEnabled(false);
|
||||||
ui_->actionView_optimized_mesh->setEnabled(false);
|
ui_->actionView_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionExport_optimized_mesh->setEnabled(false);
|
ui_->actionExport_optimized_mesh->setEnabled(false);
|
||||||
ui_->actionUpdate_optimized_mesh->setEnabled(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.13.0") >= 0);
|
ui_->actionUpdate_optimized_mesh->setEnabled(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.13.0") >= 0);
|
||||||
@@ -1705,8 +1730,10 @@ void DatabaseViewer::updateIds()
|
|||||||
|
|
||||||
float xMin, yMin, cellSize;
|
float xMin, yMin, cellSize;
|
||||||
bool hasMap = !dbDriver_->load2DMap(xMin, yMin, cellSize).empty();
|
bool hasMap = !dbDriver_->load2DMap(xMin, yMin, cellSize).empty();
|
||||||
|
ui_->actionEdit_optimized_2D_map->setEnabled(hasMap);
|
||||||
ui_->actionExport_saved_2D_map->setEnabled(hasMap);
|
ui_->actionExport_saved_2D_map->setEnabled(hasMap);
|
||||||
ui_->actionImport_2D_map->setEnabled(hasMap);
|
ui_->actionImport_2D_map->setEnabled(hasMap);
|
||||||
|
ui_->actionRegenerate_optimized_2D_map->setEnabled(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") >= 0);
|
||||||
|
|
||||||
if(!dbDriver_->loadOptimizedMesh().empty())
|
if(!dbDriver_->loadOptimizedMesh().empty())
|
||||||
{
|
{
|
||||||
@@ -2425,6 +2452,74 @@ void DatabaseViewer::exportGPS(int format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseViewer::editSaved2DMap()
|
||||||
|
{
|
||||||
|
if(!dbDriver_)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot edit 2D map"), tr("A database must must loaded first...\nUse File->Open database."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot edit 2D map"),
|
||||||
|
tr("The database has too old version (%1) to saved "
|
||||||
|
"optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot edit 2D map"),
|
||||||
|
tr("The database has modified links and/or modified local "
|
||||||
|
"occupancy grids, the 2D optimized map cannot be modified."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float xMin, yMin, cellSize;
|
||||||
|
cv::Mat map = dbDriver_->load2DMap(xMin, yMin, cellSize);
|
||||||
|
if(map.empty())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot export 2D map"), tr("The database doesn't contain a saved 2D map."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat map8U = rtabmap::util3d::convertMap2Image8U(map, false);
|
||||||
|
cv::Mat map8UFlip, map8URotated;
|
||||||
|
cv::flip(map8U, map8UFlip, 0);
|
||||||
|
if(!ui_->graphViewer->isOrientationENU())
|
||||||
|
{
|
||||||
|
cv::rotate(map8UFlip, map8URotated, cv::ROTATE_90_COUNTERCLOCKWISE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map8URotated = map8UFlip;
|
||||||
|
}
|
||||||
|
|
||||||
|
editMapArea_->setMap(map8URotated);
|
||||||
|
if(editMapDialog_->exec() == QDialog::Accepted && editMapArea_->isModified())
|
||||||
|
{
|
||||||
|
cv::Mat map = editMapArea_->getModifiedMap();
|
||||||
|
|
||||||
|
if(!ui_->graphViewer->isOrientationENU())
|
||||||
|
{
|
||||||
|
cv::rotate(map, map8URotated, cv::ROTATE_90_CLOCKWISE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
map8URotated = map;
|
||||||
|
}
|
||||||
|
cv::flip(map8URotated, map8UFlip, 0);
|
||||||
|
|
||||||
|
UASSERT(map8UFlip.type() == map8U.type());
|
||||||
|
UASSERT(map8UFlip.cols == map8U.cols);
|
||||||
|
UASSERT(map8UFlip.rows == map8U.rows);
|
||||||
|
|
||||||
|
dbDriver_->save2DMap(rtabmap::util3d::convertImage8U2Map(map8UFlip, false), xMin, yMin, cellSize);
|
||||||
|
QMessageBox::information(this, tr("Edit 2D map"), tr("Map updated!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseViewer::exportSaved2DMap()
|
void DatabaseViewer::exportSaved2DMap()
|
||||||
{
|
{
|
||||||
if(!dbDriver_)
|
if(!dbDriver_)
|
||||||
@@ -2469,6 +2564,22 @@ void DatabaseViewer::import2DMap()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot edit 2D map"),
|
||||||
|
tr("The database has too old version (%1) to saved "
|
||||||
|
"optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot import 2D map"),
|
||||||
|
tr("The database has modified links and/or modified local "
|
||||||
|
"occupancy grids, the 2D optimized map cannot be modified."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float xMin, yMin, cellSize;
|
float xMin, yMin, cellSize;
|
||||||
cv::Mat mapOrg = dbDriver_->load2DMap(xMin, yMin, cellSize);
|
cv::Mat mapOrg = dbDriver_->load2DMap(xMin, yMin, cellSize);
|
||||||
if(mapOrg.empty())
|
if(mapOrg.empty())
|
||||||
@@ -2500,6 +2611,64 @@ void DatabaseViewer::import2DMap()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseViewer::regenerateSavedMap()
|
||||||
|
{
|
||||||
|
if(!dbDriver_)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot import 2D map"), tr("A database must must loaded first...\nUse File->Open database."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot edit 2D map"),
|
||||||
|
tr("The database has too old version (%1) to saved "
|
||||||
|
"optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot import 2D map"),
|
||||||
|
tr("The database has modified links and/or modified local "
|
||||||
|
"occupancy grids, the 2D optimized map cannot be modified."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((int)graphes_.empty() || localMaps_.empty())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Cannot regenerate 2D map"),
|
||||||
|
tr("Graph is empty, make sure you opened the "
|
||||||
|
"Graph View and there is a map shown."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//update scans
|
||||||
|
UINFO("Update local maps list...");
|
||||||
|
OccupancyGrid grid(ui_->parameters_toolbox->getParameters());
|
||||||
|
for(std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps_.begin(); iter!=localMaps_.end(); ++iter)
|
||||||
|
{
|
||||||
|
grid.addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
|
||||||
|
}
|
||||||
|
grid.update(graphes_.back());
|
||||||
|
float xMin, yMin;
|
||||||
|
cv::Mat map = grid.getMap(xMin, yMin);
|
||||||
|
|
||||||
|
if(map.empty())
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, tr("Regenerate 2D map"), tr("Failed to renegerate the map, resulting map is empty!"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbDriver_->save2DMap(map, xMin, yMin, grid.getCellSize());
|
||||||
|
QMessageBox::information(this, tr("Regenerate 2D map"), tr("Map regenerated!"));
|
||||||
|
ui_->actionEdit_optimized_2D_map->setEnabled(true);
|
||||||
|
ui_->actionExport_saved_2D_map->setEnabled(true);
|
||||||
|
ui_->actionImport_2D_map->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseViewer::viewOptimizedMesh()
|
void DatabaseViewer::viewOptimizedMesh()
|
||||||
{
|
{
|
||||||
if(!dbDriver_)
|
if(!dbDriver_)
|
||||||
|
|||||||
248
guilib/src/EditMapArea.cpp
Normal file
248
guilib/src/EditMapArea.cpp
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
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 <QWidget>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QInputDialog>
|
||||||
|
|
||||||
|
#include "rtabmap/gui/EditMapArea.h"
|
||||||
|
#include <rtabmap/utilite/ULogger.h>
|
||||||
|
|
||||||
|
namespace rtabmap {
|
||||||
|
|
||||||
|
EditMapArea::EditMapArea(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_StaticContents);
|
||||||
|
modified_ = false;
|
||||||
|
scribbling_ = false;
|
||||||
|
myPenWidth_ = 3;
|
||||||
|
|
||||||
|
menu_ = new QMenu(tr(""), this);
|
||||||
|
setPenWidth_ = menu_->addAction(tr("Set Pen Width..."));
|
||||||
|
addObstacle_ = menu_->addAction(tr("Add Obstacle"));
|
||||||
|
addObstacle_->setCheckable(true);
|
||||||
|
addObstacle_->setChecked(true);
|
||||||
|
clearObstacle_ = menu_->addAction(tr("Clear Obstacle"));
|
||||||
|
clearObstacle_->setCheckable(true);
|
||||||
|
clearObstacle_->setChecked(false);
|
||||||
|
setUnknown_ = menu_->addAction(tr("Set Unknown"));
|
||||||
|
setUnknown_->setCheckable(true);
|
||||||
|
setUnknown_->setChecked(false);
|
||||||
|
QActionGroup * group = new QActionGroup(this);
|
||||||
|
group->addAction(addObstacle_);
|
||||||
|
group->addAction(clearObstacle_);
|
||||||
|
group->addAction(setUnknown_);
|
||||||
|
resetChanges_ = menu_->addAction(tr("Reset Changes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::setMap(const cv::Mat &map)
|
||||||
|
{
|
||||||
|
UASSERT(!map.empty());
|
||||||
|
UASSERT(map.type() == CV_8UC1);
|
||||||
|
originalMap_ = map;
|
||||||
|
|
||||||
|
map_ = uCvMat2QImage(map, true).convertToFormat(QImage::Format_RGB32);
|
||||||
|
|
||||||
|
modified_ = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat EditMapArea::getModifiedMap() const
|
||||||
|
{
|
||||||
|
cv::Mat modifiedMap = originalMap_.clone();
|
||||||
|
if(modified_)
|
||||||
|
{
|
||||||
|
UASSERT(map_.width() == modifiedMap.cols &&
|
||||||
|
map_.height() == modifiedMap.rows);
|
||||||
|
UASSERT(modifiedMap.type() == CV_8UC1);
|
||||||
|
for(int j=0; j<map_.height(); ++j)
|
||||||
|
{
|
||||||
|
for(int i=0; i<map_.width(); ++i)
|
||||||
|
{
|
||||||
|
modifiedMap.at<unsigned char>(j,i) = qRed(map_.pixel(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modifiedMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::setPenWidth(int newWidth)
|
||||||
|
{
|
||||||
|
myPenWidth_ = newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::resetChanges()
|
||||||
|
{
|
||||||
|
map_ = uCvMat2QImage(originalMap_).convertToFormat(QImage::Format_RGB32);
|
||||||
|
modified_ = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
float scale, offsetX, offsetY;
|
||||||
|
computeScaleOffsets(rect(), scale, offsetX, offsetY);
|
||||||
|
lastPoint_.setX((event->pos().x()-offsetX)/scale);
|
||||||
|
lastPoint_.setY((event->pos().y()-offsetY)/scale);
|
||||||
|
|
||||||
|
scribbling_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if ((event->buttons() & Qt::LeftButton) && scribbling_)
|
||||||
|
{
|
||||||
|
float scale, offsetX, offsetY;
|
||||||
|
computeScaleOffsets(rect(), scale, offsetX, offsetY);
|
||||||
|
QPoint to;
|
||||||
|
to.setX((event->pos().x()-offsetX)/scale);
|
||||||
|
to.setY((event->pos().y()-offsetY)/scale);
|
||||||
|
drawLineTo(to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton && scribbling_) {
|
||||||
|
float scale, offsetX, offsetY;
|
||||||
|
computeScaleOffsets(rect(), scale, offsetX, offsetY);
|
||||||
|
QPoint to;
|
||||||
|
to.setX((event->pos().x()-offsetX)/scale);
|
||||||
|
to.setY((event->pos().y()-offsetY)/scale);
|
||||||
|
drawLineTo(to);
|
||||||
|
scribbling_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const
|
||||||
|
{
|
||||||
|
scale = 1.0f;
|
||||||
|
offsetX = 0.0f;
|
||||||
|
offsetY = 0.0f;
|
||||||
|
|
||||||
|
if(!map_.isNull())
|
||||||
|
{
|
||||||
|
float w = map_.width();
|
||||||
|
float h = map_.height();
|
||||||
|
float widthRatio = float(targetRect.width()) / w;
|
||||||
|
float heightRatio = float(targetRect.height()) / h;
|
||||||
|
|
||||||
|
//printf("w=%f, h=%f, wR=%f, hR=%f, sW=%d, sH=%d\n", w, h, widthRatio, heightRatio, this->rect().width(), this->rect().height());
|
||||||
|
if(widthRatio < heightRatio)
|
||||||
|
{
|
||||||
|
scale = widthRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = heightRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("ratio=%f\n",ratio);
|
||||||
|
|
||||||
|
w *= scale;
|
||||||
|
h *= scale;
|
||||||
|
|
||||||
|
if(w < targetRect.width())
|
||||||
|
{
|
||||||
|
offsetX = (targetRect.width() - w)/2.0f;
|
||||||
|
}
|
||||||
|
if(h < targetRect.height())
|
||||||
|
{
|
||||||
|
offsetY = (targetRect.height() - h)/2.0f;
|
||||||
|
}
|
||||||
|
//printf("offsetX=%f, offsetY=%f\n",offsetX, offsetY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
//Scale
|
||||||
|
float ratio, offsetX, offsetY;
|
||||||
|
this->computeScaleOffsets(event->rect(), ratio, offsetX, offsetY);
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
painter.translate(offsetX, offsetY);
|
||||||
|
painter.scale(ratio, ratio);
|
||||||
|
painter.drawImage(QPoint(0,0), map_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::contextMenuEvent(QContextMenuEvent * e)
|
||||||
|
{
|
||||||
|
QAction * action = menu_->exec(e->globalPos());
|
||||||
|
if(action == setPenWidth_)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
int width = QInputDialog::getInt(this, tr("Set Pen Width"), tr("Width:"), penWidth(), 1, 99, 1, &ok);
|
||||||
|
if(ok)
|
||||||
|
{
|
||||||
|
myPenWidth_ = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(action == resetChanges_)
|
||||||
|
{
|
||||||
|
this->resetChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMapArea::drawLineTo(const QPoint &endPoint)
|
||||||
|
{
|
||||||
|
QPainter painter(&map_);
|
||||||
|
QColor color;
|
||||||
|
|
||||||
|
//base on util3d::convertMap2Image8U();
|
||||||
|
if(addObstacle_->isChecked())
|
||||||
|
{
|
||||||
|
color.setRgb(0,0,0);
|
||||||
|
}
|
||||||
|
else if(clearObstacle_->isChecked())
|
||||||
|
{
|
||||||
|
color.setRgb(178,178,178);
|
||||||
|
}
|
||||||
|
else //unknown
|
||||||
|
{
|
||||||
|
color.setRgb(89,89,89);
|
||||||
|
}
|
||||||
|
painter.setPen(QPen(color, myPenWidth_, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||||
|
painter.drawLine(lastPoint_, endPoint);
|
||||||
|
modified_ = true;
|
||||||
|
|
||||||
|
update();
|
||||||
|
lastPoint_ = endPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>398</width>
|
<width>413</width>
|
||||||
<height>288</height>
|
<height>288</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>397</width>
|
<width>412</width>
|
||||||
<height>288</height>
|
<height>288</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -647,7 +647,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1547</width>
|
<width>1547</width>
|
||||||
<height>25</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
@@ -687,8 +687,10 @@
|
|||||||
<addaction name="menuExport_poses"/>
|
<addaction name="menuExport_poses"/>
|
||||||
<addaction name="menuExport_GPS"/>
|
<addaction name="menuExport_GPS"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionEdit_optimized_2D_map"/>
|
||||||
<addaction name="actionExport_saved_2D_map"/>
|
<addaction name="actionExport_saved_2D_map"/>
|
||||||
<addaction name="actionImport_2D_map"/>
|
<addaction name="actionImport_2D_map"/>
|
||||||
|
<addaction name="actionRegenerate_optimized_2D_map"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionView_optimized_mesh"/>
|
<addaction name="actionView_optimized_mesh"/>
|
||||||
<addaction name="actionUpdate_optimized_mesh"/>
|
<addaction name="actionUpdate_optimized_mesh"/>
|
||||||
@@ -1300,7 +1302,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>318</width>
|
<width>318</width>
|
||||||
<height>219</height>
|
<height>197</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1461,8 +1463,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>282</width>
|
<width>280</width>
|
||||||
<height>885</height>
|
<height>875</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1995,8 +1997,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>307</width>
|
<width>296</width>
|
||||||
<height>171</height>
|
<height>160</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -2124,7 +2126,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>185</width>
|
<width>185</width>
|
||||||
<height>487</height>
|
<height>485</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -2781,12 +2783,12 @@
|
|||||||
</action>
|
</action>
|
||||||
<action name="actionExport_saved_2D_map">
|
<action name="actionExport_saved_2D_map">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Export saved 2D map...</string>
|
<string>Export optimized 2D map...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImport_2D_map">
|
<action name="actionImport_2D_map">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Import 2D map...</string>
|
<string>Import optimized 2D map...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionView_optimized_mesh">
|
<action name="actionView_optimized_mesh">
|
||||||
@@ -2822,6 +2824,16 @@
|
|||||||
<string>RGBD-SLAM (stamp tx ty tz qx qy qz qw)</string>
|
<string>RGBD-SLAM (stamp tx ty tz qx qy qz qw)</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionEdit_optimized_2D_map">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit optimized 2D map...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRegenerate_optimized_2D_map">
|
||||||
|
<property name="text">
|
||||||
|
<string>Regenerate optimized 2D map...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|||||||
Reference in New Issue
Block a user