30 #include "ui_DatabaseViewer.h" 31 #include <QMessageBox> 32 #include <QFileDialog> 33 #include <QInputDialog> 34 #include <QDesktopWidget> 35 #include <QColorDialog> 36 #include <QGraphicsLineItem> 37 #include <QtGui/QCloseEvent> 38 #include <QGraphicsOpacityEffect> 39 #include <QtCore/QBuffer> 40 #include <QtCore/QTextStream> 41 #include <QtCore/QDateTime> 42 #include <QtCore/QSettings> 47 #include <opencv2/core/core_c.h> 48 #include <opencv2/imgproc/types_c.h> 49 #include <opencv2/highgui/highgui.hpp> 89 #include <pcl/io/pcd_io.h> 90 #include <pcl/io/ply_io.h> 91 #include <pcl/io/obj_io.h> 92 #include <pcl/filters/voxel_grid.h> 93 #include <pcl/filters/crop_box.h> 94 #include <pcl/common/transforms.h> 95 #include <pcl/common/common.h> 97 #ifdef RTABMAP_OCTOMAP 108 editDepthDialog_(new QDialog(this)),
109 editMapDialog_(new QDialog(this)),
110 savedMaximized_(
false),
113 infoReducedGraph_(
false),
124 ui_ =
new Ui_DatabaseViewer();
126 ui_->buttonBox->setVisible(
false);
127 connect(
ui_->buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(close()));
129 ui_->comboBox_logger_level->setVisible(parent==0);
130 ui_->label_logger_level->setVisible(parent==0);
131 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateLoggerLevel()));
132 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
setupMainLayout(
bool)));
137 vLayout->setContentsMargins(0,0,0,0);
138 vLayout->setSpacing(0);
140 QDialogButtonBox * buttonBox =
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal,
editDepthDialog_);
141 vLayout->addWidget(buttonBox);
144 connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
editDepthArea_, SLOT(resetChanges()));
151 vLayout->setContentsMargins(0,0,0,0);
152 vLayout->setSpacing(0);
154 buttonBox =
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal,
editMapDialog_);
155 vLayout->addWidget(buttonBox);
156 connect(buttonBox, SIGNAL(accepted()),
editMapDialog_, SLOT(accept()));
157 connect(buttonBox, SIGNAL(rejected()),
editMapDialog_, SLOT(reject()));
158 connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
editMapArea_, SLOT(resetChanges()));
162 QString title(
"RTAB-Map Database Viewer[*]");
163 this->setWindowTitle(title);
165 ui_->dockWidget_constraints->setVisible(
false);
166 ui_->dockWidget_graphView->setVisible(
false);
167 ui_->dockWidget_occupancyGridView->setVisible(
false);
168 ui_->dockWidget_guiparameters->setVisible(
false);
169 ui_->dockWidget_coreparameters->setVisible(
false);
170 ui_->dockWidget_info->setVisible(
false);
171 ui_->dockWidget_stereoView->setVisible(
false);
172 ui_->dockWidget_view3d->setVisible(
false);
173 ui_->dockWidget_statistics->setVisible(
false);
193 ui_->graphicsView_stereo->setAlpha(255);
195 #ifndef RTABMAP_OCTOMAP 196 ui_->checkBox_octomap->setEnabled(
false);
197 ui_->checkBox_octomap->setChecked(
false);
228 ui_->parameters_toolbox->setupUi(parameters);
234 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
235 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
236 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
237 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
238 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
239 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
241 ui_->menuView->addAction(
ui_->dockWidget_constraints->toggleViewAction());
242 ui_->menuView->addAction(
ui_->dockWidget_graphView->toggleViewAction());
243 ui_->menuView->addAction(
ui_->dockWidget_occupancyGridView->toggleViewAction());
244 ui_->menuView->addAction(
ui_->dockWidget_stereoView->toggleViewAction());
245 ui_->menuView->addAction(
ui_->dockWidget_view3d->toggleViewAction());
246 ui_->menuView->addAction(
ui_->dockWidget_guiparameters->toggleViewAction());
247 ui_->menuView->addAction(
ui_->dockWidget_coreparameters->toggleViewAction());
248 ui_->menuView->addAction(
ui_->dockWidget_info->toggleViewAction());
249 ui_->menuView->addAction(
ui_->dockWidget_statistics->toggleViewAction());
250 connect(
ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
251 connect(
ui_->dockWidget_occupancyGridView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
252 connect(
ui_->dockWidget_statistics->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateStatistics()));
253 connect(
ui_->dockWidget_info->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateInfo()));
256 connect(
ui_->parameters_toolbox, SIGNAL(parametersChanged(
const QStringList &)),
this, SLOT(
notifyParametersChanged(
const QStringList &)));
258 connect(
ui_->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
260 ui_->actionOpen_database->setEnabled(
true);
261 ui_->actionClose_database->setEnabled(
false);
264 ui_->actionSave_config->setShortcut(QKeySequence::Save);
265 connect(
ui_->actionSave_config, SIGNAL(triggered()),
this, SLOT(
writeSettings()));
266 connect(
ui_->actionOpen_database, SIGNAL(triggered()),
this, SLOT(
openDatabase()));
267 connect(
ui_->actionClose_database, SIGNAL(triggered()),
this, SLOT(
closeDatabase()));
268 connect(
ui_->actionDatabase_recovery, SIGNAL(triggered()),
this, SLOT(
recoverDatabase()));
270 connect(
ui_->actionExtract_images, SIGNAL(triggered()),
this, SLOT(
extractImages()));
271 connect(
ui_->actionEdit_depth_image, SIGNAL(triggered()),
this, SLOT(
editDepthImage()));
272 connect(
ui_->actionGenerate_graph_dot, SIGNAL(triggered()),
this, SLOT(
generateGraph()));
274 connect(
ui_->actionRaw_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesRaw()));
278 connect(
ui_->actionKITTI_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesKITTI()));
281 connect(
ui_->actionPoses_KML, SIGNAL(triggered()),
this , SLOT(
exportPosesKML()));
282 connect(
ui_->actionGPS_TXT, SIGNAL(triggered()),
this , SLOT(
exportGPS_TXT()));
283 connect(
ui_->actionGPS_KML, SIGNAL(triggered()),
this , SLOT(
exportGPS_KML()));
284 connect(
ui_->actionEdit_optimized_2D_map, SIGNAL(triggered()),
this , SLOT(
editSaved2DMap()));
285 connect(
ui_->actionExport_saved_2D_map, SIGNAL(triggered()),
this , SLOT(
exportSaved2DMap()));
286 connect(
ui_->actionImport_2D_map, SIGNAL(triggered()),
this , SLOT(
import2DMap()));
287 connect(
ui_->actionRegenerate_optimized_2D_map, SIGNAL(triggered()),
this , SLOT(
regenerateSavedMap()));
291 connect(
ui_->actionView_3D_map, SIGNAL(triggered()),
this, SLOT(
view3DMap()));
292 connect(
ui_->actionGenerate_3D_map_pcd, SIGNAL(triggered()),
this, SLOT(
generate3DMap()));
301 connect(
ui_->actionReset_all_changes, SIGNAL(triggered()),
this, SLOT(
resetAllChanges()));
306 connect(
ui_->pushButton_add, SIGNAL(clicked()),
this, SLOT(
addConstraint()));
309 ui_->pushButton_refine->setEnabled(
false);
310 ui_->pushButton_add->setEnabled(
false);
311 ui_->pushButton_reset->setEnabled(
false);
312 ui_->pushButton_reject->setEnabled(
false);
314 ui_->menuEdit->setEnabled(
false);
315 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
316 ui_->actionExport->setEnabled(
false);
317 ui_->actionExtract_images->setEnabled(
false);
318 ui_->menuExport_poses->setEnabled(
false);
319 ui_->menuExport_GPS->setEnabled(
false);
320 ui_->actionPoses_KML->setEnabled(
false);
321 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
322 ui_->actionExport_saved_2D_map->setEnabled(
false);
323 ui_->actionImport_2D_map->setEnabled(
false);
324 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
325 ui_->actionView_optimized_mesh->setEnabled(
false);
326 ui_->actionExport_optimized_mesh->setEnabled(
false);
327 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
329 ui_->horizontalSlider_A->setTracking(
false);
330 ui_->horizontalSlider_B->setTracking(
false);
331 ui_->horizontalSlider_A->setEnabled(
false);
332 ui_->horizontalSlider_B->setEnabled(
false);
335 connect(
ui_->horizontalSlider_A, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderAMoved(
int)));
336 connect(
ui_->horizontalSlider_B, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderBMoved(
int)));
338 connect(
ui_->spinBox_mesh_angleTolerance, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
339 connect(
ui_->spinBox_mesh_minClusterSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
340 connect(
ui_->spinBox_mesh_fillDepthHoles, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
341 connect(
ui_->spinBox_mesh_depthError, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
342 connect(
ui_->checkBox_mesh_quad, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
343 connect(
ui_->spinBox_mesh_triangleSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
344 connect(
ui_->checkBox_showWords, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
345 connect(
ui_->checkBox_showCloud, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
346 connect(
ui_->checkBox_showMesh, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
347 connect(
ui_->checkBox_showScan, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
348 connect(
ui_->checkBox_showMap, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
349 connect(
ui_->checkBox_showGrid, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
350 connect(
ui_->checkBox_odomFrame_3dview, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
351 connect(
ui_->checkBox_gravity_3dview, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
353 ui_->horizontalSlider_neighbors->setTracking(
false);
354 ui_->horizontalSlider_loops->setTracking(
false);
355 ui_->horizontalSlider_neighbors->setEnabled(
false);
356 ui_->horizontalSlider_loops->setEnabled(
false);
366 ui_->checkBox_showOptimized->setEnabled(
false);
367 connect(
ui_->toolButton_constraint, SIGNAL(clicked(
bool)),
this, SLOT(
editConstraint()));
370 ui_->horizontalSlider_iterations->setTracking(
false);
371 ui_->horizontalSlider_iterations->setEnabled(
false);
372 ui_->spinBox_optimizationsFrom->setEnabled(
false);
375 connect(
ui_->spinBox_optimizationsFrom, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
376 connect(
ui_->checkBox_iterativeOptimization, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
377 connect(
ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
378 connect(
ui_->checkBox_wmState, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
379 connect(
ui_->graphViewer, SIGNAL(mapShownRequested()),
this, SLOT(
updateGraphView()));
380 connect(
ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
382 connect(
ui_->checkBox_ignoreGlobalLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
383 connect(
ui_->checkBox_ignoreLocalLoopSpace, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
384 connect(
ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
385 connect(
ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
386 connect(
ui_->checkBox_ignoreLandmarks, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
387 connect(
ui_->doubleSpinBox_optimizationScale, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
388 connect(
ui_->checkBox_octomap, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
389 connect(
ui_->checkBox_grid_2d, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
390 connect(
ui_->comboBox_octomap_rendering_type, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateOctomapView()));
392 connect(
ui_->checkBox_grid_empty, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
393 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
updateConstraintView()));
395 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
update3dView()));
396 connect(
ui_->checkBox_cameraProjection, SIGNAL(stateChanged(
int)),
this, SLOT(
update3dView()));
397 connect(
ui_->checkBox_showDisparityInsteadOfRight, SIGNAL(stateChanged(
int)),
this, SLOT(
update3dView()));
399 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
400 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
updateGraphView()));
401 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
402 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
404 ui_->label_stereo_inliers_name->setStyleSheet(
"QLabel {color : blue; }");
405 ui_->label_stereo_flowOutliers_name->setStyleSheet(
"QLabel {color : red; }");
406 ui_->label_stereo_slopeOutliers_name->setStyleSheet(
"QLabel {color : yellow; }");
407 ui_->label_stereo_disparityOutliers_name->setStyleSheet(
"QLabel {color : magenta; }");
411 connect(
ui_->graphViewer, SIGNAL(configChanged()),
this, SLOT(
configModified()));
412 connect(
ui_->graphicsView_A, SIGNAL(configChanged()),
this, SLOT(
configModified()));
413 connect(
ui_->graphicsView_B, SIGNAL(configChanged()),
this, SLOT(
configModified()));
414 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
configModified()));
415 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
416 connect(
ui_->checkBox_alignPosesWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
417 connect(
ui_->checkBox_alignScansCloudsWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
418 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
419 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
420 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
421 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
updateStatistics()));
423 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
424 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
425 connect(
ui_->checkBox_cameraProjection, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
426 connect(
ui_->checkBox_showDisparityInsteadOfRight, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
427 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
428 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
configModified()));
429 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
430 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
432 connect(
ui_->spinBox_icp_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
433 connect(
ui_->doubleSpinBox_icp_maxDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
434 connect(
ui_->doubleSpinBox_icp_minDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
435 connect(
ui_->checkBox_icp_from_depth, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
437 connect(
ui_->doubleSpinBox_detectMore_radius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
438 connect(
ui_->doubleSpinBox_detectMore_radiusMin, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
439 connect(
ui_->doubleSpinBox_detectMore_angle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
440 connect(
ui_->spinBox_detectMore_iterations, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
441 connect(
ui_->checkBox_detectMore_intraSession, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
442 connect(
ui_->checkBox_detectMore_interSession, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
444 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
445 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
446 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
447 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
448 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
449 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
452 connect(
ui_->toolButton_emptyColor, SIGNAL(clicked(
bool)),
this, SLOT(
selectEmptyColor()));
453 connect(
ui_->spinBox_cropRadius, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
454 connect(
ui_->checkBox_grid_showProbMap, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
455 connect(
ui_->checkBox_grid_showProbMap, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
460 QList<QDockWidget*> dockWidgets = this->findChildren<QDockWidget*>();
461 for(
int i=0; i<dockWidgets.size(); ++i)
463 connect(dockWidgets[i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
this, SLOT(
configModified()));
464 connect(dockWidgets[i]->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
466 ui_->dockWidget_constraints->installEventFilter(
this);
467 ui_->dockWidget_graphView->installEventFilter(
this);
468 ui_->dockWidget_occupancyGridView->installEventFilter(
this);
469 ui_->dockWidget_stereoView->installEventFilter(
this);
470 ui_->dockWidget_view3d->installEventFilter(
this);
471 ui_->dockWidget_guiparameters->installEventFilter(
this);
472 ui_->dockWidget_coreparameters->installEventFilter(
this);
473 ui_->dockWidget_info->installEventFilter(
this);
474 ui_->dockWidget_statistics->installEventFilter(
this);
481 #ifdef RTABMAP_OCTOMAP 490 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::TopToBottom);
494 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::LeftToRight);
504 ui_->buttonBox->setVisible(visible);
509 this->setWindowModified(
true);
518 QString privatePath = QDir::homePath() +
"/.rtabmap";
519 if(!QDir(privatePath).exists())
521 QDir::home().mkdir(
".rtabmap");
523 return privatePath +
"/rtabmap.ini";
529 QSettings settings(path, QSettings::IniFormat);
530 settings.beginGroup(
"DatabaseViewer");
534 bytes = settings.value(
"geometry", QByteArray()).toByteArray();
537 this->restoreGeometry(bytes);
539 bytes = settings.value(
"state", QByteArray()).toByteArray();
542 this->restoreState(bytes);
546 ui_->comboBox_logger_level->setCurrentIndex(settings.value(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex()).toInt());
547 ui_->actionVertical_Layout->setChecked(settings.value(
"verticalLayout",
ui_->actionVertical_Layout->isChecked()).toBool());
548 ui_->checkBox_ignoreIntermediateNodes->setChecked(settings.value(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked()).toBool());
549 ui_->checkBox_timeStats->setChecked(settings.value(
"timeStats",
ui_->checkBox_timeStats->isChecked()).toBool());
552 ui_->graphViewer->loadSettings(settings,
"GraphView");
554 settings.beginGroup(
"optimization");
555 ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble());
556 ui_->doubleSpinBox_voxelSize->setValue(settings.value(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value()).toDouble());
557 ui_->spinBox_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_decimation->value()).toInt());
558 ui_->checkBox_cameraProjection->setChecked(settings.value(
"camProj",
ui_->checkBox_cameraProjection->isChecked()).toBool());
559 ui_->checkBox_showDisparityInsteadOfRight->setChecked(settings.value(
"showDisp",
ui_->checkBox_showDisparityInsteadOfRight->isChecked()).toBool());
562 settings.beginGroup(
"grid");
563 ui_->groupBox_posefiltering->setChecked(settings.value(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked()).toBool());
564 ui_->doubleSpinBox_posefilteringRadius->setValue(settings.value(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value()).toDouble());
565 ui_->doubleSpinBox_posefilteringAngle->setValue(settings.value(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value()).toDouble());
566 ui_->lineEdit_obstacleColor->setText(settings.value(
"colorObstacle",
ui_->lineEdit_obstacleColor->text()).toString());
567 ui_->lineEdit_groundColor->setText(settings.value(
"colorGround",
ui_->lineEdit_groundColor->text()).toString());
568 ui_->lineEdit_emptyColor->setText(settings.value(
"colorEmpty",
ui_->lineEdit_emptyColor->text()).toString());
569 ui_->spinBox_cropRadius->setValue(settings.value(
"cropRadius",
ui_->spinBox_cropRadius->value()).toInt());
570 ui_->checkBox_grid_showProbMap->setChecked(settings.value(
"probMap",
ui_->checkBox_grid_showProbMap->isChecked()).toBool());
573 settings.beginGroup(
"mesh");
574 ui_->checkBox_mesh_quad->setChecked(settings.value(
"quad",
ui_->checkBox_mesh_quad->isChecked()).toBool());
575 ui_->spinBox_mesh_angleTolerance->setValue(settings.value(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value()).toInt());
576 ui_->spinBox_mesh_minClusterSize->setValue(settings.value(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value()).toInt());
577 ui_->spinBox_mesh_fillDepthHoles->setValue(settings.value(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value()).toInt());
578 ui_->spinBox_mesh_depthError->setValue(settings.value(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value()).toInt());
579 ui_->spinBox_mesh_triangleSize->setValue(settings.value(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value()).toInt());
583 ui_->graphicsView_A->loadSettings(settings,
"ImageViewA");
584 ui_->graphicsView_B->loadSettings(settings,
"ImageViewB");
587 settings.beginGroup(
"icp");
588 ui_->spinBox_icp_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_icp_decimation->value()).toInt());
589 ui_->doubleSpinBox_icp_maxDepth->setValue(settings.value(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value()).toDouble());
590 ui_->doubleSpinBox_icp_minDepth->setValue(settings.value(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value()).toDouble());
591 ui_->checkBox_icp_from_depth->setChecked(settings.value(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked()).toBool());
597 settings.beginGroup(
"Gui");
599 settings.beginGroup(
"PostProcessingDialog");
600 ui_->doubleSpinBox_detectMore_radius->setValue(settings.value(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value()).toDouble());
601 ui_->doubleSpinBox_detectMore_radiusMin->setValue(settings.value(
"cluster_radius_min",
ui_->doubleSpinBox_detectMore_radiusMin->value()).toDouble());
602 ui_->doubleSpinBox_detectMore_angle->setValue(settings.value(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value()).toDouble());
603 ui_->spinBox_detectMore_iterations->setValue(settings.value(
"iterations",
ui_->spinBox_detectMore_iterations->value()).toInt());
604 ui_->checkBox_detectMore_intraSession->setChecked(settings.value(
"intra_session",
ui_->checkBox_detectMore_intraSession->isChecked()).toBool());
605 ui_->checkBox_detectMore_interSession->setChecked(settings.value(
"inter_session",
ui_->checkBox_detectMore_interSession->isChecked()).toBool());
612 for(ParametersMap::iterator iter = parameters.begin(); iter!= parameters.end(); ++iter)
614 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
621 QSettings settings(path, QSettings::IniFormat);
622 settings.beginGroup(
"DatabaseViewer");
625 if(!this->isMaximized())
627 settings.setValue(
"geometry", this->saveGeometry());
629 settings.setValue(
"state", this->saveState());
630 settings.setValue(
"maximized", this->isMaximized());
633 settings.setValue(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex());
634 settings.setValue(
"verticalLayout",
ui_->actionVertical_Layout->isChecked());
635 settings.setValue(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked());
636 settings.setValue(
"timeStats",
ui_->checkBox_timeStats->isChecked());
639 ui_->graphViewer->saveSettings(settings,
"GraphView");
642 settings.beginGroup(
"optimization");
643 settings.setValue(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value());
644 settings.setValue(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value());
645 settings.setValue(
"decimation",
ui_->spinBox_decimation->value());
646 settings.setValue(
"camProj",
ui_->checkBox_cameraProjection->isChecked());
647 settings.setValue(
"showDisp",
ui_->checkBox_showDisparityInsteadOfRight->isChecked());
651 settings.beginGroup(
"grid");
652 settings.setValue(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked());
653 settings.setValue(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value());
654 settings.setValue(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value());
655 settings.setValue(
"colorObstacle",
ui_->lineEdit_obstacleColor->text());
656 settings.setValue(
"colorGround",
ui_->lineEdit_groundColor->text());
657 settings.setValue(
"colorEmpty",
ui_->lineEdit_emptyColor->text());
658 settings.setValue(
"cropRadius",
ui_->spinBox_cropRadius->value());
659 settings.setValue(
"probMap",
ui_->checkBox_grid_showProbMap->isChecked());
662 settings.beginGroup(
"mesh");
663 settings.setValue(
"quad",
ui_->checkBox_mesh_quad->isChecked());
664 settings.setValue(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value());
665 settings.setValue(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value());
666 settings.setValue(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value());
667 settings.setValue(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value());
668 settings.setValue(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value());
672 ui_->graphicsView_A->saveSettings(settings,
"ImageViewA");
673 ui_->graphicsView_B->saveSettings(settings,
"ImageViewB");
676 settings.beginGroup(
"icp");
677 settings.setValue(
"decimation",
ui_->spinBox_icp_decimation->value());
678 settings.setValue(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value());
679 settings.setValue(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value());
680 settings.setValue(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked());
686 settings.beginGroup(
"Gui");
688 settings.beginGroup(
"PostProcessingDialog");
689 settings.setValue(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value());
690 settings.setValue(
"cluster_radius_min",
ui_->doubleSpinBox_detectMore_radiusMin->value());
691 settings.setValue(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value());
692 settings.setValue(
"iterations",
ui_->spinBox_detectMore_iterations->value());
693 settings.setValue(
"intra_session",
ui_->checkBox_detectMore_intraSession->isChecked());
694 settings.setValue(
"inter_session",
ui_->checkBox_detectMore_interSession->isChecked());
699 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end();)
701 if(!
ui_->parameters_toolbox->getParameterWidget(iter->first.c_str()))
703 parameters.erase(iter++);
712 this->setWindowModified(
false);
718 ui_->comboBox_logger_level->setCurrentIndex(1);
719 ui_->checkBox_alignPosesWithGroundTruth->setChecked(
true);
720 ui_->checkBox_alignScansCloudsWithGroundTruth->setChecked(
false);
721 ui_->checkBox_ignoreIntermediateNodes->setChecked(
false);
722 ui_->checkBox_timeStats->setChecked(
true);
724 ui_->checkBox_iterativeOptimization->setChecked(
true);
725 ui_->checkBox_spanAllMaps->setChecked(
true);
726 ui_->checkBox_wmState->setChecked(
false);
727 ui_->checkBox_ignorePoseCorrection->setChecked(
false);
728 ui_->checkBox_ignoreGlobalLoop->setChecked(
false);
729 ui_->checkBox_ignoreLocalLoopSpace->setChecked(
false);
730 ui_->checkBox_ignoreLocalLoopTime->setChecked(
false);
731 ui_->checkBox_ignoreUserLoop->setChecked(
false);
732 ui_->checkBox_ignoreLandmarks->setChecked(
false);
733 ui_->doubleSpinBox_optimizationScale->setValue(1.0);
734 ui_->doubleSpinBox_gainCompensationRadius->setValue(0.0);
735 ui_->doubleSpinBox_voxelSize->setValue(0.0);
736 ui_->spinBox_decimation->setValue(1);
737 ui_->checkBox_cameraProjection->setChecked(
false);
738 ui_->checkBox_showDisparityInsteadOfRight->setChecked(
false);
740 ui_->groupBox_posefiltering->setChecked(
false);
741 ui_->doubleSpinBox_posefilteringRadius->setValue(0.1);
742 ui_->doubleSpinBox_posefilteringAngle->setValue(30);
743 ui_->checkBox_grid_empty->setChecked(
true);
744 ui_->checkBox_octomap->setChecked(
false);
745 ui_->lineEdit_obstacleColor->setText(QColor(Qt::red).
name());
746 ui_->lineEdit_groundColor->setText(QColor(Qt::green).
name());
747 ui_->lineEdit_emptyColor->setText(QColor(Qt::yellow).
name());
748 ui_->spinBox_cropRadius->setValue(1);
749 ui_->checkBox_grid_showProbMap->setChecked(
false);
751 ui_->checkBox_mesh_quad->setChecked(
true);
752 ui_->spinBox_mesh_angleTolerance->setValue(15);
753 ui_->spinBox_mesh_minClusterSize->setValue(0);
754 ui_->spinBox_mesh_fillDepthHoles->setValue(
false);
755 ui_->spinBox_mesh_depthError->setValue(10);
756 ui_->spinBox_mesh_triangleSize->setValue(2);
758 ui_->spinBox_icp_decimation->setValue(1);
759 ui_->doubleSpinBox_icp_maxDepth->setValue(0.0);
760 ui_->doubleSpinBox_icp_minDepth->setValue(0.0);
761 ui_->checkBox_icp_from_depth->setChecked(
false);
763 ui_->doubleSpinBox_detectMore_radius->setValue(1.0);
764 ui_->doubleSpinBox_detectMore_radiusMin->setValue(0.0);
765 ui_->doubleSpinBox_detectMore_angle->setValue(30.0);
766 ui_->spinBox_detectMore_iterations->setValue(5);
767 ui_->checkBox_detectMore_intraSession->setChecked(
true);
768 ui_->checkBox_detectMore_interSession->setChecked(
true);
773 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
782 UDEBUG(
"Open database \"%s\"", path.toStdString().c_str());
783 if(QFile::exists(path))
785 if(QFileInfo(path).isFile())
787 std::string driverType =
"sqlite3";
793 ui_->actionClose_database->setEnabled(
false);
794 ui_->actionOpen_database->setEnabled(
true);
797 QMessageBox::warning(
this,
"Database error", tr(
"Can't open database \"%1\"").arg(path));
801 ui_->actionClose_database->setEnabled(
true);
802 ui_->actionOpen_database->setEnabled(
false);
815 if(parameters.size())
817 const ParametersMap & currentParameters =
ui_->parameters_toolbox->getParameters();
819 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
821 ParametersMap::const_iterator jter = currentParameters.find(iter->first);
822 if(jter!=currentParameters.end() &&
823 ui_->parameters_toolbox->getParameterWidget(QString(iter->first.c_str())) != 0 &&
824 iter->second.compare(jter->second) != 0 &&
825 iter->first.compare(Parameters::kRtabmapWorkingDirectory()) != 0)
827 bool different =
true;
838 differentParameters.insert(*iter);
839 QString msg = tr(
"Parameter \"%1\": database=\"%2\" Preferences=\"%3\"")
840 .arg(iter->first.c_str())
841 .arg(iter->second.c_str())
842 .arg(jter->second.c_str());
843 UWARN(msg.toStdString().c_str());
848 if(differentParameters.size())
850 int r = QMessageBox::question(
this,
851 tr(
"Update parameters..."),
852 tr(
"The database is using %1 different parameter(s) than " 853 "those currently set in Core parameters panel. Do you want " 854 "to use database's parameters?").arg(differentParameters.size()),
855 QMessageBox::Yes | QMessageBox::No,
857 if(r == QMessageBox::Yes)
860 for(rtabmap::ParametersMap::const_iterator iter = differentParameters.begin(); iter!=differentParameters.end(); ++iter)
862 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
863 str.push_back(iter->first.c_str());
871 this->setWindowTitle(
"RTAB-Map Database Viewer - " + path +
"[*]");
887 QMessageBox::warning(
this,
"Database error", tr(
"Database \"%1\" does not exist.").arg(path));
894 this->setWindowTitle(
"RTAB-Map Database Viewer[*]");
899 QMessageBox::StandardButton button = QMessageBox::question(
this,
900 tr(
"Links modified"),
901 tr(
"Some links are modified (%1 added, %2 refined, %3 removed), do you want to save them?")
903 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
904 QMessageBox::Cancel);
906 if(button == QMessageBox::Yes)
909 for(std::multimap<int, rtabmap::Link>::iterator iter=
linksAdded_.begin(); iter!=
linksAdded_.end(); ++iter)
955 if(button != QMessageBox::Yes && button != QMessageBox::No)
964 QMessageBox::StandardButton button = QMessageBox::question(
this,
965 tr(
"Local occupancy grid maps modified"),
966 tr(
"%1 occupancy grid maps are modified, do you want to " 967 "save them? This will overwrite occupancy grids saved in the database.")
969 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
970 QMessageBox::Cancel);
972 if(button == QMessageBox::Yes)
975 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat > >::iterator mapIter =
generatedLocalMaps_.begin();
979 UASSERT(mapIter->first == infoIter->first);
982 mapIter->second.first.first,
983 mapIter->second.first.second,
984 mapIter->second.second,
985 infoIter->second.first,
986 infoIter->second.second);
997 if(button != QMessageBox::Yes && button != QMessageBox::No)
1005 QMessageBox::StandardButton button = QMessageBox::question(
this,
1006 tr(
"Laser scans modified"),
1007 tr(
"%1 laser scans are modified, do you want to " 1008 "save them? This will overwrite laser scans saved in the database.")
1010 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
1011 QMessageBox::Cancel);
1013 if(button == QMessageBox::Yes)
1022 if(button != QMessageBox::Yes && button != QMessageBox::No)
1053 ui_->graphViewer->clearAll();
1055 ui_->menuEdit->setEnabled(
false);
1056 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
1057 ui_->actionExport->setEnabled(
false);
1058 ui_->actionExtract_images->setEnabled(
false);
1059 ui_->menuExport_poses->setEnabled(
false);
1060 ui_->menuExport_GPS->setEnabled(
false);
1061 ui_->actionPoses_KML->setEnabled(
false);
1062 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
1063 ui_->actionExport_saved_2D_map->setEnabled(
false);
1064 ui_->actionImport_2D_map->setEnabled(
false);
1065 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
1066 ui_->actionView_optimized_mesh->setEnabled(
false);
1067 ui_->actionExport_optimized_mesh->setEnabled(
false);
1068 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
1069 ui_->checkBox_showOptimized->setEnabled(
false);
1070 ui_->toolBox_statistics->clear();
1072 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
1073 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
1074 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
1075 ui_->label_scale_title->setVisible(
false);
1076 ui_->label_rmse->setVisible(
false);
1077 ui_->label_rmse_title->setVisible(
false);
1078 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
1079 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
1080 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
1081 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
1082 ui_->label_optimizeFrom->setText(tr(
"Root"));
1083 ui_->textEdit_info->clear();
1085 ui_->pushButton_refine->setEnabled(
false);
1086 ui_->pushButton_add->setEnabled(
false);
1087 ui_->pushButton_reset->setEnabled(
false);
1088 ui_->pushButton_reject->setEnabled(
false);
1090 ui_->horizontalSlider_loops->setEnabled(
false);
1091 ui_->horizontalSlider_loops->setMaximum(0);
1092 ui_->horizontalSlider_iterations->setEnabled(
false);
1093 ui_->horizontalSlider_iterations->setMaximum(0);
1094 ui_->horizontalSlider_neighbors->setEnabled(
false);
1095 ui_->horizontalSlider_neighbors->setMaximum(0);
1096 ui_->label_constraint->clear();
1097 ui_->label_constraint_opt->clear();
1098 ui_->label_variance->clear();
1099 ui_->lineEdit_covariance->clear();
1100 ui_->label_type->clear();
1101 ui_->label_type_name->clear();
1102 ui_->checkBox_showOptimized->setEnabled(
false);
1104 ui_->horizontalSlider_A->setEnabled(
false);
1105 ui_->horizontalSlider_A->setMaximum(0);
1106 ui_->horizontalSlider_B->setEnabled(
false);
1107 ui_->horizontalSlider_B->setMaximum(0);
1108 ui_->label_idA->setText(
"NaN");
1109 ui_->label_idB->setText(
"NaN");
1122 ui_->graphViewer->clearAll();
1123 ui_->label_loopClosures->clear();
1124 ui_->label_timeOptimization->clear();
1125 ui_->label_pathLength->clear();
1126 ui_->label_poses->clear();
1127 ui_->label_rmse->clear();
1128 ui_->spinBox_optimizationsFrom->setEnabled(
false);
1130 ui_->graphicsView_A->clear();
1131 ui_->graphicsView_B->clear();
1133 ui_->graphicsView_stereo->clear();
1137 ui_->toolBox_statistics->clear();
1149 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
1154 QMessageBox::information(
this,
"Database recovery", tr(
"The selected database is already opened, close it first."));
1157 std::string errorMsg;
1159 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1161 progressDialog->show();
1166 QMessageBox::information(
this,
"Database recovery", tr(
"Database \"%1\" recovered! Try opening it again.").arg(path));
1170 QMessageBox::warning(
this,
"Database recovery", tr(
"Database recovery failed: \"%1\".").arg(errorMsg.c_str()));
1180 if(this->isWindowModified())
1182 QMessageBox::Button b=QMessageBox::question(
this,
1183 tr(
"Database Viewer"),
1184 tr(
"There are unsaved changed settings. Save them?"),
1185 QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
1186 if(b == QMessageBox::Save)
1190 else if(b != QMessageBox::Discard)
1209 if(event->isAccepted())
1211 ui_->toolBox_statistics->closeFigures();
1222 this->setWindowModified(
false);
1224 if((
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()) &&
graphes_.size() &&
localMaps_.size()==0)
1232 if(this->isVisible())
1245 if(this->isVisible())
1254 if((event->modifiers() & Qt::ControlModifier) && event->key() == Qt::Key_S)
1262 if (event->type() == QEvent::Resize && qobject_cast<QDockWidget*>(obj))
1264 this->setWindowModified(
true);
1266 return QWidget::eventFilter(obj, event);
1290 double previousStamp = 0;
1291 std::vector<double> delays(
ids_.size());
1293 std::map<int, Transform> poses;
1294 std::map<int, double> stamps;
1295 std::map<int, Transform> groundTruths;
1296 std::map<int, GPS> gpsValues;
1297 std::map<int, EnvSensors> sensorsValues;
1298 for(
int i=0; i<
ids_.size(); i+=1+framesIgnored)
1305 std::vector<float> velocity;
1310 if(frameRate == 0 ||
1311 previousStamp == 0 ||
1313 stamp - previousStamp >= 1.0/frameRate)
1315 if(sessionExported < 0 || sessionExported == mapId)
1317 ids.push_back(
ids_[i]);
1319 if(previousStamp && stamp)
1321 delays[oi++] = stamp - previousStamp;
1323 previousStamp = stamp;
1325 poses.insert(std::make_pair(
ids_[i], odomPose));
1326 stamps.insert(std::make_pair(
ids_[i], stamp));
1327 groundTruths.insert(std::make_pair(
ids_[i], groundTruth));
1328 if(gps.
stamp() > 0.0)
1330 gpsValues.insert(std::make_pair(
ids_[i], gps));
1334 sensorsValues.insert(std::make_pair(
ids_[i], sensors));
1338 if(sessionExported >= 0 && mapId > sessionExported)
1346 if(recorder.
init(path,
false))
1349 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1351 progressDialog->show();
1353 UINFO(
"Decompress: rgb=%d depth=%d scan=%d userData=%d",
1359 for(
int i=0; i<ids.size() && !progressDialog->
isCanceled(); ++i)
1365 cv::Mat depth, rgb, userData;
1372 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
1375 std::multimap<int, Link> links;
1377 if(links.size() && links.begin()->first < id)
1379 covariance = links.begin()->second.infMatrix().inv();
1406 if(groundTruths.find(
id)!=groundTruths.end())
1410 if(gpsValues.find(
id)!=gpsValues.end())
1412 sensorData.
setGPS(gpsValues.at(
id));
1414 if(sensorsValues.find(
id)!=sensorsValues.end())
1421 progressDialog->
appendText(tr(
"Exported node %1").arg(
id));
1423 QApplication::processEvents();
1428 progressDialog->
appendText(tr(
"Average frame rate=%1 Hz (Min=%2, Max=%3)")
1429 .arg(1.0/
uMean(delays)).arg(1.0/
uMax(delays)).arg(1.0/
uMin(delays)));
1431 progressDialog->
appendText(tr(
"Export finished to \"%1\"!").arg(path));
1435 UERROR(
"DataRecorder init failed?!");
1440 QMessageBox::warning(
this, tr(
"Cannot export database"), tr(
"An output path must be set!"));
1452 QStringList formats;
1453 formats.push_back(
"id.jpg");
1454 formats.push_back(
"id.png");
1455 formats.push_back(
"timestamp.jpg");
1456 formats.push_back(
"timestamp.png");
1458 QString format = QInputDialog::getItem(
this, tr(
"Which RGB format?"), tr(
"Format:"), formats, 0,
false, &ok);
1464 QString ext = format.split(
'.').back();
1465 bool useStamp = format.split(
'.').front().compare(
"timestamp") == 0;
1466 bool directoriesCreated =
false;
1467 QString path = QFileDialog::getExistingDirectory(
this, tr(
"Select directory where to save images..."),
pathDatabase_);
1471 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1474 progressDialog->
appendText(tr(
"Saving %1 images to %2...").arg(
ids_.size()).arg(path));
1475 progressDialog->show();
1477 int imagesExported = 0;
1478 for(
int i=0; i<
ids_.size(); ++i)
1480 QString
id = QString::number(
ids_.at(i));
1484 data.uncompressData();
1486 if(!directoriesCreated)
1489 if(!data.imageRaw().empty() && !data.rightRaw().empty())
1492 dir.mkdir(QString(
"%1/left").arg(path));
1493 dir.mkdir(QString(
"%1/right").arg(path));
1494 dir.mkdir(QString(
"%1/calib").arg(path));
1495 directoriesCreated =
true;
1497 else if(!data.imageRaw().empty())
1499 if(!data.depthRaw().empty())
1502 dir.mkdir(QString(
"%1/rgb").arg(path));
1503 dir.mkdir(QString(
"%1/depth").arg(path));
1504 dir.mkdir(QString(
"%1/calib").arg(path));
1505 directoriesCreated =
true;
1510 if(!data.imageRaw().empty() && useStamp)
1516 std::vector<float> v;
1522 UWARN(
"Node %d has null timestamp! Using id instead!",
ids_.at(i));
1526 id = QString::number(stamp,
'f');
1530 if(!data.imageRaw().empty())
1532 if(!data.rightRaw().empty())
1534 if(!cv::imwrite(QString(
"%1/left/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.imageRaw()))
1535 UWARN(
"Failed saving \"%s\"", QString(
"%1/left/%2.%3").arg(path).arg(
id).arg(ext).toStdString().c_str());
1536 if(!cv::imwrite(QString(
"%1/right/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.rightRaw()))
1537 UWARN(
"Failed saving \"%s\"", QString(
"%1/right/%2.%3").arg(path).arg(
id).arg(ext).toStdString().c_str());
1538 UINFO(QString(
"Saved left/%1.%2 and right/%1.%2").arg(
id).arg(ext).toStdString().c_str());
1542 UERROR(
"Cannot save calibration file, database name is empty!");
1544 else if(data.stereoCameraModels().size()>=1 && data.stereoCameraModels().front().isValidForProjection())
1546 for(
size_t i=0; i<data.stereoCameraModels().size(); ++i)
1548 std::string cameraName =
id.toStdString();
1549 if(data.stereoCameraModels().size()>1)
1555 data.imageRaw().size(),
1556 data.stereoCameraModels()[i].left().K(),
1557 data.stereoCameraModels()[i].left().D(),
1558 data.stereoCameraModels()[i].left().R(),
1559 data.stereoCameraModels()[i].left().P(),
1560 data.rightRaw().size(),
1561 data.stereoCameraModels()[i].right().K(),
1562 data.stereoCameraModels()[i].right().D(),
1563 data.stereoCameraModels()[i].right().R(),
1564 data.stereoCameraModels()[i].right().P(),
1565 data.stereoCameraModels()[i].R(),
1566 data.stereoCameraModels()[i].T(),
1567 data.stereoCameraModels()[i].E(),
1568 data.stereoCameraModels()[i].F(),
1569 data.stereoCameraModels()[i].left().localTransform());
1570 if(
model.save(path.toStdString() +
"/calib"))
1572 UINFO(
"Saved stereo calibration \"%s\"", (path.toStdString()+
"/calib/"+cameraName+
".yaml").c_str());
1576 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/calib/"+cameraName+
".yaml").c_str());
1583 if(!data.depthRaw().empty())
1585 if(!cv::imwrite(QString(
"%1/rgb/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.imageRaw()))
1586 UWARN(
"Failed saving \"%s\"", QString(
"%1/rgb/%2.%3").arg(path).arg(
id).arg(ext).toStdString().c_str());
1587 if(!cv::imwrite(QString(
"%1/depth/%2.png").arg(path).arg(
id).toStdString(), data.depthRaw().type()==CV_32FC1?
util2d::cvtDepthFromFloat(data.depthRaw()):data.depthRaw()))
1588 UWARN(
"Failed saving \"%s\"", QString(
"%1/depth/%2.png").arg(path).arg(
id).toStdString().c_str());
1589 UINFO(QString(
"Saved rgb/%1.%2 and depth/%1.png").arg(
id).arg(ext).toStdString().c_str());
1593 if(!cv::imwrite(QString(
"%1/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.imageRaw()))
1594 UWARN(
"Failed saving \"%s\"", QString(
"%1/%2.%3").arg(path).arg(
id).arg(ext).toStdString().c_str());
1596 UINFO(QString(
"Saved %1.%2").arg(
id).arg(ext).toStdString().c_str());
1601 UERROR(
"Cannot save calibration file, database name is empty!");
1603 else if(data.cameraModels().size() >= 1 && data.cameraModels().front().isValidForProjection())
1605 for(
size_t i=0; i<data.cameraModels().size(); ++i)
1607 std::string cameraName =
id.toStdString();
1608 if(data.cameraModels().size()>1)
1613 data.imageRaw().size(),
1614 data.cameraModels()[i].K(),
1615 data.cameraModels()[i].D(),
1616 data.cameraModels()[i].R(),
1617 data.cameraModels()[i].P(),
1618 data.cameraModels()[i].localTransform());
1619 std::string dirPrefix =
"";
1620 if(!data.depthRaw().empty())
1622 dirPrefix =
"/calib";
1624 if(
model.save(path.toStdString()+dirPrefix))
1626 UINFO(
"Saved calibration \"%s\"", (path.toStdString()+dirPrefix+
"/"+cameraName+
".yaml").c_str());
1630 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/"+cameraName+
".yaml").c_str());
1638 QApplication::processEvents();
1648 QMessageBox::information(
this, tr(
"Exporting"), tr(
"%1 images exported!").arg(imagesExported));
1660 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1661 int progressSteps = 5;
1662 if(
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
1666 if(
ui_->textEdit_info->isVisible())
1670 if(
ui_->toolBox_statistics->isVisible())
1675 progressDialog->show();
1678 progressDialog->
appendText(tr(
"Loading all ids..."));
1679 QApplication::processEvents();
1681 QApplication::processEvents();
1683 UINFO(
"Loading all IDs...");
1686 ids_ = QList<int>::fromStdList(std::list<int>(ids.begin(), ids.end()));
1698 ui_->checkBox_wmState->setVisible(
false);
1699 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
1700 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
1701 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
1702 ui_->label_scale_title->setVisible(
false);
1703 ui_->label_rmse->setVisible(
false);
1704 ui_->label_rmse_title->setVisible(
false);
1705 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
1706 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
1707 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
1708 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
1709 ui_->menuEdit->setEnabled(
true);
1710 ui_->actionGenerate_3D_map_pcd->setEnabled(
true);
1711 ui_->actionExport->setEnabled(
true);
1712 ui_->actionExtract_images->setEnabled(
true);
1713 ui_->menuExport_poses->setEnabled(
false);
1714 ui_->menuExport_GPS->setEnabled(
false);
1715 ui_->actionPoses_KML->setEnabled(
false);
1716 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
1717 ui_->actionExport_saved_2D_map->setEnabled(
false);
1718 ui_->actionImport_2D_map->setEnabled(
false);
1719 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
1720 ui_->actionView_optimized_mesh->setEnabled(
false);
1721 ui_->actionExport_optimized_mesh->setEnabled(
false);
1727 ui_->toolBox_statistics->clear();
1728 ui_->label_optimizeFrom->setText(tr(
"Root"));
1730 progressDialog->
appendText(tr(
"%1 ids loaded!").arg(ids.size()));
1732 progressDialog->
appendText(tr(
"Loading all links..."));
1733 QApplication::processEvents();
1735 QApplication::processEvents();
1737 std::multimap<int, Link> unilinks;
1739 UDEBUG(
"%d total links loaded", (
int)unilinks.size());
1741 std::multimap<int, Link> links;
1742 for(std::multimap<int, Link>::iterator iter=unilinks.begin(); iter!=unilinks.end(); ++iter)
1744 links.insert(*iter);
1745 if(
graph::findLink(unilinks, iter->second.to(), iter->second.from(),
false) == unilinks.end())
1747 links.insert(std::make_pair(iter->second.to(), iter->second.inverse()));
1751 progressDialog->
appendText(tr(
"%1 links loaded!").arg(unilinks.size()));
1753 progressDialog->
appendText(
"Loading Working Memory state...");
1754 QApplication::processEvents();
1756 QApplication::processEvents();
1762 double previousStamp = 0.0;
1766 progressDialog->
appendText(
"Loading Working Memory state... done!");
1768 progressDialog->
appendText(
"Loading info for all nodes...");
1769 QApplication::processEvents();
1771 QApplication::processEvents();
1773 int lastValidNodeId = 0;
1774 for(
int i=0; i<
ids_.size(); ++i)
1783 std::vector<float> v;
1791 for(std::multimap<int, Link>::iterator iter=links.find(
ids_[i]); iter!=links.end() && iter->first==
ids_[i]; ++iter)
1796 lastValidNodeId =
ids_[i];
1800 if(wmStates.find(
ids_[i]) != wmStates.end())
1803 ui_->checkBox_wmState->setVisible(
true);
1807 ui_->checkBox_ignoreIntermediateNodes->setVisible(
true);
1808 ui_->label_ignoreINtermediateNdoes->setVisible(
true);
1819 if(previousStamp > 0.0 && s > 0.0)
1833 for(std::multimap<int, Link>::iterator jter=links.find(
ids_[i]); jter!=links.end() && jter->first ==
ids_[i]; ++jter)
1840 std::multimap<int, Link>::iterator invertedLinkIter =
graph::findLink(links, jter->second.to(), jter->second.from(),
false, jter->second.type());
1841 if( jter->second.isValid() &&
1842 ids.find(jter->second.from()) != ids.end() &&
1843 (ids.find(jter->second.to()) != ids.end() || jter->second.to()<0) &&
1845 invertedLinkIter != links.end() &&
1849 if(jter->second.userDataCompressed().cols == 0 &&
1850 invertedLinkIter->second.userDataCompressed().cols != 0)
1852 links_.insert(std::make_pair(invertedLinkIter->second.from(), invertedLinkIter->second));
1856 links_.insert(std::make_pair(
ids_[i], jter->second));
1866 if(gps.
stamp() > 0.0)
1870 cv::Point3f p(0.0
f,0.0
f,0.0
f);
1882 progressDialog->
appendText(
"Loading info for all nodes... done!");
1884 progressDialog->
appendText(
"Loading optimized poses and maps...");
1885 QApplication::processEvents();
1887 QApplication::processEvents();
1891 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
true);
1892 ui_->doubleSpinBox_optimizationScale->setVisible(
true);
1893 ui_->label_scale_title->setVisible(
true);
1894 ui_->label_rmse->setVisible(
true);
1895 ui_->label_rmse_title->setVisible(
true);
1896 ui_->label_alignPosesWithGroundTruth->setVisible(
true);
1900 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with ground truth"));
1901 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
true);
1902 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
true);
1906 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with GPS"));
1911 ui_->menuExport_GPS->setEnabled(
true);
1912 ui_->actionPoses_KML->setEnabled(
true);
1915 float xMin, yMin, cellSize;
1917 ui_->actionEdit_optimized_2D_map->setEnabled(hasMap);
1918 ui_->actionExport_saved_2D_map->setEnabled(hasMap);
1919 ui_->actionImport_2D_map->setEnabled(hasMap);
1924 ui_->actionView_optimized_mesh->setEnabled(
true);
1925 ui_->actionExport_optimized_mesh->setEnabled(
true);
1930 progressDialog->
appendText(
"Loading optimized poses and maps... done!");
1932 QApplication::processEvents();
1934 QApplication::processEvents();
1936 if(
ids_.size() &&
ui_->toolBox_statistics->isVisible())
1938 progressDialog->
appendText(
"Loading statistics...");
1939 QApplication::processEvents();
1941 QApplication::processEvents();
1943 UINFO(
"Update statistics...");
1946 progressDialog->
appendText(
"Loading statistics... done!");
1948 QApplication::processEvents();
1950 QApplication::processEvents();
1954 ui_->textEdit_info->clear();
1955 if(
ui_->textEdit_info->isVisible())
1957 progressDialog->
appendText(
"Update database info...");
1958 QApplication::processEvents();
1960 QApplication::processEvents();
1964 progressDialog->
appendText(
"Update database info... done!");
1966 QApplication::processEvents();
1968 QApplication::processEvents();
1975 bool nullPoses =
odomPoses_.begin()->second.isNull();
1978 if((!iter->second.isNull() && nullPoses) ||
1979 (iter->second.isNull() && !nullPoses))
1981 if(iter->second.isNull())
1983 UWARN(
"Pose %d is null!", iter->first);
1985 UWARN(
"Mixed valid and null poses! Ignoring graph...");
2000 ui_->spinBox_optimizationsFrom->setValue(
odomPoses_.begin()->first);
2001 ui_->label_optimizeFrom->setText(tr(
"Root [%1, %2]").arg(
odomPoses_.begin()->first).arg(
odomPoses_.rbegin()->first));
2005 if(lastValidNodeId>0)
2010 std::map<int, rtabmap::Transform> posesOut;
2011 std::multimap<int, rtabmap::Link> linksOut;
2012 UINFO(
"Get connected graph from %d (%d poses, %d links)", lastValidNodeId, (
int)
odomPoses_.size(), (int)
links_.size());
2020 if(!posesOut.empty())
2022 bool optimizeFromGraphEnd = Parameters::defaultRGBDOptimizeFromGraphEnd();
2024 if(optimizeFromGraphEnd)
2026 ui_->spinBox_optimizationsFrom->setValue(posesOut.rbegin()->first);
2030 ui_->spinBox_optimizationsFrom->setValue(posesOut.lower_bound(1)->first);
2043 for(std::multimap<int, rtabmap::Link>::iterator iter =
links_.begin(); iter!=
links_.end(); ++iter)
2045 if(!iter->second.transform().isNull())
2052 else if(iter->second.from()!=iter->second.to())
2059 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
2065 ui_->horizontalSlider_A->setMinimum(0);
2066 ui_->horizontalSlider_B->setMinimum(0);
2067 ui_->horizontalSlider_A->setMaximum(
ids_.size()-1);
2068 ui_->horizontalSlider_B->setMaximum(
ids_.size()-1);
2069 ui_->horizontalSlider_A->setEnabled(
true);
2070 ui_->horizontalSlider_B->setEnabled(
true);
2071 ui_->horizontalSlider_A->setSliderPosition(0);
2072 ui_->horizontalSlider_B->setSliderPosition(0);
2078 ui_->horizontalSlider_A->setEnabled(
false);
2079 ui_->horizontalSlider_B->setEnabled(
false);
2080 ui_->label_idA->setText(
"NaN");
2081 ui_->label_idB->setText(
"NaN");
2086 ui_->horizontalSlider_neighbors->setMinimum(0);
2088 ui_->horizontalSlider_neighbors->setEnabled(
true);
2089 ui_->horizontalSlider_neighbors->setSliderPosition(0);
2093 ui_->horizontalSlider_neighbors->setEnabled(
false);
2099 if(
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
2101 progressDialog->
appendText(
"Updating Graph View...");
2102 QApplication::processEvents();
2104 QApplication::processEvents();
2108 progressDialog->
appendText(
"Updating Graph View... done!");
2110 QApplication::processEvents();
2112 QApplication::processEvents();
2120 UINFO(
"Update database info...");
2123 if(
ui_->textEdit_info->toPlainText().isEmpty())
2130 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m (approx. as graph has been reduced)").arg(
infoTotalOdom_));
2134 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m").arg(
infoTotalOdom_));
2137 int lastWordIdId = 0;
2144 ids.insert(lastWordIdId);
2145 std::list<VisualWord *> vws;
2149 wordsDim = vws.front()->getDescriptor().cols;
2150 wordsType = vws.front()->getDescriptor().type();
2156 ui_->textEdit_info->append(tr(
"Total time:\t\t%1").arg(QDateTime::fromMSecsSinceEpoch(
infoTotalTime_*1000).toUTC().toString(
"hh:mm:ss.zzz")));
2159 ui_->textEdit_info->append(tr(
"Global graph:\t%1 poses and %2 links").arg(
odomPoses_.size()).arg(
links_.size()));
2161 ui_->textEdit_info->append(tr(
"GPS:\t%1 poses").arg(
gpsValues_.size()));
2162 ui_->textEdit_info->append(
"");
2166 ui_->textEdit_info->append(tr(
"Database size:\t%1 %2").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes"));
2169 ui_->textEdit_info->append(tr(
"Nodes size:\t\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2172 ui_->textEdit_info->append(tr(
"Links size:\t\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2175 ui_->textEdit_info->append(tr(
"RGB Images size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2178 ui_->textEdit_info->append(tr(
"Depth Images size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2181 ui_->textEdit_info->append(tr(
"Calibrations size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2184 ui_->textEdit_info->append(tr(
"Grids size:\t\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2187 ui_->textEdit_info->append(tr(
"Scans size:\t\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2190 ui_->textEdit_info->append(tr(
"User data size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2193 ui_->textEdit_info->append(tr(
"Dictionary size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2196 ui_->textEdit_info->append(tr(
"Features size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2199 ui_->textEdit_info->append(tr(
"Statistics size:\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2200 mem = dbSize - total;
2201 ui_->textEdit_info->append(tr(
"Other (indexing, unused):\t%1 %2\t%3%").arg(mem>1000000?mem/1000000:mem>1000?mem/1000:mem).arg(mem>1000000?
"MB":mem>1000?
"KB":
"Bytes").arg(dbSize>0?QString::number(
double(mem)/
double(dbSize)*100.0,
'f', 2 ):
"0"));
2202 ui_->textEdit_info->append(
"");
2203 std::set<int> idsWithoutBad;
2205 int infoBadcountInLTM = 0;
2206 int infoBadCountInGraph = 0;
2207 for(
int i=0; i<
ids_.size(); ++i)
2209 if(idsWithoutBad.find(
ids_[i]) == idsWithoutBad.end())
2211 ++infoBadcountInLTM;
2214 ++infoBadCountInGraph;
2218 ui_->textEdit_info->append(tr(
"%1 bad signatures in LTM").arg(infoBadcountInLTM));
2219 ui_->textEdit_info->append(tr(
"%1 bad signatures in the global graph").arg(infoBadCountInGraph));
2220 ui_->textEdit_info->append(
"");
2222 QFontMetrics metrics(
ui_->textEdit_info->font());
2223 int tabW =
ui_->textEdit_info->tabStopWidth();
2224 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
2226 int strW = metrics.width(QString(iter->first.c_str()) +
"=");
2227 ui_->textEdit_info->append(tr(
"%1=%2%3")
2228 .arg(iter->first.c_str())
2229 .arg(strW < tabW?
"\t\t\t\t":strW < tabW*2?
"\t\t\t":strW < tabW*3?
"\t\t":
"\t")
2230 .arg(iter->second.c_str()));
2234 ui_->textEdit_info->moveCursor(QTextCursor::Start) ;
2235 ui_->textEdit_info->ensureCursorVisible() ;
2240 ui_->textEdit_info->clear();
2249 ui_->toolBox_statistics->clear();
2250 double firstStamp = 0.0;
2253 std::map<std::string, std::pair<std::vector<qreal>, std::vector<qreal> > > allData;
2254 std::map<std::string, int > allDataOi;
2256 for(std::map<
int, std::pair<std::map<std::string, float>,
double> >::iterator jter=allStats.begin(); jter!=allStats.end(); ++jter)
2258 double stamp=jter->second.second;
2259 std::map<std::string, float> & statistics = jter->second.first;
2264 for(std::map<std::string, float>::iterator iter=statistics.begin(); iter!=statistics.end(); ++iter)
2266 if(allData.find(iter->first) == allData.end())
2269 allData.insert(std::make_pair(iter->first, std::make_pair(std::vector<qreal>(allStats.size(), 0.0f), std::vector<qreal>(allStats.size(), 0.0f) )));
2270 allDataOi.insert(std::make_pair(iter->first, 0));
2273 int & oi = allDataOi.at(iter->first);
2274 allData.at(iter->first).first[oi] =
ui_->checkBox_timeStats->isChecked()?qreal(stamp-firstStamp):jter->first;
2275 allData.at(iter->first).second[oi] = iter->second;
2280 for(std::map<std::string, std::pair<std::vector<qreal>, std::vector<qreal> > >::iterator iter=allData.begin(); iter!=allData.end(); ++iter)
2282 int oi = allDataOi.at(iter->first);
2283 iter->second.first.resize(oi);
2284 iter->second.second.resize(oi);
2285 ui_->toolBox_statistics->updateStat(iter->first.c_str(), iter->second.first, iter->second.second,
true);
2293 QColor c = QColorDialog::getColor(
ui_->lineEdit_obstacleColor->text(),
this);
2296 ui_->lineEdit_obstacleColor->setText(c.name());
2301 QColor c = QColorDialog::getColor(
ui_->lineEdit_groundColor->text(),
this);
2304 ui_->lineEdit_groundColor->setText(c.name());
2309 QColor c = QColorDialog::getColor(
ui_->lineEdit_emptyColor->text(),
this);
2312 ui_->lineEdit_emptyColor->setText(c.name());
2380 types.push_back(
"Map's graph (see Graph View)");
2381 types.push_back(
"Odometry");
2384 types.push_back(
"Ground Truth");
2387 QString type = QInputDialog::getItem(
this, tr(
"Which poses?"), tr(
"Poses:"), types, 0,
false, &ok);
2392 bool odometry = type.compare(
"Odometry") == 0;
2393 bool groundTruth = type.compare(
"Ground Truth") == 0;
2397 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No ground truth poses in database?!"));
2400 else if(!odometry &&
graphes_.empty())
2403 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
2405 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No graph in database?!"));
2411 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No odometry poses in database?!"));
2419 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No GPS in database?!"));
2423 std::map<int, rtabmap::Transform> graph;
2439 pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
2440 cloud1.resize(graph.size());
2441 cloud2.resize(graph.size());
2444 for(std::map<int, Transform>::const_iterator iter=
gpsPoses_.begin(); iter!=
gpsPoses_.end(); ++iter)
2446 std::map<int, Transform>::iterator iter2 = graph.find(iter->first);
2447 if(iter2!=graph.end())
2451 idFirst = iter->first;
2453 cloud1[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
2454 cloud2[oi++] = pcl::PointXYZ(iter2->second.x(), iter2->second.y(), iter2->second.z());
2468 t =
gpsPoses_.at(idFirst) * graph.at(idFirst).inverse();
2471 std::map<int, GPS> values;
2473 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
2475 iter->second = t * iter->second;
2478 coord.
fromENU_WGS84(cv::Point3d(iter->second.x(), iter->second.y(), iter->second.z()), origin);
2479 double bearing = -(iter->second.theta()*180.0/
M_PI-90.0);
2490 std::vector<float> v;
2497 QString output =
pathDatabase_ + QDir::separator() +
"poses.kml";
2498 QString path = QFileDialog::getSaveFileName(
2502 tr(
"Google Earth file (*.kml)"));
2506 bool saved =
graph::exportGPS(path.toStdString(), values,
ui_->graphViewer->getNodeColor().rgba());
2510 QMessageBox::information(
this,
2511 tr(
"Export poses..."),
2512 tr(
"GPS coordinates saved to \"%1\".")
2517 QMessageBox::information(
this,
2518 tr(
"Export poses..."),
2519 tr(
"Failed to save GPS coordinates to \"%1\"!")
2527 std::map<int, Transform> optimizedPoses;
2543 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked())
2546 if(refPoses.empty())
2554 float translational_rmse = 0.0f;
2555 float translational_mean = 0.0f;
2556 float translational_median = 0.0f;
2557 float translational_std = 0.0f;
2558 float translational_min = 0.0f;
2559 float translational_max = 0.0f;
2560 float rotational_rmse = 0.0f;
2561 float rotational_mean = 0.0f;
2562 float rotational_median = 0.0f;
2563 float rotational_std = 0.0f;
2564 float rotational_min = 0.0f;
2565 float rotational_max = 0.0f;
2572 translational_median,
2583 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
2585 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2587 iter->second = gtToMap * iter->second;
2594 if(optimizedPoses.size())
2596 std::map<int, Transform> localTransforms;
2598 items.push_back(
"Robot (base frame)");
2599 items.push_back(
"Camera");
2600 items.push_back(
"Scan");
2602 QString item = QInputDialog::getItem(
this, tr(
"Export Poses"), tr(
"Frame: "), items, 0,
false, &ok);
2603 if(!ok || item.isEmpty())
2607 if(item.compare(
"Robot (base frame)") != 0)
2609 bool cameraFrame = item.compare(
"Camera") == 0;
2610 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2615 std::vector<CameraModel> models;
2616 std::vector<StereoCameraModel> stereoModels;
2619 if((models.size() == 1 &&
2620 !models.at(0).localTransform().isNull()))
2622 localTransform = models.at(0).localTransform();
2624 else if(stereoModels.size() == 1 &&
2625 !stereoModels[0].localTransform().isNull())
2627 localTransform = stereoModels[0].localTransform();
2629 else if(models.size()>1)
2631 UWARN(
"Multi-camera is not supported (node %d)", iter->first);
2635 UWARN(
"Calibration not valid for node %d", iter->first);
2640 UWARN(
"Missing calibration for node %d", iter->first);
2652 UWARN(
"Missing scan info for node %d", iter->first);
2656 if(!localTransform.
isNull())
2658 localTransforms.insert(std::make_pair(iter->first, localTransform));
2661 if(localTransforms.empty())
2663 QMessageBox::warning(
this,
2665 tr(
"Could not find any \"%1\" frame, exporting in Robot frame instead.").arg(item));
2669 std::map<int, Transform> poses;
2670 std::multimap<int, Link> links;
2671 if(localTransforms.empty())
2673 poses = optimizedPoses;
2682 for(std::map<int, Transform>::iterator iter=localTransforms.begin(); iter!=localTransforms.end(); ++iter)
2684 poses.insert(std::make_pair(iter->first, optimizedPoses.at(iter->first) * iter->second));
2692 std::multimap<int, Link>::iterator inserted = links.insert(*iter);
2693 int from = iter->second.from();
2694 int to = iter->second.to();
2695 inserted->second.setTransform(localTransforms.at(from).inverse()*iter->second.transform()*localTransforms.at(to));
2701 if(format != 4 && !poses.empty() && poses.begin()->first<0)
2703 UWARN(
"Only g2o format (4) can export landmarks, they are ignored with format %d", format);
2704 std::map<int, Transform>::iterator iter=poses.begin();
2705 while(iter!=poses.end() && iter->first < 0)
2707 poses.erase(iter++);
2711 std::map<int, double> stamps;
2712 if(format == 1 || format == 10 || format == 11)
2714 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
2721 std::vector<float> v;
2726 stamps.insert(std::make_pair(iter->first, stamp));
2729 if(stamps.size()!=poses.size())
2731 QMessageBox::warning(
this, tr(
"Export poses..."), tr(
"Poses (%1) and stamps (%2) have not the same size! Cannot export in RGB-D SLAM format.")
2732 .arg(poses.size()).arg(stamps.size()));
2737 QString output =
pathDatabase_ + QDir::separator() + (format==3?
"toro%1.graph":format==4?
"poses%1.g2o":
"poses%1.txt");
2738 QString suffix = odometry?
"_odom":groundTruth?
"_gt":
"";
2739 output = output.arg(suffix);
2741 QString path = QFileDialog::getSaveFileName(
2745 format == 3?tr(
"TORO file (*.graph)"):format==4?tr(
"g2o file (*.g2o)"):tr(
"Text file (*.txt)"));
2749 if(QFileInfo(path).suffix() ==
"")
2765 bool saved =
graph::exportPoses(path.toStdString(), format, poses, links, stamps,
ui_->parameters_toolbox->getParameters());
2769 QMessageBox::information(
this,
2770 tr(
"Export poses..."),
2771 tr(
"%1 saved to \"%2\".")
2772 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"Poses")
2777 QMessageBox::information(
this,
2778 tr(
"Export poses..."),
2779 tr(
"Failed to save %1 to \"%2\"!")
2780 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"poses")
2800 QString output =
pathDatabase_ + QDir::separator() + (format==0?
"gps.txt":
"gps.kml");
2801 QString path = QFileDialog::getSaveFileName(
2805 format==0?tr(
"Raw format (*.txt)"):tr(
"Google Earth file (*.kml)"));
2813 QMessageBox::information(
this,
2814 tr(
"Export poses..."),
2815 tr(
"GPS coordinates saved to \"%1\".")
2820 QMessageBox::information(
this,
2821 tr(
"Export poses..."),
2822 tr(
"Failed to save GPS coordinates to \"%1\"!")
2833 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2839 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
2840 tr(
"The database has too old version (%1) to saved " 2847 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
2848 tr(
"The database has modified links and/or modified local " 2849 "occupancy grids, the 2D optimized map cannot be modified."));
2853 float xMin, yMin, cellSize;
2857 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2862 cv::Mat map8UFlip, map8URotated;
2863 cv::flip(map8U, map8UFlip, 0);
2864 if(!
ui_->graphViewer->isOrientationENU())
2867 cv::transpose(map8UFlip, map8URotated);
2868 cv::flip(map8URotated, map8URotated, 0);
2872 map8URotated = map8UFlip;
2881 if(!
ui_->graphViewer->isOrientationENU())
2884 cv::transpose(mapModified, map8URotated);
2885 cv::flip(map8URotated, map8URotated, 1);
2889 map8URotated = mapModified;
2891 cv::flip(map8URotated, map8UFlip, 0);
2893 UASSERT(map8UFlip.type() == map8U.type());
2894 UASSERT(map8UFlip.cols == map8U.cols);
2895 UASSERT(map8UFlip.rows == map8U.rows);
2902 QMessageBox::information(
this, tr(
"Edit 2D map"), tr(
"Map updated!"));
2905 int cropRadius =
ui_->spinBox_cropRadius->value();
2906 QMessageBox::StandardButton b = QMessageBox::question(
this,
2907 tr(
"Crop empty space"),
2908 tr(
"Do you want to clear empty space from local occupancy grids and laser scans?\n\n" 2910 " * If the map needs to be regenerated in the future (e.g., when we re-use the map in SLAM mode), removed obstacles won't reappear.\n" 2911 " * The cropped laser scans will be also used for localization, so if dynamic obstacles have been removed, localization won't try to match them anymore.\n\n" 2913 " * Cropping the laser scans cannot be reverted after the viewer is closed and changes have been saved.\n\n" 2915 " Crop radius = %1 pixels\n\n" 2916 "Press \"Yes\" to filter only grids.\n" 2917 "Press \"Yes to All\" to filter both grids and laser scans.\n").arg(cropRadius),
2918 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No, QMessageBox::No);
2919 if(b == QMessageBox::Yes || b == QMessageBox::YesToAll)
2927 progressDialog.show();
2929 progressDialog.
appendText(QString(
"Cropping empty space... %1 scans to filter").arg(poses.size()));
2930 progressDialog.setMinimumWidth(800);
2931 QApplication::processEvents();
2933 UINFO(
"Cropping empty space... poses=%d cropRadius=%d", poses.size(), cropRadius);
2935 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end() && !progressDialog.
isCanceled(); ++iter)
2939 cv::Mat gridObstacles;
2946 data.
uncompressData(0,0,&scan,0,&gridGround,&gridObstacles,&gridEmpty);
2952 if(!gridObstacles.empty())
2954 cv::Mat filtered = cv::Mat(1, gridObstacles.cols, gridObstacles.type());
2956 for(
int i=0; i<gridObstacles.cols; ++i)
2958 const float * ptr = gridObstacles.ptr<
float>(0, i);
2959 cv::Point3f pt(ptr[0], ptr[1], gridObstacles.channels()==2?0:ptr[2]);
2962 int x = int((pt.x - xMin) / cellSize + 0.5f);
2963 int y = int((pt.y - yMin) / cellSize + 0.5f);
2965 if(x>=0 && x<map8S.cols &&
2966 y>=0 && y<map8S.rows)
2968 bool obstacleDetected =
false;
2970 for(
int j=-cropRadius; j<=cropRadius && !obstacleDetected; ++j)
2972 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
2974 if(x+j>=0 && x+j<map8S.cols &&
2975 y+k>=0 && y+k<map8S.rows &&
2976 map8S.at<
unsigned char>(y+k,x+j) == 100)
2978 obstacleDetected =
true;
2983 if(map8S.at<
unsigned char>(y,x) != 0 || obstacleDetected)
2992 if(oi != gridObstacles.cols)
2994 progressDialog.
appendText(QString(
"Grid %1 filtered %2 pts -> %3 pts").arg(iter->first).arg(gridObstacles.cols).arg(oi));
2995 UINFO(
"Grid %d filtered %d -> %d", iter->first, gridObstacles.cols, oi);
2998 std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> value;
3005 value.first.first = gridGround;
3006 value.second = gridEmpty;
3009 value.first.second = cv::Mat(filtered,
cv::Range::all(), cv::Range(0, oi));
3014 if(b == QMessageBox::YesToAll && !scan.
isEmpty())
3018 cv::Mat filtered = cv::Mat(1, scan.
size(), scan.
dataType());
3020 for(
int i=0; i<scan.
size(); ++i)
3022 const float * ptr = scan.
data().ptr<
float>(0, i);
3023 cv::Point3f pt(ptr[0], ptr[1], scan.
is2d()?0:ptr[2]);
3026 int x = int((pt.x - xMin) / cellSize + 0.5f);
3027 int y = int((pt.y - yMin) / cellSize + 0.5f);
3029 if(x>=0 && x<map8S.cols &&
3030 y>=0 && y<map8S.rows)
3032 bool obstacleDetected =
false;
3034 for(
int j=-cropRadius; j<=cropRadius && !obstacleDetected; ++j)
3036 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
3038 if(x+j>=0 && x+j<map8S.cols &&
3039 y+k>=0 && y+k<map8S.rows &&
3040 map8S.at<
unsigned char>(y+k,x+j) == 100)
3042 obstacleDetected =
true;
3047 if(map8S.at<
unsigned char>(y,x) != 0 || obstacleDetected)
3056 if(oi != scan.
size())
3058 progressDialog.
appendText(QString(
"Scan %1 filtered %2 pts -> %3 pts").arg(iter->first).arg(scan.
size()).arg(oi));
3059 UINFO(
"Scan %d filtered %d -> %d", iter->first, scan.
size(), oi);
3089 QApplication::processEvents();
3109 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
3113 float xMin, yMin, cellSize;
3117 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"The database doesn't contain a saved 2D map."));
3123 QString path = QFileDialog::getSaveFileName(
3131 if(QFileInfo(path).suffix() ==
"")
3135 cv::imwrite(path.toStdString(), map8U);
3136 QMessageBox::information(
this, tr(
"Export 2D map"), tr(
"Exported %1!").arg(path));
3145 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
3151 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
3152 tr(
"The database has too old version (%1) to saved " 3159 QMessageBox::warning(
this, tr(
"Cannot import 2D map"),
3160 tr(
"The database has modified links and/or modified local " 3161 "occupancy grids, the 2D optimized map cannot be modified."));
3165 float xMin, yMin, cellSize;
3169 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"The database doesn't contain a saved 2D map."));
3173 QString path = QFileDialog::getOpenFileName(
3180 cv::Mat map8U = cv::imread(path.toStdString(), cv::IMREAD_UNCHANGED);
3183 if(mapOrg.cols == map.cols && mapOrg.rows == map8U.rows)
3186 QMessageBox::information(
this, tr(
"Import 2D map"), tr(
"Imported %1!").arg(path));
3190 QMessageBox::warning(
this, tr(
"Import 2D map"), tr(
"Cannot import %1 as its size doesn't match the current saved map. Import 2D Map action should only be used to modify the map saved in the database.").arg(path));
3200 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
3206 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
3207 tr(
"The database has too old version (%1) to saved " 3214 QMessageBox::warning(
this, tr(
"Cannot import 2D map"),
3215 tr(
"The database has modified links and/or modified local " 3216 "occupancy grids, the 2D optimized map cannot be modified. Try " 3217 "closing the database and re-open it to save the changes."));
3223 QMessageBox::warning(
this, tr(
"Cannot regenerate 2D map"),
3224 tr(
"Graph is empty, make sure you opened the " 3225 "Graph View and there is a map shown."));
3230 #ifdef RTABMAP_OCTOMAP 3232 types.push_back(
"Default occupancy grid");
3233 types.push_back(
"From OctoMap projection");
3235 QString type = QInputDialog::getItem(
this, tr(
"Which type?"), tr(
"Type:"), types, 0,
false, &ok);
3243 UINFO(
"Update local maps list...");
3246 float gridCellSize = Parameters::defaultGridCellSize();
3247 Parameters::parse(
ui_->parameters_toolbox->getParameters(), Parameters::kGridCellSize(), gridCellSize);
3248 #ifdef RTABMAP_OCTOMAP 3249 if(type.compare(
"From OctoMap projection") == 0)
3253 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end(); ++iter)
3255 if(iter->second.first.first.channels() == 2 || iter->second.first.second.channels() == 2)
3257 QMessageBox::warning(
this, tr(
""),
3258 tr(
"Some local occupancy grids are 2D, but OctoMap requires 3D local " 3259 "occupancy grids. Select default occupancy grid or generate " 3260 "3D local occupancy grids (\"Grid/3D\" core parameter)."));
3263 octomap.addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second,
localMapsInfo_.at(iter->first).second);
3267 map =
octomap.createProjectionMap(xMin, yMin, gridCellSize, 0);
3273 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end(); ++iter)
3275 grid.
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
3278 map = grid.getMap(xMin, yMin);
3283 QMessageBox::information(
this, tr(
"Regenerate 2D map"), tr(
"Failed to renegerate the map, resulting map is empty!"));
3293 lastlocalizationPose =
graphes_.back().rbegin()->second;
3298 QMessageBox::information(
this, tr(
"Regenerate 2D map"), tr(
"Map regenerated!"));
3299 ui_->actionEdit_optimized_2D_map->setEnabled(
true);
3300 ui_->actionExport_saved_2D_map->setEnabled(
true);
3301 ui_->actionImport_2D_map->setEnabled(
true);
3309 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
3313 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3314 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 3315 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3317 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3321 if(cloudMat.empty())
3323 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
3328 viewer->setWindowFlags(Qt::Window);
3329 viewer->setAttribute(Qt::WA_DeleteOnClose);
3331 if(!textures.empty())
3335 viewer->setWindowTitle(
"Optimized Textured Mesh");
3339 else if(polygons.size() == 1)
3342 viewer->setWindowTitle(
"Optimized Mesh");
3350 viewer->setWindowTitle(
"Optimized Point Cloud");
3361 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
3365 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3366 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 3367 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3369 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3373 if(cloudMat.empty())
3375 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
3381 if(!textures.empty())
3384 QString path = QFileDialog::getSaveFileName(
3388 tr(
"Mesh (*.obj)"));
3392 if(QFileInfo(path).suffix() ==
"")
3396 QString baseName = QFileInfo(path).baseName();
3397 if(mesh->tex_materials.size() == 1)
3399 mesh->tex_materials.at(0).tex_file = baseName.toStdString() +
".png";
3400 cv::imwrite((QFileInfo(path).absoluteDir().absolutePath()+QDir::separator()+baseName).toStdString() +
".png", textures);
3404 for(
unsigned int i=0; i<mesh->tex_materials.size(); ++i)
3406 mesh->tex_materials.at(i).tex_file = (baseName+QDir::separator()+QString::number(i)+
".png").toStdString();
3407 UASSERT((i+1)*textures.rows <= (
unsigned int)textures.cols);
3408 cv::imwrite((QFileInfo(path).absoluteDir().absolutePath()+QDir::separator()+baseName+QDir::separator()+QString::number(i)+
".png").toStdString(), textures(
cv::Range::all(), cv::Range(i*textures.rows, (i+1)*textures.rows)));
3411 pcl::io::saveOBJFile(path.toStdString(), *mesh);
3413 QMessageBox::information(
this, tr(
"Export Textured Mesh"), tr(
"Exported %1!").arg(path));
3416 else if(polygons.size() == 1)
3419 QString path = QFileDialog::getSaveFileName(
3423 tr(
"Mesh (*.ply)"));
3427 if(QFileInfo(path).suffix() ==
"")
3431 pcl::io::savePLYFileBinary(path.toStdString(), *mesh);
3432 QMessageBox::information(
this, tr(
"Export Mesh"), tr(
"Exported %1!").arg(path));
3437 QString path = QFileDialog::getSaveFileName(
3441 tr(
"Point cloud data (*.ply *.pcd)"));
3445 if(QFileInfo(path).suffix() ==
"")
3449 bool success =
false;
3451 if(QFileInfo(path).suffix() ==
"pcd")
3453 success = pcl::io::savePCDFile(path.toStdString(), *cloud) == 0;
3457 success = pcl::io::savePLYFile(path.toStdString(), *cloud) == 0;
3461 QMessageBox::information(
this, tr(
"Export Point Cloud"), tr(
"Exported %1!").arg(path));
3465 QMessageBox::critical(
this, tr(
"Export Point Cloud"), tr(
"Failed exporting %1!").arg(path));
3476 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3483 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3485 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3490 std::map<int, Transform> optimizedPoses;
3499 if(
ui_->groupBox_posefiltering->isChecked())
3502 ui_->doubleSpinBox_posefilteringRadius->value(),
3503 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3509 if(optimizedPoses.size() > 0)
3515 std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> clouds;
3516 std::map<int, pcl::PolygonMesh::Ptr> meshes;
3517 std::map<int, pcl::TextureMesh::Ptr> textureMeshes;
3518 std::vector<std::map<int, pcl::PointXY> > textureVertexToPixels;
3524 QMap<int, Signature>(),
3525 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3526 std::map<int, LaserScan>(),
3528 ui_->parameters_toolbox->getParameters(),
3532 textureVertexToPixels))
3534 if(textureMeshes.size())
3538 cv::Mat globalTextures;
3539 pcl::TextureMeshPtr textureMesh = textureMeshes.at(0);
3540 if(textureMesh->tex_materials.size()>1)
3544 std::map<int, cv::Mat>(),
3545 std::map<
int, std::vector<CameraModel> >(),
3550 textureVertexToPixels,
3563 textureMesh->tex_coordinates,
3565 QMessageBox::information(
this, tr(
"Update Optimized Textured Mesh"), tr(
"Updated!"));
3566 ui_->actionView_optimized_mesh->setEnabled(
true);
3567 ui_->actionExport_optimized_mesh->setEnabled(
true);
3570 else if(meshes.size())
3573 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(1);
3576 QMessageBox::information(
this, tr(
"Update Optimized Mesh"), tr(
"Updated!"));
3577 ui_->actionView_optimized_mesh->setEnabled(
true);
3578 ui_->actionExport_optimized_mesh->setEnabled(
true);
3581 else if(clouds.size())
3585 QMessageBox::information(
this, tr(
"Update Optimized PointCloud"), tr(
"Updated!"));
3586 ui_->actionView_optimized_mesh->setEnabled(
true);
3587 ui_->actionExport_optimized_mesh->setEnabled(
true);
3592 QMessageBox::critical(
this, tr(
"Update Optimized Mesh"), tr(
"Nothing to save!"));
3599 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3607 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"A database must must loaded first...\nUse File->Open database."));
3611 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph.dot", tr(
"Graphiz file (*.dot)"));
3622 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3626 int id = QInputDialog::getInt(
this, tr(
"Around which location?"), tr(
"Location ID"),
ids_.first(),
ids_.first(),
ids_.last(), 1, &ok);
3630 int margin = QInputDialog::getInt(
this, tr(
"Depth around the location?"), tr(
"Margin"), 4, 1, 100, 1, &ok);
3633 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph" + QString::number(
id) +
".dot", tr(
"Graphiz file (*.dot)"));
3634 if(!path.isEmpty() &&
id>0)
3636 std::map<int, int> ids;
3637 std::list<int> curentMarginList;
3638 std::set<int> currentMargin;
3639 std::set<int> nextMargin;
3640 nextMargin.insert(
id);
3642 while((margin == 0 || m < margin) && nextMargin.size())
3644 curentMarginList = std::list<int>(nextMargin.rbegin(), nextMargin.rend());
3647 for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
3649 if(ids.find(*jter) == ids.end())
3651 std::multimap<int, Link> links;
3652 ids.insert(std::pair<int, int>(*jter, m));
3658 for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
3666 nextMargin.insert(iter->first);
3671 if(currentMargin.insert(iter->first).second)
3673 curentMarginList.push_back(iter->first);
3685 ids.insert(std::pair<int,int>(
id, 0));
3686 std::set<int> idsSet;
3687 for(std::map<int, int>::iterator iter = ids.begin(); iter!=ids.end(); ++iter)
3689 idsSet.insert(idsSet.end(), iter->first);
3690 UINFO(
"Node %d", iter->first);
3692 UINFO(
"idsSet=%d", idsSet.size());
3697 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for signature %1.").arg(
id));
3713 progressDialog.show();
3717 plot->setWindowFlags(Qt::Window);
3718 plot->setWindowTitle(
"Local Occupancy Grid Generation Time (ms)");
3719 plot->setAttribute(Qt::WA_DeleteOnClose);
3725 plotCells->setWindowFlags(Qt::Window);
3726 plotCells->setWindowTitle(
"Occupancy Cells");
3727 plotCells->setAttribute(Qt::WA_DeleteOnClose);
3734 double decompressionTime = 0;
3735 double gridCreationTime = 0;
3737 for(
int i =0; i<
ids_.size() && !progressDialog.
isCanceled(); ++i)
3743 decompressionTime = timer.
ticks()*1000.0;
3750 std::vector<float> velocity;
3753 if(
dbDriver_->
getNodeInfo(data.
id(), odomPose, mapId, weight, label, stamp, groundTruth, velocity, gps, sensors))
3757 cv::Mat ground, obstacles, empty;
3758 cv::Point3f viewpoint;
3778 viewpoint.x += t.
x();
3779 viewpoint.y += t.
y();
3780 viewpoint.z += t.
z();
3800 viewpoint.x += t.
x();
3801 viewpoint.y += t.
y();
3802 viewpoint.z += t.
z();
3819 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
3822 gridCreationTime = timer.
ticks()*1000.0;
3825 msg = QString(
"Generated local occupancy grid map %1/%2").arg(i+1).arg((
int)
ids_.size());
3827 totalCurve->
addValue(
ids_.at(i), obstacles.cols+ground.cols+empty.cols);
3836 decompressionCurve->
addValue(
ids_.at(i), decompressionTime);
3837 gridCreationCurve->
addValue(
ids_.at(i), gridCreationTime);
3839 if(
ids_.size() < 50 || (i+1) % 25 == 0)
3841 QApplication::processEvents();
3862 if(
ids_.size() == 0)
3864 UWARN(
"ids_ is empty!");
3869 idsSet.insert(
ids_.at(
ui_->horizontalSlider_A->value()));
3870 idsSet.insert(
ids_.at(
ui_->horizontalSlider_B->value()));
3871 QList<int> ids = idsSet.toList();
3875 progressDialog.show();
3877 for(
int i =0; i<ids.size(); ++i)
3891 std::vector<float> velocity;
3894 if(
dbDriver_->
getNodeInfo(data.
id(), odomPose, mapId, weight, label, stamp, groundTruth, velocity, gps, sensors))
3898 cv::Mat ground, obstacles, empty;
3899 cv::Point3f viewpoint;
3918 viewpoint.x += t.
x();
3919 viewpoint.y += t.
y();
3920 viewpoint.z += t.
z();
3940 viewpoint.x += t.
x();
3941 viewpoint.y += t.
y();
3942 viewpoint.z += t.
z();
3959 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
3965 msg = QString(
"Generated local occupancy grid map %1/%2 (%3s)").arg(i+1).arg((
int)ids.size()).arg(time.
ticks());
3970 QApplication::processEvents();
3989 QMessageBox::warning(
this, tr(
"Cannot view 3D map"), tr(
"The database is empty..."));
3996 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3998 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
4003 std::map<int, Transform> optimizedPoses;
4012 if(
ui_->groupBox_posefiltering->isChecked())
4015 ui_->doubleSpinBox_posefilteringRadius->value(),
4016 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
4018 if(optimizedPoses.size() > 0)
4024 QMap<int, Signature>(),
4025 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
4026 std::map<int, LaserScan>(),
4028 ui_->parameters_toolbox->getParameters());
4032 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
4040 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
4047 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
4049 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
4054 std::map<int, Transform> optimizedPoses;
4063 if(
ui_->groupBox_posefiltering->isChecked())
4066 ui_->doubleSpinBox_posefilteringRadius->value(),
4067 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
4069 if(optimizedPoses.size() > 0)
4075 QMap<int, Signature>(),
4076 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
4077 std::map<int, LaserScan>(),
4079 ui_->parameters_toolbox->getParameters());
4083 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
4092 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
4094 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
4099 std::map<int, Transform> optimizedPoses =
graphes_.back();
4102 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
4105 progressDialog->setMinimumWidth(800);
4106 progressDialog->show();
4108 const ParametersMap & parameters =
ui_->parameters_toolbox->getParameters();
4109 bool loopCovLimited = Parameters::defaultRGBDLoopCovLimited();
4110 Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), loopCovLimited);
4116 int iterations =
ui_->spinBox_detectMore_iterations->value();
4119 std::multimap<int, int> checkedLoopClosures;
4120 std::pair<int, int> lastAdded(0,0);
4121 bool intraSession =
ui_->checkBox_detectMore_intraSession->isChecked();
4122 bool interSession =
ui_->checkBox_detectMore_interSession->isChecked();
4123 if(!interSession && !intraSession)
4125 QMessageBox::warning(
this, tr(
"Cannot detect more loop closures"), tr(
"Intra and inter session parameters are disabled! Enable one or both."));
4129 for(
int n=0; n<iterations; ++n)
4131 UINFO(
"iteration %d/%d", n+1, iterations);
4133 std::map<int, Transform>(optimizedPoses.upper_bound(0), optimizedPoses.end()),
4134 ui_->doubleSpinBox_detectMore_radius->value(),
4135 ui_->doubleSpinBox_detectMore_angle->value()*CV_PI/180.0);
4138 progressDialog->
appendText(tr(
"Looking for more loop closures, %1 clusters found.").arg(clusters.size()));
4139 QApplication::processEvents();
4145 std::set<int> addedLinks;
4147 for(std::multimap<int, int>::iterator iter=clusters.begin(); iter!= clusters.end() && !progressDialog->
isCanceled(); ++iter, ++i)
4149 int from = iter->first;
4150 int to = iter->second;
4153 from = iter->second;
4160 if((interSession && mapIdFrom != mapIdTo) ||
4161 (intraSession && mapIdFrom == mapIdTo))
4167 addedLinks.find(from) == addedLinks.end() &&
4168 addedLinks.find(to) == addedLinks.end())
4171 Transform delta = optimizedPoses.at(from).
inverse() * optimizedPoses.at(to);
4172 if(delta.
getNorm() <
ui_->doubleSpinBox_detectMore_radius->value() &&
4173 delta.
getNorm() >=
ui_->doubleSpinBox_detectMore_radiusMin->value())
4175 checkedLoopClosures.insert(std::make_pair(from, to));
4178 UINFO(
"Added new loop closure between %d and %d.", from, to);
4180 addedLinks.insert(from);
4181 addedLinks.insert(to);
4182 lastAdded.first = from;
4183 lastAdded.second = to;
4185 progressDialog->
appendText(tr(
"Detected loop closure %1->%2! (%3/%4)").arg(from).arg(to).arg(i+1).arg(clusters.size()));
4186 QApplication::processEvents();
4197 QApplication::processEvents();
4200 UINFO(
"Iteration %d/%d: added %d loop closures.", n+1, iterations, (
int)addedLinks.size()/2);
4201 progressDialog->
appendText(tr(
"Iteration %1/%2: Detected %3 loop closures!").arg(n+1).arg(iterations).arg(addedLinks.size()/2));
4202 if(addedLinks.size() == 0)
4221 UINFO(
"Total added %d loop closures.", added);
4223 progressDialog->
appendText(tr(
"Total new loop closures detected=%1").arg(added));
4233 QList<rtabmap::Link> links;
4245 QList<rtabmap::Link> links;
4261 double stddev = QInputDialog::getDouble(
this, tr(
"Linear error"), tr(
"Std deviation (m) 0=inf"), 0.01, 0.0, 9, 4, &ok);
4263 double linearVar = stddev*stddev;
4264 stddev = QInputDialog::getDouble(
this, tr(
"Angular error"), tr(
"Std deviation (deg) 0=inf"), 1, 0.0, 90, 2, &ok)*
M_PI/180.0;
4266 double angularVar = stddev*stddev;
4269 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
4272 progressDialog->setMinimumWidth(800);
4273 progressDialog->show();
4275 cv::Mat infMatrix = cv::Mat::eye(6,6,CV_64FC1);
4276 if(linearVar == 0.0)
4278 infMatrix(cv::Range(0,3), cv::Range(0,3)) /= 9999.9;
4282 infMatrix(cv::Range(0,3), cv::Range(0,3)) /= linearVar;
4284 if(angularVar == 0.0)
4286 infMatrix(cv::Range(3,6), cv::Range(3,6)) /= 9999.9;
4290 infMatrix(cv::Range(3,6), cv::Range(3,6)) /= angularVar;
4293 for(
int i=0; i<links.size(); ++i)
4295 int from = links[i].from();
4296 int to = links[i].to();
4301 UERROR(
"Not found link! (%d->%d)", from, to);
4311 bool updated =
false;
4312 std::multimap<int, Link>::iterator iter =
linksRefined_.find(currentLink.
from());
4315 if(iter->second.to() == currentLink.
to() &&
4316 iter->second.type() == currentLink.
type())
4318 iter->second = currentLink;
4329 progressDialog->
appendText(tr(
"Updated link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(links.size()));
4331 QApplication::processEvents();
4340 progressDialog->
appendText(
"Refining links finished!");
4357 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
4360 progressDialog->setMinimumWidth(800);
4361 progressDialog->show();
4363 for(
int i=0; i<links.size(); ++i)
4365 int from = links[i].from();
4366 int to = links[i].to();
4367 if(from > 0 && to > 0)
4370 progressDialog->
appendText(tr(
"Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(links.size()));
4374 progressDialog->
appendText(tr(
"Ignored link %1->%2 (landmark)").arg(from).arg(to));
4377 QApplication::processEvents();
4386 progressDialog->
appendText(
"Refining links finished!");
4392 if(QMessageBox::question(
this,
4393 tr(
"Reset all changes"),
4394 tr(
"You are about to reset all changes you've made so far, do you want to continue?"),
4395 QMessageBox::Yes | QMessageBox::No,
4396 QMessageBox::No) == QMessageBox::Yes)
4413 ui_->label_parentsA,
4414 ui_->label_childrenA,
4418 ui_->graphicsView_A,
4422 ui_->label_optposeA,
4426 ui_->label_gravityA,
4430 ui_->label_sensorsA,
4438 ui_->label_parentsB,
4439 ui_->label_childrenB,
4443 ui_->graphicsView_B,
4447 ui_->label_optposeB,
4451 ui_->label_gravityB,
4455 ui_->label_sensorsB,
4460 QLabel * labelIndex,
4461 QLabel * labelParents,
4462 QLabel * labelChildren,
4468 QLabel * labelMapId,
4470 QLabel * labelOptPose,
4471 QLabel * labelVelocity,
4472 QLabel * labelCalib,
4474 QLabel * labelGravity,
4475 QLabel * labelPrior,
4478 QLabel * labelSensors,
4484 labelIndex->setText(QString::number(value));
4485 labelParents->clear();
4486 labelChildren->clear();
4489 labelMapId->clear();
4491 labelOptPose->clear();
4492 labelVelocity->clear();
4494 labelCalib->clear();
4495 labelScan ->clear();
4496 labelGravity->clear();
4497 labelPrior->clear();
4500 labelSensors->clear();
4501 if(value >= 0 && value <
ids_.size())
4504 int id =
ids_.at(value);
4506 labelId->setText(QString::number(
id));
4526 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
4535 ui_->checkBox_showDisparityInsteadOfRight->isChecked())
4555 if(!imgDepth.empty())
4560 rect.setWidth(imgDepth.cols);
4561 rect.setHeight(imgDepth.rows);
4575 std::list<Signature*> signatures;
4578 if(signatures.size() && signatures.front()!=0 && !signatures.front()->getWordsKpts().empty())
4580 std::multimap<int, cv::KeyPoint> keypoints;
4581 for(std::map<int, int>::const_iterator iter=signatures.front()->getWords().begin(); iter!=signatures.front()->getWords().end(); ++iter)
4583 keypoints.insert(std::make_pair(iter->first, signatures.front()->getWordsKpts()[iter->second]));
4592 std::vector<float> v;
4598 label->setText(l.c_str());
4601 labelPose->setText(QString(
"%1xyz=(%2,%3,%4)\nrpy=(%5,%6,%7)").arg(odomPose.
isIdentity()?
"* ":
"").arg(x).arg(y).arg(z).arg(roll).arg(pitch).arg(yaw));
4606 labelOptPose->setText(
"<Not in optimized graph>");
4610 graphes_.back().find(
id)->second.getTranslationAndEulerAngles(x,y,z,roll, pitch,yaw);
4611 labelOptPose->setText(QString(
"xyz=(%1,%2,%3)\nrpy=(%4,%5,%6)").arg(x).arg(y).arg(z).arg(roll).arg(pitch).arg(yaw));
4616 stamp->setText(QString::number(s,
'f'));
4617 stamp->setToolTip(QDateTime::fromMSecsSinceEpoch(s*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
4621 labelVelocity->setText(QString(
"vx=%1 vy=%2 vz=%3 vroll=%4 vpitch=%5 vyaw=%6").arg(v[0]).arg(v[1]).arg(v[2]).arg(v[3]).arg(v[4]).arg(v[5]));
4624 std::multimap<int, Link> gravityLink;
4626 if(!gravityLink.empty())
4629 gravityLink.begin()->second.transform().getEulerAngles(roll, pitch, yaw);
4630 Eigen::Vector3d v =
Transform(0,0,0,roll,pitch,0).
toEigen3d() * -Eigen::Vector3d::UnitZ();
4631 labelGravity->setText(QString(
"x=%1 y=%2 z=%3").arg(v[0]).arg(v[1]).arg(v[2]));
4632 labelGravity->setToolTip(QString(
"roll=%1 pitch=%2 yaw=%3").arg(roll).arg(pitch).arg(yaw));
4635 std::multimap<int, Link> priorLink;
4637 if(!priorLink.empty())
4639 priorLink.begin()->second.transform().getTranslationAndEulerAngles(x,y,z,roll, pitch,yaw);
4640 labelPrior->setText(QString(
"xyz=(%1,%2,%3)\nrpy=(%4,%5,%6)").arg(x).arg(y).arg(z).arg(roll).arg(pitch).arg(yaw));
4641 std::stringstream out;
4642 out << priorLink.begin()->second.infMatrix().inv();
4643 labelPrior->setToolTip(QString(
"%1").arg(out.str().c_str()));
4648 labelGps->setText(QString(
"stamp=%1 longitude=%2 latitude=%3 altitude=%4m error=%5m bearing=%6deg").arg(QString::number(gps.
stamp(),
'f')).arg(gps.
longitude()).arg(gps.
latitude()).arg(gps.
altitude()).arg(gps.
error()).arg(gps.
bearing()));
4649 labelGps->setToolTip(QDateTime::fromMSecsSinceEpoch(gps.
stamp()*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
4653 labelGt->setText(QString(
"%1").arg(g.
prettyPrint().c_str()));
4659 for(EnvSensors::iterator iter=sensors.begin(); iter!=sensors.end(); ++iter)
4661 if(iter != sensors.begin())
4663 sensorsStr +=
" | ";
4664 tooltipStr +=
" | ";
4669 sensorsStr +=
uFormat(
"%.1f dbm", iter->second.value()).c_str();
4670 tooltipStr +=
"Wifi signal strength";
4674 sensorsStr +=
uFormat(
"%.1f \u00B0C", iter->second.value()).c_str();
4675 tooltipStr +=
"Ambient Temperature";
4679 sensorsStr +=
uFormat(
"%.1f hPa", iter->second.value()).c_str();
4680 tooltipStr +=
"Ambient Air Pressure";
4684 sensorsStr +=
uFormat(
"%.0f lx", iter->second.value()).c_str();
4685 tooltipStr +=
"Ambient Light";
4689 sensorsStr +=
uFormat(
"%.0f %%", iter->second.value()).c_str();
4690 tooltipStr +=
"Ambient Relative Humidity";
4694 sensorsStr +=
uFormat(
"%.2f", iter->second.value()).c_str();
4695 tooltipStr += QString(
"Type %1").arg((
int)iter->first);
4699 labelSensors->setText(sensorsStr);
4700 labelSensors->setToolTip(tooltipStr);
4704 std::stringstream calibrationDetails;
4709 labelCalib->setText(tr(
"%1 %2x%3 [%8x%9] fx=%4 fy=%5 cx=%6 cy=%7 T=%10 [%11 %12 %13 %14; %15 %16 %17 %18; %19 %20 %21 %22]")
4719 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str())
4726 labelCalib->setText(tr(
"%1 %2x%3 fx=%4 fy=%5 cx=%6 cy=%7 T=%8 [%9 %10 %11 %12; %13 %14 %15 %16; %17 %18 %19 %20]")
4734 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str())
4740 for(
unsigned int i=0; i<data.
cameraModels().size();++i)
4742 if(i!=0) calibrationDetails << std::endl;
4743 calibrationDetails <<
"Id: " << i <<
" Size=" << data.
cameraModels()[i].imageWidth() <<
"x" << data.
cameraModels()[i].imageHeight() << std::endl;
4744 if( data.
cameraModels()[i].K_raw().total()) calibrationDetails <<
"K=" << data.
cameraModels()[i].K_raw() << std::endl;
4745 if( data.
cameraModels()[i].D_raw().total()) calibrationDetails <<
"D=" << data.
cameraModels()[i].D_raw() << std::endl;
4754 labelCalib->setText(tr(
"%1x%2 fx=%3 fy=%4 cx=%5 cy=%6 baseline=%7m T=%8 [%9 %10 %11 %12; %13 %14 %15 %16; %17 %18 %19 %20]")
4769 calibrationDetails <<
"Id: " << i << std::endl;
4786 labelCalib->setToolTip(calibrationDetails.str().c_str());
4791 labelCalib->setText(
"NA");
4796 labelScan->setText(tr(
"Format=%1 Points=%2 [max=%3] Range=[%4->%5 m] Angle=[%6->%7 rad inc=%8] Has [Color=%9 2D=%10 Normals=%11 Intensity=%12] %13")
4820 ui_->graphicsView_stereo->clear();
4839 if(signatures.size() &&
ui_->checkBox_odomFrame_3dview->isChecked())
4842 (*signatures.begin())->getPose().getTranslationAndEulerAngles(x, y, z, roll, pitch, yaw);
4846 if(!gravityLink.empty() &&
ui_->checkBox_gravity_3dview->isChecked())
4848 Transform gravityT = gravityLink.begin()->second.transform();
4849 Eigen::Vector3f gravity(0,0,-1);
4852 gravityT = gravityT.
inverse();
4854 gravity = (gravityT.
rotation()*(pose).
rotation().inverse()).toEigen3f()*gravity;
4855 cloudViewer_->
addOrUpdateLine(
"gravity", pose, (pose).
translation()*
Transform(gravity[0], gravity[1], gravity[2], 0, 0, 0)*pose.
rotation().
inverse(), Qt::yellow,
true,
false);
4864 if(
ui_->checkBox_showScan->isChecked() && laserScanRaw.
size())
4881 else if(laserScanRaw.
hasRGB())
4899 if(
ui_->checkBox_showCloud->isChecked() &&
ui_->checkBox_cameraProjection->isChecked() &&
4913 if(!models.empty() && !models[0].isValidForProjection())
4918 if(!models.empty() && models[0].imageWidth() != 0 && models[0].imageHeight() != 0)
4920 std::map<int, Transform> cameraPoses;
4921 std::map<int, std::vector<CameraModel> > cameraModels;
4923 cameraModels.insert(std::make_pair(data.
id(), models));
4925 std::vector<std::pair< std::pair<int, int>, pcl::PointXY> > pointToPixel;
4931 UASSERT(pointToPixel.empty() || pointToPixel.size() == cloud->size());
4932 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudValidPoints(
new pcl::PointCloud<pcl::PointXYZRGB>);
4933 cloudValidPoints->resize(cloud->size());
4935 for(
size_t i=0; i<pointToPixel.size(); ++i)
4937 pcl::PointXYZINormal & pt = cloud->at(i);
4938 pcl::PointXYZRGB ptColor;
4939 int nodeID = pointToPixel[i].first.first;
4940 int cameraIndex = pointToPixel[i].first.second;
4941 if(nodeID>0 && cameraIndex>=0)
4945 int subImageWidth = image.cols / cameraModels.at(nodeID).size();
4946 image = image(
cv::Range::all(), cv::Range(cameraIndex*subImageWidth, (cameraIndex+1)*subImageWidth));
4949 int x = pointToPixel[i].second.x * (float)image.cols;
4950 int y = pointToPixel[i].second.y * (
float)image.rows;
4951 UASSERT(x>=0 && x<image.cols);
4952 UASSERT(y>=0 && y<image.rows);
4954 if(image.type()==CV_8UC3)
4956 cv::Vec3b bgr = image.at<cv::Vec3b>(y, x);
4963 UASSERT(image.type()==CV_8UC1);
4964 ptColor.r = ptColor.g = ptColor.b = image.at<
unsigned char>(pointToPixel[i].second.y * image.rows, pointToPixel[i].second.x * image.cols);
4970 cloudValidPoints->at(oi++) = ptColor;
4973 cloudValidPoints->resize(oi);
4974 if(!cloudValidPoints->empty())
4976 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
4978 cloudValidPoints =
util3d::voxelize(cloudValidPoints,
ui_->doubleSpinBox_voxelSize->value());
4985 UWARN(
"Camera projection to scan returned an empty cloud, no visible points from cameras...");
4990 UERROR(
"Node has invalid camera models, camera projection on scan cannot be done!.");
4993 else if(
ui_->checkBox_showCloud->isChecked() ||
ui_->checkBox_showMesh->isChecked())
4999 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
5000 pcl::IndicesPtr indices(
new std::vector<int>);
5004 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
5012 ui_->spinBox_decimation->value(),0,0,indices.get());
5025 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
5030 if(
ui_->checkBox_showMesh->isChecked() && !cloud->is_dense)
5032 Eigen::Vector3f viewpoint(0.0
f,0.0
f,0.0
f);
5035 viewpoint[0] = data.
cameraModels()[0].localTransform().x();
5036 viewpoint[1] = data.
cameraModels()[0].localTransform().y();
5037 viewpoint[2] = data.
cameraModels()[0].localTransform().z();
5047 float(
ui_->spinBox_mesh_angleTolerance->value())*
M_PI/180.0
f,
5048 ui_->checkBox_mesh_quad->isChecked(),
5049 ui_->spinBox_mesh_triangleSize->value(),
5052 if(
ui_->spinBox_mesh_minClusterSize->value())
5055 std::vector<std::set<int> > neighbors;
5056 std::vector<std::set<int> > vertexToPolygons;
5063 ui_->spinBox_mesh_minClusterSize->value());
5064 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
5066 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
5068 for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
5070 filteredPolygons[oi++] = polygons.at(*jter);
5073 filteredPolygons.resize(oi);
5074 polygons = filteredPolygons;
5079 if(
ui_->checkBox_showCloud->isChecked())
5085 else if(
ui_->checkBox_showCloud->isChecked())
5087 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
5088 pcl::IndicesPtr indices(
new std::vector<int>);
5092 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
5117 if(
ui_->checkBox_showWords->isChecked() &&
5118 !signatures.empty() &&
5119 !(*signatures.begin())->getWords3().empty())
5121 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
5122 cloud->resize((*signatures.begin())->getWords3().size());
5124 for(std::multimap<int, int>::const_iterator iter=(*signatures.begin())->getWords().begin();
5125 iter!=(*signatures.begin())->getWords().end();
5128 const cv::Point3f & pt = (*signatures.begin())->getWords3()[iter->second];
5129 cloud->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
5144 if(
ui_->checkBox_showMap->isChecked() ||
ui_->checkBox_showGrid->isChecked())
5146 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
5147 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
5158 if(!localMaps.empty())
5160 std::map<int, Transform> poses;
5161 poses.insert(std::make_pair(data.
id(), pose));
5163 #ifdef RTABMAP_OCTOMAP 5165 if(
ui_->checkBox_octomap->isChecked() &&
5166 (!localMaps.begin()->second.first.first.empty() || !localMaps.begin()->second.first.second.empty()) &&
5167 (localMaps.begin()->second.first.first.empty() || localMaps.begin()->second.first.first.channels() > 2) &&
5168 (localMaps.begin()->second.first.second.empty() || localMaps.begin()->second.first.second.channels() > 2) &&
5169 (localMaps.begin()->second.second.empty() || localMaps.begin()->second.second.channels() > 2) &&
5170 localMapsInfo.begin()->second.first > 0.0f)
5175 octomap =
new OctoMap(params);
5176 octomap->
addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second, localMapsInfo.begin()->second.second);
5181 if(
ui_->checkBox_showMap->isChecked())
5183 float xMin=0.0f, yMin=0.0f;
5186 float gridCellSize = Parameters::defaultGridCellSize();
5189 #ifdef RTABMAP_OCTOMAP 5199 grid.
addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second);
5201 map8S = grid.
getMap(xMin, yMin);
5210 if(
ui_->checkBox_showGrid->isChecked())
5212 #ifdef RTABMAP_OCTOMAP 5215 if(
ui_->comboBox_octomap_rendering_type->currentIndex()== 0)
5217 pcl::IndicesPtr obstacles(
new std::vector<int>);
5218 pcl::IndicesPtr empty(
new std::vector<int>);
5219 pcl::IndicesPtr ground(
new std::vector<int>);
5220 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->
createCloud(
ui_->spinBox_grid_depth->value(), obstacles.get(), empty.get(), ground.get());
5223 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
5224 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
5228 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
5229 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
5235 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5236 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
5240 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5241 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
5246 if(
ui_->checkBox_grid_empty->isChecked())
5248 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5249 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
5286 if(
ui_->checkBox_grid_empty->isChecked())
5291 QColor(
ui_->lineEdit_emptyColor->text()));
5297 #ifdef RTABMAP_OCTOMAP 5310 if(signatures.size())
5312 UASSERT(signatures.front() != 0 && signatures.size() == 1);
5313 delete signatures.front();
5319 std::multimap<int, rtabmap::Link> links;
5323 QString strParents, strChildren;
5324 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
5329 if(iter->first <
id)
5331 strChildren.append(QString(
"%1 ").arg(iter->first));
5335 strParents.append(QString(
"%1 ").arg(iter->first));
5339 labelParents->setText(strParents);
5340 labelChildren->setText(strChildren);
5346 labelMapId->setText(QString::number(mapId));
5357 if(updateConstraintView &&
ui_->dockWidget_constraints->isVisible())
5360 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5361 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5370 if(i !=
ui_->horizontalSlider_loops->value())
5372 ui_->horizontalSlider_loops->blockSignals(
true);
5373 ui_->horizontalSlider_loops->setValue(i);
5374 ui_->horizontalSlider_loops->blockSignals(
false);
5377 ui_->horizontalSlider_neighbors->blockSignals(
true);
5378 ui_->horizontalSlider_neighbors->setValue(0);
5379 ui_->horizontalSlider_neighbors->blockSignals(
false);
5389 if(i !=
ui_->horizontalSlider_neighbors->value())
5391 ui_->horizontalSlider_neighbors->blockSignals(
true);
5392 ui_->horizontalSlider_neighbors->setValue(i);
5393 ui_->horizontalSlider_neighbors->blockSignals(
false);
5396 ui_->horizontalSlider_loops->blockSignals(
true);
5397 ui_->horizontalSlider_loops->setValue(0);
5398 ui_->horizontalSlider_loops->blockSignals(
false);
5406 ui_->horizontalSlider_loops->blockSignals(
true);
5407 ui_->horizontalSlider_neighbors->blockSignals(
true);
5408 ui_->horizontalSlider_loops->setValue(0);
5409 ui_->horizontalSlider_neighbors->setValue(0);
5410 ui_->horizontalSlider_loops->blockSignals(
false);
5411 ui_->horizontalSlider_neighbors->blockSignals(
false);
5416 bool constraintViewUpdated =
false;
5420 constraintViewUpdated =
true;
5425 std::map<int, Transform> optimizedPoses =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
5426 if(optimizedPoses.size() > 0)
5428 std::map<int, Transform>::iterator fromIter = optimizedPoses.find(from);
5429 std::map<int, Transform>::iterator toIter = optimizedPoses.find(to);
5430 if(fromIter != optimizedPoses.end() &&
5431 toIter != optimizedPoses.end())
5433 Link link(from, to,
Link::kUndef, fromIter->second.inverse() * toIter->second);
5435 constraintViewUpdated =
true;
5439 if(!constraintViewUpdated)
5441 ui_->label_constraint->clear();
5442 ui_->label_constraint_opt->clear();
5443 ui_->label_variance->clear();
5444 ui_->lineEdit_covariance->clear();
5445 ui_->label_type->clear();
5446 ui_->label_type_name->clear();
5447 ui_->checkBox_showOptimized->setEnabled(
false);
5457 if(this->parent() == 0)
5465 if(
ui_->horizontalSlider_A->maximum())
5467 int id =
ids_.at(
ui_->horizontalSlider_A->value());
5478 ui_->dockWidget_stereoView->isVisible() &&
5486 if(data->
imageRaw().channels() == 3)
5488 cv::cvtColor(data->
imageRaw(), leftMono, CV_BGR2GRAY);
5500 std::vector<cv::KeyPoint> kpts;
5501 uInsert(parameters,
ParametersPair(Parameters::kKpMaxFeatures(), parameters.at(Parameters::kVisMaxFeatures())));
5502 uInsert(parameters,
ParametersPair(Parameters::kKpMinDepth(), parameters.at(Parameters::kVisMinDepth())));
5503 uInsert(parameters,
ParametersPair(Parameters::kKpMaxDepth(), parameters.at(Parameters::kVisMaxDepth())));
5504 uInsert(parameters,
ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType())));
5505 uInsert(parameters,
ParametersPair(Parameters::kKpRoiRatios(), parameters.at(Parameters::kVisRoiRatios())));
5506 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixEps(), parameters.at(Parameters::kVisSubPixEps())));
5507 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixIterations(), parameters.at(Parameters::kVisSubPixIterations())));
5508 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixWinSize(), parameters.at(Parameters::kVisSubPixWinSize())));
5513 float timeKpt = timer.
ticks();
5515 std::vector<cv::Point2f> leftCorners;
5516 cv::KeyPoint::convert(kpts, leftCorners);
5519 std::vector<unsigned char> status;
5520 std::vector<cv::Point2f> rightCorners;
5529 float timeStereo = timer.
ticks();
5531 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
5532 cloud->resize(kpts.size());
5533 float bad_point = std::numeric_limits<float>::quiet_NaN ();
5534 UASSERT(status.size() == kpts.size());
5537 int flowOutliers= 0;
5538 int slopeOutliers= 0;
5539 int negativeDisparityOutliers = 0;
5540 for(
unsigned int i=0; i<status.size(); ++i)
5542 cv::Point3f pt(bad_point, bad_point, bad_point);
5545 float disparity = leftCorners[i].x - rightCorners[i].x;
5546 if(disparity > 0.0
f)
5558 cloud->at(oi++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
5564 ++negativeDisparityOutliers;
5574 UINFO(
"correspondences = %d/%d (%f) (time kpt=%fs stereo=%fs)",
5575 (
int)cloud->size(), (int)leftCorners.size(), float(cloud->size())/
float(leftCorners.size()), timeKpt, timeStereo);
5581 ui_->label_stereo_inliers->setNum(inliers);
5582 ui_->label_stereo_flowOutliers->setNum(flowOutliers);
5583 ui_->label_stereo_slopeOutliers->setNum(slopeOutliers);
5584 ui_->label_stereo_disparityOutliers->setNum(negativeDisparityOutliers);
5586 std::vector<cv::KeyPoint> rightKpts;
5587 cv::KeyPoint::convert(rightCorners, rightKpts);
5588 std::vector<cv::DMatch> good_matches(kpts.size());
5589 for(
unsigned int i=0; i<good_matches.size(); ++i)
5591 good_matches[i].trainIdx = i;
5592 good_matches[i].queryIdx = i;
5604 ui_->graphicsView_stereo->clear();
5605 ui_->graphicsView_stereo->setLinesShown(
true);
5606 ui_->graphicsView_stereo->setFeaturesShown(
false);
5607 ui_->graphicsView_stereo->setImageDepthShown(
true);
5613 for(
unsigned int i=0; i<kpts.size(); ++i)
5615 if(rightKpts[i].pt.x > 0 && rightKpts[i].pt.y > 0)
5617 QColor c = Qt::green;
5622 else if(status[i] == 100)
5626 else if(status[i] == 101)
5630 else if(status[i] == 102)
5634 else if(status[i] == 110)
5638 ui_->graphicsView_stereo->addLine(
5644 QString(
"%1: (%2,%3) -> (%4,%5) d=%6").arg(i).arg(kpts[i].pt.x).arg(kpts[i].pt.y).arg(rightKpts[i].pt.x).arg(rightKpts[i].pt.y).arg(kpts[i].pt.x - rightKpts[i].pt.x));
5647 ui_->graphicsView_stereo->update();
5653 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5654 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5657 ui_->graphicsView_A->clearLines();
5658 ui_->graphicsView_A->setFeaturesColor(
ui_->graphicsView_A->getDefaultFeatureColor());
5659 ui_->graphicsView_B->clearLines();
5660 ui_->graphicsView_B->setFeaturesColor(
ui_->graphicsView_B->getDefaultFeatureColor());
5662 const QMultiMap<int, KeypointItem*> & wordsA =
ui_->graphicsView_A->getFeatures();
5663 const QMultiMap<int, KeypointItem*> & wordsB =
ui_->graphicsView_B->getFeatures();
5664 std::set<int> inliersSet(inliers.begin(), inliers.end());
5665 if(wordsA.size() && wordsB.size())
5667 QList<int> ids = wordsA.uniqueKeys();
5668 for(
int i=0; i<ids.size(); ++i)
5670 if(ids[i] > 0 && wordsA.count(ids[i]) == 1 && wordsB.count(ids[i]) == 1)
5674 float scaleAX =
ui_->graphicsView_A->viewScale();
5675 float scaleBX =
ui_->graphicsView_B->viewScale();
5677 float marginAX = (
ui_->graphicsView_A->width() -
ui_->graphicsView_A->sceneRect().width()*scaleAX)/2.0
f;
5678 float marginAY = (
ui_->graphicsView_A->height() -
ui_->graphicsView_A->sceneRect().height()*scaleAX)/2.0
f;
5679 float marginBX = (
ui_->graphicsView_B->width() -
ui_->graphicsView_B->sceneRect().width()*scaleBX)/2.0
f;
5680 float marginBY = (
ui_->graphicsView_B->height() -
ui_->graphicsView_B->sceneRect().height()*scaleBX)/2.0
f;
5685 if(
ui_->actionVertical_Layout->isChecked())
5687 deltaY =
ui_->graphicsView_A->height();
5691 deltaX =
ui_->graphicsView_A->width();
5697 QColor cA =
ui_->graphicsView_A->getDefaultMatchingLineColor();
5698 QColor cB =
ui_->graphicsView_B->getDefaultMatchingLineColor();
5699 if(inliersSet.find(ids[i])!=inliersSet.end())
5701 cA =
ui_->graphicsView_A->getDefaultMatchingFeatureColor();
5702 cB =
ui_->graphicsView_B->getDefaultMatchingFeatureColor();
5703 ui_->graphicsView_A->setFeatureColor(ids[i],
ui_->graphicsView_A->getDefaultMatchingFeatureColor());
5704 ui_->graphicsView_B->setFeatureColor(ids[i],
ui_->graphicsView_B->getDefaultMatchingFeatureColor());
5708 ui_->graphicsView_A->setFeatureColor(ids[i],
ui_->graphicsView_A->getDefaultMatchingLineColor());
5709 ui_->graphicsView_B->setFeatureColor(ids[i],
ui_->graphicsView_B->getDefaultMatchingLineColor());
5712 ui_->graphicsView_A->addLine(
5715 (kptB->
keypoint().pt.x*scaleBX+marginBX+deltaX-marginAX)/scaleAX,
5716 (kptB->
keypoint().pt.y*scaleBX+marginBY+deltaY-marginAY)/scaleAX,
5719 ui_->graphicsView_B->addLine(
5720 (kptA->
keypoint().pt.x*scaleAX+marginAX-deltaX-marginBX)/scaleBX,
5721 (kptA->
keypoint().pt.y*scaleAX+marginAY-deltaY-marginBY)/scaleBX,
5727 ui_->graphicsView_A->update();
5728 ui_->graphicsView_B->update();
5735 ui_->label_indexA->setText(QString::number(value));
5736 if(value>=0 && value <
ids_.size())
5738 ui_->label_idA->setText(QString::number(
ids_.at(value)));
5748 ui_->label_indexB->setText(QString::number(value));
5749 if(value>=0 && value <
ids_.size())
5751 ui_->label_idB->setText(QString::number(
ids_.at(value)));
5794 int position =
ui_->horizontalSlider_loops->value();
5803 cv::Mat covBefore = link.
infMatrix().inv();
5805 covBefore.at<
double>(0,0)<9999.0?
std::sqrt(covBefore.at<
double>(0,0)):0.0,
5806 covBefore.at<
double>(5,5)<9999.0?
std::sqrt(covBefore.at<
double>(5,5)):0.0);
5807 if(dialog.exec() == QDialog::Accepted)
5809 bool updated =
false;
5810 cv::Mat covariance = cv::Mat::eye(6, 6, CV_64FC1);
5817 covariance(cv::Range(0,3), cv::Range(0,3)) *= 9999.9;
5825 covariance(cv::Range(3,6), cv::Range(3,6)) *= 9999.9;
5831 if(iter->second.to() == link.
to() &&
5832 iter->second.type() == link.
type())
5834 iter->second = newLink;
5842 linksRefined_.insert(std::make_pair(newLink.from(), newLink));
5855 if(dialog.exec() == QDialog::Accepted)
5857 cv::Mat covariance = cv::Mat::eye(6, 6, CV_64FC1);
5864 covariance(cv::Range(0,3), cv::Range(0,3)) *= 9999.9;
5872 covariance(cv::Range(3,6), cv::Range(3,6)) *= 9999.9;
5874 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5875 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5882 if(newLink.from() < newLink.to())
5886 linksAdded_.insert(std::make_pair(newLink.from(), newLink));
5905 ui_->horizontalSlider_neighbors->value() >= 0 &&
ui_->horizontalSlider_neighbors->value() <
neighborLinks_.size())
5910 ui_->horizontalSlider_loops->value() >= 0 &&
ui_->horizontalSlider_loops->value() <
loopLinks_.size())
5924 bool updateImageSliders,
5934 if(iterLink->second.from() == link.to())
5936 link = iterLink->second.
inverse();
5940 link = iterLink->second;
5943 else if(
ui_->checkBox_ignorePoseCorrection->isChecked())
5950 if(!poseFrom.
isNull() && !poseTo.isNull())
5954 link =
Link(link.from(),
5961 UDEBUG(
"%d -> %d", link.from(), link.to());
5967 t.getEulerAngles(roll, pitch, yaw);
5971 ui_->label_constraint->clear();
5972 ui_->label_constraint_opt->clear();
5973 ui_->checkBox_showOptimized->setEnabled(
false);
5976 ui_->label_type->setText(QString::number(link.type()));
5977 ui_->label_type_name->setText(tr(
"(%1)")
5987 ui_->label_variance->setText(QString(
"%1, %2")
5988 .arg(
sqrt(link.transVariance()))
5989 .arg(
sqrt(link.rotVariance())));
5990 std::stringstream out;
5991 out << link.infMatrix().inv();
5992 ui_->lineEdit_covariance->setText(out.str().c_str());
5993 ui_->label_constraint->setText(QString(
"%1").arg(t.prettyPrint().c_str()).replace(
" ",
"\n"));
5995 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
5997 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
5999 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(link.from());
6000 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(link.to());
6001 if(iterFrom != graph.end() && iterTo != graph.end())
6003 ui_->checkBox_showOptimized->setEnabled(
true);
6008 float a = pcl::getAngle3D(Eigen::Vector4f(v1.
x(), v1.
y(), v1.
z(), 0), Eigen::Vector4f(v2.
x(), v2.
y(), v2.
z(), 0));
6009 a = (a *180.0f) / CV_PI;
6010 ui_->label_constraint_opt->setText(QString(
"%1\n(error=%2% a=%3)").arg(QString(topt.
prettyPrint().c_str()).replace(
" ",
"\n")).arg((t.getNorm()>0?diff/t.getNorm():0)*100.0
f).arg(a));
6012 if(
ui_->checkBox_showOptimized->isChecked())
6019 if(updateImageSliders)
6021 ui_->horizontalSlider_A->blockSignals(
true);
6022 ui_->horizontalSlider_B->blockSignals(
true);
6025 ui_->horizontalSlider_A->setValue(
idToIndex_.value(link.from()));
6027 ui_->horizontalSlider_B->setValue(
idToIndex_.value(link.to()));
6028 ui_->horizontalSlider_A->blockSignals(
false);
6029 ui_->horizontalSlider_B->blockSignals(
false);
6033 ui_->label_parentsA,
6034 ui_->label_childrenA,
6038 ui_->graphicsView_A,
6042 ui_->label_optposeA,
6046 ui_->label_gravityA,
6050 ui_->label_sensorsA,
6056 ui_->label_parentsB,
6057 ui_->label_childrenB,
6061 ui_->graphicsView_B,
6065 ui_->label_optposeB,
6069 ui_->label_gravityB,
6073 ui_->label_sensorsB,
6082 if(signatureFrom.
id()>0)
6094 if(signatureTo.
id()>0)
6098 else if(link.to()>0)
6108 if(
ui_->checkBox_odomFrame->isChecked())
6114 std::vector<float> v;
6130 if(
ui_->checkBox_show3Dclouds->isChecked())
6132 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFrom, cloudTo;
6133 pcl::IndicesPtr indicesFrom(
new std::vector<int>);
6134 pcl::IndicesPtr indicesTo(
new std::vector<int>);
6144 if(cloudTo.get() && indicesTo->size())
6150 if(
ui_->doubleSpinBox_gainCompensationRadius->value()>0.0 &&
6151 cloudFrom.get() && indicesFrom->size() &&
6152 cloudTo.get() && indicesTo->size())
6157 compensator.apply(0, cloudFrom, indicesFrom);
6158 compensator.apply(1, cloudTo, indicesTo);
6159 UINFO(
"Gain compensation time = %fs", t.
ticks());
6162 if(cloudFrom.get() && indicesFrom->size())
6164 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
6166 cloudFrom =
util3d::voxelize(cloudFrom, indicesFrom,
ui_->doubleSpinBox_voxelSize->value());
6170 if(cloudTo.get() && indicesTo->size())
6172 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
6182 if(
ui_->checkBox_show3DWords->isChecked())
6185 ids.push_back(link.from());
6188 ids.push_back(link.to());
6190 std::list<Signature*> signatures;
6192 if(signatures.size() == 2 || (link.to()<0 && signatures.size()==1))
6194 const Signature * sFrom = signatureFrom.
id()>0?&signatureFrom:signatures.front();
6196 if(signatures.size()==2)
6198 sTo = signatureTo.
id()>0?&signatureTo:signatures.back();
6202 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom(
new pcl::PointCloud<pcl::PointXYZ>);
6203 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo(
new pcl::PointCloud<pcl::PointXYZ>);
6204 cloudFrom->resize(sFrom->
getWords3().size());
6207 cloudTo->resize(sTo->
getWords3().size());
6212 for(std::multimap<int, int>::const_iterator iter=sFrom->
getWords().begin();
6216 const cv::Point3f & pt = sFrom->
getWords3()[iter->second];
6217 cloudFrom->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
6223 for(std::multimap<int, int>::const_iterator iter=sTo->
getWords().begin();
6227 const cv::Point3f & pt = sTo->
getWords3()[iter->second];
6228 cloudTo->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
6232 if(cloudFrom->size())
6245 if(cloudFrom->size())
6251 UWARN(
"Empty 3D words for node %d", link.from());
6262 UWARN(
"Empty 3D words for node %d", link.to());
6269 UERROR(
"Not found signature %d or %d in RAM", link.from(), link.to());
6274 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
6284 if(
ui_->checkBox_show2DScans->isChecked())
6288 !link.userDataCompressed().empty() &&
6289 signatureTo.
id()==0)
6291 std::vector<int> ids;
6292 cv::Mat userData = link.uncompressUserDataConst();
6293 if(userData.type() == CV_8SC1 &&
6294 userData.rows == 1 &&
6295 userData.cols >= 8 &&
6296 userData.at<
char>(userData.cols-1) == 0 &&
6297 memcmp(userData.data,
"SCANS:", 6) == 0)
6299 std::string scansStr = (
const char *)userData.data;
6300 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
6301 if(!scansStr.empty())
6303 std::list<std::string> strs =
uSplit(scansStr,
':');
6304 if(strs.size() == 2)
6306 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
6307 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
6309 ids.push_back(atoi(iter->c_str()));
6310 if(ids.back() == link.from())
6323 std::map<int, rtabmap::Transform> poses;
6324 for(
unsigned int i=0; i<ids.size(); ++i)
6332 UERROR(
"Not found %d node!", ids[i]);
6340 std::map<int, rtabmap::Transform> posesOut;
6341 std::multimap<int, rtabmap::Link> linksOut;
6349 if(poses.size() != posesOut.size())
6351 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)poses.size(), (int)posesOut.size());
6355 for(std::map<int, Transform>::iterator iter=posesOut.begin(); iter!=posesOut.end(); ++iter)
6357 UDEBUG(
" %d=%s", iter->first, iter->second.prettyPrint().c_str());
6360 for(std::multimap<int, Link>::iterator iter=linksOut.begin(); iter!=linksOut.end(); ++iter)
6362 UDEBUG(
" %d->%d (type=%s) %s", iter->second.from(), iter->second.to(), iter->second.typeName().c_str(), iter->second.transform().prettyPrint().c_str());
6365 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(link.to(), posesOut, linksOut);
6368 UDEBUG(
"Output poses: ");
6369 for(std::map<int, Transform>::iterator iter=finalPoses.begin(); iter!=finalPoses.end(); ++iter)
6371 UDEBUG(
" %d=%s", iter->first, iter->second.prettyPrint().c_str());
6376 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledScans(
new pcl::PointCloud<pcl::PointXYZ>);
6377 pcl::PointCloud<pcl::PointNormal>::Ptr assembledNormalScans(
new pcl::PointCloud<pcl::PointNormal>);
6378 pcl::PointCloud<pcl::PointXYZI>::Ptr assembledIScans(
new pcl::PointCloud<pcl::PointXYZI>);
6379 pcl::PointCloud<pcl::PointXYZINormal>::Ptr assembledINormalScans(
new pcl::PointCloud<pcl::PointXYZINormal>);
6380 pcl::PointCloud<pcl::PointXYZ>::Ptr graph(
new pcl::PointCloud<pcl::PointXYZ>);
6381 for(std::map<int, Transform>::iterator iter=finalPoses.begin(); iter!=finalPoses.end(); ++iter)
6383 iter->second = u * iter->second;
6384 if(iter->first != link.to())
6411 graph->push_back(
util3d::transformPoint(pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z()), pose));
6414 if(assembledNormalScans->size())
6419 if(assembledScans->size())
6424 if(assembledINormalScans->size())
6429 if(assembledIScans->size())
6449 pcl::PointCloud<pcl::PointXYZINormal>::Ptr scan;
6456 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
6463 pcl::PointCloud<pcl::PointXYZI>::Ptr scan;
6470 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
6480 pcl::PointCloud<pcl::PointXYZINormal>::Ptr scan;
6487 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
6494 pcl::PointCloud<pcl::PointXYZI>::Ptr scan;
6501 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
6537 #if PCL_VERSION_COMPARE(>=, 1, 7, 2) 6558 ui_->pushButton_refine->setEnabled(
false);
6559 ui_->pushButton_reset->setEnabled(
false);
6560 ui_->pushButton_add->setEnabled(
false);
6561 ui_->pushButton_reject->setEnabled(
false);
6562 ui_->toolButton_constraint->setEnabled(
false);
6570 currentLink =
loopLinks_.at(
ui_->horizontalSlider_loops->value());
6571 from = currentLink.
from();
6572 to = currentLink.
to();
6576 from =
ids_.at(
ui_->horizontalSlider_A->value());
6577 to =
ids_.at(
ui_->horizontalSlider_B->value());
6578 if(from!=to && from && to &&
6581 (
ui_->checkBox_enableForAll->isChecked() ||
6588 ui_->pushButton_add->setEnabled(
true);
6591 else if(
ui_->checkBox_enableForAll->isChecked())
6595 UWARN(
"Button \"Add\" cannot be enabled even if \"all\" checkbox is checked, as node %d doesn't have odometry set.", from);
6599 UWARN(
"Button \"Add\" cannot be enabled even if \"all\" checkbox is checked, as node %d doesn't have odometry set.", to);
6607 ((currentLink.
from() == from && currentLink.
to() == to) || (currentLink.
from() == to && currentLink.
to() == from)))
6611 ui_->pushButton_reject->setEnabled(
true);
6618 currentLink = iter->second;
6619 ui_->pushButton_reset->setEnabled(
true);
6622 ui_->toolButton_constraint->setEnabled(
true);
6633 if(refPoses.empty())
6643 if(refPoses.size() == graph.size() && length >= 100.0f)
6648 UINFO(
"KITTI t_err = %f %%", t_err);
6649 UINFO(
"KITTI r_err = %f deg/m", r_err);
6652 float translational_rmse = 0.0f;
6653 float translational_mean = 0.0f;
6654 float translational_median = 0.0f;
6655 float translational_std = 0.0f;
6656 float translational_min = 0.0f;
6657 float translational_max = 0.0f;
6658 float rotational_rmse = 0.0f;
6659 float rotational_mean = 0.0f;
6660 float rotational_median = 0.0f;
6661 float rotational_std = 0.0f;
6662 float rotational_min = 0.0f;
6663 float rotational_max = 0.0f;
6670 translational_median,
6682 ui_->label_rmse->setNum(translational_rmse);
6683 UINFO(
"translational_rmse=%f", translational_rmse);
6684 UINFO(
"translational_mean=%f", translational_mean);
6685 UINFO(
"translational_median=%f", translational_median);
6686 UINFO(
"translational_std=%f", translational_std);
6687 UINFO(
"translational_min=%f", translational_min);
6688 UINFO(
"translational_max=%f", translational_max);
6690 UINFO(
"rotational_rmse=%f", rotational_rmse);
6691 UINFO(
"rotational_mean=%f", rotational_mean);
6692 UINFO(
"rotational_median=%f", rotational_median);
6693 UINFO(
"rotational_std=%f", rotational_std);
6694 UINFO(
"rotational_min=%f", rotational_min);
6695 UINFO(
"rotational_max=%f", rotational_max);
6697 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
6699 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
6701 iter->second = gtToMap * iter->second;
6706 std::map<int, rtabmap::Transform> graphFiltered;
6713 graphFiltered = graph;
6715 if(
ui_->groupBox_posefiltering->isChecked())
6718 ui_->doubleSpinBox_posefilteringRadius->value(),
6719 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
6721 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
6722 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
6723 #ifdef RTABMAP_OCTOMAP 6730 if(
ui_->dockWidget_graphView->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
6733 UINFO(
"Update local maps list...");
6734 std::vector<int> ids =
uKeys(graphFiltered);
6735 for(
unsigned int i=0; i<ids.size(); ++i)
6744 if(!
localMaps_.find(ids[i])->second.first.first.empty() || !
localMaps_.find(ids[i])->second.first.second.empty())
6746 localMaps.insert(*
localMaps_.find(ids.at(i)));
6750 else if(ids.at(i)>0)
6754 cv::Mat ground, obstacles, empty;
6756 localMaps_.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
6758 if(!ground.empty() || !obstacles.empty())
6760 localMaps.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
6766 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end();)
6768 if(graphFiltered.find(iter->first) == graphFiltered.end())
6778 UINFO(
"Update local maps list... done (%d local maps, graph size=%d)", (
int)localMaps.size(), (int)graph.size());
6782 float cellSize = Parameters::defaultGridCellSize();
6788 if(!
ui_->checkBox_wmState->isChecked())
6790 bool allNodesAreInWM =
true;
6791 std::map<int, float> colors;
6792 for(std::map<int, rtabmap::Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
6796 colors.insert(std::make_pair(iter->first, 1));
6800 allNodesAreInWM =
false;
6803 if(!allNodesAreInWM)
6805 ui_->graphViewer->updatePosterior(colors, 1, 1);
6808 QGraphicsRectItem * rectScaleItem = 0;
6809 ui_->graphViewer->clearMap();
6811 if(graph.size() && localMaps.size() &&
6812 (
ui_->graphViewer->isGridMapVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()))
6817 #ifdef RTABMAP_OCTOMAP 6818 if(
ui_->checkBox_octomap->isChecked())
6821 bool updateAborted =
false;
6822 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6824 if(iter->second.first.first.channels() == 2 || iter->second.first.second.channels() == 2)
6826 QMessageBox::warning(
this, tr(
""),
6827 tr(
"Some local occupancy grids are 2D, but OctoMap requires 3D local " 6828 "occupancy grids. Uncheck OctoMap under GUI parameters or generate " 6829 "3D local occupancy grids (\"Grid/3D\" core parameter)."));
6830 updateAborted =
true;
6833 octomap_->
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second, localMapsInfo.at(iter->first).second);
6843 if((
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible()) ||
6844 (
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked()))
6846 bool eroded = Parameters::defaultGridGlobalEroded();
6851 #ifdef RTABMAP_OCTOMAP 6852 if(
ui_->checkBox_octomap->isChecked())
6865 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6867 grid.
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
6869 grid.
update(graphFiltered);
6870 if(
ui_->checkBox_grid_showProbMap->isChecked())
6876 map = grid.
getMap(xMin, yMin);
6880 ui_->label_timeGrid->setNum(
double(time.elapsed())/1000.0);
6885 if(
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible())
6887 ui_->graphViewer->updateMap(map8U, cellSize, xMin, yMin);
6889 if(
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked())
6898 int xLast = map.cols;
6899 int yLast = map.rows;
6900 bool firstSet =
false;
6901 bool lastSet =
false;
6902 for(
int x=0;
x<map.cols && (!firstSet || !lastSet); ++
x)
6904 for(
int y=0; y<map.rows; ++y)
6907 if(!firstSet && map.at<
char>(y,
x) != -1)
6913 int opp = map.cols-(
x+1);
6914 if(!lastSet && map.at<
char>(y, opp) != -1)
6923 for(
int y=0; y<map.rows && (!firstSet || !lastSet); ++y)
6925 for(
int x=0;
x<map.cols; ++
x)
6928 if(!firstSet && map.at<
char>(y,
x) != -1)
6934 int opp = map.rows-(y+1);
6935 if(!lastSet && map.at<
char>(map.rows-(y+1),
x) != -1)
6943 if( (xLast > xFirst && yLast > yFirst) &&
6945 xLast < map.cols-50 ||
6947 yLast < map.rows-50))
6949 rectScaleItem =
ui_->graphViewer->scene()->addRect(
6954 rectScaleItem->setTransform(QTransform::fromScale(cellSize*100.0
f, -cellSize*100.0f),
true);
6955 rectScaleItem->setRotation(90);
6956 rectScaleItem->setPos(-yMin*100.0f, -xMin*100.0f);
6962 if(
ui_->dockWidget_occupancyGridView->isVisible())
6964 #ifdef RTABMAP_OCTOMAP 6965 if(
ui_->checkBox_octomap->isChecked())
6972 pcl::PointCloud<pcl::PointXYZ>::Ptr groundXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6973 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6974 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCellsXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6975 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6976 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6977 pcl::PointCloud<pcl::PointXYZRGB>::Ptr emptyCellsRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6979 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6981 Transform pose = graphFiltered.at(iter->first);
6985 if(!iter->second.first.first.empty())
6987 if(iter->second.first.first.channels() == 4)
6996 if(!iter->second.first.second.empty())
6998 if(iter->second.first.second.channels() == 4)
7007 if(
ui_->checkBox_grid_empty->isChecked())
7009 if(!iter->second.second.empty())
7011 if(iter->second.second.channels() == 4)
7023 if(groundRGB->size())
7029 QColor(
ui_->lineEdit_groundColor->text()));
7032 if(groundXYZ->size())
7038 QColor(
ui_->lineEdit_groundColor->text()));
7041 if(obstaclesRGB->size())
7047 QColor(
ui_->lineEdit_obstacleColor->text()));
7050 if(obstaclesXYZ->size())
7056 QColor(
ui_->lineEdit_obstacleColor->text()));
7059 if(emptyCellsRGB->size())
7065 QColor(
ui_->lineEdit_emptyColor->text()));
7069 if(emptyCellsXYZ->size())
7075 QColor(
ui_->lineEdit_emptyColor->text()));
7083 ui_->graphViewer->fitInView(
ui_->graphViewer->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
7084 if(rectScaleItem != 0)
7086 ui_->graphViewer->fitInView(rectScaleItem, Qt::KeepAspectRatio);
7087 ui_->graphViewer->scene()->removeItem(rectScaleItem);
7088 delete rectScaleItem;
7091 ui_->graphViewer->update();
7092 ui_->label_iterations->setNum(value);
7096 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
graphLinks_.begin(); iter!=
graphLinks_.end(); ++iter)
7098 std::map<int, rtabmap::Transform>::const_iterator jterA = graph.find(iter->first);
7099 std::map<int, rtabmap::Transform>::const_iterator jterB = graph.find(iter->second.to());
7100 if(jterA != graph.end() && jterB != graph.end())
7107 Eigen::Vector3f vA, vB;
7110 vA[0] = x; vA[1] = y; vA[2] = z;
7112 vB[0] = x; vB[1] = y; vB[2] = z;
7113 length += (vB - vA).norm();
7117 ui_->label_pathLength->setNum(length);
7122 ui_->label_loopClosures->clear();
7123 ui_->label_poses->clear();
7124 ui_->label_rmse->clear();
7128 int fromId =
ui_->spinBox_optimizationsFrom->value();
7131 QMessageBox::warning(
this, tr(
""), tr(
"Graph optimization from id (%1) for which node is not linked to graph.\n Minimum=%2, Maximum=%3")
7141 std::map<int, rtabmap::Transform> poses =
odomPoses_;
7144 std::map<int, rtabmap::Transform> wmPoses;
7145 std::vector<int> & wmState =
wmStates_.at(fromId);
7146 for(
unsigned int i=0; i<wmState.size(); ++i)
7148 std::map<int, rtabmap::Transform>::iterator iter = poses.find(wmState[i]);
7149 if(iter!=poses.end())
7151 wmPoses.insert(*iter);
7154 if(!wmPoses.empty())
7160 UWARN(
"Empty WM poses!? Ignoring WM state... (root id=%d, wmState=%d)", fromId, wmState.size());
7167 int currentMapId =
mapIds_.at(fromId);
7168 for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end();)
7172 poses.erase(iter++);
7181 ui_->menuExport_poses->setEnabled(
true);
7182 std::multimap<int, rtabmap::Link> links =
links_;
7188 int currentMapId =
mapIds_.at(fromId);
7189 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
7191 if((iter->second.from()>0 && (!
uContains(
mapIds_, iter->second.from()) ||
mapIds_.at(iter->second.from()) != currentMapId)) ||
7192 (iter->second.to()>0 && (!
uContains(
mapIds_, iter->second.to()) ||
mapIds_.at(iter->second.to()) != currentMapId)))
7194 links.erase(iter++);
7204 if(
ui_->checkBox_ignorePoseCorrection->isChecked())
7206 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
7213 if(!poseFrom.
isNull() && !poseTo.isNull())
7216 iter->second =
Link(
7217 iter->second.from(),
7219 iter->second.type(),
7227 double markerPriorsLinearVariance = Parameters::defaultMarkerPriorsVarianceLinear();
7228 double markerPriorsAngularVariance = Parameters::defaultMarkerPriorsVarianceAngular();
7229 std::map<int, Transform> markerPriors;
7231 Parameters::parse(parameters, Parameters::kMarkerPriorsVarianceLinear(), markerPriorsLinearVariance);
7232 UASSERT(markerPriorsLinearVariance>0.0
f);
7233 Parameters::parse(parameters, Parameters::kMarkerPriorsVarianceAngular(), markerPriorsAngularVariance);
7234 UASSERT(markerPriorsAngularVariance>0.0
f);
7235 std::string markerPriorsStr;
7238 std::list<std::string> strList =
uSplit(markerPriorsStr,
'|');
7239 for(std::list<std::string>::iterator iter=strList.begin(); iter!=strList.end(); ++iter)
7241 std::string markerStr = *iter;
7242 while(!markerStr.empty() && !
uIsDigit(markerStr[0]))
7244 markerStr.erase(markerStr.begin());
7246 if(!markerStr.empty())
7251 if(!prior.
isNull() &&
id>0)
7253 markerPriors.insert(std::make_pair(-
id, prior));
7258 UERROR(
"Failed to parse element \"%s\" in parameter %s", markerStr.c_str(), Parameters::kMarkerPriors().c_str());
7261 else if(!iter->empty())
7263 UERROR(
"Failed to parse parameter %s, value=\"%s\"", Parameters::kMarkerPriors().c_str(), iter->c_str());
7270 int totalNeighbor = 0;
7271 int totalNeighborMerged = 0;
7272 int totalGlobal = 0;
7273 int totalLocalTime = 0;
7274 int totalLocalSpace = 0;
7276 int totalPriors = 0;
7277 int totalLandmarks = 0;
7278 int totalGravity = 0;
7279 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
7287 ++totalNeighborMerged;
7291 if(
ui_->checkBox_ignoreGlobalLoop->isChecked())
7293 links.erase(iter++);
7301 if(
ui_->checkBox_ignoreLocalLoopSpace->isChecked())
7303 links.erase(iter++);
7311 if(
ui_->checkBox_ignoreLocalLoopTime->isChecked())
7313 links.erase(iter++);
7321 if(
ui_->checkBox_ignoreUserLoop->isChecked())
7323 links.erase(iter++);
7331 if(
ui_->checkBox_ignoreLandmarks->isChecked())
7333 links.erase(iter++);
7336 UASSERT(iter->second.from() > 0 && iter->second.to() < 0);
7337 if(poses.find(iter->second.from()) != poses.end() && poses.find(iter->second.to()) == poses.end())
7339 poses.insert(std::make_pair(iter->second.to(), poses.at(iter->second.from())*iter->second.transform()));
7345 int markerId = iter->second.to();
7346 if(markerPriors.find(markerId) != markerPriors.end())
7348 cv::Mat infMatrix = cv::Mat::eye(6, 6, CV_64FC1);
7349 infMatrix(cv::Range(0,3), cv::Range(0,3)) /= markerPriorsLinearVariance;
7350 infMatrix(cv::Range(3,6), cv::Range(3,6)) /= markerPriorsAngularVariance;
7351 links.insert(std::make_pair(markerId,
Link(markerId, markerId,
Link::kPosePrior, markerPriors.at(markerId), infMatrix)));
7352 UDEBUG(
"Added prior %d : %s (variance: lin=%f ang=%f)", markerId, markerPriors.at(markerId).prettyPrint().c_str(),
7353 markerPriorsLinearVariance, markerPriorsAngularVariance);
7373 ui_->label_loopClosures->setText(tr(
"(%1, %2, %3, %4, %5, %6, %7, %8, %9)")
7375 .arg(totalNeighborMerged)
7377 .arg(totalLocalSpace)
7378 .arg(totalLocalTime)
7381 .arg(totalLandmarks)
7382 .arg(totalGravity));
7385 if(
ui_->checkBox_ignoreIntermediateNodes->isVisible() &&
7386 ui_->checkBox_ignoreIntermediateNodes->isChecked())
7388 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
7393 Link link = iter->second;
7396 std::multimap<int, Link>::iterator uter = links.find(link.
to());
7397 if(uter != links.end())
7400 poses.erase(link.
to());
7401 link = link.
merge(uter->second, uter->second.type());
7410 iter->second = link;
7419 std::map<int, rtabmap::Transform> posesOut;
7420 std::multimap<int, rtabmap::Link> linksOut;
7421 UINFO(
"Get connected graph from %d (%d poses, %d links)", fromId, (
int)poses.size(), (int)links.size());
7428 UINFO(
"Connected graph of %d poses and %d links", (
int)posesOut.size(), (int)linksOut.size());
7431 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(fromId, posesOut, linksOut,
ui_->checkBox_iterativeOptimization->isChecked()?&
graphes_:0);
7432 ui_->label_timeOptimization->setNum(
double(time.elapsed())/1000.0);
7434 if(posesOut.size() && finalPoses.empty())
7436 UWARN(
"Optimization failed... (poses=%d, links=%d).", (
int)posesOut.size(), (int)linksOut.size());
7439 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors. " 7440 "Give it a try with %1=0 and %2=true.").arg(Parameters::kOptimizerStrategy().c_str()).arg(Parameters::kOptimizerVarianceIgnored().c_str()));
7444 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors."));
7447 ui_->label_poses->setNum((
int)finalPoses.size());
7453 if(
ui_->doubleSpinBox_optimizationScale->value()!=-1.0)
7456 for(std::list<std::map<int, Transform> >::iterator iter=
graphes_.begin(); iter!=
graphes_.end(); ++iter)
7458 for(std::map<int, Transform>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
7460 jter->second = jter->second.clone();
7461 jter->second.x() *=
ui_->doubleSpinBox_optimizationScale->value();
7462 jter->second.y() *=
ui_->doubleSpinBox_optimizationScale->value();
7463 jter->second.z() *=
ui_->doubleSpinBox_optimizationScale->value();
7468 ui_->horizontalSlider_iterations->setMaximum((
int)
graphes_.size()-1);
7469 ui_->horizontalSlider_iterations->setValue((
int)
graphes_.size()-1);
7470 ui_->horizontalSlider_iterations->setEnabled(
true);
7471 ui_->spinBox_optimizationsFrom->setEnabled(
true);
7476 ui_->horizontalSlider_iterations->setEnabled(
false);
7477 ui_->spinBox_optimizationsFrom->setEnabled(
false);
7483 if(sender() ==
ui_->checkBox_grid_2d && !
ui_->checkBox_grid_2d->isChecked())
7491 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
7492 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
7493 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
7494 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
7495 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
7496 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
7505 #ifdef RTABMAP_OCTOMAP 7506 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
7507 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
7508 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
7509 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
7510 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
7511 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
7513 if(
ui_->checkBox_octomap->isChecked())
7520 if(
ui_->comboBox_octomap_rendering_type->currentIndex()>0)
7526 pcl::IndicesPtr obstacles(
new std::vector<int>);
7527 pcl::IndicesPtr empty(
new std::vector<int>);
7528 pcl::IndicesPtr ground(
new std::vector<int>);
7529 std::vector<double> prob;
7531 ui_->spinBox_grid_depth->value(),
7541 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
7542 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
7546 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
7547 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
7553 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
7554 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
7558 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
7559 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
7564 if(
ui_->checkBox_grid_empty->isChecked())
7566 if(prob.size()==cloud->size())
7568 float occThr = Parameters::defaultGridGlobalOccupancyThr();
7569 Parameters::parse(
ui_->parameters_toolbox->getParameters(), Parameters::kGridGlobalOccupancyThr(), occThr);
7570 pcl::PointCloud<pcl::PointXYZRGB>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
7571 emptyCloud->resize(empty->size());
7572 for(
unsigned int i=0;i<empty->size(); ++i)
7574 emptyCloud->points.at(i).x = cloud->points.at(empty->at(i)).
x;
7575 emptyCloud->points.at(i).y = cloud->points.at(empty->at(i)).y;
7576 emptyCloud->points.at(i).z = cloud->points.at(empty->at(i)).z;
7577 QColor hsv = QColor::fromHsv(
int(prob.at(empty->at(i))/occThr*240.0), 255, 255, 255);
7578 QRgb color = hsv.rgb();
7579 emptyCloud->points.at(i).r = qRed(color);
7580 emptyCloud->points.at(i).g = qGreen(color);
7581 emptyCloud->points.at(i).b = qBlue(color);
7589 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
7590 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
7599 if(
ui_->dockWidget_view3d->isVisible() &&
ui_->checkBox_showGrid->isChecked())
7613 link = findIter->second;
7620 link = findIter->second;
7625 if(findIter !=
links_.end())
7627 link = findIter->second;
7641 int from =
ids_.at(
ui_->horizontalSlider_A->value());
7642 int to =
ids_.at(
ui_->horizontalSlider_B->value());
7648 UDEBUG(
"%d -> %d", from, to);
7649 bool switchedIds =
false;
7652 UWARN(
"Cannot refine link to same node");
7660 UERROR(
"Not found link! (%d->%d)", from, to);
7664 UDEBUG(
"%d -> %d (type=%d)", currentLink.
from(), currentLink.
to(), currentLink.
type());
7666 if(
ui_->checkBox_showOptimized->isChecked() &&
7669 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
7671 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
7674 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(currentLink.
from());
7675 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(currentLink.
to());
7676 if(iterFrom != graph.end() && iterTo != graph.end())
7683 else if(
ui_->checkBox_ignorePoseCorrection->isChecked() &&
7691 if(!poseFrom.
isNull() && !poseTo.isNull())
7693 t = poseFrom.
inverse() * poseTo;
7706 UERROR(
"Signature %d not found!", currentLink.
from());
7716 std::map<int, rtabmap::Transform> scanPoses;
7720 userData.type() == CV_8SC1 &&
7721 userData.rows == 1 &&
7722 userData.cols >= 8 &&
7723 userData.at<
char>(userData.cols-1) == 0 &&
7724 memcmp(userData.data,
"SCANS:", 6) == 0 &&
7725 currentLink.
from() > currentLink.
to())
7727 std::string scansStr = (
const char *)userData.data;
7728 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
7729 if(!scansStr.empty())
7731 std::list<std::string> strs =
uSplit(scansStr,
':');
7732 if(strs.size() == 2)
7734 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
7735 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
7737 int id = atoi(iter->c_str());
7744 UERROR(
"Not found %d node!",
id);
7750 if(scanPoses.size()>1)
7756 std::map<int, rtabmap::Transform> posesOut;
7757 std::multimap<int, rtabmap::Link> linksOut;
7765 if(scanPoses.size() != posesOut.size())
7767 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)scanPoses.size(), (int)posesOut.size());
7768 UWARN(
"Input poses: ");
7769 for(std::map<int, Transform>::iterator iter=scanPoses.begin(); iter!=scanPoses.end(); ++iter)
7771 UWARN(
" %d", iter->first);
7773 UWARN(
"Input links: ");
7775 for(std::multimap<int, Link>::iterator iter=modifiedLinks.begin(); iter!=modifiedLinks.end(); ++iter)
7777 UWARN(
" %d->%d", iter->second.from(), iter->second.to());
7781 scanPoses = optimizer->
optimize(currentLink.
to(), posesOut, linksOut);
7784 std::map<int, Transform> filteredScanPoses = scanPoses;
7785 float proximityFilteringRadius = 0.0f;
7786 Parameters::parse(parameters, Parameters::kRGBDProximityPathFilteringRadius(), proximityFilteringRadius);
7787 if(scanPoses.size() > 2 && proximityFilteringRadius > 0.0f)
7792 filteredScanPoses.insert(*scanPoses.find(currentLink.
to()));
7799 int maxPoints = fromScan.
size();
7802 UWARN(
"From scan %d is empty!", fromS->
id());
7804 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledToClouds(
new pcl::PointCloud<pcl::PointXYZ>);
7805 pcl::PointCloud<pcl::PointNormal>::Ptr assembledToNormalClouds(
new pcl::PointCloud<pcl::PointNormal>);
7806 pcl::PointCloud<pcl::PointXYZI>::Ptr assembledToIClouds(
new pcl::PointCloud<pcl::PointXYZI>);
7807 pcl::PointCloud<pcl::PointXYZINormal>::Ptr assembledToNormalIClouds(
new pcl::PointCloud<pcl::PointXYZINormal>);
7808 pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledToRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGB>);
7809 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr assembledToNormalRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
7810 for(std::map<int, Transform>::const_iterator iter = filteredScanPoses.begin(); iter!=filteredScanPoses.end(); ++iter)
7812 if(iter->first != currentLink.
from())
7862 if(scan.
size() > maxPoints)
7864 maxPoints = scan.
size();
7869 UWARN(
"scan format of %d is not the same than from scan %d: %d vs %d", data.
id(), fromS->
id(), scan.
format(), fromScan.
format());
7874 UWARN(
"Laser scan not found for signature %d", iter->first);
7880 if(assembledToNormalClouds->size())
7884 else if(assembledToClouds->size())
7888 else if(assembledToNormalIClouds->size())
7892 else if(assembledToIClouds->size())
7896 else if(assembledToNormalRGBClouds->size())
7901 else if(assembledToRGBClouds->size())
7908 UWARN(
"Assembled scan is empty!");
7932 UERROR(
"Signature %d not found!", currentLink.
to());
7937 bool reextractVisualFeatures =
uStr2Bool(parameters.at(Parameters::kRGBDLoopClosureReextractFeatures()));
7939 if( reg->isScanRequired() ||
7940 reg->isUserDataRequired() ||
7941 reextractVisualFeatures ||
7944 dbDriver_->
loadNodeData(fromS, reextractVisualFeatures || !silent || (reg->isScanRequired() &&
ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
7945 dbDriver_->
loadNodeData(toS, reextractVisualFeatures || !silent || (reg->isScanRequired() &&
ui_->checkBox_icp_from_depth->isChecked()), reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
7954 if(reextractVisualFeatures)
7957 fromS->
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
7962 if(reg->isScanRequired())
7964 if(
ui_->checkBox_icp_from_depth->isChecked())
7967 cv::Mat tmpA, tmpB, tmpC, tmpD;
7972 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
7973 ui_->doubleSpinBox_icp_maxDepth->value(),
7974 ui_->doubleSpinBox_icp_minDepth->value(),
7976 ui_->parameters_toolbox->getParameters());
7979 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
7980 ui_->doubleSpinBox_icp_maxDepth->value(),
7981 ui_->doubleSpinBox_icp_minDepth->value(),
7983 ui_->parameters_toolbox->getParameters());
7985 if(cloudFrom->empty() && cloudTo->empty())
7987 std::string msg =
"Option to generate scan from depth is checked (GUI Parameters->Refine), but " 7988 "resulting clouds from depth are empty. Transformation estimation will likely " 7989 "fails. Uncheck the parameter to use laser scans.";
7993 QMessageBox::warning(
this,
7995 tr(
"%1").arg(msg.c_str()));
8000 UWARN(
"There are laser scans in data, but generate laser scan from " 8001 "depth image option is activated (GUI Parameters->Refine). " 8002 "Ignoring saved laser scans...");
8005 int maxLaserScans = cloudFrom->size();
8017 if(reg->isImageRequired() && reextractVisualFeatures)
8019 cv::Mat tmpA, tmpB, tmpC, tmpD;
8024 UINFO(
"Uncompress time: %f s", timer.
ticks());
8026 if(fromS->
id() < toS->
id())
8028 transform = reg->computeTransformationMod(*fromS, *toS, t, &info);
8032 transform = reg->computeTransformationMod(*toS, *fromS, t.isNull()?t:t.inverse(), &info);
8038 UINFO(
"(%d ->%d) Registration time: %f s", currentLink.
from(), currentLink.
to(), timer.
ticks());
8046 info.
covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001;
8051 transform = transform.
inverse();
8056 bool updated =
false;
8057 std::multimap<int, Link>::iterator iter =
linksRefined_.find(currentLink.
from());
8060 if(iter->second.to() == currentLink.
to() &&
8061 iter->second.type() == currentLink.
type())
8063 iter->second = newLink;
8071 linksRefined_.insert(std::make_pair(newLink.from(), newLink));
8075 if(updated && !silent)
8080 if(!silent &&
ui_->dockWidget_constraints->isVisible())
8082 if(toS && fromS->
id() > 0 && toS->
id() > 0)
8085 std::multimap<int, cv::KeyPoint> keypointsFrom;
8086 std::multimap<int, cv::KeyPoint> keypointsTo;
8089 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
8091 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
8096 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
8098 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
8124 if(toS && fromS->
id() > 0 && toS->
id() > 0)
8127 std::multimap<int, cv::KeyPoint> keypointsFrom;
8128 std::multimap<int, cv::KeyPoint> keypointsTo;
8131 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
8133 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
8138 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
8140 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
8156 QMessageBox::warning(
this,
8158 tr(
"Cannot find a transformation between nodes %1 and %2: %3").arg(currentLink.
from()).arg(currentLink.
to()).arg(info.
rejectedMsg.c_str()));
8166 int from =
ids_.at(
ui_->horizontalSlider_A->value());
8167 int to =
ids_.at(
ui_->horizontalSlider_B->value());
8173 bool switchedIds =
false;
8176 UWARN(
"Cannot add link to same node");
8186 std::list<Signature*> signatures;
8201 bool loopCovLimited = Parameters::defaultRGBDLoopCovLimited();
8202 Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), loopCovLimited);
8212 ids.push_back(from);
8215 if(signatures.size() != 2)
8217 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
8223 fromS = *signatures.begin();
8224 toS = *signatures.rbegin();
8226 bool reextractVisualFeatures =
uStr2Bool(parameters.at(Parameters::kRGBDLoopClosureReextractFeatures()));
8229 reextractVisualFeatures ||
8237 if(reextractVisualFeatures)
8240 fromS->
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
8249 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
8250 ui_->doubleSpinBox_icp_maxDepth->value(),
8251 ui_->doubleSpinBox_icp_minDepth->value(),
8253 ui_->parameters_toolbox->getParameters());
8256 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
8257 ui_->doubleSpinBox_icp_maxDepth->value(),
8258 ui_->doubleSpinBox_icp_minDepth->value(),
8260 ui_->parameters_toolbox->getParameters());
8262 if(cloudFrom->empty() && cloudTo->empty())
8264 std::string msg =
"Option to generate scan from depth is checked (GUI Parameters->Refine), but " 8265 "resulting clouds from depth are empty. Transformation estimation will likely " 8266 "fails. Uncheck the parameter to use laser scans.";
8270 QMessageBox::warning(
this,
8272 tr(
"%1").arg(msg.c_str()));
8277 UWARN(
"There are laser scans in data, but generate laser scan from " 8278 "depth image option is activated (GUI Parameters->Refine). Ignoring saved laser scans...");
8281 int maxLaserScans = cloudFrom->size();
8286 else if(!reextractVisualFeatures && fromS->
getWords().empty() && toS->
getWords().empty())
8288 std::string msg =
uFormat(
"\"%s\" is false and signatures (%d and %d) don't have words, " 8289 "registration will not be possible. Set \"%s\" to true.",
8290 Parameters::kRGBDLoopClosureReextractFeatures().c_str(),
8293 Parameters::kRGBDLoopClosureReextractFeatures().c_str());
8297 QMessageBox::warning(
this,
8299 tr(
"%1").arg(msg.c_str()));
8304 bool guessFromGraphRejected =
false;
8310 std::map<int, Transform> optimizedPoses =
graphes_.back();
8311 if(optimizedPoses.size() > 0)
8313 std::map<int, Transform>::iterator fromIter = optimizedPoses.find(from);
8314 std::map<int, Transform>::iterator toIter = optimizedPoses.find(to);
8315 if(fromIter != optimizedPoses.end() &&
8316 toIter != optimizedPoses.end())
8320 if(QMessageBox::question(
this,
8321 tr(
"Add constraint from optimized graph"),
8322 tr(
"Registration is done without vision (see %1 parameter), " 8323 "do you want to use a guess from the optimized graph?" 8325 "\n\nOtherwise, if " 8326 "the database has images, it is recommended to use %2=2 instead so that " 8327 "the guess can be found visually.")
8328 .arg(Parameters::kRegStrategy().c_str()).arg(Parameters::kRegStrategy().c_str()),
8329 QMessageBox::Yes | QMessageBox::No,
8330 QMessageBox::Yes) == QMessageBox::Yes)
8332 guess = fromIter->second.
inverse() * toIter->second;
8336 guessFromGraphRejected =
true;
8341 guess = fromIter->second.
inverse() * toIter->second;
8346 if(guess.
isNull() && !silent && !guessFromGraphRejected)
8348 if(QMessageBox::question(
this,
8349 tr(
"Add constraint without guess"),
8350 tr(
"Registration is done without vision (see %1 parameter) and we cannot (or we don't want to) find relative " 8351 "transformation between the nodes with the current graph. Do you want to use an identity " 8352 "transform for ICP guess? " 8354 "\n\nOtherwise, if the database has images, it is recommended to use %2=2 " 8355 "instead so that the guess can be found visually.")
8356 .arg(Parameters::kRegStrategy().c_str()).arg(Parameters::kRegStrategy().c_str()),
8357 QMessageBox::Yes | QMessageBox::Abort,
8358 QMessageBox::Abort) == QMessageBox::Yes)
8364 guessFromGraphRejected =
true;
8387 if(odomMaxInf.size() == 6 && information.cols==6 && information.rows==6)
8389 for(
int i=0; i<6; ++i)
8391 if(information.at<
double>(i,i) > odomMaxInf[i])
8393 information.at<
double>(i,i) = odomMaxInf[i];
8400 else if(!silent && !guessFromGraphRejected)
8402 QMessageBox::StandardButton button = QMessageBox::warning(
this,
8404 tr(
"Cannot find a transformation between nodes %1 and %2: %3\n\nDo you want to add it manually?").arg(from).arg(to).arg(info.
rejectedMsg.c_str()),
8405 QMessageBox::Yes | QMessageBox::No,
8407 if(button == QMessageBox::Yes)
8419 bool updateConstraints = newLink.
isValid();
8420 float maxOptimizationError =
uStr2Float(
ui_->parameters_toolbox->getParameters().at(Parameters::kRGBDOptimizeMaxError()));
8422 maxOptimizationError > 0.0f &&
8423 uStr2Int(
ui_->parameters_toolbox->getParameters().at(Parameters::kOptimizerIterations())) > 0.0
f)
8425 int fromId = newLink.
from();
8427 linksIn.insert(std::make_pair(newLink.
from(), newLink));
8428 const Link * maxLinearLink = 0;
8429 const Link * maxAngularLink = 0;
8430 float maxLinearErrorRatio = 0.0f;
8431 float maxAngularErrorRatio = 0.0f;
8433 std::map<int, Transform> poses;
8434 std::multimap<int, Link> links;
8442 const std::map<int, Transform> & optimizedPoses =
graphes_.back();
8443 for(std::map<int, Transform>::iterator iter = poses.begin(); iter!=poses.end(); ++iter)
8445 if(optimizedPoses.find(iter->first) != optimizedPoses.end())
8447 iter->second = optimizedPoses.at(iter->first);
8451 UASSERT(poses.find(fromId) != poses.end());
8452 UASSERT_MSG(poses.find(newLink.
from()) != poses.end(),
uFormat(
"id=%d poses=%d links=%d", newLink.
from(), (int)poses.size(), (int)links.size()).c_str());
8453 UASSERT_MSG(poses.find(newLink.
to()) != poses.end(),
uFormat(
"id=%d poses=%d links=%d", newLink.
to(), (int)poses.size(), (int)links.size()).c_str());
8455 std::map<int, Transform> posesIn = poses;
8456 poses = optimizer->
optimize(fromId, posesIn, links);
8457 if(posesIn.size() && poses.empty())
8459 UWARN(
"Optimization failed... (poses=%d, links=%d).", (
int)posesIn.size(), (int)links.size());
8464 float maxLinearError = 0.0f;
8465 float maxAngularError = 0.0f;
8469 maxLinearErrorRatio,
8470 maxAngularErrorRatio,
8477 UINFO(
"Max optimization linear error = %f m (link %d->%d, var=%f, ratio error/std=%f)", maxLinearError, maxLinearLink->
from(), maxLinearLink->
to(), maxLinearLink->
transVariance(), maxLinearError/
sqrt(maxLinearLink->
transVariance()));
8478 if(maxLinearErrorRatio > maxOptimizationError)
8480 msg =
uFormat(
"Rejecting edge %d->%d because " 8481 "graph error is too large (abs=%f m) after optimization (ratio %f for edge %d->%d, stddev=%f m). " 8486 maxLinearErrorRatio,
8487 maxLinearLink->
from(),
8488 maxLinearLink->
to(),
8490 Parameters::kRGBDOptimizeMaxError().c_str(),
8491 maxOptimizationError);
8496 UINFO(
"Max optimization angular error = %f deg (link %d->%d, var=%f, ratio error/std=%f)", maxAngularError*180.0
f/CV_PI, maxAngularLink->
from(), maxAngularLink->
to(), maxAngularLink->
rotVariance(), maxAngularError/
sqrt(maxAngularLink->
rotVariance()));
8497 if(maxAngularErrorRatio > maxOptimizationError)
8499 msg =
uFormat(
"Rejecting edge %d->%d because " 8500 "graph error is too large (abs=%f deg) after optimization (ratio %f for edge %d->%d, stddev=%f deg). " 8504 maxAngularError*180.0f/CV_PI,
8505 maxAngularErrorRatio,
8506 maxAngularLink->
from(),
8507 maxAngularLink->
to(),
8509 Parameters::kRGBDOptimizeMaxError().c_str(),
8510 maxOptimizationError);
8516 msg =
uFormat(
"Rejecting edge %d->%d because graph optimization has failed!",
8522 UWARN(
"%s", msg.c_str());
8525 QMessageBox::warning(
this,
8527 tr(
"%1").arg(msg.c_str()));
8530 updateConstraints =
false;
8533 if(updateConstraints && silent && !
graphes_.empty() &&
graphes_.back().size() == poses.size())
8539 if(updateConstraints)
8548 if(newLink.
from() < newLink.
to())
8560 if((updateConstraints && newLink.
from() > newLink.
to()) || (!updateConstraints && switchedIds))
8567 if(updateConstraints)
8574 std::multimap<int, cv::KeyPoint> keypointsFrom;
8575 std::multimap<int, cv::KeyPoint> keypointsTo;
8578 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
8580 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
8585 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
8587 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
8594 else if(updateConstraints)
8601 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
8606 return updateConstraints;
8611 int from =
ids_.at(
ui_->horizontalSlider_A->value());
8612 int to =
ids_.at(
ui_->horizontalSlider_B->value());
8615 int position =
ui_->horizontalSlider_loops->value();
8630 UWARN(
"Cannot reset link to same node");
8647 int from =
ids_.at(
ui_->horizontalSlider_A->value());
8648 int to =
ids_.at(
ui_->horizontalSlider_B->value());
8651 int position =
ui_->horizontalSlider_loops->value();
8666 UWARN(
"Cannot reject link to same node");
8670 bool removed =
false;
8673 std::multimap<int, Link>::iterator iter;
8679 QMessageBox::StandardButton button = QMessageBox::warning(
this, tr(
"Reject link"),
8680 tr(
"Removing the neighbor link %1->%2 will split the graph. Do you want to continue?").arg(from).arg(to),
8681 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
8682 if(button != QMessageBox::Yes)
8712 const std::multimap<int, rtabmap::Link> & edgeConstraints)
8716 std::multimap<int, rtabmap::Link> links;
8717 for(std::multimap<int, rtabmap::Link>::const_iterator iter=edgeConstraints.begin();
8718 iter!=edgeConstraints.end();
8721 std::multimap<int, rtabmap::Link>::iterator findIter;
8726 UDEBUG(
"Removed link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
8733 links.insert(*findIter);
8734 UDEBUG(
"Updated link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
8738 links.insert(*iter);
8742 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
linksAdded_.begin();
8749 links.insert(*findIter);
8750 UDEBUG(
"Added refined link (%d->%d, %d)", findIter->second.from(), findIter->second.to(), findIter->second.type());
8754 UDEBUG(
"Added link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
8755 links.insert(*iter);
8763 UDEBUG(
"%d %d", from, to);
8766 int position =
ui_->horizontalSlider_loops->value();
8767 std::multimap<int, Link> linksSortedByParents;
8768 for(std::multimap<int, rtabmap::Link>::iterator iter = links.begin(); iter!=links.end(); ++iter)
8770 if(iter->second.to() > iter->second.from())
8772 linksSortedByParents.insert(std::make_pair(iter->second.to(), iter->second.inverse()));
8774 else if(iter->second.to() != iter->second.from())
8776 linksSortedByParents.insert(*iter);
8779 for(std::multimap<int, rtabmap::Link>::iterator iter = linksSortedByParents.begin(); iter!=linksSortedByParents.end(); ++iter)
8781 if(!iter->second.transform().isNull())
8786 if((iter->second.from() == from && iter->second.to() == to) ||
8787 (iter->second.to() == from && iter->second.from() == to))
8796 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
8807 ui_->horizontalSlider_loops->setMinimum(0);
8808 ui_->horizontalSlider_loops->setMaximum(
loopLinks_.size()-1);
8809 ui_->horizontalSlider_loops->setEnabled(
true);
8810 if(position !=
ui_->horizontalSlider_loops->value())
8812 ui_->horizontalSlider_loops->setValue(position);
8821 ui_->horizontalSlider_loops->setEnabled(
false);
8832 for(QStringList::const_iterator iter=parametersChanged.constBegin();
8833 iter!=parametersChanged.constEnd() && (!updateStereo || !
updateGraphView);
8836 QString group = iter->split(
'/').first();
8837 if(!updateStereo && group ==
"Stereo")
8839 updateStereo =
true;
8842 if(!updateGraphView && group ==
"Optimize")
8844 updateGraphView =
true;
const cv::Mat & infMatrix() const
int UTILITE_EXP uStr2Int(const std::string &str)
void removeGraph(const std::string &id)
void exportPosesRGBDSLAMMotionCapture()
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
bool RTABMAP_EXP isFinite(const cv::Point3f &pt)
void setImage(const cv::Mat &depth, const cv::Mat &rgb=cv::Mat())
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
std::multimap< int, rtabmap::Link > updateLinksWithModifications(const std::multimap< int, rtabmap::Link > &edgeConstraints)
std::vector< double > odomMaxInf_
std::map< int, std::pair< float, cv::Point3f > > generatedLocalMapsInfo_
Link merge(const Link &link, Type outputType) const
bool update(const std::map< int, Transform > &poses)
void incrementStep(int steps=1)
Transform computeTransformationMod(Signature &from, Signature &to, Transform guess=Transform::getIdentity(), RegistrationInfo *info=0) const
long getWordsMemoryUsed() const
const double & error() const
Transform RTABMAP_EXP transformFromXYZCorrespondencesSVD(const pcl::PointCloud< pcl::PointXYZ > &cloud1, const pcl::PointCloud< pcl::PointXYZ > &cloud2)
virtual std::vector< cv::Point2f > computeCorrespondences(const cv::Mat &leftImage, const cv::Mat &rightImage, const std::vector< cv::Point2f > &leftCorners, std::vector< unsigned char > &status) const
cv::Mat load2DMap(float &xMin, float &yMin, float &cellSize) const
void sliderBValueChanged(int)
const double & latitude() const
void save2DMap(const cv::Mat &map, float xMin, float yMin, float cellSize) const
T uMean(const T *v, unsigned int size)
double rotVariance(bool minimum=true) const
cv::Point3f RTABMAP_EXP projectDisparityTo3D(const cv::Point2f &pt, float disparity, const StereoCameraModel &model)
int sessionExported() const
pcl::PointCloud< pcl::PointXYZRGB >::Ptr createCloud(unsigned int treeDepth=0, std::vector< int > *obstacleIndices=0, std::vector< int > *emptyIndices=0, std::vector< int > *groundIndices=0, bool originalRefPoints=true, std::vector< int > *frontierIndices=0, std::vector< double > *cloudProb=0) const
const double & stamp() const
std::map< int, Transform > RTABMAP_EXP radiusPosesFiltering(const std::map< int, Transform > &poses, float radius, float angle, bool keepLatest=true)
std::multimap< int, Link >::iterator RTABMAP_EXP findLink(std::multimap< int, Link > &links, int from, int to, bool checkBothWays=true, Link::Type type=Link::kUndef)
void RTABMAP_EXP computeMaxGraphErrors(const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, float &maxLinearErrorRatio, float &maxAngularErrorRatio, float &maxLinearError, float &maxAngularError, const Link **maxLinearErrorLink=0, const Link **maxAngularErrorLink=0, bool for3DoF=false)
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
const cv::KeyPoint & keypoint() const
void setCancelButtonVisible(bool visible)
static StereoDense * create(const ParametersMap ¶meters)
Signature * loadSignature(int id, bool *loadedFromTrash=0)
std::vector< K > uKeys(const std::multimap< K, V > &mm)
void loadWords(const std::set< int > &wordIds, std::list< VisualWord *> &vws)
long getStatisticsMemoryUsed() const
double UTILITE_EXP uStr2Double(const std::string &str)
bool uIsDigit(const char c)
void updateLaserScan(int nodeId, const LaserScan &scan)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP transformPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const Transform &transform)
void setLaserScan(const LaserScan &laserScan, bool clearPreviousData=true)
V & uValueAt(std::list< V > &list, const unsigned int &pos)
virtual void resizeEvent(QResizeEvent *anEvent)
int getTextureSize() const
const LaserScan & laserScanCompressed() const
cv::Mat getProbMap(float &xMin, float &yMin) const
void addOrUpdateCoordinate(const std::string &id, const Transform &transform, double scale, bool foreground=false)
std::map< int, rtabmap::Transform > gpsPoses_
void regenerateCurrentLocalMaps()
bool RTABMAP_EXP exportGPS(const std::string &filePath, const std::map< int, GPS > &gpsValues, unsigned int rgba=0xFFFFFFFF)
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
virtual void closeEvent(QCloseEvent *event)
int uStrNumCmp(const std::string &a, const std::string &b)
static std::string getDir(const std::string &filePath)
virtual void showEvent(QShowEvent *anEvent)
pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr RTABMAP_EXP laserScanToPointCloudRGBNormal(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=100, unsigned char g=100, unsigned char b=100)
std::pair< std::string, std::string > ParametersPair
std::list< std::map< int, rtabmap::Transform > > graphes_
CloudViewer * constraintsViewer_
void addData(const rtabmap::SensorData &data, const Transform &pose=Transform(), const cv::Mat &infMatrix=cv::Mat::eye(6, 6, CV_64FC1))
bool UTILITE_EXP uStr2Bool(const char *str)
bool removeCloud(const std::string &id)
static int channels(const Format &format)
const cv::Mat & depthOrRightRaw() const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP removeNaNFromPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud)
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack, float depthMin=0, float depthMax=0)
pcl::PCLPointCloud2::Ptr RTABMAP_EXP laserScanToPointCloud2(const LaserScan &laserScan, const Transform &transform=Transform())
cv::Mat RTABMAP_EXP depthFromDisparity(const cv::Mat &disparity, float fx, float baseline, int type=CV_32FC1)
void saveOptimizedMesh(const cv::Mat &cloud, const std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > > &polygons=std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > >(), const std::vector< std::vector< Eigen::Vector2f > > &texCoords=std::vector< std::vector< Eigen::Vector2f > >(), const cv::Mat &textures=cv::Mat()) const
void setMap(const cv::Mat &map)
void updateConstraintView()
void setColorMap(uCvQtDepthColorMap type)
float UTILITE_EXP uStr2Float(const std::string &str)
const cv::Mat & userDataCompressed() const
double getAngularVariance() const
void exportGPS(int format)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
bool addOccupancyGridMap(const cv::Mat &map8U, float resolution, float xMin, float yMin, float opacity)
const std::vector< StereoCameraModel > & stereoCameraModels() const
void viewClouds(const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, int > &mapIds, const QMap< int, Signature > &cachedSignatures, const std::map< int, std::pair< pcl::PointCloud< pcl::PointXYZRGB >::Ptr, pcl::IndicesPtr > > &cachedClouds, const std::map< int, LaserScan > &cachedScans, const QString &workingDirectory, const ParametersMap ¶meters)
bool getExportedClouds(const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, int > &mapIds, const QMap< int, Signature > &cachedSignatures, const std::map< int, std::pair< pcl::PointCloud< pcl::PointXYZRGB >::Ptr, pcl::IndicesPtr > > &cachedClouds, const std::map< int, LaserScan > &cachedScans, const QString &workingDirectory, const ParametersMap ¶meters, std::map< int, pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr > &clouds, std::map< int, pcl::PolygonMesh::Ptr > &meshes, std::map< int, pcl::TextureMesh::Ptr > &textureMeshes, std::vector< std::map< int, pcl::PointXY > > &textureVertexToPixels)
const cv::Mat & data() const
long getFeaturesMemoryUsed() const
std::map< std::string, std::string > ParametersMap
QString getIniFilePath() const
const std::vector< cv::Point3f > & getWords3() const
static void writeINI(const std::string &configFile, const ParametersMap ¶meters)
void setCellSize(float cellSize)
void setGPS(const GPS &gps)
std::vector< int > inliersIDs
Some conversion functions.
void addValue(UPlotItem *data)
void setImage(const QImage &image)
void loadLinks(int signatureId, std::multimap< int, Link > &links, Link::Type type=Link::kUndef) const
pcl::TextureMesh::Ptr RTABMAP_EXP assembleTextureMesh(const cv::Mat &cloudMat, const std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > > &polygons, const std::vector< std::vector< Eigen::Vector2f > > &texCoords, cv::Mat &textures, bool mergeTextures=false)
void setPolygonPicking(bool enabled)
std::multimap< int, rtabmap::Link > linksAdded_
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
void updateOptimizedMesh()
void buildPickingLocator(bool enable)
QList< rtabmap::Link > neighborLinks_
Link findActiveLink(int from, int to)
std::multimap< int, rtabmap::Link > links_
long getNodesMemoryUsed() const
bool isFrustumShown() const
void notifyParametersChanged(const QStringList &)
ExportCloudsDialog * exportDialog_
static void setLevel(ULogger::Level level)
cv::Mat getModifiedMap() const
bool containsLink(std::multimap< int, Link > &links, int from, int to)
void refineAllLoopClosureLinks()
std::vector< cv::KeyPoint > generateKeypoints(const cv::Mat &image, const cv::Mat &mask=cv::Mat())
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
QMap< int, int > idToIndex_
T uMin(const T *v, unsigned int size, unsigned int &index)
int getBlendingDecimation() const
void setDBDriver(const DBDriver *dbDriver)
std::map< int, LaserScan > modifiedLaserScans_
void generateGraph(const std::string &fileName, const std::set< int > &ids=std::set< int >(), const std::map< int, Signature *> &otherSignatures=std::map< int, Signature *>())
std::map< int, Transform > loadOptimizedPoses(Transform *lastlocalizationPose=0) const
void saveOptimizedPoses(const std::map< int, Transform > &optimizedPoses, const Transform &lastlocalizationPose) const
bool addCloudTextureMesh(const std::string &id, const pcl::TextureMesh::Ptr &textureMesh, const cv::Mat &texture, const Transform &pose=Transform::getIdentity())
QDialog * editDepthDialog_
float gridCellSize() const
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP cloudFromDepthRGB(const cv::Mat &imageRgb, const cv::Mat &imageDepth, const CameraModel &model, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0)
std::string databaseFileName_
double getLinearVariance() const
void detectMoreLoopClosures()
EditDepthArea * editDepthArea_
bool isOdomExported() const
void addOrUpdateLine(const std::string &id, const Transform &from, const Transform &to, const QColor &color, bool arrow=false, bool foreground=false)
std::multimap< int, rtabmap::Link > linksRefined_
bool openConnection(const std::string &url, bool overwritten=false)
void getAllLinks(std::multimap< int, Link > &links, bool ignoreNullLinks=true, bool withLandmarks=false) const
const std::vector< cv::KeyPoint > & getWordsKpts() const
long getLaserScansMemoryUsed() const
void getLastNodeIds(std::set< int > &ids) const
void loadSettings(QSettings &settings, const QString &group="")
#define UASSERT(condition)
bool update(const std::map< int, Transform > &poses)
void updateAllLandmarkCovariances()
std::list< std::string > uSplit(const std::string &str, char separator=' ')
const double & altitude() const
void setupMainLayout(bool vertical)
const double & bearing() const
void selectObstacleColor()
void addToCache(int nodeId, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &ground, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &obstacles, const pcl::PointXYZ &viewPoint)
bool isDepthExported() const
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP laserScanToPointCloudRGB(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=100, unsigned char g=100, unsigned char b=100)
void setSceneRect(const QRectF &rect)
bool isExposeFusion() const
int getTotalDictionarySize() const
const std::vector< CameraModel > & cameraModels() const
std::list< std::list< int > > RTABMAP_EXP clusterPolygons(const std::vector< std::set< int > > &neighborPolygons, int minClusterSize=0)
double targetFramerate() const
cv::Point3d toENU_WGS84(const GeodeticCoords &origin) const
virtual ~DatabaseViewer()
static Feature2D * create(const ParametersMap ¶meters=ParametersMap())
void update(int value, QLabel *labelIndex, QLabel *labelParents, QLabel *labelChildren, QLabel *weight, QLabel *label, QLabel *stamp, rtabmap::ImageView *view, QLabel *labelId, QLabel *labelMapId, QLabel *labelPose, QLabel *labelOptPose, QLabel *labelVelocity, QLabel *labelCalib, QLabel *labelScan, QLabel *labelGravity, QLabel *labelPrior, QLabel *labelGps, QLabel *labelGt, QLabel *labelSensors, bool updateConstraintView)
static ParametersMap filterParameters(const ParametersMap ¶meters, const std::string &group, bool remove=false)
virtual cv::Mat computeDisparity(const cv::Mat &leftImage, const cv::Mat &rightImage) const =0
bool isScanRequired() const
std::map< int, int > mapIds_
#define ULOGGER_DEBUG(...)
void updateWordsMatching(const std::vector< int > &inliers=std::vector< int >())
bool isDepth2dExported() const
std::map< int, GPS > gpsValues_
bool getNodeInfo(int signatureId, Transform &pose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruthPose, std::vector< float > &velocity, GPS &gps, EnvSensors &sensors) const
std::multimap< int, rtabmap::Link > graphLinks_
QList< rtabmap::Link > loopLinks_
#define UASSERT_MSG(condition, msg_str)
void sliderNeighborValueChanged(int)
UPlotCurve * addCurve(const QString &curveName, const QColor &color=QColor())
void updateConstraintButtons()
void addToCache(int nodeId, const cv::Mat &ground, const cv::Mat &obstacles, const cv::Mat &empty)
pcl::PointCloud< pcl::PointXYZINormal >::Ptr RTABMAP_EXP laserScanToPointCloudINormal(const LaserScan &laserScan, const Transform &transform=Transform(), float intensity=0.0f)
void exportOptimizedMesh()
void setImageDepth(const cv::Mat &imageDepth)
const cv::Mat & imageRaw() const
bool getCalibration(int signatureId, std::vector< CameraModel > &models, std::vector< StereoCameraModel > &stereoModels) const
void getAllNodeIds(std::set< int > &ids, bool ignoreChildren=false, bool ignoreBadSignatures=false, bool ignoreIntermediateNodes=false) const
const double & altitude() const
std::map< int, Transform > optimize(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)
Transform RTABMAP_EXP calcRMSE(const std::map< int, Transform > &groundTruth, const std::map< int, Transform > &poses, float &translational_rmse, float &translational_mean, float &translational_median, float &translational_std, float &translational_min, float &translational_max, float &rotational_rmse, float &rotational_mean, float &rotational_median, float &rotational_std, float &rotational_min, float &rotational_max)
std::vector< std::pair< std::pair< int, int >, pcl::PointXY > > RTABMAP_EXP projectCloudToCameras(const pcl::PointCloud< pcl::PointXYZRGBNormal > &cloud, const std::map< int, Transform > &cameraPoses, const std::map< int, std::vector< CameraModel > > &cameraModels, float maxDistance=0.0f, float maxAngle=0.0f, const std::vector< float > &roiRatios=std::vector< float >(), const cv::Mat &projMask=cv::Mat(), bool distanceToCamPolicy=false, const ProgressState *state=0)
std::vector< double > RTABMAP_EXP getMaxOdomInf(const std::multimap< int, Link > &links)
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP cloudRGBFromSensorData(const SensorData &sensorData, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0, const ParametersMap &stereoParameters=ParametersMap(), const std::vector< float > &roiRatios=std::vector< float >())
int lastSliderIndexBrowsed_
double getGainBeta() const
std::map< int, std::vector< int > > wmStates_
void removeOccupancyGridMap()
void regenerateLocalMaps()
void setCloudPointSize(const std::string &id, int size)
void getNodeData(int signatureId, SensorData &data, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
bool isImageRequired() const
long getGridsMemoryUsed() const
void sliderIterationsValueChanged(int)
void setMaximumSteps(int steps)
const Transform & localTransform() const
cv::Mat RTABMAP_EXP convertImage8U2Map(const cv::Mat &map8U, bool pgmFormat=false)
std::map< int, std::pair< float, cv::Point3f > > localMapsInfo_
void updateCameraTargetPosition(const Transform &pose)
void updateLink(const Link &link)
cv::Mat getMap(float &xMin, float &yMin) const
void addOrUpdateFrustum(const std::string &id, const Transform &pose, const Transform &localTransform, double scale, const QColor &color=QColor(), float fovX=1.1, float fovY=0.85)
LaserScan laserScanFromPointCloud(const PointCloud2T &cloud, bool filterNaNs, bool is2D, const Transform &transform)
std::map< int, int > weights_
std::multimap< int, rtabmap::Link > linksRemoved_
void updateDepthImage(int nodeId, const cv::Mat &image)
QColor getFrustumColor() const
std::list< std::string > uSplitNumChar(const std::string &str)
std::vector< pcl::Vertices > RTABMAP_EXP organizedFastMesh(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, double angleTolerance, bool quad, int trianglePixelSize, const Eigen::Vector3f &viewpoint=Eigen::Vector3f(0, 0, 0))
void saveSettings(QSettings &settings, const QString &group="") const
void exportPoses(int format)
Transform getTransform() const
void setProgressDialogToMax()
void setEnvSensors(const EnvSensors &sensors)
std::map< int, rtabmap::Transform > odomPoses_
bool getLaserScanInfo(int signatureId, LaserScan &info) const
void getConnectedGraph(int fromId, const std::map< int, Transform > &posesIn, const std::multimap< int, Link > &linksIn, std::map< int, Transform > &posesOut, std::multimap< int, Link > &linksOut, bool adjustPosesWithConstraints=true) const
bool uContains(const std::list< V > &list, const V &value)
GeodeticCoords toGeodeticCoords() const
std::multimap< int, int > RTABMAP_EXP radiusPosesClustering(const std::map< int, Transform > &poses, float radius, float angle)
void exportClouds(const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, int > &mapIds, const QMap< int, Signature > &cachedSignatures, const std::map< int, std::pair< pcl::PointCloud< pcl::PointXYZRGB >::Ptr, pcl::IndicesPtr > > &cachedClouds, const std::map< int, LaserScan > &cachedScans, const QString &workingDirectory, const ParametersMap ¶meters)
std::map< int, std::pair< std::map< std::string, float >, double > > getAllStatistics() const
bool RTABMAP_EXP exportPoses(const std::string &filePath, int format, const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints=std::multimap< int, Link >(), const std::map< int, double > &stamps=std::map< int, double >(), const ParametersMap ¶meters=ParametersMap())
RecoveryProgressState state
void setCameraLockZ(bool enabled=true)
void setPose(const Transform &pose)
static DBDriver * create(const ParametersMap ¶meters=ParametersMap())
std::map< int, rtabmap::Transform > groundTruthPoses_
GLM_FUNC_DECL detail::tquat< T, P > rotation(detail::tvec3< T, P > const &orig, detail::tvec3< T, P > const &dest)
static Stereo * create(const ParametersMap ¶meters=ParametersMap())
long getCalibrationsMemoryUsed() const
int getTextureBrightnessConstrastRatioHigh() const
CloudViewer * stereoViewer_
cv::Mat RTABMAP_EXP mergeTextures(pcl::TextureMesh &mesh, const std::map< int, cv::Mat > &images, const std::map< int, CameraModel > &calibrations, const Memory *memory=0, const DBDriver *dbDriver=0, int textureSize=4096, int textureCount=1, const std::vector< std::map< int, pcl::PointXY > > &vertexToPixels=std::vector< std::map< int, pcl::PointXY > >(), bool gainCompensation=true, float gainBeta=10.0f, bool gainRGB=true, bool blending=true, int blendingDecimation=0, int brightnessContrastRatioLow=0, int brightnessContrastRatioHigh=0, bool exposureFusion=false, const ProgressState *state=0, unsigned char blankValue=255, std::map< int, std::map< int, cv::Vec4d > > *gains=0, std::map< int, std::map< int, cv::Mat > > *blendingGains=0, std::pair< float, float > *contrastValues=0)
bool addCloud(const std::string &id, const pcl::PCLPointCloud2Ptr &binaryCloud, const Transform &pose, bool rgb, bool hasNormals, bool hasIntensity, const QColor &color=QColor(), int viewport=1)
static std::string getType(const std::string ¶mKey)
int getLastNodesSize() const
void restoreDefaultSettings()
T uMax(const T *v, unsigned int size, unsigned int &index)
QString outputPath() const
void uSleep(unsigned int ms)
std::vector< std::vector< RTABMAP_PCL_INDEX > > RTABMAP_EXP convertPolygonsFromPCL(const std::vector< pcl::Vertices > &polygons)
void refineAllLinks(const QList< Link > &links)
rtabmap::DBDriver * dbDriver_
bool isRgbExported() const
cv::Mat RTABMAP_EXP convertMap2Image8U(const cv::Mat &map8S, bool pgmFormat=false)
static const ParametersMap & getDefaultParameters()
void RTABMAP_EXP fixTextureMeshForVisualization(pcl::TextureMesh &textureMesh)
const cv::Point3f & gridViewPoint() const
bool isUserDataExported() const
void addOrUpdateGraph(const std::string &id, const pcl::PointCloud< pcl::PointXYZ >::Ptr &graph, const QColor &color=Qt::gray)
float getFrustumScale() const
std::vector< V > uValues(const std::multimap< K, V > &mm)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP cloudFromSensorData(const SensorData &sensorData, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0, const ParametersMap &stereoParameters=ParametersMap(), const std::vector< float > &roiRatios=std::vector< float >())
virtual Type type() const =0
static Registration * create(const ParametersMap ¶meters)
const LaserScan & laserScanRaw() const
void getLastWordId(int &id) const
SensorData & sensorData()
cv::Mat getModifiedImage() const
void loadNodeData(Signature *signature, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
void updateCameraFrustums(const Transform &pose, const std::vector< CameraModel > &models)
int getTextureBrightnessConstrastRatioLow() const
void showCloseButton(bool visible=true)
bool isUserDataRequired() const
void loadSignatures(const std::list< int > &ids, std::list< Signature *> &signatures, std::set< int > *loadedFromTrash=0)
const double & longitude() const
bool RTABMAP_EXP databaseRecovery(const std::string &corruptedDatabase, bool keepCorruptedDatabase=true, std::string *errorMsg=0, ProgressState *progressState=0)
int getMaxTextures() const
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP laserScanToPointCloudNormal(const LaserScan &laserScan, const Transform &transform=Transform())
void RTABMAP_EXP createPolygonIndexes(const std::vector< pcl::Vertices > &polygons, int cloudSize, std::vector< std::set< int > > &neighborPolygons, std::vector< std::set< int > > &vertexPolygons)
Given a set of polygons, create two indexes: polygons to neighbor polygons and vertices to polygons...
void refineAllNeighborLinks()
void updateLoopClosuresSlider(int from=0, int to=0)
const cv::Mat & gridEmptyCellsRaw() const
cv::Mat RTABMAP_EXP fillDepthHoles(const cv::Mat &depth, int maximumHoleSize=1, float errorRatio=0.02f)
int framesIgnored() const
void updateOccupancyGrid(int nodeId, const cv::Mat &ground, const cv::Mat &obstacles, const cv::Mat &empty, float cellSize, const cv::Point3f &viewpoint)
virtual void keyPressEvent(QKeyEvent *event)
const Transform & getPose() const
void updateAllLoopClosureCovariances()
ULogger class and convenient macros.
const cv::Mat & gridGroundCellsRaw() const
long getDepthImagesMemoryUsed() const
std::set< int > lastWmIds_
void feed(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloudA, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloudB, const Transform &transformB)
const double & longitude() const
ParametersMap getLastParameters() const
cv::Mat loadOptimizedMesh(std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > > *polygons=0, std::vector< std::vector< Eigen::Vector2f > > *texCoords=0, cv::Mat *textures=0) const
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
static bool exists(const std::string &dirPath)
static void readINI(const std::string &configFile, ParametersMap ¶meters, bool modifiedOnly=false)
void setCloudColorIndex(const std::string &id, int index)
void exportPosesRGBDSLAMID()
double transVariance(bool minimum=true) const
void removeCoordinate(const std::string &id)
bool hasIntensity() const
bool init(const QString &path, bool recordInRAM=true)
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > localMaps_
long getImagesMemoryUsed() const
void setGroundTruth(const Transform &pose)
cv::Mat RTABMAP_EXP cvtDepthFromFloat(const cv::Mat &depth32F)
std::string getDatabaseVersion() const
int getLastDictionarySize() const
const cv::Mat & gridObstacleCellsRaw() const
CloudViewer * cloudViewer_
void updateAllNeighborCovariances()
void forceAssembling(bool enabled)
const double & latitude() const
std::map< EnvSensor::Type, EnvSensor > EnvSensors
float angleIncrement() const
cv::Mat createProjectionMap(float &xMin, float &yMin, float &gridCellSize, float minGridSize=0.0f, unsigned int treeDepth=0)
static std::string formatName(const Format &format)
void generateLocalGraph()
bool addOctomap(const OctoMap *octomap, unsigned int treeDepth=0, bool volumeRepresentation=true)
void updateAllCovariances(const QList< Link > &links)
void sliderLoopValueChanged(int)
bool addCloudMesh(const std::string &id, const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const std::vector< pcl::Vertices > &polygons, const Transform &pose=Transform::getIdentity())
pcl::PointCloud< pcl::PointXYZI >::Ptr RTABMAP_EXP laserScanToPointCloudI(const LaserScan &laserScan, const Transform &transform=Transform(), float intensity=0.0f)
const Transform & transform() const
DatabaseViewer(const QString &ini=QString(), QWidget *parent=0)
long getUserDataMemoryUsed() const
GLM_FUNC_DECL genType::value_type length(genType const &x)
bool isCovarianceIgnored() const
cv::Mat uncompressUserDataConst() const
void addLink(const Link &link)
void appendText(const QString &text, const QColor &color=Qt::black)
virtual bool eventFilter(QObject *obj, QEvent *event)
#define ULOGGER_ERROR(...)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
virtual void moveEvent(QMoveEvent *anEvent)
void removeLink(int from, int to)
float RTABMAP_EXP computePathLength(const std::vector< std::pair< int, Transform > > &path, unsigned int fromIndex=0, unsigned int toIndex=0)
std::string UTILITE_EXP uFormat(const char *fmt,...)
long getLinksMemoryUsed() const
std::string UTILITE_EXP uNumber2Str(unsigned int number)
void regenerateSavedMap()
static LaserScan backwardCompatibility(const cv::Mat &oldScanFormat, int maxPoints=0, int maxRange=0, const Transform &localTransform=Transform::getIdentity())
void uncompressDataConst(cv::Mat *imageRaw, cv::Mat *depthOrRightRaw, LaserScan *laserScanRaw=0, cv::Mat *userDataRaw=0, cv::Mat *groundCellsRaw=0, cv::Mat *obstacleCellsRaw=0, cv::Mat *emptyCellsRaw=0) const
CloudViewer * occupancyGridViewer_
void exportPosesRGBDSLAM()
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > generatedLocalMaps_
void removeAllFrustums(bool exceptCameraReference=false)
Transform localTransform() const
void fromENU_WGS84(const cv::Point3d &enu, const GeodeticCoords &origin)
static Optimizer * create(const ParametersMap ¶meters)
LaserScan RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
bool isGainCompensation() const
void setFeatures(const std::multimap< int, cv::KeyPoint > &refWords, const cv::Mat &depth=cv::Mat(), const QColor &color=Qt::yellow)
V uValue(const std::map< K, V > &m, const K &key, const V &defaultValue=V())
void setFeatures(const std::vector< cv::KeyPoint > &keypoints, const std::vector< cv::Point3f > &keypoints3D, const cv::Mat &descriptors)
const std::string & getUrl() const
std::map< int, std::vector< int > > getAllStatisticsWmStates() const
pcl::PolygonMesh::Ptr RTABMAP_EXP assemblePolygonMesh(const cv::Mat &cloudMat, const std::vector< std::vector< RTABMAP_PCL_INDEX > > &polygons)
EditMapArea * editMapArea_
void setCloudOpacity(const std::string &id, double opacity=1.0)
void RTABMAP_EXP calcKittiSequenceErrors(const std::vector< Transform > &poses_gt, const std::vector< Transform > &poses_result, float &t_err, float &r_err)
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
const std::multimap< int, int > & getWords() const
void sliderAValueChanged(int)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)