30 #include "ui_mainWindow.h"
73 #include <QtGui/QCloseEvent>
74 #include <QtGui/QPixmap>
75 #include <QtCore/QDir>
76 #include <QtCore/QFile>
77 #include <QtCore/QTextStream>
78 #include <QtCore/QFileInfo>
79 #include <QMessageBox>
80 #include <QFileDialog>
81 #include <QGraphicsEllipseItem>
82 #include <QDockWidget>
83 #include <QtCore/QBuffer>
84 #include <QtCore/QTimer>
85 #include <QtCore/QTime>
86 #include <QActionGroup>
87 #include <QtGui/QDesktopServices>
88 #include <QtCore/QStringList>
89 #include <QtCore/QProcess>
90 #include <QSplashScreen>
91 #include <QInputDialog>
92 #include <QToolButton>
108 #include <pcl/visualization/cloud_viewer.h>
109 #include <pcl/common/transforms.h>
110 #include <pcl/common/common.h>
111 #include <pcl/io/pcd_io.h>
112 #include <pcl/io/ply_io.h>
113 #include <pcl/filters/filter.h>
114 #include <pcl/search/kdtree.h>
118 #ifdef RTABMAP_OCTOMAP
122 #ifdef RTABMAP_GRIDMAP
126 #ifdef HAVE_OPENCV_ARUCO
127 #include <opencv2/aruco.hpp>
130 #define LOG_FILE_NAME "LogRtabmap.txt"
131 #define SHARE_SHOW_LOG_FILE "share/rtabmap/showlogs.m"
132 #define SHARE_GET_PRECISION_RECALL_FILE "share/rtabmap/getPrecisionRecall.m"
133 #define SHARE_IMPORT_FILE "share/rtabmap/importfile.m"
149 _preferencesDialog(0),
151 _exportCloudsDialog(0),
152 _exportBundlerDialog(0),
156 _processingStatistics(
false),
157 _processingDownloadedMap(
false),
159 _odometryReceived(
false),
160 _newDatabasePath(
""),
161 _newDatabasePathOutput(
""),
162 _openedDatabasePath(
""),
163 _databaseUpdated(
false),
164 _odomImageShow(
true),
165 _odomImageDepthShow(
false),
166 _savedMaximized(
false),
168 _cachedMemoryUsage(0),
169 _createdCloudsMemoryUsage(0),
173 _odometryCorrection(
Transform::getIdentity()),
174 _processingOdometry(
false),
180 _rawLikelihoodCurve(0),
181 _exportPosesFrame(0),
182 _autoScreenCaptureOdomSync(
false),
183 _autoScreenCaptureRAM(
false),
184 _autoScreenCapturePNG(
false),
186 _progressCanceled(
false)
193 QSplashScreen * splash = 0;
194 if (showSplashScreen)
196 QPixmap pixmap(
":images/RTAB-Map.png");
197 splash =
new QSplashScreen(pixmap);
199 splash->showMessage(tr(
"Loading..."));
200 QApplication::processEvents();
215 _ui =
new Ui_mainWindow();
231 UDEBUG(
"Setup ui... end");
233 QString title(
"RTAB-Map[*]");
234 this->setWindowTitle(title);
235 this->setWindowIconText(tr(
"RTAB-Map"));
236 this->setObjectName(
"MainWindow");
241 _ui->widget_mainWindow->setVisible(
false);
257 bool statusBarShown =
false;
274 #ifdef RTABMAP_OCTOMAP
277 #ifdef RTABMAP_GRIDMAP
285 _ui->label_elapsedTime->setText(
"00:00:00");
291 _ui->imageView_source->setBackgroundColor(
_ui->imageView_source->getDefaultBackgroundColor());
292 _ui->imageView_loopClosure->setBackgroundColor(
_ui->imageView_loopClosure->getDefaultBackgroundColor());
293 _ui->imageView_odometry->setBackgroundColor(
_ui->imageView_odometry->getDefaultBackgroundColor());
294 _ui->imageView_odometry->setAlpha(200);
302 _ui->posteriorPlot->showLegend(
false);
303 _ui->posteriorPlot->setFixedYAxis(0,1);
310 _ui->likelihoodPlot->showLegend(
false);
314 _ui->rawLikelihoodPlot->showLegend(
false);
323 connect(
_ui->widget_mapVisibility, SIGNAL(visibilityChanged(
int,
bool)),
this, SLOT(
updateNodeVisibility(
int,
bool)));
326 connect(
_ui->actionExit, SIGNAL(triggered()),
this, SLOT(close()));
327 qRegisterMetaType<MainWindow::State>(
"MainWindow::State");
330 qRegisterMetaType<rtabmap::RtabmapEvent3DMap>(
"rtabmap::RtabmapEvent3DMap");
332 qRegisterMetaType<rtabmap::RtabmapGlobalPathEvent>(
"rtabmap::RtabmapGlobalPathEvent");
338 _ui->menuShow_view->addAction(
_ui->dockWidget_imageView->toggleViewAction());
339 _ui->menuShow_view->addAction(
_ui->dockWidget_posterior->toggleViewAction());
340 _ui->menuShow_view->addAction(
_ui->dockWidget_likelihood->toggleViewAction());
341 _ui->menuShow_view->addAction(
_ui->dockWidget_rawlikelihood->toggleViewAction());
342 _ui->menuShow_view->addAction(
_ui->dockWidget_statsV2->toggleViewAction());
343 _ui->menuShow_view->addAction(
_ui->dockWidget_console->toggleViewAction());
344 _ui->menuShow_view->addAction(
_ui->dockWidget_cloudViewer->toggleViewAction());
345 _ui->menuShow_view->addAction(
_ui->dockWidget_loopClosureViewer->toggleViewAction());
346 _ui->menuShow_view->addAction(
_ui->dockWidget_mapVisibility->toggleViewAction());
347 _ui->menuShow_view->addAction(
_ui->dockWidget_graphViewer->toggleViewAction());
348 _ui->menuShow_view->addAction(
_ui->dockWidget_odometry->toggleViewAction());
349 _ui->menuShow_view->addAction(
_ui->dockWidget_multiSessionLoc->toggleViewAction());
350 _ui->menuShow_view->addAction(
_ui->toolBar->toggleViewAction());
351 _ui->toolBar->setWindowTitle(tr(
"File toolbar"));
352 _ui->menuShow_view->addAction(
_ui->toolBar_2->toggleViewAction());
353 _ui->toolBar_2->setWindowTitle(tr(
"Control toolbar"));
354 QAction *
a =
_ui->menuShow_view->addAction(
"Progress dialog");
355 a->setCheckable(
false);
357 QAction * statusBarAction =
_ui->menuShow_view->addAction(
"Status bar");
358 statusBarAction->setCheckable(
true);
359 statusBarAction->setChecked(statusBarShown);
360 connect(statusBarAction, SIGNAL(toggled(
bool)), this->statusBar(), SLOT(setVisible(
bool)));
363 connect(
_ui->actionSave_GUI_config, SIGNAL(triggered()),
this, SLOT(
saveConfigGUI()));
364 connect(
_ui->actionNew_database, SIGNAL(triggered()),
this, SLOT(
newDatabase()));
365 connect(
_ui->actionOpen_database, SIGNAL(triggered()),
this, SLOT(
openDatabase()));
366 connect(
_ui->actionClose_database, SIGNAL(triggered()),
this, SLOT(
closeDatabase()));
367 connect(
_ui->actionEdit_database, SIGNAL(triggered()),
this, SLOT(
editDatabase()));
371 connect(
_ui->actionDump_the_memory, SIGNAL(triggered()),
this, SLOT(
dumpTheMemory()));
372 connect(
_ui->actionDump_the_prediction_matrix, SIGNAL(triggered()),
this, SLOT(
dumpThePrediction()));
373 connect(
_ui->actionSend_goal, SIGNAL(triggered()),
this, SLOT(
sendGoal()));
374 connect(
_ui->actionSend_waypoints, SIGNAL(triggered()),
this, SLOT(
sendWaypoints()));
375 connect(
_ui->actionCancel_goal, SIGNAL(triggered()),
this, SLOT(
cancelGoal()));
376 connect(
_ui->actionLabel_current_location, SIGNAL(triggered()),
this, SLOT(
label()));
377 connect(
_ui->actionRemove_label, SIGNAL(triggered()),
this, SLOT(
removeLabel()));
378 connect(
_ui->actionClear_cache, SIGNAL(triggered()),
this, SLOT(
clearTheCache()));
380 connect(
_ui->actionHelp, SIGNAL(triggered()),
this , SLOT(
openHelp()));
381 connect(
_ui->actionPrint_loop_closure_IDs_to_console, SIGNAL(triggered()),
this, SLOT(
printLoopClosureIds()));
383 connect(
_ui->actionRaw_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesRaw()));
387 connect(
_ui->actionKITTI_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesKITTI()));
390 connect(
_ui->actionDelete_memory, SIGNAL(triggered()),
this , SLOT(
deleteMemory()));
396 connect(
_ui->actionDefault_views, SIGNAL(triggered(
bool)),
this, SLOT(
setDefaultViews()));
398 connect(
_ui->actionScreenshot, SIGNAL(triggered()),
this, SLOT(
takeScreenshot()));
408 connect(
_ui->actionSave_point_cloud, SIGNAL(triggered()),
this, SLOT(
exportClouds()));
409 connect(
_ui->actionExport_2D_Grid_map_bmp_png, SIGNAL(triggered()),
this, SLOT(
exportGridMap()));
410 connect(
_ui->actionExport_images_RGB_jpg_Depth_png, SIGNAL(triggered()),
this , SLOT(
exportImages()));
411 connect(
_ui->actionExport_cameras_in_Bundle_format_out, SIGNAL(triggered()), SLOT(
exportBundlerFormat()));
412 connect(
_ui->actionExport_octomap, SIGNAL(triggered()),
this, SLOT(
exportOctomap()));
413 connect(
_ui->actionView_high_res_point_cloud, SIGNAL(triggered()),
this, SLOT(
viewClouds()));
414 connect(
_ui->actionReset_Odometry, SIGNAL(triggered()),
this, SLOT(
resetOdometry()));
415 connect(
_ui->actionTrigger_a_new_map, SIGNAL(triggered()),
this, SLOT(
triggerNewMap()));
416 connect(
_ui->actionData_recorder, SIGNAL(triggered()),
this, SLOT(
dataRecorder()));
418 connect(
_ui->actionDepth_Calibration, SIGNAL(triggered()),
this, SLOT(
depthCalibration()));
420 _ui->actionPause->setShortcut(Qt::Key_Space);
421 _ui->actionSave_GUI_config->setShortcut(QKeySequence::Save);
424 this->addAction(
_ui->actionSave_GUI_config);
425 _ui->actionReset_Odometry->setEnabled(
false);
426 _ui->actionPost_processing->setEnabled(
false);
427 _ui->actionAnchor_clouds_to_ground_truth->setEnabled(
false);
429 QToolButton* toolButton =
new QToolButton(
this);
430 toolButton->setMenu(
_ui->menuSelect_source);
431 toolButton->setPopupMode(QToolButton::InstantPopup);
432 toolButton->setIcon(QIcon(
":images/kinect_xbox_360.png"));
433 toolButton->setToolTip(
"Select sensor driver");
434 _ui->toolBar->addWidget(toolButton)->setObjectName(
"toolbar_source");
436 #if defined(Q_WS_MAC) || defined(Q_WS_WIN)
439 _ui->menuEdit->removeAction(
_ui->actionOpen_working_directory);
444 connect(
_ui->actionOpenNI_PCL, SIGNAL(triggered()),
this, SLOT(
selectOpenni()));
445 connect(
_ui->actionOpenNI_PCL_ASUS, SIGNAL(triggered()),
this, SLOT(
selectOpenni()));
447 connect(
_ui->actionOpenNI_CV, SIGNAL(triggered()),
this, SLOT(
selectOpenniCv()));
449 connect(
_ui->actionOpenNI2, SIGNAL(triggered()),
this, SLOT(
selectOpenni2()));
450 connect(
_ui->actionOpenNI2_kinect, SIGNAL(triggered()),
this, SLOT(
selectOpenni2()));
451 connect(
_ui->actionOpenNI2_orbbec, SIGNAL(triggered()),
this, SLOT(
selectOpenni2()));
452 connect(
_ui->actionOpenNI2_sense, SIGNAL(triggered()),
this, SLOT(
selectOpenni2()));
454 connect(
_ui->actionKinect_for_Windows_SDK_v2, SIGNAL(triggered()),
this, SLOT(
selectK4W2()));
455 connect(
_ui->actionKinect_for_Azure, SIGNAL(triggered()),
this, SLOT(
selectK4A()));
456 connect(
_ui->actionRealSense_R200, SIGNAL(triggered()),
this, SLOT(
selectRealSense()));
457 connect(
_ui->actionRealSense_ZR300, SIGNAL(triggered()),
this, SLOT(
selectRealSense()));
468 connect(
_ui->actionMYNT_EYE_S_SDK, SIGNAL(triggered()),
this, SLOT(
selectMyntEyeS()));
473 connect(
_ui->actionVelodyne_VLP_16, SIGNAL(triggered()),
this, SLOT(
selectVLP16()));
506 QActionGroup * modeGrp =
new QActionGroup(
this);
507 modeGrp->addAction(
_ui->actionSLAM_mode);
508 modeGrp->addAction(
_ui->actionLocalization_mode);
516 qRegisterMetaType<PreferencesDialog::PANEL_FLAGS>(
"PreferencesDialog::PANEL_FLAGS");
518 qRegisterMetaType<rtabmap::ParametersMap>(
"rtabmap::ParametersMap");
536 connect(
_ui->toolBar->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
configGUIModified()));
537 connect(
_ui->toolBar, SIGNAL(orientationChanged(Qt::Orientation)),
this, SLOT(
configGUIModified()));
538 connect(statusBarAction, SIGNAL(toggled(
bool)),
this, SLOT(
configGUIModified()));
539 QList<QDockWidget*> dockWidgets = this->findChildren<QDockWidget*>();
540 for(
int i=0;
i<dockWidgets.size(); ++
i)
542 connect(dockWidgets[
i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
this, SLOT(
configGUIModified()));
543 connect(dockWidgets[
i]->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
configGUIModified()));
545 connect(
_ui->dockWidget_graphViewer->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
547 _ui->dockWidget_posterior->installEventFilter(
this);
548 _ui->dockWidget_likelihood->installEventFilter(
this);
549 _ui->dockWidget_rawlikelihood->installEventFilter(
this);
550 _ui->dockWidget_statsV2->installEventFilter(
this);
551 _ui->dockWidget_console->installEventFilter(
this);
552 _ui->dockWidget_loopClosureViewer->installEventFilter(
this);
553 _ui->dockWidget_mapVisibility->installEventFilter(
this);
554 _ui->dockWidget_graphViewer->installEventFilter(
this);
555 _ui->dockWidget_odometry->installEventFilter(
this);
556 _ui->dockWidget_cloudViewer->installEventFilter(
this);
557 _ui->dockWidget_imageView->installEventFilter(
this);
558 _ui->dockWidget_multiSessionLoc->installEventFilter(
this);
572 qRegisterMetaType<rtabmap::Statistics>(
"rtabmap::Statistics");
575 qRegisterMetaType<rtabmap::SensorCaptureInfo>(
"rtabmap::SensorCaptureInfo");
578 qRegisterMetaType<rtabmap::OdometryEvent>(
"rtabmap::OdometryEvent");
587 _ui->statsToolBox->setNewFigureMaxItems(50);
601 if(
_ui->statsToolBox->findChildren<
StatItem*>().size() == 0)
604 for(std::map<std::string, float>::const_iterator
iter = statistics.begin();
iter != statistics.end(); ++
iter)
607 if(!QString((*iter).first.c_str()).contains(
"Gt/"))
609 _ui->statsToolBox->updateStat(QString((*iter).first.c_str()).replace(
'_',
' '),
false);
614 _ui->statsToolBox->updateStat(
"Planning/From/",
false);
615 _ui->statsToolBox->updateStat(
"Planning/Time/ms",
false);
616 _ui->statsToolBox->updateStat(
"Planning/Goal/",
false);
617 _ui->statsToolBox->updateStat(
"Planning/Poses/",
false);
618 _ui->statsToolBox->updateStat(
"Planning/Length/m",
false);
620 _ui->statsToolBox->updateStat(
"Camera/Time capturing/ms",
false);
621 _ui->statsToolBox->updateStat(
"Camera/Time deskewing/ms",
false);
622 _ui->statsToolBox->updateStat(
"Camera/Time undistort depth/ms",
false);
623 _ui->statsToolBox->updateStat(
"Camera/Time bilateral filtering/ms",
false);
624 _ui->statsToolBox->updateStat(
"Camera/Time decimation/ms",
false);
625 _ui->statsToolBox->updateStat(
"Camera/Time disparity/ms",
false);
626 _ui->statsToolBox->updateStat(
"Camera/Time mirroring/ms",
false);
627 _ui->statsToolBox->updateStat(
"Camera/Time histogram equalization/ms",
false);
628 _ui->statsToolBox->updateStat(
"Camera/Time exposure compensation/ms",
false);
629 _ui->statsToolBox->updateStat(
"Camera/Time scan from depth/ms",
false);
630 _ui->statsToolBox->updateStat(
"Camera/Time total/ms",
false);
632 _ui->statsToolBox->updateStat(
"Odometry/ID/",
false);
633 _ui->statsToolBox->updateStat(
"Odometry/Features/",
false);
634 _ui->statsToolBox->updateStat(
"Odometry/Matches/",
false);
635 _ui->statsToolBox->updateStat(
"Odometry/MatchesRatio/",
false);
636 _ui->statsToolBox->updateStat(
"Odometry/Inliers/",
false);
637 _ui->statsToolBox->updateStat(
"Odometry/InliersMeanDistance/m",
false);
638 _ui->statsToolBox->updateStat(
"Odometry/InliersDistribution/",
false);
639 _ui->statsToolBox->updateStat(
"Odometry/InliersRatio/",
false);
640 _ui->statsToolBox->updateStat(
"Odometry/ICPInliersRatio/",
false);
641 _ui->statsToolBox->updateStat(
"Odometry/ICPRotation/rad",
false);
642 _ui->statsToolBox->updateStat(
"Odometry/ICPTranslation/m",
false);
643 _ui->statsToolBox->updateStat(
"Odometry/ICPStructuralComplexity/",
false);
644 _ui->statsToolBox->updateStat(
"Odometry/ICPStructuralDistribution/",
false);
645 _ui->statsToolBox->updateStat(
"Odometry/ICPCorrespondences/",
false);
646 _ui->statsToolBox->updateStat(
"Odometry/ICPRMS/",
false);
647 _ui->statsToolBox->updateStat(
"Odometry/StdDevLin/m",
false);
648 _ui->statsToolBox->updateStat(
"Odometry/StdDevAng/rad",
false);
649 _ui->statsToolBox->updateStat(
"Odometry/VarianceLin/",
false);
650 _ui->statsToolBox->updateStat(
"Odometry/VarianceAng/",
false);
651 _ui->statsToolBox->updateStat(
"Odometry/TimeDeskewing/ms",
false);
652 _ui->statsToolBox->updateStat(
"Odometry/TimeEstimation/ms",
false);
653 _ui->statsToolBox->updateStat(
"Odometry/TimeFiltering/ms",
false);
654 _ui->statsToolBox->updateStat(
"Odometry/GravityRollError/deg",
false);
655 _ui->statsToolBox->updateStat(
"Odometry/GravityPitchError/deg",
false);
656 _ui->statsToolBox->updateStat(
"Odometry/LocalMapSize/",
false);
657 _ui->statsToolBox->updateStat(
"Odometry/LocalScanMapSize/",
false);
658 _ui->statsToolBox->updateStat(
"Odometry/LocalKeyFrames/",
false);
659 _ui->statsToolBox->updateStat(
"Odometry/localBundleOutliers/",
false);
660 _ui->statsToolBox->updateStat(
"Odometry/localBundleConstraints/",
false);
661 _ui->statsToolBox->updateStat(
"Odometry/localBundleTime/ms",
false);
662 _ui->statsToolBox->updateStat(
"Odometry/localBundleAvgInlierDistance/pix",
false);
663 _ui->statsToolBox->updateStat(
"Odometry/localBundleMaxKeyFramesForInlier/",
false);
664 _ui->statsToolBox->updateStat(
"Odometry/KeyFrameAdded/",
false);
665 _ui->statsToolBox->updateStat(
"Odometry/Interval/ms",
false);
666 _ui->statsToolBox->updateStat(
"Odometry/Speed/kph",
false);
667 _ui->statsToolBox->updateStat(
"Odometry/Speed/mph",
false);
668 _ui->statsToolBox->updateStat(
"Odometry/Speed/mps",
false);
669 _ui->statsToolBox->updateStat(
"Odometry/SpeedGuess/kph",
false);
670 _ui->statsToolBox->updateStat(
"Odometry/SpeedGuess/mph",
false);
671 _ui->statsToolBox->updateStat(
"Odometry/SpeedGuess/mps",
false);
672 _ui->statsToolBox->updateStat(
"Odometry/Distance/m",
false);
673 _ui->statsToolBox->updateStat(
"Odometry/T/m",
false);
674 _ui->statsToolBox->updateStat(
"Odometry/Tx/m",
false);
675 _ui->statsToolBox->updateStat(
"Odometry/Ty/m",
false);
676 _ui->statsToolBox->updateStat(
"Odometry/Tz/m",
false);
677 _ui->statsToolBox->updateStat(
"Odometry/Troll/deg",
false);
678 _ui->statsToolBox->updateStat(
"Odometry/Tpitch/deg",
false);
679 _ui->statsToolBox->updateStat(
"Odometry/Tyaw/deg",
false);
680 _ui->statsToolBox->updateStat(
"Odometry/Px/m",
false);
681 _ui->statsToolBox->updateStat(
"Odometry/Py/m",
false);
682 _ui->statsToolBox->updateStat(
"Odometry/Pz/m",
false);
683 _ui->statsToolBox->updateStat(
"Odometry/Proll/deg",
false);
684 _ui->statsToolBox->updateStat(
"Odometry/Ppitch/deg",
false);
685 _ui->statsToolBox->updateStat(
"Odometry/Pyaw/deg",
false);
687 _ui->statsToolBox->updateStat(
"GUI/Refresh odom/ms",
false);
688 _ui->statsToolBox->updateStat(
"GUI/RGB-D cloud/ms",
false);
689 _ui->statsToolBox->updateStat(
"GUI/Graph Update/ms",
false);
690 #ifdef RTABMAP_OCTOMAP
691 _ui->statsToolBox->updateStat(
"GUI/Octomap Update/ms",
false);
692 _ui->statsToolBox->updateStat(
"GUI/Octomap Rendering/ms",
false);
694 #ifdef RTABMAP_GRIDMAP
695 _ui->statsToolBox->updateStat(
"GUI/Elevation Update/ms",
false);
696 _ui->statsToolBox->updateStat(
"GUI/Elevation Rendering/ms",
false);
698 _ui->statsToolBox->updateStat(
"GUI/Grid Update/ms",
false);
699 _ui->statsToolBox->updateStat(
"GUI/Grid Rendering/ms",
false);
700 _ui->statsToolBox->updateStat(
"GUI/Refresh stats/ms",
false);
701 _ui->statsToolBox->updateStat(
"GUI/Cache Data Size/MB",
false);
702 _ui->statsToolBox->updateStat(
"GUI/Cache Clouds Size/MB",
false);
703 #ifdef RTABMAP_OCTOMAP
704 _ui->statsToolBox->updateStat(
"GUI/Octomap Size/MB",
false);
732 #ifdef RTABMAP_OCTOMAP
735 #ifdef RTABMAP_GRIDMAP
746 qobject_cast<QHBoxLayout *>(
_ui->layout_imageview->layout())->setDirection(QBoxLayout::TopToBottom);
750 qobject_cast<QHBoxLayout *>(
_ui->layout_imageview->layout())->setDirection(QBoxLayout::LeftToRight);
756 return _ui->widget_mapVisibility->getVisiblePoses();
794 bool processStopped =
true;
807 processStopped =
false;
815 if(this->isWindowModified())
817 QMessageBox::Button
b=QMessageBox::question(
this,
819 tr(
"There are unsaved changed settings. Save them?"),
820 QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
821 if(
b == QMessageBox::Save)
825 else if(
b != QMessageBox::Discard)
837 _ui->statsToolBox->closeFigures();
839 _ui->dockWidget_imageView->close();
840 _ui->dockWidget_likelihood->close();
841 _ui->dockWidget_rawlikelihood->close();
842 _ui->dockWidget_posterior->close();
843 _ui->dockWidget_statsV2->close();
844 _ui->dockWidget_console->close();
845 _ui->dockWidget_cloudViewer->close();
846 _ui->dockWidget_loopClosureViewer->close();
847 _ui->dockWidget_mapVisibility->close();
848 _ui->dockWidget_graphViewer->close();
849 _ui->dockWidget_odometry->close();
850 _ui->dockWidget_multiSessionLoc->close();
854 UERROR(
"Camera must be already deleted here!");
865 UERROR(
"OdomThread must be already deleted here!");
885 else if(anEvent->
getClassName().compare(
"RtabmapEvent") == 0)
889 int highestHypothesisId =
int(
uValue(
stats.data(), Statistics::kLoopHighest_hypothesis_id(), 0.0f));
890 int proximityClosureId =
int(
uValue(
stats.data(), Statistics::kProximitySpace_last_detection_id(), 0.0f));
891 bool rejectedHyp = bool(
uValue(
stats.data(), Statistics::kLoopRejectedHypothesis(), 0.0f));
892 float highestHypothesisValue =
uValue(
stats.data(), Statistics::kLoopHighest_hypothesis_value(), 0.0f);
893 if((
stats.loopClosureId() > 0 &&
894 _ui->actionPause_on_match->isChecked())
896 (
stats.loopClosureId() == 0 &&
897 highestHypothesisId > 0 &&
899 _ui->actionPause_when_a_loop_hypothesis_is_rejected->isChecked() &&
902 (proximityClosureId > 0 &&
903 _ui->actionPause_on_local_loop_detection->isChecked()))
909 QMetaObject::invokeMethod(
this,
"beep");
921 else if(anEvent->
getClassName().compare(
"RtabmapEventInit") == 0)
929 else if(anEvent->
getClassName().compare(
"RtabmapEvent3DMap") == 0)
934 else if(anEvent->
getClassName().compare(
"RtabmapGlobalPathEvent") == 0)
939 else if(anEvent->
getClassName().compare(
"RtabmapLabelErrorEvent") == 0)
944 else if(anEvent->
getClassName().compare(
"RtabmapGoalStatusEvent") == 0)
948 else if(anEvent->
getClassName().compare(
"SensorEvent") == 0)
955 QMetaObject::invokeMethod(
this,
"beep");
979 else if(anEvent->
getClassName().compare(
"OdometryEvent") == 0)
998 else if(anEvent->
getClassName().compare(
"ULogEvent") == 0)
1003 QMetaObject::invokeMethod(
_ui->dockWidget_console,
"show");
1010 QMetaObject::invokeMethod(
this,
"beep");
1057 if(
_ui->imageView_odometry->toolTip().isEmpty())
1059 _ui->imageView_odometry->setToolTip(
1060 "Background Color Code:\n"
1061 " Dark Red = Odometry Lost\n"
1062 " Dark Yellow = Low Inliers\n"
1063 "Feature Color code:\n"
1064 " Green = Inliers\n"
1065 " Yellow = Not matched features from previous frame(s)\n"
1071 bool lostStateChanged =
false;
1078 _ui->imageView_odometry->setBackgroundColor(Qt::darkRed);
1090 _ui->imageView_odometry->setBackgroundColor(Qt::darkYellow);
1097 _ui->imageView_odometry->setBackgroundColor(
_ui->imageView_odometry->getDefaultBackgroundColor());
1100 if(!pose.
isNull() && (
_ui->dockWidget_cloudViewer->isVisible() ||
_ui->graphicsView_graphView->isVisible()))
1108 if(!
data->imageRaw().empty() &&
1110 (
_ui->dockWidget_odometry->isVisible() && (
_ui->imageView_odometry->isImageShown() ||
_ui->imageView_odometry->isImageDepthShown()))))
1114 bool imagesAlreadyRectified = Parameters::defaultRtabmapImagesAlreadyRectified();
1115 Parameters::parse(allParameters, Parameters::kRtabmapImagesAlreadyRectified(), imagesAlreadyRectified);
1116 if(!imagesAlreadyRectified)
1118 rectifiedData = odom.
data();
1119 if(
data->cameraModels().size())
1122 UASSERT(
int((
data->imageRaw().cols/
data->cameraModels().size())*
data->cameraModels().size()) ==
data->imageRaw().cols);
1123 int subImageWidth =
data->imageRaw().cols/
data->cameraModels().size();
1124 cv::Mat rectifiedImages =
data->imageRaw().clone();
1130 for(
unsigned int i=0;
i<
data->cameraModels().
size(); ++
i)
1132 if(
data->cameraModels()[
i].isValidForRectification())
1139 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)...",
i);
1141 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)... done!",
i);
1146 cv::Mat rectifiedImage =
_rectCameraModelsOdom[
i].rectifyImage(cv::Mat(
data->imageRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->imageRaw().rows)));
1147 rectifiedImage.copyTo(cv::Mat(rectifiedImages, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->imageRaw().rows)));
1151 UWARN(
"Camera %d of data %d is not valid for rectification (%dx%d).",
1153 data->cameraModels()[
i].imageWidth(),
1154 data->cameraModels()[
i].imageHeight());
1159 else if(!
data->rightRaw().empty() &&
data->stereoCameraModels().size())
1161 UASSERT(
int((
data->imageRaw().cols/
data->stereoCameraModels().size())*
data->stereoCameraModels().size()) ==
data->imageRaw().cols);
1162 int subImageWidth =
data->imageRaw().cols/
data->stereoCameraModels().size();
1163 cv::Mat rectifiedLeftImages =
data->imageRaw().clone();
1164 cv::Mat rectifiedRightImages =
data->imageRaw().clone();
1170 for(
unsigned int i=0;
i<
data->stereoCameraModels().
size(); ++
i)
1172 if(
data->stereoCameraModels()[
i].isValidForRectification())
1180 UWARN(
"Initializing rectification maps for stereo camera %d (only done for the first image received)...",
i);
1183 UWARN(
"Initializing rectification maps for stereo camera %d (only done for the first image received)... done!",
i);
1190 cv::Mat rectifiedLeftImage =
_rectCameraModelsOdom[
i*2].rectifyImage(cv::Mat(
data->imageRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->imageRaw().rows)));
1191 cv::Mat rectifiedRightImage =
_rectCameraModelsOdom[
i*2+1].rectifyImage(cv::Mat(
data->rightRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->rightRaw().rows)));
1192 rectifiedLeftImage.copyTo(cv::Mat(rectifiedLeftImages, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->imageRaw().rows)));
1193 rectifiedRightImage.copyTo(cv::Mat(rectifiedRightImages, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data->rightRaw().rows)));
1197 UWARN(
"Stereo camera %d of data %d is not valid for rectification (%dx%d).",
1199 data->stereoCameraModels()[
i].left().imageWidth(),
1200 data->stereoCameraModels()[
i].right().imageHeight());
1203 rectifiedData.
setStereoImage(rectifiedLeftImages, rectifiedRightImages,
data->stereoCameraModels());
1205 UDEBUG(
"Time rectification: %fs",
time.ticks());
1206 data = &rectifiedData;
1210 if(
_ui->dockWidget_cloudViewer->isVisible())
1212 bool cloudUpdated =
false;
1213 bool scanUpdated =
false;
1214 bool featuresUpdated =
false;
1215 bool filteredGravityUpdated =
false;
1216 bool accelerationUpdated =
false;
1220 if(!
data->imageRaw().empty() &&
1221 !
data->depthOrRightRaw().empty() &&
1222 (
data->cameraModels().size() ||
data->stereoCameraModels().size()) &&
1225 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
1226 pcl::IndicesPtr
indices(
new std::vector<int>);
1242 pcl::PointCloud<pcl::PointXYZRGB>::Ptr output(
new pcl::PointCloud<pcl::PointXYZRGB>);
1246 Eigen::Vector3f viewpoint(0.0
f,0.0
f,0.0
f);
1247 if(
data->cameraModels().size() && !
data->cameraModels()[0].localTransform().isNull())
1249 viewpoint[0] =
data->cameraModels()[0].localTransform().x();
1250 viewpoint[1] =
data->cameraModels()[0].localTransform().y();
1251 viewpoint[2] =
data->cameraModels()[0].localTransform().z();
1253 else if(
data->stereoCameraModels().size() && !
data->stereoCameraModels()[0].localTransform().isNull())
1255 viewpoint[0] =
data->stereoCameraModels()[0].localTransform().x();
1256 viewpoint[1] =
data->stereoCameraModels()[0].localTransform().y();
1257 viewpoint[2] =
data->stereoCameraModels()[0].localTransform().z();
1264 Eigen::Vector3f(pose.
x(), pose.
y(), pose.
z()) + viewpoint);
1269 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
1270 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1271 textureMesh->tex_polygons.push_back(polygons);
1272 int w = cloud->width;
1273 int h = cloud->height;
1275 textureMesh->tex_coordinates.resize(1);
1276 int nPoints = (
int)(textureMesh->cloud.data.size()/textureMesh->cloud.point_step);
1277 textureMesh->tex_coordinates[0].resize(nPoints);
1278 for(
int i=0;
i<nPoints; ++
i)
1281 textureMesh->tex_coordinates[0][
i] = Eigen::Vector2f(
1282 float(
i %
w) /
float(
w),
1283 float(
h -
i /
w) /
float(
h));
1286 pcl::TexMaterial mesh_material;
1287 mesh_material.tex_d = 1.0f;
1288 mesh_material.tex_Ns = 75.0f;
1289 mesh_material.tex_illum = 1;
1291 mesh_material.tex_name =
"material_odom";
1292 mesh_material.tex_file =
"";
1293 textureMesh->tex_materials.push_back(mesh_material);
1297 UERROR(
"Adding cloudOdom to viewer failed!");
1302 UERROR(
"Adding cloudOdom to viewer failed!");
1310 UERROR(
"Adding cloudOdom to viewer failed!");
1318 cloudUpdated =
true;
1330 bool scanAdded =
false;
1359 UERROR(
"Adding scanMapOdom to viewer failed!");
1372 if(!
data->laserScanRaw().isEmpty())
1386 bool scanAdded =
false;
1390 pcl::PointCloud<pcl::PointXYZINormal>::Ptr cloud;
1400 pcl::PointCloud<pcl::PointNormal>::Ptr cloud;
1410 pcl::PointCloud<pcl::PointXYZI>::Ptr cloud;
1420 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
1431 UERROR(
"Adding scanOdom to viewer failed!");
1449 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
1457 (*cloud)[
i].x =
iter->second.x;
1458 (*cloud)[
i].y =
iter->second.y;
1459 (*cloud)[
i].z =
iter->second.z;
1463 (*cloud)[
i].r = inlier?0:255;
1464 (*cloud)[
i].g = 255;
1478 featuresUpdated =
true;
1484 for(QMap<std::string, Transform>::iterator
iter = addedFrustums.begin();
iter!=addedFrustums.end(); ++
iter)
1487 if(splitted.size() == 2)
1489 int id = std::atoi(splitted.back().c_str());
1491 if(splitted.front().compare(
"f_odom_") == 0 &&
1501 std::string frustumId =
uFormat(
"f_odom_%d",
iter->first*10);
1504 for(
size_t i=0;
i<10; ++
i)
1506 std::string subFrustumId =
uFormat(
"f_odom_%d",
iter->first*10+
i);
1513 for(
size_t i=0;
i<models.size(); ++
i)
1518 QColor color = Qt::yellow;
1519 std::string subFrustumId =
uFormat(
"f_odom_%d",
iter->first*10+
i);
1527 (
data->imu().orientation().val[0]!=0 ||
1528 data->imu().orientation().val[1]!=0 ||
1529 data->imu().orientation().val[2]!=0 ||
1530 data->imu().orientation().val[3]!=0))
1535 _cloudViewer->
addOrUpdateLine(
"odom_imu_orientation",
_odometryCorrection*pose, (
_odometryCorrection*pose).
translation()*
Transform(gravity[0], gravity[1], gravity[2], 0, 0, 0)*pose.
rotation().
inverse(), Qt::yellow,
true,
true);
1536 filteredGravityUpdated =
true;
1539 (
data->imu().linearAcceleration().val[0]!=0 ||
1540 data->imu().linearAcceleration().val[1]!=0 ||
1541 data->imu().linearAcceleration().val[2]!=0))
1543 Eigen::Vector3f gravity(
1544 -
data->imu().linearAcceleration().val[0],
1545 -
data->imu().linearAcceleration().val[1],
1546 -
data->imu().linearAcceleration().val[2]);
1548 gravity =
data->imu().localTransform().toEigen3f()*gravity;
1549 _cloudViewer->
addOrUpdateLine(
"odom_imu_acc",
_odometryCorrection*pose,
_odometryCorrection*pose*
Transform(gravity[0], gravity[1], gravity[2], 0, 0, 0), Qt::red,
true,
true);
1550 accelerationUpdated =
true;
1580 UDEBUG(
"Time 3D Rendering: %fs",
time.ticks());
1587 if(
data->cameraModels().size() &&
data->cameraModels()[0].isValidForProjection())
1591 else if(
data->stereoCameraModels().size() &&
data->stereoCameraModels()[0].isValidForProjection())
1595 else if(!
data->laserScanRaw().isEmpty() ||
1596 !
data->laserScanCompressed().isEmpty())
1599 if(!
data->laserScanRaw().isEmpty())
1601 scanLocalTransform =
data->laserScanRaw().localTransform();
1605 scanLocalTransform =
data->laserScanCompressed().localTransform();
1619 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
1630 UDEBUG(
"Time Update Pose: %fs",
time.ticks());
1635 if(
_ui->graphicsView_graphView->isVisible())
1640 _ui->graphicsView_graphView->update();
1641 UDEBUG(
"Time Update graphview: %fs",
time.ticks());
1645 if(
_ui->dockWidget_odometry->isVisible() &&
1646 !
data->imageRaw().empty())
1648 if(
_ui->imageView_odometry->isFeaturesShown())
1654 std::multimap<int, cv::KeyPoint> kpInliers;
1655 for(
unsigned int i=0;
i<odom.
info().reg.inliersIDs.size(); ++
i)
1659 _ui->imageView_odometry->setFeatures(
1666 _ui->imageView_odometry->setFeatures(
1679 std::vector<cv::KeyPoint> kpts;
1681 _ui->imageView_odometry->setFeatures(
1689 bool monoInitialization =
false;
1692 monoInitialization =
true;
1695 _ui->imageView_odometry->clearLines();
1696 if(lost && !monoInitialization)
1698 if(lostStateChanged)
1704 _ui->imageView_odometry->setImageDepth(
data->imageRaw());
1705 _ui->imageView_odometry->setImageShown(
true);
1706 _ui->imageView_odometry->setImageDepthShown(
true);
1710 if(lostStateChanged)
1718 if(
_ui->imageView_odometry->isImageDepthShown() && !
data->depthOrRightRaw().empty())
1720 _ui->imageView_odometry->setImageDepth(
data->depthOrRightRaw());
1731 for(
unsigned int i=0;
i<odom.
info().reg.matchesIDs.size(); ++
i)
1735 for(
unsigned int i=0;
i<odom.
info().reg.inliersIDs.size(); ++
i)
1745 if(
_ui->imageView_odometry->isFeaturesShown() ||
_ui->imageView_odometry->isLinesShown())
1750 int subImageWidth = 0;
1751 if(
data->cameraModels().size()>1 ||
data->stereoCameraModels().size()>1)
1753 subImageWidth =
data->cameraModels().size()?
data->cameraModels()[0].imageWidth():
data->stereoCameraModels()[0].left().imageWidth();
1755 for(
unsigned int i=0;
i<odom.
info().refCorners.size(); ++
i)
1757 if(
_ui->imageView_odometry->isFeaturesShown() && inliers.find(
i) != inliers.end())
1759 _ui->imageView_odometry->setFeatureColor(
i, Qt::green);
1761 if(
_ui->imageView_odometry->isLinesShown())
1766 _ui->imageView_odometry->addLine(
1771 inliers.find(
i) != inliers.end()?Qt::blue:Qt::yellow);
1778 if(!
data->imageRaw().empty())
1780 _ui->imageView_odometry->setSceneRect(QRectF(0,0,(
float)
data->imageRaw().cols, (
float)
data->imageRaw().rows));
1783 _ui->imageView_odometry->update();
1785 UDEBUG(
"Time update imageview: %fs",
time.ticks());
1802 for(
size_t i=0;
i<odom.
info().reg.matchesPerCam.size(); ++
i)
1806 for(
size_t i=0;
i<odom.
info().reg.inliersPerCam.size(); ++
i)
1812 for(
size_t i=0;
i<odom.
info().reg.matchesPerCam.size(); ++
i)
1853 for(
size_t i=0;
i<odom.
info().localBundleOutliersPerCam.size(); ++
i)
1944 if(!
data->groundTruth().isNull())
1961 UDEBUG(
"Time updating Stats toolbox: %fs",
time.ticks());
1972 QElapsedTimer
time, totalTime;
1982 int refMapId = -1, loopMapId = -1;
1987 int highestHypothesisId =
static_cast<float>(
uValue(stat.
data(), Statistics::kLoopHighest_hypothesis_id(), 0.0f));
1994 _ui->label_refId->setText(QString(
"New ID = %1 [%2]").arg(stat.
refImageId()).arg(refMapId));
1998 float totalTime =
static_cast<float>(
uValue(stat.
data(), Statistics::kTimingTotal(), 0.0f));
2005 bool highestHypothesisIsSaved = (bool)
uValue(stat.
data(), Statistics::kLoopHypothesis_reactivated(), 0.0f);
2007 bool smallMovement = (bool)
uValue(stat.
data(), Statistics::kMemorySmall_movement(), 0.0f);
2009 bool fastMovement = (bool)
uValue(stat.
data(), Statistics::kMemoryFast_movement(), 0.0f);
2011 int rehearsalMerged = (
int)
uValue(stat.
data(), Statistics::kMemoryRehearsal_merged(), 0.0f);
2019 else if(rehearsalMerged>0 &&
2026 if(signature.
id()!=0)
2031 _ui->imageView_source->isVisible() ||
2040 cv::Mat tmpRgb, tmpDepth, tmpG, tmpO, tmpE;
2043 uncompressImages?&tmpRgb:0,
2045 uncompressScan?&tmpScan:0,
2046 0, &tmpG, &tmpO, &tmpE);
2052 if(smallMovement || fastMovement)
2060 unsigned int count = 0;
2063 for(std::multimap<int, int>::const_iterator jter=signature.
getWords().upper_bound(-1); jter!=signature.
getWords().end(); ++jter)
2081 if(signature.
id() !=
iter->first &&
2083 (
_cachedSignatures.value(
iter->first).sensorData().imageCompressed().empty() && !
iter->second.sensorData().imageCompressed().empty())))
2087 unsigned int count = 0;
2088 if(!
iter->second.getWords3().empty())
2090 for(std::multimap<int, int>::const_iterator jter=
iter->second.getWords().upper_bound(-1); jter!=
iter->second.getWords().end(); ++jter)
2099 UINFO(
"Added node data %d [map=%d] to cache",
iter->first,
iter->second.mapId());
2102 if(!
iter->second.getGroundTruthPose().isNull())
2112 _ui->imageView_source->clear();
2113 _ui->imageView_loopClosure->clear();
2118 _ui->imageView_source->setSceneRect(QRect(0,0,640,480));
2121 _ui->imageView_source->setBackgroundColor(
_ui->imageView_source->getDefaultBackgroundColor());
2122 _ui->imageView_loopClosure->setBackgroundColor(
_ui->imageView_loopClosure->getDefaultBackgroundColor());
2124 _ui->label_matchId->clear();
2126 bool rehearsedSimilarity = (
float)
uValue(stat.
data(), Statistics::kMemoryRehearsal_id(), 0.0f) != 0.0
f;
2127 int proximityTimeDetections = (
int)
uValue(stat.
data(), Statistics::kProximityTime_detections(), 0.0f);
2128 bool scanMatchingSuccess = (bool)
uValue(stat.
data(), Statistics::kNeighborLinkRefiningAccepted(), 0.0f);
2129 _ui->label_stats_imageNumber->setText(QString(
"%1 [%2]").arg(stat.
refImageId()).arg(refMapId));
2131 if(rehearsalMerged > 0)
2133 _ui->imageView_source->setBackgroundColor(Qt::blue);
2135 else if(proximityTimeDetections > 0)
2137 _ui->imageView_source->setBackgroundColor(Qt::darkYellow);
2139 else if(scanMatchingSuccess)
2141 _ui->imageView_source->setBackgroundColor(Qt::darkCyan);
2143 else if(rehearsedSimilarity)
2145 _ui->imageView_source->setBackgroundColor(Qt::darkBlue);
2147 else if(smallMovement)
2149 _ui->imageView_source->setBackgroundColor(Qt::gray);
2151 else if(fastMovement)
2153 _ui->imageView_source->setBackgroundColor(Qt::magenta);
2156 if(
_ui->label_refId->toolTip().isEmpty())
2158 _ui->label_refId->setToolTip(
2159 "Background Color Code:\n"
2160 " Blue = Weight Update Merged\n"
2161 " Dark Blue = Weight Update\n"
2162 " Dark Yellow = Proximity Detection in Time\n"
2163 " Dark Cyan = Neighbor Link Refined\n"
2164 " Gray = Small Movement\n"
2165 " Magenta = Fast Movement\n"
2166 "Feature Color code:\n"
2168 " Yellow = New but Not Unique\n"
2169 " Red = In Vocabulary\n"
2170 " Blue = In Vocabulary and in Previous Signature\n"
2171 " Pink = In Vocabulary and in Loop Closure Signature\n"
2172 " Gray = Not Quantized to Vocabulary");
2175 if(
_ui->label_matchId->toolTip().isEmpty())
2177 _ui->label_matchId->setToolTip(
2178 "Background Color Code:\n"
2179 " Green = Accepted Loop Closure Detection\n"
2180 " Red = Rejected Loop Closure Detection\n"
2181 " Yellow = Proximity Detection in Space\n"
2182 "Feature Color code:\n"
2183 " Red = In Vocabulary\n"
2184 " Pink = In Vocabulary and in Loop Closure Signature\n"
2185 " Gray = Not Quantized to Vocabulary");
2188 int rejectedHyp = bool(
uValue(stat.
data(), Statistics::kLoopRejectedHypothesis(), 0.0f));
2189 float highestHypothesisValue =
uValue(stat.
data(), Statistics::kLoopHighest_hypothesis_value(), 0.0f);
2190 int landmarkId =
static_cast<int>(
uValue(stat.
data(), Statistics::kLoopLandmark_detected(), 0.0f));
2191 int landmarkNodeRef =
static_cast<int>(
uValue(stat.
data(), Statistics::kLoopLandmark_detected_node_ref(), 0.0f));
2194 int shownLoopId = 0;
2200 _ui->imageView_loopClosure->setBackgroundColor(Qt::green);
2201 _ui->label_stats_loopClosuresDetected->setText(QString::number(
_ui->label_stats_loopClosuresDetected->text().toInt() + 1));
2202 if(highestHypothesisIsSaved)
2204 _ui->label_stats_loopClosuresReactivatedDetected->setText(QString::number(
_ui->label_stats_loopClosuresReactivatedDetected->text().toInt() + 1));
2206 _ui->label_matchId->setText(QString(
"Match ID = %1 [%2]").arg(stat.
loopClosureId()).arg(loopMapId));
2211 _ui->imageView_loopClosure->setBackgroundColor(Qt::yellow);
2212 _ui->label_matchId->setText(QString(
"Local match = %1 [%2]").arg(stat.
proximityDetectionId()).arg(loopMapId));
2215 else if(landmarkId!=0)
2217 highestHypothesisId = landmarkNodeRef;
2223 _ui->imageView_loopClosure->setBackgroundColor(Qt::red);
2224 _ui->label_stats_loopClosuresRejected->setText(QString::number(
_ui->label_stats_loopClosuresRejected->text().toInt() + 1));
2225 _ui->label_matchId->setText(QString(
"Landmark rejected = %1 with %2").arg(landmarkId).arg(landmarkNodeRef));
2230 _ui->imageView_loopClosure->setBackgroundColor(QColor(
"orange"));
2231 _ui->label_matchId->setText(QString(
"Landmark match = %1 with %2").arg(landmarkId).arg(landmarkNodeRef));
2232 matchId = landmarkNodeRef;
2240 _ui->imageView_loopClosure->setBackgroundColor(Qt::red);
2241 _ui->label_stats_loopClosuresRejected->setText(QString::number(
_ui->label_stats_loopClosuresRejected->text().toInt() + 1));
2242 _ui->label_matchId->setText(QString(
"Loop hypothesis %1 rejected!").arg(highestHypothesisId));
2250 _ui->label_matchId->setText(QString(
"Highest hypothesis (%1)").arg(highestHypothesisId));
2256 shownLoopId = matchId>0?matchId:highestHypothesisId;
2263 _ui->imageView_source->isVisible() ||
2268 if(uncompressImages || uncompressScan)
2270 cv::Mat tmpRGB, tmpDepth;
2273 uncompressImages?&tmpRGB:0,
2274 uncompressImages?&tmpDepth:0,
2275 uncompressScan?&tmpScan:0);
2286 UDEBUG(
"time= %d ms (update detection ui)",
time.restart());
2302 if(refImage.channels() == 1)
2305 cvtColor(refImage, imgColor, cv::COLOR_GRAY2BGR);
2306 refImage = imgColor;
2310 refImage = refImage.clone();
2316 if(loopImage.channels() == 1)
2319 cv::cvtColor(loopImage, imgColor, cv::COLOR_GRAY2BGR);
2320 loopImage = imgColor;
2324 loopImage = loopImage.clone();
2332 qimageThread.
start();
2333 qimageLoopThread.
start();
2334 qimageThread.
join();
2335 qimageLoopThread.
join();
2337 QImage lcImg = qimageLoopThread.
getQImage();
2338 UDEBUG(
"time= %d ms (convert image to qt)",
time.restart());
2342 _ui->imageView_source->setImage(
img);
2367 if(sceneRect.isValid())
2369 _ui->imageView_source->setSceneRect(sceneRect);
2374 _ui->imageView_loopClosure->setImage(lcImg);
2380 if(
_ui->imageView_loopClosure->sceneRect().isNull())
2382 _ui->imageView_loopClosure->setSceneRect(
_ui->imageView_source->sceneRect());
2385 else if(
_ui->imageView_loopClosure->sceneRect().isNull() &&
2386 !
_ui->imageView_source->sceneRect().isNull())
2388 _ui->imageView_loopClosure->setSceneRect(
_ui->imageView_source->sceneRect());
2391 UDEBUG(
"time= %d ms (update detection imageviews)",
time.restart());
2394 std::multimap<int, cv::KeyPoint> wordsA;
2395 std::multimap<int, cv::KeyPoint> wordsB;
2398 wordsA.insert(wordsA.end(), std::make_pair(
iter->first, signature.
getWordsKpts()[
iter->second]));
2402 wordsB.insert(wordsB.end(), std::make_pair(
iter->first, loopSignature.
getWordsKpts()[
iter->second]));
2406 UDEBUG(
"time= %d ms (draw keypoints)",
time.restart());
2415 signature.
setPose(loopClosureTransform);
2417 if(
_ui->dockWidget_loopClosureViewer->isVisible())
2421 UINFO(
"Updating loop closure cloud view time=%fs", loopTimer.
elapsed());
2428 UDEBUG(
"time= %d ms (update loop closure viewer)",
time.restart());
2433 if(!stat.
posterior().empty() &&
_ui->dockWidget_posterior->isVisible())
2442 if(!stat.
likelihood().empty() &&
_ui->dockWidget_likelihood->isVisible())
2446 if(!stat.
rawLikelihood().empty() &&
_ui->dockWidget_rawlikelihood->isVisible())
2450 UDEBUG(
"time= %d ms (update likelihood and posterior)",
time.restart());
2455 const std::map<std::string, float> & statistics = stat.
data();
2456 std::string odomStr =
"Odometry/";
2457 for(std::map<std::string, float>::const_iterator
iter = statistics.begin();
iter != statistics.end(); ++
iter)
2460 if((*iter).first.size()<odomStr.size() || (*iter).first.substr(0, odomStr.size()).compare(odomStr)!=0)
2467 UDEBUG(
"time= %d ms (update stats toolbox)",
time.restart());
2477 if(stat.
poses().size())
2491 _ui->graphicsView_graphView->getWorldMapRotation()==0.0f &&
2497 _ui->graphicsView_graphView->setWorldMapRotation(gpsRotationOffset);
2500 _ui->graphicsView_graphView->getWorldMapRotation() != 0.0f)
2502 _ui->graphicsView_graphView->setWorldMapRotation(0.0
f);
2506 std::map<int, Transform> poses = stat.
poses();
2508 UDEBUG(
"time= %d ms (update gt-gps stuff)",
time.restart());
2510 UDEBUG(
"%d %d %d", poses.size(), poses.size()?poses.rbegin()->first:0, stat.
refImageId());
2550 if(
_ui->graphicsView_graphView->isVisible())
2552 _ui->graphicsView_graphView->updateReferentialPosition(poses.rbegin()->second);
2558 if(poses.find(stat.
refImageId())!=poses.end())
2560 poses.insert(std::make_pair(0, poses.at(stat.
refImageId())));
2563 if(groundTruth.find(stat.
refImageId())!=groundTruth.end())
2565 groundTruth.insert(std::make_pair(0, groundTruth.at(stat.
refImageId())));
2570 std::map<std::string, float> updateCloudSats;
2584 UDEBUG(
"time= %d ms (update map cloud)",
time.restart());
2588 for(std::map<std::string, float>::iterator
iter=updateCloudSats.begin();
iter!=updateCloudSats.end(); ++
iter)
2594 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
2617 if(
_ui->graphicsView_graphView->isVisible())
2623 _ui->graphicsView_graphView->updateNodeColorByValue(
"Posterior", stat.
posterior());
2640 std::map<int, float> colors;
2641 colors.insert(std::make_pair(stat.
odomCachePoses().rbegin()->first, 240));
2646 uInsert(colors, std::pair<int,float>(
iter->second.from()>
iter->second.to()?
iter->second.from():
iter->second.to(), 120));
2653 colors.insert(std::make_pair(
iter->first, 240));
2656 _ui->graphicsView_graphView->updateNodeColorByValue(
"Re-Localized", colors, 240);
2659 _ui->graphicsView_graphView->updateLocalPath(stat.
localPath());
2663 _ui->graphicsView_graphView->setGlobalPath(std::vector<std::pair<int, Transform> >());
2670 UDEBUG(
"time= %d ms (update graph view)",
time.restart());
2685 s.sensorData().clearRawData();
2686 s.sensorData().clearOccupancyGridRaw();
2697 std::vector<int> missingIds;
2698 bool ignoreNewData = smallMovement || fastMovement || signature.
getWeight()<0;
2705 for(std::set<int>::const_iterator
iter=ids.lower_bound(1);
iter!=ids.end(); ++
iter)
2711 (ster.value().getWeight() >=0 &&
2712 ster.value().sensorData().imageCompressed().empty() &&
2713 ster.value().sensorData().depthOrRightCompressed().empty() &&
2714 ster.value().sensorData().laserScanCompressed().empty()))
2716 missingIds.push_back(*
iter);
2720 if(!missingIds.empty())
2727 UDEBUG(
"time= %d ms (update cache)",
time.restart());
2731 _ui->label_stats_loopClosuresDetected->setText(QString::number(
_ui->label_stats_loopClosuresDetected->text().toInt() + 1));
2736 _ui->label_matchId->clear();
2738 float elapsedTime =
static_cast<float>(totalTime.elapsed());
2739 UINFO(
"Updating GUI time = %fs", elapsedTime/1000.0
f);
2759 #ifdef RTABMAP_OCTOMAP
2776 const std::map<int, Transform> & posesIn,
2777 const std::multimap<int, Link> & constraints,
2778 const std::map<int, int> & mapIdsIn,
2779 const std::map<int, std::string> & labels,
2780 const std::map<int, Transform> & groundTruths,
2781 const std::map<int, Transform> & odomCachePoses,
2782 const std::multimap<int, Link> & odomCacheConstraints,
2783 bool verboseProgress,
2784 std::map<std::string, float> * stats)
2787 std::map<int, Transform> nodePoses(posesIn.lower_bound(0), posesIn.end());
2788 UDEBUG(
"nodes=%d landmarks=%d constraints=%d mapIdsIn=%d labelsIn=%d",
2789 (
int)nodePoses.size(), (
int)(posesIn.size() - nodePoses.size()), (
int)constraints.size(), (
int)mapIdsIn.size(), (
int)
labels.size());
2808 std::map<int, Transform> poses;
2809 std::map<int, int> mapIds;
2814 bool hasZero = nodePoses.find(0) != nodePoses.end();
2817 std::map<int, Transform> posesInTmp = nodePoses;
2818 posesInTmp.erase(0);
2825 for(std::map<int, Transform>::iterator
iter= poses.begin();
iter!=poses.end(); ++
iter)
2827 std::map<int, int>::const_iterator jter = mapIdsIn.find(
iter->first);
2828 if(jter!=mapIdsIn.end())
2830 mapIds.insert(*jter);
2836 poses.insert(*nodePoses.find(0));
2842 QApplication::processEvents();
2851 std::map<int, bool> posesMask;
2852 for(std::map<int, Transform>::const_iterator
iter = nodePoses.begin();
iter!=nodePoses.end(); ++
iter)
2854 posesMask.insert(posesMask.end(), std::make_pair(
iter->first, poses.find(
iter->first) != poses.end()));
2856 _ui->widget_mapVisibility->setMap(nodePoses, posesMask);
2858 if(groundTruths.size() &&
_ui->actionAnchor_clouds_to_ground_truth->isChecked())
2860 for(std::map<int, Transform>::iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
2862 std::map<int, Transform>::const_iterator gtIter = groundTruths.find(
iter->first);
2863 if(gtIter!=groundTruths.end())
2865 iter->second = gtIter->second;
2869 UWARN(
"Not found ground truth pose for node %d",
iter->first);
2875 _ui->actionAnchor_clouds_to_ground_truth->setChecked(
false);
2880 if((maxNodes > 0 || altitudeDelta>0.0) && poses.size()>1)
2882 Transform currentPose = poses.rbegin()->second;
2883 if(poses.find(0) != poses.end())
2885 currentPose = poses.at(0);
2888 std::map<int, Transform> nearestPoses;
2894 if(altitudeDelta<=0.0 ||
2895 fabs(poses.at(
iter->first).z()-currentPose.
z())<altitudeDelta)
2897 nearestPoses.insert(*poses.find(
iter->first));
2903 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
2905 if(
fabs(
iter->second.z()-currentPose.
z())<altitudeDelta)
2907 nearestPoses.insert(*
iter);
2913 if(poses.find(0) != poses.end())
2915 nearestPoses.insert(*poses.find(0));
2921 UDEBUG(
"Update map with %d locations", poses.size());
2925 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
2927 if(!
iter->second.isNull())
2929 std::string cloudName =
uFormat(
"cloud%d",
iter->first);
2931 if(
iter->first == 0)
2933 viewerClouds.remove(cloudName);
2942 if(viewerClouds.contains(cloudName))
2947 if(tCloud.
isNull() ||
iter->second != tCloud)
2951 UERROR(
"Updating pose cloud %d failed!",
iter->first);
2970 else if(viewerClouds.contains(cloudName))
2976 std::string scanName =
uFormat(
"scan%d",
iter->first);
2977 if(
iter->first == 0)
2979 viewerClouds.remove(scanName);
2984 if(viewerClouds.contains(scanName))
2993 UERROR(
"Updating pose scan %d failed!",
iter->first);
3004 if(!jter->sensorData().laserScanCompressed().isEmpty() || !jter->sensorData().laserScanRaw().isEmpty())
3010 else if(viewerClouds.contains(scanName))
3016 bool updateGridMap =
3017 ((
_ui->graphicsView_graphView->isVisible() &&
_ui->graphicsView_graphView->isGridMapVisible()) ||
3020 bool updateOctomap =
false;
3021 bool updateElevationMap =
false;
3022 #ifdef RTABMAP_OCTOMAP
3028 #ifdef RTABMAP_GRIDMAP
3029 updateElevationMap =
3034 if(updateGridMap || updateOctomap || updateElevationMap)
3043 jter->sensorData().uncompressDataConst(0, 0, 0, 0, &ground, &obstacles, &
empty);
3045 double resolution = jter->sensorData().gridCellSize();
3052 if(ground.channels() == 2)
3056 if(obstacles.channels() == 2)
3060 if(
empty.channels() == 2)
3071 std::string featuresName =
uFormat(
"features%d",
iter->first);
3072 if(
iter->first == 0)
3074 viewerClouds.remove(featuresName);
3079 if(viewerClouds.contains(featuresName))
3084 if(tFeatures.
isNull() ||
iter->second != tFeatures)
3088 UERROR(
"Updating pose features %d failed!",
iter->first);
3097 if(!jter->getWords3().empty())
3103 else if(viewerClouds.contains(featuresName))
3109 std::string gravityName =
uFormat(
"gravity%d",
iter->first);
3110 if(
iter->first == 0)
3112 viewerLines.erase(gravityName);
3118 if(linkIter != constraints.end())
3120 Transform gravityT = linkIter->second.transform();
3123 _cloudViewer->
addOrUpdateLine(gravityName,
iter->second,
iter->second*
Transform(gravity[0], gravity[1], gravity[2], 0, 0, 0), Qt::yellow,
false,
false);
3126 else if(viewerLines.find(gravityName)!=viewerLines.end())
3135 if(poses.size() < 200 ||
i % 100 == 0)
3137 QApplication::processEvents();
3150 for(QMap<std::string, Transform>::iterator
iter = viewerClouds.begin();
iter!=viewerClouds.end(); ++
iter)
3154 if(splitted.size() == 2)
3156 id = std::atoi(splitted.back().c_str());
3157 if(poses.find(
id) == poses.end())
3168 for(std::set<std::string>::iterator
iter = viewerLines.begin();
iter!=viewerLines.end(); ++
iter)
3172 if(splitted.size() == 2)
3174 id = std::atoi(splitted.back().c_str());
3175 if(poses.find(
id) == poses.end())
3186 stats->insert(std::make_pair(
"GUI/RGB-D cloud/ms", (
float)
timer.
restart()*1000.0f));
3195 for(QMap<std::string, Transform>::iterator
iter = addedFrustums.begin();
iter!=addedFrustums.end(); ++
iter)
3198 if(splitted.size() == 2)
3200 if((splitted.front().compare(
"f_") == 0 || splitted.front().compare(
"f_gt_") == 0))
3214 std::map<int, Transform> posesWithOdomCache;
3216 if(
_ui->graphicsView_graphView->isVisible() ||
3219 posesWithOdomCache = posesIn;
3220 for(std::map<int, Transform>::const_iterator
iter=odomCachePoses.begin();
iter!=odomCachePoses.end(); ++
iter)
3230 std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > graphs;
3231 for(std::map<int, Transform>::iterator
iter=posesWithOdomCache.lower_bound(1);
iter!=posesWithOdomCache.end(); ++
iter)
3238 std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >
::iterator kter = graphs.find(mapId);
3239 if(kter == graphs.end())
3241 kter = graphs.insert(std::make_pair(mapId, pcl::PointCloud<pcl::PointXYZ>::Ptr(
new pcl::PointCloud<pcl::PointXYZ>))).first;
3243 pcl::PointXYZ pt(
iter->second.x(),
iter->second.y(),
iter->second.z());
3244 kter->second->push_back(pt);
3250 std::string frustumId =
uFormat(
"f_%d",
iter->first);
3259 if(
s.sensorData().cameraModels().size() == 1 ||
s.sensorData().stereoCameraModels().size()==1)
3261 const CameraModel &
model =
s.sensorData().stereoCameraModels().size()?
s.sensorData().stereoCameraModels()[0].left():
s.sensorData().cameraModels()[0];
3265 QColor color = (Qt::GlobalColor)((mapId+3) % 12 + 7 );
3270 std::string gtFrustumId =
uFormat(
"f_gt_%d",
iter->first);
3288 std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >
::iterator kter = graphs.find(mapId);
3289 if(kter == graphs.end())
3291 kter = graphs.insert(std::make_pair(mapId, pcl::PointCloud<pcl::PointXYZ>::Ptr(
new pcl::PointCloud<pcl::PointXYZ>))).first;
3294 pcl::PointXYZ pt(
t.
x(),
t.
y(),
t.z());
3295 kter->second->push_back(pt);
3300 for(std::map<
int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::
iterator iter=graphs.begin();
iter!=graphs.end(); ++
iter)
3302 QColor color = Qt::gray;
3303 if(
iter->first >= 0)
3305 color = (Qt::GlobalColor)((
iter->first+3) % 12 + 7 );
3313 UDEBUG(
"remove not used frustums");
3314 for(QMap<std::string, Transform>::iterator
iter = addedFrustums.begin();
iter!=addedFrustums.end(); ++
iter)
3317 if(splitted.size() == 2)
3319 int id = std::atoi(splitted.back().c_str());
3320 if((splitted.front().compare(
"f_") == 0 || splitted.front().compare(
"f_gt_") == 0) &&
3321 posesWithOdomCache.find(
id) == posesWithOdomCache.end())
3340 if(nodePoses.find(
iter->first)!=nodePoses.end())
3342 int mapId =
uValue(mapIdsIn,
iter->first, -1);
3343 QColor color = Qt::gray;
3346 color = (Qt::GlobalColor)((mapId+3) % 12 + 7 );
3361 stats->insert(std::make_pair(
"GUI/Graph Update/ms", (
float)
timer.
restart()*1000.0f));
3364 #ifdef RTABMAP_OCTOMAP
3372 UINFO(
"Octomap update time = %fs",
time.ticks());
3376 stats->insert(std::make_pair(
"GUI/Octomap Update/ms", (
float)
timer.
restart()*1000.0f));
3388 pcl::IndicesPtr obstacles(
new std::vector<int>);
3390 if(obstacles->size())
3396 UINFO(
"Octomap show 3d map time = %fs",
time.ticks());
3401 stats->insert(std::make_pair(
"GUI/Octomap Rendering/ms", (
float)
timer.
restart()*1000.0f));
3405 #ifdef RTABMAP_GRIDMAP
3413 UINFO(
"Elevation map update time = %fs",
time.ticks());
3417 stats->insert(std::make_pair(
"GUI/Elevation Update/ms", (
float)
timer.
restart()*1000.0f));
3425 float xMin, yMin, cellSize;
3435 if(mesh->cloud.data.size())
3440 UINFO(
"Show elevation map time = %fs",
time.ticks());
3445 stats->insert(std::make_pair(
"GUI/Elevation Rendering/ms", (
float)
timer.
restart()*1000.0f));
3450 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
3455 for(std::map<int, Transform>::const_iterator
iter=posesIn.begin();
iter!=posesIn.end() &&
iter->first<0; ++
iter)
3457 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
3464 std::string(
"landmark_str_") + num,
3474 if(
_ui->graphicsView_graphView->isVisible())
3476 std::multimap<int, Link> constraintsWithOdomCache;
3477 constraintsWithOdomCache = constraints;
3478 constraintsWithOdomCache.insert(odomCacheConstraints.begin(), odomCacheConstraints.end());
3479 _ui->graphicsView_graphView->updateGraph(posesWithOdomCache, constraintsWithOdomCache, mapIdsIn, std::map<int, int>(),
uKeysSet(odomCachePoses));
3483 for(std::map<int, Transform>::iterator
iter=gtPoses.begin();
iter!=gtPoses.end(); ++
iter)
3485 iter->second = mapToGt *
iter->second;
3487 _ui->graphicsView_graphView->updateGTGraph(gtPoses);
3495 if((
_ui->graphicsView_graphView->isVisible() &&
_ui->graphicsView_graphView->isGridMapVisible()) ||
3501 #ifdef RTABMAP_OCTOMAP
3515 stats->insert(std::make_pair(
"GUI/Grid Update/ms", (
float)
timer.
restart()*1000.0f));
3529 if(
_ui->graphicsView_graphView->isVisible() &&
_ui->graphicsView_graphView->isGridMapVisible())
3531 _ui->graphicsView_graphView->updateMap(map8U, resolution, xMin, yMin);
3535 _ui->graphicsView_graphView->update();
3542 stats->insert(std::make_pair(
"GUI/Grid Rendering/ms", (
float)
timer.
restart()*1000.0f));
3551 if(viewerClouds.contains(
"cloudOdom"))
3567 if(viewerClouds.contains(
"scanOdom"))
3583 if(viewerClouds.contains(
"scanMapOdom"))
3599 if(viewerClouds.contains(
"featuresOdom"))
3620 #ifdef RTABMAP_OCTOMAP
3623 _ui->actionExport_octomap->setEnabled(
false);
3635 std::string cloudName =
uFormat(
"cloud%d", nodeId);
3636 std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> outputPair;
3639 UERROR(
"Cloud %d already added to map.", nodeId);
3646 UERROR(
"Node %d is not in the cache.", nodeId);
3652 if((!
iter->sensorData().imageCompressed().empty() || !
iter->sensorData().imageRaw().empty()) &&
3653 (!
iter->sensorData().depthOrRightCompressed().empty() || !
iter->sensorData().depthOrRightRaw().empty()))
3655 cv::Mat image, depth;
3657 data.uncompressData(&image, &depth, 0);
3659 bool rectifyOnlyFeatures = Parameters::defaultRtabmapRectifyOnlyFeatures();
3660 bool imagesAlreadyRectified = Parameters::defaultRtabmapImagesAlreadyRectified();
3661 Parameters::parse(allParameters, Parameters::kRtabmapRectifyOnlyFeatures(), rectifyOnlyFeatures);
3662 Parameters::parse(allParameters, Parameters::kRtabmapImagesAlreadyRectified(), imagesAlreadyRectified);
3663 if(rectifyOnlyFeatures && !imagesAlreadyRectified)
3665 if(
data.cameraModels().size())
3669 UASSERT(
int((
data.imageRaw().cols/
data.cameraModels().size())*
data.cameraModels().size()) ==
data.imageRaw().cols);
3670 int subImageWidth =
data.imageRaw().cols/
data.cameraModels().size();
3671 cv::Mat rectifiedImages =
data.imageRaw().clone();
3677 for(
unsigned int i=0;
i<
data.cameraModels().
size(); ++
i)
3679 if(
data.cameraModels()[
i].isValidForRectification())
3686 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)...",
i);
3688 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)... done!",
i);
3693 cv::Mat rectifiedImage =
_rectCameraModels[
i].rectifyImage(cv::Mat(
data.imageRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
3694 rectifiedImage.copyTo(cv::Mat(rectifiedImages, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
3698 UWARN(
"Camera %d of data %d is not valid for rectification (%dx%d).",
3700 data.cameraModels()[
i].imageWidth(),
3701 data.cameraModels()[
i].imageHeight());
3704 UINFO(
"Time rectification: %fs",
time.ticks());
3705 data.setRGBDImage(rectifiedImages,
data.depthOrRightRaw(),
data.cameraModels());
3706 image = rectifiedImages;
3710 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
3711 pcl::IndicesPtr
indices(
new std::vector<int>);
3724 Eigen::Vector3f viewPoint(0.0
f,0.0
f,0.0
f);
3725 if(
data.cameraModels().size() && !
data.cameraModels()[0].localTransform().isNull())
3727 viewPoint[0] =
data.cameraModels()[0].localTransform().x();
3728 viewPoint[1] =
data.cameraModels()[0].localTransform().y();
3729 viewPoint[2] =
data.cameraModels()[0].localTransform().z();
3731 else if(
data.stereoCameraModels().size() && !
data.stereoCameraModels()[0].localTransform().isNull())
3733 viewPoint[0] =
data.stereoCameraModels()[0].localTransform().x();
3734 viewPoint[1] =
data.stereoCameraModels()[0].localTransform().y();
3735 viewPoint[2] =
data.stereoCameraModels()[0].localTransform().z();
3743 indices->resize(cloud->size());
3744 for(
unsigned int i=0;
i<cloud->size(); ++
i)
3777 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3782 pcl::IndicesPtr beforeFiltering =
indices;
3783 if( cloud->size() &&
3806 pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
3810 UWARN(
"Cloud subtraction with angle filtering is activated but "
3811 "cloud normal K search is 0. Subtraction is done with angle.");
3815 if(cloudWithNormals->size() &&
3842 UINFO(
"Time subtract filtering %d from %d -> %d (%fs)",
3844 (
int)beforeFiltering->size(),
3858 pcl::PointCloud<pcl::PointXYZRGB>::Ptr output;
3874 pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputFiltered(
new pcl::PointCloud<pcl::PointXYZRGB>);
3875 std::vector<pcl::Vertices> outputPolygons;
3880 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
3881 pcl::toPCLPointCloud2(*outputFiltered, textureMesh->cloud);
3882 textureMesh->tex_polygons.push_back(outputPolygons);
3883 int w = cloud->width;
3884 int h = cloud->height;
3886 textureMesh->tex_coordinates.resize(1);
3887 int nPoints = (
int)outputFiltered->size();
3888 textureMesh->tex_coordinates[0].resize(nPoints);
3889 for(
int i=0;
i<nPoints; ++
i)
3892 UASSERT(
i < (
int)denseToOrganizedIndices.size());
3893 int originalVertex = denseToOrganizedIndices[
i];
3894 textureMesh->tex_coordinates[0][
i] = Eigen::Vector2f(
3895 float(originalVertex %
w) /
float(
w),
3896 float(
h - originalVertex /
w) /
float(
h));
3899 pcl::TexMaterial mesh_material;
3900 mesh_material.tex_d = 1.0f;
3901 mesh_material.tex_Ns = 75.0f;
3902 mesh_material.tex_illum = 1;
3904 std::stringstream tex_name;
3905 tex_name <<
"material_" << nodeId;
3906 tex_name >> mesh_material.tex_name;
3908 mesh_material.tex_file =
"";
3910 textureMesh->tex_materials.push_back(mesh_material);
3914 UERROR(
"Adding texture mesh %d to viewer failed!", nodeId);
3923 UERROR(
"Adding mesh cloud %d to viewer failed!", nodeId);
3935 UWARN(
"Online meshing is activated but the generated cloud is "
3936 "dense (voxel filtering is used or multiple cameras are used). Disable "
3937 "online meshing in Preferences->3D Rendering to hide this warning.");
3943 pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
3946 QColor color = Qt::gray;
3949 color = (Qt::GlobalColor)(mapId+3 % 12 + 7 );
3954 if(cloudWithNormals->size())
3956 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr outputWithNormals;
3961 UERROR(
"Adding cloud %d to viewer failed!", nodeId);
3972 UERROR(
"Adding cloud %d to viewer failed!", nodeId);
3982 outputPair.first = output;
4009 std::string scanName =
uFormat(
"scan%d", nodeId);
4012 UERROR(
"Scan %d already added to map.", nodeId);
4019 UERROR(
"Node %d is not in the cache.", nodeId);
4023 if(!
iter->sensorData().laserScanCompressed().isEmpty() || !
iter->sensorData().laserScanRaw().isEmpty())
4026 iter->sensorData().uncompressData(0, 0, &scan);
4038 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
4039 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudRGB;
4040 pcl::PointCloud<pcl::PointXYZI>::Ptr cloudI;
4041 pcl::PointCloud<pcl::PointNormal>::Ptr cloudWithNormals;
4042 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudRGBWithNormals;
4043 pcl::PointCloud<pcl::PointXYZINormal>::Ptr cloudIWithNormals;
4086 if((!scan.
is2d()) &&
4090 if(cloudRGBWithNormals.get())
4103 if(cloudIWithNormals.get())
4116 if(cloudWithNormals.get())
4170 if( (cloud.get() || cloudRGB.get() || cloudI.get()) &&
4173 Eigen::Vector3f scanViewpoint(
4178 pcl::PointCloud<pcl::Normal>::Ptr normals;
4179 if(cloud.get() && cloud->size())
4189 cloudWithNormals.reset(
new pcl::PointCloud<pcl::PointNormal>);
4190 pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
4193 else if(cloudRGB.get() && cloudRGB->size())
4197 cloudRGBWithNormals.reset(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
4198 pcl::concatenateFields(*cloudRGB, *normals, *cloudRGBWithNormals);
4201 else if(cloudI.get())
4211 cloudIWithNormals.reset(
new pcl::PointCloud<pcl::PointXYZINormal>);
4212 pcl::concatenateFields(*cloudI, *normals, *cloudIWithNormals);
4217 QColor color = Qt::gray;
4220 color = (Qt::GlobalColor)(mapId+3 % 12 + 7 );
4223 if(cloudRGBWithNormals.get())
4226 if(added && nodeId > 0)
4231 else if(cloudIWithNormals.get())
4234 if(added && nodeId > 0)
4246 else if(cloudWithNormals.get())
4249 if(added && nodeId > 0)
4261 else if(cloudRGB.get())
4264 if(added && nodeId > 0)
4269 else if(cloudI.get())
4272 if(added && nodeId > 0)
4288 if(added && nodeId > 0)
4302 UERROR(
"Adding cloud %d to viewer failed!", nodeId);
4322 std::string cloudName =
uFormat(
"features%d", nodeId);
4325 UERROR(
"Features cloud %d already added to map.", nodeId);
4332 UERROR(
"Node %d is not in the cache.", nodeId);
4338 UDEBUG(
"Features cloud %d already created.");
4342 if(
iter->getWords3().size())
4344 UINFO(
"Create cloud from 3D words");
4345 QColor color = Qt::gray;
4348 color = (Qt::GlobalColor)(mapId+3 % 12 + 7 );
4352 if(!
iter->sensorData().imageCompressed().empty() || !
iter->sensorData().imageRaw().empty())
4355 data.uncompressData(&rgb, 0, 0);
4358 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
4359 cloud->resize(
iter->getWords3().size());
4363 UDEBUG(
"rgb.channels()=%d");
4364 if(!
iter->getWords3().empty() && !
iter->getWordsKpts().empty())
4367 if(
iter.
value().sensorData().cameraModels().size() == 1 &&
4368 iter.
value().sensorData().cameraModels().at(0).isValidForProjection())
4370 invLocalTransform =
iter.
value().sensorData().cameraModels()[0].localTransform().inverse();
4372 else if(
iter.
value().sensorData().stereoCameraModels().size() == 1 &&
4373 iter.
value().sensorData().stereoCameraModels()[0].isValidForProjection())
4375 invLocalTransform =
iter.
value().sensorData().stereoCameraModels()[0].left().localTransform().inverse();
4378 for(std::multimap<int, int>::const_iterator jter=
iter->getWords().begin(); jter!=
iter->getWords().end(); ++jter)
4380 const cv::Point3f & pt =
iter->getWords3()[jter->second];
4382 (maxDepth == 0.0
f ||
4384 (
iter.
value().sensorData().cameraModels().size()<=1 &&
4387 (*cloud)[oi].x = pt.x;
4388 (*cloud)[oi].y = pt.y;
4389 (*cloud)[oi].z = pt.z;
4390 const cv::KeyPoint & kpt =
iter->getWordsKpts()[jter->second];
4391 int u = kpt.pt.x+0.5;
4392 int v = kpt.pt.y+0.5;
4397 if(rgb.channels() == 1)
4399 (*cloud)[oi].r = (*cloud)[oi].g = (*cloud)[oi].b = rgb.at<
unsigned char>(
v, u);
4403 cv::Vec3b bgr = rgb.at<cv::Vec3b>(
v, u);
4404 (*cloud)[oi].b = bgr.val[0];
4405 (*cloud)[oi].g = bgr.val[1];
4406 (*cloud)[oi].r = bgr.val[2];
4411 (*cloud)[oi].r = (*cloud)[oi].g = (*cloud)[oi].b = 255;
4420 UERROR(
"Adding features cloud %d to viewer failed!", nodeId);
4437 const std::map<int, Transform> & poses,
4438 const std::map<int, Transform> & groundTruth)
4441 if(groundTruth.size() && poses.size())
4443 float translational_rmse = 0.0f;
4444 float translational_mean = 0.0f;
4445 float translational_median = 0.0f;
4446 float translational_std = 0.0f;
4447 float translational_min = 0.0f;
4448 float translational_max = 0.0f;
4449 float rotational_rmse = 0.0f;
4450 float rotational_mean = 0.0f;
4451 float rotational_median = 0.0f;
4452 float rotational_std = 0.0f;
4453 float rotational_min = 0.0f;
4454 float rotational_max = 0.0f;
4461 translational_median,
4473 UINFO(
"translational_rmse=%f", translational_rmse);
4474 UINFO(
"translational_mean=%f", translational_mean);
4475 UINFO(
"translational_median=%f", translational_median);
4476 UINFO(
"translational_std=%f", translational_std);
4477 UINFO(
"translational_min=%f", translational_min);
4478 UINFO(
"translational_max=%f", translational_max);
4480 UINFO(
"rotational_rmse=%f", rotational_rmse);
4481 UINFO(
"rotational_mean=%f", rotational_mean);
4482 UINFO(
"rotational_median=%f", rotational_median);
4483 UINFO(
"rotational_std=%f", rotational_std);
4484 UINFO(
"rotational_min=%f", rotational_min);
4485 UINFO(
"rotational_max=%f", rotational_max);
4492 UINFO(
"Update visibility %d", nodeId);
4496 _ui->actionAnchor_clouds_to_ground_truth->isChecked() &&
4506 if(!pose.
isNull() || !visible)
4510 std::string cloudName =
uFormat(
"cloud%d", nodeId);
4511 if(visible && !viewerClouds.contains(cloudName) &&
_cachedSignatures.contains(nodeId))
4515 else if(viewerClouds.contains(cloudName))
4528 std::string scanName =
uFormat(
"scan%d", nodeId);
4529 if(visible && !viewerClouds.contains(scanName) &&
_cachedSignatures.contains(nodeId))
4533 else if(viewerClouds.contains(scanName))
4550 if(
_ui->dockWidget_graphViewer->isVisible())
4552 UDEBUG(
"Graph visible!");
4602 bool removed =
true;
4613 QMessageBox::information(
this, tr(
"Database saved!"), QString(
msg.c_str()));
4617 std::string
msg =
uFormat(
"Failed to rename temporary database from \"%s\" to \"%s\".",
4620 QMessageBox::critical(
this, tr(
"Closing failed!"), QString(
msg.c_str()));
4625 std::string
msg =
uFormat(
"Failed to overwrite the database \"%s\". The temporary database is still correctly saved at \"%s\".",
4628 QMessageBox::critical(
this, tr(
"Closing failed!"), QString(
msg.c_str()));
4645 QMessageBox::information(
this, tr(
"Database updated!"), QString(
msg.c_str()));
4665 if(applicationClosing)
4680 msg.prepend(tr(
"[ERROR] "));
4698 UERROR(
"Map received with code error %d!", event.
getCode());
4706 UINFO(
"Received map!");
4712 QApplication::processEvents();
4714 int addedSignatures = 0;
4715 std::map<int, int> mapIds;
4716 std::map<int, Transform> groundTruth;
4717 std::map<int, std::string>
labels;
4718 for(std::map<int, Signature>::const_iterator
iter = event.
getSignatures().begin();
4722 mapIds.insert(std::make_pair(
iter->first,
iter->second.mapId()));
4723 if(!
iter->second.getGroundTruthPose().isNull())
4725 groundTruth.insert(std::make_pair(
iter->first,
iter->second.getGroundTruthPose()));
4727 if(!
iter->second.getLabel().empty())
4729 labels.insert(std::make_pair(
iter->first,
iter->second.getLabel()));
4732 (
_cachedSignatures.value(
iter->first).sensorData().imageCompressed().empty() && !
iter->second.sensorData().imageCompressed().empty()))
4736 unsigned int count = 0;
4737 if(!
iter->second.getWords3().empty())
4739 for(std::multimap<int, int>::const_iterator jter=
iter->second.getWords().upper_bound(-1); jter!=
iter->second.getWords().end(); ++jter)
4751 QApplication::processEvents();
4755 QApplication::processEvents();
4765 QApplication::processEvents();
4766 std::map<int, Transform> poses =
event.getPoses();
4769 if(
_ui->graphicsView_graphView->isVisible() &&
4782 UINFO(
"Map received is empty! Cannot update the map cloud...");
4812 _ui->graphicsView_graphView->setGlobalPath(event.
getPoses());
4828 QMessageBox * warn =
new QMessageBox(
4829 QMessageBox::Warning,
4830 tr(
"Setting goal failed!"),
4831 tr(
"Setting goal to location %1%2 failed. "
4833 "1) the robot is not yet localized in the map,\n"
4834 "2) the location doesn't exist in the map,\n"
4835 "3) the location is not linked to the global map or\n"
4836 "4) the location is too near of the current location (goal already reached).")
4841 warn->setAttribute(Qt::WA_DeleteOnClose,
true);
4846 QMessageBox *
info =
new QMessageBox(
4847 QMessageBox::Information,
4848 tr(
"Goal detected!"),
4849 tr(
"Global path computed to %1%2 (%3 poses, %4 m).")
4856 info->setAttribute(Qt::WA_DeleteOnClose,
true);
4863 QTimer::singleShot(1000,
this, SLOT(
postGoal()));
4869 QMessageBox * warn =
new QMessageBox(
4870 QMessageBox::Warning,
4871 tr(
"Setting label failed!"),
4872 tr(
"Setting label %1 to location %2 failed. "
4874 "1) the location doesn't exist in the map,\n"
4875 "2) the location has already a label.").
arg(
label).
arg(
id),
4878 warn->setAttribute(Qt::WA_DeleteOnClose,
true);
4917 UDEBUG(
"General settings changed...");
4925 _ui->graphicsView_graphView->clearNodeColorByValue();
4931 UDEBUG(
"Cloud rendering settings changed...");
4945 UDEBUG(
"Logging settings changed...");
4964 if(parameters.size())
4966 for(rtabmap::ParametersMap::const_iterator
iter = parameters.begin();
iter!=parameters.end(); ++
iter)
4968 UDEBUG(
"Parameter changed: Key=%s Value=%s",
iter->first.c_str(),
iter->second.c_str());
4973 if(
uContains(parameters, Parameters::kRtabmapWorkingDirectory()))
4993 if(
uContains(parameters, Parameters::kRGBDLocalRadius()))
4995 _ui->graphicsView_graphView->setLocalRadius(
uStr2Float(parameters.at(Parameters::kRGBDLocalRadius())));
5015 _ui->imageView_source->clearFeatures();
5017 for(std::multimap<int, cv::KeyPoint>::const_iterator
iter = refWords.begin();
iter != refWords.end(); ++
iter )
5019 int id =
iter->first;
5029 color = Qt::magenta;
5041 else if(refWords.count(
id) > 1)
5051 _ui->imageView_source->addFeature(
iter->first,
iter->second, 0, color);
5057 QList<QPair<cv::Point2f, cv::Point2f> > uniqueCorrespondences;
5058 if(loopWords.size())
5060 _ui->imageView_loopClosure->clearFeatures();
5062 for(std::multimap<int, cv::KeyPoint>::const_iterator
iter = loopWords.begin();
iter != loopWords.end(); ++
iter )
5064 int id =
iter->first;
5074 color = Qt::magenta;
5078 const cv::KeyPoint &
a = refWords.find(
id)->second;
5079 const cv::KeyPoint &
b =
iter->second;
5080 uniqueCorrespondences.push_back(QPair<cv::Point2f, cv::Point2f>(
a.pt,
b.pt));
5088 else if(refWords.count(
id) > 1)
5098 _ui->imageView_loopClosure->addFeature(
iter->first,
iter->second, 0, color);
5103 if(refWords.size()>0)
5105 if((*refWords.rbegin()).first >
_lastId)
5109 std::list<int> kpts =
uKeysList(refWords);
5110 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 3)
5111 _lastIds = QSet<int>(kpts.begin(), kpts.end());
5113 _lastIds = QSet<int>::fromList(QList<int>::fromStdList(kpts));
5118 float scaleSource =
_ui->imageView_source->viewScale();
5119 float scaleLoop =
_ui->imageView_loopClosure->viewScale();
5120 UDEBUG(
"scale source=%f loop=%f", scaleSource, scaleLoop);
5122 float sourceMarginX = (
_ui->imageView_source->width() -
_ui->imageView_source->sceneRect().width()*scaleSource)/2.0
f;
5123 float sourceMarginY = (
_ui->imageView_source->height() -
_ui->imageView_source->sceneRect().height()*scaleSource)/2.0
f;
5124 float loopMarginX = (
_ui->imageView_loopClosure->width() -
_ui->imageView_loopClosure->sceneRect().width()*scaleLoop)/2.0
f;
5125 float loopMarginY = (
_ui->imageView_loopClosure->height() -
_ui->imageView_loopClosure->sceneRect().height()*scaleLoop)/2.0
f;
5132 deltaY =
_ui->label_matchId->height() +
_ui->imageView_source->height();
5136 deltaX =
_ui->imageView_source->width();
5139 if(refWords.size() && loopWords.size())
5141 _ui->imageView_source->clearLines();
5142 _ui->imageView_loopClosure->clearLines();
5145 for(QList<QPair<cv::Point2f, cv::Point2f> >::
iterator iter = uniqueCorrespondences.begin();
5146 iter!=uniqueCorrespondences.end();
5150 _ui->imageView_source->addLine(
5153 (
iter->second.x*scaleLoop+loopMarginX+deltaX-sourceMarginX)/scaleSource,
5154 (
iter->second.y*scaleLoop+loopMarginY+deltaY-sourceMarginY)/scaleSource,
5155 _ui->imageView_source->getDefaultMatchingLineColor());
5157 _ui->imageView_loopClosure->addLine(
5158 (
iter->first.x*scaleSource+sourceMarginX-deltaX-loopMarginX)/scaleLoop,
5159 (
iter->first.y*scaleSource+sourceMarginY-deltaY-loopMarginY)/scaleLoop,
5162 _ui->imageView_loopClosure->getDefaultMatchingLineColor());
5164 _ui->imageView_source->update();
5165 _ui->imageView_loopClosure->update();
5184 if(
model.isValidForProjection())
5187 cv::Vec3d rvec, tvec;
5188 tvec.val[0] =
t.
x();
5189 tvec.val[1] =
t.
y();
5190 tvec.val[2] =
t.z();
5196 t.rotationMatrix().convertTo(
R, CV_64F);
5197 cv::Rodrigues(
R, rvec);
5202 std::vector< cv::Point3f > axisPoints;
5204 axisPoints.push_back(cv::Point3f(0, 0, 0));
5205 axisPoints.push_back(cv::Point3f(
length, 0, 0));
5206 axisPoints.push_back(cv::Point3f(0,
length, 0));
5207 axisPoints.push_back(cv::Point3f(0, 0,
length));
5208 std::vector< cv::Point2f > imagePoints;
5209 projectPoints(axisPoints, rvec, tvec,
model.K(),
model.D(), imagePoints);
5215 if(
model.imageWidth() <= 0)
5218 UWARN(
"Cannot draw correctly landmark %d with provided camera model %d (missing image width)", -
iter->first, (
int)
i);
5222 for(
int j=0;
j<4; ++
j)
5224 imagePoints[
j].x +=
i*
model.imageWidth();
5231 cv::line(image, imagePoints[0], imagePoints[1], cv::Scalar(0, 0, 255), 3);
5232 cv::line(image, imagePoints[0], imagePoints[2], cv::Scalar(0, 255, 0), 3);
5233 cv::line(image, imagePoints[0], imagePoints[3], cv::Scalar(255, 0, 0), 3);
5234 cv::putText(image,
uNumber2Str(-
iter->first), imagePoints[0], cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 255, 255), 2);
5250 if(this->isVisible())
5263 if(this->isVisible())
5272 if((event->modifiers() & Qt::ControlModifier) && event->key() == Qt::Key_S)
5280 if (event->type() == QEvent::Resize && qobject_cast<QDockWidget*>(obj))
5282 this->setWindowModified(
true);
5284 else if(event->type() == QEvent::FileOpen )
5288 return QWidget::eventFilter(obj, event);
5293 _ui->actionMore_options->setChecked(
5357 QString
name = (QDateTime::currentDateTime().toString(
"yyMMddhhmmsszzz") + (png?
".png":
".jpg"));
5358 _ui->statusbar->clearMessage();
5359 QPixmap figure = this->grab();
5365 msg = tr(
"Screen captured \"%1\"").arg(
name);
5368 buffer.open(QIODevice::WriteOnly);
5369 figure.save(&
buffer, png?
"PNG":
"JPEG");
5375 if(!dir.exists(targetDir))
5377 dir.mkdir(targetDir);
5379 targetDir += QDir::separator();
5380 targetDir +=
"Main_window";
5381 if(!dir.exists(targetDir))
5383 dir.mkdir(targetDir);
5385 targetDir += QDir::separator();
5387 figure.save(targetDir +
name);
5388 msg = tr(
"Screen captured \"%1\"").arg(targetDir +
name);
5391 _ui->widget_console->appendMsg(
msg);
5393 return targetDir +
name;
5398 QApplication::beep();
5409 this->setWindowModified(
true);
5414 if(parameters.size())
5416 for(ParametersMap::const_iterator
iter= parameters.begin();
iter!=parameters.end(); ++
iter)
5418 QString
msg = tr(
"Parameter update \"%1\"=\"%2\"")
5419 .arg(
iter->first.c_str())
5420 .arg(
iter->second.c_str());
5421 _ui->widget_console->appendMsg(
msg);
5424 QMessageBox::StandardButton button = QMessageBox::question(
this,
5426 tr(
"Some parameters have been set on command line, do you "
5427 "want to set all other RTAB-Map's parameters to default?"),
5428 QMessageBox::Yes | QMessageBox::No,
5453 this->setWindowModified(
false);
5460 UERROR(
"This method can be called only in IDLE state.");
5476 if(QFile::exists(databasePath.c_str()))
5478 int r = QMessageBox::question(
this,
5479 tr(
"Creating temporary database"),
5480 tr(
"Cannot create a new database because the temporary database \"%1\" already exists. "
5481 "There may be another instance of RTAB-Map running with the same Working Directory or "
5482 "the last time RTAB-Map was not closed correctly. "
5483 "Do you want to recover the database (click Ignore to delete it and create a new one)?").
arg(databasePath.c_str()),
5484 QMessageBox::Yes | QMessageBox::No | QMessageBox::Ignore, QMessageBox::No);
5486 if(r == QMessageBox::Ignore)
5488 if(QFile::remove(databasePath.c_str()))
5490 UINFO(
"Deleted temporary database \"%s\".", databasePath.c_str());
5494 UERROR(
"Temporary database \"%s\" could not be deleted!", databasePath.c_str());
5498 else if(r == QMessageBox::Yes)
5500 std::string errorMsg;
5512 QString newPath = QFileDialog::getSaveFileName(
this, tr(
"Save recovered database"),
_preferencesDialog->
getWorkingDirectory()+QDir::separator()+QString(
"recovered.db"), tr(
"RTAB-Map database files (*.db)"));
5513 if(newPath.isEmpty())
5517 if(QFileInfo(newPath).suffix() ==
"")
5521 if(QFile::exists(newPath))
5523 QFile::remove(newPath);
5525 QFile::rename(databasePath.c_str(), newPath);
5532 QMessageBox::warning(
this,
"Database recovery", tr(
"Database recovery failed: \"%1\".").
arg(errorMsg.c_str()));
5559 UERROR(
"Database can only be opened in IDLE state.");
5584 if(parameters.size())
5589 parameters.insert(*
iter);
5592 uInsert(parameters, overridedParameters);
5596 for(ParametersMap::iterator
iter=parameters.begin();
iter!=parameters.end(); ++
iter)
5598 ParametersMap::iterator jter = currentParameters.find(
iter->first);
5599 if(jter!=currentParameters.end() &&
5600 iter->second.compare(jter->second) != 0 &&
5601 iter->first.compare(Parameters::kRtabmapWorkingDirectory()) != 0)
5603 bool different =
true;
5621 differentParameters.insert(*
iter);
5622 QString
msg = tr(
"Parameter \"%1\": %2=\"%3\" Preferences=\"%4\"")
5623 .arg(
iter->first.c_str())
5624 .arg(overridedParameters.find(
iter->first) != overridedParameters.end()?
"Arguments":
"Database")
5625 .arg(
iter->second.c_str())
5626 .arg(jter->second.c_str());
5627 _ui->widget_console->appendMsg(
msg);
5633 if(differentParameters.size())
5635 int r = QMessageBox::question(
this,
5636 tr(
"Update parameters..."),
5637 tr(
"The %1 using %2 different parameter(s) than "
5638 "those currently set in Preferences. Do you want "
5639 "to use those parameters?")
5640 .
arg(overridedParameters.empty()?tr(
"database is"):tr(
"database and input arguments are"))
5641 .
arg(differentParameters.size()),
5642 QMessageBox::Yes | QMessageBox::No,
5644 if(r == QMessageBox::Yes)
5665 UERROR(
"This method can be called only in INITIALIZED state.");
5672 QMessageBox::Button
b = QMessageBox::question(
this,
5673 tr(
"Save database"),
5674 tr(
"Save the new database?"),
5675 QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard,
5678 if(
b == QMessageBox::Save)
5681 QString newName = QDateTime::currentDateTime().toString(
"yyMMdd-hhmmss");
5684 newPath = QFileDialog::getSaveFileName(
this, tr(
"Save database"), newPath, tr(
"RTAB-Map database files (*.db)"));
5685 if(newPath.isEmpty())
5690 if(QFileInfo(newPath).suffix() ==
"")
5697 else if(
b != QMessageBox::Discard)
5711 UERROR(
"This method can be called only in IDLE state.");
5721 dbSettingsIn.beginGroup(
"DatabaseViewer");
5722 dbSettingsOut.beginGroup(
"DatabaseViewer");
5723 QStringList
keys = dbSettingsIn.childKeys();
5728 dbSettingsIn.endGroup();
5729 dbSettingsOut.endGroup();
5733 viewer->setWindowModality(Qt::WindowModal);
5734 viewer->setAttribute(Qt::WA_DeleteOnClose,
true);
5739 viewer->showMaximized();
5765 float detectionRate =
uStr2Float(parameters.at(Parameters::kRtabmapDetectionRate()));
5766 int bufferingSize =
uStr2Float(parameters.at(Parameters::kRtabmapImageBufferSize()));
5767 if(((detectionRate!=0.0
f && detectionRate <= inputRate) || (detectionRate > 0.0
f && inputRate == 0.0
f)) &&
5770 int button = QMessageBox::question(
this,
5771 tr(
"Incompatible frame rates!"),
5772 tr(
"\"Source/Input rate\" (%1 Hz) is equal to/higher than \"RTAB-Map/Detection rate\" (%2 Hz). As the "
5773 "source input is a directory of images/video/database, some images may be "
5774 "skipped by the detector. You may want to increase the \"RTAB-Map/Detection rate\" over "
5775 "the \"Source/Input rate\" to guaranty that all images are processed. Would you want to "
5776 "start the detection anyway?").
arg(inputRate).
arg(detectionRate),
5777 QMessageBox::Yes | QMessageBox::No);
5778 if(button == QMessageBox::No)
5785 if(bufferingSize != 0)
5787 int button = QMessageBox::question(
this,
5788 tr(
"Some images may be skipped!"),
5789 tr(
"\"RTAB-Map/Images buffer size\" is not infinite (size=%1). As the "
5790 "source input is a directory of images/video/database, some images may be "
5791 "skipped by the detector if the \"Source/Input rate\" (which is %2 Hz) is higher than the "
5792 "rate at which RTAB-Map can process the images. You may want to set the "
5793 "\"RTAB-Map/Images buffer size\" to 0 (infinite) to guaranty that all "
5794 "images are processed. Would you want to start the detection "
5795 "anyway?").
arg(bufferingSize).
arg(inputRate),
5796 QMessageBox::Yes | QMessageBox::No);
5797 if(button == QMessageBox::No)
5802 else if(inputRate == 0)
5804 int button = QMessageBox::question(
this,
5805 tr(
"Large number of images may be buffered!"),
5806 tr(
"\"RTAB-Map/Images buffer size\" is infinite. As the "
5807 "source input is a directory of images/video/database and "
5808 "that \"Source/Input rate\" is infinite too, a lot of images "
5809 "could be buffered at the same time (e.g., reading all images "
5810 "of a directory at once). This could make the GUI not responsive. "
5811 "You may want to set \"Source/Input rate\" at the rate at "
5812 "which the images have been recorded. "
5813 "Would you want to start the detection "
5814 "anyway?").
arg(bufferingSize).
arg(inputRate),
5815 QMessageBox::Yes | QMessageBox::No);
5816 if(button == QMessageBox::No)
5829 QMessageBox::warning(
this,
5831 tr(
"A camera is running, stop it first."));
5832 UWARN(
"_sensorCapture is not null... it must be stopped first");
5841 QMessageBox::warning(
this,
5843 tr(
"No sources are selected. See Preferences->Source panel."));
5844 UWARN(
"No sources are selected. See Preferences->Source panel.");
5850 double poseTimeOffset = 0.0;
5851 float scaleFactor = 0.0f;
5852 double waitTime = 0.1;
5891 UINFO(
"Create Odom Sensor %d (camera = %d)",
5905 UINFO(
"The camera is also the odometry sensor (camera=%d odom=%d).",
5951 if(
uStr2Bool(parameters.at(Parameters::kRGBDEnabled()).c_str()))
5956 UWARN(
"Camera is not calibrated!");
5961 int button = QMessageBox::question(
this,
5962 tr(
"Camera is not calibrated!"),
5963 tr(
"RTAB-Map in metric SLAM mode cannot run with an uncalibrated camera. Do you want to calibrate the camera now?"),
5964 QMessageBox::Yes | QMessageBox::No);
5965 if(button == QMessageBox::Yes)
5975 UERROR(
"OdomThread must be already deleted here?!");
5982 UERROR(
"ImuThread must be already deleted here?!");
5994 odomParameters.erase(Parameters::kRtabmapPublishRAMUsage());
5995 int odomStrategy = Parameters::defaultOdomStrategy();
5998 UDEBUG(
"Odom gravitySigma=%f", gravitySigma);
5999 if(gravitySigma >= 0.0)
6003 if(odomStrategy != 1)
6006 odomParameters.erase(Parameters::kVisCorType());
6021 QMessageBox::warning(
this, tr(
"Source IMU Path"),
6056 _ui->actionReset_Odometry->setEnabled(
true);
6061 QMessageBox::information(
this,
6063 tr(
"Note that publishing statistics is disabled, "
6064 "progress will not be shown in the GUI."));
6078 #ifdef RTABMAP_OCTOMAP
6083 #ifdef RTABMAP_GRIDMAP
6103 if(
_state ==
kPaused && (QApplication::keyboardModifiers() & Qt::ShiftModifier))
6123 UINFO(
"Sending pause event!");
6128 UINFO(
"Sending unpause event!");
6143 QMessageBox::StandardButton button = QMessageBox::question(
this, tr(
"Stopping process..."), tr(
"Are you sure you want to stop the process?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
6145 if(button != QMessageBox::Yes)
6165 _ui->actionReset_Odometry->setEnabled(
false);
6197 QMessageBox::information(
this,
6198 tr(
"No more images..."),
6199 tr(
"The camera has reached the end of the stream."));
6204 _ui->dockWidget_console->show();
6209 msgRef.append(QString::number(
_refIds[
i]));
6214 msgLoop.append(
" ");
6217 _ui->widget_console->appendMsg(QString(
"IDs = [%1];").
arg(msgRef));
6218 _ui->widget_console->appendMsg(QString(
"LoopIDs = [%1];").
arg(msgLoop));
6229 int id = QInputDialog::getInt(
this, tr(
"Around which location?"), tr(
"Location ID (0=full map)"), 0, 0, 999999, 0, &ok);
6235 margin = QInputDialog::getInt(
this, tr(
"Depth around the location?"), tr(
"Margin"), 4, 1, 100, 1, &ok);
6240 QString
path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
_graphSavingFileName, tr(
"Graphiz file (*.dot)"));
6246 _ui->dockWidget_console->show();
6286 std::map<int, Transform> localTransforms;
6288 items.push_back(
"Robot (base frame)");
6289 items.push_back(
"Camera");
6290 items.push_back(
"Scan");
6292 QString item = QInputDialog::getItem(
this, tr(
"Export Poses"), tr(
"Frame: "), items,
_exportPosesFrame,
false, &ok);
6293 if(!ok || item.isEmpty())
6297 if(item.compare(
"Robot (base frame)") != 0)
6299 bool cameraFrame = item.compare(
"Camera") == 0;
6316 localTransform =
_cachedSignatures[
iter->first].sensorData().stereoCameraModels()[0].localTransform();
6321 UWARN(
"Multi-camera is not supported (node %d)",
iter->first);
6325 UWARN(
"Missing calibration for node %d",
iter->first);
6334 else if(!
_cachedSignatures[
iter->first].sensorData().laserScanCompressed().localTransform().isNull())
6336 localTransform =
_cachedSignatures[
iter->first].sensorData().laserScanCompressed().localTransform();
6340 UWARN(
"Missing scan info for node %d",
iter->first);
6343 if(!localTransform.
isNull())
6345 localTransforms.insert(std::make_pair(
iter->first, localTransform));
6350 UWARN(
"Did not find node %d in cache",
iter->first);
6353 if(localTransforms.empty())
6355 QMessageBox::warning(
this,
6357 tr(
"Could not find any \"%1\" frame, exporting in Robot frame instead.").
arg(item));
6365 std::map<int, Transform> poses;
6366 std::multimap<int, Link> links;
6367 if(localTransforms.empty())
6375 for(std::map<int, Transform>::iterator
iter=localTransforms.begin();
iter!=localTransforms.end(); ++
iter)
6383 std::multimap<int, Link>::iterator inserted = links.insert(*
iter);
6384 int from =
iter->second.from();
6385 int to =
iter->second.to();
6386 inserted->second.setTransform(localTransforms.at(from).inverse()*
iter->second.transform()*localTransforms.at(to));
6391 if(
format != 4 &&
format != 11 && !poses.empty() && poses.begin()->first<0)
6393 UWARN(
"Only g2o format (4) and RGBD format with ID format can export landmarks, they are ignored with format %d",
format);
6394 for(std::map<int, Transform>::iterator
iter=poses.begin();
iter!=poses.end() &&
iter->first < 0;)
6396 poses.erase(
iter++);
6398 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end();)
6400 if(
iter->second.from() < 0 ||
iter->second.to() < 0)
6402 links.erase(
iter++);
6411 std::map<int, double> stamps;
6414 for(std::map<int, Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
6418 stamps.insert(std::make_pair(
iter->first, 0));
6425 if(stamps.size()!=poses.size())
6427 QMessageBox::warning(
this, tr(
"Export poses..."), tr(
"RGB-D SLAM format: Poses (%1) and stamps (%2) have not the same size! Try again after updating the cache.")
6428 .
arg(poses.size()).
arg(stamps.size()));
6438 QString
path = QFileDialog::getSaveFileName(
6442 format == 3?tr(
"TORO file (*.graph)"):
format==4?tr(
"g2o file (*.g2o)"):tr(
"Text file (*.txt)"));
6446 if(QFileInfo(
path).suffix() ==
"")
6467 QMessageBox::information(
this,
6468 tr(
"Export poses..."),
6469 tr(
"%1 saved to \"%2\".")
6475 QMessageBox::information(
this,
6476 tr(
"Export poses..."),
6477 tr(
"Failed to save %1 to \"%2\"!")
6509 bool refineNeighborLinks,
6510 bool refineLoopClosureLinks,
6511 bool detectMoreLoopClosures,
6512 double clusterRadius,
6513 double clusterAngle,
6521 double sbaRematchFeatures,
6522 bool abortIfDataMissing)
6526 QMessageBox::warning(
this,
6527 tr(
"Post-processing..."),
6528 tr(
"Signatures must be cached in the GUI for post-processing. "
6529 "Check the option in Preferences->General Settings (GUI), then "
6530 "refresh the cache."));
6534 if(!detectMoreLoopClosures && !refineNeighborLinks && !refineLoopClosureLinks && !sba)
6536 UWARN(
"No post-processing selection...");
6542 UWARN(
"No nodes to process...");
6547 std::map<int, Transform> odomPoses;
6548 bool allDataAvailable =
true;
6557 allDataAvailable =
false;
6559 else if(!jter.value().getPose().isNull())
6561 odomPoses.insert(std::make_pair(
iter->first, jter.value().getPose()));
6565 if(!allDataAvailable)
6567 QString
msg = tr(
"Some data missing in the cache to respect the constraints chosen. "
6568 "Try \"Edit->Download all clouds\" to update the cache and try again.");
6570 if(abortIfDataMissing)
6572 QMessageBox::warning(
this, tr(
"Not all data available in the GUI..."),
msg);
6585 if(refineNeighborLinks)
6589 if(refineLoopClosureLinks)
6602 bool optimizeFromGraphEnd = Parameters::defaultRGBDOptimizeFromGraphEnd();
6603 float optimizeMaxError = Parameters::defaultRGBDOptimizeMaxError();
6604 int optimizeIterations = Parameters::defaultOptimizerIterations();
6605 bool reextractFeatures = Parameters::defaultRGBDLoopClosureReextractFeatures();
6606 Parameters::parse(parameters, Parameters::kRGBDOptimizeFromGraphEnd(), optimizeFromGraphEnd);
6607 Parameters::parse(parameters, Parameters::kRGBDOptimizeMaxError(), optimizeMaxError);
6608 Parameters::parse(parameters, Parameters::kOptimizerIterations(), optimizeIterations);
6609 Parameters::parse(parameters, Parameters::kRGBDLoopClosureReextractFeatures(), reextractFeatures);
6612 int loopClosuresAdded = 0;
6613 std::multimap<int, int> checkedLoopClosures;
6614 if(detectMoreLoopClosures)
6618 bool loopCovLimited = Parameters::defaultRGBDLoopCovLimited();
6619 Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), loopCovLimited);
6620 std::vector<double> odomMaxInf;
6629 _progressDialog->
appendText(tr(
"Looking for more loop closures, clustering poses... (iteration=%1/%2, radius=%3 m angle=%4 degrees)")
6630 .
arg(
n+1).
arg(iterations).
arg(clusterRadius).
arg(clusterAngle));
6635 clusterAngle*CV_PI/180.0);
6639 QApplication::processEvents();
6642 std::set<int> addedLinks;
6645 int from =
iter->first;
6646 int to =
iter->second;
6649 from =
iter->second;
6656 if((interSession && mapIdFrom != mapIdTo) ||
6657 (intraSession && mapIdFrom == mapIdTo))
6659 bool alreadyChecked =
false;
6660 for(std::multimap<int, int>::iterator jter = checkedLoopClosures.lower_bound(from);
6661 !alreadyChecked && jter!=checkedLoopClosures.end() && jter->first == from;
6664 if(to == jter->second)
6666 alreadyChecked =
true;
6673 if(addedLinks.find(from) == addedLinks.end() &&
6674 addedLinks.find(to) == addedLinks.end() &&
6679 if(
delta.getNorm() < clusterRadius)
6681 checkedLoopClosures.insert(std::make_pair(from, to));
6685 UERROR(
"Didn't find signature %d", from);
6689 UERROR(
"Didn't find signature %d", to);
6701 if(parameters.find(Parameters::kRegStrategy()) != parameters.end() &&
6702 parameters.at(Parameters::kRegStrategy()).compare(
"1") == 0)
6708 if(reextractFeatures)
6716 UWARN(
"\"%s\" is false and signatures (%d and %d) don't have raw "
6717 "images. Update the cache.",
6718 Parameters::kRGBDLoopClosureReextractFeatures().
c_str());
6723 signatureFrom.
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
6725 signatureTo.
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
6728 else if(!reextractFeatures && signatureFrom.
getWords().empty() && signatureTo.
getWords().empty())
6730 UWARN(
"\"%s\" is false and signatures (%d and %d) don't have words, "
6731 "registration will not be possible. Set \"%s\" to true.",
6732 Parameters::kRGBDLoopClosureReextractFeatures().
c_str(),
6735 Parameters::kRGBDLoopClosureReextractFeatures().c_str());
6738 delete registration;
6742 bool updateConstraint =
true;
6743 cv::Mat information =
info.covariance.inv();
6744 if(odomMaxInf.size() == 6 && information.cols==6 && information.rows==6)
6746 for(
int i=0;
i<6; ++
i)
6748 if(information.at<
double>(
i,
i) > odomMaxInf[
i])
6750 information.at<
double>(
i,
i) = odomMaxInf[
i];
6754 if(optimizeMaxError > 0.0
f && optimizeIterations > 0)
6763 fromId =
iter->first;
6769 const Link * maxLinearLink = 0;
6770 const Link * maxAngularLink = 0;
6771 float maxLinearError = 0.0f;
6772 float maxAngularError = 0.0f;
6773 std::map<int, Transform> poses;
6774 std::multimap<int, Link> links;
6779 UASSERT(poses.find(fromId) != poses.end());
6780 UASSERT_MSG(poses.find(from) != poses.end(),
uFormat(
"id=%d poses=%d links=%d", from, (
int)poses.size(), (
int)links.size()).c_str());
6781 UASSERT_MSG(poses.find(to) != poses.end(),
uFormat(
"id=%d poses=%d links=%d", to, (
int)poses.size(), (
int)links.size()).c_str());
6783 poses = optimizer->
optimize(fromId, poses, links);
6787 float maxLinearErrorRatio = 0.0f;
6788 float maxAngularErrorRatio = 0.0f;
6792 maxLinearErrorRatio,
6793 maxAngularErrorRatio,
6800 UINFO(
"Max optimization linear error = %f m (link %d->%d)", maxLinearError, maxLinearLink->
from(), maxLinearLink->
to());
6801 if(maxLinearErrorRatio > optimizeMaxError)
6803 msg =
uFormat(
"Rejecting edge %d->%d because "
6804 "graph error is too large after optimization (%f m for edge %d->%d with ratio %f > std=%f m). "
6809 maxLinearLink->
from(),
6810 maxLinearLink->
to(),
6811 maxLinearErrorRatio,
6813 Parameters::kRGBDOptimizeMaxError().c_str(),
6817 else if(maxAngularLink)
6819 UINFO(
"Max optimization angular error = %f deg (link %d->%d)", maxAngularError*180.0
f/
M_PI, maxAngularLink->
from(), maxAngularLink->
to());
6820 if(maxAngularErrorRatio > optimizeMaxError)
6822 msg =
uFormat(
"Rejecting edge %d->%d because "
6823 "graph error is too large after optimization (%f deg for edge %d->%d with ratio %f > std=%f deg). "
6827 maxAngularError*180.0
f/
M_PI,
6828 maxAngularLink->
from(),
6829 maxAngularLink->
to(),
6830 maxAngularErrorRatio,
6832 Parameters::kRGBDOptimizeMaxError().c_str(),
6839 msg =
uFormat(
"Rejecting edge %d->%d because graph optimization has failed!",
6847 QApplication::processEvents();
6848 updateConstraint =
false;
6856 if(updateConstraint)
6858 UINFO(
"Added new loop closure between %d and %d.", from, to);
6859 addedLinks.insert(from);
6860 addedLinks.insert(to);
6863 ++loopClosuresAdded;
6873 QApplication::processEvents();
6877 if(addedLinks.size() == 0)
6882 if(
n+1 < iterations)
6886 QApplication::processEvents();
6890 std::map<int, rtabmap::Transform> posesOut;
6891 std::multimap<int, rtabmap::Link> linksOut;
6892 std::map<int, rtabmap::Transform> optimizedPoses;
6900 optimizedPoses = optimizer->
optimize(fromId, posesOut, linksOut);
6905 UINFO(
"Added %d loop closures.", loopClosuresAdded);
6912 if(refineLoopClosureLinks)
6918 QApplication::processEvents();
6926 int from =
iter->second.from();
6927 int to =
iter->second.to();
6934 QApplication::processEvents();
6938 UERROR(
"Didn't find signature %d",from);
6942 UERROR(
"Didn't find signature %d", to);
6962 iter->second = newLink;
6966 QString
str = tr(
"Cannot refine link %1->%2 (%3").arg(from).arg(to).arg(
info.rejectedMsg.c_str());
6968 UWARN(
"%s",
str.toStdString().c_str());
6977 str = tr(
"Cannot refine link %1->%2 (Intermediate node detected!)").arg(from).arg(to);
6981 str = tr(
"Cannot refine link %1->%2 (scans empty!)").arg(from).arg(to);
6985 UWARN(
"%s",
str.toStdString().c_str());
6999 std::map<int, rtabmap::Transform> posesOut;
7000 std::multimap<int, rtabmap::Link> linksOut;
7001 std::map<int, rtabmap::Transform> optimizedPoses;
7009 optimizedPoses = optimizer->
optimize(fromId, posesOut, linksOut);
7017 .
arg(optimizedPoses.size()).
arg(linksOut.size()).arg(sbaIterations));
7018 QApplication::processEvents();
7020 QApplication::processEvents();
7023 uInsert(parametersSBA, std::make_pair(Parameters::kOptimizerIterations(),
uNumber2Str(sbaIterations)));
7024 uInsert(parametersSBA, std::make_pair(Parameters::kg2oPixelVariance(),
uNumber2Str(sbaVariance)));
7026 std::map<int, Transform> newPoses = sbaOptimizer->
optimizeBA(optimizedPoses.begin()->first, optimizedPoses, linksOut,
_cachedSignatures.toStdMap(), sbaRematchFeatures);
7027 delete sbaOptimizer;
7030 optimizedPoses = newPoses;
7048 std::map<int, Transform>(),
7049 std::multimap<int, Link>(),
7078 QMessageBox::warning(
this, tr(
"Depth Calibration"), tr(
"No data in cache. Try to refresh the cache."));
7084 QMessageBox::StandardButton button;
7087 button = QMessageBox::question(
this,
7088 tr(
"Deleting memory..."),
7089 tr(
"The remote database and log files will be deleted. Are you sure you want to continue? (This cannot be reverted)"),
7090 QMessageBox::Yes|QMessageBox::No,
7095 button = QMessageBox::question(
this,
7096 tr(
"Deleting memory..."),
7097 tr(
"The current database and log files will be deleted. Are you sure you want to continue? (This cannot be reverted)"),
7098 QMessageBox::Yes|QMessageBox::No,
7102 if(button != QMessageBox::Yes)
7123 #if defined(Q_WS_MAC)
7126 args <<
"tell application \"Finder\"";
7130 args <<
"select POSIX file \""+filePath+
"\"";
7133 QProcess::startDetached(
"osascript",
args);
7134 #elif defined(Q_WS_WIN)
7136 args <<
"/select," << QDir::toNativeSeparators(filePath);
7137 QProcess::startDetached(
"explorer",
args);
7139 UERROR(
"Only works on Mac and Windows");
7288 UINFO(
"Sending a goal...");
7290 QString
text = QInputDialog::getText(
this, tr(
"Send a goal"), tr(
"Goal location ID or label: "), QLineEdit::Normal,
"", &ok);
7291 if(ok && !
text.isEmpty())
7302 UINFO(
"Sending waypoints...");
7304 QString
text = QInputDialog::getText(
this, tr(
"Send waypoints"), tr(
"Waypoint IDs or labels (separated by spaces): "), QLineEdit::Normal,
"", &ok);
7305 if(ok && !
text.isEmpty())
7307 QStringList wp =
text.split(
' ');
7310 QMessageBox::warning(
this, tr(
"Send waypoints"), tr(
"At least two waypoints should be set. For only one goal, use send goal action."));
7334 int id = goal.toInt(&ok);
7335 _ui->graphicsView_graphView->setGlobalPath(std::vector<std::pair<int, Transform> >());
7336 UINFO(
"Posting event with goal %s", goal.toStdString().c_str());
7350 UINFO(
"Cancelling goal...");
7358 UINFO(
"Labelling current location...");
7360 QString
label = QInputDialog::getText(
this, tr(
"Label current location"), tr(
"Label: "), QLineEdit::Normal,
"", &ok);
7361 if(ok && !
label.isEmpty())
7369 UINFO(
"Removing label...");
7371 QString
label = QInputDialog::getText(
this, tr(
"Remove label"), tr(
"Label: "), QLineEdit::Normal,
"", &ok);
7372 if(ok && !
label.isEmpty())
7381 QString
path = QFileDialog::getOpenFileName(
this, tr(
"Select file"), dir, tr(
"RTAB-Map database files (*.db)"));
7395 UINFO(
"Update cache...");
7403 std::list<Signature*> signaturesList;
7404 driver->
loadSignatures(std::list<int>(ids.begin(), ids.end()), signaturesList);
7405 std::map<int, Signature> signatures;
7407 for(std::list<Signature *>::iterator
iter=signaturesList.begin();
iter!=signaturesList.end(); ++
iter)
7409 signatures.insert(std::make_pair((*iter)->id(), *(*
iter)));
7422 QMessageBox::warning(
this, tr(
"Update cache"), tr(
"Failed to open database \"%1\"").
arg(
path));
7431 items.append(
"Local map optimized");
7432 items.append(
"Local map not optimized");
7433 items.append(
"Global map optimized");
7434 items.append(
"Global map not optimized");
7437 QString item = QInputDialog::getItem(
this, tr(
"Download map"), tr(
"Options:"), items, 0,
false, &ok);
7440 bool optimized=
false, global=
false;
7441 if(item.compare(
"Local map optimized") == 0)
7445 else if(item.compare(
"Local map not optimized") == 0)
7449 else if(item.compare(
"Global map optimized") == 0)
7454 else if(item.compare(
"Global map not optimized") == 0)
7460 UFATAL(
"Item \"%s\" not found?!?", item.toStdString().c_str());
7463 UINFO(
"Download clouds...");
7467 .
arg(global?
"true":
"false").
arg(optimized?
"true":
"false"));
7475 items.append(
"Local map optimized");
7476 items.append(
"Local map not optimized");
7477 items.append(
"Global map optimized");
7478 items.append(
"Global map not optimized");
7481 QString item = QInputDialog::getItem(
this, tr(
"Download graph"), tr(
"Options:"), items, 0,
false, &ok);
7484 bool optimized=
false, global=
false;
7485 if(item.compare(
"Local map optimized") == 0)
7489 else if(item.compare(
"Local map not optimized") == 0)
7493 else if(item.compare(
"Global map optimized") == 0)
7498 else if(item.compare(
"Global map not optimized") == 0)
7504 UFATAL(
"Item \"%s\" not found?!?", item.toStdString().c_str());
7507 UINFO(
"Download the graph...");
7511 .
arg(global?
"true":
"false").
arg(optimized?
"true":
"false"));
7544 _ui->widget_mapVisibility->clear();
7552 _ui->statsToolBox->clear();
7554 _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(
false);
7555 _ui->actionPost_processing->setEnabled(
false);
7556 _ui->actionSave_point_cloud->setEnabled(
false);
7557 _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(
false);
7558 _ui->actionDepth_Calibration->setEnabled(
false);
7559 _ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(
false);
7560 _ui->actionExport_octomap->setEnabled(
false);
7561 _ui->actionView_high_res_point_cloud->setEnabled(
false);
7568 _ui->label_stats_loopClosuresDetected->setText(
"0");
7569 _ui->label_stats_loopClosuresReactivatedDetected->setText(
"0");
7570 _ui->label_stats_loopClosuresRejected->setText(
"0");
7574 _ui->label_refId->clear();
7575 _ui->label_matchId->clear();
7576 _ui->graphicsView_graphView->clearAll();
7577 _ui->imageView_source->clear();
7578 _ui->imageView_loopClosure->clear();
7579 _ui->imageView_odometry->clear();
7580 _ui->imageView_source->setBackgroundColor(
_ui->imageView_source->getDefaultBackgroundColor());
7581 _ui->imageView_loopClosure->setBackgroundColor(
_ui->imageView_loopClosure->getDefaultBackgroundColor());
7582 _ui->imageView_odometry->setBackgroundColor(
_ui->imageView_odometry->getDefaultBackgroundColor());
7585 #ifdef RTABMAP_OCTOMAP
7599 QDesktopServices::openUrl(QUrl(
"http://wiki.ros.org/rtabmap_ros"));
7603 QDesktopServices::openUrl(QUrl(
"https://github.com/introlab/rtabmap/wiki"));
7611 QString
format =
"hh:mm:ss";
7612 _ui->label_elapsedTime->setText((QTime().fromString(
_ui->label_elapsedTime->text(),
format).addMSecs(
_elapsedTime->restart())).toString(
format));
7618 QList<int> curvesPerFigure;
7619 QStringList curveNames;
7620 QStringList curveThresholds;
7621 _ui->statsToolBox->getFiguresSetup(curvesPerFigure, curveNames, curveThresholds);
7623 QStringList curvesPerFigureStr;
7624 for(
int i=0;
i<curvesPerFigure.size(); ++
i)
7626 curvesPerFigureStr.append(QString::number(curvesPerFigure[
i]));
7628 for(
int i=0;
i<curveNames.size(); ++
i)
7630 curveNames[
i].replace(
' ',
'_');
7643 if(!curvesPerFigure.isEmpty())
7645 QStringList curvesPerFigureList = curvesPerFigure.split(
" ");
7646 QStringList curvesNamesList = curveNames.split(
" ");
7647 QStringList curveThresholdsList = curveThresholds.split(
" ");
7648 if(curveThresholdsList[0].isEmpty()) {
7649 curveThresholdsList.clear();
7651 UASSERT(curveThresholdsList.isEmpty() || curveThresholdsList.size() == curvesNamesList.size());
7654 for(
int i=0;
i<curvesPerFigureList.size(); ++
i)
7657 int count = curvesPerFigureList[
i].toInt(&ok);
7660 QMessageBox::warning(
this,
"Loading failed",
"Corrupted figures setup...");
7665 _ui->statsToolBox->addCurve(curvesNamesList[
j++].replace(
'_',
' '));
7666 for(
int k=1; k<
count &&
j<curveNames.size(); ++k)
7668 if(curveThresholdsList.size())
7671 double thresholdValue = curveThresholdsList[
j].toDouble(&ok);
7674 _ui->statsToolBox->addThreshold(curvesNamesList[
j++].replace(
'_',
' '), thresholdValue);
7678 _ui->statsToolBox->addCurve(curvesNamesList[
j++].replace(
'_',
' '),
false);
7683 _ui->statsToolBox->addCurve(curvesNamesList[
j++].replace(
'_',
' '),
false);
7707 _ui->dockWidget_posterior->setVisible(
false);
7708 _ui->dockWidget_likelihood->setVisible(
false);
7709 _ui->dockWidget_rawlikelihood->setVisible(
false);
7710 _ui->dockWidget_statsV2->setVisible(
false);
7711 _ui->dockWidget_console->setVisible(
false);
7712 _ui->dockWidget_loopClosureViewer->setVisible(
false);
7713 _ui->dockWidget_mapVisibility->setVisible(
false);
7714 _ui->dockWidget_graphViewer->setVisible(
false);
7715 _ui->dockWidget_odometry->setVisible(
true);
7716 _ui->dockWidget_cloudViewer->setVisible(
true);
7717 _ui->dockWidget_imageView->setVisible(
true);
7718 _ui->dockWidget_multiSessionLoc->setVisible(
false);
7720 _ui->toolBar_2->setVisible(
true);
7721 _ui->statusbar->setVisible(
false);
7733 items << QString(
"Synchronize with map update") << QString(
"Synchronize with odometry update");
7735 QString item = QInputDialog::getItem(
this, tr(
"Select synchronization behavior"), tr(
"Sync:"), items, 0,
false, &ok);
7736 if(ok && !item.isEmpty())
7738 if(item.compare(
"Synchronize with map update") == 0)
7749 int r = QMessageBox::question(
this, tr(
"Hard drive or RAM?"), tr(
"Save in RAM? Images will be saved on disk when clicking auto screen capture again."), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
7750 if(r == QMessageBox::No || r == QMessageBox::Yes)
7756 _ui->actionAuto_screen_capture->setChecked(
false);
7759 r = QMessageBox::question(
this, tr(
"Save in JPEG?"), tr(
"Save in JPEG format? Otherwise they are saved in PNG."), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
7760 if(r == QMessageBox::No || r == QMessageBox::Yes)
7766 _ui->actionAuto_screen_capture->setChecked(
false);
7772 _ui->actionAuto_screen_capture->setChecked(
false);
7779 if(!dir.exists(targetDir))
7781 dir.mkdir(targetDir);
7783 targetDir += QDir::separator();
7784 targetDir +=
"Main_window";
7785 if(!dir.exists(targetDir))
7787 dir.mkdir(targetDir);
7789 targetDir += QDir::separator();
7803 QApplication::processEvents();
7813 QDesktopServices::openUrl(QUrl::fromLocalFile(this->
captureScreen()));
7818 QRect rect = this->geometry();
7822 if(
float(rect.width())/
float(rect.height()) >
float(
w)/
float(
h))
7824 rect.setWidth(
w*(rect.height()/
h));
7825 rect.setHeight((rect.height()/
h)*
h);
7829 rect.setHeight(
h*(rect.width()/
w));
7830 rect.setWidth((rect.width()/
w)*
w);
7839 this->setGeometry(rect);
7885 int width = QInputDialog::getInt(
this, tr(
"Aspect ratio"), tr(
"Width (pixels):"), this->geometry().width(), 100, 10000, 100, &ok);
7888 int height = QInputDialog::getInt(
this, tr(
"Aspect ratio"), tr(
"Height (pixels):"), this->geometry().height(), 100, 10000, 100, &ok);
7898 float gridCellSize = 0.05f;
7900 gridCellSize = (
float)QInputDialog::getDouble(
this, tr(
"Grid cell size"), tr(
"Size (m):"), (double)gridCellSize, 0.01, 1, 2, &ok);
7907 float xMin=0.0f, yMin=0.0f;
7909 #ifdef RTABMAP_OCTOMAP
7923 cv::Mat map8U(pixels.rows, pixels.cols, CV_8U);
7925 for (
int i = 0;
i < pixels.rows; ++
i)
7927 for (
int j = 0;
j < pixels.cols; ++
j)
7929 char v = pixels.at<
char>(
i,
j);
7943 map8U.at<
unsigned char>(
i,
j) = gray;
7949 QString
path = QFileDialog::getSaveFileName(
this, tr(
"Save to ..."),
"grid.png", tr(
"Image (*.png *.bmp)"));
7952 if(QFileInfo(
path).suffix() !=
"png" && QFileInfo(
path).suffix() !=
"bmp")
7958 QImage
img = image.mirrored(
false,
true).transformed(QTransform().
rotate(-90));
7959 QPixmap::fromImage(
img).save(
path);
7961 QDesktopServices::openUrl(QUrl::fromLocalFile(
path));
7973 std::map<int, Transform> poses =
_ui->widget_mapVisibility->getVisiblePoses();
7978 for(std::map<int, Transform>::iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
7983 iter->second = gtIter->second;
7987 UWARN(
"Not found ground truth pose for node %d",
iter->first);
8010 std::map<int, Transform> poses =
_ui->widget_mapVisibility->getVisiblePoses();
8015 for(std::map<int, Transform>::iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
8020 iter->second = gtIter->second;
8024 UWARN(
"Not found ground truth pose for node %d",
iter->first);
8043 #ifdef RTABMAP_OCTOMAP
8046 QString
path = QFileDialog::getSaveFileName(
8050 tr(
"Octomap file (*.bt)"));
8056 QMessageBox::information(
this,
8057 tr(
"Export octomap..."),
8058 tr(
"Octomap successfully saved to \"%1\".")
8063 QMessageBox::information(
this,
8064 tr(
"Export octomap..."),
8065 tr(
"Failed to save octomap to \"%1\"!")
8072 UERROR(
"Empty octomap.");
8075 UERROR(
"Cannot export octomap, RTAB-Map is not built with it.");
8083 QMessageBox::warning(
this, tr(
"Export images..."), tr(
"Cannot export images, the cache is empty!"));
8086 std::map<int, Transform> poses =
_ui->widget_mapVisibility->getVisiblePoses();
8090 QMessageBox::warning(
this, tr(
"Export images..."), tr(
"There is no map!"));
8094 QStringList formats;
8095 formats.push_back(
"id.jpg");
8096 formats.push_back(
"id.png");
8097 formats.push_back(
"timestamp.jpg");
8098 formats.push_back(
"timestamp.png");
8100 QString
format = QInputDialog::getItem(
this, tr(
"Which RGB format?"), tr(
"Format:"), formats, 0,
false, &ok);
8105 QString ext =
format.split(
'.').back();
8106 bool useStamp =
format.split(
'.').front().compare(
"timestamp") == 0;
8108 QMap<int, double> stamps;
8109 QString
path = QFileDialog::getExistingDirectory(
this, tr(
"Select directory where to save images..."), this->
getWorkingDirectory());
8116 data.uncompressData();
8123 unsigned int saved = 0;
8124 bool calibrationSaved =
false;
8125 for(std::map<int, Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
8127 QString
id = QString::number(
iter->first);
8133 data.uncompressData();
8135 if(!calibrationSaved)
8137 if(!
data.imageRaw().empty() && !
data.rightRaw().empty())
8140 dir.mkdir(QString(
"%1/left").
arg(
path));
8141 dir.mkdir(QString(
"%1/right").
arg(
path));
8142 if(
data.stereoCameraModels().size() > 1)
8144 UERROR(
"Only one stereo camera calibration can be saved at this time (%d detected)", (
int)
data.stereoCameraModels().size());
8146 else if(
data.stereoCameraModels().size() == 1 &&
data.stereoCameraModels().front().isValidForProjection())
8148 std::string cameraName =
"calibration";
8151 data.imageRaw().size(),
8152 data.stereoCameraModels()[0].left().K(),
8153 data.stereoCameraModels()[0].left().D(),
8154 data.stereoCameraModels()[0].left().R(),
8155 data.stereoCameraModels()[0].left().P(),
8156 data.rightRaw().size(),
8157 data.stereoCameraModels()[0].right().K(),
8158 data.stereoCameraModels()[0].right().D(),
8159 data.stereoCameraModels()[0].right().R(),
8160 data.stereoCameraModels()[0].right().P(),
8161 data.stereoCameraModels()[0].R(),
8162 data.stereoCameraModels()[0].T(),
8163 data.stereoCameraModels()[0].E(),
8164 data.stereoCameraModels()[0].F(),
8165 data.stereoCameraModels()[0].left().localTransform());
8168 calibrationSaved =
true;
8169 UINFO(
"Saved stereo calibration \"%s\"", (
path.toStdString()+
"/"+cameraName).c_str());
8173 UERROR(
"Failed saving calibration \"%s\"", (
path.toStdString()+
"/"+cameraName).c_str());
8177 else if(!
data.imageRaw().empty())
8179 if(!
data.depthRaw().empty())
8182 dir.mkdir(QString(
"%1/rgb").
arg(
path));
8183 dir.mkdir(QString(
"%1/depth").
arg(
path));
8186 if(
data.cameraModels().size() > 1)
8188 UERROR(
"Only one camera calibration can be saved at this time (%d detected)", (
int)
data.cameraModels().size());
8190 else if(
data.cameraModels().size() == 1 &&
data.cameraModels().front().isValidForProjection())
8192 std::string cameraName =
"calibration";
8194 data.imageRaw().size(),
8195 data.cameraModels().front().K(),
8196 data.cameraModels().front().D(),
8197 data.cameraModels().front().R(),
8198 data.cameraModels().front().P(),
8199 data.cameraModels().front().localTransform());
8202 calibrationSaved =
true;
8203 UINFO(
"Saved calibration \"%s\"", (
path.toStdString()+
"/"+cameraName).c_str());
8207 UERROR(
"Failed saving calibration \"%s\"", (
path.toStdString()+
"/"+cameraName).c_str());
8213 if(!
data.imageRaw().empty() && useStamp)
8218 UWARN(
"Node %d has null timestamp! Using id instead!",
iter->first);
8222 id = QString::number(stamp,
'f');
8228 if(!
data.imageRaw().empty() && !
data.rightRaw().empty())
8230 if(!cv::imwrite(QString(
"%1/left/%2.%3").
arg(
path).
arg(
id).
arg(ext).toStdString(),
data.imageRaw()))
8232 if(!cv::imwrite(QString(
"%1/right/%2.%3").
arg(
path).
arg(
id).
arg(ext).toStdString(),
data.rightRaw()))
8234 info = tr(
"Saved left/%1.%2 and right/%1.%2.").arg(
id).arg(ext);
8236 else if(!
data.imageRaw().empty() && !
data.depthRaw().empty())
8238 if(!cv::imwrite(QString(
"%1/rgb/%2.%3").
arg(
path).
arg(
id).
arg(ext).toStdString(),
data.imageRaw()))
8241 UWARN(
"Failed saving \"%s\"", QString(
"%1/depth/%2.png").
arg(
path).
arg(
id).toStdString().
c_str());
8242 info = tr(
"Saved rgb/%1.%2 and depth/%1.png.").arg(
id).arg(ext);
8244 else if(!
data.imageRaw().empty())
8246 if(!cv::imwrite(QString(
"%1/%2.%3").
arg(
path).
arg(
id).
arg(ext).toStdString(),
data.imageRaw()))
8249 info = tr(
"Saved %1.%2.").arg(
id).arg(ext);
8253 info = tr(
"No images saved for node %1!").arg(
id);
8259 QApplication::processEvents();
8262 if(saved!=poses.size())
8272 if(!calibrationSaved)
8274 QMessageBox::warning(
this,
8275 tr(
"Export images..."),
8276 tr(
"Data in the cache don't seem to have valid calibration. Calibration file will not be saved. Try refreshing the cache (with clouds)."));
8290 std::map<int, Transform> posesIn =
_ui->widget_mapVisibility->getVisiblePoses();
8295 for(std::map<int, Transform>::iterator
iter = posesIn.begin();
iter!=posesIn.end(); ++
iter)
8300 iter->second = gtIter->second;
8304 UWARN(
"Not found ground truth pose for node %d",
iter->first);
8309 std::map<int, Transform> poses;
8310 for(std::map<int, Transform>::iterator
iter=posesIn.begin();
iter!=posesIn.end(); ++
iter)
8317 UWARN(
"Missing image in cache for node %d",
iter->first);
8324 poses.insert(*
iter);
8328 UWARN(
"Missing calibration for node %d",
iter->first);
8333 UWARN(
"Did not find node %d in cache",
iter->first);
8347 UINFO(
"Updating map...");
8354 std::map<int, Transform>(),
8355 std::multimap<int, Link>(),
8357 UINFO(
"Updating map... done!");
8362 QMessageBox::warning(
this, tr(
"Exporting cameras..."), tr(
"No poses exported because of missing images. Try refreshing the cache (with clouds)."));
8368 UINFO(
"reset odometry");
8374 UINFO(
"trigger a new map");
8385 int r = QMessageBox::question(
this, tr(
"Hard drive or RAM?"), tr(
"Save in RAM?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
8387 if(r == QMessageBox::No || r == QMessageBox::Yes)
8389 bool recordInRAM = r == QMessageBox::Yes;
8405 _ui->actionData_recorder->setEnabled(
false);
8409 QMessageBox::warning(
this, tr(
""), tr(
"Cannot initialize the data recorder!"));
8410 UERROR(
"Cannot initialize the data recorder!");
8419 UERROR(
"Only one recorder at the same time.");
8425 _ui->actionData_recorder->setEnabled(
true);
8443 _ui->label_source->setVisible(!monitoring);
8444 _ui->label_stats_source->setVisible(!monitoring);
8445 _ui->actionNew_database->setVisible(!monitoring);
8446 _ui->actionOpen_database->setVisible(!monitoring);
8447 _ui->actionClose_database->setVisible(!monitoring);
8448 _ui->actionEdit_database->setVisible(!monitoring);
8449 _ui->actionStart->setVisible(!monitoring);
8450 _ui->actionStop->setVisible(!monitoring);
8451 _ui->actionDump_the_memory->setVisible(!monitoring);
8452 _ui->actionDump_the_prediction_matrix->setVisible(!monitoring);
8453 _ui->actionGenerate_map->setVisible(!monitoring);
8454 _ui->actionUpdate_cache_from_database->setVisible(monitoring);
8455 _ui->actionData_recorder->setVisible(!monitoring);
8456 _ui->menuSelect_source->menuAction()->setVisible(!monitoring);
8457 _ui->doubleSpinBox_stats_imgRate->setVisible(!monitoring);
8458 _ui->doubleSpinBox_stats_imgRate_label->setVisible(!monitoring);
8460 if(wasMonitoring != monitoring)
8462 _ui->toolBar->setVisible(!monitoring);
8463 _ui->toolBar->toggleViewAction()->setVisible(!monitoring);
8465 QList<QAction*> actions =
_ui->menuTools->actions();
8466 for(
int i=0;
i<actions.size(); ++
i)
8468 if(actions.at(
i)->isSeparator())
8470 actions.at(
i)->setVisible(!monitoring);
8473 actions =
_ui->menuFile->actions();
8474 if(actions.size()==16)
8476 if(actions.at(2)->isSeparator())
8478 actions.at(2)->setVisible(!monitoring);
8482 UWARN(
"Menu File separators have not the same order.");
8484 if(actions.at(12)->isSeparator())
8486 actions.at(12)->setVisible(!monitoring);
8490 UWARN(
"Menu File separators have not the same order.");
8495 UWARN(
"Menu File actions size has changed (%d)", actions.size());
8497 actions =
_ui->menuProcess->actions();
8498 if(actions.size()>=2)
8500 if(actions.at(1)->isSeparator())
8502 actions.at(1)->setVisible(!monitoring);
8506 UWARN(
"Menu File separators have not the same order.");
8511 UWARN(
"Menu File separators have not the same order.");
8519 _ui->actionNew_database->setEnabled(
true);
8520 _ui->actionOpen_database->setEnabled(
true);
8521 _ui->actionClose_database->setEnabled(
false);
8522 _ui->actionEdit_database->setEnabled(
true);
8523 _ui->actionStart->setEnabled(
false);
8524 _ui->actionPause->setEnabled(
false);
8525 _ui->actionPause->setChecked(
false);
8526 _ui->actionPause->setToolTip(tr(
"Pause"));
8527 _ui->actionStop->setEnabled(
false);
8528 _ui->actionPause_on_match->setEnabled(
true);
8529 _ui->actionPause_on_local_loop_detection->setEnabled(
true);
8530 _ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(
true);
8531 _ui->actionDump_the_memory->setEnabled(
false);
8532 _ui->actionDump_the_prediction_matrix->setEnabled(
false);
8533 _ui->actionDelete_memory->setEnabled(
false);
8536 _ui->actionGenerate_map->setEnabled(
false);
8541 #ifdef RTABMAP_OCTOMAP
8544 _ui->actionExport_octomap->setEnabled(
false);
8548 _ui->actionDownload_all_clouds->setEnabled(
false);
8549 _ui->actionDownload_graph->setEnabled(
false);
8550 _ui->menuSelect_source->setEnabled(
true);
8551 _ui->actionLabel_current_location->setEnabled(
false);
8552 _ui->actionSend_goal->setEnabled(
false);
8553 _ui->actionCancel_goal->setEnabled(
false);
8554 _ui->toolBar->findChild<QAction*>(
"toolbar_source")->setEnabled(
true);
8555 _ui->actionTrigger_a_new_map->setEnabled(
false);
8556 _ui->doubleSpinBox_stats_imgRate->setEnabled(
true);
8557 _ui->statusbar->clearMessage();
8564 _ui->actionStart->setEnabled(
false);
8565 _ui->actionPause->setEnabled(
false);
8566 _ui->actionStop->setEnabled(
false);
8571 _ui->actionNew_database->setEnabled(
false);
8572 _ui->actionOpen_database->setEnabled(
false);
8573 _ui->actionClose_database->setEnabled(
false);
8574 _ui->actionEdit_database->setEnabled(
false);
8579 _ui->actionNew_database->setEnabled(
false);
8580 _ui->actionOpen_database->setEnabled(
false);
8581 _ui->actionClose_database->setEnabled(
true);
8582 _ui->actionEdit_database->setEnabled(
false);
8583 _ui->actionStart->setEnabled(
true);
8584 _ui->actionPause->setEnabled(
false);
8585 _ui->actionPause->setChecked(
false);
8586 _ui->actionPause->setToolTip(tr(
"Pause"));
8587 _ui->actionStop->setEnabled(
false);
8588 _ui->actionPause_on_match->setEnabled(
true);
8589 _ui->actionPause_on_local_loop_detection->setEnabled(
true);
8590 _ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(
true);
8591 _ui->actionDump_the_memory->setEnabled(
true);
8592 _ui->actionDump_the_prediction_matrix->setEnabled(
true);
8596 _ui->actionGenerate_map->setEnabled(
true);
8601 #ifdef RTABMAP_OCTOMAP
8604 _ui->actionExport_octomap->setEnabled(
false);
8608 _ui->actionDownload_all_clouds->setEnabled(
true);
8609 _ui->actionDownload_graph->setEnabled(
true);
8610 _ui->menuSelect_source->setEnabled(
true);
8611 _ui->actionLabel_current_location->setEnabled(
true);
8612 _ui->actionSend_goal->setEnabled(
true);
8613 _ui->actionCancel_goal->setEnabled(
true);
8614 _ui->toolBar->findChild<QAction*>(
"toolbar_source")->setEnabled(
true);
8615 _ui->actionTrigger_a_new_map->setEnabled(
true);
8616 _ui->doubleSpinBox_stats_imgRate->setEnabled(
true);
8617 _ui->statusbar->clearMessage();
8623 _ui->actionStart->setEnabled(
false);
8628 _ui->actionNew_database->setEnabled(
false);
8629 _ui->actionOpen_database->setEnabled(
false);
8630 _ui->actionClose_database->setEnabled(
false);
8631 _ui->actionEdit_database->setEnabled(
false);
8632 _ui->actionStart->setEnabled(
false);
8633 _ui->actionPause->setEnabled(
true);
8634 _ui->actionPause->setChecked(
false);
8635 _ui->actionPause->setToolTip(tr(
"Pause"));
8636 _ui->actionStop->setEnabled(
true);
8637 _ui->actionPause_on_match->setEnabled(
true);
8638 _ui->actionPause_on_local_loop_detection->setEnabled(
true);
8639 _ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(
true);
8640 _ui->actionDump_the_memory->setEnabled(
false);
8641 _ui->actionDump_the_prediction_matrix->setEnabled(
false);
8642 _ui->actionDelete_memory->setEnabled(
false);
8643 _ui->actionPost_processing->setEnabled(
false);
8644 _ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(
false);
8645 _ui->actionGenerate_map->setEnabled(
false);
8646 _ui->menuExport_poses->setEnabled(
false);
8647 _ui->actionSave_point_cloud->setEnabled(
false);
8648 _ui->actionView_high_res_point_cloud->setEnabled(
false);
8649 _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(
false);
8650 _ui->actionExport_octomap->setEnabled(
false);
8651 _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(
false);
8652 _ui->actionDepth_Calibration->setEnabled(
false);
8653 _ui->actionDownload_all_clouds->setEnabled(
false);
8654 _ui->actionDownload_graph->setEnabled(
false);
8655 _ui->menuSelect_source->setEnabled(
false);
8656 _ui->actionLabel_current_location->setEnabled(
true);
8657 _ui->actionSend_goal->setEnabled(
true);
8658 _ui->actionCancel_goal->setEnabled(
true);
8659 _ui->toolBar->findChild<QAction*>(
"toolbar_source")->setEnabled(
false);
8660 _ui->actionTrigger_a_new_map->setEnabled(
true);
8661 _ui->doubleSpinBox_stats_imgRate->setEnabled(
true);
8662 _ui->statusbar->showMessage(tr(
"Detecting..."));
8664 _ui->label_elapsedTime->setText(
"00:00:00");
8684 _ui->actionPause->setToolTip(tr(
"Pause"));
8685 _ui->actionPause->setChecked(
false);
8686 _ui->statusbar->showMessage(tr(
"Detecting..."));
8687 _ui->actionDump_the_memory->setEnabled(
false);
8688 _ui->actionDump_the_prediction_matrix->setEnabled(
false);
8689 _ui->actionDelete_memory->setEnabled(
false);
8690 _ui->actionPost_processing->setEnabled(
false);
8691 _ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(
false);
8692 _ui->actionGenerate_map->setEnabled(
false);
8693 _ui->menuExport_poses->setEnabled(
false);
8694 _ui->actionSave_point_cloud->setEnabled(
false);
8695 _ui->actionView_high_res_point_cloud->setEnabled(
false);
8696 _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(
false);
8697 _ui->actionExport_octomap->setEnabled(
false);
8698 _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(
false);
8699 _ui->actionDepth_Calibration->setEnabled(
false);
8700 _ui->actionDownload_all_clouds->setEnabled(
false);
8701 _ui->actionDownload_graph->setEnabled(
false);
8718 _ui->actionPause->setToolTip(tr(
"Continue (shift-click for step-by-step)"));
8719 _ui->actionPause->setChecked(
true);
8720 _ui->statusbar->showMessage(tr(
"Paused..."));
8721 _ui->actionDump_the_memory->setEnabled(
true);
8722 _ui->actionDump_the_prediction_matrix->setEnabled(
true);
8723 _ui->actionDelete_memory->setEnabled(
false);
8726 _ui->actionGenerate_map->setEnabled(
true);
8731 #ifdef RTABMAP_OCTOMAP
8734 _ui->actionExport_octomap->setEnabled(
false);
8738 _ui->actionDownload_all_clouds->setEnabled(
true);
8739 _ui->actionDownload_graph->setEnabled(
true);
8755 _ui->actionPause->setEnabled(
true);
8756 _ui->actionPause->setChecked(
false);
8757 _ui->actionPause->setToolTip(tr(
"Pause"));
8758 _ui->actionPause_on_match->setEnabled(
true);
8759 _ui->actionPause_on_local_loop_detection->setEnabled(
true);
8760 _ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(
true);
8761 _ui->actionReset_Odometry->setEnabled(
true);
8762 _ui->actionPost_processing->setEnabled(
false);
8763 _ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(
false);
8764 _ui->menuExport_poses->setEnabled(
false);
8765 _ui->actionSave_point_cloud->setEnabled(
false);
8766 _ui->actionView_high_res_point_cloud->setEnabled(
false);
8767 _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(
false);
8768 _ui->actionExport_octomap->setEnabled(
false);
8769 _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(
false);
8770 _ui->actionDepth_Calibration->setEnabled(
false);
8771 _ui->actionDelete_memory->setEnabled(
true);
8772 _ui->actionDownload_all_clouds->setEnabled(
true);
8773 _ui->actionDownload_graph->setEnabled(
true);
8774 _ui->actionTrigger_a_new_map->setEnabled(
true);
8775 _ui->actionLabel_current_location->setEnabled(
true);
8776 _ui->actionSend_goal->setEnabled(
true);
8777 _ui->actionCancel_goal->setEnabled(
true);
8778 _ui->statusbar->showMessage(tr(
"Monitoring..."));
8785 _ui->actionPause->setToolTip(tr(
"Continue"));
8786 _ui->actionPause->setChecked(
true);
8787 _ui->actionPause->setEnabled(
true);
8788 _ui->actionPause_on_match->setEnabled(
true);
8789 _ui->actionPause_on_local_loop_detection->setEnabled(
true);
8790 _ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(
true);
8791 _ui->actionReset_Odometry->setEnabled(
true);
8798 #ifdef RTABMAP_OCTOMAP
8801 _ui->actionExport_octomap->setEnabled(
false);
8805 _ui->actionDelete_memory->setEnabled(
true);
8806 _ui->actionDownload_all_clouds->setEnabled(
true);
8807 _ui->actionDownload_graph->setEnabled(
true);
8808 _ui->actionTrigger_a_new_map->setEnabled(
true);
8809 _ui->actionLabel_current_location->setEnabled(
true);
8810 _ui->actionSend_goal->setEnabled(
true);
8811 _ui->actionCancel_goal->setEnabled(
true);
8812 _ui->statusbar->showMessage(tr(
"Monitoring paused..."));