Reprocess: added --skip option (to skip frames when reprocessing). Rtabmap: always save Loop/Map_id/ stat. UPlot: export NaN insted of NA for invalid values (compatible with octave). GraphViewer and ImageView: added support for PDF output format, also changed default directory to User's Pictures standard folder.

This commit is contained in:
matlabbe
2020-09-21 19:32:48 -04:00
parent 3d33370e4c
commit eef0a23b1b
5 changed files with 181 additions and 78 deletions
+3 -2
View File
@@ -3180,7 +3180,9 @@ bool Rtabmap::process(
statistics_.setProximityDetectionId(lastProximitySpaceClosureId);
statistics_.setProximityDetectionMapId(_memory->getMapId(lastProximitySpaceClosureId));
statistics_.addStatistic(Statistics::kLoopId(), _loopClosureHypothesis.first>0?_loopClosureHypothesis.first:lastProximitySpaceClosureId);
int loopId = _loopClosureHypothesis.first>0?_loopClosureHypothesis.first:lastProximitySpaceClosureId;
statistics_.addStatistic(Statistics::kLoopId(), loopId);
statistics_.addStatistic(Statistics::kLoopMap_id(), (loopId>0 && sLoop)?sLoop->mapId():-1);
float x,y,z,roll,pitch,yaw;
if(_loopClosureHypothesis.first || lastProximitySpaceClosureId)
@@ -3192,7 +3194,6 @@ bool Rtabmap::process(
UINFO("Set loop closure transform = %s", loopIter->second.transform().prettyPrint().c_str());
statistics_.setLoopClosureTransform(loopIter->second.transform());
statistics_.addStatistic(Statistics::kLoopMap_id(), sLoop->mapId());
statistics_.addStatistic(Statistics::kLoopVisual_words(), sLoop->getWords().size());
statistics_.addStatistic(Statistics::kLoopDistance_since_last_loc(), _distanceTravelledSinceLastLocalization);
_distanceTravelledSinceLastLocalization = 0.0f;
+85 -64
View File
@@ -37,6 +37,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtGui/QDesktopServices>
#include <QtGui/QContextMenuEvent>
#include <QColorDialog>
#include <QPrinter>
#include <QFileDialog>
#ifdef QT_SVG_LIB
#include <QtSvg/QSvgGenerator>
#endif
@@ -54,6 +56,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UTimer.h>
#include <QtGlobal>
#if QT_VERSION >= 0x050000
#include <QStandardPaths>
#endif
namespace rtabmap {
class NodeItem: public QGraphicsEllipseItem
@@ -1540,11 +1547,7 @@ QIcon createIcon(const QColor & color)
void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
{
QMenu menu;
QAction * aScreenShotPNG = menu.addAction(tr("Take a screenshot (PNG)"));
QAction * aScreenShotSVG = menu.addAction(tr("Take a screenshot (SVG)"));
#ifndef QT_SVG_LIB
aScreenShotSVG->setEnabled(false);
#endif
QAction * aScreenShot = menu.addAction(tr("Take a screenshot..."));
menu.addSeparator();
QAction * aChangeNodeColor = menu.addAction(createIcon(_nodeColor), tr("Set node color..."));
@@ -1710,85 +1713,103 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
QAction * aRestoreDefaults = menu.addAction(tr("Restore defaults"));
QAction * r = menu.exec(event->globalPos());
if(r == aScreenShotPNG || r == aScreenShotSVG)
if(r == aScreenShot)
{
if(_root)
{
QString targetDir = _workingDirectory + "/ScreensCaptured";
QString filePath;
#if QT_VERSION >= 0x050000
filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
#endif
QDir dir;
if(!dir.exists(targetDir))
if(!dir.exists(filePath))
{
dir.mkdir(targetDir);
filePath = QDir::homePath();
}
targetDir += "/";
targetDir += "Graph_view";
if(!dir.exists(targetDir))
{
dir.mkdir(targetDir);
}
targetDir += "/";
bool isPNG = r == aScreenShotPNG;
QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + (isPNG?".png":".svg"));
filePath += "/graph.png";
if(_gridCellSize)
#ifdef QT_SVG_LIB
filePath = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), filePath, "*.png *.xpm *.jpg *.pdf *.svg");
#else
filePath = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), filePath, "*.png *.xpm *.jpg *.pdf");
#endif
if(!filePath.isEmpty())
{
_root->setScale(1.0f/(_gridCellSize*100.0f)); // grid map precision (for 5cm grid cell, x20 to have 1pix/5cm)
}
else
{
_root->setScale(this->transform().m11()); // current view
}
this->scene()->clearSelection(); // Selections would also render to the file
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QSize sceneSize = this->scene()->sceneRect().size().toSize();
if(isPNG)
{
QImage image(sceneSize, QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
image.fill(Qt::transparent); // Start all pixels transparent
QPainter painter(&image);
this->scene()->render(&painter);
if(!image.isNull())
if(QFileInfo(filePath).suffix() == "")
{
image.save(targetDir + name);
//use png by default
filePath += ".png";
}
if(_gridCellSize)
{
_root->setScale(1.0f/(_gridCellSize*100.0f)); // grid map precision (for 5cm grid cell, x20 to have 1pix/5cm)
}
else
{
QMessageBox::warning(this,
tr("Save PNG"),
tr("Could not export in PNG (the scene may be too large %1x%2), try saving in SVG.").arg(sceneSize.width()).arg(sceneSize.height()));
_root->setScale(this->transform().m11()); // current view
}
}
else
{
this->scene()->clearSelection(); // Selections would also render to the file
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QSize sceneSize = this->scene()->sceneRect().size().toSize();
if(QFileInfo(filePath).suffix().compare("pdf") == 0)
{
QPrinter printer(QPrinter::HighResolution);
printer.setOrientation(QPrinter::Portrait);
printer.setOutputFileName( filePath );
QPainter p(&printer);
scene()->render(&p);
p.end();
}
else if(QFileInfo(filePath).suffix().compare("svg") == 0)
{
#ifdef QT_SVG_LIB
QSvgGenerator svgGen;
QSvgGenerator svgGen;
svgGen.setFileName( targetDir + name );
svgGen.setSize(sceneSize);
// add 1% border to make sure values are not cropped
int borderH = sceneSize.width()/100;
int borderV = sceneSize.height()/100;
svgGen.setViewBox(QRect(-borderH, -borderV, sceneSize.width()+borderH*2, sceneSize.height()+borderV*2));
svgGen.setTitle(tr("RTAB-Map graph"));
svgGen.setDescription(tr("RTAB-Map map and graph"));
svgGen.setFileName( filePath );
svgGen.setSize(sceneSize);
// add 1% border to make sure values are not cropped
int borderH = sceneSize.width()/100;
int borderV = sceneSize.height()/100;
svgGen.setViewBox(QRect(-borderH, -borderV, sceneSize.width()+borderH*2, sceneSize.height()+borderV*2));
svgGen.setTitle(tr("RTAB-Map graph"));
svgGen.setDescription(tr("RTAB-Map map and graph"));
QPainter painter( &svgGen );
QPainter painter( &svgGen );
this->scene()->render(&painter);
this->scene()->render(&painter);
#else
UERROR("RTAB-MAp is not built with Qt's SVG library, cannot save picture in svg format.");
UERROR("RTAB-MAp is not built with Qt's SVG library, cannot save picture in svg format.");
#endif
}
else
{
QImage image(sceneSize, QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
image.fill(Qt::transparent); // Start all pixels transparent
QPainter painter(&image);
this->scene()->render(&painter);
if(!image.isNull())
{
image.save(filePath);
}
else
{
QMessageBox::warning(this,
tr("Save PNG"),
tr("Could not export in PNG (the scene may be too large %1x%2), try saving in SVG.").arg(sceneSize.width()).arg(sceneSize.height()));
}
}
//reset scale
_root->setScale(1.0f);
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
}
//reset scale
_root->setScale(1.0f);
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QDesktopServices::openUrl(QUrl::fromLocalFile(targetDir + name));
}
return; // without emitting configChanged
}
+49 -9
View File
@@ -37,11 +37,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QInputDialog>
#include <QVBoxLayout>
#include <QColorDialog>
#include <QPrinter>
#include <QGraphicsRectItem>
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/gui/KeypointItem.h"
#include "rtabmap/core/util2d.h"
#include <QtGlobal>
#if QT_VERSION >= 0x050000
#include <QStandardPaths>
#endif
namespace rtabmap {
//LineItem
@@ -158,7 +164,6 @@ QIcon ImageView::createIcon(const QColor & color)
ImageView::ImageView(QWidget * parent) :
QWidget(parent),
_savedFileName((QDir::homePath()+ "/") + "picture" + ".png"),
_alpha(100),
_featuresSize(0.0f),
_defaultBgColor(Qt::black),
@@ -168,6 +173,19 @@ ImageView::ImageView(QWidget * parent) :
_imageItem(0),
_imageDepthItem(0)
{
#if QT_VERSION >= 0x050000
_savedFileName = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
#endif
QDir dir;
if(!dir.exists(_savedFileName))
{
_savedFileName = QDir::homePath()+ "/picture.png";
}
else
{
_savedFileName += "/picture.png";
}
_graphicsView = new QGraphicsView(this);
_graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
_graphicsView->setScene(new QGraphicsScene(this));
@@ -806,11 +824,16 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
if(!_graphicsView->scene()->sceneRect().isNull())
{
QString text;
QString extensions = "*.png *.xpm *.jpg";
if(_graphicsView->isVisible())
{
extensions += " *.pdf";
}
#ifdef QT_SVG_LIB
text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, "*.png *.xpm *.jpg *.pdf *.svg");
#else
text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, "*.png *.xpm *.jpg *.pdf");
extensions += " *.svg";
#endif
text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, extensions);
if(!text.isEmpty())
{
if(QFileInfo(text).suffix() == "")
@@ -820,17 +843,34 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e)
}
_savedFileName = text;
QImage img(_graphicsView->sceneRect().width(), _graphicsView->sceneRect().height(), QImage::Format_ARGB32_Premultiplied);
QPainter p(&img);
if(_graphicsView->isVisible())
if(QFileInfo(text).suffix().compare("pdf") == 0)
{
QPrinter printer(QPrinter::HighResolution);
printer.setOrientation(QPrinter::Portrait);
printer.setOutputFileName( text );
QPainter p(&printer);
p.begin(&printer);
double xscale = printer.pageRect().width()/double(_graphicsView->sceneRect().width());
double yscale = printer.pageRect().height()/double(_graphicsView->sceneRect().height());
double scale = qMin(xscale, yscale);
p.scale(scale, scale);
_graphicsView->scene()->render(&p, _graphicsView->sceneRect(), _graphicsView->sceneRect());
p.end();
}
else
{
this->render(&p, QPoint(), _graphicsView->sceneRect().toRect());
QImage img(_graphicsView->sceneRect().width(), _graphicsView->sceneRect().height(), QImage::Format_ARGB32_Premultiplied);
QPainter p(&img);
if(_graphicsView->isVisible())
{
_graphicsView->scene()->render(&p, _graphicsView->sceneRect(), _graphicsView->sceneRect());
}
else
{
this->render(&p, QPoint(), _graphicsView->sceneRect().toRect());
}
img.save(text);
}
img.save(text);
}
}
}
+1 -1
View File
@@ -1743,7 +1743,7 @@ void UPlotLegend::contextMenuEvent(QContextMenuEvent * event)
{
if(uIsNan(axes[j][i]))
{
text.append("NA");
text.append("NaN"); // NaN is interpreted by default as NaN in MatLab/Octave
}
else
{
+43 -2
View File
@@ -58,6 +58,7 @@ void showUsage()
" To see warnings when loop closures are rejected, add \"--uwarn\" argument.\n"
" Options:\n"
" -r Use database stamps as input rate.\n"
" -skip # Skip # frames after each processed frame (default 0=don't skip any frames).\n"
" -c \"path.ini\" Configuration file, overwriting parameters read \n"
" from the database. If custom parameters are also set as \n"
" arguments, they overwrite those in config file and the database.\n"
@@ -213,6 +214,7 @@ int main(int argc, char * argv[])
bool useDatabaseRate = false;
int startId = 0;
int stopId = 0;
int framesToSkip = 0;
bool scanFromDepth = false;
int scanDecimation = 1;
float scanRangeMin = 0.0f;
@@ -257,7 +259,7 @@ int main(int argc, char * argv[])
}
else
{
printf("-start option require a value\n");
printf("-start option requires a value\n");
showUsage();
}
}
@@ -271,7 +273,21 @@ int main(int argc, char * argv[])
}
else
{
printf("-stop option require a value\n");
printf("-stop option requires a value\n");
showUsage();
}
}
else if (strcmp(argv[i], "-skip") == 0 || strcmp(argv[i], "--skip") == 0)
{
++i;
if(i < argc - 2)
{
framesToSkip = atoi(argv[i]);
printf("Will skip %d frames.\n", framesToSkip);
}
else
{
printf("-skip option requires a value\n");
showUsage();
}
}
@@ -516,6 +532,11 @@ int main(int argc, char * argv[])
delete dbDriver;
dbDriver = 0;
if(framesToSkip)
{
totalIds/=framesToSkip+1;
}
std::string workingDirectory = UDirectory::getDir(outputDatabasePath);
printf("Set working directory to \"%s\".\n", workingDirectory.c_str());
uInsert(parameters, ParametersPair(Parameters::kRtabmapWorkingDirectory(), workingDirectory));
@@ -742,6 +763,26 @@ int main(int argc, char * argv[])
}
Transform odomPose = info.odomPose;
if(framesToSkip>0)
{
int skippedFrames = framesToSkip;
while(skippedFrames-- > 0)
{
data = dbReader->takeImage(&info);
if(!odometryIgnored && !info.odomCovariance.empty() && info.odomCovariance.at<double>(0,0)>=9999)
{
printf("High variance detected, triggering a new map...\n");
if(!incrementalMemory && processed>0)
{
showLocalizationStats(outputDatabasePath);
lastLocalizationOdomPose = info.odomPose;
}
rtabmap.triggerNewMap();
}
}
}
data = dbReader->takeImage(&info);
if(scanFromDepth)
{